Merge tag 'usb-4.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 18 Aug 2018 17:21:49 +0000 (10:21 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 18 Aug 2018 17:21:49 +0000 (10:21 -0700)
Pull USB/PHY updates from Greg KH:
 "Here is the big USB and phy driver patch set for 4.19-rc1.

  Nothing huge but there was a lot of work that happened this
  development cycle:

   - lots of type-c work, with drivers graduating out of staging, and
     displayport support being added.

   - new PHY drivers

   - the normal collection of gadget driver updates and fixes

   - code churn to work on the urb handling path, using irqsave()
     everywhere in anticipation of making this codepath a lot simpler in
     the future.

   - usbserial driver fixes and reworks

   - other misc changes

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

* tag 'usb-4.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (159 commits)
  USB: serial: pl2303: add a new device id for ATEN
  usb: renesas_usbhs: Kconfig: convert to SPDX identifiers
  usb: dwc3: gadget: Check MaxPacketSize from descriptor
  usb: dwc2: Turn on uframe_sched on "stm32f4x9_fsotg" platforms
  usb: dwc2: Turn on uframe_sched on "amlogic" platforms
  usb: dwc2: Turn on uframe_sched on "his" platforms
  usb: dwc2: Turn on uframe_sched on "bcm" platforms
  usb: dwc2: gadget: ISOC's starting flow improvement
  usb: dwc2: Make dwc2_readl/writel functions endianness-agnostic.
  usb: dwc3: core: Enable AutoRetry feature in the controller
  usb: dwc3: Set default mode for dwc_usb31
  usb: gadget: udc: renesas_usb3: Add register of usb role switch
  usb: dwc2: replace ioread32/iowrite32_rep with dwc2_readl/writel_rep
  usb: dwc2: Modify dwc2_readl/writel functions prototype
  usb: dwc3: pci: Intel Merrifield can be host
  usb: dwc3: pci: Supply device properties via driver data
  arm64: dts: dwc3: description of incr burst type
  usb: dwc3: Enable undefined length INCR burst type
  usb: dwc3: add global soc bus configuration reg0
  usb: dwc3: Describe 'wakeup_work' field of struct dwc3_pci
  ...

165 files changed:
Documentation/ABI/obsolete/sysfs-class-typec [new file with mode: 0644]
Documentation/ABI/testing/configfs-usb-gadget-uvc
Documentation/ABI/testing/sysfs-bus-typec [new file with mode: 0644]
Documentation/ABI/testing/sysfs-class-typec
Documentation/ABI/testing/sysfs-driver-typec-displayport [new file with mode: 0644]
Documentation/devicetree/bindings/connector/usb-connector.txt
Documentation/devicetree/bindings/phy/brcm,sr-pcie-phy.txt [new file with mode: 0644]
Documentation/devicetree/bindings/phy/phy-mtk-tphy.txt
Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt
Documentation/devicetree/bindings/phy/rcar-gen3-phy-pcie.txt [new file with mode: 0644]
Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt
Documentation/devicetree/bindings/usb/dwc3.txt
Documentation/devicetree/bindings/usb/npcm7xx-usb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/usb/typec-tcpci.txt [new file with mode: 0644]
Documentation/devicetree/bindings/usb/usb-xhci.txt
Documentation/driver-api/usb/typec_bus.rst [new file with mode: 0644]
Documentation/usb/usb-serial.txt
MAINTAINERS
drivers/nfc/nfcmrvl/usb.c
drivers/phy/broadcom/Kconfig
drivers/phy/broadcom/Makefile
drivers/phy/broadcom/phy-bcm-sr-pcie.c [new file with mode: 0644]
drivers/phy/marvell/phy-berlin-sata.c
drivers/phy/marvell/phy-berlin-usb.c
drivers/phy/marvell/phy-mvebu-cp110-comphy.c
drivers/phy/mediatek/Makefile
drivers/phy/mediatek/phy-mtk-tphy.c
drivers/phy/qualcomm/phy-qcom-usb-hs.c
drivers/phy/renesas/Kconfig
drivers/phy/renesas/Makefile
drivers/phy/renesas/phy-rcar-gen3-pcie.c [new file with mode: 0644]
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/typec/Kconfig [deleted file]
drivers/staging/typec/Makefile [deleted file]
drivers/staging/typec/TODO [deleted file]
drivers/usb/chipidea/ci_hdrc_tegra.c
drivers/usb/class/cdc-acm.c
drivers/usb/class/cdc-wdm.c
drivers/usb/class/usblp.c
drivers/usb/class/usbtmc.c
drivers/usb/core/devio.c
drivers/usb/core/hub.c
drivers/usb/core/message.c
drivers/usb/dwc2/core.c
drivers/usb/dwc2/core.h
drivers/usb/dwc2/core_intr.c
drivers/usb/dwc2/debugfs.c
drivers/usb/dwc2/gadget.c
drivers/usb/dwc2/hcd.c
drivers/usb/dwc2/hcd.h
drivers/usb/dwc2/hcd_ddma.c
drivers/usb/dwc2/hcd_intr.c
drivers/usb/dwc2/hcd_queue.c
drivers/usb/dwc2/params.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-haps.c [new file with mode: 0644]
drivers/usb/dwc3/dwc3-of-simple.c
drivers/usb/dwc3/dwc3-pci.c
drivers/usb/dwc3/gadget.c
drivers/usb/dwc3/gadget.h
drivers/usb/gadget/configfs.c
drivers/usb/gadget/function/f_mass_storage.c
drivers/usb/gadget/function/f_mass_storage.h
drivers/usb/gadget/function/f_uvc.c
drivers/usb/gadget/function/f_uvc.h
drivers/usb/gadget/function/u_uvc.h
drivers/usb/gadget/function/uvc.h
drivers/usb/gadget/function/uvc_configfs.c
drivers/usb/gadget/function/uvc_queue.h
drivers/usb/gadget/function/uvc_v4l2.c
drivers/usb/gadget/function/uvc_video.h
drivers/usb/gadget/legacy/tcm_usb_gadget.c
drivers/usb/gadget/legacy/webcam.c
drivers/usb/gadget/udc/Kconfig
drivers/usb/gadget/udc/core.c
drivers/usb/gadget/udc/renesas_usb3.c
drivers/usb/host/Kconfig
drivers/usb/host/Makefile
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-hub.c
drivers/usb/host/ehci-npcm7xx.c [new file with mode: 0644]
drivers/usb/host/ehci-sched.c
drivers/usb/host/u132-hcd.c
drivers/usb/host/whci/pzl.c
drivers/usb/host/xhci-dbgcap.c
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-plat.c
drivers/usb/host/xhci-rcar.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/isp1760/isp1760-hcd.c
drivers/usb/misc/adutux.c
drivers/usb/misc/appledisplay.c
drivers/usb/misc/iowarrior.c
drivers/usb/misc/ldusb.c
drivers/usb/misc/legousbtower.c
drivers/usb/misc/sisusbvga/sisusb.c
drivers/usb/misc/usbtest.c
drivers/usb/misc/uss720.c
drivers/usb/mon/mon_bin.c
drivers/usb/musb/musb_dsps.c
drivers/usb/musb/musb_host.c
drivers/usb/renesas_usbhs/Kconfig
drivers/usb/renesas_usbhs/mod_gadget.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/cyberjack.c
drivers/usb/serial/digi_acceleport.c
drivers/usb/serial/io_edgeport.c
drivers/usb/serial/io_ti.c
drivers/usb/serial/ir-usb.c
drivers/usb/serial/iuu_phoenix.c
drivers/usb/serial/kl5kusb105.c
drivers/usb/serial/kl5kusb105.h
drivers/usb/serial/kobil_sct.c
drivers/usb/serial/mos7720.c
drivers/usb/serial/mos7840.c
drivers/usb/serial/option.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/pl2303.h
drivers/usb/serial/quatech2.c
drivers/usb/serial/sierra.c
drivers/usb/serial/ssu100.c
drivers/usb/serial/symbolserial.c
drivers/usb/serial/ti_usb_3410_5052.c
drivers/usb/serial/usb_wwan.c
drivers/usb/typec/Kconfig
drivers/usb/typec/Makefile
drivers/usb/typec/altmodes/Kconfig [new file with mode: 0644]
drivers/usb/typec/altmodes/Makefile [new file with mode: 0644]
drivers/usb/typec/altmodes/displayport.c [new file with mode: 0644]
drivers/usb/typec/bus.c [new file with mode: 0644]
drivers/usb/typec/bus.h [new file with mode: 0644]
drivers/usb/typec/class.c
drivers/usb/typec/fusb302/fusb302.c
drivers/usb/typec/mux.c
drivers/usb/typec/mux/pi3usb30532.c
drivers/usb/typec/tcpci.c [moved from drivers/staging/typec/tcpci.c with 92% similarity]
drivers/usb/typec/tcpci.h [moved from drivers/staging/typec/tcpci.h with 100% similarity]
drivers/usb/typec/tcpci_rt1711h.c [moved from drivers/staging/typec/tcpci_rt1711h.c with 100% similarity]
drivers/usb/typec/tcpm.c
drivers/usb/typec/tps6598x.c
drivers/usb/usb-skeleton.c
drivers/usb/usbip/vudc_dev.c
drivers/usb/wusbcore/security.c
drivers/usb/wusbcore/wa-xfer.c
drivers/uwb/hwa-rc.c
include/dt-bindings/usb/pd.h [new file with mode: 0644]
include/linux/mod_devicetable.h
include/linux/usb/hcd.h
include/linux/usb/pd.h
include/linux/usb/tcpm.h
include/linux/usb/typec.h
include/linux/usb/typec_altmode.h [new file with mode: 0644]
include/linux/usb/typec_dp.h [new file with mode: 0644]
include/linux/usb/typec_mux.h
include/uapi/linux/usb/g_uvc.h [new file with mode: 0644]
include/uapi/linux/usb/tmc.h
scripts/mod/devicetable-offsets.c
scripts/mod/file2alias.c
tools/testing/selftests/drivers/usb/usbip/usbip_test.sh

diff --git a/Documentation/ABI/obsolete/sysfs-class-typec b/Documentation/ABI/obsolete/sysfs-class-typec
new file mode 100644 (file)
index 0000000..3262351
--- /dev/null
@@ -0,0 +1,48 @@
+These files are deprecated and will be removed. The same files are available
+under /sys/bus/typec (see Documentation/ABI/testing/sysfs-bus-typec).
+
+What:          /sys/class/typec/<port|partner|cable>/<dev>/svid
+Date:          April 2017
+Contact:       Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Description:
+               The SVID (Standard or Vendor ID) assigned by USB-IF for this
+               alternate mode.
+
+What:          /sys/class/typec/<port|partner|cable>/<dev>/mode<index>/
+Date:          April 2017
+Contact:       Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Description:
+               Every supported mode will have its own directory. The name of
+               a mode will be "mode<index>" (for example mode1), where <index>
+               is the actual index to the mode VDO returned by Discover Modes
+               USB power delivery command.
+
+What:          /sys/class/typec/<port|partner|cable>/<dev>/mode<index>/description
+Date:          April 2017
+Contact:       Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Description:
+               Shows description of the mode. The description is optional for
+               the drivers, just like with the Billboard Devices.
+
+What:          /sys/class/typec/<port|partner|cable>/<dev>/mode<index>/vdo
+Date:          April 2017
+Contact:       Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Description:
+               Shows the VDO in hexadecimal returned by Discover Modes command
+               for this mode.
+
+What:          /sys/class/typec/<port|partner|cable>/<dev>/mode<index>/active
+Date:          April 2017
+Contact:       Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Description:
+               Shows if the mode is active or not. The attribute can be used
+               for entering/exiting the mode with partners and cable plugs, and
+               with the port alternate modes it can be used for disabling
+               support for specific alternate modes. Entering/exiting modes is
+               supported as synchronous operation so write(2) to the attribute
+               does not return until the enter/exit mode operation has
+               finished. The attribute is notified when the mode is
+               entered/exited so poll(2) on the attribute wakes up.
+               Entering/exiting a mode will also generate uevent KOBJ_CHANGE.
+
+               Valid values: yes, no
index 1ba0d0f..9281e2a 100644 (file)
@@ -263,3 +263,8 @@ Description:        Specific streaming header descriptors
                                        is connected
                bmInfo                  - capabilities of this video streaming
                                        interface
+
+What:          /sys/class/udc/udc.name/device/gadget/video4linux/video.name/function_name
+Date:          May 2018
+KernelVersion: 4.19
+Description:   UVC configfs function instance name
diff --git a/Documentation/ABI/testing/sysfs-bus-typec b/Documentation/ABI/testing/sysfs-bus-typec
new file mode 100644 (file)
index 0000000..205d9c9
--- /dev/null
@@ -0,0 +1,51 @@
+What:          /sys/bus/typec/devices/.../active
+Date:          July 2018
+Contact:       Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Description:
+               Shows if the mode is active or not. The attribute can be used
+               for entering/exiting the mode. Entering/exiting modes is
+               supported as synchronous operation so write(2) to the attribute
+               does not return until the enter/exit mode operation has
+               finished. The attribute is notified when the mode is
+               entered/exited so poll(2) on the attribute wakes up.
+               Entering/exiting a mode will also generate uevent KOBJ_CHANGE.
+
+               Valid values are boolean.
+
+What:          /sys/bus/typec/devices/.../description
+Date:          July 2018
+Contact:       Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Description:
+               Shows description of the mode. The description is optional for
+               the drivers, just like with the Billboard Devices.
+
+What:          /sys/bus/typec/devices/.../mode
+Date:          July 2018
+Contact:       Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Description:
+               The index number of the mode returned by Discover Modes USB
+               Power Delivery command. Depending on the alternate mode, the
+               mode index may be significant.
+
+               With some alternate modes (SVIDs), the mode index is assigned
+               for specific functionality in the specification for that
+               alternate mode.
+
+               With other alternate modes, the mode index values are not
+               assigned, and can not be therefore used for identification. When
+               the mode index is not assigned, identifying the alternate mode
+               must be done with either mode VDO or the description.
+
+What:          /sys/bus/typec/devices/.../svid
+Date:          July 2018
+Contact:       Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Description:
+               The Standard or Vendor ID (SVID) assigned by USB-IF for this
+               alternate mode.
+
+What:          /sys/bus/typec/devices/.../vdo
+Date:          July 2018
+Contact:       Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Description:
+               Shows the VDO in hexadecimal returned by Discover Modes command
+               for this mode.
index 5be552e..d7647b2 100644 (file)
@@ -222,70 +222,12 @@ Description:
                available. The value can be polled.
 
 
-Alternate Mode devices.
+USB Type-C port alternate mode devices.
 
-The alternate modes will have Standard or Vendor ID (SVID) assigned by USB-IF.
-The ports, partners and cable plugs can have alternate modes. A supported SVID
-will consist of a set of modes. Every SVID a port/partner/plug supports will
-have a device created for it, and every supported mode for a supported SVID will
-have its own directory under that device. Below <dev> refers to the device for
-the alternate mode.
-
-What:          /sys/class/typec/<port|partner|cable>/<dev>/svid
-Date:          April 2017
-Contact:       Heikki Krogerus <heikki.krogerus@linux.intel.com>
-Description:
-               The SVID (Standard or Vendor ID) assigned by USB-IF for this
-               alternate mode.
-
-What:          /sys/class/typec/<port|partner|cable>/<dev>/mode<index>/
-Date:          April 2017
-Contact:       Heikki Krogerus <heikki.krogerus@linux.intel.com>
-Description:
-               Every supported mode will have its own directory. The name of
-               a mode will be "mode<index>" (for example mode1), where <index>
-               is the actual index to the mode VDO returned by Discover Modes
-               USB power delivery command.
-
-What:          /sys/class/typec/<port|partner|cable>/<dev>/mode<index>/description
-Date:          April 2017
-Contact:       Heikki Krogerus <heikki.krogerus@linux.intel.com>
-Description:
-               Shows description of the mode. The description is optional for
-               the drivers, just like with the Billboard Devices.
-
-What:          /sys/class/typec/<port|partner|cable>/<dev>/mode<index>/vdo
-Date:          April 2017
-Contact:       Heikki Krogerus <heikki.krogerus@linux.intel.com>
-Description:
-               Shows the VDO in hexadecimal returned by Discover Modes command
-               for this mode.
-
-What:          /sys/class/typec/<port|partner|cable>/<dev>/mode<index>/active
-Date:          April 2017
-Contact:       Heikki Krogerus <heikki.krogerus@linux.intel.com>
-Description:
-               Shows if the mode is active or not. The attribute can be used
-               for entering/exiting the mode with partners and cable plugs, and
-               with the port alternate modes it can be used for disabling
-               support for specific alternate modes. Entering/exiting modes is
-               supported as synchronous operation so write(2) to the attribute
-               does not return until the enter/exit mode operation has
-               finished. The attribute is notified when the mode is
-               entered/exited so poll(2) on the attribute wakes up.
-               Entering/exiting a mode will also generate uevent KOBJ_CHANGE.
-
-               Valid values: yes, no
-
-What:          /sys/class/typec/<port>/<dev>/mode<index>/supported_roles
+What:          /sys/class/typec/<port>/<alt mode>/supported_roles
 Date:          April 2017
 Contact:       Heikki Krogerus <heikki.krogerus@linux.intel.com>
 Description:
                Space separated list of the supported roles.
 
-               This attribute is available for the devices describing the
-               alternate modes a port supports, and it will not be exposed with
-               the devices presenting the alternate modes the partners or cable
-               plugs support.
-
                Valid values: source, sink
diff --git a/Documentation/ABI/testing/sysfs-driver-typec-displayport b/Documentation/ABI/testing/sysfs-driver-typec-displayport
new file mode 100644 (file)
index 0000000..231471a
--- /dev/null
@@ -0,0 +1,49 @@
+What:          /sys/bus/typec/devices/.../displayport/configuration
+Date:          July 2018
+Contact:       Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Description:
+               Shows the current DisplayPort configuration for the connector.
+               Valid values are USB, source and sink. Source means DisplayPort
+               source, and sink means DisplayPort sink.
+
+               All supported configurations are listed as space separated list
+               with the active one wrapped in square brackets.
+
+               Source example:
+
+                       USB [source] sink
+
+               The configuration can be changed by writing to the file
+
+               Note. USB configuration does not equal to Exit Mode. It is
+               separate configuration defined in VESA DisplayPort Alt Mode on
+               USB Type-C Standard. Functionally it equals to the situation
+               where the mode has been exited (to exit the mode, see
+               Documentation/ABI/testing/sysfs-bus-typec, and use file
+               /sys/bus/typec/devices/.../active).
+
+What:          /sys/bus/typec/devices/.../displayport/pin_assignment
+Date:          July 2018
+Contact:       Heikki Krogerus <heikki.krogerus@linux.intel.com>
+Description:
+               VESA DisplayPort Alt Mode on USB Type-C Standard defines six
+               different pin assignments for USB Type-C connector that are
+               labeled A, B, C, D, E, and F. The supported pin assignments are
+               listed as space separated list with the active one wrapped in
+               square brackets.
+
+               Example:
+
+                       C [D]
+
+               Pin assignment can be changed by writing to the file. It is
+               possible to set pin assignment before configuration has been
+               set, but the assignment will not be active before the
+               connector is actually configured.
+
+               Note. As of VESA DisplayPort Alt Mode on USB Type-C Standard
+               version 1.0b, pin assignments A, B, and F are deprecated. Only
+               pin assignment D can now carry simultaneously one channel of
+               USB SuperSpeed protocol. From user perspective pin assignments C
+               and E are equal, where all channels on the connector are used
+               for carrying DisplayPort protocol (allowing higher resolutions).
index e1463f1..8855bfc 100644 (file)
@@ -15,6 +15,33 @@ Optional properties:
 - type: size of the connector, should be specified in case of USB-A, USB-B
   non-fullsize connectors: "mini", "micro".
 
+Optional properties for usb-c-connector:
+- power-role: should be one of "source", "sink" or "dual"(DRP) if typec
+  connector has power support.
+- try-power-role: preferred power role if "dual"(DRP) can support Try.SNK
+  or Try.SRC, should be "sink" for Try.SNK or "source" for Try.SRC.
+- data-role: should be one of "host", "device", "dual"(DRD) if typec
+  connector supports USB data.
+
+Required properties for usb-c-connector with power delivery support:
+- source-pdos: An array of u32 with each entry providing supported power
+  source data object(PDO), the detailed bit definitions of PDO can be found
+  in "Universal Serial Bus Power Delivery Specification" chapter 6.4.1.2
+  Source_Capabilities Message, the order of each entry(PDO) should follow
+  the PD spec chapter 6.4.1. Required for power source and power dual role.
+  User can specify the source PDO array via PDO_FIXED/BATT/VAR() defined in
+  dt-bindings/usb/pd.h.
+- sink-pdos: An array of u32 with each entry providing supported power
+  sink data object(PDO), the detailed bit definitions of PDO can be found
+  in "Universal Serial Bus Power Delivery Specification" chapter 6.4.1.3
+  Sink Capabilities Message, the order of each entry(PDO) should follow
+  the PD spec chapter 6.4.1. Required for power sink and power dual role.
+  User can specify the sink PDO array via PDO_FIXED/BATT/VAR() defined in
+  dt-bindings/usb/pd.h.
+- op-sink-microwatt: Sink required operating power in microwatt, if source
+  can't offer the power, Capability Mismatch is set. Required for power
+  sink and power dual role.
+
 Required nodes:
 - any data bus to the connector should be modeled using the OF graph bindings
   specified in bindings/graph.txt, unless the bus is between parent node and
@@ -73,3 +100,20 @@ ccic: s2mm005@33 {
                };
        };
 };
+
+3. USB-C connector attached to a typec port controller(ptn5110), which has
+power delivery support and enables drp.
+
+typec: ptn5110@50 {
+       ...
+       usb_con: connector {
+               compatible = "usb-c-connector";
+               label = "USB-C";
+               power-role = "dual";
+               try-power-role = "sink";
+               source-pdos = <PDO_FIXED(5000, 2000, PDO_FIXED_USB_COMM)>;
+               sink-pdos = <PDO_FIXED(5000, 2000, PDO_FIXED_USB_COMM)
+                            PDO_VAR(5000, 12000, 2000)>;
+               op-sink-microwatt = <10000000>;
+       };
+};
diff --git a/Documentation/devicetree/bindings/phy/brcm,sr-pcie-phy.txt b/Documentation/devicetree/bindings/phy/brcm,sr-pcie-phy.txt
new file mode 100644 (file)
index 0000000..e8d8228
--- /dev/null
@@ -0,0 +1,41 @@
+Broadcom Stingray PCIe PHY
+
+Required properties:
+- compatible: must be "brcm,sr-pcie-phy"
+- reg: base address and length of the PCIe SS register space
+- brcm,sr-cdru: phandle to the CDRU syscon node
+- brcm,sr-mhb: phandle to the MHB syscon node
+- #phy-cells: Must be 1, denotes the PHY index
+
+For PAXB based root complex, one can have a configuration of up to 8 PHYs
+PHY index goes from 0 to 7
+
+For the internal PAXC based root complex, PHY index is always 8
+
+Example:
+       mhb: syscon@60401000 {
+               compatible = "brcm,sr-mhb", "syscon";
+               reg = <0 0x60401000 0 0x38c>;
+       };
+
+       cdru: syscon@6641d000 {
+               compatible = "brcm,sr-cdru", "syscon";
+               reg = <0 0x6641d000 0 0x400>;
+       };
+
+       pcie_phy: phy@40000000 {
+               compatible = "brcm,sr-pcie-phy";
+               reg = <0 0x40000000 0 0x800>;
+               brcm,sr-cdru = <&cdru>;
+               brcm,sr-mhb = <&mhb>;
+               #phy-cells = <1>;
+       };
+
+       /* users of the PCIe PHY */
+
+       pcie0: pcie@48000000 {
+               ...
+               ...
+               phys = <&pcie_phy 0>;
+               phy-names = "pcie-phy";
+       };
index 0d34b2b..a5f7a4f 100644 (file)
@@ -47,6 +47,12 @@ Required properties (port (child) node):
                        - PHY_TYPE_PCIE
                        - PHY_TYPE_SATA
 
+Optional properties (PHY_TYPE_USB2 port (child) node):
+- mediatek,eye-src     : u32, the value of slew rate calibrate
+- mediatek,eye-vrt     : u32, the selection of VRT reference voltage
+- mediatek,eye-term    : u32, the selection of HS_TX TERM reference voltage
+- mediatek,bc12        : bool, enable BC12 of u2phy if support it
+
 Example:
 
 u3phy: usb-phy@11290000 {
index 266a1bb..0c7629e 100644 (file)
@@ -12,7 +12,14 @@ Required properties:
               "qcom,sdm845-qmp-usb3-phy" for USB3 QMP V3 phy on sdm845,
               "qcom,sdm845-qmp-usb3-uni-phy" for USB3 QMP V3 UNI phy on sdm845.
 
- - reg: offset and length of register set for PHY's common serdes block.
+ - reg:
+   - For "qcom,sdm845-qmp-usb3-phy":
+     - index 0: address and length of register set for PHY's common serdes
+       block.
+     - named register "dp_com" (using reg-names): address and length of the
+       DP_COM control block.
+   - For all others:
+     - offset and length of register set for PHY's common serdes block.
 
  - #clock-cells: must be 1
     - Phy pll outputs a bunch of clocks for Tx, Rx and Pipe
@@ -60,7 +67,10 @@ Required nodes:
 
 Required properties for child node:
  - reg: list of offset and length pairs of register sets for PHY blocks -
-       tx, rx and pcs.
+       - index 0: tx
+       - index 1: rx
+       - index 2: pcs
+       - index 3: pcs_misc (optional)
 
  - #phy-cells: must be 0
 
diff --git a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-pcie.txt b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-pcie.txt
new file mode 100644 (file)
index 0000000..63853b3
--- /dev/null
@@ -0,0 +1,24 @@
+* Renesas R-Car generation 3 PCIe PHY
+
+This file provides information on what the device node for the R-Car
+generation 3 PCIe PHY contains.
+
+Required properties:
+- compatible: "renesas,r8a77980-pcie-phy" if the device is a part of the
+             R8A77980 SoC.
+- reg: offset and length of the register block.
+- clocks: clock phandle and specifier pair.
+- power-domains: power domain phandle and specifier pair.
+- resets: reset phandle and specifier pair.
+- #phy-cells: see phy-bindings.txt in the same directory, must be <0>.
+
+Example (R-Car V3H):
+
+       pcie-phy@e65d0000 {
+               compatible = "renesas,r8a77980-pcie-phy";
+               reg = <0 0xe65d0000 0 0x8000>;
+               #phy-cells = <0>;
+               clocks = <&cpg CPG_MOD 319>;
+               power-domains = <&sysc 32>;
+               resets = <&cpg 319>;
+       };
index dbd137c..fb4a204 100644 (file)
@@ -10,6 +10,8 @@ Required properties:
              SoC.
              "renesas,usb2-phy-r8a77965" if the device is a part of an
              R8A77965 SoC.
+             "renesas,usb2-phy-r8a77990" if the device is a part of an
+             R8A77990 SoC.
              "renesas,usb2-phy-r8a77995" if the device is a part of an
              R8A77995 SoC.
              "renesas,rcar-gen3-usb2-phy" for a generic R-Car Gen3 compatible device.
index 7f13ebe..3e4c38b 100644 (file)
@@ -96,6 +96,11 @@ Optional properties:
                        enable periodic ESS TX threshold.
 
  - <DEPRECATED> tx-fifo-resize: determines if the FIFO *has* to be reallocated.
+ - snps,incr-burst-type-adjustment: Value for INCR burst type of GSBUSCFG0
+                       register, undefined length INCR burst type enable and INCRx type.
+                       When just one value, which means INCRX burst mode enabled. When
+                       more than one value, which means undefined length INCR burst type
+                       enabled. The values can be 1, 4, 8, 16, 32, 64, 128 and 256.
 
  - in addition all properties from usb-xhci.txt from the current directory are
    supported as well
@@ -108,4 +113,5 @@ dwc3@4a030000 {
        reg = <0x4a030000 0xcfff>;
        interrupts = <0 92 4>
        usb-phy = <&usb2_phy>, <&usb3,phy>;
+       snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
 };
diff --git a/Documentation/devicetree/bindings/usb/npcm7xx-usb.txt b/Documentation/devicetree/bindings/usb/npcm7xx-usb.txt
new file mode 100644 (file)
index 0000000..5a0f1f1
--- /dev/null
@@ -0,0 +1,18 @@
+Nuvoton NPCM7XX SoC USB controllers:
+-----------------------------
+
+EHCI:
+-----
+
+Required properties:
+- compatible: "nuvoton,npcm750-ehci"
+- interrupts: Should contain the EHCI interrupt
+- reg:        Physical address and length of the register set for the device
+
+Example:
+
+       ehci1: usb@f0806000 {
+               compatible = "nuvoton,npcm750-ehci";
+               reg = <0xf0806000 0x1000>;
+               interrupts = <0 61 4>;
+       };
diff --git a/Documentation/devicetree/bindings/usb/typec-tcpci.txt b/Documentation/devicetree/bindings/usb/typec-tcpci.txt
new file mode 100644 (file)
index 0000000..0dd1469
--- /dev/null
@@ -0,0 +1,49 @@
+TCPCI(Typec port cotroller interface) binding
+---------------------------------------------
+
+Required properties:
+- compatible:       should be set one of following:
+                   - "nxp,ptn5110" for NXP USB PD TCPC PHY IC ptn5110.
+
+- reg:              the i2c slave address of typec port controller device.
+- interrupt-parent: the phandle to the interrupt controller which provides
+                    the interrupt.
+- interrupts:       interrupt specification for tcpci alert.
+
+Required sub-node:
+- connector: The "usb-c-connector" attached to the tcpci chip, the bindings
+  of connector node are specified in
+  Documentation/devicetree/bindings/connector/usb-connector.txt
+
+Example:
+
+ptn5110@50 {
+       compatible = "nxp,ptn5110";
+       reg = <0x50>;
+       interrupt-parent = <&gpio3>;
+       interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+
+       usb_con: connector {
+               compatible = "usb-c-connector";
+               label = "USB-C";
+               data-role = "dual";
+               power-role = "dual";
+               try-power-role = "sink";
+               source-pdos = <PDO_FIXED(5000, 2000, PDO_FIXED_USB_COMM)>;
+               sink-pdos = <PDO_FIXED(5000, 2000, PDO_FIXED_USB_COMM)
+                            PDO_VAR(5000, 12000, 2000)>;
+               op-sink-microwatt = <10000000>;
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@1 {
+                               reg = <1>;
+                               usb_con_ss: endpoint {
+                                       remote-endpoint = <&usb3_data_ss>;
+                               };
+                       };
+               };
+       };
+};
index bd1dd31..ac4cd0d 100644 (file)
@@ -14,6 +14,7 @@ Required properties:
     - "renesas,xhci-r8a7795" for r8a7795 SoC
     - "renesas,xhci-r8a7796" for r8a7796 SoC
     - "renesas,xhci-r8a77965" for r8a77965 SoC
+    - "renesas,xhci-r8a77990" for r8a77990 SoC
     - "renesas,rcar-gen2-xhci" for a generic R-Car Gen2 or RZ/G1 compatible
       device
     - "renesas,rcar-gen3-xhci" for a generic R-Car Gen3 compatible device
diff --git a/Documentation/driver-api/usb/typec_bus.rst b/Documentation/driver-api/usb/typec_bus.rst
new file mode 100644 (file)
index 0000000..d5eec17
--- /dev/null
@@ -0,0 +1,136 @@
+
+API for USB Type-C Alternate Mode drivers
+=========================================
+
+Introduction
+------------
+
+Alternate modes require communication with the partner using Vendor Defined
+Messages (VDM) as defined in USB Type-C and USB Power Delivery Specifications.
+The communication is SVID (Standard or Vendor ID) specific, i.e. specific for
+every alternate mode, so every alternate mode will need a custom driver.
+
+USB Type-C bus allows binding a driver to the discovered partner alternate
+modes by using the SVID and the mode number.
+
+USB Type-C Connector Class provides a device for every alternate mode a port
+supports, and separate device for every alternate mode the partner supports.
+The drivers for the alternate modes are bound to the partner alternate mode
+devices, and the port alternate mode devices must be handled by the port
+drivers.
+
+When a new partner alternate mode device is registered, it is linked to the
+alternate mode device of the port that the partner is attached to, that has
+matching SVID and mode. Communication between the port driver and alternate mode
+driver will happen using the same API.
+
+The port alternate mode devices are used as a proxy between the partner and the
+alternate mode drivers, so the port drivers are only expected to pass the SVID
+specific commands from the alternate mode drivers to the partner, and from the
+partners to the alternate mode drivers. No direct SVID specific communication is
+needed from the port drivers, but the port drivers need to provide the operation
+callbacks for the port alternate mode devices, just like the alternate mode
+drivers need to provide them for the partner alternate mode devices.
+
+Usage:
+------
+
+General
+~~~~~~~
+
+By default, the alternate mode drivers are responsible for entering the mode.
+It is also possible to leave the decision about entering the mode to the user
+space (See Documentation/ABI/testing/sysfs-class-typec). Port drivers should not
+enter any modes on their own.
+
+``->vdm`` is the most important callback in the operation callbacks vector. It
+will be used to deliver all the SVID specific commands from the partner to the
+alternate mode driver, and vice versa in case of port drivers. The drivers send
+the SVID specific commands to each other using :c:func:`typec_altmode_vmd()`.
+
+If the communication with the partner using the SVID specific commands results
+in need to reconfigure the pins on the connector, the alternate mode driver
+needs to notify the bus using :c:func:`typec_altmode_notify()`. The driver
+passes the negotiated SVID specific pin configuration value to the function as
+parameter. The bus driver will then configure the mux behind the connector using
+that value as the state value for the mux, and also call blocking notification
+chain to notify the external drivers about the state of the connector that need
+to know it.
+
+NOTE: The SVID specific pin configuration values must always start from
+``TYPEC_STATE_MODAL``. USB Type-C specification defines two default states for
+the connector: ``TYPEC_STATE_USB`` and ``TYPEC_STATE_SAFE``. These values are
+reserved by the bus as the first possible values for the state. When the
+alternate mode is entered, the bus will put the connector into
+``TYPEC_STATE_SAFE`` before sending Enter or Exit Mode command as defined in USB
+Type-C Specification, and also put the connector back to ``TYPEC_STATE_USB``
+after the mode has been exited.
+
+An example of working definitions for SVID specific pin configurations would
+look like this:
+
+enum {
+       ALTMODEX_CONF_A = TYPEC_STATE_MODAL,
+       ALTMODEX_CONF_B,
+       ...
+};
+
+Helper macro ``TYPEC_MODAL_STATE()`` can also be used:
+
+#define ALTMODEX_CONF_A = TYPEC_MODAL_STATE(0);
+#define ALTMODEX_CONF_B = TYPEC_MODAL_STATE(1);
+
+Notification chain
+~~~~~~~~~~~~~~~~~~
+
+The drivers for the components that the alternate modes are designed for need to
+get details regarding the results of the negotiation with the partner, and the
+pin configuration of the connector. In case of DisplayPort alternate mode for
+example, the GPU drivers will need to know those details. In case of
+Thunderbolt alternate mode, the thunderbolt drivers will need to know them, and
+so on.
+
+The notification chain is designed for this purpose. The drivers can register
+notifiers with :c:func:`typec_altmode_register_notifier()`.
+
+Cable plug alternate modes
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The alternate mode drivers are not bound to cable plug alternate mode devices,
+only to the partner alternate mode devices. If the alternate mode supports, or
+requires, a cable that responds to SOP Prime, and optionally SOP Double Prime
+messages, the driver for that alternate mode must request handle to the cable
+plug alternate modes using :c:func:`typec_altmode_get_plug()`, and take over
+their control.
+
+Driver API
+----------
+
+Alternate mode driver registering/unregistering
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. kernel-doc:: drivers/usb/typec/bus.c
+   :functions: typec_altmode_register_driver typec_altmode_unregister_driver
+
+Alternate mode driver operations
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. kernel-doc:: drivers/usb/typec/bus.c
+   :functions: typec_altmode_enter typec_altmode_exit typec_altmode_attention typec_altmode_vdm typec_altmode_notify
+
+API for the port drivers
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. kernel-doc:: drivers/usb/typec/bus.c
+   :functions: typec_match_altmode
+
+Cable Plug operations
+~~~~~~~~~~~~~~~~~~~~~
+
+.. kernel-doc:: drivers/usb/typec/bus.c
+   :functions: typec_altmode_get_plug typec_altmode_put_plug
+
+Notifications
+~~~~~~~~~~~~~
+.. kernel-doc:: drivers/usb/typec/class.c
+   :functions: typec_altmode_register_notifier typec_altmode_unregister_notifier
index 349f310..ab100d6 100644 (file)
@@ -418,15 +418,6 @@ Current status:
   why it is wise to cut down on the rate used is wise for large
   transfers until this is settled.
   
-Options supported:
-  If this driver is compiled as a module you can pass the following
-  options to it:
-  debug                        - extra verbose debugging info
-                         (default: 0; nonzero enables)
-  use_lowlatency       - use low_latency flag to speed up tty layer
-                         when reading from the device.
-                         (default: 0; nonzero enables)
-
   See http://www.uuhaus.de/linux/palmconnect.html for up-to-date
   information on this driver.
 
index e933696..246afc0 100644 (file)
@@ -1665,7 +1665,8 @@ M:        Chunfeng Yun <chunfeng.yun@mediatek.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     linux-mediatek@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
-F:     drivers/phy/mediatek/phy-mtk-tphy.c
+F:     drivers/phy/mediatek/
+F:     Documentation/devicetree/bindings/phy/phy-mtk-*
 
 ARM/MICREL KS8695 ARCHITECTURE
 M:     Greg Ungerer <gerg@uclinux.org>
@@ -15117,7 +15118,7 @@ L:      linux-usb@vger.kernel.org
 S:     Maintained
 F:     drivers/usb/typec/mux/pi3usb30532.c
 
-USB TYPEC SUBSYSTEM
+USB TYPEC CLASS
 M:     Heikki Krogerus <heikki.krogerus@linux.intel.com>
 L:     linux-usb@vger.kernel.org
 S:     Maintained
@@ -15126,6 +15127,15 @@ F:     Documentation/driver-api/usb/typec.rst
 F:     drivers/usb/typec/
 F:     include/linux/usb/typec.h
 
+USB TYPEC BUS FOR ALTERNATE MODES
+M:     Heikki Krogerus <heikki.krogerus@linux.intel.com>
+L:     linux-usb@vger.kernel.org
+S:     Maintained
+F:     Documentation/ABI/testing/sysfs-bus-typec
+F:     Documentation/driver-api/usb/typec_bus.rst
+F:     drivers/usb/typec/altmodes/
+F:     include/linux/usb/typec_altmode.h
+
 USB UHCI DRIVER
 M:     Alan Stern <stern@rowland.harvard.edu>
 L:     linux-usb@vger.kernel.org
@@ -15156,6 +15166,7 @@ L:      linux-usb@vger.kernel.org
 S:     Maintained
 F:     drivers/usb/gadget/function/*uvc*
 F:     drivers/usb/gadget/legacy/webcam.c
+F:     include/uapi/linux/usb/g_uvc.h
 
 USB WIRELESS RNDIS DRIVER (rndis_wlan)
 M:     Jussi Kivilinna <jussi.kivilinna@iki.fi>
index bd35eab..945cc90 100644 (file)
@@ -160,13 +160,14 @@ static void nfcmrvl_tx_complete(struct urb *urb)
        struct nci_dev *ndev = (struct nci_dev *)skb->dev;
        struct nfcmrvl_private *priv = nci_get_drvdata(ndev);
        struct nfcmrvl_usb_drv_data *drv_data = priv->drv_data;
+       unsigned long flags;
 
        nfc_info(priv->dev, "urb %p status %d count %d\n",
                 urb, urb->status, urb->actual_length);
 
-       spin_lock(&drv_data->txlock);
+       spin_lock_irqsave(&drv_data->txlock, flags);
        drv_data->tx_in_flight--;
-       spin_unlock(&drv_data->txlock);
+       spin_unlock_irqrestore(&drv_data->txlock, flags);
 
        kfree(urb->setup_packet);
        kfree_skb(skb);
index 97d27b0..8786a96 100644 (file)
@@ -80,3 +80,13 @@ config PHY_BRCM_USB
          This driver is required by the USB XHCI, EHCI and OHCI
          drivers.
          If unsure, say N.
+
+config PHY_BCM_SR_PCIE
+       tristate "Broadcom Stingray PCIe PHY driver"
+       depends on OF && (ARCH_BCM_IPROC || COMPILE_TEST)
+       select GENERIC_PHY
+       select MFD_SYSCON
+       default ARCH_BCM_IPROC
+       help
+         Enable this to support the Broadcom Stingray PCIe PHY
+         If unsure, say N.
index 13e000c..0f60184 100644 (file)
@@ -9,3 +9,5 @@ obj-$(CONFIG_PHY_BRCM_SATA)             += phy-brcm-sata.o
 obj-$(CONFIG_PHY_BRCM_USB)             += phy-brcm-usb-dvr.o
 
 phy-brcm-usb-dvr-objs := phy-brcm-usb.o phy-brcm-usb-init.o
+
+obj-$(CONFIG_PHY_BCM_SR_PCIE)          += phy-bcm-sr-pcie.o
diff --git a/drivers/phy/broadcom/phy-bcm-sr-pcie.c b/drivers/phy/broadcom/phy-bcm-sr-pcie.c
new file mode 100644 (file)
index 0000000..c10e95f
--- /dev/null
@@ -0,0 +1,305 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2016-2018 Broadcom
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+/* we have up to 8 PAXB based RC. The 9th one is always PAXC */
+#define SR_NR_PCIE_PHYS               9
+#define SR_PAXC_PHY_IDX               (SR_NR_PCIE_PHYS - 1)
+
+#define PCIE_PIPEMUX_CFG_OFFSET       0x10c
+#define PCIE_PIPEMUX_SELECT_STRAP     0xf
+
+#define CDRU_STRAP_DATA_LSW_OFFSET    0x5c
+#define PCIE_PIPEMUX_SHIFT            19
+#define PCIE_PIPEMUX_MASK             0xf
+
+#define MHB_MEM_PW_PAXC_OFFSET        0x1c0
+#define MHB_PWR_ARR_POWERON           0x8
+#define MHB_PWR_ARR_POWEROK           0x4
+#define MHB_PWR_POWERON               0x2
+#define MHB_PWR_POWEROK               0x1
+#define MHB_PWR_STATUS_MASK           (MHB_PWR_ARR_POWERON | \
+                                      MHB_PWR_ARR_POWEROK | \
+                                      MHB_PWR_POWERON | \
+                                      MHB_PWR_POWEROK)
+
+struct sr_pcie_phy_core;
+
+/**
+ * struct sr_pcie_phy - Stingray PCIe PHY
+ *
+ * @core: pointer to the Stingray PCIe PHY core control
+ * @index: PHY index
+ * @phy: pointer to the kernel PHY device
+ */
+struct sr_pcie_phy {
+       struct sr_pcie_phy_core *core;
+       unsigned int index;
+       struct phy *phy;
+};
+
+/**
+ * struct sr_pcie_phy_core - Stingray PCIe PHY core control
+ *
+ * @dev: pointer to device
+ * @base: base register of PCIe SS
+ * @cdru: regmap to the CDRU device
+ * @mhb: regmap to the MHB device
+ * @pipemux: pipemuex strap
+ * @phys: array of PCIe PHYs
+ */
+struct sr_pcie_phy_core {
+       struct device *dev;
+       void __iomem *base;
+       struct regmap *cdru;
+       struct regmap *mhb;
+       u32 pipemux;
+       struct sr_pcie_phy phys[SR_NR_PCIE_PHYS];
+};
+
+/*
+ * PCIe PIPEMUX lookup table
+ *
+ * Each array index represents a PIPEMUX strap setting
+ * The array element represents a bitmap where a set bit means the PCIe
+ * core and associated serdes has been enabled as RC and is available for use
+ */
+static const u8 pipemux_table[] = {
+       /* PIPEMUX = 0, EP 1x16 */
+       0x00,
+       /* PIPEMUX = 1, EP 2x8 */
+       0x00,
+       /* PIPEMUX = 2, EP 4x4 */
+       0x00,
+       /* PIPEMUX = 3, RC 2x8, cores 0, 7 */
+       0x81,
+       /* PIPEMUX = 4, RC 4x4, cores 0, 1, 6, 7 */
+       0xc3,
+       /* PIPEMUX = 5, RC 8x2, all 8 cores */
+       0xff,
+       /* PIPEMUX = 6, RC 3x4 + 2x2, cores 0, 2, 3, 6, 7 */
+       0xcd,
+       /* PIPEMUX = 7, RC 1x4 + 6x2, cores 0, 2, 3, 4, 5, 6, 7 */
+       0xfd,
+       /* PIPEMUX = 8, EP 1x8 + RC 4x2, cores 4, 5, 6, 7 */
+       0xf0,
+       /* PIPEMUX = 9, EP 1x8 + RC 2x4, cores 6, 7 */
+       0xc0,
+       /* PIPEMUX = 10, EP 2x4 + RC 2x4, cores 1, 6 */
+       0x42,
+       /* PIPEMUX = 11, EP 2x4 + RC 4x2, cores 2, 3, 4, 5 */
+       0x3c,
+       /* PIPEMUX = 12, EP 1x4 + RC 6x2, cores 2, 3, 4, 5, 6, 7 */
+       0xfc,
+       /* PIPEMUX = 13, RC 2x4 + RC 1x4 + 2x2, cores 2, 3, 6 */
+       0x4c,
+};
+
+/*
+ * Return true if the strap setting is valid
+ */
+static bool pipemux_strap_is_valid(u32 pipemux)
+{
+       return !!(pipemux < ARRAY_SIZE(pipemux_table));
+}
+
+/*
+ * Read the PCIe PIPEMUX from strap
+ */
+static u32 pipemux_strap_read(struct sr_pcie_phy_core *core)
+{
+       u32 pipemux;
+
+       /*
+        * Read PIPEMUX configuration register to determine the pipemux setting
+        *
+        * In the case when the value indicates using HW strap, fall back to
+        * use HW strap
+        */
+       pipemux = readl(core->base + PCIE_PIPEMUX_CFG_OFFSET);
+       pipemux &= PCIE_PIPEMUX_MASK;
+       if (pipemux == PCIE_PIPEMUX_SELECT_STRAP) {
+               regmap_read(core->cdru, CDRU_STRAP_DATA_LSW_OFFSET, &pipemux);
+               pipemux >>= PCIE_PIPEMUX_SHIFT;
+               pipemux &= PCIE_PIPEMUX_MASK;
+       }
+
+       return pipemux;
+}
+
+/*
+ * Given a PIPEMUX strap and PCIe core index, this function returns true if the
+ * PCIe core needs to be enabled
+ */
+static bool pcie_core_is_for_rc(struct sr_pcie_phy *phy)
+{
+       struct sr_pcie_phy_core *core = phy->core;
+       unsigned int core_idx = phy->index;
+
+       return !!((pipemux_table[core->pipemux] >> core_idx) & 0x1);
+}
+
+static int sr_pcie_phy_init(struct phy *p)
+{
+       struct sr_pcie_phy *phy = phy_get_drvdata(p);
+
+       /*
+        * Check whether this PHY is for root complex or not. If yes, return
+        * zero so the host driver can proceed to enumeration. If not, return
+        * an error and that will force the host driver to bail out
+        */
+       if (pcie_core_is_for_rc(phy))
+               return 0;
+
+       return -ENODEV;
+}
+
+static int sr_paxc_phy_init(struct phy *p)
+{
+       struct sr_pcie_phy *phy = phy_get_drvdata(p);
+       struct sr_pcie_phy_core *core = phy->core;
+       unsigned int core_idx = phy->index;
+       u32 val;
+
+       if (core_idx != SR_PAXC_PHY_IDX)
+               return -EINVAL;
+
+       regmap_read(core->mhb, MHB_MEM_PW_PAXC_OFFSET, &val);
+       if ((val & MHB_PWR_STATUS_MASK) != MHB_PWR_STATUS_MASK) {
+               dev_err(core->dev, "PAXC is not powered up\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static const struct phy_ops sr_pcie_phy_ops = {
+       .init = sr_pcie_phy_init,
+       .owner = THIS_MODULE,
+};
+
+static const struct phy_ops sr_paxc_phy_ops = {
+       .init = sr_paxc_phy_init,
+       .owner = THIS_MODULE,
+};
+
+static struct phy *sr_pcie_phy_xlate(struct device *dev,
+                                    struct of_phandle_args *args)
+{
+       struct sr_pcie_phy_core *core;
+       int phy_idx;
+
+       core = dev_get_drvdata(dev);
+       if (!core)
+               return ERR_PTR(-EINVAL);
+
+       phy_idx = args->args[0];
+
+       if (WARN_ON(phy_idx >= SR_NR_PCIE_PHYS))
+               return ERR_PTR(-ENODEV);
+
+       return core->phys[phy_idx].phy;
+}
+
+static int sr_pcie_phy_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *node = dev->of_node;
+       struct sr_pcie_phy_core *core;
+       struct resource *res;
+       struct phy_provider *provider;
+       unsigned int phy_idx = 0;
+
+       core = devm_kzalloc(dev, sizeof(*core), GFP_KERNEL);
+       if (!core)
+               return -ENOMEM;
+
+       core->dev = dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       core->base = devm_ioremap_resource(core->dev, res);
+       if (IS_ERR(core->base))
+               return PTR_ERR(core->base);
+
+       core->cdru = syscon_regmap_lookup_by_phandle(node, "brcm,sr-cdru");
+       if (IS_ERR(core->cdru)) {
+               dev_err(core->dev, "unable to find CDRU device\n");
+               return PTR_ERR(core->cdru);
+       }
+
+       core->mhb = syscon_regmap_lookup_by_phandle(node, "brcm,sr-mhb");
+       if (IS_ERR(core->mhb)) {
+               dev_err(core->dev, "unable to find MHB device\n");
+               return PTR_ERR(core->mhb);
+       }
+
+       /* read the PCIe PIPEMUX strap setting */
+       core->pipemux = pipemux_strap_read(core);
+       if (!pipemux_strap_is_valid(core->pipemux)) {
+               dev_err(core->dev, "invalid PCIe PIPEMUX strap %u\n",
+                       core->pipemux);
+               return -EIO;
+       }
+
+       for (phy_idx = 0; phy_idx < SR_NR_PCIE_PHYS; phy_idx++) {
+               struct sr_pcie_phy *p = &core->phys[phy_idx];
+               const struct phy_ops *ops;
+
+               if (phy_idx == SR_PAXC_PHY_IDX)
+                       ops = &sr_paxc_phy_ops;
+               else
+                       ops = &sr_pcie_phy_ops;
+
+               p->phy = devm_phy_create(dev, NULL, ops);
+               if (IS_ERR(p->phy)) {
+                       dev_err(dev, "failed to create PCIe PHY\n");
+                       return PTR_ERR(p->phy);
+               }
+
+               p->core = core;
+               p->index = phy_idx;
+               phy_set_drvdata(p->phy, p);
+       }
+
+       dev_set_drvdata(dev, core);
+
+       provider = devm_of_phy_provider_register(dev, sr_pcie_phy_xlate);
+       if (IS_ERR(provider)) {
+               dev_err(dev, "failed to register PHY provider\n");
+               return PTR_ERR(provider);
+       }
+
+       dev_info(dev, "Stingray PCIe PHY driver initialized\n");
+
+       return 0;
+}
+
+static const struct of_device_id sr_pcie_phy_match_table[] = {
+       { .compatible = "brcm,sr-pcie-phy" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, sr_pcie_phy_match_table);
+
+static struct platform_driver sr_pcie_phy_driver = {
+       .driver = {
+               .name           = "sr-pcie-phy",
+               .of_match_table = sr_pcie_phy_match_table,
+       },
+       .probe  = sr_pcie_phy_probe,
+};
+module_platform_driver(sr_pcie_phy_driver);
+
+MODULE_AUTHOR("Ray Jui <ray.jui@broadcom.com>");
+MODULE_DESCRIPTION("Broadcom Stingray PCIe PHY driver");
+MODULE_LICENSE("GPL v2");
index 2c7a57f..c1bb672 100644 (file)
@@ -1,13 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Marvell Berlin SATA PHY driver
  *
  * Copyright (C) 2014 Marvell Technology Group Ltd.
  *
  * Antoine Ténart <antoine.tenart@free-electrons.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
  */
 
 #include <linux/clk.h>
index 8f2b5ca..a43df63 100644 (file)
@@ -1,12 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright (C) 2014 Marvell Technology Group Ltd.
  *
  * Antoine Tenart <antoine.tenart@free-electrons.com>
  * Jisheng Zhang <jszhang@marvell.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
  */
 
 #include <linux/io.h>
index 4ef4292..86a5f7b 100644 (file)
@@ -1,11 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright (C) 2017 Marvell
  *
  * Antoine Tenart <antoine.tenart@free-electrons.com>
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
  */
 
 #include <linux/io.h>
index e5074b6..ee49edc 100644 (file)
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
 #
 # Makefile for the phy drivers.
 #
index 38c281b..3eb8e1b 100644 (file)
@@ -1,16 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright (c) 2015 MediaTek Inc.
  * Author: Chunfeng Yun <chunfeng.yun@mediatek.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 <dt-bindings/phy/phy.h>
 #define PA0_RG_U2PLL_FORCE_ON          BIT(15)
 #define PA0_RG_USB20_INTR_EN           BIT(5)
 
+#define U3P_USBPHYACR1         0x004
+#define PA1_RG_VRT_SEL                 GENMASK(14, 12)
+#define PA1_RG_VRT_SEL_VAL(x)  ((0x7 & (x)) << 12)
+#define PA1_RG_TERM_SEL                GENMASK(10, 8)
+#define PA1_RG_TERM_SEL_VAL(x) ((0x7 & (x)) << 8)
+
 #define U3P_USBPHYACR2         0x008
 #define PA2_RG_SIF_U2PLL_FORCE_EN      BIT(18)
 
 #define P2C_RG_AVALID                  BIT(2)
 #define P2C_RG_IDDIG                   BIT(1)
 
+#define U3P_U2PHYBC12C         0x080
+#define P2C_RG_CHGDT_EN                BIT(0)
+
 #define U3P_U3_CHIP_GPIO_CTLD          0x0c
 #define P3C_REG_IP_SW_RST              BIT(31)
 #define P3C_MCU_BUS_CK_GATE_EN         BIT(30)
@@ -296,6 +297,10 @@ struct mtk_phy_instance {
        struct clk *ref_clk;    /* reference clock of anolog phy */
        u32 index;
        u8 type;
+       int eye_src;
+       int eye_vrt;
+       int eye_term;
+       bool bc12_en;
 };
 
 struct mtk_tphy {
@@ -320,6 +325,10 @@ static void hs_slew_rate_calibrate(struct mtk_tphy *tphy,
        int fm_out;
        u32 tmp;
 
+       /* use force value */
+       if (instance->eye_src)
+               return;
+
        /* enable USB ring oscillator */
        tmp = readl(com + U3P_USBPHYACR5);
        tmp |= PA5_RG_U2_HSTX_SRCAL_EN;
@@ -826,6 +835,61 @@ static void phy_v2_banks_init(struct mtk_tphy *tphy,
        }
 }
 
+static void phy_parse_property(struct mtk_tphy *tphy,
+                               struct mtk_phy_instance *instance)
+{
+       struct device *dev = &instance->phy->dev;
+
+       if (instance->type != PHY_TYPE_USB2)
+               return;
+
+       instance->bc12_en = device_property_read_bool(dev, "mediatek,bc12");
+       device_property_read_u32(dev, "mediatek,eye-src",
+                                &instance->eye_src);
+       device_property_read_u32(dev, "mediatek,eye-vrt",
+                                &instance->eye_vrt);
+       device_property_read_u32(dev, "mediatek,eye-term",
+                                &instance->eye_term);
+       dev_dbg(dev, "bc12:%d, src:%d, vrt:%d, term:%d\n",
+               instance->bc12_en, instance->eye_src,
+               instance->eye_vrt, instance->eye_term);
+}
+
+static void u2_phy_props_set(struct mtk_tphy *tphy,
+                            struct mtk_phy_instance *instance)
+{
+       struct u2phy_banks *u2_banks = &instance->u2_banks;
+       void __iomem *com = u2_banks->com;
+       u32 tmp;
+
+       if (instance->bc12_en) {
+               tmp = readl(com + U3P_U2PHYBC12C);
+               tmp |= P2C_RG_CHGDT_EN; /* BC1.2 path Enable */
+               writel(tmp, com + U3P_U2PHYBC12C);
+       }
+
+       if (instance->eye_src) {
+               tmp = readl(com + U3P_USBPHYACR5);
+               tmp &= ~PA5_RG_U2_HSTX_SRCTRL;
+               tmp |= PA5_RG_U2_HSTX_SRCTRL_VAL(instance->eye_src);
+               writel(tmp, com + U3P_USBPHYACR5);
+       }
+
+       if (instance->eye_vrt) {
+               tmp = readl(com + U3P_USBPHYACR1);
+               tmp &= ~PA1_RG_VRT_SEL;
+               tmp |= PA1_RG_VRT_SEL_VAL(instance->eye_vrt);
+               writel(tmp, com + U3P_USBPHYACR1);
+       }
+
+       if (instance->eye_term) {
+               tmp = readl(com + U3P_USBPHYACR1);
+               tmp &= ~PA1_RG_TERM_SEL;
+               tmp |= PA1_RG_TERM_SEL_VAL(instance->eye_term);
+               writel(tmp, com + U3P_USBPHYACR1);
+       }
+}
+
 static int mtk_phy_init(struct phy *phy)
 {
        struct mtk_phy_instance *instance = phy_get_drvdata(phy);
@@ -847,6 +911,7 @@ static int mtk_phy_init(struct phy *phy)
        switch (instance->type) {
        case PHY_TYPE_USB2:
                u2_phy_instance_init(tphy, instance);
+               u2_phy_props_set(tphy, instance);
                break;
        case PHY_TYPE_USB3:
                u3_phy_instance_init(tphy, instance);
@@ -959,6 +1024,8 @@ static struct phy *mtk_phy_xlate(struct device *dev,
                return ERR_PTR(-EINVAL);
        }
 
+       phy_parse_property(tphy, instance);
+
        return instance->phy;
 }
 
index 2d0c70b..abbbe75 100644 (file)
@@ -55,6 +55,7 @@ static int qcom_usb_hs_phy_set_mode(struct phy *phy, enum phy_mode mode)
                case PHY_MODE_USB_OTG:
                case PHY_MODE_USB_HOST:
                        val |= ULPI_INT_IDGRD;
+                       /* fall through */
                case PHY_MODE_USB_DEVICE:
                        val |= ULPI_INT_SESS_VALID;
                default:
index c845fac..4bd390c 100644 (file)
@@ -8,6 +8,13 @@ config PHY_RCAR_GEN2
        help
          Support for USB PHY found on Renesas R-Car generation 2 SoCs.
 
+config PHY_RCAR_GEN3_PCIE
+       tristate "Renesas R-Car generation 3 PCIe PHY driver"
+       depends on ARCH_RENESAS
+       select GENERIC_PHY
+       help
+         Support for the PCIe PHY found on Renesas R-Car generation 3 SoCs.
+
 config PHY_RCAR_GEN3_USB2
        tristate "Renesas R-Car generation 3 USB 2.0 PHY driver"
        depends on ARCH_RENESAS
index 8b60259..4b76fc4 100644 (file)
@@ -1,3 +1,4 @@
 obj-$(CONFIG_PHY_RCAR_GEN2)            += phy-rcar-gen2.o
+obj-$(CONFIG_PHY_RCAR_GEN3_PCIE)       += phy-rcar-gen3-pcie.o
 obj-$(CONFIG_PHY_RCAR_GEN3_USB2)       += phy-rcar-gen3-usb2.o
 obj-$(CONFIG_PHY_RCAR_GEN3_USB3)       += phy-rcar-gen3-usb3.o
diff --git a/drivers/phy/renesas/phy-rcar-gen3-pcie.c b/drivers/phy/renesas/phy-rcar-gen3-pcie.c
new file mode 100644 (file)
index 0000000..c4e4aa2
--- /dev/null
@@ -0,0 +1,151 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas R-Car Gen3 PCIe PHY driver
+ *
+ * Copyright (C) 2018 Cogent Embedded, Inc.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/phy/phy.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+#define PHY_CTRL               0x4000          /* R8A77980 only */
+
+/* PHY control register (PHY_CTRL) */
+#define PHY_CTRL_PHY_PWDN      BIT(2)
+
+struct rcar_gen3_phy {
+       struct phy *phy;
+       spinlock_t lock;
+       void __iomem *base;
+};
+
+static void rcar_gen3_phy_pcie_modify_reg(struct phy *p, unsigned int reg,
+                                         u32 clear, u32 set)
+{
+       struct rcar_gen3_phy *phy = phy_get_drvdata(p);
+       void __iomem *base = phy->base;
+       unsigned long flags;
+       u32 value;
+
+       spin_lock_irqsave(&phy->lock, flags);
+
+       value = readl(base + reg);
+       value &= ~clear;
+       value |= set;
+       writel(value, base + reg);
+
+       spin_unlock_irqrestore(&phy->lock, flags);
+}
+
+static int r8a77980_phy_pcie_power_on(struct phy *p)
+{
+       /* Power on the PCIe PHY */
+       rcar_gen3_phy_pcie_modify_reg(p, PHY_CTRL, PHY_CTRL_PHY_PWDN, 0);
+
+       return 0;
+}
+
+static int r8a77980_phy_pcie_power_off(struct phy *p)
+{
+       /* Power off the PCIe PHY */
+       rcar_gen3_phy_pcie_modify_reg(p, PHY_CTRL, 0, PHY_CTRL_PHY_PWDN);
+
+       return 0;
+}
+
+static const struct phy_ops r8a77980_phy_pcie_ops = {
+       .power_on       = r8a77980_phy_pcie_power_on,
+       .power_off      = r8a77980_phy_pcie_power_off,
+       .owner          = THIS_MODULE,
+};
+
+static const struct of_device_id rcar_gen3_phy_pcie_match_table[] = {
+       { .compatible = "renesas,r8a77980-pcie-phy" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, rcar_gen3_phy_pcie_match_table);
+
+static int rcar_gen3_phy_pcie_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct phy_provider *provider;
+       struct rcar_gen3_phy *phy;
+       struct resource *res;
+       void __iomem *base;
+       int error;
+
+       if (!dev->of_node) {
+               dev_err(dev,
+                       "This driver must only be instantiated from the device tree\n");
+               return -EINVAL;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
+       if (!phy)
+               return -ENOMEM;
+
+       spin_lock_init(&phy->lock);
+
+       phy->base = base;
+
+       /*
+        * devm_phy_create() will call pm_runtime_enable(&phy->dev);
+        * And then, phy-core will manage runtime PM for this device.
+        */
+       pm_runtime_enable(dev);
+
+       phy->phy = devm_phy_create(dev, NULL, &r8a77980_phy_pcie_ops);
+       if (IS_ERR(phy->phy)) {
+               dev_err(dev, "Failed to create PCIe PHY\n");
+               error = PTR_ERR(phy->phy);
+               goto error;
+       }
+       phy_set_drvdata(phy->phy, phy);
+
+       provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+       if (IS_ERR(provider)) {
+               dev_err(dev, "Failed to register PHY provider\n");
+               error = PTR_ERR(provider);
+               goto error;
+       }
+
+       return 0;
+
+error:
+       pm_runtime_disable(dev);
+
+       return error;
+}
+
+static int rcar_gen3_phy_pcie_remove(struct platform_device *pdev)
+{
+       pm_runtime_disable(&pdev->dev);
+
+       return 0;
+};
+
+static struct platform_driver rcar_gen3_phy_driver = {
+       .driver = {
+               .name           = "phy_rcar_gen3_pcie",
+               .of_match_table = rcar_gen3_phy_pcie_match_table,
+       },
+       .probe  = rcar_gen3_phy_pcie_probe,
+       .remove = rcar_gen3_phy_pcie_remove,
+};
+
+module_platform_driver(rcar_gen3_phy_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Renesas R-Car Gen3 PCIe PHY");
+MODULE_AUTHOR("Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>");
index 75a4804..af9a82f 100644 (file)
@@ -106,8 +106,6 @@ source "drivers/staging/greybus/Kconfig"
 
 source "drivers/staging/vc04_services/Kconfig"
 
-source "drivers/staging/typec/Kconfig"
-
 source "drivers/staging/vboxvideo/Kconfig"
 
 source "drivers/staging/pi433/Kconfig"
index e84959a..8479d47 100644 (file)
@@ -2,7 +2,6 @@
 # Makefile for staging directory
 
 obj-y                          += media/
-obj-y                          += typec/
 obj-$(CONFIG_PRISM2_USB)       += wlan-ng/
 obj-$(CONFIG_COMEDI)           += comedi/
 obj-$(CONFIG_FB_OLPC_DCON)     += olpc_dcon/
diff --git a/drivers/staging/typec/Kconfig b/drivers/staging/typec/Kconfig
deleted file mode 100644 (file)
index e45ed08..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-menu "USB Power Delivery and Type-C drivers"
-
-if TYPEC_TCPM
-
-config TYPEC_TCPCI
-       tristate "Type-C Port Controller Interface driver"
-       depends on I2C
-       select REGMAP_I2C
-       help
-         Type-C Port Controller driver for TCPCI-compliant controller.
-
-config TYPEC_RT1711H
-       tristate "Richtek RT1711H Type-C chip driver"
-       depends on I2C
-       select TYPEC_TCPCI
-       help
-         Richtek RT1711H Type-C chip driver that works with
-         Type-C Port Controller Manager to provide USB PD and USB
-         Type-C functionalities.
-
-endif
-
-endmenu
diff --git a/drivers/staging/typec/Makefile b/drivers/staging/typec/Makefile
deleted file mode 100644 (file)
index 7803d48..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-obj-$(CONFIG_TYPEC_TCPCI)      += tcpci.o
-obj-$(CONFIG_TYPEC_RT1711H)    += tcpci_rt1711h.o
diff --git a/drivers/staging/typec/TODO b/drivers/staging/typec/TODO
deleted file mode 100644 (file)
index 53fe2f7..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-tcpci:
-- Test with real hardware
-
-Please send patches to Guenter Roeck <linux@roeck-us.net> and copy
-Heikki Krogerus <heikki.krogerus@linux.intel.com>.
index 7f4d2b6..772851b 100644 (file)
@@ -33,11 +33,11 @@ static const struct tegra_udc_soc_info tegra30_udc_soc_info = {
 };
 
 static const struct tegra_udc_soc_info tegra114_udc_soc_info = {
-       .flags = 0,
+       .flags = CI_HDRC_REQUIRES_ALIGNED_DMA,
 };
 
 static const struct tegra_udc_soc_info tegra124_udc_soc_info = {
-       .flags = 0,
+       .flags = CI_HDRC_REQUIRES_ALIGNED_DMA,
 };
 
 static const struct of_device_id tegra_udc_of_match[] = {
index 75c4623..27346d6 100644 (file)
@@ -276,6 +276,7 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf)
 {
        int newctrl;
        int difference;
+       unsigned long flags;
        struct usb_cdc_notification *dr = (struct usb_cdc_notification *)buf;
        unsigned char *data = buf + sizeof(struct usb_cdc_notification);
 
@@ -303,7 +304,7 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf)
                }
 
                difference = acm->ctrlin ^ newctrl;
-               spin_lock(&acm->read_lock);
+               spin_lock_irqsave(&acm->read_lock, flags);
                acm->ctrlin = newctrl;
                acm->oldcount = acm->iocount;
 
@@ -321,7 +322,7 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf)
                        acm->iocount.parity++;
                if (difference & ACM_CTRL_OVERRUN)
                        acm->iocount.overrun++;
-               spin_unlock(&acm->read_lock);
+               spin_unlock_irqrestore(&acm->read_lock, flags);
 
                if (difference)
                        wake_up_all(&acm->wioctl);
@@ -1378,6 +1379,9 @@ made_compressed_probe:
        if (acm == NULL)
                goto alloc_fail;
 
+       tty_port_init(&acm->port);
+       acm->port.ops = &acm_port_ops;
+
        minor = acm_alloc_minor(acm);
        if (minor < 0)
                goto alloc_fail1;
@@ -1413,22 +1417,20 @@ made_compressed_probe:
                acm->out = usb_sndintpipe(usb_dev, epwrite->bEndpointAddress);
        else
                acm->out = usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress);
-       tty_port_init(&acm->port);
-       acm->port.ops = &acm_port_ops;
        init_usb_anchor(&acm->delayed);
        acm->quirks = quirks;
 
        buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
        if (!buf)
-               goto alloc_fail2;
+               goto alloc_fail1;
        acm->ctrl_buffer = buf;
 
        if (acm_write_buffers_alloc(acm) < 0)
-               goto alloc_fail4;
+               goto alloc_fail2;
 
        acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
        if (!acm->ctrlurb)
-               goto alloc_fail5;
+               goto alloc_fail3;
 
        for (i = 0; i < num_rx_buf; i++) {
                struct acm_rb *rb = &(acm->read_buffers[i]);
@@ -1437,13 +1439,13 @@ made_compressed_probe:
                rb->base = usb_alloc_coherent(acm->dev, readsize, GFP_KERNEL,
                                                                &rb->dma);
                if (!rb->base)
-                       goto alloc_fail6;
+                       goto alloc_fail4;
                rb->index = i;
                rb->instance = acm;
 
                urb = usb_alloc_urb(0, GFP_KERNEL);
                if (!urb)
-                       goto alloc_fail6;
+                       goto alloc_fail4;
 
                urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
                urb->transfer_dma = rb->dma;
@@ -1465,7 +1467,7 @@ made_compressed_probe:
 
                snd->urb = usb_alloc_urb(0, GFP_KERNEL);
                if (snd->urb == NULL)
-                       goto alloc_fail7;
+                       goto alloc_fail5;
 
                if (usb_endpoint_xfer_int(epwrite))
                        usb_fill_int_urb(snd->urb, usb_dev, acm->out,
@@ -1483,7 +1485,7 @@ made_compressed_probe:
 
        i = device_create_file(&intf->dev, &dev_attr_bmCapabilities);
        if (i < 0)
-               goto alloc_fail7;
+               goto alloc_fail5;
 
        if (h.usb_cdc_country_functional_desc) { /* export the country data */
                struct usb_cdc_country_functional_desc * cfd =
@@ -1542,7 +1544,7 @@ skip_countries:
                        &control_interface->dev);
        if (IS_ERR(tty_dev)) {
                rv = PTR_ERR(tty_dev);
-               goto alloc_fail8;
+               goto alloc_fail6;
        }
 
        if (quirks & CLEAR_HALT_CONDITIONS) {
@@ -1551,7 +1553,7 @@ skip_countries:
        }
 
        return 0;
-alloc_fail8:
+alloc_fail6:
        if (acm->country_codes) {
                device_remove_file(&acm->control->dev,
                                &dev_attr_wCountryCodes);
@@ -1560,23 +1562,21 @@ alloc_fail8:
                kfree(acm->country_codes);
        }
        device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities);
-alloc_fail7:
+alloc_fail5:
        usb_set_intfdata(intf, NULL);
        for (i = 0; i < ACM_NW; i++)
                usb_free_urb(acm->wb[i].urb);
-alloc_fail6:
+alloc_fail4:
        for (i = 0; i < num_rx_buf; i++)
                usb_free_urb(acm->read_urbs[i]);
        acm_read_buffers_free(acm);
        usb_free_urb(acm->ctrlurb);
-alloc_fail5:
+alloc_fail3:
        acm_write_buffers_free(acm);
-alloc_fail4:
-       usb_free_coherent(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
 alloc_fail2:
-       acm_release_minor(acm);
+       usb_free_coherent(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
 alloc_fail1:
-       kfree(acm);
+       tty_port_put(&acm->port);
 alloc_fail:
        return rv;
 }
index a0d284e..bec581f 100644 (file)
@@ -96,6 +96,7 @@ struct wdm_device {
        struct mutex            rlock;
        wait_queue_head_t       wait;
        struct work_struct      rxwork;
+       struct work_struct      service_outs_intr;
        int                     werr;
        int                     rerr;
        int                     resp_count;
@@ -141,26 +142,26 @@ found:
 static void wdm_out_callback(struct urb *urb)
 {
        struct wdm_device *desc;
+       unsigned long flags;
+
        desc = urb->context;
-       spin_lock(&desc->iuspin);
+       spin_lock_irqsave(&desc->iuspin, flags);
        desc->werr = urb->status;
-       spin_unlock(&desc->iuspin);
+       spin_unlock_irqrestore(&desc->iuspin, flags);
        kfree(desc->outbuf);
        desc->outbuf = NULL;
        clear_bit(WDM_IN_USE, &desc->flags);
        wake_up(&desc->wait);
 }
 
-/* forward declaration */
-static int service_outstanding_interrupt(struct wdm_device *desc);
-
 static void wdm_in_callback(struct urb *urb)
 {
+       unsigned long flags;
        struct wdm_device *desc = urb->context;
        int status = urb->status;
        int length = urb->actual_length;
 
-       spin_lock(&desc->iuspin);
+       spin_lock_irqsave(&desc->iuspin, flags);
        clear_bit(WDM_RESPONDING, &desc->flags);
 
        if (status) {
@@ -209,8 +210,6 @@ static void wdm_in_callback(struct urb *urb)
                }
        }
 skip_error:
-       set_bit(WDM_READ, &desc->flags);
-       wake_up(&desc->wait);
 
        if (desc->rerr) {
                /*
@@ -219,14 +218,17 @@ skip_error:
                 * We should respond to further attempts from the device to send
                 * data, so that we can get unstuck.
                 */
-               service_outstanding_interrupt(desc);
+               schedule_work(&desc->service_outs_intr);
+       } else {
+               set_bit(WDM_READ, &desc->flags);
+               wake_up(&desc->wait);
        }
-
-       spin_unlock(&desc->iuspin);
+       spin_unlock_irqrestore(&desc->iuspin, flags);
 }
 
 static void wdm_int_callback(struct urb *urb)
 {
+       unsigned long flags;
        int rv = 0;
        int responding;
        int status = urb->status;
@@ -286,7 +288,7 @@ static void wdm_int_callback(struct urb *urb)
                goto exit;
        }
 
-       spin_lock(&desc->iuspin);
+       spin_lock_irqsave(&desc->iuspin, flags);
        responding = test_and_set_bit(WDM_RESPONDING, &desc->flags);
        if (!desc->resp_count++ && !responding
                && !test_bit(WDM_DISCONNECTING, &desc->flags)
@@ -294,7 +296,7 @@ static void wdm_int_callback(struct urb *urb)
                rv = usb_submit_urb(desc->response, GFP_ATOMIC);
                dev_dbg(&desc->intf->dev, "submit response URB %d\n", rv);
        }
-       spin_unlock(&desc->iuspin);
+       spin_unlock_irqrestore(&desc->iuspin, flags);
        if (rv < 0) {
                clear_bit(WDM_RESPONDING, &desc->flags);
                if (rv == -EPERM)
@@ -758,6 +760,21 @@ static void wdm_rxwork(struct work_struct *work)
        }
 }
 
+static void service_interrupt_work(struct work_struct *work)
+{
+       struct wdm_device *desc;
+
+       desc = container_of(work, struct wdm_device, service_outs_intr);
+
+       spin_lock_irq(&desc->iuspin);
+       service_outstanding_interrupt(desc);
+       if (!desc->resp_count) {
+               set_bit(WDM_READ, &desc->flags);
+               wake_up(&desc->wait);
+       }
+       spin_unlock_irq(&desc->iuspin);
+}
+
 /* --- hotplug --- */
 
 static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor *ep,
@@ -779,6 +796,7 @@ static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor
        desc->inum = cpu_to_le16((u16)intf->cur_altsetting->desc.bInterfaceNumber);
        desc->intf = intf;
        INIT_WORK(&desc->rxwork, wdm_rxwork);
+       INIT_WORK(&desc->service_outs_intr, service_interrupt_work);
 
        rv = -EINVAL;
        if (!usb_endpoint_is_int_in(ep))
@@ -964,6 +982,7 @@ static void wdm_disconnect(struct usb_interface *intf)
        mutex_lock(&desc->wlock);
        kill_urbs(desc);
        cancel_work_sync(&desc->rxwork);
+       cancel_work_sync(&desc->service_outs_intr);
        mutex_unlock(&desc->wlock);
        mutex_unlock(&desc->rlock);
 
@@ -1006,6 +1025,7 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message)
                /* callback submits work - order is essential */
                kill_urbs(desc);
                cancel_work_sync(&desc->rxwork);
+               cancel_work_sync(&desc->service_outs_intr);
        }
        if (!PMSG_IS_AUTO(message)) {
                mutex_unlock(&desc->wlock);
@@ -1065,6 +1085,7 @@ static int wdm_pre_reset(struct usb_interface *intf)
        mutex_lock(&desc->wlock);
        kill_urbs(desc);
        cancel_work_sync(&desc->rxwork);
+       cancel_work_sync(&desc->service_outs_intr);
        return 0;
 }
 
index d058d7a..407a7a6 100644 (file)
@@ -292,6 +292,7 @@ static void usblp_bulk_read(struct urb *urb)
 {
        struct usblp *usblp = urb->context;
        int status = urb->status;
+       unsigned long flags;
 
        if (usblp->present && usblp->used) {
                if (status)
@@ -299,14 +300,14 @@ static void usblp_bulk_read(struct urb *urb)
                            "nonzero read bulk status received: %d\n",
                            usblp->minor, status);
        }
-       spin_lock(&usblp->lock);
+       spin_lock_irqsave(&usblp->lock, flags);
        if (status < 0)
                usblp->rstatus = status;
        else
                usblp->rstatus = urb->actual_length;
        usblp->rcomplete = 1;
        wake_up(&usblp->rwait);
-       spin_unlock(&usblp->lock);
+       spin_unlock_irqrestore(&usblp->lock, flags);
 
        usb_free_urb(urb);
 }
@@ -315,6 +316,7 @@ static void usblp_bulk_write(struct urb *urb)
 {
        struct usblp *usblp = urb->context;
        int status = urb->status;
+       unsigned long flags;
 
        if (usblp->present && usblp->used) {
                if (status)
@@ -322,7 +324,7 @@ static void usblp_bulk_write(struct urb *urb)
                            "nonzero write bulk status received: %d\n",
                            usblp->minor, status);
        }
-       spin_lock(&usblp->lock);
+       spin_lock_irqsave(&usblp->lock, flags);
        if (status < 0)
                usblp->wstatus = status;
        else
@@ -330,7 +332,7 @@ static void usblp_bulk_write(struct urb *urb)
        usblp->no_paper = 0;
        usblp->wcomplete = 1;
        wake_up(&usblp->wwait);
-       spin_unlock(&usblp->lock);
+       spin_unlock_irqrestore(&usblp->lock, flags);
 
        usb_free_urb(urb);
 }
index 529295a..83ffa5a 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/poll.h>
 #include <linux/mutex.h>
 #include <linux/usb.h>
+#include <linux/compat.h>
 #include <linux/usb/tmc.h>
 
 
@@ -30,6 +31,8 @@
  */
 #define USBTMC_SIZE_IOBUFFER   2048
 
+/* Minimum USB timeout (in milliseconds) */
+#define USBTMC_MIN_TIMEOUT     100
 /* Default USB timeout (in milliseconds) */
 #define USBTMC_TIMEOUT         5000
 
@@ -67,6 +70,7 @@ struct usbtmc_device_data {
        const struct usb_device_id *id;
        struct usb_device *usb_dev;
        struct usb_interface *intf;
+       struct list_head file_list;
 
        unsigned int bulk_in;
        unsigned int bulk_out;
@@ -87,7 +91,6 @@ struct usbtmc_device_data {
        int            iin_interval;
        struct urb    *iin_urb;
        u16            iin_wMaxPacketSize;
-       atomic_t       srq_asserted;
 
        /* coalesced usb488_caps from usbtmc_dev_capabilities */
        __u8 usb488_caps;
@@ -104,9 +107,25 @@ struct usbtmc_device_data {
        struct mutex io_mutex;  /* only one i/o function running at a time */
        wait_queue_head_t waitq;
        struct fasync_struct *fasync;
+       spinlock_t dev_lock; /* lock for file_list */
 };
 #define to_usbtmc_data(d) container_of(d, struct usbtmc_device_data, kref)
 
+/*
+ * This structure holds private data for each USBTMC file handle.
+ */
+struct usbtmc_file_data {
+       struct usbtmc_device_data *data;
+       struct list_head file_elem;
+
+       u32            timeout;
+       u8             srq_byte;
+       atomic_t       srq_asserted;
+       u8             eom_val;
+       u8             term_char;
+       bool           term_char_enabled;
+};
+
 /* Forward declarations */
 static struct usb_driver usbtmc_driver;
 
@@ -122,7 +141,7 @@ static int usbtmc_open(struct inode *inode, struct file *filp)
 {
        struct usb_interface *intf;
        struct usbtmc_device_data *data;
-       int retval = 0;
+       struct usbtmc_file_data *file_data;
 
        intf = usb_find_interface(&usbtmc_driver, iminor(inode));
        if (!intf) {
@@ -130,21 +149,51 @@ static int usbtmc_open(struct inode *inode, struct file *filp)
                return -ENODEV;
        }
 
+       file_data = kzalloc(sizeof(*file_data), GFP_KERNEL);
+       if (!file_data)
+               return -ENOMEM;
+
        data = usb_get_intfdata(intf);
        /* Protect reference to data from file structure until release */
        kref_get(&data->kref);
 
+       mutex_lock(&data->io_mutex);
+       file_data->data = data;
+
+       /* copy default values from device settings */
+       file_data->timeout = USBTMC_TIMEOUT;
+       file_data->term_char = data->TermChar;
+       file_data->term_char_enabled = data->TermCharEnabled;
+       file_data->eom_val = 1;
+
+       INIT_LIST_HEAD(&file_data->file_elem);
+       spin_lock_irq(&data->dev_lock);
+       list_add_tail(&file_data->file_elem, &data->file_list);
+       spin_unlock_irq(&data->dev_lock);
+       mutex_unlock(&data->io_mutex);
+
        /* Store pointer in file structure's private data field */
-       filp->private_data = data;
+       filp->private_data = file_data;
 
-       return retval;
+       return 0;
 }
 
 static int usbtmc_release(struct inode *inode, struct file *file)
 {
-       struct usbtmc_device_data *data = file->private_data;
+       struct usbtmc_file_data *file_data = file->private_data;
 
-       kref_put(&data->kref, usbtmc_delete);
+       /* prevent IO _AND_ usbtmc_interrupt */
+       mutex_lock(&file_data->data->io_mutex);
+       spin_lock_irq(&file_data->data->dev_lock);
+
+       list_del(&file_data->file_elem);
+
+       spin_unlock_irq(&file_data->data->dev_lock);
+       mutex_unlock(&file_data->data->io_mutex);
+
+       kref_put(&file_data->data->kref, usbtmc_delete);
+       file_data->data = NULL;
+       kfree(file_data);
        return 0;
 }
 
@@ -369,10 +418,12 @@ exit:
        return rv;
 }
 
-static int usbtmc488_ioctl_read_stb(struct usbtmc_device_data *data,
+static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data,
                                void __user *arg)
 {
+       struct usbtmc_device_data *data = file_data->data;
        struct device *dev = &data->intf->dev;
+       int srq_asserted = 0;
        u8 *buffer;
        u8 tag;
        __u8 stb;
@@ -381,15 +432,25 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_device_data *data,
        dev_dbg(dev, "Enter ioctl_read_stb iin_ep_present: %d\n",
                data->iin_ep_present);
 
+       spin_lock_irq(&data->dev_lock);
+       srq_asserted = atomic_xchg(&file_data->srq_asserted, srq_asserted);
+       if (srq_asserted) {
+               /* a STB with SRQ is already received */
+               stb = file_data->srq_byte;
+               spin_unlock_irq(&data->dev_lock);
+               rv = put_user(stb, (__u8 __user *)arg);
+               dev_dbg(dev, "stb:0x%02x with srq received %d\n",
+                       (unsigned int)stb, rv);
+               return rv;
+       }
+       spin_unlock_irq(&data->dev_lock);
+
        buffer = kmalloc(8, GFP_KERNEL);
        if (!buffer)
                return -ENOMEM;
 
        atomic_set(&data->iin_data_valid, 0);
 
-       /* must issue read_stb before using poll or select */
-       atomic_set(&data->srq_asserted, 0);
-
        rv = usb_control_msg(data->usb_dev,
                        usb_rcvctrlpipe(data->usb_dev, 0),
                        USBTMC488_REQUEST_READ_STATUS_BYTE,
@@ -412,7 +473,7 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_device_data *data,
                rv = wait_event_interruptible_timeout(
                        data->waitq,
                        atomic_read(&data->iin_data_valid) != 0,
-                       USBTMC_TIMEOUT);
+                       file_data->timeout);
                if (rv < 0) {
                        dev_dbg(dev, "wait interrupted %d\n", rv);
                        goto exit;
@@ -420,7 +481,7 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_device_data *data,
 
                if (rv == 0) {
                        dev_dbg(dev, "wait timed out\n");
-                       rv = -ETIME;
+                       rv = -ETIMEDOUT;
                        goto exit;
                }
 
@@ -435,9 +496,8 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_device_data *data,
                stb = buffer[2];
        }
 
-       rv = copy_to_user(arg, &stb, sizeof(stb));
-       if (rv)
-               rv = -EFAULT;
+       rv = put_user(stb, (__u8 __user *)arg);
+       dev_dbg(dev, "stb:0x%02x received %d\n", (unsigned int)stb, rv);
 
  exit:
        /* bump interrupt bTag */
@@ -506,6 +566,51 @@ static int usbtmc488_ioctl_simple(struct usbtmc_device_data *data,
 }
 
 /*
+ * Sends a TRIGGER Bulk-OUT command message
+ * See the USBTMC-USB488 specification, Table 2.
+ *
+ * Also updates bTag_last_write.
+ */
+static int usbtmc488_ioctl_trigger(struct usbtmc_file_data *file_data)
+{
+       struct usbtmc_device_data *data = file_data->data;
+       int retval;
+       u8 *buffer;
+       int actual;
+
+       buffer = kzalloc(USBTMC_HEADER_SIZE, GFP_KERNEL);
+       if (!buffer)
+               return -ENOMEM;
+
+       buffer[0] = 128;
+       buffer[1] = data->bTag;
+       buffer[2] = ~data->bTag;
+
+       retval = usb_bulk_msg(data->usb_dev,
+                             usb_sndbulkpipe(data->usb_dev,
+                                             data->bulk_out),
+                             buffer, USBTMC_HEADER_SIZE,
+                             &actual, file_data->timeout);
+
+       /* Store bTag (in case we need to abort) */
+       data->bTag_last_write = data->bTag;
+
+       /* Increment bTag -- and increment again if zero */
+       data->bTag++;
+       if (!data->bTag)
+               data->bTag++;
+
+       kfree(buffer);
+       if (retval < 0) {
+               dev_err(&data->intf->dev, "%s returned %d\n",
+                       __func__, retval);
+               return retval;
+       }
+
+       return 0;
+}
+
+/*
  * Sends a REQUEST_DEV_DEP_MSG_IN message on the Bulk-OUT endpoint.
  * @transfer_size: number of bytes to request from the device.
  *
@@ -513,8 +618,10 @@ static int usbtmc488_ioctl_simple(struct usbtmc_device_data *data,
  *
  * Also updates bTag_last_write.
  */
-static int send_request_dev_dep_msg_in(struct usbtmc_device_data *data, size_t transfer_size)
+static int send_request_dev_dep_msg_in(struct usbtmc_file_data *file_data,
+                                      size_t transfer_size)
 {
+       struct usbtmc_device_data *data = file_data->data;
        int retval;
        u8 *buffer;
        int actual;
@@ -533,9 +640,9 @@ static int send_request_dev_dep_msg_in(struct usbtmc_device_data *data, size_t t
        buffer[5] = transfer_size >> 8;
        buffer[6] = transfer_size >> 16;
        buffer[7] = transfer_size >> 24;
-       buffer[8] = data->TermCharEnabled * 2;
+       buffer[8] = file_data->term_char_enabled * 2;
        /* Use term character? */
-       buffer[9] = data->TermChar;
+       buffer[9] = file_data->term_char;
        buffer[10] = 0; /* Reserved */
        buffer[11] = 0; /* Reserved */
 
@@ -543,7 +650,8 @@ static int send_request_dev_dep_msg_in(struct usbtmc_device_data *data, size_t t
        retval = usb_bulk_msg(data->usb_dev,
                              usb_sndbulkpipe(data->usb_dev,
                                              data->bulk_out),
-                             buffer, USBTMC_HEADER_SIZE, &actual, USBTMC_TIMEOUT);
+                             buffer, USBTMC_HEADER_SIZE,
+                             &actual, file_data->timeout);
 
        /* Store bTag (in case we need to abort) */
        data->bTag_last_write = data->bTag;
@@ -565,6 +673,7 @@ static int send_request_dev_dep_msg_in(struct usbtmc_device_data *data, size_t t
 static ssize_t usbtmc_read(struct file *filp, char __user *buf,
                           size_t count, loff_t *f_pos)
 {
+       struct usbtmc_file_data *file_data;
        struct usbtmc_device_data *data;
        struct device *dev;
        u32 n_characters;
@@ -576,7 +685,8 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
        size_t this_part;
 
        /* Get pointer to private data structure */
-       data = filp->private_data;
+       file_data = filp->private_data;
+       data = file_data->data;
        dev = &data->intf->dev;
 
        buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL);
@@ -591,7 +701,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
 
        dev_dbg(dev, "usb_bulk_msg_in: count(%zu)\n", count);
 
-       retval = send_request_dev_dep_msg_in(data, count);
+       retval = send_request_dev_dep_msg_in(file_data, count);
 
        if (retval < 0) {
                if (data->auto_abort)
@@ -610,7 +720,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
                                      usb_rcvbulkpipe(data->usb_dev,
                                                      data->bulk_in),
                                      buffer, USBTMC_SIZE_IOBUFFER, &actual,
-                                     USBTMC_TIMEOUT);
+                                     file_data->timeout);
 
                dev_dbg(dev, "usb_bulk_msg: retval(%u), done(%zu), remaining(%zu), actual(%d)\n", retval, done, remaining, actual);
 
@@ -721,6 +831,7 @@ exit:
 static ssize_t usbtmc_write(struct file *filp, const char __user *buf,
                            size_t count, loff_t *f_pos)
 {
+       struct usbtmc_file_data *file_data;
        struct usbtmc_device_data *data;
        u8 *buffer;
        int retval;
@@ -730,7 +841,8 @@ static ssize_t usbtmc_write(struct file *filp, const char __user *buf,
        int done;
        int this_part;
 
-       data = filp->private_data;
+       file_data = filp->private_data;
+       data = file_data->data;
 
        buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL);
        if (!buffer)
@@ -751,7 +863,7 @@ static ssize_t usbtmc_write(struct file *filp, const char __user *buf,
                        buffer[8] = 0;
                } else {
                        this_part = remaining;
-                       buffer[8] = 1;
+                       buffer[8] = file_data->eom_val;
                }
 
                /* Setup IO buffer for DEV_DEP_MSG_OUT message */
@@ -781,7 +893,7 @@ static ssize_t usbtmc_write(struct file *filp, const char __user *buf,
                                              usb_sndbulkpipe(data->usb_dev,
                                                              data->bulk_out),
                                              buffer, n_bytes,
-                                             &actual, USBTMC_TIMEOUT);
+                                             &actual, file_data->timeout);
                        if (retval != 0)
                                break;
                        n_bytes -= actual;
@@ -1138,12 +1250,91 @@ exit:
        return rv;
 }
 
+/*
+ * Get the usb timeout value
+ */
+static int usbtmc_ioctl_get_timeout(struct usbtmc_file_data *file_data,
+                               void __user *arg)
+{
+       u32 timeout;
+
+       timeout = file_data->timeout;
+
+       return put_user(timeout, (__u32 __user *)arg);
+}
+
+/*
+ * Set the usb timeout value
+ */
+static int usbtmc_ioctl_set_timeout(struct usbtmc_file_data *file_data,
+                               void __user *arg)
+{
+       u32 timeout;
+
+       if (get_user(timeout, (__u32 __user *)arg))
+               return -EFAULT;
+
+       /* Note that timeout = 0 means
+        * MAX_SCHEDULE_TIMEOUT in usb_control_msg
+        */
+       if (timeout < USBTMC_MIN_TIMEOUT)
+               return -EINVAL;
+
+       file_data->timeout = timeout;
+
+       return 0;
+}
+
+/*
+ * enables/disables sending EOM on write
+ */
+static int usbtmc_ioctl_eom_enable(struct usbtmc_file_data *file_data,
+                               void __user *arg)
+{
+       u8 eom_enable;
+
+       if (copy_from_user(&eom_enable, arg, sizeof(eom_enable)))
+               return -EFAULT;
+
+       if (eom_enable > 1)
+               return -EINVAL;
+
+       file_data->eom_val = eom_enable;
+
+       return 0;
+}
+
+/*
+ * Configure termination character for read()
+ */
+static int usbtmc_ioctl_config_termc(struct usbtmc_file_data *file_data,
+                               void __user *arg)
+{
+       struct usbtmc_termchar termc;
+
+       if (copy_from_user(&termc, arg, sizeof(termc)))
+               return -EFAULT;
+
+       if ((termc.term_char_enabled > 1) ||
+               (termc.term_char_enabled &&
+               !(file_data->data->capabilities.device_capabilities & 1)))
+               return -EINVAL;
+
+       file_data->term_char = termc.term_char;
+       file_data->term_char_enabled = termc.term_char_enabled;
+
+       return 0;
+}
+
 static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
+       struct usbtmc_file_data *file_data;
        struct usbtmc_device_data *data;
        int retval = -EBADRQC;
 
-       data = file->private_data;
+       file_data = file->private_data;
+       data = file_data->data;
+
        mutex_lock(&data->io_mutex);
        if (data->zombie) {
                retval = -ENODEV;
@@ -1175,6 +1366,26 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                retval = usbtmc_ioctl_abort_bulk_in(data);
                break;
 
+       case USBTMC_IOCTL_GET_TIMEOUT:
+               retval = usbtmc_ioctl_get_timeout(file_data,
+                                                 (void __user *)arg);
+               break;
+
+       case USBTMC_IOCTL_SET_TIMEOUT:
+               retval = usbtmc_ioctl_set_timeout(file_data,
+                                                 (void __user *)arg);
+               break;
+
+       case USBTMC_IOCTL_EOM_ENABLE:
+               retval = usbtmc_ioctl_eom_enable(file_data,
+                                                (void __user *)arg);
+               break;
+
+       case USBTMC_IOCTL_CONFIG_TERMCHAR:
+               retval = usbtmc_ioctl_config_termc(file_data,
+                                                  (void __user *)arg);
+               break;
+
        case USBTMC488_IOCTL_GET_CAPS:
                retval = copy_to_user((void __user *)arg,
                                &data->usb488_caps,
@@ -1184,7 +1395,8 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                break;
 
        case USBTMC488_IOCTL_READ_STB:
-               retval = usbtmc488_ioctl_read_stb(data, (void __user *)arg);
+               retval = usbtmc488_ioctl_read_stb(file_data,
+                                                 (void __user *)arg);
                break;
 
        case USBTMC488_IOCTL_REN_CONTROL:
@@ -1201,6 +1413,10 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                retval = usbtmc488_ioctl_simple(data, (void __user *)arg,
                                                USBTMC488_REQUEST_LOCAL_LOCKOUT);
                break;
+
+       case USBTMC488_IOCTL_TRIGGER:
+               retval = usbtmc488_ioctl_trigger(file_data);
+               break;
        }
 
 skip_io_on_zombie:
@@ -1210,14 +1426,15 @@ skip_io_on_zombie:
 
 static int usbtmc_fasync(int fd, struct file *file, int on)
 {
-       struct usbtmc_device_data *data = file->private_data;
+       struct usbtmc_file_data *file_data = file->private_data;
 
-       return fasync_helper(fd, file, on, &data->fasync);
+       return fasync_helper(fd, file, on, &file_data->data->fasync);
 }
 
 static __poll_t usbtmc_poll(struct file *file, poll_table *wait)
 {
-       struct usbtmc_device_data *data = file->private_data;
+       struct usbtmc_file_data *file_data = file->private_data;
+       struct usbtmc_device_data *data = file_data->data;
        __poll_t mask;
 
        mutex_lock(&data->io_mutex);
@@ -1229,7 +1446,7 @@ static __poll_t usbtmc_poll(struct file *file, poll_table *wait)
 
        poll_wait(file, &data->waitq, wait);
 
-       mask = (atomic_read(&data->srq_asserted)) ? EPOLLIN | EPOLLRDNORM : 0;
+       mask = (atomic_read(&file_data->srq_asserted)) ? EPOLLPRI : 0;
 
 no_poll:
        mutex_unlock(&data->io_mutex);
@@ -1243,6 +1460,9 @@ static const struct file_operations fops = {
        .open           = usbtmc_open,
        .release        = usbtmc_release,
        .unlocked_ioctl = usbtmc_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = usbtmc_ioctl,
+#endif
        .fasync         = usbtmc_fasync,
        .poll           = usbtmc_poll,
        .llseek         = default_llseek,
@@ -1276,15 +1496,33 @@ static void usbtmc_interrupt(struct urb *urb)
                }
                /* check for SRQ notification */
                if (data->iin_buffer[0] == 0x81) {
+                       unsigned long flags;
+                       struct list_head *elem;
+
                        if (data->fasync)
                                kill_fasync(&data->fasync,
-                                       SIGIO, POLL_IN);
+                                       SIGIO, POLL_PRI);
 
-                       atomic_set(&data->srq_asserted, 1);
-                       wake_up_interruptible(&data->waitq);
+                       spin_lock_irqsave(&data->dev_lock, flags);
+                       list_for_each(elem, &data->file_list) {
+                               struct usbtmc_file_data *file_data;
+
+                               file_data = list_entry(elem,
+                                                      struct usbtmc_file_data,
+                                                      file_elem);
+                               file_data->srq_byte = data->iin_buffer[1];
+                               atomic_set(&file_data->srq_asserted, 1);
+                       }
+                       spin_unlock_irqrestore(&data->dev_lock, flags);
+
+                       dev_dbg(dev, "srq received bTag %x stb %x\n",
+                               (unsigned int)data->iin_buffer[0],
+                               (unsigned int)data->iin_buffer[1]);
+                       wake_up_interruptible_all(&data->waitq);
                        goto exit;
                }
-               dev_warn(dev, "invalid notification: %x\n", data->iin_buffer[0]);
+               dev_warn(dev, "invalid notification: %x\n",
+                        data->iin_buffer[0]);
                break;
        case -EOVERFLOW:
                dev_err(dev, "overflow with length %d, actual length is %d\n",
@@ -1295,6 +1533,7 @@ static void usbtmc_interrupt(struct urb *urb)
        case -ESHUTDOWN:
        case -EILSEQ:
        case -ETIME:
+       case -EPIPE:
                /* urb terminated, clean up */
                dev_dbg(dev, "urb terminated, status: %d\n", status);
                return;
@@ -1339,7 +1578,9 @@ static int usbtmc_probe(struct usb_interface *intf,
        mutex_init(&data->io_mutex);
        init_waitqueue_head(&data->waitq);
        atomic_set(&data->iin_data_valid, 0);
-       atomic_set(&data->srq_asserted, 0);
+       INIT_LIST_HEAD(&data->file_list);
+       spin_lock_init(&data->dev_lock);
+
        data->zombie = 0;
 
        /* Initialize USBTMC bTag and other fields */
@@ -1442,17 +1683,14 @@ err_put:
 
 static void usbtmc_disconnect(struct usb_interface *intf)
 {
-       struct usbtmc_device_data *data;
-
-       dev_dbg(&intf->dev, "usbtmc_disconnect called\n");
+       struct usbtmc_device_data *data  = usb_get_intfdata(intf);
 
-       data = usb_get_intfdata(intf);
        usb_deregister_dev(intf, &usbtmc_class);
        sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp);
        sysfs_remove_group(&intf->dev.kobj, &data_attr_grp);
        mutex_lock(&data->io_mutex);
        data->zombie = 1;
-       wake_up_all(&data->waitq);
+       wake_up_interruptible_all(&data->waitq);
        mutex_unlock(&data->io_mutex);
        usbtmc_free_int(data);
        kref_put(&data->kref, usbtmc_delete);
index 476dcc5..6ce77b3 100644 (file)
@@ -585,9 +585,10 @@ static void async_completed(struct urb *urb)
        struct siginfo sinfo;
        struct pid *pid = NULL;
        const struct cred *cred = NULL;
+       unsigned long flags;
        int signr;
 
-       spin_lock(&ps->lock);
+       spin_lock_irqsave(&ps->lock, flags);
        list_move_tail(&as->asynclist, &ps->async_completed);
        as->status = urb->status;
        signr = as->signr;
@@ -611,7 +612,7 @@ static void async_completed(struct urb *urb)
                cancel_bulk_urbs(ps, as->bulk_addr);
 
        wake_up(&ps->wait);
-       spin_unlock(&ps->lock);
+       spin_unlock_irqrestore(&ps->lock, flags);
 
        if (signr) {
                kill_pid_info_as_cred(sinfo.si_signo, &sinfo, pid, cred);
index 1fb2668..462ce49 100644 (file)
@@ -3660,12 +3660,54 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
        return 0;
 }
 
+/* Report wakeup requests from the ports of a resuming root hub */
+static void report_wakeup_requests(struct usb_hub *hub)
+{
+       struct usb_device       *hdev = hub->hdev;
+       struct usb_device       *udev;
+       struct usb_hcd          *hcd;
+       unsigned long           resuming_ports;
+       int                     i;
+
+       if (hdev->parent)
+               return;         /* Not a root hub */
+
+       hcd = bus_to_hcd(hdev->bus);
+       if (hcd->driver->get_resuming_ports) {
+
+               /*
+                * The get_resuming_ports() method returns a bitmap (origin 0)
+                * of ports which have started wakeup signaling but have not
+                * yet finished resuming.  During system resume we will
+                * resume all the enabled ports, regardless of any wakeup
+                * signals, which means the wakeup requests would be lost.
+                * To prevent this, report them to the PM core here.
+                */
+               resuming_ports = hcd->driver->get_resuming_ports(hcd);
+               for (i = 0; i < hdev->maxchild; ++i) {
+                       if (test_bit(i, &resuming_ports)) {
+                               udev = hub->ports[i]->child;
+                               if (udev)
+                                       pm_wakeup_event(&udev->dev, 0);
+                       }
+               }
+       }
+}
+
 static int hub_resume(struct usb_interface *intf)
 {
        struct usb_hub *hub = usb_get_intfdata(intf);
 
        dev_dbg(&intf->dev, "%s\n", __func__);
        hub_activate(hub, HUB_RESUME);
+
+       /*
+        * This should be called only for system resume, not runtime resume.
+        * We can't tell the difference here, so some wakeup requests will be
+        * reported at the wrong time or more than once.  This shouldn't
+        * matter much, so long as they do get reported.
+        */
+       report_wakeup_requests(hub);
        return 0;
 }
 
index 1a15392..228672f 100644 (file)
@@ -269,10 +269,11 @@ static void sg_clean(struct usb_sg_request *io)
 
 static void sg_complete(struct urb *urb)
 {
+       unsigned long flags;
        struct usb_sg_request *io = urb->context;
        int status = urb->status;
 
-       spin_lock(&io->lock);
+       spin_lock_irqsave(&io->lock, flags);
 
        /* In 2.5 we require hcds' endpoint queues not to progress after fault
         * reports, until the completion callback (this!) returns.  That lets
@@ -306,7 +307,7 @@ static void sg_complete(struct urb *urb)
                 * unlink pending urbs so they won't rx/tx bad data.
                 * careful: unlink can sometimes be synchronous...
                 */
-               spin_unlock(&io->lock);
+               spin_unlock_irqrestore(&io->lock, flags);
                for (i = 0, found = 0; i < io->entries; i++) {
                        if (!io->urbs[i])
                                continue;
@@ -323,7 +324,7 @@ static void sg_complete(struct urb *urb)
                        } else if (urb == io->urbs[i])
                                found = 1;
                }
-               spin_lock(&io->lock);
+               spin_lock_irqsave(&io->lock, flags);
        }
 
        /* on the last completion, signal usb_sg_wait() */
@@ -332,7 +333,7 @@ static void sg_complete(struct urb *urb)
        if (!io->count)
                complete(&io->complete);
 
-       spin_unlock(&io->lock);
+       spin_unlock_irqrestore(&io->lock, flags);
 }
 
 
index 1c36a6a..55d5ae2 100644 (file)
@@ -73,17 +73,17 @@ int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg)
        /* Backup global regs */
        gr = &hsotg->gr_backup;
 
-       gr->gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
-       gr->gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
-       gr->gahbcfg = dwc2_readl(hsotg->regs + GAHBCFG);
-       gr->gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
-       gr->grxfsiz = dwc2_readl(hsotg->regs + GRXFSIZ);
-       gr->gnptxfsiz = dwc2_readl(hsotg->regs + GNPTXFSIZ);
-       gr->gdfifocfg = dwc2_readl(hsotg->regs + GDFIFOCFG);
-       gr->pcgcctl1 = dwc2_readl(hsotg->regs + PCGCCTL1);
-       gr->glpmcfg = dwc2_readl(hsotg->regs + GLPMCFG);
-       gr->gi2cctl = dwc2_readl(hsotg->regs + GI2CCTL);
-       gr->pcgcctl = dwc2_readl(hsotg->regs + PCGCTL);
+       gr->gotgctl = dwc2_readl(hsotg, GOTGCTL);
+       gr->gintmsk = dwc2_readl(hsotg, GINTMSK);
+       gr->gahbcfg = dwc2_readl(hsotg, GAHBCFG);
+       gr->gusbcfg = dwc2_readl(hsotg, GUSBCFG);
+       gr->grxfsiz = dwc2_readl(hsotg, GRXFSIZ);
+       gr->gnptxfsiz = dwc2_readl(hsotg, GNPTXFSIZ);
+       gr->gdfifocfg = dwc2_readl(hsotg, GDFIFOCFG);
+       gr->pcgcctl1 = dwc2_readl(hsotg, PCGCCTL1);
+       gr->glpmcfg = dwc2_readl(hsotg, GLPMCFG);
+       gr->gi2cctl = dwc2_readl(hsotg, GI2CCTL);
+       gr->pcgcctl = dwc2_readl(hsotg, PCGCTL);
 
        gr->valid = true;
        return 0;
@@ -111,18 +111,18 @@ int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg)
        }
        gr->valid = false;
 
-       dwc2_writel(0xffffffff, hsotg->regs + GINTSTS);
-       dwc2_writel(gr->gotgctl, hsotg->regs + GOTGCTL);
-       dwc2_writel(gr->gintmsk, hsotg->regs + GINTMSK);
-       dwc2_writel(gr->gusbcfg, hsotg->regs + GUSBCFG);
-       dwc2_writel(gr->gahbcfg, hsotg->regs + GAHBCFG);
-       dwc2_writel(gr->grxfsiz, hsotg->regs + GRXFSIZ);
-       dwc2_writel(gr->gnptxfsiz, hsotg->regs + GNPTXFSIZ);
-       dwc2_writel(gr->gdfifocfg, hsotg->regs + GDFIFOCFG);
-       dwc2_writel(gr->pcgcctl1, hsotg->regs + PCGCCTL1);
-       dwc2_writel(gr->glpmcfg, hsotg->regs + GLPMCFG);
-       dwc2_writel(gr->pcgcctl, hsotg->regs + PCGCTL);
-       dwc2_writel(gr->gi2cctl, hsotg->regs + GI2CCTL);
+       dwc2_writel(hsotg, 0xffffffff, GINTSTS);
+       dwc2_writel(hsotg, gr->gotgctl, GOTGCTL);
+       dwc2_writel(hsotg, gr->gintmsk, GINTMSK);
+       dwc2_writel(hsotg, gr->gusbcfg, GUSBCFG);
+       dwc2_writel(hsotg, gr->gahbcfg, GAHBCFG);
+       dwc2_writel(hsotg, gr->grxfsiz, GRXFSIZ);
+       dwc2_writel(hsotg, gr->gnptxfsiz, GNPTXFSIZ);
+       dwc2_writel(hsotg, gr->gdfifocfg, GDFIFOCFG);
+       dwc2_writel(hsotg, gr->pcgcctl1, PCGCCTL1);
+       dwc2_writel(hsotg, gr->glpmcfg, GLPMCFG);
+       dwc2_writel(hsotg, gr->pcgcctl, PCGCTL);
+       dwc2_writel(hsotg, gr->gi2cctl, GI2CCTL);
 
        return 0;
 }
@@ -141,17 +141,17 @@ int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, bool restore)
        if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_PARTIAL)
                return -ENOTSUPP;
 
-       pcgcctl = dwc2_readl(hsotg->regs + PCGCTL);
+       pcgcctl = dwc2_readl(hsotg, PCGCTL);
        pcgcctl &= ~PCGCTL_STOPPCLK;
-       dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
+       dwc2_writel(hsotg, pcgcctl, PCGCTL);
 
-       pcgcctl = dwc2_readl(hsotg->regs + PCGCTL);
+       pcgcctl = dwc2_readl(hsotg, PCGCTL);
        pcgcctl &= ~PCGCTL_PWRCLMP;
-       dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
+       dwc2_writel(hsotg, pcgcctl, PCGCTL);
 
-       pcgcctl = dwc2_readl(hsotg->regs + PCGCTL);
+       pcgcctl = dwc2_readl(hsotg, PCGCTL);
        pcgcctl &= ~PCGCTL_RSTPDWNMODULE;
-       dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
+       dwc2_writel(hsotg, pcgcctl, PCGCTL);
 
        udelay(100);
        if (restore) {
@@ -222,21 +222,21 @@ int dwc2_enter_partial_power_down(struct dwc2_hsotg *hsotg)
         * Clear any pending interrupts since dwc2 will not be able to
         * clear them after entering partial_power_down.
         */
-       dwc2_writel(0xffffffff, hsotg->regs + GINTSTS);
+       dwc2_writel(hsotg, 0xffffffff, GINTSTS);
 
        /* Put the controller in low power state */
-       pcgcctl = dwc2_readl(hsotg->regs + PCGCTL);
+       pcgcctl = dwc2_readl(hsotg, PCGCTL);
 
        pcgcctl |= PCGCTL_PWRCLMP;
-       dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
+       dwc2_writel(hsotg, pcgcctl, PCGCTL);
        ndelay(20);
 
        pcgcctl |= PCGCTL_RSTPDWNMODULE;
-       dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
+       dwc2_writel(hsotg, pcgcctl, PCGCTL);
        ndelay(20);
 
        pcgcctl |= PCGCTL_STOPPCLK;
-       dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
+       dwc2_writel(hsotg, pcgcctl, PCGCTL);
 
        return ret;
 }
@@ -272,39 +272,39 @@ static void dwc2_restore_essential_regs(struct dwc2_hsotg *hsotg, int rmode,
                if (!(pcgcctl & PCGCTL_P2HD_DEV_ENUM_SPD_MASK))
                        pcgcctl |= BIT(17);
        }
-       dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
+       dwc2_writel(hsotg, pcgcctl, PCGCTL);
 
        /* Umnask global Interrupt in GAHBCFG and restore it */
-       dwc2_writel(gr->gahbcfg | GAHBCFG_GLBL_INTR_EN, hsotg->regs + GAHBCFG);
+       dwc2_writel(hsotg, gr->gahbcfg | GAHBCFG_GLBL_INTR_EN, GAHBCFG);
 
        /* Clear all pending interupts */
-       dwc2_writel(0xffffffff, hsotg->regs + GINTSTS);
+       dwc2_writel(hsotg, 0xffffffff, GINTSTS);
 
        /* Unmask restore done interrupt */
-       dwc2_writel(GINTSTS_RESTOREDONE, hsotg->regs + GINTMSK);
+       dwc2_writel(hsotg, GINTSTS_RESTOREDONE, GINTMSK);
 
        /* Restore GUSBCFG and HCFG/DCFG */
-       dwc2_writel(gr->gusbcfg, hsotg->regs + GUSBCFG);
+       dwc2_writel(hsotg, gr->gusbcfg, GUSBCFG);
 
        if (is_host) {
-               dwc2_writel(hr->hcfg, hsotg->regs + HCFG);
+               dwc2_writel(hsotg, hr->hcfg, HCFG);
                if (rmode)
                        pcgcctl |= PCGCTL_RESTOREMODE;
-               dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
+               dwc2_writel(hsotg, pcgcctl, PCGCTL);
                udelay(10);
 
                pcgcctl |= PCGCTL_ESS_REG_RESTORED;
-               dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
+               dwc2_writel(hsotg, pcgcctl, PCGCTL);
                udelay(10);
        } else {
-               dwc2_writel(dr->dcfg, hsotg->regs + DCFG);
+               dwc2_writel(hsotg, dr->dcfg, DCFG);
                if (!rmode)
                        pcgcctl |= PCGCTL_RESTOREMODE | PCGCTL_RSTPDWNMODULE;
-               dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
+               dwc2_writel(hsotg, pcgcctl, PCGCTL);
                udelay(10);
 
                pcgcctl |= PCGCTL_ESS_REG_RESTORED;
-               dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
+               dwc2_writel(hsotg, pcgcctl, PCGCTL);
                udelay(10);
        }
 }
@@ -322,42 +322,42 @@ void dwc2_hib_restore_common(struct dwc2_hsotg *hsotg, int rem_wakeup,
        u32 gpwrdn;
 
        /* Switch-on voltage to the core */
-       gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+       gpwrdn = dwc2_readl(hsotg, GPWRDN);
        gpwrdn &= ~GPWRDN_PWRDNSWTCH;
-       dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+       dwc2_writel(hsotg, gpwrdn, GPWRDN);
        udelay(10);
 
        /* Reset core */
-       gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+       gpwrdn = dwc2_readl(hsotg, GPWRDN);
        gpwrdn &= ~GPWRDN_PWRDNRSTN;
-       dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+       dwc2_writel(hsotg, gpwrdn, GPWRDN);
        udelay(10);
 
        /* Enable restore from PMU */
-       gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+       gpwrdn = dwc2_readl(hsotg, GPWRDN);
        gpwrdn |= GPWRDN_RESTORE;
-       dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+       dwc2_writel(hsotg, gpwrdn, GPWRDN);
        udelay(10);
 
        /* Disable Power Down Clamp */
-       gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+       gpwrdn = dwc2_readl(hsotg, GPWRDN);
        gpwrdn &= ~GPWRDN_PWRDNCLMP;
-       dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+       dwc2_writel(hsotg, gpwrdn, GPWRDN);
        udelay(50);
 
        if (!is_host && rem_wakeup)
                udelay(70);
 
        /* Deassert reset core */
-       gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+       gpwrdn = dwc2_readl(hsotg, GPWRDN);
        gpwrdn |= GPWRDN_PWRDNRSTN;
-       dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+       dwc2_writel(hsotg, gpwrdn, GPWRDN);
        udelay(10);
 
        /* Disable PMU interrupt */
-       gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+       gpwrdn = dwc2_readl(hsotg, GPWRDN);
        gpwrdn &= ~GPWRDN_PMUINTSEL;
-       dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+       dwc2_writel(hsotg, gpwrdn, GPWRDN);
        udelay(10);
 
        /* Set Restore Essential Regs bit in PCGCCTL register */
@@ -431,7 +431,7 @@ static bool dwc2_iddig_filter_enabled(struct dwc2_hsotg *hsotg)
                return false;
 
        /* Check if core configuration includes the IDDIG filter. */
-       ghwcfg4 = dwc2_readl(hsotg->regs + GHWCFG4);
+       ghwcfg4 = dwc2_readl(hsotg, GHWCFG4);
        if (!(ghwcfg4 & GHWCFG4_IDDIG_FILT_EN))
                return false;
 
@@ -439,9 +439,9 @@ static bool dwc2_iddig_filter_enabled(struct dwc2_hsotg *hsotg)
         * Check if the IDDIG debounce filter is bypassed. Available
         * in core version >= 3.10a.
         */
-       gsnpsid = dwc2_readl(hsotg->regs + GSNPSID);
+       gsnpsid = dwc2_readl(hsotg, GSNPSID);
        if (gsnpsid >= DWC2_CORE_REV_3_10a) {
-               u32 gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
+               u32 gotgctl = dwc2_readl(hsotg, GOTGCTL);
 
                if (gotgctl & GOTGCTL_DBNCE_FLTR_BYPASS)
                        return false;
@@ -510,8 +510,8 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait)
         * reset and account for this delay after the reset.
         */
        if (dwc2_iddig_filter_enabled(hsotg)) {
-               u32 gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
-               u32 gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
+               u32 gotgctl = dwc2_readl(hsotg, GOTGCTL);
+               u32 gusbcfg = dwc2_readl(hsotg, GUSBCFG);
 
                if (!(gotgctl & GOTGCTL_CONID_B) ||
                    (gusbcfg & GUSBCFG_FORCEHOSTMODE)) {
@@ -520,9 +520,9 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait)
        }
 
        /* Core Soft Reset */
-       greset = dwc2_readl(hsotg->regs + GRSTCTL);
+       greset = dwc2_readl(hsotg, GRSTCTL);
        greset |= GRSTCTL_CSFTRST;
-       dwc2_writel(greset, hsotg->regs + GRSTCTL);
+       dwc2_writel(hsotg, greset, GRSTCTL);
 
        if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_CSFTRST, 50)) {
                dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL GRSTCTL_CSFTRST\n",
@@ -594,14 +594,14 @@ void dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host)
        if (WARN_ON(!host && hsotg->dr_mode == USB_DR_MODE_HOST))
                return;
 
-       gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
+       gusbcfg = dwc2_readl(hsotg, GUSBCFG);
 
        set = host ? GUSBCFG_FORCEHOSTMODE : GUSBCFG_FORCEDEVMODE;
        clear = host ? GUSBCFG_FORCEDEVMODE : GUSBCFG_FORCEHOSTMODE;
 
        gusbcfg &= ~clear;
        gusbcfg |= set;
-       dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG);
+       dwc2_writel(hsotg, gusbcfg, GUSBCFG);
 
        dwc2_wait_for_mode(hsotg, host);
        return;
@@ -627,10 +627,10 @@ static void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg)
 
        dev_dbg(hsotg->dev, "Clearing force mode bits\n");
 
-       gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
+       gusbcfg = dwc2_readl(hsotg, GUSBCFG);
        gusbcfg &= ~GUSBCFG_FORCEHOSTMODE;
        gusbcfg &= ~GUSBCFG_FORCEDEVMODE;
-       dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG);
+       dwc2_writel(hsotg, gusbcfg, GUSBCFG);
 
        if (dwc2_iddig_filter_enabled(hsotg))
                msleep(100);
@@ -670,11 +670,11 @@ void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg)
 void dwc2_enable_acg(struct dwc2_hsotg *hsotg)
 {
        if (hsotg->params.acg_enable) {
-               u32 pcgcctl1 = dwc2_readl(hsotg->regs + PCGCCTL1);
+               u32 pcgcctl1 = dwc2_readl(hsotg, PCGCCTL1);
 
                dev_dbg(hsotg->dev, "Enabling Active Clock Gating\n");
                pcgcctl1 |= PCGCCTL1_GATEEN;
-               dwc2_writel(pcgcctl1, hsotg->regs + PCGCCTL1);
+               dwc2_writel(hsotg, pcgcctl1, PCGCCTL1);
        }
 }
 
@@ -695,56 +695,57 @@ void dwc2_dump_host_registers(struct dwc2_hsotg *hsotg)
        dev_dbg(hsotg->dev, "Host Global Registers\n");
        addr = hsotg->regs + HCFG;
        dev_dbg(hsotg->dev, "HCFG        @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, dwc2_readl(addr));
+               (unsigned long)addr, dwc2_readl(hsotg, HCFG));
        addr = hsotg->regs + HFIR;
        dev_dbg(hsotg->dev, "HFIR        @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, dwc2_readl(addr));
+               (unsigned long)addr, dwc2_readl(hsotg, HFIR));
        addr = hsotg->regs + HFNUM;
        dev_dbg(hsotg->dev, "HFNUM       @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, dwc2_readl(addr));
+               (unsigned long)addr, dwc2_readl(hsotg, HFNUM));
        addr = hsotg->regs + HPTXSTS;
        dev_dbg(hsotg->dev, "HPTXSTS     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, dwc2_readl(addr));
+               (unsigned long)addr, dwc2_readl(hsotg, HPTXSTS));
        addr = hsotg->regs + HAINT;
        dev_dbg(hsotg->dev, "HAINT       @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, dwc2_readl(addr));
+               (unsigned long)addr, dwc2_readl(hsotg, HAINT));
        addr = hsotg->regs + HAINTMSK;
        dev_dbg(hsotg->dev, "HAINTMSK    @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, dwc2_readl(addr));
+               (unsigned long)addr, dwc2_readl(hsotg, HAINTMSK));
        if (hsotg->params.dma_desc_enable) {
                addr = hsotg->regs + HFLBADDR;
                dev_dbg(hsotg->dev, "HFLBADDR @0x%08lX : 0x%08X\n",
-                       (unsigned long)addr, dwc2_readl(addr));
+                       (unsigned long)addr, dwc2_readl(hsotg, HFLBADDR));
        }
 
        addr = hsotg->regs + HPRT0;
        dev_dbg(hsotg->dev, "HPRT0       @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, dwc2_readl(addr));
+               (unsigned long)addr, dwc2_readl(hsotg, HPRT0));
 
        for (i = 0; i < hsotg->params.host_channels; i++) {
                dev_dbg(hsotg->dev, "Host Channel %d Specific Registers\n", i);
                addr = hsotg->regs + HCCHAR(i);
                dev_dbg(hsotg->dev, "HCCHAR      @0x%08lX : 0x%08X\n",
-                       (unsigned long)addr, dwc2_readl(addr));
+                       (unsigned long)addr, dwc2_readl(hsotg, HCCHAR(i)));
                addr = hsotg->regs + HCSPLT(i);
                dev_dbg(hsotg->dev, "HCSPLT      @0x%08lX : 0x%08X\n",
-                       (unsigned long)addr, dwc2_readl(addr));
+                       (unsigned long)addr, dwc2_readl(hsotg, HCSPLT(i)));
                addr = hsotg->regs + HCINT(i);
                dev_dbg(hsotg->dev, "HCINT       @0x%08lX : 0x%08X\n",
-                       (unsigned long)addr, dwc2_readl(addr));
+                       (unsigned long)addr, dwc2_readl(hsotg, HCINT(i)));
                addr = hsotg->regs + HCINTMSK(i);
                dev_dbg(hsotg->dev, "HCINTMSK    @0x%08lX : 0x%08X\n",
-                       (unsigned long)addr, dwc2_readl(addr));
+                       (unsigned long)addr, dwc2_readl(hsotg, HCINTMSK(i)));
                addr = hsotg->regs + HCTSIZ(i);
                dev_dbg(hsotg->dev, "HCTSIZ      @0x%08lX : 0x%08X\n",
-                       (unsigned long)addr, dwc2_readl(addr));
+                       (unsigned long)addr, dwc2_readl(hsotg, HCTSIZ(i)));
                addr = hsotg->regs + HCDMA(i);
                dev_dbg(hsotg->dev, "HCDMA       @0x%08lX : 0x%08X\n",
-                       (unsigned long)addr, dwc2_readl(addr));
+                       (unsigned long)addr, dwc2_readl(hsotg, HCDMA(i)));
                if (hsotg->params.dma_desc_enable) {
                        addr = hsotg->regs + HCDMAB(i);
                        dev_dbg(hsotg->dev, "HCDMAB      @0x%08lX : 0x%08X\n",
-                               (unsigned long)addr, dwc2_readl(addr));
+                               (unsigned long)addr, dwc2_readl(hsotg,
+                                                               HCDMAB(i)));
                }
        }
 #endif
@@ -766,80 +767,80 @@ void dwc2_dump_global_registers(struct dwc2_hsotg *hsotg)
        dev_dbg(hsotg->dev, "Core Global Registers\n");
        addr = hsotg->regs + GOTGCTL;
        dev_dbg(hsotg->dev, "GOTGCTL     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, dwc2_readl(addr));
+               (unsigned long)addr, dwc2_readl(hsotg, GOTGCTL));
        addr = hsotg->regs + GOTGINT;
        dev_dbg(hsotg->dev, "GOTGINT     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, dwc2_readl(addr));
+               (unsigned long)addr, dwc2_readl(hsotg, GOTGINT));
        addr = hsotg->regs + GAHBCFG;
        dev_dbg(hsotg->dev, "GAHBCFG     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, dwc2_readl(addr));
+               (unsigned long)addr, dwc2_readl(hsotg, GAHBCFG));
        addr = hsotg->regs + GUSBCFG;
        dev_dbg(hsotg->dev, "GUSBCFG     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, dwc2_readl(addr));
+               (unsigned long)addr, dwc2_readl(hsotg, GUSBCFG));
        addr = hsotg->regs + GRSTCTL;
        dev_dbg(hsotg->dev, "GRSTCTL     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, dwc2_readl(addr));
+               (unsigned long)addr, dwc2_readl(hsotg, GRSTCTL));
        addr = hsotg->regs + GINTSTS;
        dev_dbg(hsotg->dev, "GINTSTS     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, dwc2_readl(addr));
+               (unsigned long)addr, dwc2_readl(hsotg, GINTSTS));
        addr = hsotg->regs + GINTMSK;
        dev_dbg(hsotg->dev, "GINTMSK     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, dwc2_readl(addr));
+               (unsigned long)addr, dwc2_readl(hsotg, GINTMSK));
        addr = hsotg->regs + GRXSTSR;
        dev_dbg(hsotg->dev, "GRXSTSR     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, dwc2_readl(addr));
+               (unsigned long)addr, dwc2_readl(hsotg, GRXSTSR));
        addr = hsotg->regs + GRXFSIZ;
        dev_dbg(hsotg->dev, "GRXFSIZ     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, dwc2_readl(addr));
+               (unsigned long)addr, dwc2_readl(hsotg, GRXFSIZ));
        addr = hsotg->regs + GNPTXFSIZ;
        dev_dbg(hsotg->dev, "GNPTXFSIZ   @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, dwc2_readl(addr));
+               (unsigned long)addr, dwc2_readl(hsotg, GNPTXFSIZ));
        addr = hsotg->regs + GNPTXSTS;
        dev_dbg(hsotg->dev, "GNPTXSTS    @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, dwc2_readl(addr));
+               (unsigned long)addr, dwc2_readl(hsotg, GNPTXSTS));
        addr = hsotg->regs + GI2CCTL;
        dev_dbg(hsotg->dev, "GI2CCTL     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, dwc2_readl(addr));
+               (unsigned long)addr, dwc2_readl(hsotg, GI2CCTL));
        addr = hsotg->regs + GPVNDCTL;
        dev_dbg(hsotg->dev, "GPVNDCTL    @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, dwc2_readl(addr));
+               (unsigned long)addr, dwc2_readl(hsotg, GPVNDCTL));
        addr = hsotg->regs + GGPIO;
        dev_dbg(hsotg->dev, "GGPIO       @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, dwc2_readl(addr));
+               (unsigned long)addr, dwc2_readl(hsotg, GGPIO));
        addr = hsotg->regs + GUID;
        dev_dbg(hsotg->dev, "GUID        @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, dwc2_readl(addr));
+               (unsigned long)addr, dwc2_readl(hsotg, GUID));
        addr = hsotg->regs + GSNPSID;
        dev_dbg(hsotg->dev, "GSNPSID     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, dwc2_readl(addr));
+               (unsigned long)addr, dwc2_readl(hsotg, GSNPSID));
        addr = hsotg->regs + GHWCFG1;
        dev_dbg(hsotg->dev, "GHWCFG1     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, dwc2_readl(addr));
+               (unsigned long)addr, dwc2_readl(hsotg, GHWCFG1));
        addr = hsotg->regs + GHWCFG2;
        dev_dbg(hsotg->dev, "GHWCFG2     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, dwc2_readl(addr));
+               (unsigned long)addr, dwc2_readl(hsotg, GHWCFG2));
        addr = hsotg->regs + GHWCFG3;
        dev_dbg(hsotg->dev, "GHWCFG3     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, dwc2_readl(addr));
+               (unsigned long)addr, dwc2_readl(hsotg, GHWCFG3));
        addr = hsotg->regs + GHWCFG4;
        dev_dbg(hsotg->dev, "GHWCFG4     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, dwc2_readl(addr));
+               (unsigned long)addr, dwc2_readl(hsotg, GHWCFG4));
        addr = hsotg->regs + GLPMCFG;
        dev_dbg(hsotg->dev, "GLPMCFG     @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, dwc2_readl(addr));
+               (unsigned long)addr, dwc2_readl(hsotg, GLPMCFG));
        addr = hsotg->regs + GPWRDN;
        dev_dbg(hsotg->dev, "GPWRDN      @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, dwc2_readl(addr));
+               (unsigned long)addr, dwc2_readl(hsotg, GPWRDN));
        addr = hsotg->regs + GDFIFOCFG;
        dev_dbg(hsotg->dev, "GDFIFOCFG   @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, dwc2_readl(addr));
+               (unsigned long)addr, dwc2_readl(hsotg, GDFIFOCFG));
        addr = hsotg->regs + HPTXFSIZ;
        dev_dbg(hsotg->dev, "HPTXFSIZ    @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, dwc2_readl(addr));
+               (unsigned long)addr, dwc2_readl(hsotg, HPTXFSIZ));
 
        addr = hsotg->regs + PCGCTL;
        dev_dbg(hsotg->dev, "PCGCTL      @0x%08lX : 0x%08X\n",
-               (unsigned long)addr, dwc2_readl(addr));
+               (unsigned long)addr, dwc2_readl(hsotg, PCGCTL));
 #endif
 }
 
@@ -862,7 +863,7 @@ void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num)
 
        greset = GRSTCTL_TXFFLSH;
        greset |= num << GRSTCTL_TXFNUM_SHIFT & GRSTCTL_TXFNUM_MASK;
-       dwc2_writel(greset, hsotg->regs + GRSTCTL);
+       dwc2_writel(hsotg, greset, GRSTCTL);
 
        if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_TXFFLSH, 10000))
                dev_warn(hsotg->dev, "%s:  HANG! timeout GRSTCTL GRSTCTL_TXFFLSH\n",
@@ -889,7 +890,7 @@ void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg)
                         __func__);
 
        greset = GRSTCTL_RXFFLSH;
-       dwc2_writel(greset, hsotg->regs + GRSTCTL);
+       dwc2_writel(hsotg, greset, GRSTCTL);
 
        /* Wait for RxFIFO flush done */
        if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_RXFFLSH, 10000))
@@ -902,7 +903,7 @@ void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg)
 
 bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg)
 {
-       if (dwc2_readl(hsotg->regs + GSNPSID) == 0xffffffff)
+       if (dwc2_readl(hsotg, GSNPSID) == 0xffffffff)
                return false;
        else
                return true;
@@ -916,10 +917,10 @@ bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg)
  */
 void dwc2_enable_global_interrupts(struct dwc2_hsotg *hsotg)
 {
-       u32 ahbcfg = dwc2_readl(hsotg->regs + GAHBCFG);
+       u32 ahbcfg = dwc2_readl(hsotg, GAHBCFG);
 
        ahbcfg |= GAHBCFG_GLBL_INTR_EN;
-       dwc2_writel(ahbcfg, hsotg->regs + GAHBCFG);
+       dwc2_writel(hsotg, ahbcfg, GAHBCFG);
 }
 
 /**
@@ -930,16 +931,16 @@ void dwc2_enable_global_interrupts(struct dwc2_hsotg *hsotg)
  */
 void dwc2_disable_global_interrupts(struct dwc2_hsotg *hsotg)
 {
-       u32 ahbcfg = dwc2_readl(hsotg->regs + GAHBCFG);
+       u32 ahbcfg = dwc2_readl(hsotg, GAHBCFG);
 
        ahbcfg &= ~GAHBCFG_GLBL_INTR_EN;
-       dwc2_writel(ahbcfg, hsotg->regs + GAHBCFG);
+       dwc2_writel(hsotg, ahbcfg, GAHBCFG);
 }
 
 /* Returns the controller's GHWCFG2.OTG_MODE. */
 unsigned int dwc2_op_mode(struct dwc2_hsotg *hsotg)
 {
-       u32 ghwcfg2 = dwc2_readl(hsotg->regs + GHWCFG2);
+       u32 ghwcfg2 = dwc2_readl(hsotg, GHWCFG2);
 
        return (ghwcfg2 & GHWCFG2_OP_MODE_MASK) >>
                GHWCFG2_OP_MODE_SHIFT;
@@ -988,7 +989,7 @@ int dwc2_hsotg_wait_bit_set(struct dwc2_hsotg *hsotg, u32 offset, u32 mask,
        u32 i;
 
        for (i = 0; i < timeout; i++) {
-               if (dwc2_readl(hsotg->regs + offset) & mask)
+               if (dwc2_readl(hsotg, offset) & mask)
                        return 0;
                udelay(1);
        }
@@ -1011,7 +1012,7 @@ int dwc2_hsotg_wait_bit_clear(struct dwc2_hsotg *hsotg, u32 offset, u32 mask,
        u32 i;
 
        for (i = 0; i < timeout; i++) {
-               if (!(dwc2_readl(hsotg->regs + offset) & mask))
+               if (!(dwc2_readl(hsotg, offset) & mask))
                        return 0;
                udelay(1);
        }
index 71b3b08..cc9c93a 100644 (file)
        DWC2_TRACE_SCHEDULER_VB(pr_fmt("%s: SCH: " fmt),                \
                                dev_name(hsotg->dev), ##__VA_ARGS__)
 
-#ifdef CONFIG_MIPS
-/*
- * There are some MIPS machines that can run in either big-endian
- * or little-endian mode and that use the dwc2 register without
- * a byteswap in both ways.
- * Unlike other architectures, MIPS apparently does not require a
- * barrier before the __raw_writel() to synchronize with DMA but does
- * require the barrier after the __raw_writel() to serialize a set of
- * writes. This set of operations was added specifically for MIPS and
- * should only be used there.
- */
-static inline u32 dwc2_readl(const void __iomem *addr)
-{
-       u32 value = __raw_readl(addr);
-
-       /* In order to preserve endianness __raw_* operation is used. Therefore
-        * a barrier is needed to ensure IO access is not re-ordered across
-        * reads or writes
-        */
-       mb();
-       return value;
-}
-
-static inline void dwc2_writel(u32 value, void __iomem *addr)
-{
-       __raw_writel(value, addr);
-
-       /*
-        * In order to preserve endianness __raw_* operation is used. Therefore
-        * a barrier is needed to ensure IO access is not re-ordered across
-        * reads or writes
-        */
-       mb();
-#ifdef DWC2_LOG_WRITES
-       pr_info("INFO:: wrote %08x to %p\n", value, addr);
-#endif
-}
-#else
-/* Normal architectures just use readl/write */
-static inline u32 dwc2_readl(const void __iomem *addr)
-{
-       return readl(addr);
-}
-
-static inline void dwc2_writel(u32 value, void __iomem *addr)
-{
-       writel(value, addr);
-
-#ifdef DWC2_LOG_WRITES
-       pr_info("info:: wrote %08x to %p\n", value, addr);
-#endif
-}
-#endif
-
 /* Maximum number of Endpoints/HostChannels */
 #define MAX_EPS_CHANNELS       16
 
@@ -911,6 +857,7 @@ struct dwc2_hregs_backup {
  * @gr_backup: Backup of global registers during suspend
  * @dr_backup: Backup of device registers during suspend
  * @hr_backup: Backup of host registers during suspend
+ * @needs_byte_swap:           Specifies whether the opposite endianness.
  *
  * These are for host mode:
  *
@@ -1100,6 +1047,7 @@ struct dwc2_hsotg {
 
        struct dentry *debug_root;
        struct debugfs_regset32 *regset;
+       bool needs_byte_swap;
 
        /* DWC OTG HW Release versions */
 #define DWC2_CORE_REV_2_71a    0x4f54271a
@@ -1215,6 +1163,55 @@ struct dwc2_hsotg {
 #endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */
 };
 
+/* Normal architectures just use readl/write */
+static inline u32 dwc2_readl(struct dwc2_hsotg *hsotg, u32 offset)
+{
+       u32 val;
+
+       val = readl(hsotg->regs + offset);
+       if (hsotg->needs_byte_swap)
+               return swab32(val);
+       else
+               return val;
+}
+
+static inline void dwc2_writel(struct dwc2_hsotg *hsotg, u32 value, u32 offset)
+{
+       if (hsotg->needs_byte_swap)
+               writel(swab32(value), hsotg->regs + offset);
+       else
+               writel(value, hsotg->regs + offset);
+
+#ifdef DWC2_LOG_WRITES
+       pr_info("info:: wrote %08x to %p\n", value, hsotg->regs + offset);
+#endif
+}
+
+static inline void dwc2_readl_rep(struct dwc2_hsotg *hsotg, u32 offset,
+                                 void *buffer, unsigned int count)
+{
+       if (count) {
+               u32 *buf = buffer;
+
+               do {
+                       u32 x = dwc2_readl(hsotg, offset);
+                       *buf++ = x;
+               } while (--count);
+       }
+}
+
+static inline void dwc2_writel_rep(struct dwc2_hsotg *hsotg, u32 offset,
+                                  const void *buffer, unsigned int count)
+{
+       if (count) {
+               const u32 *buf = buffer;
+
+               do {
+                       dwc2_writel(hsotg, *buf++, offset);
+               } while (--count);
+       }
+}
+
 /* Reasons for halting a host channel */
 enum dwc2_halt_status {
        DWC2_HC_XFER_NO_HALT_STATUS,
@@ -1320,12 +1317,12 @@ bool dwc2_hw_is_device(struct dwc2_hsotg *hsotg);
  */
 static inline int dwc2_is_host_mode(struct dwc2_hsotg *hsotg)
 {
-       return (dwc2_readl(hsotg->regs + GINTSTS) & GINTSTS_CURMODE_HOST) != 0;
+       return (dwc2_readl(hsotg, GINTSTS) & GINTSTS_CURMODE_HOST) != 0;
 }
 
 static inline int dwc2_is_device_mode(struct dwc2_hsotg *hsotg)
 {
-       return (dwc2_readl(hsotg->regs + GINTSTS) & GINTSTS_CURMODE_HOST) == 0;
+       return (dwc2_readl(hsotg, GINTSTS) & GINTSTS_CURMODE_HOST) == 0;
 }
 
 /*
index cc90b58..19ae259 100644 (file)
@@ -81,11 +81,11 @@ static const char *dwc2_op_state_str(struct dwc2_hsotg *hsotg)
  */
 static void dwc2_handle_usb_port_intr(struct dwc2_hsotg *hsotg)
 {
-       u32 hprt0 = dwc2_readl(hsotg->regs + HPRT0);
+       u32 hprt0 = dwc2_readl(hsotg, HPRT0);
 
        if (hprt0 & HPRT0_ENACHG) {
                hprt0 &= ~HPRT0_ENA;
-               dwc2_writel(hprt0, hsotg->regs + HPRT0);
+               dwc2_writel(hsotg, hprt0, HPRT0);
        }
 }
 
@@ -97,7 +97,7 @@ static void dwc2_handle_usb_port_intr(struct dwc2_hsotg *hsotg)
 static void dwc2_handle_mode_mismatch_intr(struct dwc2_hsotg *hsotg)
 {
        /* Clear interrupt */
-       dwc2_writel(GINTSTS_MODEMIS, hsotg->regs + GINTSTS);
+       dwc2_writel(hsotg, GINTSTS_MODEMIS, GINTSTS);
 
        dev_warn(hsotg->dev, "Mode Mismatch Interrupt: currently in %s mode\n",
                 dwc2_is_host_mode(hsotg) ? "Host" : "Device");
@@ -115,8 +115,8 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
        u32 gotgctl;
        u32 gintmsk;
 
-       gotgint = dwc2_readl(hsotg->regs + GOTGINT);
-       gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
+       gotgint = dwc2_readl(hsotg, GOTGINT);
+       gotgctl = dwc2_readl(hsotg, GOTGCTL);
        dev_dbg(hsotg->dev, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint,
                dwc2_op_state_str(hsotg));
 
@@ -124,7 +124,7 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
                dev_dbg(hsotg->dev,
                        " ++OTG Interrupt: Session End Detected++ (%s)\n",
                        dwc2_op_state_str(hsotg));
-               gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
+               gotgctl = dwc2_readl(hsotg, GOTGCTL);
 
                if (dwc2_is_device_mode(hsotg))
                        dwc2_hsotg_disconnect(hsotg);
@@ -150,24 +150,24 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
                        hsotg->lx_state = DWC2_L0;
                }
 
-               gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
+               gotgctl = dwc2_readl(hsotg, GOTGCTL);
                gotgctl &= ~GOTGCTL_DEVHNPEN;
-               dwc2_writel(gotgctl, hsotg->regs + GOTGCTL);
+               dwc2_writel(hsotg, gotgctl, GOTGCTL);
        }
 
        if (gotgint & GOTGINT_SES_REQ_SUC_STS_CHNG) {
                dev_dbg(hsotg->dev,
                        " ++OTG Interrupt: Session Request Success Status Change++\n");
-               gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
+               gotgctl = dwc2_readl(hsotg, GOTGCTL);
                if (gotgctl & GOTGCTL_SESREQSCS) {
                        if (hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS &&
                            hsotg->params.i2c_enable) {
                                hsotg->srp_success = 1;
                        } else {
                                /* Clear Session Request */
-                               gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
+                               gotgctl = dwc2_readl(hsotg, GOTGCTL);
                                gotgctl &= ~GOTGCTL_SESREQ;
-                               dwc2_writel(gotgctl, hsotg->regs + GOTGCTL);
+                               dwc2_writel(hsotg, gotgctl, GOTGCTL);
                        }
                }
        }
@@ -177,7 +177,7 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
                 * Print statements during the HNP interrupt handling
                 * can cause it to fail
                 */
-               gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
+               gotgctl = dwc2_readl(hsotg, GOTGCTL);
                /*
                 * WA for 3.00a- HW is not setting cur_mode, even sometimes
                 * this does not help
@@ -197,9 +197,9 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
                                 * interrupt does not get handled and Linux
                                 * complains loudly.
                                 */
-                               gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
+                               gintmsk = dwc2_readl(hsotg, GINTMSK);
                                gintmsk &= ~GINTSTS_SOF;
-                               dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
+                               dwc2_writel(hsotg, gintmsk, GINTMSK);
 
                                /*
                                 * Call callback function with spin lock
@@ -213,9 +213,9 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
                                hsotg->op_state = OTG_STATE_B_HOST;
                        }
                } else {
-                       gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
+                       gotgctl = dwc2_readl(hsotg, GOTGCTL);
                        gotgctl &= ~(GOTGCTL_HNPREQ | GOTGCTL_DEVHNPEN);
-                       dwc2_writel(gotgctl, hsotg->regs + GOTGCTL);
+                       dwc2_writel(hsotg, gotgctl, GOTGCTL);
                        dev_dbg(hsotg->dev, "HNP Failed\n");
                        dev_err(hsotg->dev,
                                "Device Not Connected/Responding\n");
@@ -241,9 +241,9 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
                        hsotg->op_state = OTG_STATE_A_PERIPHERAL;
                } else {
                        /* Need to disable SOF interrupt immediately */
-                       gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
+                       gintmsk = dwc2_readl(hsotg, GINTMSK);
                        gintmsk &= ~GINTSTS_SOF;
-                       dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
+                       dwc2_writel(hsotg, gintmsk, GINTMSK);
                        spin_unlock(&hsotg->lock);
                        dwc2_hcd_start(hsotg);
                        spin_lock(&hsotg->lock);
@@ -258,7 +258,7 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
                dev_dbg(hsotg->dev, " ++OTG Interrupt: Debounce Done++\n");
 
        /* Clear GOTGINT */
-       dwc2_writel(gotgint, hsotg->regs + GOTGINT);
+       dwc2_writel(hsotg, gotgint, GOTGINT);
 }
 
 /**
@@ -276,12 +276,12 @@ static void dwc2_handle_conn_id_status_change_intr(struct dwc2_hsotg *hsotg)
        u32 gintmsk;
 
        /* Clear interrupt */
-       dwc2_writel(GINTSTS_CONIDSTSCHNG, hsotg->regs + GINTSTS);
+       dwc2_writel(hsotg, GINTSTS_CONIDSTSCHNG, GINTSTS);
 
        /* Need to disable SOF interrupt immediately */
-       gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
+       gintmsk = dwc2_readl(hsotg, GINTMSK);
        gintmsk &= ~GINTSTS_SOF;
-       dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
+       dwc2_writel(hsotg, gintmsk, GINTMSK);
 
        dev_dbg(hsotg->dev, " ++Connector ID Status Change Interrupt++  (%s)\n",
                dwc2_is_host_mode(hsotg) ? "Host" : "Device");
@@ -314,7 +314,7 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
        int ret;
 
        /* Clear interrupt */
-       dwc2_writel(GINTSTS_SESSREQINT, hsotg->regs + GINTSTS);
+       dwc2_writel(hsotg, GINTSTS_SESSREQINT, GINTSTS);
 
        dev_dbg(hsotg->dev, "Session request interrupt - lx_state=%d\n",
                hsotg->lx_state);
@@ -351,15 +351,15 @@ static void dwc2_wakeup_from_lpm_l1(struct dwc2_hsotg *hsotg)
                return;
        }
 
-       glpmcfg = dwc2_readl(hsotg->regs + GLPMCFG);
+       glpmcfg = dwc2_readl(hsotg, GLPMCFG);
        if (dwc2_is_device_mode(hsotg)) {
                dev_dbg(hsotg->dev, "Exit from L1 state\n");
                glpmcfg &= ~GLPMCFG_ENBLSLPM;
                glpmcfg &= ~GLPMCFG_HIRD_THRES_EN;
-               dwc2_writel(glpmcfg, hsotg->regs + GLPMCFG);
+               dwc2_writel(hsotg, glpmcfg, GLPMCFG);
 
                do {
-                       glpmcfg = dwc2_readl(hsotg->regs + GLPMCFG);
+                       glpmcfg = dwc2_readl(hsotg, GLPMCFG);
 
                        if (!(glpmcfg & (GLPMCFG_COREL1RES_MASK |
                                         GLPMCFG_L1RESUMEOK | GLPMCFG_SLPSTS)))
@@ -398,7 +398,7 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
        int ret;
 
        /* Clear interrupt */
-       dwc2_writel(GINTSTS_WKUPINT, hsotg->regs + GINTSTS);
+       dwc2_writel(hsotg, GINTSTS_WKUPINT, GINTSTS);
 
        dev_dbg(hsotg->dev, "++Resume or Remote Wakeup Detected Interrupt++\n");
        dev_dbg(hsotg->dev, "%s lxstate = %d\n", __func__, hsotg->lx_state);
@@ -410,13 +410,13 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
 
        if (dwc2_is_device_mode(hsotg)) {
                dev_dbg(hsotg->dev, "DSTS=0x%0x\n",
-                       dwc2_readl(hsotg->regs + DSTS));
+                       dwc2_readl(hsotg, DSTS));
                if (hsotg->lx_state == DWC2_L2) {
-                       u32 dctl = dwc2_readl(hsotg->regs + DCTL);
+                       u32 dctl = dwc2_readl(hsotg, DCTL);
 
                        /* Clear Remote Wakeup Signaling */
                        dctl &= ~DCTL_RMTWKUPSIG;
-                       dwc2_writel(dctl, hsotg->regs + DCTL);
+                       dwc2_writel(hsotg, dctl, DCTL);
                        ret = dwc2_exit_partial_power_down(hsotg, true);
                        if (ret && (ret != -ENOTSUPP))
                                dev_err(hsotg->dev, "exit power_down failed\n");
@@ -430,11 +430,11 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
                        return;
 
                if (hsotg->lx_state != DWC2_L1) {
-                       u32 pcgcctl = dwc2_readl(hsotg->regs + PCGCTL);
+                       u32 pcgcctl = dwc2_readl(hsotg, PCGCTL);
 
                        /* Restart the Phy Clock */
                        pcgcctl &= ~PCGCTL_STOPPCLK;
-                       dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
+                       dwc2_writel(hsotg, pcgcctl, PCGCTL);
                        mod_timer(&hsotg->wkp_timer,
                                  jiffies + msecs_to_jiffies(71));
                } else {
@@ -450,7 +450,7 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
  */
 static void dwc2_handle_disconnect_intr(struct dwc2_hsotg *hsotg)
 {
-       dwc2_writel(GINTSTS_DISCONNINT, hsotg->regs + GINTSTS);
+       dwc2_writel(hsotg, GINTSTS_DISCONNINT, GINTSTS);
 
        dev_dbg(hsotg->dev, "++Disconnect Detected Interrupt++ (%s) %s\n",
                dwc2_is_host_mode(hsotg) ? "Host" : "Device",
@@ -474,7 +474,7 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
        int ret;
 
        /* Clear interrupt */
-       dwc2_writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS);
+       dwc2_writel(hsotg, GINTSTS_USBSUSP, GINTSTS);
 
        dev_dbg(hsotg->dev, "USB SUSPEND\n");
 
@@ -483,7 +483,7 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
                 * Check the Device status register to determine if the Suspend
                 * state is active
                 */
-               dsts = dwc2_readl(hsotg->regs + DSTS);
+               dsts = dwc2_readl(hsotg, DSTS);
                dev_dbg(hsotg->dev, "%s: DSTS=0x%0x\n", __func__, dsts);
                dev_dbg(hsotg->dev,
                        "DSTS.Suspend Status=%d HWCFG4.Power Optimize=%d HWCFG4.Hibernation=%d\n",
@@ -563,9 +563,9 @@ static void dwc2_handle_lpm_intr(struct dwc2_hsotg *hsotg)
        u32 enslpm;
 
        /* Clear interrupt */
-       dwc2_writel(GINTSTS_LPMTRANRCVD, hsotg->regs + GINTSTS);
+       dwc2_writel(hsotg, GINTSTS_LPMTRANRCVD, GINTSTS);
 
-       glpmcfg = dwc2_readl(hsotg->regs + GLPMCFG);
+       glpmcfg = dwc2_readl(hsotg, GLPMCFG);
 
        if (!(glpmcfg & GLPMCFG_LPMCAP)) {
                dev_err(hsotg->dev, "Unexpected LPM interrupt\n");
@@ -588,16 +588,16 @@ static void dwc2_handle_lpm_intr(struct dwc2_hsotg *hsotg)
                } else {
                        dev_dbg(hsotg->dev, "Entering Sleep with L1 Gating\n");
 
-                       pcgcctl = dwc2_readl(hsotg->regs + PCGCTL);
+                       pcgcctl = dwc2_readl(hsotg, PCGCTL);
                        pcgcctl |= PCGCTL_ENBL_SLEEP_GATING;
-                       dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
+                       dwc2_writel(hsotg, pcgcctl, PCGCTL);
                }
                /**
                 * Examine prt_sleep_sts after TL1TokenTetry period max (10 us)
                 */
                udelay(10);
 
-               glpmcfg = dwc2_readl(hsotg->regs + GLPMCFG);
+               glpmcfg = dwc2_readl(hsotg, GLPMCFG);
 
                if (glpmcfg & GLPMCFG_SLPSTS) {
                        /* Save the current state */
@@ -627,9 +627,9 @@ static u32 dwc2_read_common_intr(struct dwc2_hsotg *hsotg)
        u32 gahbcfg;
        u32 gintmsk_common = GINTMSK_COMMON;
 
-       gintsts = dwc2_readl(hsotg->regs + GINTSTS);
-       gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
-       gahbcfg = dwc2_readl(hsotg->regs + GAHBCFG);
+       gintsts = dwc2_readl(hsotg, GINTSTS);
+       gintmsk = dwc2_readl(hsotg, GINTMSK);
+       gahbcfg = dwc2_readl(hsotg, GAHBCFG);
 
        /* If any common interrupts set */
        if (gintsts & gintmsk_common)
@@ -653,9 +653,9 @@ static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg *hsotg)
        u32 gpwrdn;
        int linestate;
 
-       gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+       gpwrdn = dwc2_readl(hsotg, GPWRDN);
        /* clear all interrupt */
-       dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+       dwc2_writel(hsotg, gpwrdn, GPWRDN);
        linestate = (gpwrdn & GPWRDN_LINESTATE_MASK) >> GPWRDN_LINESTATE_SHIFT;
        dev_dbg(hsotg->dev,
                "%s: dwc2_handle_gpwrdwn_intr called gpwrdn= %08x\n", __func__,
@@ -668,38 +668,38 @@ static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg *hsotg)
                dev_dbg(hsotg->dev, "%s: GPWRDN_DISCONN_DET\n", __func__);
 
                /* Switch-on voltage to the core */
-               gpwrdn_tmp = dwc2_readl(hsotg->regs + GPWRDN);
+               gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
                gpwrdn_tmp &= ~GPWRDN_PWRDNSWTCH;
-               dwc2_writel(gpwrdn_tmp, hsotg->regs + GPWRDN);
+               dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
                udelay(10);
 
                /* Reset core */
-               gpwrdn_tmp = dwc2_readl(hsotg->regs + GPWRDN);
+               gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
                gpwrdn_tmp &= ~GPWRDN_PWRDNRSTN;
-               dwc2_writel(gpwrdn_tmp, hsotg->regs + GPWRDN);
+               dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
                udelay(10);
 
                /* Disable Power Down Clamp */
-               gpwrdn_tmp = dwc2_readl(hsotg->regs + GPWRDN);
+               gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
                gpwrdn_tmp &= ~GPWRDN_PWRDNCLMP;
-               dwc2_writel(gpwrdn_tmp, hsotg->regs + GPWRDN);
+               dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
                udelay(10);
 
                /* Deassert reset core */
-               gpwrdn_tmp = dwc2_readl(hsotg->regs + GPWRDN);
+               gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
                gpwrdn_tmp |= GPWRDN_PWRDNRSTN;
-               dwc2_writel(gpwrdn_tmp, hsotg->regs + GPWRDN);
+               dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
                udelay(10);
 
                /* Disable PMU interrupt */
-               gpwrdn_tmp = dwc2_readl(hsotg->regs + GPWRDN);
+               gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
                gpwrdn_tmp &= ~GPWRDN_PMUINTSEL;
-               dwc2_writel(gpwrdn_tmp, hsotg->regs + GPWRDN);
+               dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
 
                /* De-assert Wakeup Logic */
-               gpwrdn_tmp = dwc2_readl(hsotg->regs + GPWRDN);
+               gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
                gpwrdn_tmp &= ~GPWRDN_PMUACTV;
-               dwc2_writel(gpwrdn_tmp, hsotg->regs + GPWRDN);
+               dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
 
                hsotg->hibernated = 0;
 
@@ -780,10 +780,10 @@ irqreturn_t dwc2_handle_common_intr(int irq, void *dev)
 
        /* Reading current frame number value in device or host modes. */
        if (dwc2_is_device_mode(hsotg))
-               hsotg->frame_number = (dwc2_readl(hsotg->regs + DSTS)
+               hsotg->frame_number = (dwc2_readl(hsotg, DSTS)
                                       & DSTS_SOFFN_MASK) >> DSTS_SOFFN_SHIFT;
        else
-               hsotg->frame_number = (dwc2_readl(hsotg->regs + HFNUM)
+               hsotg->frame_number = (dwc2_readl(hsotg, HFNUM)
                                       & HFNUM_FRNUM_MASK) >> HFNUM_FRNUM_SHIFT;
 
        gintsts = dwc2_read_common_intr(hsotg);
index d0bdb79..22d015b 100644 (file)
@@ -69,7 +69,7 @@ static int testmode_show(struct seq_file *s, void *unused)
        int dctl;
 
        spin_lock_irqsave(&hsotg->lock, flags);
-       dctl = dwc2_readl(hsotg->regs + DCTL);
+       dctl = dwc2_readl(hsotg, DCTL);
        dctl &= DCTL_TSTCTL_MASK;
        dctl >>= DCTL_TSTCTL_SHIFT;
        spin_unlock_irqrestore(&hsotg->lock, flags);
@@ -126,42 +126,41 @@ static const struct file_operations testmode_fops = {
 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",
-                  dwc2_readl(regs + DCFG),
-                dwc2_readl(regs + DCTL),
-                dwc2_readl(regs + DSTS));
+                  dwc2_readl(hsotg, DCFG),
+                dwc2_readl(hsotg, DCTL),
+                dwc2_readl(hsotg, DSTS));
 
        seq_printf(seq, "DIEPMSK=0x%08x, DOEPMASK=0x%08x\n",
-                  dwc2_readl(regs + DIEPMSK), dwc2_readl(regs + DOEPMSK));
+                  dwc2_readl(hsotg, DIEPMSK), dwc2_readl(hsotg, DOEPMSK));
 
        seq_printf(seq, "GINTMSK=0x%08x, GINTSTS=0x%08x\n",
-                  dwc2_readl(regs + GINTMSK),
-                  dwc2_readl(regs + GINTSTS));
+                  dwc2_readl(hsotg, GINTMSK),
+                  dwc2_readl(hsotg, GINTSTS));
 
        seq_printf(seq, "DAINTMSK=0x%08x, DAINT=0x%08x\n",
-                  dwc2_readl(regs + DAINTMSK),
-                  dwc2_readl(regs + DAINT));
+                  dwc2_readl(hsotg, DAINTMSK),
+                  dwc2_readl(hsotg, DAINT));
 
        seq_printf(seq, "GNPTXSTS=0x%08x, GRXSTSR=%08x\n",
-                  dwc2_readl(regs + GNPTXSTS),
-                  dwc2_readl(regs + GRXSTSR));
+                  dwc2_readl(hsotg, GNPTXSTS),
+                  dwc2_readl(hsotg, GRXSTSR));
 
        seq_puts(seq, "\nEndpoint status:\n");
 
        for (idx = 0; idx < hsotg->num_of_eps; idx++) {
                u32 in, out;
 
-               in = dwc2_readl(regs + DIEPCTL(idx));
-               out = dwc2_readl(regs + DOEPCTL(idx));
+               in = dwc2_readl(hsotg, DIEPCTL(idx));
+               out = dwc2_readl(hsotg, DOEPCTL(idx));
 
                seq_printf(seq, "ep%d: DIEPCTL=0x%08x, DOEPCTL=0x%08x",
                           idx, in, out);
 
-               in = dwc2_readl(regs + DIEPTSIZ(idx));
-               out = dwc2_readl(regs + DOEPTSIZ(idx));
+               in = dwc2_readl(hsotg, DIEPTSIZ(idx));
+               out = dwc2_readl(hsotg, DOEPTSIZ(idx));
 
                seq_printf(seq, ", DIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x",
                           in, out);
@@ -184,14 +183,13 @@ DEFINE_SHOW_ATTRIBUTE(state);
 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", dwc2_readl(regs + GRXFSIZ));
+       seq_printf(seq, "RXFIFO: Size %d\n", dwc2_readl(hsotg, GRXFSIZ));
 
-       val = dwc2_readl(regs + GNPTXFSIZ);
+       val = dwc2_readl(hsotg, GNPTXFSIZ);
        seq_printf(seq, "NPTXFIFO: Size %d, Start 0x%08x\n",
                   val >> FIFOSIZE_DEPTH_SHIFT,
                   val & FIFOSIZE_STARTADDR_MASK);
@@ -199,7 +197,7 @@ static int fifo_show(struct seq_file *seq, void *v)
        seq_puts(seq, "\nPeriodic TXFIFOs:\n");
 
        for (idx = 1; idx < hsotg->num_of_eps; idx++) {
-               val = dwc2_readl(regs + DPTXFSIZN(idx));
+               val = dwc2_readl(hsotg, DPTXFSIZN(idx));
 
                seq_printf(seq, "\tDPTXFIFO%2d: Size %d, Start 0x%08x\n", idx,
                           val >> FIFOSIZE_DEPTH_SHIFT,
@@ -228,7 +226,6 @@ static int ep_show(struct seq_file *seq, void *v)
        struct dwc2_hsotg_ep *ep = seq->private;
        struct dwc2_hsotg *hsotg = ep->parent;
        struct dwc2_hsotg_req *req;
-       void __iomem *regs = hsotg->regs;
        int index = ep->index;
        int show_limit = 15;
        unsigned long flags;
@@ -239,20 +236,20 @@ static int ep_show(struct seq_file *seq, void *v)
        /* first show the register state */
 
        seq_printf(seq, "\tDIEPCTL=0x%08x, DOEPCTL=0x%08x\n",
-                  dwc2_readl(regs + DIEPCTL(index)),
-                  dwc2_readl(regs + DOEPCTL(index)));
+                  dwc2_readl(hsotg, DIEPCTL(index)),
+                  dwc2_readl(hsotg, DOEPCTL(index)));
 
        seq_printf(seq, "\tDIEPDMA=0x%08x, DOEPDMA=0x%08x\n",
-                  dwc2_readl(regs + DIEPDMA(index)),
-                  dwc2_readl(regs + DOEPDMA(index)));
+                  dwc2_readl(hsotg, DIEPDMA(index)),
+                  dwc2_readl(hsotg, DOEPDMA(index)));
 
        seq_printf(seq, "\tDIEPINT=0x%08x, DOEPINT=0x%08x\n",
-                  dwc2_readl(regs + DIEPINT(index)),
-                  dwc2_readl(regs + DOEPINT(index)));
+                  dwc2_readl(hsotg, DIEPINT(index)),
+                  dwc2_readl(hsotg, DOEPINT(index)));
 
        seq_printf(seq, "\tDIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x\n",
-                  dwc2_readl(regs + DIEPTSIZ(index)),
-                  dwc2_readl(regs + DOEPTSIZ(index)));
+                  dwc2_readl(hsotg, DIEPTSIZ(index)),
+                  dwc2_readl(hsotg, DOEPTSIZ(index)));
 
        seq_puts(seq, "\n");
        seq_printf(seq, "mps %d\n", ep->ep.maxpacket);
index cefc99a..220c0f9 100644 (file)
@@ -47,14 +47,14 @@ static inline struct dwc2_hsotg *to_hsotg(struct usb_gadget *gadget)
        return container_of(gadget, struct dwc2_hsotg, gadget);
 }
 
-static inline void dwc2_set_bit(void __iomem *ptr, u32 val)
+static inline void dwc2_set_bit(struct dwc2_hsotg *hsotg, u32 offset, u32 val)
 {
-       dwc2_writel(dwc2_readl(ptr) | val, ptr);
+       dwc2_writel(hsotg, dwc2_readl(hsotg, offset) | val, offset);
 }
 
-static inline void dwc2_clear_bit(void __iomem *ptr, u32 val)
+static inline void dwc2_clear_bit(struct dwc2_hsotg *hsotg, u32 offset, u32 val)
 {
-       dwc2_writel(dwc2_readl(ptr) & ~val, ptr);
+       dwc2_writel(hsotg, dwc2_readl(hsotg, offset) & ~val, offset);
 }
 
 static inline struct dwc2_hsotg_ep *index_to_ep(struct dwc2_hsotg *hsotg,
@@ -129,14 +129,14 @@ static inline void dwc2_gadget_incr_frame_num(struct dwc2_hsotg_ep *hs_ep)
  */
 static void dwc2_hsotg_en_gsint(struct dwc2_hsotg *hsotg, u32 ints)
 {
-       u32 gsintmsk = dwc2_readl(hsotg->regs + GINTMSK);
+       u32 gsintmsk = dwc2_readl(hsotg, GINTMSK);
        u32 new_gsintmsk;
 
        new_gsintmsk = gsintmsk | ints;
 
        if (new_gsintmsk != gsintmsk) {
                dev_dbg(hsotg->dev, "gsintmsk now 0x%08x\n", new_gsintmsk);
-               dwc2_writel(new_gsintmsk, hsotg->regs + GINTMSK);
+               dwc2_writel(hsotg, new_gsintmsk, GINTMSK);
        }
 }
 
@@ -147,13 +147,13 @@ static void dwc2_hsotg_en_gsint(struct dwc2_hsotg *hsotg, u32 ints)
  */
 static void dwc2_hsotg_disable_gsint(struct dwc2_hsotg *hsotg, u32 ints)
 {
-       u32 gsintmsk = dwc2_readl(hsotg->regs + GINTMSK);
+       u32 gsintmsk = dwc2_readl(hsotg, GINTMSK);
        u32 new_gsintmsk;
 
        new_gsintmsk = gsintmsk & ~ints;
 
        if (new_gsintmsk != gsintmsk)
-               dwc2_writel(new_gsintmsk, hsotg->regs + GINTMSK);
+               dwc2_writel(hsotg, new_gsintmsk, GINTMSK);
 }
 
 /**
@@ -178,12 +178,12 @@ static void dwc2_hsotg_ctrl_epint(struct dwc2_hsotg *hsotg,
                bit <<= 16;
 
        local_irq_save(flags);
-       daint = dwc2_readl(hsotg->regs + DAINTMSK);
+       daint = dwc2_readl(hsotg, DAINTMSK);
        if (en)
                daint |= bit;
        else
                daint &= ~bit;
-       dwc2_writel(daint, hsotg->regs + DAINTMSK);
+       dwc2_writel(hsotg, daint, DAINTMSK);
        local_irq_restore(flags);
 }
 
@@ -266,10 +266,11 @@ static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg)
        hsotg->fifo_map = 0;
 
        /* set RX/NPTX FIFO sizes */
-       dwc2_writel(hsotg->params.g_rx_fifo_size, hsotg->regs + GRXFSIZ);
-       dwc2_writel((hsotg->params.g_rx_fifo_size << FIFOSIZE_STARTADDR_SHIFT) |
+       dwc2_writel(hsotg, hsotg->params.g_rx_fifo_size, GRXFSIZ);
+       dwc2_writel(hsotg, (hsotg->params.g_rx_fifo_size <<
+                   FIFOSIZE_STARTADDR_SHIFT) |
                    (hsotg->params.g_np_tx_fifo_size << FIFOSIZE_DEPTH_SHIFT),
-                   hsotg->regs + GNPTXFSIZ);
+                   GNPTXFSIZ);
 
        /*
         * arange all the rest of the TX FIFOs, as some versions of this
@@ -295,25 +296,25 @@ static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg)
                          "insufficient fifo memory");
                addr += txfsz[ep];
 
-               dwc2_writel(val, hsotg->regs + DPTXFSIZN(ep));
-               val = dwc2_readl(hsotg->regs + DPTXFSIZN(ep));
+               dwc2_writel(hsotg, val, DPTXFSIZN(ep));
+               val = dwc2_readl(hsotg, DPTXFSIZN(ep));
        }
 
-       dwc2_writel(hsotg->hw_params.total_fifo_size |
+       dwc2_writel(hsotg, hsotg->hw_params.total_fifo_size |
                    addr << GDFIFOCFG_EPINFOBASE_SHIFT,
-                   hsotg->regs + GDFIFOCFG);
+                   GDFIFOCFG);
        /*
         * according to p428 of the design guide, we need to ensure that
         * all fifos are flushed before continuing
         */
 
-       dwc2_writel(GRSTCTL_TXFNUM(0x10) | GRSTCTL_TXFFLSH |
-              GRSTCTL_RXFFLSH, hsotg->regs + GRSTCTL);
+       dwc2_writel(hsotg, GRSTCTL_TXFNUM(0x10) | GRSTCTL_TXFFLSH |
+              GRSTCTL_RXFFLSH, GRSTCTL);
 
        /* wait until the fifos are both flushed */
        timeout = 100;
        while (1) {
-               val = dwc2_readl(hsotg->regs + GRSTCTL);
+               val = dwc2_readl(hsotg, GRSTCTL);
 
                if ((val & (GRSTCTL_TXFFLSH | GRSTCTL_RXFFLSH)) == 0)
                        break;
@@ -451,7 +452,7 @@ static int dwc2_hsotg_write_fifo(struct dwc2_hsotg *hsotg,
                                struct dwc2_hsotg_req *hs_req)
 {
        bool periodic = is_ep_periodic(hs_ep);
-       u32 gnptxsts = dwc2_readl(hsotg->regs + GNPTXSTS);
+       u32 gnptxsts = dwc2_readl(hsotg, GNPTXSTS);
        int buf_pos = hs_req->req.actual;
        int to_write = hs_ep->size_loaded;
        void *data;
@@ -466,7 +467,7 @@ static int dwc2_hsotg_write_fifo(struct dwc2_hsotg *hsotg,
                return 0;
 
        if (periodic && !hsotg->dedicated_fifos) {
-               u32 epsize = dwc2_readl(hsotg->regs + DIEPTSIZ(hs_ep->index));
+               u32 epsize = dwc2_readl(hsotg, DIEPTSIZ(hs_ep->index));
                int size_left;
                int size_done;
 
@@ -507,8 +508,8 @@ static int dwc2_hsotg_write_fifo(struct dwc2_hsotg *hsotg,
                        return -ENOSPC;
                }
        } else if (hsotg->dedicated_fifos && hs_ep->index != 0) {
-               can_write = dwc2_readl(hsotg->regs +
-                               DTXFSTS(hs_ep->fifo_index));
+               can_write = dwc2_readl(hsotg,
+                                      DTXFSTS(hs_ep->fifo_index));
 
                can_write &= 0xffff;
                can_write *= 4;
@@ -598,7 +599,7 @@ static int dwc2_hsotg_write_fifo(struct dwc2_hsotg *hsotg,
        to_write = DIV_ROUND_UP(to_write, 4);
        data = hs_req->req.buf + buf_pos;
 
-       iowrite32_rep(hsotg->regs + EPFIFO(hs_ep->index), data, to_write);
+       dwc2_writel_rep(hsotg, EPFIFO(hs_ep->index), data, to_write);
 
        return (to_write >= can_write) ? -ENOSPC : 0;
 }
@@ -652,7 +653,7 @@ static u32 dwc2_hsotg_read_frameno(struct dwc2_hsotg *hsotg)
 {
        u32 dsts;
 
-       dsts = dwc2_readl(hsotg->regs + DSTS);
+       dsts = dwc2_readl(hsotg, DSTS);
        dsts &= DSTS_SOFFN_MASK;
        dsts >>= DSTS_SOFFN_SHIFT;
 
@@ -915,11 +916,11 @@ static void dwc2_gadget_start_isoc_ddma(struct dwc2_hsotg_ep *hs_ep)
        dma_reg = hs_ep->dir_in ? DIEPDMA(index) : DOEPDMA(index);
 
        /* write descriptor chain address to control register */
-       dwc2_writel(hs_ep->desc_list_dma, hsotg->regs + dma_reg);
+       dwc2_writel(hsotg, hs_ep->desc_list_dma, dma_reg);
 
-       ctrl = dwc2_readl(hsotg->regs + depctl);
+       ctrl = dwc2_readl(hsotg, depctl);
        ctrl |= DXEPCTL_EPENA | DXEPCTL_CNAK;
-       dwc2_writel(ctrl, hsotg->regs + depctl);
+       dwc2_writel(hsotg, ctrl, depctl);
 }
 
 /**
@@ -967,11 +968,11 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg,
        epsize_reg = dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index);
 
        dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x, ep %d, dir %s\n",
-               __func__, dwc2_readl(hsotg->regs + epctrl_reg), index,
+               __func__, dwc2_readl(hsotg, epctrl_reg), index,
                hs_ep->dir_in ? "in" : "out");
 
        /* If endpoint is stalled, we will restart request later */
-       ctrl = dwc2_readl(hsotg->regs + epctrl_reg);
+       ctrl = dwc2_readl(hsotg, epctrl_reg);
 
        if (index && ctrl & DXEPCTL_STALL) {
                dev_warn(hsotg->dev, "%s: ep%d is stalled\n", __func__, index);
@@ -1064,13 +1065,13 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg,
                                                     length);
 
                /* write descriptor chain address to control register */
-               dwc2_writel(hs_ep->desc_list_dma, hsotg->regs + dma_reg);
+               dwc2_writel(hsotg, hs_ep->desc_list_dma, dma_reg);
 
                dev_dbg(hsotg->dev, "%s: %08x pad => 0x%08x\n",
                        __func__, (u32)hs_ep->desc_list_dma, dma_reg);
        } else {
                /* write size / packets */
-               dwc2_writel(epsize, hsotg->regs + epsize_reg);
+               dwc2_writel(hsotg, epsize, epsize_reg);
 
                if (using_dma(hsotg) && !continuing && (length != 0)) {
                        /*
@@ -1078,7 +1079,7 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg,
                         * already synced by dwc2_hsotg_ep_queue().
                         */
 
-                       dwc2_writel(ureq->dma, hsotg->regs + dma_reg);
+                       dwc2_writel(hsotg, ureq->dma, dma_reg);
 
                        dev_dbg(hsotg->dev, "%s: %pad => 0x%08x\n",
                                __func__, &ureq->dma, dma_reg);
@@ -1104,7 +1105,7 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg,
                ctrl |= DXEPCTL_CNAK;   /* clear NAK set by core */
 
        dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl);
-       dwc2_writel(ctrl, hsotg->regs + epctrl_reg);
+       dwc2_writel(hsotg, ctrl, epctrl_reg);
 
        /*
         * set these, it seems that DMA support increments past the end
@@ -1127,13 +1128,13 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg,
         */
 
        /* check ep is enabled */
-       if (!(dwc2_readl(hsotg->regs + epctrl_reg) & DXEPCTL_EPENA))
+       if (!(dwc2_readl(hsotg, epctrl_reg) & DXEPCTL_EPENA))
                dev_dbg(hsotg->dev,
                        "ep%d: failed to become enabled (DXEPCTL=0x%08x)?\n",
-                        index, dwc2_readl(hsotg->regs + epctrl_reg));
+                        index, dwc2_readl(hsotg, epctrl_reg));
 
        dev_dbg(hsotg->dev, "%s: DXEPCTL=0x%08x\n",
-               __func__, dwc2_readl(hsotg->regs + epctrl_reg));
+               __func__, dwc2_readl(hsotg, epctrl_reg));
 
        /* enable ep interrupts */
        dwc2_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 1);
@@ -1466,7 +1467,7 @@ static struct dwc2_hsotg_ep *ep_from_windex(struct dwc2_hsotg *hsotg,
  */
 int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode)
 {
-       int dctl = dwc2_readl(hsotg->regs + DCTL);
+       int dctl = dwc2_readl(hsotg, DCTL);
 
        dctl &= ~DCTL_TSTCTL_MASK;
        switch (testmode) {
@@ -1480,7 +1481,7 @@ int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode)
        default:
                return -EINVAL;
        }
-       dwc2_writel(dctl, hsotg->regs + DCTL);
+       dwc2_writel(hsotg, dctl, DCTL);
        return 0;
 }
 
@@ -1634,9 +1635,9 @@ static void dwc2_gadget_start_next_request(struct dwc2_hsotg_ep *hs_ep)
        } else {
                dev_dbg(hsotg->dev, "%s: No more ISOC-OUT requests\n",
                        __func__);
-               mask = dwc2_readl(hsotg->regs + epmsk_reg);
+               mask = dwc2_readl(hsotg, epmsk_reg);
                mask |= DOEPMSK_OUTTKNEPDISMSK;
-               dwc2_writel(mask, hsotg->regs + epmsk_reg);
+               dwc2_writel(hsotg, mask, epmsk_reg);
        }
 }
 
@@ -1773,14 +1774,14 @@ static void dwc2_hsotg_stall_ep0(struct dwc2_hsotg *hsotg)
         * taken effect, so no need to clear later.
         */
 
-       ctrl = dwc2_readl(hsotg->regs + reg);
+       ctrl = dwc2_readl(hsotg, reg);
        ctrl |= DXEPCTL_STALL;
        ctrl |= DXEPCTL_CNAK;
-       dwc2_writel(ctrl, hsotg->regs + reg);
+       dwc2_writel(hsotg, ctrl, reg);
 
        dev_dbg(hsotg->dev,
                "written DXEPCTL=0x%08x to %08x (DXEPCTL=0x%08x)\n",
-               ctrl, reg, dwc2_readl(hsotg->regs + reg));
+               ctrl, reg, dwc2_readl(hsotg, reg));
 
         /*
          * complete won't be called, so we enqueue
@@ -1825,11 +1826,11 @@ static void dwc2_hsotg_process_control(struct dwc2_hsotg *hsotg,
                switch (ctrl->bRequest) {
                case USB_REQ_SET_ADDRESS:
                        hsotg->connected = 1;
-                       dcfg = dwc2_readl(hsotg->regs + DCFG);
+                       dcfg = dwc2_readl(hsotg, DCFG);
                        dcfg &= ~DCFG_DEVADDR_MASK;
                        dcfg |= (le16_to_cpu(ctrl->wValue) <<
                                 DCFG_DEVADDR_SHIFT) & DCFG_DEVADDR_MASK;
-                       dwc2_writel(dcfg, hsotg->regs + DCFG);
+                       dwc2_writel(hsotg, dcfg, DCFG);
 
                        dev_info(hsotg->dev, "new address %d\n", ctrl->wValue);
 
@@ -1955,16 +1956,16 @@ static void dwc2_hsotg_program_zlp(struct dwc2_hsotg *hsotg,
 
                dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, dma, 0);
        } else {
-               dwc2_writel(DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) |
-                           DXEPTSIZ_XFERSIZE(0), hsotg->regs +
+               dwc2_writel(hsotg, DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) |
+                           DXEPTSIZ_XFERSIZE(0),
                            epsiz_reg);
        }
 
-       ctrl = dwc2_readl(hsotg->regs + epctl_reg);
+       ctrl = dwc2_readl(hsotg, epctl_reg);
        ctrl |= DXEPCTL_CNAK;  /* clear NAK set by core */
        ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */
        ctrl |= DXEPCTL_USBACTEP;
-       dwc2_writel(ctrl, hsotg->regs + epctl_reg);
+       dwc2_writel(hsotg, ctrl, epctl_reg);
 }
 
 /**
@@ -2124,13 +2125,12 @@ static void dwc2_hsotg_rx_data(struct dwc2_hsotg *hsotg, int ep_idx, int size)
 {
        struct dwc2_hsotg_ep *hs_ep = hsotg->eps_out[ep_idx];
        struct dwc2_hsotg_req *hs_req = hs_ep->req;
-       void __iomem *fifo = hsotg->regs + EPFIFO(ep_idx);
        int to_read;
        int max_req;
        int read_ptr;
 
        if (!hs_req) {
-               u32 epctl = dwc2_readl(hsotg->regs + DOEPCTL(ep_idx));
+               u32 epctl = dwc2_readl(hsotg, DOEPCTL(ep_idx));
                int ptr;
 
                dev_dbg(hsotg->dev,
@@ -2139,7 +2139,7 @@ static void dwc2_hsotg_rx_data(struct dwc2_hsotg *hsotg, int ep_idx, int size)
 
                /* dump the data from the FIFO, we've nothing we can do */
                for (ptr = 0; ptr < size; ptr += 4)
-                       (void)dwc2_readl(fifo);
+                       (void)dwc2_readl(hsotg, EPFIFO(ep_idx));
 
                return;
        }
@@ -2169,7 +2169,8 @@ static void dwc2_hsotg_rx_data(struct dwc2_hsotg *hsotg, int ep_idx, int size)
         * note, we might over-write the buffer end by 3 bytes depending on
         * alignment of the data.
         */
-       ioread32_rep(fifo, hs_req->req.buf + read_ptr, to_read);
+       dwc2_readl_rep(hsotg, EPFIFO(ep_idx),
+                      hs_req->req.buf + read_ptr, to_read);
 }
 
 /**
@@ -2198,12 +2199,12 @@ static void dwc2_hsotg_change_ep_iso_parity(struct dwc2_hsotg *hsotg,
 {
        u32 ctrl;
 
-       ctrl = dwc2_readl(hsotg->regs + epctl_reg);
+       ctrl = dwc2_readl(hsotg, epctl_reg);
        if (ctrl & DXEPCTL_EOFRNUM)
                ctrl |= DXEPCTL_SETEVENFR;
        else
                ctrl |= DXEPCTL_SETODDFR;
-       dwc2_writel(ctrl, hsotg->regs + epctl_reg);
+       dwc2_writel(hsotg, ctrl, epctl_reg);
 }
 
 /*
@@ -2247,7 +2248,7 @@ static unsigned int dwc2_gadget_get_xfersize_ddma(struct dwc2_hsotg_ep *hs_ep)
  */
 static void dwc2_hsotg_handle_outdone(struct dwc2_hsotg *hsotg, int epnum)
 {
-       u32 epsize = dwc2_readl(hsotg->regs + DOEPTSIZ(epnum));
+       u32 epsize = dwc2_readl(hsotg, DOEPTSIZ(epnum));
        struct dwc2_hsotg_ep *hs_ep = hsotg->eps_out[epnum];
        struct dwc2_hsotg_req *hs_req = hs_ep->req;
        struct usb_request *req = &hs_req->req;
@@ -2343,7 +2344,7 @@ static void dwc2_hsotg_handle_outdone(struct dwc2_hsotg *hsotg, int epnum)
  */
 static void dwc2_hsotg_handle_rx(struct dwc2_hsotg *hsotg)
 {
-       u32 grxstsr = dwc2_readl(hsotg->regs + GRXSTSP);
+       u32 grxstsr = dwc2_readl(hsotg, GRXSTSP);
        u32 epnum, status, size;
 
        WARN_ON(using_dma(hsotg));
@@ -2374,7 +2375,7 @@ static void dwc2_hsotg_handle_rx(struct dwc2_hsotg *hsotg)
                dev_dbg(hsotg->dev,
                        "SetupDone (Frame=0x%08x, DOPEPCTL=0x%08x)\n",
                        dwc2_hsotg_read_frameno(hsotg),
-                       dwc2_readl(hsotg->regs + DOEPCTL(0)));
+                       dwc2_readl(hsotg, DOEPCTL(0)));
                /*
                 * Call dwc2_hsotg_handle_outdone here if it was not called from
                 * GRXSTS_PKTSTS_OUTDONE. That is, if the core didn't
@@ -2392,7 +2393,7 @@ static void dwc2_hsotg_handle_rx(struct dwc2_hsotg *hsotg)
                dev_dbg(hsotg->dev,
                        "SetupRX (Frame=0x%08x, DOPEPCTL=0x%08x)\n",
                        dwc2_hsotg_read_frameno(hsotg),
-                       dwc2_readl(hsotg->regs + DOEPCTL(0)));
+                       dwc2_readl(hsotg, DOEPCTL(0)));
 
                WARN_ON(hsotg->ep0_state != DWC2_EP0_SETUP);
 
@@ -2446,7 +2447,6 @@ static void dwc2_hsotg_set_ep_maxpacket(struct dwc2_hsotg *hsotg,
                                        unsigned int mc, unsigned int dir_in)
 {
        struct dwc2_hsotg_ep *hs_ep;
-       void __iomem *regs = hsotg->regs;
        u32 reg;
 
        hs_ep = index_to_ep(hsotg, ep, dir_in);
@@ -2472,15 +2472,15 @@ static void dwc2_hsotg_set_ep_maxpacket(struct dwc2_hsotg *hsotg,
        }
 
        if (dir_in) {
-               reg = dwc2_readl(regs + DIEPCTL(ep));
+               reg = dwc2_readl(hsotg, DIEPCTL(ep));
                reg &= ~DXEPCTL_MPS_MASK;
                reg |= mps;
-               dwc2_writel(reg, regs + DIEPCTL(ep));
+               dwc2_writel(hsotg, reg, DIEPCTL(ep));
        } else {
-               reg = dwc2_readl(regs + DOEPCTL(ep));
+               reg = dwc2_readl(hsotg, DOEPCTL(ep));
                reg &= ~DXEPCTL_MPS_MASK;
                reg |= mps;
-               dwc2_writel(reg, regs + DOEPCTL(ep));
+               dwc2_writel(hsotg, reg, DOEPCTL(ep));
        }
 
        return;
@@ -2496,8 +2496,8 @@ bad_mps:
  */
 static void dwc2_hsotg_txfifo_flush(struct dwc2_hsotg *hsotg, unsigned int idx)
 {
-       dwc2_writel(GRSTCTL_TXFNUM(idx) | GRSTCTL_TXFFLSH,
-                   hsotg->regs + GRSTCTL);
+       dwc2_writel(hsotg, GRSTCTL_TXFNUM(idx) | GRSTCTL_TXFFLSH,
+                   GRSTCTL);
 
        /* wait until the fifo is flushed */
        if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_TXFFLSH, 100))
@@ -2550,7 +2550,7 @@ static void dwc2_hsotg_complete_in(struct dwc2_hsotg *hsotg,
                                   struct dwc2_hsotg_ep *hs_ep)
 {
        struct dwc2_hsotg_req *hs_req = hs_ep->req;
-       u32 epsize = dwc2_readl(hsotg->regs + DIEPTSIZ(hs_ep->index));
+       u32 epsize = dwc2_readl(hsotg, DIEPTSIZ(hs_ep->index));
        int size_left, size_done;
 
        if (!hs_req) {
@@ -2654,12 +2654,12 @@ static u32 dwc2_gadget_read_ep_interrupts(struct dwc2_hsotg *hsotg,
        u32 mask;
        u32 diepempmsk;
 
-       mask = dwc2_readl(hsotg->regs + epmsk_reg);
-       diepempmsk = dwc2_readl(hsotg->regs + DIEPEMPMSK);
+       mask = dwc2_readl(hsotg, epmsk_reg);
+       diepempmsk = dwc2_readl(hsotg, DIEPEMPMSK);
        mask |= ((diepempmsk >> idx) & 0x1) ? DIEPMSK_TXFIFOEMPTY : 0;
        mask |= DXEPINT_SETUP_RCVD;
 
-       ints = dwc2_readl(hsotg->regs + epint_reg);
+       ints = dwc2_readl(hsotg, epint_reg);
        ints &= mask;
        return ints;
 }
@@ -2684,12 +2684,12 @@ static void dwc2_gadget_handle_ep_disabled(struct dwc2_hsotg_ep *hs_ep)
        unsigned char idx = hs_ep->index;
        int dir_in = hs_ep->dir_in;
        u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx);
-       int dctl = dwc2_readl(hsotg->regs + DCTL);
+       int dctl = dwc2_readl(hsotg, DCTL);
 
        dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__);
 
        if (dir_in) {
-               int epctl = dwc2_readl(hsotg->regs + epctl_reg);
+               int epctl = dwc2_readl(hsotg, epctl_reg);
 
                dwc2_hsotg_txfifo_flush(hsotg, hs_ep->fifo_index);
 
@@ -2699,17 +2699,17 @@ static void dwc2_gadget_handle_ep_disabled(struct dwc2_hsotg_ep *hs_ep)
                }
 
                if ((epctl & DXEPCTL_STALL) && (epctl & DXEPCTL_EPTYPE_BULK)) {
-                       int dctl = dwc2_readl(hsotg->regs + DCTL);
+                       int dctl = dwc2_readl(hsotg, DCTL);
 
                        dctl |= DCTL_CGNPINNAK;
-                       dwc2_writel(dctl, hsotg->regs + DCTL);
+                       dwc2_writel(hsotg, dctl, DCTL);
                }
                return;
        }
 
        if (dctl & DCTL_GOUTNAKSTS) {
                dctl |= DCTL_CGOUTNAK;
-               dwc2_writel(dctl, hsotg->regs + DCTL);
+               dwc2_writel(hsotg, dctl, DCTL);
        }
 
        if (!hs_ep->isochronous)
@@ -2750,21 +2750,14 @@ static void dwc2_gadget_handle_out_token_ep_disabled(struct dwc2_hsotg_ep *ep)
        struct dwc2_hsotg *hsotg = ep->parent;
        int dir_in = ep->dir_in;
        u32 doepmsk;
-       u32 tmp;
 
        if (dir_in || !ep->isochronous)
                return;
 
-       /*
-        * Store frame in which irq was asserted here, as
-        * it can change while completing request below.
-        */
-       tmp = dwc2_hsotg_read_frameno(hsotg);
-
        if (using_desc_dma(hsotg)) {
                if (ep->target_frame == TARGET_FRAME_INITIAL) {
                        /* Start first ISO Out */
-                       ep->target_frame = tmp;
+                       ep->target_frame = hsotg->frame_number;
                        dwc2_gadget_start_isoc_ddma(ep);
                }
                return;
@@ -2772,26 +2765,24 @@ static void dwc2_gadget_handle_out_token_ep_disabled(struct dwc2_hsotg_ep *ep)
 
        if (ep->interval > 1 &&
            ep->target_frame == TARGET_FRAME_INITIAL) {
-               u32 dsts;
                u32 ctrl;
 
-               dsts = dwc2_readl(hsotg->regs + DSTS);
-               ep->target_frame = dwc2_hsotg_read_frameno(hsotg);
+               ep->target_frame = hsotg->frame_number;
                dwc2_gadget_incr_frame_num(ep);
 
-               ctrl = dwc2_readl(hsotg->regs + DOEPCTL(ep->index));
+               ctrl = dwc2_readl(hsotg, DOEPCTL(ep->index));
                if (ep->target_frame & 0x1)
                        ctrl |= DXEPCTL_SETODDFR;
                else
                        ctrl |= DXEPCTL_SETEVENFR;
 
-               dwc2_writel(ctrl, hsotg->regs + DOEPCTL(ep->index));
+               dwc2_writel(hsotg, ctrl, DOEPCTL(ep->index));
        }
 
        dwc2_gadget_start_next_request(ep);
-       doepmsk = dwc2_readl(hsotg->regs + DOEPMSK);
+       doepmsk = dwc2_readl(hsotg, DOEPMSK);
        doepmsk &= ~DOEPMSK_OUTTKNEPDISMSK;
-       dwc2_writel(doepmsk, hsotg->regs + DOEPMSK);
+       dwc2_writel(hsotg, doepmsk, DOEPMSK);
 }
 
 /**
@@ -2812,31 +2803,29 @@ static void dwc2_gadget_handle_nak(struct dwc2_hsotg_ep *hs_ep)
 {
        struct dwc2_hsotg *hsotg = hs_ep->parent;
        int dir_in = hs_ep->dir_in;
-       u32 tmp;
 
        if (!dir_in || !hs_ep->isochronous)
                return;
 
        if (hs_ep->target_frame == TARGET_FRAME_INITIAL) {
 
-               tmp = dwc2_hsotg_read_frameno(hsotg);
                if (using_desc_dma(hsotg)) {
-                       hs_ep->target_frame = tmp;
+                       hs_ep->target_frame = hsotg->frame_number;
                        dwc2_gadget_incr_frame_num(hs_ep);
                        dwc2_gadget_start_isoc_ddma(hs_ep);
                        return;
                }
 
-               hs_ep->target_frame = tmp;
+               hs_ep->target_frame = hsotg->frame_number;
                if (hs_ep->interval > 1) {
-                       u32 ctrl = dwc2_readl(hsotg->regs +
+                       u32 ctrl = dwc2_readl(hsotg,
                                              DIEPCTL(hs_ep->index));
                        if (hs_ep->target_frame & 0x1)
                                ctrl |= DXEPCTL_SETODDFR;
                        else
                                ctrl |= DXEPCTL_SETEVENFR;
 
-                       dwc2_writel(ctrl, hsotg->regs + DIEPCTL(hs_ep->index));
+                       dwc2_writel(hsotg, ctrl, DIEPCTL(hs_ep->index));
                }
 
                dwc2_hsotg_complete_request(hsotg, hs_ep,
@@ -2866,10 +2855,10 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx,
        u32 ctrl;
 
        ints = dwc2_gadget_read_ep_interrupts(hsotg, idx, dir_in);
-       ctrl = dwc2_readl(hsotg->regs + epctl_reg);
+       ctrl = dwc2_readl(hsotg, epctl_reg);
 
        /* Clear endpoint interrupts */
-       dwc2_writel(ints, hsotg->regs + epint_reg);
+       dwc2_writel(hsotg, ints, epint_reg);
 
        if (!hs_ep) {
                dev_err(hsotg->dev, "%s:Interrupt for unconfigured ep%d(%s)\n",
@@ -2897,8 +2886,8 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx,
        if (ints & DXEPINT_XFERCOMPL) {
                dev_dbg(hsotg->dev,
                        "%s: XferCompl: DxEPCTL=0x%08x, DXEPTSIZ=%08x\n",
-                       __func__, dwc2_readl(hsotg->regs + epctl_reg),
-                       dwc2_readl(hsotg->regs + epsiz_reg));
+                       __func__, dwc2_readl(hsotg, epctl_reg),
+                       dwc2_readl(hsotg, epsiz_reg));
 
                /* In DDMA handle isochronous requests separately */
                if (using_desc_dma(hsotg) && hs_ep->isochronous) {
@@ -3016,7 +3005,7 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx,
  */
 static void dwc2_hsotg_irq_enumdone(struct dwc2_hsotg *hsotg)
 {
-       u32 dsts = dwc2_readl(hsotg->regs + DSTS);
+       u32 dsts = dwc2_readl(hsotg, DSTS);
        int ep0_mps = 0, ep_mps = 8;
 
        /*
@@ -3087,8 +3076,8 @@ static void dwc2_hsotg_irq_enumdone(struct dwc2_hsotg *hsotg)
        dwc2_hsotg_enqueue_setup(hsotg);
 
        dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
-               dwc2_readl(hsotg->regs + DIEPCTL0),
-               dwc2_readl(hsotg->regs + DOEPCTL0));
+               dwc2_readl(hsotg, DIEPCTL0),
+               dwc2_readl(hsotg, DOEPCTL0));
 }
 
 /**
@@ -3115,7 +3104,7 @@ static void kill_all_requests(struct dwc2_hsotg *hsotg,
 
        if (!hsotg->dedicated_fifos)
                return;
-       size = (dwc2_readl(hsotg->regs + DTXFSTS(ep->fifo_index)) & 0xffff) * 4;
+       size = (dwc2_readl(hsotg, DTXFSTS(ep->fifo_index)) & 0xffff) * 4;
        if (size < ep->fifo_size)
                dwc2_hsotg_txfifo_flush(hsotg, ep->fifo_index);
 }
@@ -3216,7 +3205,7 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
         */
 
        /* keep other bits untouched (so e.g. forced modes are not lost) */
-       usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
+       usbcfg = dwc2_readl(hsotg, GUSBCFG);
        usbcfg &= ~(GUSBCFG_TOUTCAL_MASK | GUSBCFG_PHYIF16 | GUSBCFG_SRPCAP |
                GUSBCFG_HNPCAP | GUSBCFG_USBTRDTIM_MASK);
 
@@ -3231,12 +3220,12 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
                usbcfg |= hsotg->phyif | GUSBCFG_TOUTCAL(7) |
                        (val << GUSBCFG_USBTRDTIM_SHIFT);
        }
-       dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
+       dwc2_writel(hsotg, usbcfg, GUSBCFG);
 
        dwc2_hsotg_init_fifo(hsotg);
 
        if (!is_usb_reset)
-               dwc2_set_bit(hsotg->regs + DCTL, DCTL_SFTDISCON);
+               dwc2_set_bit(hsotg, DCTL, DCTL_SFTDISCON);
 
        dcfg |= DCFG_EPMISCNT(1);
 
@@ -3257,13 +3246,13 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
        if (hsotg->params.ipg_isoc_en)
                dcfg |= DCFG_IPG_ISOC_SUPPORDED;
 
-       dwc2_writel(dcfg,  hsotg->regs + DCFG);
+       dwc2_writel(hsotg, dcfg,  DCFG);
 
        /* Clear any pending OTG interrupts */
-       dwc2_writel(0xffffffff, hsotg->regs + GOTGINT);
+       dwc2_writel(hsotg, 0xffffffff, GOTGINT);
 
        /* Clear any pending interrupts */
-       dwc2_writel(0xffffffff, hsotg->regs + GINTSTS);
+       dwc2_writel(hsotg, 0xffffffff, GINTSTS);
        intmsk = GINTSTS_ERLYSUSP | GINTSTS_SESSREQINT |
                GINTSTS_GOUTNAKEFF | GINTSTS_GINNAKEFF |
                GINTSTS_USBRST | GINTSTS_RESETDET |
@@ -3277,22 +3266,22 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
        if (!hsotg->params.external_id_pin_ctl)
                intmsk |= GINTSTS_CONIDSTSCHNG;
 
-       dwc2_writel(intmsk, hsotg->regs + GINTMSK);
+       dwc2_writel(hsotg, intmsk, GINTMSK);
 
        if (using_dma(hsotg)) {
-               dwc2_writel(GAHBCFG_GLBL_INTR_EN | GAHBCFG_DMA_EN |
+               dwc2_writel(hsotg, GAHBCFG_GLBL_INTR_EN | GAHBCFG_DMA_EN |
                            hsotg->params.ahbcfg,
-                           hsotg->regs + GAHBCFG);
+                           GAHBCFG);
 
                /* Set DDMA mode support in the core if needed */
                if (using_desc_dma(hsotg))
-                       dwc2_set_bit(hsotg->regs + DCFG, DCFG_DESCDMA_EN);
+                       dwc2_set_bit(hsotg, DCFG, DCFG_DESCDMA_EN);
 
        } else {
-               dwc2_writel(((hsotg->dedicated_fifos) ?
+               dwc2_writel(hsotg, ((hsotg->dedicated_fifos) ?
                                                (GAHBCFG_NP_TXF_EMP_LVL |
                                                 GAHBCFG_P_TXF_EMP_LVL) : 0) |
-                           GAHBCFG_GLBL_INTR_EN, hsotg->regs + GAHBCFG);
+                           GAHBCFG_GLBL_INTR_EN, GAHBCFG);
        }
 
        /*
@@ -3301,33 +3290,33 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
         * interrupts.
         */
 
-       dwc2_writel(((hsotg->dedicated_fifos && !using_dma(hsotg)) ?
+       dwc2_writel(hsotg, ((hsotg->dedicated_fifos && !using_dma(hsotg)) ?
                DIEPMSK_TXFIFOEMPTY | DIEPMSK_INTKNTXFEMPMSK : 0) |
                DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK |
                DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK,
-               hsotg->regs + DIEPMSK);
+               DIEPMSK);
 
        /*
         * don't need XferCompl, we get that from RXFIFO in slave mode. In
         * DMA mode we may need this and StsPhseRcvd.
         */
-       dwc2_writel((using_dma(hsotg) ? (DIEPMSK_XFERCOMPLMSK |
+       dwc2_writel(hsotg, (using_dma(hsotg) ? (DIEPMSK_XFERCOMPLMSK |
                DOEPMSK_STSPHSERCVDMSK) : 0) |
                DOEPMSK_EPDISBLDMSK | DOEPMSK_AHBERRMSK |
                DOEPMSK_SETUPMSK,
-               hsotg->regs + DOEPMSK);
+               DOEPMSK);
 
        /* Enable BNA interrupt for DDMA */
        if (using_desc_dma(hsotg)) {
-               dwc2_set_bit(hsotg->regs + DOEPMSK, DOEPMSK_BNAMSK);
-               dwc2_set_bit(hsotg->regs + DIEPMSK, DIEPMSK_BNAININTRMSK);
+               dwc2_set_bit(hsotg, DOEPMSK, DOEPMSK_BNAMSK);
+               dwc2_set_bit(hsotg, DIEPMSK, DIEPMSK_BNAININTRMSK);
        }
 
-       dwc2_writel(0, hsotg->regs + DAINTMSK);
+       dwc2_writel(hsotg, 0, DAINTMSK);
 
        dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
-               dwc2_readl(hsotg->regs + DIEPCTL0),
-               dwc2_readl(hsotg->regs + DOEPCTL0));
+               dwc2_readl(hsotg, DIEPCTL0),
+               dwc2_readl(hsotg, DOEPCTL0));
 
        /* enable in and out endpoint interrupts */
        dwc2_hsotg_en_gsint(hsotg, GINTSTS_OEPINT | GINTSTS_IEPINT);
@@ -3345,12 +3334,12 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
        dwc2_hsotg_ctrl_epint(hsotg, 0, 1, 1);
 
        if (!is_usb_reset) {
-               dwc2_set_bit(hsotg->regs + DCTL, DCTL_PWRONPRGDONE);
+               dwc2_set_bit(hsotg, DCTL, DCTL_PWRONPRGDONE);
                udelay(10);  /* see openiboot */
-               dwc2_clear_bit(hsotg->regs + DCTL, DCTL_PWRONPRGDONE);
+               dwc2_clear_bit(hsotg, DCTL, DCTL_PWRONPRGDONE);
        }
 
-       dev_dbg(hsotg->dev, "DCTL=0x%08x\n", dwc2_readl(hsotg->regs + DCTL));
+       dev_dbg(hsotg->dev, "DCTL=0x%08x\n", dwc2_readl(hsotg, DCTL));
 
        /*
         * DxEPCTL_USBActEp says RO in manual, but seems to be set by
@@ -3358,23 +3347,23 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
         */
 
        /* set to read 1 8byte packet */
-       dwc2_writel(DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) |
-              DXEPTSIZ_XFERSIZE(8), hsotg->regs + DOEPTSIZ0);
+       dwc2_writel(hsotg, DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) |
+              DXEPTSIZ_XFERSIZE(8), DOEPTSIZ0);
 
-       dwc2_writel(dwc2_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) |
+       dwc2_writel(hsotg, dwc2_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) |
               DXEPCTL_CNAK | DXEPCTL_EPENA |
               DXEPCTL_USBACTEP,
-              hsotg->regs + DOEPCTL0);
+              DOEPCTL0);
 
        /* enable, but don't activate EP0in */
-       dwc2_writel(dwc2_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) |
-              DXEPCTL_USBACTEP, hsotg->regs + DIEPCTL0);
+       dwc2_writel(hsotg, dwc2_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) |
+              DXEPCTL_USBACTEP, DIEPCTL0);
 
        /* clear global NAKs */
        val = DCTL_CGOUTNAK | DCTL_CGNPINNAK;
        if (!is_usb_reset)
                val |= DCTL_SFTDISCON;
-       dwc2_set_bit(hsotg->regs + DCTL, val);
+       dwc2_set_bit(hsotg, DCTL, val);
 
        /* configure the core to support LPM */
        dwc2_gadget_init_lpm(hsotg);
@@ -3387,20 +3376,20 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
        dwc2_hsotg_enqueue_setup(hsotg);
 
        dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n",
-               dwc2_readl(hsotg->regs + DIEPCTL0),
-               dwc2_readl(hsotg->regs + DOEPCTL0));
+               dwc2_readl(hsotg, DIEPCTL0),
+               dwc2_readl(hsotg, DOEPCTL0));
 }
 
 static void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg)
 {
        /* set the soft-disconnect bit */
-       dwc2_set_bit(hsotg->regs + DCTL, DCTL_SFTDISCON);
+       dwc2_set_bit(hsotg, DCTL, DCTL_SFTDISCON);
 }
 
 void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg)
 {
        /* remove the soft-disconnect and let's go */
-       dwc2_clear_bit(hsotg->regs + DCTL, DCTL_SFTDISCON);
+       dwc2_clear_bit(hsotg, DCTL, DCTL_SFTDISCON);
 }
 
 /**
@@ -3425,7 +3414,7 @@ static void dwc2_gadget_handle_incomplete_isoc_in(struct dwc2_hsotg *hsotg)
 
        dev_dbg(hsotg->dev, "Incomplete isoc in interrupt received:\n");
 
-       daintmsk = dwc2_readl(hsotg->regs + DAINTMSK);
+       daintmsk = dwc2_readl(hsotg, DAINTMSK);
 
        for (idx = 1; idx < hsotg->num_of_eps; idx++) {
                hs_ep = hsotg->eps_in[idx];
@@ -3433,17 +3422,17 @@ static void dwc2_gadget_handle_incomplete_isoc_in(struct dwc2_hsotg *hsotg)
                if ((BIT(idx) & ~daintmsk) || !hs_ep->isochronous)
                        continue;
 
-               epctrl = dwc2_readl(hsotg->regs + DIEPCTL(idx));
+               epctrl = dwc2_readl(hsotg, DIEPCTL(idx));
                if ((epctrl & DXEPCTL_EPENA) &&
                    dwc2_gadget_target_frame_elapsed(hs_ep)) {
                        epctrl |= DXEPCTL_SNAK;
                        epctrl |= DXEPCTL_EPDIS;
-                       dwc2_writel(epctrl, hsotg->regs + DIEPCTL(idx));
+                       dwc2_writel(hsotg, epctrl, DIEPCTL(idx));
                }
        }
 
        /* Clear interrupt */
-       dwc2_writel(GINTSTS_INCOMPL_SOIN, hsotg->regs + GINTSTS);
+       dwc2_writel(hsotg, GINTSTS_INCOMPL_SOIN, GINTSTS);
 }
 
 /**
@@ -3470,7 +3459,7 @@ static void dwc2_gadget_handle_incomplete_isoc_out(struct dwc2_hsotg *hsotg)
 
        dev_dbg(hsotg->dev, "%s: GINTSTS_INCOMPL_SOOUT\n", __func__);
 
-       daintmsk = dwc2_readl(hsotg->regs + DAINTMSK);
+       daintmsk = dwc2_readl(hsotg, DAINTMSK);
        daintmsk >>= DAINT_OUTEP_SHIFT;
 
        for (idx = 1; idx < hsotg->num_of_eps; idx++) {
@@ -3479,24 +3468,24 @@ static void dwc2_gadget_handle_incomplete_isoc_out(struct dwc2_hsotg *hsotg)
                if ((BIT(idx) & ~daintmsk) || !hs_ep->isochronous)
                        continue;
 
-               epctrl = dwc2_readl(hsotg->regs + DOEPCTL(idx));
+               epctrl = dwc2_readl(hsotg, DOEPCTL(idx));
                if ((epctrl & DXEPCTL_EPENA) &&
                    dwc2_gadget_target_frame_elapsed(hs_ep)) {
                        /* Unmask GOUTNAKEFF interrupt */
-                       gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
+                       gintmsk = dwc2_readl(hsotg, GINTMSK);
                        gintmsk |= GINTSTS_GOUTNAKEFF;
-                       dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
+                       dwc2_writel(hsotg, gintmsk, GINTMSK);
 
-                       gintsts = dwc2_readl(hsotg->regs + GINTSTS);
+                       gintsts = dwc2_readl(hsotg, GINTSTS);
                        if (!(gintsts & GINTSTS_GOUTNAKEFF)) {
-                               dwc2_set_bit(hsotg->regs + DCTL, DCTL_SGOUTNAK);
+                               dwc2_set_bit(hsotg, DCTL, DCTL_SGOUTNAK);
                                break;
                        }
                }
        }
 
        /* Clear interrupt */
-       dwc2_writel(GINTSTS_INCOMPL_SOOUT, hsotg->regs + GINTSTS);
+       dwc2_writel(hsotg, GINTSTS_INCOMPL_SOOUT, GINTSTS);
 }
 
 /**
@@ -3516,8 +3505,8 @@ static irqreturn_t dwc2_hsotg_irq(int irq, void *pw)
 
        spin_lock(&hsotg->lock);
 irq_retry:
-       gintsts = dwc2_readl(hsotg->regs + GINTSTS);
-       gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
+       gintsts = dwc2_readl(hsotg, GINTSTS);
+       gintmsk = dwc2_readl(hsotg, GINTMSK);
 
        dev_dbg(hsotg->dev, "%s: %08x %08x (%08x) retry %d\n",
                __func__, gintsts, gintsts & gintmsk, gintmsk, retry_count);
@@ -3527,7 +3516,7 @@ irq_retry:
        if (gintsts & GINTSTS_RESETDET) {
                dev_dbg(hsotg->dev, "%s: USBRstDet\n", __func__);
 
-               dwc2_writel(GINTSTS_RESETDET, hsotg->regs + GINTSTS);
+               dwc2_writel(hsotg, GINTSTS_RESETDET, GINTSTS);
 
                /* This event must be used only if controller is suspended */
                if (hsotg->lx_state == DWC2_L2) {
@@ -3537,34 +3526,34 @@ irq_retry:
        }
 
        if (gintsts & (GINTSTS_USBRST | GINTSTS_RESETDET)) {
-               u32 usb_status = dwc2_readl(hsotg->regs + GOTGCTL);
+               u32 usb_status = dwc2_readl(hsotg, GOTGCTL);
                u32 connected = hsotg->connected;
 
                dev_dbg(hsotg->dev, "%s: USBRst\n", __func__);
                dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n",
-                       dwc2_readl(hsotg->regs + GNPTXSTS));
+                       dwc2_readl(hsotg, GNPTXSTS));
 
-               dwc2_writel(GINTSTS_USBRST, hsotg->regs + GINTSTS);
+               dwc2_writel(hsotg, GINTSTS_USBRST, GINTSTS);
 
                /* Report disconnection if it is not already done. */
                dwc2_hsotg_disconnect(hsotg);
 
                /* Reset device address to zero */
-               dwc2_clear_bit(hsotg->regs + DCFG, DCFG_DEVADDR_MASK);
+               dwc2_clear_bit(hsotg, DCFG, DCFG_DEVADDR_MASK);
 
                if (usb_status & GOTGCTL_BSESVLD && connected)
                        dwc2_hsotg_core_init_disconnected(hsotg, true);
        }
 
        if (gintsts & GINTSTS_ENUMDONE) {
-               dwc2_writel(GINTSTS_ENUMDONE, hsotg->regs + GINTSTS);
+               dwc2_writel(hsotg, GINTSTS_ENUMDONE, GINTSTS);
 
                dwc2_hsotg_irq_enumdone(hsotg);
        }
 
        if (gintsts & (GINTSTS_OEPINT | GINTSTS_IEPINT)) {
-               u32 daint = dwc2_readl(hsotg->regs + DAINT);
-               u32 daintmsk = dwc2_readl(hsotg->regs + DAINTMSK);
+               u32 daint = dwc2_readl(hsotg, DAINT);
+               u32 daintmsk = dwc2_readl(hsotg, DAINTMSK);
                u32 daint_out, daint_in;
                int ep;
 
@@ -3623,7 +3612,7 @@ irq_retry:
 
        if (gintsts & GINTSTS_ERLYSUSP) {
                dev_dbg(hsotg->dev, "GINTSTS_ErlySusp\n");
-               dwc2_writel(GINTSTS_ERLYSUSP, hsotg->regs + GINTSTS);
+               dwc2_writel(hsotg, GINTSTS_ERLYSUSP, GINTSTS);
        }
 
        /*
@@ -3639,12 +3628,12 @@ irq_retry:
                u32 daintmsk;
                struct dwc2_hsotg_ep *hs_ep;
 
-               daintmsk = dwc2_readl(hsotg->regs + DAINTMSK);
+               daintmsk = dwc2_readl(hsotg, DAINTMSK);
                daintmsk >>= DAINT_OUTEP_SHIFT;
                /* Mask this interrupt */
-               gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
+               gintmsk = dwc2_readl(hsotg, GINTMSK);
                gintmsk &= ~GINTSTS_GOUTNAKEFF;
-               dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
+               dwc2_writel(hsotg, gintmsk, GINTMSK);
 
                dev_dbg(hsotg->dev, "GOUTNakEff triggered\n");
                for (idx = 1; idx < hsotg->num_of_eps; idx++) {
@@ -3653,12 +3642,12 @@ irq_retry:
                        if ((BIT(idx) & ~daintmsk) || !hs_ep->isochronous)
                                continue;
 
-                       epctrl = dwc2_readl(hsotg->regs + DOEPCTL(idx));
+                       epctrl = dwc2_readl(hsotg, DOEPCTL(idx));
 
                        if (epctrl & DXEPCTL_EPENA) {
                                epctrl |= DXEPCTL_SNAK;
                                epctrl |= DXEPCTL_EPDIS;
-                               dwc2_writel(epctrl, hsotg->regs + DOEPCTL(idx));
+                               dwc2_writel(hsotg, epctrl, DOEPCTL(idx));
                        }
                }
 
@@ -3668,7 +3657,7 @@ irq_retry:
        if (gintsts & GINTSTS_GINNAKEFF) {
                dev_info(hsotg->dev, "GINNakEff triggered\n");
 
-               dwc2_set_bit(hsotg->regs + DCTL, DCTL_CGNPINNAK);
+               dwc2_set_bit(hsotg, DCTL, DCTL_CGNPINNAK);
 
                dwc2_hsotg_dump(hsotg);
        }
@@ -3708,7 +3697,7 @@ static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg,
 
        if (hs_ep->dir_in) {
                if (hsotg->dedicated_fifos || hs_ep->periodic) {
-                       dwc2_set_bit(hsotg->regs + epctrl_reg, DXEPCTL_SNAK);
+                       dwc2_set_bit(hsotg, epctrl_reg, DXEPCTL_SNAK);
                        /* Wait for Nak effect */
                        if (dwc2_hsotg_wait_bit_set(hsotg, epint_reg,
                                                    DXEPINT_INEPNAKEFF, 100))
@@ -3716,7 +3705,7 @@ static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg,
                                         "%s: timeout DIEPINT.NAKEFF\n",
                                         __func__);
                } else {
-                       dwc2_set_bit(hsotg->regs + DCTL, DCTL_SGNPINNAK);
+                       dwc2_set_bit(hsotg, DCTL, DCTL_SGNPINNAK);
                        /* Wait for Nak effect */
                        if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS,
                                                    GINTSTS_GINNAKEFF, 100))
@@ -3725,8 +3714,8 @@ static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg,
                                         __func__);
                }
        } else {
-               if (!(dwc2_readl(hsotg->regs + GINTSTS) & GINTSTS_GOUTNAKEFF))
-                       dwc2_set_bit(hsotg->regs + DCTL, DCTL_SGOUTNAK);
+               if (!(dwc2_readl(hsotg, GINTSTS) & GINTSTS_GOUTNAKEFF))
+                       dwc2_set_bit(hsotg, DCTL, DCTL_SGOUTNAK);
 
                /* Wait for global nak to take effect */
                if (dwc2_hsotg_wait_bit_set(hsotg, GINTSTS,
@@ -3736,7 +3725,7 @@ static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg,
        }
 
        /* Disable ep */
-       dwc2_set_bit(hsotg->regs + epctrl_reg, DXEPCTL_EPDIS | DXEPCTL_SNAK);
+       dwc2_set_bit(hsotg, epctrl_reg, DXEPCTL_EPDIS | DXEPCTL_SNAK);
 
        /* Wait for ep to be disabled */
        if (dwc2_hsotg_wait_bit_set(hsotg, epint_reg, DXEPINT_EPDISBLD, 100))
@@ -3744,7 +3733,7 @@ static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg,
                         "%s: timeout DOEPCTL.EPDisable\n", __func__);
 
        /* Clear EPDISBLD interrupt */
-       dwc2_set_bit(hsotg->regs + epint_reg, DXEPINT_EPDISBLD);
+       dwc2_set_bit(hsotg, epint_reg, DXEPINT_EPDISBLD);
 
        if (hs_ep->dir_in) {
                unsigned short fifo_index;
@@ -3759,11 +3748,11 @@ static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg,
 
                /* Clear Global In NP NAK in Shared FIFO for non periodic ep */
                if (!hsotg->dedicated_fifos && !hs_ep->periodic)
-                       dwc2_set_bit(hsotg->regs + DCTL, DCTL_CGNPINNAK);
+                       dwc2_set_bit(hsotg, DCTL, DCTL_CGNPINNAK);
 
        } else {
                /* Remove global NAKs */
-               dwc2_set_bit(hsotg->regs + DCTL, DCTL_CGOUTNAK);
+               dwc2_set_bit(hsotg, DCTL, DCTL_CGOUTNAK);
        }
 }
 
@@ -3831,7 +3820,7 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
        /* note, we handle this here instead of dwc2_hsotg_set_ep_maxpacket */
 
        epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index);
-       epctrl = dwc2_readl(hsotg->regs + epctrl_reg);
+       epctrl = dwc2_readl(hsotg, epctrl_reg);
 
        dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x from 0x%08x\n",
                __func__, epctrl, epctrl_reg);
@@ -3879,13 +3868,13 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
                hs_ep->compl_desc = 0;
                if (dir_in) {
                        hs_ep->periodic = 1;
-                       mask = dwc2_readl(hsotg->regs + DIEPMSK);
+                       mask = dwc2_readl(hsotg, DIEPMSK);
                        mask |= DIEPMSK_NAKMSK;
-                       dwc2_writel(mask, hsotg->regs + DIEPMSK);
+                       dwc2_writel(hsotg, mask, DIEPMSK);
                } else {
-                       mask = dwc2_readl(hsotg->regs + DOEPMSK);
+                       mask = dwc2_readl(hsotg, DOEPMSK);
                        mask |= DOEPMSK_OUTTKNEPDISMSK;
-                       dwc2_writel(mask, hsotg->regs + DOEPMSK);
+                       dwc2_writel(hsotg, mask, DOEPMSK);
                }
                break;
 
@@ -3920,7 +3909,7 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
                for (i = 1; i < hsotg->num_of_eps; ++i) {
                        if (hsotg->fifo_map & (1 << i))
                                continue;
-                       val = dwc2_readl(hsotg->regs + DPTXFSIZN(i));
+                       val = dwc2_readl(hsotg, DPTXFSIZN(i));
                        val = (val >> FIFOSIZE_DEPTH_SHIFT) * 4;
                        if (val < size)
                                continue;
@@ -3958,7 +3947,7 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
                 * to 4.00a (including both). Also for FS_IOT_1.00a
                 * and HS_IOT_1.00a.
                 */
-               u32 gsnpsid = dwc2_readl(hsotg->regs + GSNPSID);
+               u32 gsnpsid = dwc2_readl(hsotg, GSNPSID);
 
                if ((gsnpsid >= DWC2_CORE_REV_2_72a &&
                     gsnpsid <= DWC2_CORE_REV_4_00a) ||
@@ -3970,9 +3959,9 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
        dev_dbg(hsotg->dev, "%s: write DxEPCTL=0x%08x\n",
                __func__, epctrl);
 
-       dwc2_writel(epctrl, hsotg->regs + epctrl_reg);
+       dwc2_writel(hsotg, epctrl, epctrl_reg);
        dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x\n",
-               __func__, dwc2_readl(hsotg->regs + epctrl_reg));
+               __func__, dwc2_readl(hsotg, epctrl_reg));
 
        /* enable the endpoint interrupt */
        dwc2_hsotg_ctrl_epint(hsotg, index, dir_in, 1);
@@ -4021,7 +4010,7 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep)
 
        spin_lock_irqsave(&hsotg->lock, flags);
 
-       ctrl = dwc2_readl(hsotg->regs + epctrl_reg);
+       ctrl = dwc2_readl(hsotg, epctrl_reg);
 
        if (ctrl & DXEPCTL_EPENA)
                dwc2_hsotg_ep_stop_xfr(hsotg, hs_ep);
@@ -4031,7 +4020,7 @@ static int dwc2_hsotg_ep_disable(struct usb_ep *ep)
        ctrl |= DXEPCTL_SNAK;
 
        dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl);
-       dwc2_writel(ctrl, hsotg->regs + epctrl_reg);
+       dwc2_writel(hsotg, ctrl, epctrl_reg);
 
        /* disable endpoint interrupts */
        dwc2_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 0);
@@ -4138,7 +4127,7 @@ static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now)
 
        if (hs_ep->dir_in) {
                epreg = DIEPCTL(index);
-               epctl = dwc2_readl(hs->regs + epreg);
+               epctl = dwc2_readl(hs, epreg);
 
                if (value) {
                        epctl |= DXEPCTL_STALL | DXEPCTL_SNAK;
@@ -4151,10 +4140,10 @@ static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now)
                            xfertype == DXEPCTL_EPTYPE_INTERRUPT)
                                epctl |= DXEPCTL_SETD0PID;
                }
-               dwc2_writel(epctl, hs->regs + epreg);
+               dwc2_writel(hs, epctl, epreg);
        } else {
                epreg = DOEPCTL(index);
-               epctl = dwc2_readl(hs->regs + epreg);
+               epctl = dwc2_readl(hs, epreg);
 
                if (value) {
                        epctl |= DXEPCTL_STALL;
@@ -4165,7 +4154,7 @@ static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now)
                            xfertype == DXEPCTL_EPTYPE_INTERRUPT)
                                epctl |= DXEPCTL_SETD0PID;
                }
-               dwc2_writel(epctl, hs->regs + epreg);
+               dwc2_writel(hs, epctl, epreg);
        }
 
        hs_ep->halted = value;
@@ -4213,29 +4202,29 @@ static void dwc2_hsotg_init(struct dwc2_hsotg *hsotg)
        u32 usbcfg;
        /* unmask subset of endpoint interrupts */
 
-       dwc2_writel(DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK |
+       dwc2_writel(hsotg, DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK |
                    DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK,
-                   hsotg->regs + DIEPMSK);
+                   DIEPMSK);
 
-       dwc2_writel(DOEPMSK_SETUPMSK | DOEPMSK_AHBERRMSK |
+       dwc2_writel(hsotg, DOEPMSK_SETUPMSK | DOEPMSK_AHBERRMSK |
                    DOEPMSK_EPDISBLDMSK | DOEPMSK_XFERCOMPLMSK,
-                   hsotg->regs + DOEPMSK);
+                   DOEPMSK);
 
-       dwc2_writel(0, hsotg->regs + DAINTMSK);
+       dwc2_writel(hsotg, 0, DAINTMSK);
 
        /* Be in disconnected state until gadget is registered */
-       dwc2_set_bit(hsotg->regs + DCTL, DCTL_SFTDISCON);
+       dwc2_set_bit(hsotg, DCTL, DCTL_SFTDISCON);
 
        /* setup fifos */
 
        dev_dbg(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n",
-               dwc2_readl(hsotg->regs + GRXFSIZ),
-               dwc2_readl(hsotg->regs + GNPTXFSIZ));
+               dwc2_readl(hsotg, GRXFSIZ),
+               dwc2_readl(hsotg, GNPTXFSIZ));
 
        dwc2_hsotg_init_fifo(hsotg);
 
        /* keep other bits untouched (so e.g. forced modes are not lost) */
-       usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
+       usbcfg = dwc2_readl(hsotg, GUSBCFG);
        usbcfg &= ~(GUSBCFG_TOUTCAL_MASK | GUSBCFG_PHYIF16 | GUSBCFG_SRPCAP |
                GUSBCFG_HNPCAP | GUSBCFG_USBTRDTIM_MASK);
 
@@ -4243,10 +4232,10 @@ static void dwc2_hsotg_init(struct dwc2_hsotg *hsotg)
        trdtim = (hsotg->phyif == GUSBCFG_PHYIF8) ? 9 : 5;
        usbcfg |= hsotg->phyif | GUSBCFG_TOUTCAL(7) |
                (trdtim << GUSBCFG_USBTRDTIM_SHIFT);
-       dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
+       dwc2_writel(hsotg, usbcfg, GUSBCFG);
 
        if (using_dma(hsotg))
-               dwc2_set_bit(hsotg->regs + GAHBCFG, GAHBCFG_DMA_EN);
+               dwc2_set_bit(hsotg, GAHBCFG, GAHBCFG_DMA_EN);
 }
 
 /**
@@ -4536,9 +4525,9 @@ static void dwc2_hsotg_initep(struct dwc2_hsotg *hsotg,
                u32 next = DXEPCTL_NEXTEP((epnum + 1) % 15);
 
                if (dir_in)
-                       dwc2_writel(next, hsotg->regs + DIEPCTL(epnum));
+                       dwc2_writel(hsotg, next, DIEPCTL(epnum));
                else
-                       dwc2_writel(next, hsotg->regs + DOEPCTL(epnum));
+                       dwc2_writel(hsotg, next, DOEPCTL(epnum));
        }
 }
 
@@ -4607,24 +4596,23 @@ static void dwc2_hsotg_dump(struct dwc2_hsotg *hsotg)
 {
 #ifdef DEBUG
        struct device *dev = hsotg->dev;
-       void __iomem *regs = hsotg->regs;
        u32 val;
        int idx;
 
        dev_info(dev, "DCFG=0x%08x, DCTL=0x%08x, DIEPMSK=%08x\n",
-                dwc2_readl(regs + DCFG), dwc2_readl(regs + DCTL),
-                dwc2_readl(regs + DIEPMSK));
+                dwc2_readl(hsotg, DCFG), dwc2_readl(hsotg, DCTL),
+                dwc2_readl(hsotg, DIEPMSK));
 
        dev_info(dev, "GAHBCFG=0x%08x, GHWCFG1=0x%08x\n",
-                dwc2_readl(regs + GAHBCFG), dwc2_readl(regs + GHWCFG1));
+                dwc2_readl(hsotg, GAHBCFG), dwc2_readl(hsotg, GHWCFG1));
 
        dev_info(dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n",
-                dwc2_readl(regs + GRXFSIZ), dwc2_readl(regs + GNPTXFSIZ));
+                dwc2_readl(hsotg, GRXFSIZ), dwc2_readl(hsotg, GNPTXFSIZ));
 
        /* show periodic fifo settings */
 
        for (idx = 1; idx < hsotg->num_of_eps; idx++) {
-               val = dwc2_readl(regs + DPTXFSIZN(idx));
+               val = dwc2_readl(hsotg, DPTXFSIZN(idx));
                dev_info(dev, "DPTx[%d] FSize=%d, StAddr=0x%08x\n", idx,
                         val >> FIFOSIZE_DEPTH_SHIFT,
                         val & FIFOSIZE_STARTADDR_MASK);
@@ -4633,20 +4621,20 @@ static void dwc2_hsotg_dump(struct dwc2_hsotg *hsotg)
        for (idx = 0; idx < hsotg->num_of_eps; idx++) {
                dev_info(dev,
                         "ep%d-in: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", idx,
-                        dwc2_readl(regs + DIEPCTL(idx)),
-                        dwc2_readl(regs + DIEPTSIZ(idx)),
-                        dwc2_readl(regs + DIEPDMA(idx)));
+                        dwc2_readl(hsotg, DIEPCTL(idx)),
+                        dwc2_readl(hsotg, DIEPTSIZ(idx)),
+                        dwc2_readl(hsotg, DIEPDMA(idx)));
 
-               val = dwc2_readl(regs + DOEPCTL(idx));
+               val = dwc2_readl(hsotg, DOEPCTL(idx));
                dev_info(dev,
                         "ep%d-out: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n",
-                        idx, dwc2_readl(regs + DOEPCTL(idx)),
-                        dwc2_readl(regs + DOEPTSIZ(idx)),
-                        dwc2_readl(regs + DOEPDMA(idx)));
+                        idx, dwc2_readl(hsotg, DOEPCTL(idx)),
+                        dwc2_readl(hsotg, DOEPTSIZ(idx)),
+                        dwc2_readl(hsotg, DOEPDMA(idx)));
        }
 
        dev_info(dev, "DVBUSDIS=0x%08x, DVBUSPULSE=%08x\n",
-                dwc2_readl(regs + DVBUSDIS), dwc2_readl(regs + DVBUSPULSE));
+                dwc2_readl(hsotg, DVBUSDIS), dwc2_readl(hsotg, DVBUSPULSE));
 #endif
 }
 
@@ -4835,15 +4823,15 @@ int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg)
        /* Backup dev regs */
        dr = &hsotg->dr_backup;
 
-       dr->dcfg = dwc2_readl(hsotg->regs + DCFG);
-       dr->dctl = dwc2_readl(hsotg->regs + DCTL);
-       dr->daintmsk = dwc2_readl(hsotg->regs + DAINTMSK);
-       dr->diepmsk = dwc2_readl(hsotg->regs + DIEPMSK);
-       dr->doepmsk = dwc2_readl(hsotg->regs + DOEPMSK);
+       dr->dcfg = dwc2_readl(hsotg, DCFG);
+       dr->dctl = dwc2_readl(hsotg, DCTL);
+       dr->daintmsk = dwc2_readl(hsotg, DAINTMSK);
+       dr->diepmsk = dwc2_readl(hsotg, DIEPMSK);
+       dr->doepmsk = dwc2_readl(hsotg, DOEPMSK);
 
        for (i = 0; i < hsotg->num_of_eps; i++) {
                /* Backup IN EPs */
-               dr->diepctl[i] = dwc2_readl(hsotg->regs + DIEPCTL(i));
+               dr->diepctl[i] = dwc2_readl(hsotg, DIEPCTL(i));
 
                /* Ensure DATA PID is correctly configured */
                if (dr->diepctl[i] & DXEPCTL_DPID)
@@ -4851,11 +4839,11 @@ int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg)
                else
                        dr->diepctl[i] |= DXEPCTL_SETD0PID;
 
-               dr->dieptsiz[i] = dwc2_readl(hsotg->regs + DIEPTSIZ(i));
-               dr->diepdma[i] = dwc2_readl(hsotg->regs + DIEPDMA(i));
+               dr->dieptsiz[i] = dwc2_readl(hsotg, DIEPTSIZ(i));
+               dr->diepdma[i] = dwc2_readl(hsotg, DIEPDMA(i));
 
                /* Backup OUT EPs */
-               dr->doepctl[i] = dwc2_readl(hsotg->regs + DOEPCTL(i));
+               dr->doepctl[i] = dwc2_readl(hsotg, DOEPCTL(i));
 
                /* Ensure DATA PID is correctly configured */
                if (dr->doepctl[i] & DXEPCTL_DPID)
@@ -4863,9 +4851,9 @@ int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg)
                else
                        dr->doepctl[i] |= DXEPCTL_SETD0PID;
 
-               dr->doeptsiz[i] = dwc2_readl(hsotg->regs + DOEPTSIZ(i));
-               dr->doepdma[i] = dwc2_readl(hsotg->regs + DOEPDMA(i));
-               dr->dtxfsiz[i] = dwc2_readl(hsotg->regs + DPTXFSIZN(i));
+               dr->doeptsiz[i] = dwc2_readl(hsotg, DOEPTSIZ(i));
+               dr->doepdma[i] = dwc2_readl(hsotg, DOEPDMA(i));
+               dr->dtxfsiz[i] = dwc2_readl(hsotg, DPTXFSIZN(i));
        }
        dr->valid = true;
        return 0;
@@ -4898,17 +4886,17 @@ int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg, int remote_wakeup)
        dr->valid = false;
 
        if (!remote_wakeup)
-               dwc2_writel(dr->dctl, hsotg->regs + DCTL);
+               dwc2_writel(hsotg, dr->dctl, DCTL);
 
-       dwc2_writel(dr->daintmsk, hsotg->regs + DAINTMSK);
-       dwc2_writel(dr->diepmsk, hsotg->regs + DIEPMSK);
-       dwc2_writel(dr->doepmsk, hsotg->regs + DOEPMSK);
+       dwc2_writel(hsotg, dr->daintmsk, DAINTMSK);
+       dwc2_writel(hsotg, dr->diepmsk, DIEPMSK);
+       dwc2_writel(hsotg, dr->doepmsk, DOEPMSK);
 
        for (i = 0; i < hsotg->num_of_eps; i++) {
                /* Restore IN EPs */
-               dwc2_writel(dr->dieptsiz[i], hsotg->regs + DIEPTSIZ(i));
-               dwc2_writel(dr->diepdma[i], hsotg->regs + DIEPDMA(i));
-               dwc2_writel(dr->doeptsiz[i], hsotg->regs + DOEPTSIZ(i));
+               dwc2_writel(hsotg, dr->dieptsiz[i], DIEPTSIZ(i));
+               dwc2_writel(hsotg, dr->diepdma[i], DIEPDMA(i));
+               dwc2_writel(hsotg, dr->doeptsiz[i], DOEPTSIZ(i));
                /** WA for enabled EPx's IN in DDMA mode. On entering to
                 * hibernation wrong value read and saved from DIEPDMAx,
                 * as result BNA interrupt asserted on hibernation exit
@@ -4917,10 +4905,10 @@ int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg, int remote_wakeup)
                if (hsotg->params.g_dma_desc &&
                    (dr->diepctl[i] & DXEPCTL_EPENA))
                        dr->diepdma[i] = hsotg->eps_in[i]->desc_list_dma;
-               dwc2_writel(dr->dtxfsiz[i], hsotg->regs + DPTXFSIZN(i));
-               dwc2_writel(dr->diepctl[i], hsotg->regs + DIEPCTL(i));
+               dwc2_writel(hsotg, dr->dtxfsiz[i], DPTXFSIZN(i));
+               dwc2_writel(hsotg, dr->diepctl[i], DIEPCTL(i));
                /* Restore OUT EPs */
-               dwc2_writel(dr->doeptsiz[i], hsotg->regs + DOEPTSIZ(i));
+               dwc2_writel(hsotg, dr->doeptsiz[i], DOEPTSIZ(i));
                /* WA for enabled EPx's OUT in DDMA mode. On entering to
                 * hibernation wrong value read and saved from DOEPDMAx,
                 * as result BNA interrupt asserted on hibernation exit
@@ -4929,8 +4917,8 @@ int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg, int remote_wakeup)
                if (hsotg->params.g_dma_desc &&
                    (dr->doepctl[i] & DXEPCTL_EPENA))
                        dr->doepdma[i] = hsotg->eps_out[i]->desc_list_dma;
-               dwc2_writel(dr->doepdma[i], hsotg->regs + DOEPDMA(i));
-               dwc2_writel(dr->doepctl[i], hsotg->regs + DOEPCTL(i));
+               dwc2_writel(hsotg, dr->doepdma[i], DOEPDMA(i));
+               dwc2_writel(hsotg, dr->doepctl[i], DOEPCTL(i));
        }
 
        return 0;
@@ -4954,9 +4942,8 @@ void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg)
        val |= hsotg->params.lpm_clock_gating ? GLPMCFG_ENBLSLPM : 0;
        val |= hsotg->params.hird_threshold << GLPMCFG_HIRD_THRES_SHIFT;
        val |= hsotg->params.besl ? GLPMCFG_ENBESL : 0;
-       dwc2_writel(val, hsotg->regs + GLPMCFG);
-       dev_dbg(hsotg->dev, "GLPMCFG=0x%08x\n", dwc2_readl(hsotg->regs
-               + GLPMCFG));
+       dwc2_writel(hsotg, val, GLPMCFG);
+       dev_dbg(hsotg->dev, "GLPMCFG=0x%08x\n", dwc2_readl(hsotg, GLPMCFG));
 }
 
 /**
@@ -4989,40 +4976,40 @@ int dwc2_gadget_enter_hibernation(struct dwc2_hsotg *hsotg)
 
        gpwrdn = GPWRDN_PWRDNRSTN;
        gpwrdn |= GPWRDN_PMUACTV;
-       dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+       dwc2_writel(hsotg, gpwrdn, GPWRDN);
        udelay(10);
 
        /* Set flag to indicate that we are in hibernation */
        hsotg->hibernated = 1;
 
        /* Enable interrupts from wake up logic */
-       gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+       gpwrdn = dwc2_readl(hsotg, GPWRDN);
        gpwrdn |= GPWRDN_PMUINTSEL;
-       dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+       dwc2_writel(hsotg, gpwrdn, GPWRDN);
        udelay(10);
 
        /* Unmask device mode interrupts in GPWRDN */
-       gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+       gpwrdn = dwc2_readl(hsotg, GPWRDN);
        gpwrdn |= GPWRDN_RST_DET_MSK;
        gpwrdn |= GPWRDN_LNSTSCHG_MSK;
        gpwrdn |= GPWRDN_STS_CHGINT_MSK;
-       dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+       dwc2_writel(hsotg, gpwrdn, GPWRDN);
        udelay(10);
 
        /* Enable Power Down Clamp */
-       gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+       gpwrdn = dwc2_readl(hsotg, GPWRDN);
        gpwrdn |= GPWRDN_PWRDNCLMP;
-       dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+       dwc2_writel(hsotg, gpwrdn, GPWRDN);
        udelay(10);
 
        /* Switch off VDD */
-       gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+       gpwrdn = dwc2_readl(hsotg, GPWRDN);
        gpwrdn |= GPWRDN_PWRDNSWTCH;
-       dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+       dwc2_writel(hsotg, gpwrdn, GPWRDN);
        udelay(10);
 
        /* Save gpwrdn register for further usage if stschng interrupt */
-       hsotg->gr_backup.gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+       hsotg->gr_backup.gpwrdn = dwc2_readl(hsotg, GPWRDN);
        dev_dbg(hsotg->dev, "Hibernation completed\n");
 
        return ret;
@@ -5064,46 +5051,46 @@ int dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg,
 
        if (!reset) {
                /* Clear all pending interupts */
-               dwc2_writel(0xffffffff, hsotg->regs + GINTSTS);
+               dwc2_writel(hsotg, 0xffffffff, GINTSTS);
        }
 
        /* De-assert Restore */
-       gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+       gpwrdn = dwc2_readl(hsotg, GPWRDN);
        gpwrdn &= ~GPWRDN_RESTORE;
-       dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+       dwc2_writel(hsotg, gpwrdn, GPWRDN);
        udelay(10);
 
        if (!rem_wakeup) {
-               pcgcctl = dwc2_readl(hsotg->regs + PCGCTL);
+               pcgcctl = dwc2_readl(hsotg, PCGCTL);
                pcgcctl &= ~PCGCTL_RSTPDWNMODULE;
-               dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
+               dwc2_writel(hsotg, pcgcctl, PCGCTL);
        }
 
        /* Restore GUSBCFG, DCFG and DCTL */
-       dwc2_writel(gr->gusbcfg, hsotg->regs + GUSBCFG);
-       dwc2_writel(dr->dcfg, hsotg->regs + DCFG);
-       dwc2_writel(dr->dctl, hsotg->regs + DCTL);
+       dwc2_writel(hsotg, gr->gusbcfg, GUSBCFG);
+       dwc2_writel(hsotg, dr->dcfg, DCFG);
+       dwc2_writel(hsotg, dr->dctl, DCTL);
 
        /* De-assert Wakeup Logic */
-       gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+       gpwrdn = dwc2_readl(hsotg, GPWRDN);
        gpwrdn &= ~GPWRDN_PMUACTV;
-       dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+       dwc2_writel(hsotg, gpwrdn, GPWRDN);
 
        if (rem_wakeup) {
                udelay(10);
                /* Start Remote Wakeup Signaling */
-               dwc2_writel(dr->dctl | DCTL_RMTWKUPSIG, hsotg->regs + DCTL);
+               dwc2_writel(hsotg, dr->dctl | DCTL_RMTWKUPSIG, DCTL);
        } else {
                udelay(50);
                /* Set Device programming done bit */
-               dctl = dwc2_readl(hsotg->regs + DCTL);
+               dctl = dwc2_readl(hsotg, DCTL);
                dctl |= DCTL_PWRONPRGDONE;
-               dwc2_writel(dctl, hsotg->regs + DCTL);
+               dwc2_writel(hsotg, dctl, DCTL);
        }
        /* Wait for interrupts which must be cleared */
        mdelay(2);
        /* Clear all pending interupts */
-       dwc2_writel(0xffffffff, hsotg->regs + GINTSTS);
+       dwc2_writel(hsotg, 0xffffffff, GINTSTS);
 
        /* Restore global registers */
        ret = dwc2_restore_global_registers(hsotg);
@@ -5123,9 +5110,9 @@ int dwc2_gadget_exit_hibernation(struct dwc2_hsotg *hsotg,
 
        if (rem_wakeup) {
                mdelay(10);
-               dctl = dwc2_readl(hsotg->regs + DCTL);
+               dctl = dwc2_readl(hsotg, DCTL);
                dctl &= ~DCTL_RMTWKUPSIG;
-               dwc2_writel(dctl, hsotg->regs + DCTL);
+               dwc2_writel(hsotg, dctl, DCTL);
        }
 
        hsotg->hibernated = 0;
index 6e2cdd7..2bd6e6b 100644 (file)
@@ -75,10 +75,10 @@ static void dwc2_enable_common_interrupts(struct dwc2_hsotg *hsotg)
        u32 intmsk;
 
        /* Clear any pending OTG Interrupts */
-       dwc2_writel(0xffffffff, hsotg->regs + GOTGINT);
+       dwc2_writel(hsotg, 0xffffffff, GOTGINT);
 
        /* Clear any pending interrupts */
-       dwc2_writel(0xffffffff, hsotg->regs + GINTSTS);
+       dwc2_writel(hsotg, 0xffffffff, GINTSTS);
 
        /* Enable the interrupts in the GINTMSK */
        intmsk = GINTSTS_MODEMIS | GINTSTS_OTGINT;
@@ -94,7 +94,7 @@ static void dwc2_enable_common_interrupts(struct dwc2_hsotg *hsotg)
        if (dwc2_is_device_mode(hsotg) && hsotg->params.lpm)
                intmsk |= GINTSTS_LPMTRANRCVD;
 
-       dwc2_writel(intmsk, hsotg->regs + GINTMSK);
+       dwc2_writel(hsotg, intmsk, GINTMSK);
 }
 
 /*
@@ -117,10 +117,10 @@ static void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg)
        }
 
        dev_dbg(hsotg->dev, "Initializing HCFG.FSLSPClkSel to %08x\n", val);
-       hcfg = dwc2_readl(hsotg->regs + HCFG);
+       hcfg = dwc2_readl(hsotg, HCFG);
        hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
        hcfg |= val << HCFG_FSLSPCLKSEL_SHIFT;
-       dwc2_writel(hcfg, hsotg->regs + HCFG);
+       dwc2_writel(hsotg, hcfg, HCFG);
 }
 
 static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
@@ -135,10 +135,10 @@ static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
        if (select_phy) {
                dev_dbg(hsotg->dev, "FS PHY selected\n");
 
-               usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
+               usbcfg = dwc2_readl(hsotg, GUSBCFG);
                if (!(usbcfg & GUSBCFG_PHYSEL)) {
                        usbcfg |= GUSBCFG_PHYSEL;
-                       dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
+                       dwc2_writel(hsotg, usbcfg, GUSBCFG);
 
                        /* Reset after a PHY select */
                        retval = dwc2_core_reset(hsotg, false);
@@ -151,7 +151,7 @@ static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
                }
 
                if (hsotg->params.activate_stm_fs_transceiver) {
-                       ggpio = dwc2_readl(hsotg->regs + GGPIO);
+                       ggpio = dwc2_readl(hsotg, GGPIO);
                        if (!(ggpio & GGPIO_STM32_OTG_GCCFG_PWRDWN)) {
                                dev_dbg(hsotg->dev, "Activating transceiver\n");
                                /*
@@ -159,7 +159,7 @@ static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
                                 * core configuration register.
                                 */
                                ggpio |= GGPIO_STM32_OTG_GCCFG_PWRDWN;
-                               dwc2_writel(ggpio, hsotg->regs + GGPIO);
+                               dwc2_writel(hsotg, ggpio, GGPIO);
                        }
                }
        }
@@ -176,18 +176,18 @@ static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
                dev_dbg(hsotg->dev, "FS PHY enabling I2C\n");
 
                /* Program GUSBCFG.OtgUtmiFsSel to I2C */
-               usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
+               usbcfg = dwc2_readl(hsotg, GUSBCFG);
                usbcfg |= GUSBCFG_OTG_UTMI_FS_SEL;
-               dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
+               dwc2_writel(hsotg, usbcfg, GUSBCFG);
 
                /* Program GI2CCTL.I2CEn */
-               i2cctl = dwc2_readl(hsotg->regs + GI2CCTL);
+               i2cctl = dwc2_readl(hsotg, GI2CCTL);
                i2cctl &= ~GI2CCTL_I2CDEVADDR_MASK;
                i2cctl |= 1 << GI2CCTL_I2CDEVADDR_SHIFT;
                i2cctl &= ~GI2CCTL_I2CEN;
-               dwc2_writel(i2cctl, hsotg->regs + GI2CCTL);
+               dwc2_writel(hsotg, i2cctl, GI2CCTL);
                i2cctl |= GI2CCTL_I2CEN;
-               dwc2_writel(i2cctl, hsotg->regs + GI2CCTL);
+               dwc2_writel(hsotg, i2cctl, GI2CCTL);
        }
 
        return retval;
@@ -201,7 +201,7 @@ static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
        if (!select_phy)
                return 0;
 
-       usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
+       usbcfg = dwc2_readl(hsotg, GUSBCFG);
        usbcfg_old = usbcfg;
 
        /*
@@ -236,7 +236,7 @@ static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
        }
 
        if (usbcfg != usbcfg_old) {
-               dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
+               dwc2_writel(hsotg, usbcfg, GUSBCFG);
 
                /* Reset after setting the PHY parameters */
                retval = dwc2_core_reset(hsotg, false);
@@ -273,15 +273,15 @@ static int dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
            hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED &&
            hsotg->params.ulpi_fs_ls) {
                dev_dbg(hsotg->dev, "Setting ULPI FSLS\n");
-               usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
+               usbcfg = dwc2_readl(hsotg, GUSBCFG);
                usbcfg |= GUSBCFG_ULPI_FS_LS;
                usbcfg |= GUSBCFG_ULPI_CLK_SUSP_M;
-               dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
+               dwc2_writel(hsotg, usbcfg, GUSBCFG);
        } else {
-               usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
+               usbcfg = dwc2_readl(hsotg, GUSBCFG);
                usbcfg &= ~GUSBCFG_ULPI_FS_LS;
                usbcfg &= ~GUSBCFG_ULPI_CLK_SUSP_M;
-               dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
+               dwc2_writel(hsotg, usbcfg, GUSBCFG);
        }
 
        return retval;
@@ -289,7 +289,7 @@ static int dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
 
 static int dwc2_gahbcfg_init(struct dwc2_hsotg *hsotg)
 {
-       u32 ahbcfg = dwc2_readl(hsotg->regs + GAHBCFG);
+       u32 ahbcfg = dwc2_readl(hsotg, GAHBCFG);
 
        switch (hsotg->hw_params.arch) {
        case GHWCFG2_EXT_DMA_ARCH:
@@ -316,7 +316,7 @@ static int dwc2_gahbcfg_init(struct dwc2_hsotg *hsotg)
        else
                hsotg->params.dma_desc_enable = false;
 
-       dwc2_writel(ahbcfg, hsotg->regs + GAHBCFG);
+       dwc2_writel(hsotg, ahbcfg, GAHBCFG);
 
        return 0;
 }
@@ -325,7 +325,7 @@ static void dwc2_gusbcfg_init(struct dwc2_hsotg *hsotg)
 {
        u32 usbcfg;
 
-       usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
+       usbcfg = dwc2_readl(hsotg, GUSBCFG);
        usbcfg &= ~(GUSBCFG_HNPCAP | GUSBCFG_SRPCAP);
 
        switch (hsotg->hw_params.op_mode) {
@@ -353,7 +353,7 @@ static void dwc2_gusbcfg_init(struct dwc2_hsotg *hsotg)
                break;
        }
 
-       dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
+       dwc2_writel(hsotg, usbcfg, GUSBCFG);
 }
 
 static int dwc2_vbus_supply_init(struct dwc2_hsotg *hsotg)
@@ -390,16 +390,16 @@ static void dwc2_enable_host_interrupts(struct dwc2_hsotg *hsotg)
        dev_dbg(hsotg->dev, "%s()\n", __func__);
 
        /* Disable all interrupts */
-       dwc2_writel(0, hsotg->regs + GINTMSK);
-       dwc2_writel(0, hsotg->regs + HAINTMSK);
+       dwc2_writel(hsotg, 0, GINTMSK);
+       dwc2_writel(hsotg, 0, HAINTMSK);
 
        /* Enable the common interrupts */
        dwc2_enable_common_interrupts(hsotg);
 
        /* Enable host mode interrupts without disturbing common interrupts */
-       intmsk = dwc2_readl(hsotg->regs + GINTMSK);
+       intmsk = dwc2_readl(hsotg, GINTMSK);
        intmsk |= GINTSTS_DISCONNINT | GINTSTS_PRTINT | GINTSTS_HCHINT;
-       dwc2_writel(intmsk, hsotg->regs + GINTMSK);
+       dwc2_writel(hsotg, intmsk, GINTMSK);
 }
 
 /**
@@ -409,12 +409,12 @@ static void dwc2_enable_host_interrupts(struct dwc2_hsotg *hsotg)
  */
 static void dwc2_disable_host_interrupts(struct dwc2_hsotg *hsotg)
 {
-       u32 intmsk = dwc2_readl(hsotg->regs + GINTMSK);
+       u32 intmsk = dwc2_readl(hsotg, GINTMSK);
 
        /* Disable host mode interrupts without disturbing common interrupts */
        intmsk &= ~(GINTSTS_SOF | GINTSTS_PRTINT | GINTSTS_HCHINT |
                    GINTSTS_PTXFEMP | GINTSTS_NPTXFEMP | GINTSTS_DISCONNINT);
-       dwc2_writel(intmsk, hsotg->regs + GINTMSK);
+       dwc2_writel(hsotg, intmsk, GINTMSK);
 }
 
 /*
@@ -494,37 +494,37 @@ static void dwc2_config_fifos(struct dwc2_hsotg *hsotg)
        dwc2_calculate_dynamic_fifo(hsotg);
 
        /* Rx FIFO */
-       grxfsiz = dwc2_readl(hsotg->regs + GRXFSIZ);
+       grxfsiz = dwc2_readl(hsotg, GRXFSIZ);
        dev_dbg(hsotg->dev, "initial grxfsiz=%08x\n", grxfsiz);
        grxfsiz &= ~GRXFSIZ_DEPTH_MASK;
        grxfsiz |= params->host_rx_fifo_size <<
                   GRXFSIZ_DEPTH_SHIFT & GRXFSIZ_DEPTH_MASK;
-       dwc2_writel(grxfsiz, hsotg->regs + GRXFSIZ);
+       dwc2_writel(hsotg, grxfsiz, GRXFSIZ);
        dev_dbg(hsotg->dev, "new grxfsiz=%08x\n",
-               dwc2_readl(hsotg->regs + GRXFSIZ));
+               dwc2_readl(hsotg, GRXFSIZ));
 
        /* Non-periodic Tx FIFO */
        dev_dbg(hsotg->dev, "initial gnptxfsiz=%08x\n",
-               dwc2_readl(hsotg->regs + GNPTXFSIZ));
+               dwc2_readl(hsotg, GNPTXFSIZ));
        nptxfsiz = params->host_nperio_tx_fifo_size <<
                   FIFOSIZE_DEPTH_SHIFT & FIFOSIZE_DEPTH_MASK;
        nptxfsiz |= params->host_rx_fifo_size <<
                    FIFOSIZE_STARTADDR_SHIFT & FIFOSIZE_STARTADDR_MASK;
-       dwc2_writel(nptxfsiz, hsotg->regs + GNPTXFSIZ);
+       dwc2_writel(hsotg, nptxfsiz, GNPTXFSIZ);
        dev_dbg(hsotg->dev, "new gnptxfsiz=%08x\n",
-               dwc2_readl(hsotg->regs + GNPTXFSIZ));
+               dwc2_readl(hsotg, GNPTXFSIZ));
 
        /* Periodic Tx FIFO */
        dev_dbg(hsotg->dev, "initial hptxfsiz=%08x\n",
-               dwc2_readl(hsotg->regs + HPTXFSIZ));
+               dwc2_readl(hsotg, HPTXFSIZ));
        hptxfsiz = params->host_perio_tx_fifo_size <<
                   FIFOSIZE_DEPTH_SHIFT & FIFOSIZE_DEPTH_MASK;
        hptxfsiz |= (params->host_rx_fifo_size +
                     params->host_nperio_tx_fifo_size) <<
                    FIFOSIZE_STARTADDR_SHIFT & FIFOSIZE_STARTADDR_MASK;
-       dwc2_writel(hptxfsiz, hsotg->regs + HPTXFSIZ);
+       dwc2_writel(hsotg, hptxfsiz, HPTXFSIZ);
        dev_dbg(hsotg->dev, "new hptxfsiz=%08x\n",
-               dwc2_readl(hsotg->regs + HPTXFSIZ));
+               dwc2_readl(hsotg, HPTXFSIZ));
 
        if (hsotg->params.en_multiple_tx_fifo &&
            hsotg->hw_params.snpsid >= DWC2_CORE_REV_2_91a) {
@@ -533,14 +533,14 @@ static void dwc2_config_fifos(struct dwc2_hsotg *hsotg)
                 * Global DFIFOCFG calculation for Host mode -
                 * include RxFIFO, NPTXFIFO and HPTXFIFO
                 */
-               dfifocfg = dwc2_readl(hsotg->regs + GDFIFOCFG);
+               dfifocfg = dwc2_readl(hsotg, GDFIFOCFG);
                dfifocfg &= ~GDFIFOCFG_EPINFOBASE_MASK;
                dfifocfg |= (params->host_rx_fifo_size +
                             params->host_nperio_tx_fifo_size +
                             params->host_perio_tx_fifo_size) <<
                            GDFIFOCFG_EPINFOBASE_SHIFT &
                            GDFIFOCFG_EPINFOBASE_MASK;
-               dwc2_writel(dfifocfg, hsotg->regs + GDFIFOCFG);
+               dwc2_writel(hsotg, dfifocfg, GDFIFOCFG);
        }
 }
 
@@ -560,8 +560,8 @@ u32 dwc2_calc_frame_interval(struct dwc2_hsotg *hsotg)
        u32 hprt0;
        int clock = 60; /* default value */
 
-       usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
-       hprt0 = dwc2_readl(hsotg->regs + HPRT0);
+       usbcfg = dwc2_readl(hsotg, GUSBCFG);
+       hprt0 = dwc2_readl(hsotg, HPRT0);
 
        if (!(usbcfg & GUSBCFG_PHYSEL) && (usbcfg & GUSBCFG_ULPI_UTMI_SEL) &&
            !(usbcfg & GUSBCFG_PHYIF16))
@@ -603,7 +603,6 @@ u32 dwc2_calc_frame_interval(struct dwc2_hsotg *hsotg)
  */
 void dwc2_read_packet(struct dwc2_hsotg *hsotg, u8 *dest, u16 bytes)
 {
-       u32 __iomem *fifo = hsotg->regs + HCFIFO(0);
        u32 *data_buf = (u32 *)dest;
        int word_count = (bytes + 3) / 4;
        int i;
@@ -617,7 +616,7 @@ void dwc2_read_packet(struct dwc2_hsotg *hsotg, u8 *dest, u16 bytes)
        dev_vdbg(hsotg->dev, "%s(%p,%p,%d)\n", __func__, hsotg, dest, bytes);
 
        for (i = 0; i < word_count; i++, data_buf++)
-               *data_buf = dwc2_readl(fifo);
+               *data_buf = dwc2_readl(hsotg, HCFIFO(0));
 }
 
 /**
@@ -646,10 +645,10 @@ static void dwc2_dump_channel_info(struct dwc2_hsotg *hsotg,
        if (!chan)
                return;
 
-       hcchar = dwc2_readl(hsotg->regs + HCCHAR(chan->hc_num));
-       hcsplt = dwc2_readl(hsotg->regs + HCSPLT(chan->hc_num));
-       hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chan->hc_num));
-       hc_dma = dwc2_readl(hsotg->regs + HCDMA(chan->hc_num));
+       hcchar = dwc2_readl(hsotg, HCCHAR(chan->hc_num));
+       hcsplt = dwc2_readl(hsotg, HCSPLT(chan->hc_num));
+       hctsiz = dwc2_readl(hsotg, HCTSIZ(chan->hc_num));
+       hc_dma = dwc2_readl(hsotg, HCDMA(chan->hc_num));
 
        dev_dbg(hsotg->dev, "  Assigned to channel %p:\n", chan);
        dev_dbg(hsotg->dev, "    hcchar 0x%08x, hcsplt 0x%08x\n",
@@ -797,7 +796,7 @@ static void dwc2_hc_enable_slave_ints(struct dwc2_hsotg *hsotg,
                break;
        }
 
-       dwc2_writel(hcintmsk, hsotg->regs + HCINTMSK(chan->hc_num));
+       dwc2_writel(hsotg, hcintmsk, HCINTMSK(chan->hc_num));
        if (dbg_hc(chan))
                dev_vdbg(hsotg->dev, "set HCINTMSK to %08x\n", hcintmsk);
 }
@@ -834,7 +833,7 @@ static void dwc2_hc_enable_dma_ints(struct dwc2_hsotg *hsotg,
                }
        }
 
-       dwc2_writel(hcintmsk, hsotg->regs + HCINTMSK(chan->hc_num));
+       dwc2_writel(hsotg, hcintmsk, HCINTMSK(chan->hc_num));
        if (dbg_hc(chan))
                dev_vdbg(hsotg->dev, "set HCINTMSK to %08x\n", hcintmsk);
 }
@@ -855,16 +854,16 @@ static void dwc2_hc_enable_ints(struct dwc2_hsotg *hsotg,
        }
 
        /* Enable the top level host channel interrupt */
-       intmsk = dwc2_readl(hsotg->regs + HAINTMSK);
+       intmsk = dwc2_readl(hsotg, HAINTMSK);
        intmsk |= 1 << chan->hc_num;
-       dwc2_writel(intmsk, hsotg->regs + HAINTMSK);
+       dwc2_writel(hsotg, intmsk, HAINTMSK);
        if (dbg_hc(chan))
                dev_vdbg(hsotg->dev, "set HAINTMSK to %08x\n", intmsk);
 
        /* Make sure host channel interrupts are enabled */
-       intmsk = dwc2_readl(hsotg->regs + GINTMSK);
+       intmsk = dwc2_readl(hsotg, GINTMSK);
        intmsk |= GINTSTS_HCHINT;
-       dwc2_writel(intmsk, hsotg->regs + GINTMSK);
+       dwc2_writel(hsotg, intmsk, GINTMSK);
        if (dbg_hc(chan))
                dev_vdbg(hsotg->dev, "set GINTMSK to %08x\n", intmsk);
 }
@@ -893,7 +892,7 @@ static void dwc2_hc_init(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan)
        /* Clear old interrupt conditions for this host channel */
        hcintmsk = 0xffffffff;
        hcintmsk &= ~HCINTMSK_RESERVED14_31;
-       dwc2_writel(hcintmsk, hsotg->regs + HCINT(hc_num));
+       dwc2_writel(hsotg, hcintmsk, HCINT(hc_num));
 
        /* Enable channel interrupts required for this transfer */
        dwc2_hc_enable_ints(hsotg, chan);
@@ -910,7 +909,7 @@ static void dwc2_hc_init(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan)
                hcchar |= HCCHAR_LSPDDEV;
        hcchar |= chan->ep_type << HCCHAR_EPTYPE_SHIFT & HCCHAR_EPTYPE_MASK;
        hcchar |= chan->max_packet << HCCHAR_MPS_SHIFT & HCCHAR_MPS_MASK;
-       dwc2_writel(hcchar, hsotg->regs + HCCHAR(hc_num));
+       dwc2_writel(hsotg, hcchar, HCCHAR(hc_num));
        if (dbg_hc(chan)) {
                dev_vdbg(hsotg->dev, "set HCCHAR(%d) to %08x\n",
                         hc_num, hcchar);
@@ -964,7 +963,7 @@ static void dwc2_hc_init(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan)
                }
        }
 
-       dwc2_writel(hcsplt, hsotg->regs + HCSPLT(hc_num));
+       dwc2_writel(hsotg, hcsplt, HCSPLT(hc_num));
 }
 
 /**
@@ -1034,14 +1033,14 @@ void dwc2_hc_halt(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan,
                u32 hcintmsk = HCINTMSK_CHHLTD;
 
                dev_vdbg(hsotg->dev, "dequeue/error\n");
-               dwc2_writel(hcintmsk, hsotg->regs + HCINTMSK(chan->hc_num));
+               dwc2_writel(hsotg, hcintmsk, HCINTMSK(chan->hc_num));
 
                /*
                 * Make sure no other interrupts besides halt are currently
                 * pending. Handling another interrupt could cause a crash due
                 * to the QTD and QH state.
                 */
-               dwc2_writel(~hcintmsk, hsotg->regs + HCINT(chan->hc_num));
+               dwc2_writel(hsotg, ~hcintmsk, HCINT(chan->hc_num));
 
                /*
                 * Make sure the halt status is set to URB_DEQUEUE or AHB_ERR
@@ -1050,7 +1049,7 @@ void dwc2_hc_halt(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan,
                 */
                chan->halt_status = halt_status;
 
-               hcchar = dwc2_readl(hsotg->regs + HCCHAR(chan->hc_num));
+               hcchar = dwc2_readl(hsotg, HCCHAR(chan->hc_num));
                if (!(hcchar & HCCHAR_CHENA)) {
                        /*
                         * The channel is either already halted or it hasn't
@@ -1078,7 +1077,7 @@ void dwc2_hc_halt(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan,
                return;
        }
 
-       hcchar = dwc2_readl(hsotg->regs + HCCHAR(chan->hc_num));
+       hcchar = dwc2_readl(hsotg, HCCHAR(chan->hc_num));
 
        /* No need to set the bit in DDMA for disabling the channel */
        /* TODO check it everywhere channel is disabled */
@@ -1101,7 +1100,7 @@ void dwc2_hc_halt(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan,
                if (chan->ep_type == USB_ENDPOINT_XFER_CONTROL ||
                    chan->ep_type == USB_ENDPOINT_XFER_BULK) {
                        dev_vdbg(hsotg->dev, "control/bulk\n");
-                       nptxsts = dwc2_readl(hsotg->regs + GNPTXSTS);
+                       nptxsts = dwc2_readl(hsotg, GNPTXSTS);
                        if ((nptxsts & TXSTS_QSPCAVAIL_MASK) == 0) {
                                dev_vdbg(hsotg->dev, "Disabling channel\n");
                                hcchar &= ~HCCHAR_CHENA;
@@ -1109,7 +1108,7 @@ void dwc2_hc_halt(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan,
                } else {
                        if (dbg_perio())
                                dev_vdbg(hsotg->dev, "isoc/intr\n");
-                       hptxsts = dwc2_readl(hsotg->regs + HPTXSTS);
+                       hptxsts = dwc2_readl(hsotg, HPTXSTS);
                        if ((hptxsts & TXSTS_QSPCAVAIL_MASK) == 0 ||
                            hsotg->queuing_high_bandwidth) {
                                if (dbg_perio())
@@ -1122,7 +1121,7 @@ void dwc2_hc_halt(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan,
                        dev_vdbg(hsotg->dev, "DMA enabled\n");
        }
 
-       dwc2_writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
+       dwc2_writel(hsotg, hcchar, HCCHAR(chan->hc_num));
        chan->halt_status = halt_status;
 
        if (hcchar & HCCHAR_CHENA) {
@@ -1171,10 +1170,10 @@ void dwc2_hc_cleanup(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan)
         * Clear channel interrupt enables and any unhandled channel interrupt
         * conditions
         */
-       dwc2_writel(0, hsotg->regs + HCINTMSK(chan->hc_num));
+       dwc2_writel(hsotg, 0, HCINTMSK(chan->hc_num));
        hcintmsk = 0xffffffff;
        hcintmsk &= ~HCINTMSK_RESERVED14_31;
-       dwc2_writel(hcintmsk, hsotg->regs + HCINT(chan->hc_num));
+       dwc2_writel(hsotg, hcintmsk, HCINT(chan->hc_num));
 }
 
 /**
@@ -1228,7 +1227,7 @@ static void dwc2_hc_set_even_odd_frame(struct dwc2_hsotg *hsotg,
                              !chan->do_split) ? chan->speed : USB_SPEED_HIGH;
 
                /* See how many bytes are in the periodic FIFO right now */
-               fifo_space = (dwc2_readl(hsotg->regs + HPTXSTS) &
+               fifo_space = (dwc2_readl(hsotg, HPTXSTS) &
                              TXSTS_FSPCAVAIL_MASK) >> TXSTS_FSPCAVAIL_SHIFT;
                bytes_in_fifo = sizeof(u32) *
                                (hsotg->params.host_perio_tx_fifo_size -
@@ -1348,13 +1347,13 @@ static void dwc2_hc_write_packet(struct dwc2_hsotg *hsotg,
        if (((unsigned long)data_buf & 0x3) == 0) {
                /* xfer_buf is DWORD aligned */
                for (i = 0; i < dword_count; i++, data_buf++)
-                       dwc2_writel(*data_buf, data_fifo);
+                       dwc2_writel(hsotg, *data_buf, HCFIFO(chan->hc_num));
        } else {
                /* xfer_buf is not DWORD aligned */
                for (i = 0; i < dword_count; i++, data_buf++) {
                        u32 data = data_buf[0] | data_buf[1] << 8 |
                                   data_buf[2] << 16 | data_buf[3] << 24;
-                       dwc2_writel(data, data_fifo);
+                       dwc2_writel(hsotg, data, HCFIFO(chan->hc_num));
                }
        }
 
@@ -1383,12 +1382,12 @@ static void dwc2_hc_do_ping(struct dwc2_hsotg *hsotg,
 
        hctsiz = TSIZ_DOPNG;
        hctsiz |= 1 << TSIZ_PKTCNT_SHIFT;
-       dwc2_writel(hctsiz, hsotg->regs + HCTSIZ(chan->hc_num));
+       dwc2_writel(hsotg, hctsiz, HCTSIZ(chan->hc_num));
 
-       hcchar = dwc2_readl(hsotg->regs + HCCHAR(chan->hc_num));
+       hcchar = dwc2_readl(hsotg, HCCHAR(chan->hc_num));
        hcchar |= HCCHAR_CHENA;
        hcchar &= ~HCCHAR_CHDIS;
-       dwc2_writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
+       dwc2_writel(hsotg, hcchar, HCCHAR(chan->hc_num));
 }
 
 /**
@@ -1548,7 +1547,7 @@ static void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg,
        hctsiz |= num_packets << TSIZ_PKTCNT_SHIFT & TSIZ_PKTCNT_MASK;
        hctsiz |= chan->data_pid_start << TSIZ_SC_MC_PID_SHIFT &
                  TSIZ_SC_MC_PID_MASK;
-       dwc2_writel(hctsiz, hsotg->regs + HCTSIZ(chan->hc_num));
+       dwc2_writel(hsotg, hctsiz, HCTSIZ(chan->hc_num));
        if (dbg_hc(chan)) {
                dev_vdbg(hsotg->dev, "Wrote %08x to HCTSIZ(%d)\n",
                         hctsiz, chan->hc_num);
@@ -1576,7 +1575,7 @@ static void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg,
                } else {
                        dma_addr = chan->xfer_dma;
                }
-               dwc2_writel((u32)dma_addr, hsotg->regs + HCDMA(chan->hc_num));
+               dwc2_writel(hsotg, (u32)dma_addr, HCDMA(chan->hc_num));
 
                if (dbg_hc(chan))
                        dev_vdbg(hsotg->dev, "Wrote %08lx to HCDMA(%d)\n",
@@ -1585,13 +1584,13 @@ static void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg,
 
        /* Start the split */
        if (chan->do_split) {
-               u32 hcsplt = dwc2_readl(hsotg->regs + HCSPLT(chan->hc_num));
+               u32 hcsplt = dwc2_readl(hsotg, HCSPLT(chan->hc_num));
 
                hcsplt |= HCSPLT_SPLTENA;
-               dwc2_writel(hcsplt, hsotg->regs + HCSPLT(chan->hc_num));
+               dwc2_writel(hsotg, hcsplt, HCSPLT(chan->hc_num));
        }
 
-       hcchar = dwc2_readl(hsotg->regs + HCCHAR(chan->hc_num));
+       hcchar = dwc2_readl(hsotg, HCCHAR(chan->hc_num));
        hcchar &= ~HCCHAR_MULTICNT_MASK;
        hcchar |= (ec_mc << HCCHAR_MULTICNT_SHIFT) & HCCHAR_MULTICNT_MASK;
        dwc2_hc_set_even_odd_frame(hsotg, chan, &hcchar);
@@ -1610,7 +1609,7 @@ static void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg,
                         (hcchar & HCCHAR_MULTICNT_MASK) >>
                         HCCHAR_MULTICNT_SHIFT);
 
-       dwc2_writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
+       dwc2_writel(hsotg, hcchar, HCCHAR(chan->hc_num));
        if (dbg_hc(chan))
                dev_vdbg(hsotg->dev, "Wrote %08x to HCCHAR(%d)\n", hcchar,
                         chan->hc_num);
@@ -1668,18 +1667,18 @@ void dwc2_hc_start_transfer_ddma(struct dwc2_hsotg *hsotg,
                dev_vdbg(hsotg->dev, "   NTD: %d\n", chan->ntd - 1);
        }
 
-       dwc2_writel(hctsiz, hsotg->regs + HCTSIZ(chan->hc_num));
+       dwc2_writel(hsotg, hctsiz, HCTSIZ(chan->hc_num));
 
        dma_sync_single_for_device(hsotg->dev, chan->desc_list_addr,
                                   chan->desc_list_sz, DMA_TO_DEVICE);
 
-       dwc2_writel(chan->desc_list_addr, hsotg->regs + HCDMA(chan->hc_num));
+       dwc2_writel(hsotg, chan->desc_list_addr, HCDMA(chan->hc_num));
 
        if (dbg_hc(chan))
                dev_vdbg(hsotg->dev, "Wrote %pad to HCDMA(%d)\n",
                         &chan->desc_list_addr, chan->hc_num);
 
-       hcchar = dwc2_readl(hsotg->regs + HCCHAR(chan->hc_num));
+       hcchar = dwc2_readl(hsotg, HCCHAR(chan->hc_num));
        hcchar &= ~HCCHAR_MULTICNT_MASK;
        hcchar |= chan->multi_count << HCCHAR_MULTICNT_SHIFT &
                  HCCHAR_MULTICNT_MASK;
@@ -1698,7 +1697,7 @@ void dwc2_hc_start_transfer_ddma(struct dwc2_hsotg *hsotg,
                         (hcchar & HCCHAR_MULTICNT_MASK) >>
                         HCCHAR_MULTICNT_SHIFT);
 
-       dwc2_writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
+       dwc2_writel(hsotg, hcchar, HCCHAR(chan->hc_num));
        if (dbg_hc(chan))
                dev_vdbg(hsotg->dev, "Wrote %08x to HCCHAR(%d)\n", hcchar,
                         chan->hc_num);
@@ -1755,7 +1754,7 @@ static int dwc2_hc_continue_transfer(struct dwc2_hsotg *hsotg,
                 * transfer completes, the extra requests for the channel will
                 * be flushed.
                 */
-               u32 hcchar = dwc2_readl(hsotg->regs + HCCHAR(chan->hc_num));
+               u32 hcchar = dwc2_readl(hsotg, HCCHAR(chan->hc_num));
 
                dwc2_hc_set_even_odd_frame(hsotg, chan, &hcchar);
                hcchar |= HCCHAR_CHENA;
@@ -1763,7 +1762,7 @@ static int dwc2_hc_continue_transfer(struct dwc2_hsotg *hsotg,
                if (dbg_hc(chan))
                        dev_vdbg(hsotg->dev, "   IN xfer: hcchar = 0x%08x\n",
                                 hcchar);
-               dwc2_writel(hcchar, hsotg->regs + HCCHAR(chan->hc_num));
+               dwc2_writel(hsotg, hcchar, HCCHAR(chan->hc_num));
                chan->requests++;
                return 1;
        }
@@ -1773,7 +1772,7 @@ static int dwc2_hc_continue_transfer(struct dwc2_hsotg *hsotg,
        if (chan->xfer_count < chan->xfer_len) {
                if (chan->ep_type == USB_ENDPOINT_XFER_INT ||
                    chan->ep_type == USB_ENDPOINT_XFER_ISOC) {
-                       u32 hcchar = dwc2_readl(hsotg->regs +
+                       u32 hcchar = dwc2_readl(hsotg,
                                                HCCHAR(chan->hc_num));
 
                        dwc2_hc_set_even_odd_frame(hsotg, chan,
@@ -1887,7 +1886,7 @@ void dwc2_hcd_start(struct dwc2_hsotg *hsotg)
                 */
                hprt0 = dwc2_read_hprt0(hsotg);
                hprt0 |= HPRT0_RST;
-               dwc2_writel(hprt0, hsotg->regs + HPRT0);
+               dwc2_writel(hsotg, hprt0, HPRT0);
        }
 
        queue_delayed_work(hsotg->wq_otg, &hsotg->start_work,
@@ -1908,11 +1907,11 @@ static void dwc2_hcd_cleanup_channels(struct dwc2_hsotg *hsotg)
                        channel = hsotg->hc_ptr_array[i];
                        if (!list_empty(&channel->hc_list_entry))
                                continue;
-                       hcchar = dwc2_readl(hsotg->regs + HCCHAR(i));
+                       hcchar = dwc2_readl(hsotg, HCCHAR(i));
                        if (hcchar & HCCHAR_CHENA) {
                                hcchar &= ~(HCCHAR_CHENA | HCCHAR_EPDIR);
                                hcchar |= HCCHAR_CHDIS;
-                               dwc2_writel(hcchar, hsotg->regs + HCCHAR(i));
+                               dwc2_writel(hsotg, hcchar, HCCHAR(i));
                        }
                }
        }
@@ -1921,11 +1920,11 @@ static void dwc2_hcd_cleanup_channels(struct dwc2_hsotg *hsotg)
                channel = hsotg->hc_ptr_array[i];
                if (!list_empty(&channel->hc_list_entry))
                        continue;
-               hcchar = dwc2_readl(hsotg->regs + HCCHAR(i));
+               hcchar = dwc2_readl(hsotg, HCCHAR(i));
                if (hcchar & HCCHAR_CHENA) {
                        /* Halt the channel */
                        hcchar |= HCCHAR_CHDIS;
-                       dwc2_writel(hcchar, hsotg->regs + HCCHAR(i));
+                       dwc2_writel(hsotg, hcchar, HCCHAR(i));
                }
 
                dwc2_hc_cleanup(hsotg, channel);
@@ -1985,11 +1984,11 @@ void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool force)
         * interrupt mask and status bits and disabling subsequent host
         * channel interrupts.
         */
-       intr = dwc2_readl(hsotg->regs + GINTMSK);
+       intr = dwc2_readl(hsotg, GINTMSK);
        intr &= ~(GINTSTS_NPTXFEMP | GINTSTS_PTXFEMP | GINTSTS_HCHINT);
-       dwc2_writel(intr, hsotg->regs + GINTMSK);
+       dwc2_writel(hsotg, intr, GINTMSK);
        intr = GINTSTS_NPTXFEMP | GINTSTS_PTXFEMP | GINTSTS_HCHINT;
-       dwc2_writel(intr, hsotg->regs + GINTSTS);
+       dwc2_writel(hsotg, intr, GINTSTS);
 
        /*
         * Turn off the vbus power only if the core has transitioned to device
@@ -1999,7 +1998,7 @@ void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool force)
        if (dwc2_is_device_mode(hsotg)) {
                if (hsotg->op_state != OTG_STATE_A_SUSPEND) {
                        dev_dbg(hsotg->dev, "Disconnect: PortPower off\n");
-                       dwc2_writel(0, hsotg->regs + HPRT0);
+                       dwc2_writel(hsotg, 0, HPRT0);
                }
 
                dwc2_disable_host_interrupts(hsotg);
@@ -2027,7 +2026,7 @@ void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool force)
         * and won't get any future interrupts to handle the connect.
         */
        if (!force) {
-               hprt0 = dwc2_readl(hsotg->regs + HPRT0);
+               hprt0 = dwc2_readl(hsotg, HPRT0);
                if (!(hprt0 & HPRT0_CONNDET) && (hprt0 & HPRT0_CONNSTS))
                        dwc2_hcd_connect(hsotg);
        }
@@ -2071,7 +2070,7 @@ void dwc2_hcd_stop(struct dwc2_hsotg *hsotg)
 
        /* Turn off the vbus power */
        dev_dbg(hsotg->dev, "PortPower off\n");
-       dwc2_writel(0, hsotg->regs + HPRT0);
+       dwc2_writel(hsotg, 0, HPRT0);
 }
 
 /* Caller must hold driver lock */
@@ -2095,7 +2094,7 @@ static int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg,
        if ((dev_speed == USB_SPEED_LOW) &&
            (hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED) &&
            (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI)) {
-               u32 hprt0 = dwc2_readl(hsotg->regs + HPRT0);
+               u32 hprt0 = dwc2_readl(hsotg, HPRT0);
                u32 prtspd = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
 
                if (prtspd == HPRT0_SPD_FULL_SPEED)
@@ -2114,7 +2113,7 @@ static int dwc2_hcd_urb_enqueue(struct dwc2_hsotg *hsotg,
                return retval;
        }
 
-       intr_mask = dwc2_readl(hsotg->regs + GINTMSK);
+       intr_mask = dwc2_readl(hsotg, GINTMSK);
        if (!(intr_mask & GINTSTS_SOF)) {
                enum dwc2_transaction_type tr_type;
 
@@ -2279,7 +2278,7 @@ int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup)
 
        dev_dbg(hsotg->dev, "%s(%p)\n", __func__, hsotg);
 
-       usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
+       usbcfg = dwc2_readl(hsotg, GUSBCFG);
 
        /* Set ULPI External VBUS bit if needed */
        usbcfg &= ~GUSBCFG_ULPI_EXT_VBUS_DRV;
@@ -2291,7 +2290,7 @@ int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup)
        if (hsotg->params.ts_dline)
                usbcfg |= GUSBCFG_TERMSELDLPULSE;
 
-       dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
+       dwc2_writel(hsotg, usbcfg, GUSBCFG);
 
        /*
         * Reset the Controller
@@ -2325,9 +2324,9 @@ int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup)
        dwc2_gusbcfg_init(hsotg);
 
        /* Program the GOTGCTL register */
-       otgctl = dwc2_readl(hsotg->regs + GOTGCTL);
+       otgctl = dwc2_readl(hsotg, GOTGCTL);
        otgctl &= ~GOTGCTL_OTGVER;
-       dwc2_writel(otgctl, hsotg->regs + GOTGCTL);
+       dwc2_writel(hsotg, otgctl, GOTGCTL);
 
        /* Clear the SRP success bit for FS-I2c */
        hsotg->srp_success = 0;
@@ -2374,20 +2373,20 @@ static void dwc2_core_host_init(struct dwc2_hsotg *hsotg)
         * introduced by the PHY in generating the linestate condition
         * can vary from one PHY to another.
         */
-       usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
+       usbcfg = dwc2_readl(hsotg, GUSBCFG);
        usbcfg |= GUSBCFG_TOUTCAL(7);
-       dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
+       dwc2_writel(hsotg, usbcfg, GUSBCFG);
 
        /* Restart the Phy Clock */
-       dwc2_writel(0, hsotg->regs + PCGCTL);
+       dwc2_writel(hsotg, 0, PCGCTL);
 
        /* Initialize Host Configuration Register */
        dwc2_init_fs_ls_pclk_sel(hsotg);
        if (hsotg->params.speed == DWC2_SPEED_PARAM_FULL ||
            hsotg->params.speed == DWC2_SPEED_PARAM_LOW) {
-               hcfg = dwc2_readl(hsotg->regs + HCFG);
+               hcfg = dwc2_readl(hsotg, HCFG);
                hcfg |= HCFG_FSLSSUPP;
-               dwc2_writel(hcfg, hsotg->regs + HCFG);
+               dwc2_writel(hsotg, hcfg, HCFG);
        }
 
        /*
@@ -2396,9 +2395,9 @@ static void dwc2_core_host_init(struct dwc2_hsotg *hsotg)
         * and its value must not be changed during runtime.
         */
        if (hsotg->params.reload_ctl) {
-               hfir = dwc2_readl(hsotg->regs + HFIR);
+               hfir = dwc2_readl(hsotg, HFIR);
                hfir |= HFIR_RLDCTRL;
-               dwc2_writel(hfir, hsotg->regs + HFIR);
+               dwc2_writel(hsotg, hfir, HFIR);
        }
 
        if (hsotg->params.dma_desc_enable) {
@@ -2415,9 +2414,9 @@ static void dwc2_core_host_init(struct dwc2_hsotg *hsotg)
                                "falling back to buffer DMA mode.\n");
                        hsotg->params.dma_desc_enable = false;
                } else {
-                       hcfg = dwc2_readl(hsotg->regs + HCFG);
+                       hcfg = dwc2_readl(hsotg, HCFG);
                        hcfg |= HCFG_DESCDMA;
-                       dwc2_writel(hcfg, hsotg->regs + HCFG);
+                       dwc2_writel(hsotg, hcfg, HCFG);
                }
        }
 
@@ -2426,18 +2425,18 @@ static void dwc2_core_host_init(struct dwc2_hsotg *hsotg)
 
        /* TODO - check this */
        /* Clear Host Set HNP Enable in the OTG Control Register */
-       otgctl = dwc2_readl(hsotg->regs + GOTGCTL);
+       otgctl = dwc2_readl(hsotg, GOTGCTL);
        otgctl &= ~GOTGCTL_HSTSETHNPEN;
-       dwc2_writel(otgctl, hsotg->regs + GOTGCTL);
+       dwc2_writel(hsotg, otgctl, GOTGCTL);
 
        /* Make sure the FIFOs are flushed */
        dwc2_flush_tx_fifo(hsotg, 0x10 /* all TX FIFOs */);
        dwc2_flush_rx_fifo(hsotg);
 
        /* Clear Host Set HNP Enable in the OTG Control Register */
-       otgctl = dwc2_readl(hsotg->regs + GOTGCTL);
+       otgctl = dwc2_readl(hsotg, GOTGCTL);
        otgctl &= ~GOTGCTL_HSTSETHNPEN;
-       dwc2_writel(otgctl, hsotg->regs + GOTGCTL);
+       dwc2_writel(hsotg, otgctl, GOTGCTL);
 
        if (!hsotg->params.dma_desc_enable) {
                int num_channels, i;
@@ -2446,19 +2445,19 @@ static void dwc2_core_host_init(struct dwc2_hsotg *hsotg)
                /* Flush out any leftover queued requests */
                num_channels = hsotg->params.host_channels;
                for (i = 0; i < num_channels; i++) {
-                       hcchar = dwc2_readl(hsotg->regs + HCCHAR(i));
+                       hcchar = dwc2_readl(hsotg, HCCHAR(i));
                        hcchar &= ~HCCHAR_CHENA;
                        hcchar |= HCCHAR_CHDIS;
                        hcchar &= ~HCCHAR_EPDIR;
-                       dwc2_writel(hcchar, hsotg->regs + HCCHAR(i));
+                       dwc2_writel(hsotg, hcchar, HCCHAR(i));
                }
 
                /* Halt all channels to put them into a known state */
                for (i = 0; i < num_channels; i++) {
-                       hcchar = dwc2_readl(hsotg->regs + HCCHAR(i));
+                       hcchar = dwc2_readl(hsotg, HCCHAR(i));
                        hcchar |= HCCHAR_CHENA | HCCHAR_CHDIS;
                        hcchar &= ~HCCHAR_EPDIR;
-                       dwc2_writel(hcchar, hsotg->regs + HCCHAR(i));
+                       dwc2_writel(hsotg, hcchar, HCCHAR(i));
                        dev_dbg(hsotg->dev, "%s: Halt channel %d\n",
                                __func__, i);
 
@@ -2482,7 +2481,7 @@ static void dwc2_core_host_init(struct dwc2_hsotg *hsotg)
                        !!(hprt0 & HPRT0_PWR));
                if (!(hprt0 & HPRT0_PWR)) {
                        hprt0 |= HPRT0_PWR;
-                       dwc2_writel(hprt0, hsotg->regs + HPRT0);
+                       dwc2_writel(hsotg, hprt0, HPRT0);
                }
        }
 
@@ -3084,7 +3083,7 @@ static void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg)
        if (dbg_perio())
                dev_vdbg(hsotg->dev, "Queue periodic transactions\n");
 
-       tx_status = dwc2_readl(hsotg->regs + HPTXSTS);
+       tx_status = dwc2_readl(hsotg, HPTXSTS);
        qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
                    TXSTS_QSPCAVAIL_SHIFT;
        fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
@@ -3099,7 +3098,7 @@ static void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg)
 
        qh_ptr = hsotg->periodic_sched_assigned.next;
        while (qh_ptr != &hsotg->periodic_sched_assigned) {
-               tx_status = dwc2_readl(hsotg->regs + HPTXSTS);
+               tx_status = dwc2_readl(hsotg, HPTXSTS);
                qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
                            TXSTS_QSPCAVAIL_SHIFT;
                if (qspcavail == 0) {
@@ -3169,10 +3168,10 @@ exit:
                 * level to ensure that new requests are loaded as
                 * soon as possible.)
                 */
-               gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
+               gintmsk = dwc2_readl(hsotg, GINTMSK);
                if (!(gintmsk & GINTSTS_PTXFEMP)) {
                        gintmsk |= GINTSTS_PTXFEMP;
-                       dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
+                       dwc2_writel(hsotg, gintmsk, GINTMSK);
                }
        } else {
                /*
@@ -3182,10 +3181,10 @@ exit:
                 * handlers to queue more transactions as transfer
                 * states change.
                 */
-               gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
+               gintmsk = dwc2_readl(hsotg, GINTMSK);
                if (gintmsk & GINTSTS_PTXFEMP) {
                        gintmsk &= ~GINTSTS_PTXFEMP;
-                       dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
+                       dwc2_writel(hsotg, gintmsk, GINTMSK);
                }
        }
 }
@@ -3214,7 +3213,7 @@ static void dwc2_process_non_periodic_channels(struct dwc2_hsotg *hsotg)
 
        dev_vdbg(hsotg->dev, "Queue non-periodic transactions\n");
 
-       tx_status = dwc2_readl(hsotg->regs + GNPTXSTS);
+       tx_status = dwc2_readl(hsotg, GNPTXSTS);
        qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
                    TXSTS_QSPCAVAIL_SHIFT;
        fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
@@ -3237,7 +3236,7 @@ static void dwc2_process_non_periodic_channels(struct dwc2_hsotg *hsotg)
         * available in the request queue or the Tx FIFO
         */
        do {
-               tx_status = dwc2_readl(hsotg->regs + GNPTXSTS);
+               tx_status = dwc2_readl(hsotg, GNPTXSTS);
                qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
                            TXSTS_QSPCAVAIL_SHIFT;
                if (!hsotg->params.host_dma && qspcavail == 0) {
@@ -3274,7 +3273,7 @@ next:
        } while (hsotg->non_periodic_qh_ptr != orig_qh_ptr);
 
        if (!hsotg->params.host_dma) {
-               tx_status = dwc2_readl(hsotg->regs + GNPTXSTS);
+               tx_status = dwc2_readl(hsotg, GNPTXSTS);
                qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >>
                            TXSTS_QSPCAVAIL_SHIFT;
                fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >>
@@ -3294,9 +3293,9 @@ next:
                         * level to ensure that new requests are loaded as
                         * soon as possible.)
                         */
-                       gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
+                       gintmsk = dwc2_readl(hsotg, GINTMSK);
                        gintmsk |= GINTSTS_NPTXFEMP;
-                       dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
+                       dwc2_writel(hsotg, gintmsk, GINTMSK);
                } else {
                        /*
                         * Disable the Tx FIFO empty interrupt since there are
@@ -3305,9 +3304,9 @@ next:
                         * handlers to queue more transactions as transfer
                         * states change.
                         */
-                       gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
+                       gintmsk = dwc2_readl(hsotg, GINTMSK);
                        gintmsk &= ~GINTSTS_NPTXFEMP;
-                       dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
+                       dwc2_writel(hsotg, gintmsk, GINTMSK);
                }
        }
 }
@@ -3344,10 +3343,10 @@ void dwc2_hcd_queue_transactions(struct dwc2_hsotg *hsotg,
                         * Ensure NP Tx FIFO empty interrupt is disabled when
                         * there are no non-periodic transfers to process
                         */
-                       u32 gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
+                       u32 gintmsk = dwc2_readl(hsotg, GINTMSK);
 
                        gintmsk &= ~GINTSTS_NPTXFEMP;
-                       dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
+                       dwc2_writel(hsotg, gintmsk, GINTMSK);
                }
        }
 }
@@ -3362,7 +3361,7 @@ static void dwc2_conn_id_status_change(struct work_struct *work)
 
        dev_dbg(hsotg->dev, "%s()\n", __func__);
 
-       gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
+       gotgctl = dwc2_readl(hsotg, GOTGCTL);
        dev_dbg(hsotg->dev, "gotgctl=%0x\n", gotgctl);
        dev_dbg(hsotg->dev, "gotgctl.b.conidsts=%d\n",
                !!(gotgctl & GOTGCTL_CONID_B));
@@ -3388,7 +3387,7 @@ static void dwc2_conn_id_status_change(struct work_struct *work)
                         * check it again and jump to host mode if that was
                         * the case.
                         */
-                       gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
+                       gotgctl = dwc2_readl(hsotg, GOTGCTL);
                        if (!(gotgctl & GOTGCTL_CONID_B))
                                goto host;
                        if (++count > 250)
@@ -3448,9 +3447,9 @@ static void dwc2_wakeup_detected(struct timer_list *t)
        hprt0 = dwc2_read_hprt0(hsotg);
        dev_dbg(hsotg->dev, "Resume: HPRT0=%0x\n", hprt0);
        hprt0 &= ~HPRT0_RES;
-       dwc2_writel(hprt0, hsotg->regs + HPRT0);
+       dwc2_writel(hsotg, hprt0, HPRT0);
        dev_dbg(hsotg->dev, "Clear Resume: HPRT0=%0x\n",
-               dwc2_readl(hsotg->regs + HPRT0));
+               dwc2_readl(hsotg, HPRT0));
 
        dwc2_hcd_rem_wakeup(hsotg);
        hsotg->bus_suspended = false;
@@ -3479,15 +3478,15 @@ static void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
        spin_lock_irqsave(&hsotg->lock, flags);
 
        if (windex == hsotg->otg_port && dwc2_host_is_b_hnp_enabled(hsotg)) {
-               gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
+               gotgctl = dwc2_readl(hsotg, GOTGCTL);
                gotgctl |= GOTGCTL_HSTSETHNPEN;
-               dwc2_writel(gotgctl, hsotg->regs + GOTGCTL);
+               dwc2_writel(hsotg, gotgctl, GOTGCTL);
                hsotg->op_state = OTG_STATE_A_SUSPEND;
        }
 
        hprt0 = dwc2_read_hprt0(hsotg);
        hprt0 |= HPRT0_SUSP;
-       dwc2_writel(hprt0, hsotg->regs + HPRT0);
+       dwc2_writel(hsotg, hprt0, HPRT0);
 
        hsotg->bus_suspended = true;
 
@@ -3497,17 +3496,17 @@ static void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
         */
        if (!hsotg->params.power_down) {
                /* Suspend the Phy Clock */
-               pcgctl = dwc2_readl(hsotg->regs + PCGCTL);
+               pcgctl = dwc2_readl(hsotg, PCGCTL);
                pcgctl |= PCGCTL_STOPPCLK;
-               dwc2_writel(pcgctl, hsotg->regs + PCGCTL);
+               dwc2_writel(hsotg, pcgctl, PCGCTL);
                udelay(10);
        }
 
        /* For HNP the bus must be suspended for at least 200ms */
        if (dwc2_host_is_b_hnp_enabled(hsotg)) {
-               pcgctl = dwc2_readl(hsotg->regs + PCGCTL);
+               pcgctl = dwc2_readl(hsotg, PCGCTL);
                pcgctl &= ~PCGCTL_STOPPCLK;
-               dwc2_writel(pcgctl, hsotg->regs + PCGCTL);
+               dwc2_writel(hsotg, pcgctl, PCGCTL);
 
                spin_unlock_irqrestore(&hsotg->lock, flags);
 
@@ -3531,9 +3530,9 @@ static void dwc2_port_resume(struct dwc2_hsotg *hsotg)
         * after registers restore.
         */
        if (!hsotg->params.power_down) {
-               pcgctl = dwc2_readl(hsotg->regs + PCGCTL);
+               pcgctl = dwc2_readl(hsotg, PCGCTL);
                pcgctl &= ~PCGCTL_STOPPCLK;
-               dwc2_writel(pcgctl, hsotg->regs + PCGCTL);
+               dwc2_writel(hsotg, pcgctl, PCGCTL);
                spin_unlock_irqrestore(&hsotg->lock, flags);
                msleep(20);
                spin_lock_irqsave(&hsotg->lock, flags);
@@ -3542,7 +3541,7 @@ static void dwc2_port_resume(struct dwc2_hsotg *hsotg)
        hprt0 = dwc2_read_hprt0(hsotg);
        hprt0 |= HPRT0_RES;
        hprt0 &= ~HPRT0_SUSP;
-       dwc2_writel(hprt0, hsotg->regs + HPRT0);
+       dwc2_writel(hsotg, hprt0, HPRT0);
        spin_unlock_irqrestore(&hsotg->lock, flags);
 
        msleep(USB_RESUME_TIMEOUT);
@@ -3550,7 +3549,7 @@ static void dwc2_port_resume(struct dwc2_hsotg *hsotg)
        spin_lock_irqsave(&hsotg->lock, flags);
        hprt0 = dwc2_read_hprt0(hsotg);
        hprt0 &= ~(HPRT0_RES | HPRT0_SUSP);
-       dwc2_writel(hprt0, hsotg->regs + HPRT0);
+       dwc2_writel(hsotg, hprt0, HPRT0);
        hsotg->bus_suspended = false;
        spin_unlock_irqrestore(&hsotg->lock, flags);
 }
@@ -3594,7 +3593,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
                                "ClearPortFeature USB_PORT_FEAT_ENABLE\n");
                        hprt0 = dwc2_read_hprt0(hsotg);
                        hprt0 |= HPRT0_ENA;
-                       dwc2_writel(hprt0, hsotg->regs + HPRT0);
+                       dwc2_writel(hsotg, hprt0, HPRT0);
                        break;
 
                case USB_PORT_FEAT_SUSPEND:
@@ -3614,7 +3613,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
                                "ClearPortFeature USB_PORT_FEAT_POWER\n");
                        hprt0 = dwc2_read_hprt0(hsotg);
                        hprt0 &= ~HPRT0_PWR;
-                       dwc2_writel(hprt0, hsotg->regs + HPRT0);
+                       dwc2_writel(hsotg, hprt0, HPRT0);
                        break;
 
                case USB_PORT_FEAT_INDICATOR:
@@ -3735,7 +3734,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
                        break;
                }
 
-               hprt0 = dwc2_readl(hsotg->regs + HPRT0);
+               hprt0 = dwc2_readl(hsotg, HPRT0);
                dev_vdbg(hsotg->dev, "  HPRT0: 0x%08x\n", hprt0);
 
                if (hprt0 & HPRT0_CONNSTS)
@@ -3776,9 +3775,9 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
 
                                dev_info(hsotg->dev, "Enabling descriptor DMA mode\n");
                                hsotg->params.dma_desc_enable = true;
-                               hcfg = dwc2_readl(hsotg->regs + HCFG);
+                               hcfg = dwc2_readl(hsotg, HCFG);
                                hcfg |= HCFG_DESCDMA;
-                               dwc2_writel(hcfg, hsotg->regs + HCFG);
+                               dwc2_writel(hsotg, hcfg, HCFG);
                                hsotg->new_connection = false;
                        }
                }
@@ -3825,7 +3824,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
                                "SetPortFeature - USB_PORT_FEAT_POWER\n");
                        hprt0 = dwc2_read_hprt0(hsotg);
                        hprt0 |= HPRT0_PWR;
-                       dwc2_writel(hprt0, hsotg->regs + HPRT0);
+                       dwc2_writel(hsotg, hprt0, HPRT0);
                        break;
 
                case USB_PORT_FEAT_RESET:
@@ -3835,11 +3834,11 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
                        hprt0 = dwc2_read_hprt0(hsotg);
                        dev_dbg(hsotg->dev,
                                "SetPortFeature - USB_PORT_FEAT_RESET\n");
-                       pcgctl = dwc2_readl(hsotg->regs + PCGCTL);
+                       pcgctl = dwc2_readl(hsotg, PCGCTL);
                        pcgctl &= ~(PCGCTL_ENBL_SLEEP_GATING | PCGCTL_STOPPCLK);
-                       dwc2_writel(pcgctl, hsotg->regs + PCGCTL);
+                       dwc2_writel(hsotg, pcgctl, PCGCTL);
                        /* ??? Original driver does this */
-                       dwc2_writel(0, hsotg->regs + PCGCTL);
+                       dwc2_writel(hsotg, 0, PCGCTL);
 
                        hprt0 = dwc2_read_hprt0(hsotg);
                        /* Clear suspend bit if resetting from suspend state */
@@ -3854,13 +3853,13 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
                                hprt0 |= HPRT0_PWR | HPRT0_RST;
                                dev_dbg(hsotg->dev,
                                        "In host mode, hprt0=%08x\n", hprt0);
-                               dwc2_writel(hprt0, hsotg->regs + HPRT0);
+                               dwc2_writel(hsotg, hprt0, HPRT0);
                        }
 
                        /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */
                        msleep(50);
                        hprt0 &= ~HPRT0_RST;
-                       dwc2_writel(hprt0, hsotg->regs + HPRT0);
+                       dwc2_writel(hsotg, hprt0, HPRT0);
                        hsotg->lx_state = DWC2_L0; /* Now back to On state */
                        break;
 
@@ -3876,7 +3875,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
                                "SetPortFeature - USB_PORT_FEAT_TEST\n");
                        hprt0 &= ~HPRT0_TSTCTL_MASK;
                        hprt0 |= (windex >> 8) << HPRT0_TSTCTL_SHIFT;
-                       dwc2_writel(hprt0, hsotg->regs + HPRT0);
+                       dwc2_writel(hsotg, hprt0, HPRT0);
                        break;
 
                default:
@@ -3933,7 +3932,7 @@ static int dwc2_hcd_is_status_changed(struct dwc2_hsotg *hsotg, int port)
 
 int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg)
 {
-       u32 hfnum = dwc2_readl(hsotg->regs + HFNUM);
+       u32 hfnum = dwc2_readl(hsotg, HFNUM);
 
 #ifdef DWC2_DEBUG_SOF
        dev_vdbg(hsotg->dev, "DWC OTG HCD GET FRAME NUMBER %d\n",
@@ -3944,9 +3943,9 @@ int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg)
 
 int dwc2_hcd_get_future_frame_number(struct dwc2_hsotg *hsotg, int us)
 {
-       u32 hprt = dwc2_readl(hsotg->regs + HPRT0);
-       u32 hfir = dwc2_readl(hsotg->regs + HFIR);
-       u32 hfnum = dwc2_readl(hsotg->regs + HFNUM);
+       u32 hprt = dwc2_readl(hsotg, HPRT0);
+       u32 hfir = dwc2_readl(hsotg, HFIR);
+       u32 hfnum = dwc2_readl(hsotg, HFNUM);
        unsigned int us_per_frame;
        unsigned int frame_number;
        unsigned int remaining;
@@ -4065,11 +4064,11 @@ void dwc2_hcd_dump_state(struct dwc2_hsotg *hsotg)
                if (chan->xfer_started) {
                        u32 hfnum, hcchar, hctsiz, hcint, hcintmsk;
 
-                       hfnum = dwc2_readl(hsotg->regs + HFNUM);
-                       hcchar = dwc2_readl(hsotg->regs + HCCHAR(i));
-                       hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(i));
-                       hcint = dwc2_readl(hsotg->regs + HCINT(i));
-                       hcintmsk = dwc2_readl(hsotg->regs + HCINTMSK(i));
+                       hfnum = dwc2_readl(hsotg, HFNUM);
+                       hcchar = dwc2_readl(hsotg, HCCHAR(i));
+                       hctsiz = dwc2_readl(hsotg, HCTSIZ(i));
+                       hcint = dwc2_readl(hsotg, HCINT(i));
+                       hcintmsk = dwc2_readl(hsotg, HCINTMSK(i));
                        dev_dbg(hsotg->dev, "    hfnum: 0x%08x\n", hfnum);
                        dev_dbg(hsotg->dev, "    hcchar: 0x%08x\n", hcchar);
                        dev_dbg(hsotg->dev, "    hctsiz: 0x%08x\n", hctsiz);
@@ -4117,12 +4116,12 @@ void dwc2_hcd_dump_state(struct dwc2_hsotg *hsotg)
        dev_dbg(hsotg->dev, "  periodic_channels: %d\n",
                hsotg->periodic_channels);
        dev_dbg(hsotg->dev, "  periodic_usecs: %d\n", hsotg->periodic_usecs);
-       np_tx_status = dwc2_readl(hsotg->regs + GNPTXSTS);
+       np_tx_status = dwc2_readl(hsotg, GNPTXSTS);
        dev_dbg(hsotg->dev, "  NP Tx Req Queue Space Avail: %d\n",
                (np_tx_status & TXSTS_QSPCAVAIL_MASK) >> TXSTS_QSPCAVAIL_SHIFT);
        dev_dbg(hsotg->dev, "  NP Tx FIFO Space Avail: %d\n",
                (np_tx_status & TXSTS_FSPCAVAIL_MASK) >> TXSTS_FSPCAVAIL_SHIFT);
-       p_tx_status = dwc2_readl(hsotg->regs + HPTXSTS);
+       p_tx_status = dwc2_readl(hsotg, HPTXSTS);
        dev_dbg(hsotg->dev, "  P Tx Req Queue Space Avail: %d\n",
                (p_tx_status & TXSTS_QSPCAVAIL_MASK) >> TXSTS_QSPCAVAIL_SHIFT);
        dev_dbg(hsotg->dev, "  P Tx FIFO Space Avail: %d\n",
@@ -4372,7 +4371,7 @@ static void dwc2_hcd_reset_func(struct work_struct *work)
 
        hprt0 = dwc2_read_hprt0(hsotg);
        hprt0 &= ~HPRT0_RST;
-       dwc2_writel(hprt0, hsotg->regs + HPRT0);
+       dwc2_writel(hsotg, hprt0, HPRT0);
        hsotg->flags.b.port_reset_change = 1;
 
        spin_unlock_irqrestore(&hsotg->lock, flags);
@@ -4482,7 +4481,7 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
                hprt0 = dwc2_read_hprt0(hsotg);
                hprt0 |= HPRT0_SUSP;
                hprt0 &= ~HPRT0_PWR;
-               dwc2_writel(hprt0, hsotg->regs + HPRT0);
+               dwc2_writel(hsotg, hprt0, HPRT0);
                dwc2_vbus_supply_exit(hsotg);
        }
 
@@ -4573,8 +4572,8 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)
                 * Clear Port Enable and Port Status changes.
                 * Enable Port Power.
                 */
-               dwc2_writel(HPRT0_PWR | HPRT0_CONNDET |
-                               HPRT0_ENACHG, hsotg->regs + HPRT0);
+               dwc2_writel(hsotg, HPRT0_PWR | HPRT0_CONNDET |
+                               HPRT0_ENACHG, HPRT0);
                /* Wait for controller to detect Port Connect */
                usleep_range(5000, 7000);
        }
@@ -5094,17 +5093,17 @@ static void dwc2_hcd_free(struct dwc2_hsotg *hsotg)
                hsotg->status_buf = NULL;
        }
 
-       ahbcfg = dwc2_readl(hsotg->regs + GAHBCFG);
+       ahbcfg = dwc2_readl(hsotg, GAHBCFG);
 
        /* Disable all interrupts */
        ahbcfg &= ~GAHBCFG_GLBL_INTR_EN;
-       dwc2_writel(ahbcfg, hsotg->regs + GAHBCFG);
-       dwc2_writel(0, hsotg->regs + GINTMSK);
+       dwc2_writel(hsotg, ahbcfg, GAHBCFG);
+       dwc2_writel(hsotg, 0, GINTMSK);
 
        if (hsotg->hw_params.snpsid >= DWC2_CORE_REV_3_00a) {
-               dctl = dwc2_readl(hsotg->regs + DCTL);
+               dctl = dwc2_readl(hsotg, DCTL);
                dctl |= DCTL_SFTDISCON;
-               dwc2_writel(dctl, hsotg->regs + DCTL);
+               dwc2_writel(hsotg, dctl, DCTL);
        }
 
        if (hsotg->wq_otg) {
@@ -5147,7 +5146,7 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg)
 
        retval = -ENOMEM;
 
-       hcfg = dwc2_readl(hsotg->regs + HCFG);
+       hcfg = dwc2_readl(hsotg, HCFG);
        dev_dbg(hsotg->dev, "hcfg=%08x\n", hcfg);
 
 #ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
@@ -5437,14 +5436,14 @@ int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg)
 
        /* Backup Host regs */
        hr = &hsotg->hr_backup;
-       hr->hcfg = dwc2_readl(hsotg->regs + HCFG);
-       hr->haintmsk = dwc2_readl(hsotg->regs + HAINTMSK);
+       hr->hcfg = dwc2_readl(hsotg, HCFG);
+       hr->haintmsk = dwc2_readl(hsotg, HAINTMSK);
        for (i = 0; i < hsotg->params.host_channels; ++i)
-               hr->hcintmsk[i] = dwc2_readl(hsotg->regs + HCINTMSK(i));
+               hr->hcintmsk[i] = dwc2_readl(hsotg, HCINTMSK(i));
 
        hr->hprt0 = dwc2_read_hprt0(hsotg);
-       hr->hfir = dwc2_readl(hsotg->regs + HFIR);
-       hr->hptxfsiz = dwc2_readl(hsotg->regs + HPTXFSIZ);
+       hr->hfir = dwc2_readl(hsotg, HFIR);
+       hr->hptxfsiz = dwc2_readl(hsotg, HPTXFSIZ);
        hr->valid = true;
 
        return 0;
@@ -5473,15 +5472,15 @@ int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg)
        }
        hr->valid = false;
 
-       dwc2_writel(hr->hcfg, hsotg->regs + HCFG);
-       dwc2_writel(hr->haintmsk, hsotg->regs + HAINTMSK);
+       dwc2_writel(hsotg, hr->hcfg, HCFG);
+       dwc2_writel(hsotg, hr->haintmsk, HAINTMSK);
 
        for (i = 0; i < hsotg->params.host_channels; ++i)
-               dwc2_writel(hr->hcintmsk[i], hsotg->regs + HCINTMSK(i));
+               dwc2_writel(hsotg, hr->hcintmsk[i], HCINTMSK(i));
 
-       dwc2_writel(hr->hprt0, hsotg->regs + HPRT0);
-       dwc2_writel(hr->hfir, hsotg->regs + HFIR);
-       dwc2_writel(hr->hptxfsiz, hsotg->regs + HPTXFSIZ);
+       dwc2_writel(hsotg, hr->hprt0, HPRT0);
+       dwc2_writel(hsotg, hr->hfir, HFIR);
+       dwc2_writel(hsotg, hr->hptxfsiz, HPTXFSIZ);
        hsotg->frame_number = 0;
 
        return 0;
@@ -5516,10 +5515,10 @@ int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg)
        }
 
        /* Enter USB Suspend Mode */
-       hprt0 = dwc2_readl(hsotg->regs + HPRT0);
+       hprt0 = dwc2_readl(hsotg, HPRT0);
        hprt0 |= HPRT0_SUSP;
        hprt0 &= ~HPRT0_ENA;
-       dwc2_writel(hprt0, hsotg->regs + HPRT0);
+       dwc2_writel(hsotg, hprt0, HPRT0);
 
        /* Wait for the HPRT0.PrtSusp register field to be set */
        if (dwc2_hsotg_wait_bit_set(hsotg, HPRT0, HPRT0_SUSP, 3000))
@@ -5532,56 +5531,56 @@ int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg)
        spin_lock_irqsave(&hsotg->lock, flags);
        hsotg->lx_state = DWC2_L2;
 
-       gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
+       gusbcfg = dwc2_readl(hsotg, GUSBCFG);
        if (gusbcfg & GUSBCFG_ULPI_UTMI_SEL) {
                /* ULPI interface */
                /* Suspend the Phy Clock */
-               pcgcctl = dwc2_readl(hsotg->regs + PCGCTL);
+               pcgcctl = dwc2_readl(hsotg, PCGCTL);
                pcgcctl |= PCGCTL_STOPPCLK;
-               dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
+               dwc2_writel(hsotg, pcgcctl, PCGCTL);
                udelay(10);
 
-               gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+               gpwrdn = dwc2_readl(hsotg, GPWRDN);
                gpwrdn |= GPWRDN_PMUACTV;
-               dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+               dwc2_writel(hsotg, gpwrdn, GPWRDN);
                udelay(10);
        } else {
                /* UTMI+ Interface */
-               gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+               gpwrdn = dwc2_readl(hsotg, GPWRDN);
                gpwrdn |= GPWRDN_PMUACTV;
-               dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+               dwc2_writel(hsotg, gpwrdn, GPWRDN);
                udelay(10);
 
-               pcgcctl = dwc2_readl(hsotg->regs + PCGCTL);
+               pcgcctl = dwc2_readl(hsotg, PCGCTL);
                pcgcctl |= PCGCTL_STOPPCLK;
-               dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
+               dwc2_writel(hsotg, pcgcctl, PCGCTL);
                udelay(10);
        }
 
        /* Enable interrupts from wake up logic */
-       gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+       gpwrdn = dwc2_readl(hsotg, GPWRDN);
        gpwrdn |= GPWRDN_PMUINTSEL;
-       dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+       dwc2_writel(hsotg, gpwrdn, GPWRDN);
        udelay(10);
 
        /* Unmask host mode interrupts in GPWRDN */
-       gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+       gpwrdn = dwc2_readl(hsotg, GPWRDN);
        gpwrdn |= GPWRDN_DISCONN_DET_MSK;
        gpwrdn |= GPWRDN_LNSTSCHG_MSK;
        gpwrdn |= GPWRDN_STS_CHGINT_MSK;
-       dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+       dwc2_writel(hsotg, gpwrdn, GPWRDN);
        udelay(10);
 
        /* Enable Power Down Clamp */
-       gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+       gpwrdn = dwc2_readl(hsotg, GPWRDN);
        gpwrdn |= GPWRDN_PWRDNCLMP;
-       dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+       dwc2_writel(hsotg, gpwrdn, GPWRDN);
        udelay(10);
 
        /* Switch off VDD */
-       gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+       gpwrdn = dwc2_readl(hsotg, GPWRDN);
        gpwrdn |= GPWRDN_PWRDNSWTCH;
-       dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+       dwc2_writel(hsotg, gpwrdn, GPWRDN);
 
        hsotg->hibernated = 1;
        hsotg->bus_suspended = 1;
@@ -5629,29 +5628,29 @@ int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup,
        mdelay(100);
 
        /* Clear all pending interupts */
-       dwc2_writel(0xffffffff, hsotg->regs + GINTSTS);
+       dwc2_writel(hsotg, 0xffffffff, GINTSTS);
 
        /* De-assert Restore */
-       gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+       gpwrdn = dwc2_readl(hsotg, GPWRDN);
        gpwrdn &= ~GPWRDN_RESTORE;
-       dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+       dwc2_writel(hsotg, gpwrdn, GPWRDN);
        udelay(10);
 
        /* Restore GUSBCFG, HCFG */
-       dwc2_writel(gr->gusbcfg, hsotg->regs + GUSBCFG);
-       dwc2_writel(hr->hcfg, hsotg->regs + HCFG);
+       dwc2_writel(hsotg, gr->gusbcfg, GUSBCFG);
+       dwc2_writel(hsotg, hr->hcfg, HCFG);
 
        /* De-assert Wakeup Logic */
-       gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
+       gpwrdn = dwc2_readl(hsotg, GPWRDN);
        gpwrdn &= ~GPWRDN_PMUACTV;
-       dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
+       dwc2_writel(hsotg, gpwrdn, GPWRDN);
        udelay(10);
 
        hprt0 = hr->hprt0;
        hprt0 |= HPRT0_PWR;
        hprt0 &= ~HPRT0_ENA;
        hprt0 &= ~HPRT0_SUSP;
-       dwc2_writel(hprt0, hsotg->regs + HPRT0);
+       dwc2_writel(hsotg, hprt0, HPRT0);
 
        hprt0 = hr->hprt0;
        hprt0 |= HPRT0_PWR;
@@ -5660,32 +5659,32 @@ int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup,
 
        if (reset) {
                hprt0 |= HPRT0_RST;
-               dwc2_writel(hprt0, hsotg->regs + HPRT0);
+               dwc2_writel(hsotg, hprt0, HPRT0);
 
                /* Wait for Resume time and then program HPRT again */
                mdelay(60);
                hprt0 &= ~HPRT0_RST;
-               dwc2_writel(hprt0, hsotg->regs + HPRT0);
+               dwc2_writel(hsotg, hprt0, HPRT0);
        } else {
                hprt0 |= HPRT0_RES;
-               dwc2_writel(hprt0, hsotg->regs + HPRT0);
+               dwc2_writel(hsotg, hprt0, HPRT0);
 
                /* Wait for Resume time and then program HPRT again */
                mdelay(100);
                hprt0 &= ~HPRT0_RES;
-               dwc2_writel(hprt0, hsotg->regs + HPRT0);
+               dwc2_writel(hsotg, hprt0, HPRT0);
        }
        /* Clear all interrupt status */
-       hprt0 = dwc2_readl(hsotg->regs + HPRT0);
+       hprt0 = dwc2_readl(hsotg, HPRT0);
        hprt0 |= HPRT0_CONNDET;
        hprt0 |= HPRT0_ENACHG;
        hprt0 &= ~HPRT0_ENA;
-       dwc2_writel(hprt0, hsotg->regs + HPRT0);
+       dwc2_writel(hsotg, hprt0, HPRT0);
 
-       hprt0 = dwc2_readl(hsotg->regs + HPRT0);
+       hprt0 = dwc2_readl(hsotg, HPRT0);
 
        /* Clear all pending interupts */
-       dwc2_writel(0xffffffff, hsotg->regs + GINTSTS);
+       dwc2_writel(hsotg, 0xffffffff, GINTSTS);
 
        /* Restore global registers */
        ret = dwc2_restore_global_registers(hsotg);
index 5502a50..3f9bccc 100644 (file)
@@ -469,10 +469,10 @@ static inline struct usb_hcd *dwc2_hsotg_to_hcd(struct dwc2_hsotg *hsotg)
  */
 static inline void disable_hc_int(struct dwc2_hsotg *hsotg, int chnum, u32 intr)
 {
-       u32 mask = dwc2_readl(hsotg->regs + HCINTMSK(chnum));
+       u32 mask = dwc2_readl(hsotg, HCINTMSK(chnum));
 
        mask &= ~intr;
-       dwc2_writel(mask, hsotg->regs + HCINTMSK(chnum));
+       dwc2_writel(hsotg, mask, HCINTMSK(chnum));
 }
 
 void dwc2_hc_cleanup(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan);
@@ -487,7 +487,7 @@ void dwc2_hc_start_transfer_ddma(struct dwc2_hsotg *hsotg,
  */
 static inline u32 dwc2_read_hprt0(struct dwc2_hsotg *hsotg)
 {
-       u32 hprt0 = dwc2_readl(hsotg->regs + HPRT0);
+       u32 hprt0 = dwc2_readl(hsotg, HPRT0);
 
        hprt0 &= ~(HPRT0_ENA | HPRT0_CONNDET | HPRT0_ENACHG | HPRT0_OVRCURRCHG);
        return hprt0;
@@ -690,8 +690,8 @@ static inline u16 dwc2_micro_frame_num(u16 frame)
  */
 static inline u32 dwc2_read_core_intr(struct dwc2_hsotg *hsotg)
 {
-       return dwc2_readl(hsotg->regs + GINTSTS) &
-              dwc2_readl(hsotg->regs + GINTMSK);
+       return dwc2_readl(hsotg, GINTSTS) &
+              dwc2_readl(hsotg, GINTMSK);
 }
 
 static inline u32 dwc2_hcd_urb_get_status(struct dwc2_hcd_urb *dwc2_urb)
index 74f11c8..a858b5f 100644 (file)
@@ -185,19 +185,19 @@ static void dwc2_per_sched_enable(struct dwc2_hsotg *hsotg, u32 fr_list_en)
 
        spin_lock_irqsave(&hsotg->lock, flags);
 
-       hcfg = dwc2_readl(hsotg->regs + HCFG);
+       hcfg = dwc2_readl(hsotg, HCFG);
        if (hcfg & HCFG_PERSCHEDENA) {
                /* already enabled */
                spin_unlock_irqrestore(&hsotg->lock, flags);
                return;
        }
 
-       dwc2_writel(hsotg->frame_list_dma, hsotg->regs + HFLBADDR);
+       dwc2_writel(hsotg, hsotg->frame_list_dma, HFLBADDR);
 
        hcfg &= ~HCFG_FRLISTEN_MASK;
        hcfg |= fr_list_en | HCFG_PERSCHEDENA;
        dev_vdbg(hsotg->dev, "Enabling Periodic schedule\n");
-       dwc2_writel(hcfg, hsotg->regs + HCFG);
+       dwc2_writel(hsotg, hcfg, HCFG);
 
        spin_unlock_irqrestore(&hsotg->lock, flags);
 }
@@ -209,7 +209,7 @@ static void dwc2_per_sched_disable(struct dwc2_hsotg *hsotg)
 
        spin_lock_irqsave(&hsotg->lock, flags);
 
-       hcfg = dwc2_readl(hsotg->regs + HCFG);
+       hcfg = dwc2_readl(hsotg, HCFG);
        if (!(hcfg & HCFG_PERSCHEDENA)) {
                /* already disabled */
                spin_unlock_irqrestore(&hsotg->lock, flags);
@@ -218,7 +218,7 @@ static void dwc2_per_sched_disable(struct dwc2_hsotg *hsotg)
 
        hcfg &= ~HCFG_PERSCHEDENA;
        dev_vdbg(hsotg->dev, "Disabling Periodic schedule\n");
-       dwc2_writel(hcfg, hsotg->regs + HCFG);
+       dwc2_writel(hsotg, hcfg, HCFG);
 
        spin_unlock_irqrestore(&hsotg->lock, flags);
 }
index 8ce10ca..88b5dcf 100644 (file)
@@ -144,7 +144,7 @@ static void dwc2_sof_intr(struct dwc2_hsotg *hsotg)
        enum dwc2_transaction_type tr_type;
 
        /* Clear interrupt */
-       dwc2_writel(GINTSTS_SOF, hsotg->regs + GINTSTS);
+       dwc2_writel(hsotg, GINTSTS_SOF, GINTSTS);
 
 #ifdef DEBUG_SOF
        dev_vdbg(hsotg->dev, "--Start of Frame Interrupt--\n");
@@ -191,7 +191,7 @@ static void dwc2_rx_fifo_level_intr(struct dwc2_hsotg *hsotg)
        if (dbg_perio())
                dev_vdbg(hsotg->dev, "--RxFIFO Level Interrupt--\n");
 
-       grxsts = dwc2_readl(hsotg->regs + GRXSTSP);
+       grxsts = dwc2_readl(hsotg, GRXSTSP);
        chnum = (grxsts & GRXSTS_HCHNUM_MASK) >> GRXSTS_HCHNUM_SHIFT;
        chan = hsotg->hc_ptr_array[chnum];
        if (!chan) {
@@ -274,11 +274,11 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
        dev_vdbg(hsotg->dev, "%s(%p)\n", __func__, hsotg);
 
        /* Every time when port enables calculate HFIR.FrInterval */
-       hfir = dwc2_readl(hsotg->regs + HFIR);
+       hfir = dwc2_readl(hsotg, HFIR);
        hfir &= ~HFIR_FRINT_MASK;
        hfir |= dwc2_calc_frame_interval(hsotg) << HFIR_FRINT_SHIFT &
                HFIR_FRINT_MASK;
-       dwc2_writel(hfir, hsotg->regs + HFIR);
+       dwc2_writel(hsotg, hfir, HFIR);
 
        /* Check if we need to adjust the PHY clock speed for low power */
        if (!params->host_support_fs_ls_low_power) {
@@ -287,7 +287,7 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
                return;
        }
 
-       usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
+       usbcfg = dwc2_readl(hsotg, GUSBCFG);
        prtspd = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
 
        if (prtspd == HPRT0_SPD_LOW_SPEED || prtspd == HPRT0_SPD_FULL_SPEED) {
@@ -295,11 +295,11 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
                if (!(usbcfg & GUSBCFG_PHY_LP_CLK_SEL)) {
                        /* Set PHY low power clock select for FS/LS devices */
                        usbcfg |= GUSBCFG_PHY_LP_CLK_SEL;
-                       dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
+                       dwc2_writel(hsotg, usbcfg, GUSBCFG);
                        do_reset = 1;
                }
 
-               hcfg = dwc2_readl(hsotg->regs + HCFG);
+               hcfg = dwc2_readl(hsotg, HCFG);
                fslspclksel = (hcfg & HCFG_FSLSPCLKSEL_MASK) >>
                              HCFG_FSLSPCLKSEL_SHIFT;
 
@@ -312,7 +312,7 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
                                fslspclksel = HCFG_FSLSPCLKSEL_6_MHZ;
                                hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
                                hcfg |= fslspclksel << HCFG_FSLSPCLKSEL_SHIFT;
-                               dwc2_writel(hcfg, hsotg->regs + HCFG);
+                               dwc2_writel(hsotg, hcfg, HCFG);
                                do_reset = 1;
                        }
                } else {
@@ -323,7 +323,7 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
                                fslspclksel = HCFG_FSLSPCLKSEL_48_MHZ;
                                hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
                                hcfg |= fslspclksel << HCFG_FSLSPCLKSEL_SHIFT;
-                               dwc2_writel(hcfg, hsotg->regs + HCFG);
+                               dwc2_writel(hsotg, hcfg, HCFG);
                                do_reset = 1;
                        }
                }
@@ -331,14 +331,14 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
                /* Not low power */
                if (usbcfg & GUSBCFG_PHY_LP_CLK_SEL) {
                        usbcfg &= ~GUSBCFG_PHY_LP_CLK_SEL;
-                       dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
+                       dwc2_writel(hsotg, usbcfg, GUSBCFG);
                        do_reset = 1;
                }
        }
 
        if (do_reset) {
                *hprt0_modify |= HPRT0_RST;
-               dwc2_writel(*hprt0_modify, hsotg->regs + HPRT0);
+               dwc2_writel(hsotg, *hprt0_modify, HPRT0);
                queue_delayed_work(hsotg->wq_otg, &hsotg->reset_work,
                                   msecs_to_jiffies(60));
        } else {
@@ -359,7 +359,7 @@ static void dwc2_port_intr(struct dwc2_hsotg *hsotg)
 
        dev_vdbg(hsotg->dev, "--Port Interrupt--\n");
 
-       hprt0 = dwc2_readl(hsotg->regs + HPRT0);
+       hprt0 = dwc2_readl(hsotg, HPRT0);
        hprt0_modify = hprt0;
 
        /*
@@ -374,7 +374,7 @@ static void dwc2_port_intr(struct dwc2_hsotg *hsotg)
         * Set flag and clear if detected
         */
        if (hprt0 & HPRT0_CONNDET) {
-               dwc2_writel(hprt0_modify | HPRT0_CONNDET, hsotg->regs + HPRT0);
+               dwc2_writel(hsotg, hprt0_modify | HPRT0_CONNDET, HPRT0);
 
                dev_vdbg(hsotg->dev,
                         "--Port Interrupt HPRT0=0x%08x Port Connect Detected--\n",
@@ -392,7 +392,7 @@ static void dwc2_port_intr(struct dwc2_hsotg *hsotg)
         * Clear if detected - Set internal flag if disabled
         */
        if (hprt0 & HPRT0_ENACHG) {
-               dwc2_writel(hprt0_modify | HPRT0_ENACHG, hsotg->regs + HPRT0);
+               dwc2_writel(hsotg, hprt0_modify | HPRT0_ENACHG, HPRT0);
                dev_vdbg(hsotg->dev,
                         "  --Port Interrupt HPRT0=0x%08x Port Enable Changed (now %d)--\n",
                         hprt0, !!(hprt0 & HPRT0_ENA));
@@ -406,17 +406,17 @@ static void dwc2_port_intr(struct dwc2_hsotg *hsotg)
 
                                hsotg->params.dma_desc_enable = false;
                                hsotg->new_connection = false;
-                               hcfg = dwc2_readl(hsotg->regs + HCFG);
+                               hcfg = dwc2_readl(hsotg, HCFG);
                                hcfg &= ~HCFG_DESCDMA;
-                               dwc2_writel(hcfg, hsotg->regs + HCFG);
+                               dwc2_writel(hsotg, hcfg, HCFG);
                        }
                }
        }
 
        /* Overcurrent Change Interrupt */
        if (hprt0 & HPRT0_OVRCURRCHG) {
-               dwc2_writel(hprt0_modify | HPRT0_OVRCURRCHG,
-                           hsotg->regs + HPRT0);
+               dwc2_writel(hsotg, hprt0_modify | HPRT0_OVRCURRCHG,
+                           HPRT0);
                dev_vdbg(hsotg->dev,
                         "  --Port Interrupt HPRT0=0x%08x Port Overcurrent Changed--\n",
                         hprt0);
@@ -441,7 +441,7 @@ static u32 dwc2_get_actual_xfer_length(struct dwc2_hsotg *hsotg,
 {
        u32 hctsiz, count, length;
 
-       hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
+       hctsiz = dwc2_readl(hsotg, HCTSIZ(chnum));
 
        if (halt_status == DWC2_HC_XFER_COMPLETE) {
                if (chan->ep_is_in) {
@@ -518,7 +518,7 @@ static int dwc2_update_urb_state(struct dwc2_hsotg *hsotg,
                urb->status = 0;
        }
 
-       hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
+       hctsiz = dwc2_readl(hsotg, HCTSIZ(chnum));
        dev_vdbg(hsotg->dev, "DWC_otg: %s: %s, channel %d\n",
                 __func__, (chan->ep_is_in ? "IN" : "OUT"), chnum);
        dev_vdbg(hsotg->dev, "  chan->xfer_len %d\n", chan->xfer_len);
@@ -541,7 +541,7 @@ void dwc2_hcd_save_data_toggle(struct dwc2_hsotg *hsotg,
                               struct dwc2_host_chan *chan, int chnum,
                               struct dwc2_qtd *qtd)
 {
-       u32 hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
+       u32 hctsiz = dwc2_readl(hsotg, HCTSIZ(chnum));
        u32 pid = (hctsiz & TSIZ_SC_MC_PID_MASK) >> TSIZ_SC_MC_PID_SHIFT;
 
        if (chan->ep_type != USB_ENDPOINT_XFER_CONTROL) {
@@ -780,9 +780,9 @@ cleanup:
                }
        }
 
-       haintmsk = dwc2_readl(hsotg->regs + HAINTMSK);
+       haintmsk = dwc2_readl(hsotg, HAINTMSK);
        haintmsk &= ~(1 << chan->hc_num);
-       dwc2_writel(haintmsk, hsotg->regs + HAINTMSK);
+       dwc2_writel(hsotg, haintmsk, HAINTMSK);
 
        /* Try to queue more transfers now that there's a free channel */
        tr_type = dwc2_hcd_select_transactions(hsotg);
@@ -829,9 +829,9 @@ static void dwc2_halt_channel(struct dwc2_hsotg *hsotg,
                         * is enabled so that the non-periodic schedule will
                         * be processed
                         */
-                       gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
+                       gintmsk = dwc2_readl(hsotg, GINTMSK);
                        gintmsk |= GINTSTS_NPTXFEMP;
-                       dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
+                       dwc2_writel(hsotg, gintmsk, GINTMSK);
                } else {
                        dev_vdbg(hsotg->dev, "isoc/intr\n");
                        /*
@@ -848,9 +848,9 @@ static void dwc2_halt_channel(struct dwc2_hsotg *hsotg,
                         * enabled so that the periodic schedule will be
                         * processed
                         */
-                       gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
+                       gintmsk = dwc2_readl(hsotg, GINTMSK);
                        gintmsk |= GINTSTS_PTXFEMP;
-                       dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
+                       dwc2_writel(hsotg, gintmsk, GINTMSK);
                }
        }
 }
@@ -915,7 +915,7 @@ static void dwc2_complete_periodic_xfer(struct dwc2_hsotg *hsotg,
                                        struct dwc2_qtd *qtd,
                                        enum dwc2_halt_status halt_status)
 {
-       u32 hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
+       u32 hctsiz = dwc2_readl(hsotg, HCTSIZ(chnum));
 
        qtd->error_count = 0;
 
@@ -959,7 +959,7 @@ static int dwc2_xfercomp_isoc_split_in(struct dwc2_hsotg *hsotg,
 
        qtd->isoc_split_offset += len;
 
-       hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
+       hctsiz = dwc2_readl(hsotg, HCTSIZ(chnum));
        pid = (hctsiz & TSIZ_SC_MC_PID_MASK) >> TSIZ_SC_MC_PID_SHIFT;
 
        if (frame_desc->actual_length >= frame_desc->length || pid == 0) {
@@ -1185,7 +1185,7 @@ static void dwc2_update_urb_state_abn(struct dwc2_hsotg *hsotg,
 
        urb->actual_length += xfer_length;
 
-       hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
+       hctsiz = dwc2_readl(hsotg, HCTSIZ(chnum));
        dev_vdbg(hsotg->dev, "DWC_otg: %s: %s, channel %d\n",
                 __func__, (chan->ep_is_in ? "IN" : "OUT"), chnum);
        dev_vdbg(hsotg->dev, "  chan->start_pkt_count %d\n",
@@ -1566,10 +1566,10 @@ static void dwc2_hc_ahberr_intr(struct dwc2_hsotg *hsotg,
 
        dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
 
-       hcchar = dwc2_readl(hsotg->regs + HCCHAR(chnum));
-       hcsplt = dwc2_readl(hsotg->regs + HCSPLT(chnum));
-       hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
-       hc_dma = dwc2_readl(hsotg->regs + HCDMA(chnum));
+       hcchar = dwc2_readl(hsotg, HCCHAR(chnum));
+       hcsplt = dwc2_readl(hsotg, HCSPLT(chnum));
+       hctsiz = dwc2_readl(hsotg, HCTSIZ(chnum));
+       hc_dma = dwc2_readl(hsotg, HCDMA(chnum));
 
        dev_err(hsotg->dev, "AHB ERROR, Channel %d\n", chnum);
        dev_err(hsotg->dev, "  hcchar 0x%08x, hcsplt 0x%08x\n", hcchar, hcsplt);
@@ -1781,10 +1781,10 @@ static bool dwc2_halt_status_ok(struct dwc2_hsotg *hsotg,
                 * This code is here only as a check. This condition should
                 * never happen. Ignore the halt if it does occur.
                 */
-               hcchar = dwc2_readl(hsotg->regs + HCCHAR(chnum));
-               hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
-               hcintmsk = dwc2_readl(hsotg->regs + HCINTMSK(chnum));
-               hcsplt = dwc2_readl(hsotg->regs + HCSPLT(chnum));
+               hcchar = dwc2_readl(hsotg, HCCHAR(chnum));
+               hctsiz = dwc2_readl(hsotg, HCTSIZ(chnum));
+               hcintmsk = dwc2_readl(hsotg, HCINTMSK(chnum));
+               hcsplt = dwc2_readl(hsotg, HCSPLT(chnum));
                dev_dbg(hsotg->dev,
                        "%s: chan->halt_status DWC2_HC_XFER_NO_HALT_STATUS,\n",
                         __func__);
@@ -1808,7 +1808,7 @@ static bool dwc2_halt_status_ok(struct dwc2_hsotg *hsotg,
         * when the halt interrupt occurs. Halt the channel again if it does
         * occur.
         */
-       hcchar = dwc2_readl(hsotg->regs + HCCHAR(chnum));
+       hcchar = dwc2_readl(hsotg, HCCHAR(chnum));
        if (hcchar & HCCHAR_CHDIS) {
                dev_warn(hsotg->dev,
                         "%s: hcchar.chdis set unexpectedly, hcchar 0x%08x, trying to halt again\n",
@@ -1868,7 +1868,7 @@ static void dwc2_hc_chhltd_intr_dma(struct dwc2_hsotg *hsotg,
                return;
        }
 
-       hcintmsk = dwc2_readl(hsotg->regs + HCINTMSK(chnum));
+       hcintmsk = dwc2_readl(hsotg, HCINTMSK(chnum));
 
        if (chan->hcint & HCINTMSK_XFERCOMPL) {
                /*
@@ -1963,7 +1963,7 @@ static void dwc2_hc_chhltd_intr_dma(struct dwc2_hsotg *hsotg,
                                dev_err(hsotg->dev,
                                        "hcint 0x%08x, intsts 0x%08x\n",
                                        chan->hcint,
-                                       dwc2_readl(hsotg->regs + GINTSTS));
+                                       dwc2_readl(hsotg, GINTSTS));
                                goto error;
                        }
                }
@@ -2036,11 +2036,11 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum)
 
        chan = hsotg->hc_ptr_array[chnum];
 
-       hcint = dwc2_readl(hsotg->regs + HCINT(chnum));
-       hcintmsk = dwc2_readl(hsotg->regs + HCINTMSK(chnum));
+       hcint = dwc2_readl(hsotg, HCINT(chnum));
+       hcintmsk = dwc2_readl(hsotg, HCINTMSK(chnum));
        if (!chan) {
                dev_err(hsotg->dev, "## hc_ptr_array for channel is NULL ##\n");
-               dwc2_writel(hcint, hsotg->regs + HCINT(chnum));
+               dwc2_writel(hsotg, hcint, HCINT(chnum));
                return;
        }
 
@@ -2052,7 +2052,7 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum)
                         hcint, hcintmsk, hcint & hcintmsk);
        }
 
-       dwc2_writel(hcint, hsotg->regs + HCINT(chnum));
+       dwc2_writel(hsotg, hcint, HCINT(chnum));
 
        /*
         * If we got an interrupt after someone called
@@ -2187,7 +2187,7 @@ static void dwc2_hc_intr(struct dwc2_hsotg *hsotg)
        int i;
        struct dwc2_host_chan *chan, *chan_tmp;
 
-       haint = dwc2_readl(hsotg->regs + HAINT);
+       haint = dwc2_readl(hsotg, HAINT);
        if (dbg_perio()) {
                dev_vdbg(hsotg->dev, "%s()\n", __func__);
 
@@ -2271,8 +2271,8 @@ irqreturn_t dwc2_handle_hcd_intr(struct dwc2_hsotg *hsotg)
                                 "DWC OTG HCD Finished Servicing Interrupts\n");
                        dev_vdbg(hsotg->dev,
                                 "DWC OTG HCD gintsts=0x%08x gintmsk=0x%08x\n",
-                                dwc2_readl(hsotg->regs + GINTSTS),
-                                dwc2_readl(hsotg->regs + GINTMSK));
+                                dwc2_readl(hsotg, GINTSTS),
+                                dwc2_readl(hsotg, GINTMSK));
                }
        }
 
index 301ced1..4083959 100644 (file)
@@ -1510,7 +1510,7 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
        bool ep_is_in = !!dwc2_hcd_is_pipe_in(&urb->pipe_info);
        bool ep_is_isoc = (ep_type == USB_ENDPOINT_XFER_ISOC);
        bool ep_is_int = (ep_type == USB_ENDPOINT_XFER_INT);
-       u32 hprt = dwc2_readl(hsotg->regs + HPRT0);
+       u32 hprt = dwc2_readl(hsotg, HPRT0);
        u32 prtspd = (hprt & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
        bool do_split = (prtspd == HPRT0_SPD_HIGH_SPEED &&
                         dev_speed != USB_SPEED_HIGH);
@@ -1747,9 +1747,9 @@ int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
        if (status)
                return status;
        if (!hsotg->periodic_qh_count) {
-               intr_mask = dwc2_readl(hsotg->regs + GINTMSK);
+               intr_mask = dwc2_readl(hsotg, GINTMSK);
                intr_mask |= GINTSTS_SOF;
-               dwc2_writel(intr_mask, hsotg->regs + GINTMSK);
+               dwc2_writel(hsotg, intr_mask, GINTMSK);
        }
        hsotg->periodic_qh_count++;
 
@@ -1788,9 +1788,9 @@ void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
        hsotg->periodic_qh_count--;
        if (!hsotg->periodic_qh_count &&
            !hsotg->params.dma_desc_enable) {
-               intr_mask = dwc2_readl(hsotg->regs + GINTMSK);
+               intr_mask = dwc2_readl(hsotg, GINTMSK);
                intr_mask &= ~GINTSTS_SOF;
-               dwc2_writel(intr_mask, hsotg->regs + GINTMSK);
+               dwc2_writel(hsotg, intr_mask, GINTMSK);
        }
 }
 
index af075d4..bf7052e 100644 (file)
@@ -47,7 +47,6 @@ static void dwc2_set_bcm_params(struct dwc2_hsotg *hsotg)
        p->max_transfer_size = 65535;
        p->max_packet_count = 511;
        p->ahbcfg = 0x10;
-       p->uframe_sched = false;
 }
 
 static void dwc2_set_his_params(struct dwc2_hsotg *hsotg)
@@ -68,7 +67,6 @@ static void dwc2_set_his_params(struct dwc2_hsotg *hsotg)
        p->reload_ctl = false;
        p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 <<
                GAHBCFG_HBSTLEN_SHIFT;
-       p->uframe_sched = false;
        p->change_speed_quirk = true;
        p->power_down = false;
 }
@@ -112,7 +110,6 @@ static void dwc2_set_amlogic_params(struct dwc2_hsotg *hsotg)
        p->phy_type = DWC2_PHY_TYPE_PARAM_UTMI;
        p->ahbcfg = GAHBCFG_HBSTLEN_INCR8 <<
                GAHBCFG_HBSTLEN_SHIFT;
-       p->uframe_sched = false;
 }
 
 static void dwc2_set_amcc_params(struct dwc2_hsotg *hsotg)
@@ -134,7 +131,6 @@ static void dwc2_set_stm32f4x9_fsotg_params(struct dwc2_hsotg *hsotg)
        p->max_packet_count = 256;
        p->phy_type = DWC2_PHY_TYPE_PARAM_FS;
        p->i2c_enable = false;
-       p->uframe_sched = false;
        p->activate_stm_fs_transceiver = true;
 }
 
@@ -654,8 +650,8 @@ static void dwc2_get_host_hwparams(struct dwc2_hsotg *hsotg)
 
        dwc2_force_mode(hsotg, true);
 
-       gnptxfsiz = dwc2_readl(hsotg->regs + GNPTXFSIZ);
-       hptxfsiz = dwc2_readl(hsotg->regs + HPTXFSIZ);
+       gnptxfsiz = dwc2_readl(hsotg, GNPTXFSIZ);
+       hptxfsiz = dwc2_readl(hsotg, HPTXFSIZ);
 
        hw->host_nperio_tx_fifo_size = (gnptxfsiz & FIFOSIZE_DEPTH_MASK) >>
                                       FIFOSIZE_DEPTH_SHIFT;
@@ -679,13 +675,13 @@ static void dwc2_get_dev_hwparams(struct dwc2_hsotg *hsotg)
 
        dwc2_force_mode(hsotg, false);
 
-       gnptxfsiz = dwc2_readl(hsotg->regs + GNPTXFSIZ);
+       gnptxfsiz = dwc2_readl(hsotg, GNPTXFSIZ);
 
        fifo_count = dwc2_hsotg_tx_fifo_count(hsotg);
 
        for (fifo = 1; fifo <= fifo_count; fifo++) {
                hw->g_tx_fifo_size[fifo] =
-                       (dwc2_readl(hsotg->regs + DPTXFSIZN(fifo)) &
+                       (dwc2_readl(hsotg, DPTXFSIZN(fifo)) &
                         FIFOSIZE_DEPTH_MASK) >> FIFOSIZE_DEPTH_SHIFT;
        }
 
@@ -713,7 +709,7 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
         * 0x45f4xxxx, 0x5531xxxx or 0x5532xxxx
         */
 
-       hw->snpsid = dwc2_readl(hsotg->regs + GSNPSID);
+       hw->snpsid = dwc2_readl(hsotg, GSNPSID);
        if ((hw->snpsid & GSNPSID_ID_MASK) != DWC2_OTG_ID &&
            (hw->snpsid & GSNPSID_ID_MASK) != DWC2_FS_IOT_ID &&
            (hw->snpsid & GSNPSID_ID_MASK) != DWC2_HS_IOT_ID) {
@@ -726,11 +722,11 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
                hw->snpsid >> 12 & 0xf, hw->snpsid >> 8 & 0xf,
                hw->snpsid >> 4 & 0xf, hw->snpsid & 0xf, hw->snpsid);
 
-       hwcfg1 = dwc2_readl(hsotg->regs + GHWCFG1);
-       hwcfg2 = dwc2_readl(hsotg->regs + GHWCFG2);
-       hwcfg3 = dwc2_readl(hsotg->regs + GHWCFG3);
-       hwcfg4 = dwc2_readl(hsotg->regs + GHWCFG4);
-       grxfsiz = dwc2_readl(hsotg->regs + GRXFSIZ);
+       hwcfg1 = dwc2_readl(hsotg, GHWCFG1);
+       hwcfg2 = dwc2_readl(hsotg, GHWCFG2);
+       hwcfg3 = dwc2_readl(hsotg, GHWCFG3);
+       hwcfg4 = dwc2_readl(hsotg, GHWCFG4);
+       grxfsiz = dwc2_readl(hsotg, GRXFSIZ);
 
        /* hwcfg1 */
        hw->dev_ep_dirs = hwcfg1;
index 4c08195..9a53a58 100644 (file)
@@ -353,6 +353,23 @@ static void dwc2_driver_shutdown(struct platform_device *dev)
 }
 
 /**
+ * dwc2_check_core_endianness() - Returns true if core and AHB have
+ * opposite endianness.
+ * @hsotg:     Programming view of the DWC_otg controller.
+ */
+static bool dwc2_check_core_endianness(struct dwc2_hsotg *hsotg)
+{
+       u32 snpsid;
+
+       snpsid = ioread32(hsotg->regs + GSNPSID);
+       if ((snpsid & GSNPSID_ID_MASK) == DWC2_OTG_ID ||
+           (snpsid & GSNPSID_ID_MASK) == DWC2_FS_IOT_ID ||
+           (snpsid & GSNPSID_ID_MASK) == DWC2_HS_IOT_ID)
+               return false;
+       return true;
+}
+
+/**
  * dwc2_driver_probe() - Called when the DWC_otg core is bound to the DWC_otg
  * driver
  *
@@ -395,6 +412,8 @@ static int dwc2_driver_probe(struct platform_device *dev)
        dev_dbg(&dev->dev, "mapped PA %08lx to VA %p\n",
                (unsigned long)res->start, hsotg->regs);
 
+       hsotg->needs_byte_swap = dwc2_check_core_endianness(hsotg);
+
        retval = dwc2_lowlevel_hw_init(hsotg);
        if (retval)
                return retval;
index 451012e..518ead1 100644 (file)
@@ -74,11 +74,16 @@ config USB_DWC3_PCI
        depends on USB_PCI && ACPI
        default USB_DWC3
        help
-         If you're using the DesignWare Core IP with a PCIe, please say
-         'Y' or 'M' here.
+         If you're using the DesignWare Core IP with a PCIe (but not HAPS
+         platform), please say 'Y' or 'M' here.
 
-         One such PCIe-based platform is Synopsys' PCIe HAPS model of
-         this IP.
+config USB_DWC3_HAPS
+       tristate "Synopsys PCIe-based HAPS Platforms"
+       depends on USB_PCI
+       default USB_DWC3
+       help
+         If you're using the DesignWare Core IP with a Synopsys PCIe HAPS
+         platform, please say 'Y' or 'M' here.
 
 config USB_DWC3_KEYSTONE
        tristate "Texas Instruments Keystone2 Platforms"
index 5c07d8f..6e3ef61 100644 (file)
@@ -45,6 +45,7 @@ endif
 obj-$(CONFIG_USB_DWC3_OMAP)            += dwc3-omap.o
 obj-$(CONFIG_USB_DWC3_EXYNOS)          += dwc3-exynos.o
 obj-$(CONFIG_USB_DWC3_PCI)             += dwc3-pci.o
+obj-$(CONFIG_USB_DWC3_HAPS)            += dwc3-haps.o
 obj-$(CONFIG_USB_DWC3_KEYSTONE)                += dwc3-keystone.o
 obj-$(CONFIG_USB_DWC3_OF_SIMPLE)       += dwc3-of-simple.o
 obj-$(CONFIG_USB_DWC3_ST)              += dwc3-st.o
index 1038075..88c80fc 100644 (file)
@@ -78,6 +78,14 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc)
                        mode = USB_DR_MODE_HOST;
                else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
                        mode = USB_DR_MODE_PERIPHERAL;
+
+               /*
+                * dwc_usb31 does not support OTG mode. If the controller
+                * supports DRD but the dr_mode is not specified or set to OTG,
+                * then set the mode to peripheral.
+                */
+               if (mode == USB_DR_MODE_OTG && dwc3_is_usb31(dwc))
+                       mode = USB_DR_MODE_PERIPHERAL;
        }
 
        if (mode != dwc->dr_mode) {
@@ -778,6 +786,98 @@ static void dwc3_core_setup_global_control(struct dwc3 *dwc)
 static int dwc3_core_get_phy(struct dwc3 *dwc);
 static int dwc3_core_ulpi_init(struct dwc3 *dwc);
 
+/* set global incr burst type configuration registers */
+static void dwc3_set_incr_burst_type(struct dwc3 *dwc)
+{
+       struct device *dev = dwc->dev;
+       /* incrx_mode : for INCR burst type. */
+       bool incrx_mode;
+       /* incrx_size : for size of INCRX burst. */
+       u32 incrx_size;
+       u32 *vals;
+       u32 cfg;
+       int ntype;
+       int ret;
+       int i;
+
+       cfg = dwc3_readl(dwc->regs, DWC3_GSBUSCFG0);
+
+       /*
+        * Handle property "snps,incr-burst-type-adjustment".
+        * Get the number of value from this property:
+        * result <= 0, means this property is not supported.
+        * result = 1, means INCRx burst mode supported.
+        * result > 1, means undefined length burst mode supported.
+        */
+       ntype = device_property_read_u32_array(dev,
+                       "snps,incr-burst-type-adjustment", NULL, 0);
+       if (ntype <= 0)
+               return;
+
+       vals = kcalloc(ntype, sizeof(u32), GFP_KERNEL);
+       if (!vals) {
+               dev_err(dev, "Error to get memory\n");
+               return;
+       }
+
+       /* Get INCR burst type, and parse it */
+       ret = device_property_read_u32_array(dev,
+                       "snps,incr-burst-type-adjustment", vals, ntype);
+       if (ret) {
+               dev_err(dev, "Error to get property\n");
+               return;
+       }
+
+       incrx_size = *vals;
+
+       if (ntype > 1) {
+               /* INCRX (undefined length) burst mode */
+               incrx_mode = INCRX_UNDEF_LENGTH_BURST_MODE;
+               for (i = 1; i < ntype; i++) {
+                       if (vals[i] > incrx_size)
+                               incrx_size = vals[i];
+               }
+       } else {
+               /* INCRX burst mode */
+               incrx_mode = INCRX_BURST_MODE;
+       }
+
+       /* Enable Undefined Length INCR Burst and Enable INCRx Burst */
+       cfg &= ~DWC3_GSBUSCFG0_INCRBRST_MASK;
+       if (incrx_mode)
+               cfg |= DWC3_GSBUSCFG0_INCRBRSTENA;
+       switch (incrx_size) {
+       case 256:
+               cfg |= DWC3_GSBUSCFG0_INCR256BRSTENA;
+               break;
+       case 128:
+               cfg |= DWC3_GSBUSCFG0_INCR128BRSTENA;
+               break;
+       case 64:
+               cfg |= DWC3_GSBUSCFG0_INCR64BRSTENA;
+               break;
+       case 32:
+               cfg |= DWC3_GSBUSCFG0_INCR32BRSTENA;
+               break;
+       case 16:
+               cfg |= DWC3_GSBUSCFG0_INCR16BRSTENA;
+               break;
+       case 8:
+               cfg |= DWC3_GSBUSCFG0_INCR8BRSTENA;
+               break;
+       case 4:
+               cfg |= DWC3_GSBUSCFG0_INCR4BRSTENA;
+               break;
+       case 1:
+               break;
+       default:
+               dev_err(dev, "Invalid property\n");
+               break;
+       }
+
+       dwc3_writel(dwc->regs, DWC3_GSBUSCFG0, cfg);
+}
+
 /**
  * dwc3_core_init - Low-level initialization of DWC3 Core
  * @dwc: Pointer to our controller context structure
@@ -840,6 +940,8 @@ static int dwc3_core_init(struct dwc3 *dwc)
        /* Adjust Frame Length */
        dwc3_frame_length_adjustment(dwc);
 
+       dwc3_set_incr_burst_type(dwc);
+
        usb_phy_set_suspend(dwc->usb2_phy, 0);
        usb_phy_set_suspend(dwc->usb3_phy, 0);
        ret = phy_power_on(dwc->usb2_generic_phy);
@@ -883,6 +985,22 @@ static int dwc3_core_init(struct dwc3 *dwc)
                dwc3_writel(dwc->regs, DWC3_GUCTL1, reg);
        }
 
+       if (dwc->dr_mode == USB_DR_MODE_HOST ||
+           dwc->dr_mode == USB_DR_MODE_OTG) {
+               reg = dwc3_readl(dwc->regs, DWC3_GUCTL);
+
+               /*
+                * Enable Auto retry Feature to make the controller operating in
+                * Host mode on seeing transaction errors(CRC errors or internal
+                * overrun scenerios) on IN transfers to reply to the device
+                * with a non-terminating retry ACK (i.e, an ACK transcation
+                * packet with Retry=1 & Nump != 0)
+                */
+               reg |= DWC3_GUCTL_HSTINAUTORETRY;
+
+               dwc3_writel(dwc->regs, DWC3_GUCTL, reg);
+       }
+
        /*
         * Must config both number of packets and max burst settings to enable
         * RX and/or TX threshold.
index 285ce0e..5bfb625 100644 (file)
 
 /* Bit fields */
 
+/* Global SoC Bus Configuration INCRx Register 0 */
+#define DWC3_GSBUSCFG0_INCR256BRSTENA  (1 << 7) /* INCR256 burst */
+#define DWC3_GSBUSCFG0_INCR128BRSTENA  (1 << 6) /* INCR128 burst */
+#define DWC3_GSBUSCFG0_INCR64BRSTENA   (1 << 5) /* INCR64 burst */
+#define DWC3_GSBUSCFG0_INCR32BRSTENA   (1 << 4) /* INCR32 burst */
+#define DWC3_GSBUSCFG0_INCR16BRSTENA   (1 << 3) /* INCR16 burst */
+#define DWC3_GSBUSCFG0_INCR8BRSTENA    (1 << 2) /* INCR8 burst */
+#define DWC3_GSBUSCFG0_INCR4BRSTENA    (1 << 1) /* INCR4 burst */
+#define DWC3_GSBUSCFG0_INCRBRSTENA     (1 << 0) /* undefined length enable */
+#define DWC3_GSBUSCFG0_INCRBRST_MASK   0xff
+
 /* Global Debug Queue/FIFO Space Available Register */
 #define DWC3_GDBGFIFOSPACE_NUM(n)      ((n) & 0x1f)
 #define DWC3_GDBGFIFOSPACE_TYPE(n)     (((n) << 5) & 0x1e0)
 #define DWC3_GCTL_GBLHIBERNATIONEN     BIT(1)
 #define DWC3_GCTL_DSBLCLKGTNG          BIT(0)
 
+/* Global User Control Register */
+#define DWC3_GUCTL_HSTINAUTORETRY      BIT(14)
+
 /* Global User Control 1 Register */
 #define DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS     BIT(28)
 #define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW  BIT(24)
@@ -1157,6 +1171,9 @@ struct dwc3 {
        u16                     imod_interval;
 };
 
+#define INCRX_BURST_MODE 0
+#define INCRX_UNDEF_LENGTH_BURST_MODE 1
+
 #define work_to_dwc(w)         (container_of((w), struct dwc3, drd_work))
 
 /* -------------------------------------------------------------------------- */
diff --git a/drivers/usb/dwc3/dwc3-haps.c b/drivers/usb/dwc3/dwc3-haps.c
new file mode 100644 (file)
index 0000000..c9cc338
--- /dev/null
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * dwc3-haps.c - Synopsys HAPS PCI Specific glue layer
+ *
+ * Copyright (C) 2018 Synopsys, Inc.
+ *
+ * Authors: Thinh Nguyen <thinhn@synopsys.com>,
+ *          John Youn <johnyoun@synopsys.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+
+#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3                0xabcd
+#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI    0xabce
+#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31       0xabcf
+
+/**
+ * struct dwc3_haps - Driver private structure
+ * @dwc3: child dwc3 platform_device
+ * @pci: our link to PCI bus
+ */
+struct dwc3_haps {
+       struct platform_device *dwc3;
+       struct pci_dev *pci;
+};
+
+static const struct property_entry initial_properties[] = {
+       PROPERTY_ENTRY_BOOL("snps,usb3_lpm_capable"),
+       PROPERTY_ENTRY_BOOL("snps,has-lpm-erratum"),
+       PROPERTY_ENTRY_BOOL("snps,dis_enblslpm_quirk"),
+       PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
+       { },
+};
+
+static int dwc3_haps_probe(struct pci_dev *pci,
+                          const struct pci_device_id *id)
+{
+       struct dwc3_haps        *dwc;
+       struct device           *dev = &pci->dev;
+       struct resource         res[2];
+       int                     ret;
+
+       ret = pcim_enable_device(pci);
+       if (ret) {
+               dev_err(dev, "failed to enable pci device\n");
+               return -ENODEV;
+       }
+
+       pci_set_master(pci);
+
+       dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
+       if (!dwc)
+               return -ENOMEM;
+
+       dwc->dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
+       if (!dwc->dwc3)
+               return -ENOMEM;
+
+       memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
+
+       res[0].start    = pci_resource_start(pci, 0);
+       res[0].end      = pci_resource_end(pci, 0);
+       res[0].name     = "dwc_usb3";
+       res[0].flags    = IORESOURCE_MEM;
+
+       res[1].start    = pci->irq;
+       res[1].name     = "dwc_usb3";
+       res[1].flags    = IORESOURCE_IRQ;
+
+       ret = platform_device_add_resources(dwc->dwc3, res, ARRAY_SIZE(res));
+       if (ret) {
+               dev_err(dev, "couldn't add resources to dwc3 device\n");
+               goto err;
+       }
+
+       dwc->pci = pci;
+       dwc->dwc3->dev.parent = dev;
+
+       ret = platform_device_add_properties(dwc->dwc3, initial_properties);
+       if (ret)
+               goto err;
+
+       ret = platform_device_add(dwc->dwc3);
+       if (ret) {
+               dev_err(dev, "failed to register dwc3 device\n");
+               goto err;
+       }
+
+       pci_set_drvdata(pci, dwc);
+
+       return 0;
+err:
+       platform_device_put(dwc->dwc3);
+       return ret;
+}
+
+static void dwc3_haps_remove(struct pci_dev *pci)
+{
+       struct dwc3_haps *dwc = pci_get_drvdata(pci);
+
+       platform_device_unregister(dwc->dwc3);
+}
+
+static const struct pci_device_id dwc3_haps_id_table[] = {
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
+                          PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),
+       },
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
+                          PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI),
+       },
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
+                          PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31),
+       },
+       {  }    /* Terminating Entry */
+};
+MODULE_DEVICE_TABLE(pci, dwc3_haps_id_table);
+
+static struct pci_driver dwc3_haps_driver = {
+       .name           = "dwc3-haps",
+       .id_table       = dwc3_haps_id_table,
+       .probe          = dwc3_haps_probe,
+       .remove         = dwc3_haps_remove,
+};
+
+MODULE_AUTHOR("Thinh Nguyen <thinhn@synopsys.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Synopsys HAPS PCI Glue Layer");
+
+module_pci_driver(dwc3_haps_driver);
index dbeff5e..40bf9e0 100644 (file)
@@ -28,6 +28,7 @@ struct dwc3_of_simple {
        int                     num_clocks;
        struct reset_control    *resets;
        bool                    pulse_resets;
+       bool                    need_reset;
 };
 
 static int dwc3_of_simple_clk_init(struct dwc3_of_simple *simple, int count)
@@ -93,6 +94,13 @@ static int dwc3_of_simple_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, simple);
        simple->dev = dev;
 
+       /*
+        * Some controllers need to toggle the usb3-otg reset before trying to
+        * initialize the PHY, otherwise the PHY times out.
+        */
+       if (of_device_is_compatible(np, "rockchip,rk3399-dwc3"))
+               simple->need_reset = true;
+
        if (of_device_is_compatible(np, "amlogic,meson-axg-dwc3") ||
            of_device_is_compatible(np, "amlogic,meson-gxl-dwc3")) {
                shared_resets = true;
@@ -201,9 +209,30 @@ static int dwc3_of_simple_runtime_resume(struct device *dev)
 
        return 0;
 }
+
+static int dwc3_of_simple_suspend(struct device *dev)
+{
+       struct dwc3_of_simple *simple = dev_get_drvdata(dev);
+
+       if (simple->need_reset)
+               reset_control_assert(simple->resets);
+
+       return 0;
+}
+
+static int dwc3_of_simple_resume(struct device *dev)
+{
+       struct dwc3_of_simple *simple = dev_get_drvdata(dev);
+
+       if (simple->need_reset)
+               reset_control_deassert(simple->resets);
+
+       return 0;
+}
 #endif
 
 static const struct dev_pm_ops dwc3_of_simple_dev_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(dwc3_of_simple_suspend, dwc3_of_simple_resume)
        SET_RUNTIME_PM_OPS(dwc3_of_simple_runtime_suspend,
                        dwc3_of_simple_runtime_resume, NULL)
 };
index f57e7c9..5edd794 100644 (file)
 #include <linux/pm_runtime.h>
 #include <linux/platform_device.h>
 #include <linux/gpio/consumer.h>
+#include <linux/gpio/machine.h>
 #include <linux/acpi.h>
 #include <linux/delay.h>
 
-#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3                0xabcd
-#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI    0xabce
-#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31       0xabcf
 #define PCI_DEVICE_ID_INTEL_BYT                        0x0f37
 #define PCI_DEVICE_ID_INTEL_MRFLD              0x119e
 #define PCI_DEVICE_ID_INTEL_BSW                        0x22b7
 #define PCI_INTEL_BXT_STATE_D0         0
 #define PCI_INTEL_BXT_STATE_D3         3
 
+#define GP_RWBAR                       1
+#define GP_RWREG1                      0xa0
+#define GP_RWREG1_ULPI_REFCLK_DISABLE  (1 << 17)
+
 /**
  * struct dwc3_pci - Driver private structure
  * @dwc3: child dwc3 platform_device
  * @pci: our link to PCI bus
  * @guid: _DSM GUID
  * @has_dsm_for_pm: true for devices which need to run _DSM on runtime PM
+ * @wakeup_work: work for asynchronous resume
  */
 struct dwc3_pci {
        struct platform_device *dwc3;
@@ -67,52 +70,74 @@ static const struct acpi_gpio_mapping acpi_dwc3_byt_gpios[] = {
        { },
 };
 
-static int dwc3_pci_quirks(struct dwc3_pci *dwc)
+static struct gpiod_lookup_table platform_bytcr_gpios = {
+       .dev_id         = "0000:00:16.0",
+       .table          = {
+               GPIO_LOOKUP("INT33FC:00", 54, "reset", GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP("INT33FC:02", 14, "cs", GPIO_ACTIVE_HIGH),
+               {}
+       },
+};
+
+static int dwc3_byt_enable_ulpi_refclock(struct pci_dev *pci)
 {
-       struct platform_device          *dwc3 = dwc->dwc3;
-       struct pci_dev                  *pdev = dwc->pci;
+       void __iomem    *reg;
+       u32             value;
+
+       reg = pcim_iomap(pci, GP_RWBAR, 0);
+       if (IS_ERR(reg))
+               return PTR_ERR(reg);
+
+       value = readl(reg + GP_RWREG1);
+       if (!(value & GP_RWREG1_ULPI_REFCLK_DISABLE))
+               goto unmap; /* ULPI refclk already enabled */
+
+       value &= ~GP_RWREG1_ULPI_REFCLK_DISABLE;
+       writel(value, reg + GP_RWREG1);
+       /* This comes from the Intel Android x86 tree w/o any explanation */
+       msleep(100);
+unmap:
+       pcim_iounmap(pci, reg);
+       return 0;
+}
 
-       if (pdev->vendor == PCI_VENDOR_ID_AMD &&
-           pdev->device == PCI_DEVICE_ID_AMD_NL_USB) {
-               struct property_entry properties[] = {
-                       PROPERTY_ENTRY_BOOL("snps,has-lpm-erratum"),
-                       PROPERTY_ENTRY_U8("snps,lpm-nyet-threshold", 0xf),
-                       PROPERTY_ENTRY_BOOL("snps,u2exit_lfps_quirk"),
-                       PROPERTY_ENTRY_BOOL("snps,u2ss_inp3_quirk"),
-                       PROPERTY_ENTRY_BOOL("snps,req_p1p2p3_quirk"),
-                       PROPERTY_ENTRY_BOOL("snps,del_p1p2p3_quirk"),
-                       PROPERTY_ENTRY_BOOL("snps,del_phy_power_chg_quirk"),
-                       PROPERTY_ENTRY_BOOL("snps,lfps_filter_quirk"),
-                       PROPERTY_ENTRY_BOOL("snps,rx_detect_poll_quirk"),
-                       PROPERTY_ENTRY_BOOL("snps,tx_de_emphasis_quirk"),
-                       PROPERTY_ENTRY_U8("snps,tx_de_emphasis", 1),
-                       /*
-                        * FIXME these quirks should be removed when AMD NL
-                        * tapes out
-                        */
-                       PROPERTY_ENTRY_BOOL("snps,disable_scramble_quirk"),
-                       PROPERTY_ENTRY_BOOL("snps,dis_u3_susphy_quirk"),
-                       PROPERTY_ENTRY_BOOL("snps,dis_u2_susphy_quirk"),
-                       PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
-                       { },
-               };
-
-               return platform_device_add_properties(dwc3, properties);
-       }
+static const struct property_entry dwc3_pci_intel_properties[] = {
+       PROPERTY_ENTRY_STRING("dr_mode", "peripheral"),
+       PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
+       {}
+};
 
-       if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
-               int ret;
+static const struct property_entry dwc3_pci_mrfld_properties[] = {
+       PROPERTY_ENTRY_STRING("dr_mode", "otg"),
+       PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
+       {}
+};
 
-               struct property_entry properties[] = {
-                       PROPERTY_ENTRY_STRING("dr_mode", "peripheral"),
-                       PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
-                       { }
-               };
+static const struct property_entry dwc3_pci_amd_properties[] = {
+       PROPERTY_ENTRY_BOOL("snps,has-lpm-erratum"),
+       PROPERTY_ENTRY_U8("snps,lpm-nyet-threshold", 0xf),
+       PROPERTY_ENTRY_BOOL("snps,u2exit_lfps_quirk"),
+       PROPERTY_ENTRY_BOOL("snps,u2ss_inp3_quirk"),
+       PROPERTY_ENTRY_BOOL("snps,req_p1p2p3_quirk"),
+       PROPERTY_ENTRY_BOOL("snps,del_p1p2p3_quirk"),
+       PROPERTY_ENTRY_BOOL("snps,del_phy_power_chg_quirk"),
+       PROPERTY_ENTRY_BOOL("snps,lfps_filter_quirk"),
+       PROPERTY_ENTRY_BOOL("snps,rx_detect_poll_quirk"),
+       PROPERTY_ENTRY_BOOL("snps,tx_de_emphasis_quirk"),
+       PROPERTY_ENTRY_U8("snps,tx_de_emphasis", 1),
+       /* FIXME these quirks should be removed when AMD NL tapes out */
+       PROPERTY_ENTRY_BOOL("snps,disable_scramble_quirk"),
+       PROPERTY_ENTRY_BOOL("snps,dis_u3_susphy_quirk"),
+       PROPERTY_ENTRY_BOOL("snps,dis_u2_susphy_quirk"),
+       PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
+       {}
+};
 
-               ret = platform_device_add_properties(dwc3, properties);
-               if (ret < 0)
-                       return ret;
+static int dwc3_pci_quirks(struct dwc3_pci *dwc)
+{
+       struct pci_dev                  *pdev = dwc->pci;
 
+       if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
                if (pdev->device == PCI_DEVICE_ID_INTEL_BXT ||
                                pdev->device == PCI_DEVICE_ID_INTEL_BXT_M) {
                        guid_parse(PCI_INTEL_BXT_DSM_GUID, &dwc->guid);
@@ -121,6 +146,12 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc)
 
                if (pdev->device == PCI_DEVICE_ID_INTEL_BYT) {
                        struct gpio_desc *gpio;
+                       int ret;
+
+                       /* On BYT the FW does not always enable the refclock */
+                       ret = dwc3_byt_enable_ulpi_refclock(pdev);
+                       if (ret)
+                               return ret;
 
                        ret = devm_acpi_dev_add_driver_gpios(&pdev->dev,
                                        acpi_dwc3_byt_gpios);
@@ -128,44 +159,36 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc)
                                dev_dbg(&pdev->dev, "failed to add mapping table\n");
 
                        /*
+                        * A lot of BYT devices lack ACPI resource entries for
+                        * the GPIOs, add a fallback mapping to the reference
+                        * design GPIOs which all boards seem to use.
+                        */
+                       gpiod_add_lookup_table(&platform_bytcr_gpios);
+
+                       /*
                         * These GPIOs will turn on the USB2 PHY. Note that we have to
                         * put the gpio descriptors again here because the phy driver
                         * might want to grab them, too.
                         */
-                       gpio = gpiod_get_optional(&pdev->dev, "cs", GPIOD_OUT_LOW);
+                       gpio = devm_gpiod_get_optional(&pdev->dev, "cs",
+                                                      GPIOD_OUT_LOW);
                        if (IS_ERR(gpio))
                                return PTR_ERR(gpio);
 
                        gpiod_set_value_cansleep(gpio, 1);
-                       gpiod_put(gpio);
 
-                       gpio = gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW);
+                       gpio = devm_gpiod_get_optional(&pdev->dev, "reset",
+                                                      GPIOD_OUT_LOW);
                        if (IS_ERR(gpio))
                                return PTR_ERR(gpio);
 
                        if (gpio) {
                                gpiod_set_value_cansleep(gpio, 1);
-                               gpiod_put(gpio);
                                usleep_range(10000, 11000);
                        }
                }
        }
 
-       if (pdev->vendor == PCI_VENDOR_ID_SYNOPSYS &&
-           (pdev->device == PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 ||
-            pdev->device == PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI ||
-            pdev->device == PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31)) {
-               struct property_entry properties[] = {
-                       PROPERTY_ENTRY_BOOL("snps,usb3_lpm_capable"),
-                       PROPERTY_ENTRY_BOOL("snps,has-lpm-erratum"),
-                       PROPERTY_ENTRY_BOOL("snps,dis_enblslpm_quirk"),
-                       PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
-                       { },
-               };
-
-               return platform_device_add_properties(dwc3, properties);
-       }
-
        return 0;
 }
 
@@ -185,9 +208,9 @@ static void dwc3_pci_resume_work(struct work_struct *work)
 }
 #endif
 
-static int dwc3_pci_probe(struct pci_dev *pci,
-               const struct pci_device_id *id)
+static int dwc3_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
 {
+       struct property_entry *p = (struct property_entry *)id->driver_data;
        struct dwc3_pci         *dwc;
        struct resource         res[2];
        int                     ret;
@@ -230,6 +253,10 @@ static int dwc3_pci_probe(struct pci_dev *pci,
        dwc->dwc3->dev.parent = dev;
        ACPI_COMPANION_SET(&dwc->dwc3->dev, ACPI_COMPANION(dev));
 
+       ret = platform_device_add_properties(dwc->dwc3, p);
+       if (ret < 0)
+               return ret;
+
        ret = dwc3_pci_quirks(dwc);
        if (ret)
                goto err;
@@ -257,6 +284,7 @@ static void dwc3_pci_remove(struct pci_dev *pci)
 {
        struct dwc3_pci         *dwc = pci_get_drvdata(pci);
 
+       gpiod_remove_lookup_table(&platform_bytcr_gpios);
 #ifdef CONFIG_PM
        cancel_work_sync(&dwc->wakeup_work);
 #endif
@@ -266,32 +294,47 @@ static void dwc3_pci_remove(struct pci_dev *pci)
 }
 
 static const struct pci_device_id dwc3_pci_id_table[] = {
-       {
-               PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
-                               PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),
-       },
-       {
-               PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
-                               PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI),
-       },
-       {
-               PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
-                               PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31),
-       },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW), },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTLP), },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTH), },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT), },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT_M), },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_APL), },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KBP), },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GLK), },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CNPLP), },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CNPH), },
-       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICLLP), },
-       { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB), },
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BSW),
+         (kernel_ulong_t) &dwc3_pci_intel_properties },
+
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BYT),
+         (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MRFLD),
+         (kernel_ulong_t) &dwc3_pci_mrfld_properties, },
+
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SPTLP),
+         (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SPTH),
+         (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BXT),
+         (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BXT_M),
+         (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_APL),
+         (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_KBP),
+         (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_GLK),
+         (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPLP),
+         (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPH),
+         (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+       { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICLLP),
+         (kernel_ulong_t) &dwc3_pci_intel_properties, },
+
+       { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_NL_USB),
+         (kernel_ulong_t) &dwc3_pci_amd_properties, },
        {  }    /* Terminating Entry */
 };
 MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
index 69bf137..032ea7d 100644 (file)
@@ -1121,7 +1121,7 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
                                req->request.short_not_ok,
                                req->request.no_interrupt);
        } else if (req->request.zero && req->request.length &&
-                  (IS_ALIGNED(req->request.length,dep->endpoint.maxpacket))) {
+                  (IS_ALIGNED(req->request.length, maxp))) {
                struct dwc3     *dwc = dep->dwc;
                struct dwc3_trb *trb;
 
index db610c5..2aacd1a 100644 (file)
@@ -25,7 +25,7 @@ struct dwc3;
 #define DWC3_DEPCFG_XFER_IN_PROGRESS_EN        BIT(9)
 #define DWC3_DEPCFG_XFER_NOT_READY_EN  BIT(10)
 #define DWC3_DEPCFG_FIFO_ERROR_EN      BIT(11)
-#define DWC3_DEPCFG_STREAM_EVENT_EN    BIT(12)
+#define DWC3_DEPCFG_STREAM_EVENT_EN    BIT(13)
 #define DWC3_DEPCFG_BINTERVAL_M1(n)    (((n) & 0xff) << 16)
 #define DWC3_DEPCFG_STREAM_CAPABLE     BIT(24)
 #define DWC3_DEPCFG_EP_NUMBER(n)       (((n) & 0x1f) << 25)
index efba66c..0251299 100644 (file)
@@ -1217,8 +1217,8 @@ static void purge_configs_funcs(struct gadget_info *gi)
                        list_move_tail(&f->list, &cfg->func_list);
                        if (f->unbind) {
                                dev_dbg(&gi->cdev.gadget->dev,
-                                        "unbind function '%s'/%p\n",
-                                        f->name, f);
+                                       "unbind function '%s'/%p\n",
+                                       f->name, f);
                                f->unbind(c, f);
                        }
                }
index acecd13..ca8a4b5 100644 (file)
 #include <linux/fcntl.h>
 #include <linux/file.h>
 #include <linux/fs.h>
-#include <linux/kref.h>
 #include <linux/kthread.h>
 #include <linux/sched/signal.h>
 #include <linux/limits.h>
@@ -312,8 +311,6 @@ struct fsg_common {
        void                    *private_data;
 
        char inquiry_string[INQUIRY_STRING_LEN];
-
-       struct kref             ref;
 };
 
 struct fsg_dev {
@@ -2551,25 +2548,11 @@ static DEVICE_ATTR(file, 0, file_show, file_store);
 
 /****************************** FSG COMMON ******************************/
 
-static void fsg_common_release(struct kref *ref);
-
 static void fsg_lun_release(struct device *dev)
 {
        /* Nothing needs to be done */
 }
 
-void fsg_common_get(struct fsg_common *common)
-{
-       kref_get(&common->ref);
-}
-EXPORT_SYMBOL_GPL(fsg_common_get);
-
-void fsg_common_put(struct fsg_common *common)
-{
-       kref_put(&common->ref, fsg_common_release);
-}
-EXPORT_SYMBOL_GPL(fsg_common_put);
-
 static struct fsg_common *fsg_common_setup(struct fsg_common *common)
 {
        if (!common) {
@@ -2582,7 +2565,6 @@ static struct fsg_common *fsg_common_setup(struct fsg_common *common)
        }
        init_rwsem(&common->filesem);
        spin_lock_init(&common->lock);
-       kref_init(&common->ref);
        init_completion(&common->thread_notifier);
        init_waitqueue_head(&common->io_wait);
        init_waitqueue_head(&common->fsg_wait);
@@ -2870,9 +2852,8 @@ void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn,
 }
 EXPORT_SYMBOL_GPL(fsg_common_set_inquiry_string);
 
-static void fsg_common_release(struct kref *ref)
+static void fsg_common_release(struct fsg_common *common)
 {
-       struct fsg_common *common = container_of(ref, struct fsg_common, ref);
        int i;
 
        /* If the thread isn't already dead, tell it to exit now */
@@ -3308,7 +3289,9 @@ static ssize_t fsg_opts_num_buffers_store(struct config_item *item,
        if (ret)
                goto end;
 
-       fsg_common_set_num_buffers(opts->common, num);
+       ret = fsg_common_set_num_buffers(opts->common, num);
+       if (ret)
+               goto end;
        ret = len;
 
 end:
@@ -3344,7 +3327,7 @@ static void fsg_free_inst(struct usb_function_instance *fi)
        struct fsg_opts *opts;
 
        opts = fsg_opts_from_func_inst(fi);
-       fsg_common_put(opts->common);
+       fsg_common_release(opts->common);
        kfree(opts);
 }
 
@@ -3368,7 +3351,7 @@ static struct usb_function_instance *fsg_alloc_inst(void)
        rc = fsg_common_set_num_buffers(opts->common,
                                        CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS);
        if (rc)
-               goto release_opts;
+               goto release_common;
 
        pr_info(FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n");
 
@@ -3391,6 +3374,8 @@ static struct usb_function_instance *fsg_alloc_inst(void)
 
 release_buffers:
        fsg_common_free_buffers(opts->common);
+release_common:
+       kfree(opts->common);
 release_opts:
        kfree(opts);
        return ERR_PTR(rc);
index 58857fc..3b8c4ce 100644 (file)
@@ -115,10 +115,6 @@ fsg_opts_from_func_inst(const struct usb_function_instance *fi)
        return container_of(fi, struct fsg_opts, func_inst);
 }
 
-void fsg_common_get(struct fsg_common *common);
-
-void fsg_common_put(struct fsg_common *common);
-
 void fsg_common_set_sysfs(struct fsg_common *common, bool sysfs);
 
 int fsg_common_set_num_buffers(struct fsg_common *common, unsigned int n);
index 439eba6..d8ce786 100644 (file)
@@ -6,16 +6,17 @@
  *         Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  */
 
-#include <linux/kernel.h>
-#include <linux/module.h>
 #include <linux/device.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
+#include <linux/kernel.h>
 #include <linux/list.h>
+#include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/string.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
+#include <linux/usb/g_uvc.h>
 #include <linux/usb/video.h>
 #include <linux/vmalloc.h>
 #include <linux/wait.h>
@@ -30,6 +31,8 @@
 #include "uvc_video.h"
 
 unsigned int uvc_gadget_trace_param;
+module_param_named(trace, uvc_gadget_trace_param, uint, 0644);
+MODULE_PARM_DESC(trace, "Trace level bitmask");
 
 /* --------------------------------------------------------------------------
  * Function descriptors
@@ -410,10 +413,21 @@ uvc_function_disconnect(struct uvc_device *uvc)
  * USB probe and disconnect
  */
 
+static ssize_t function_name_show(struct device *dev,
+                                 struct device_attribute *attr, char *buf)
+{
+       struct uvc_device *uvc = dev_get_drvdata(dev);
+
+       return sprintf(buf, "%s\n", uvc->func.fi->group.cg_item.ci_name);
+}
+
+static DEVICE_ATTR_RO(function_name);
+
 static int
 uvc_register_video(struct uvc_device *uvc)
 {
        struct usb_composite_dev *cdev = uvc->func.config->cdev;
+       int ret;
 
        /* TODO reference counting. */
        uvc->vdev.v4l2_dev = &uvc->v4l2_dev;
@@ -426,7 +440,17 @@ uvc_register_video(struct uvc_device *uvc)
 
        video_set_drvdata(&uvc->vdev, uvc);
 
-       return video_register_device(&uvc->vdev, VFL_TYPE_GRABBER, -1);
+       ret = video_register_device(&uvc->vdev, VFL_TYPE_GRABBER, -1);
+       if (ret < 0)
+               return ret;
+
+       ret = device_create_file(&uvc->vdev.dev, &dev_attr_function_name);
+       if (ret < 0) {
+               video_unregister_device(&uvc->vdev);
+               return ret;
+       }
+
+       return 0;
 }
 
 #define UVC_COPY_DESCRIPTOR(mem, dst, desc) \
@@ -864,6 +888,7 @@ static void uvc_unbind(struct usb_configuration *c, struct usb_function *f)
 
        INFO(cdev, "%s\n", __func__);
 
+       device_remove_file(&uvc->vdev.dev, &dev_attr_function_name);
        video_unregister_device(&uvc->vdev);
        v4l2_device_unregister(&uvc->v4l2_dev);
 
index 81defe4..a81a177 100644 (file)
@@ -9,10 +9,7 @@
 #ifndef _F_UVC_H_
 #define _F_UVC_H_
 
-#include <linux/usb/composite.h>
-#include <linux/usb/video.h>
-
-#include "uvc.h"
+struct uvc_device;
 
 void uvc_function_setup_continue(struct uvc_device *uvc);
 
@@ -21,4 +18,3 @@ void uvc_function_connect(struct uvc_device *uvc);
 void uvc_function_disconnect(struct uvc_device *uvc);
 
 #endif /* _F_UVC_H_ */
-
index d00d3de..2ed292e 100644 (file)
@@ -13,6 +13,7 @@
 #ifndef U_UVC_H
 #define U_UVC_H
 
+#include <linux/mutex.h>
 #include <linux/usb/composite.h>
 #include <linux/usb/video.h>
 
@@ -20,7 +21,6 @@
 
 struct f_uvc_opts {
        struct usb_function_instance                    func_inst;
-       unsigned int                                    uvc_gadget_trace_param;
        unsigned int                                    streaming_interval;
        unsigned int                                    streaming_maxpacket;
        unsigned int                                    streaming_maxburst;
@@ -80,7 +80,4 @@ struct f_uvc_opts {
        int                             refcnt;
 };
 
-void uvc_set_trace_param(unsigned int trace);
-
 #endif /* U_UVC_H */
-
index a64e07e..93cf78b 100644 (file)
@@ -9,52 +9,26 @@
 #ifndef _UVC_GADGET_H_
 #define _UVC_GADGET_H_
 
-#include <linux/ioctl.h>
-#include <linux/types.h>
-#include <linux/usb/ch9.h>
-
-#define UVC_EVENT_FIRST                        (V4L2_EVENT_PRIVATE_START + 0)
-#define UVC_EVENT_CONNECT              (V4L2_EVENT_PRIVATE_START + 0)
-#define UVC_EVENT_DISCONNECT           (V4L2_EVENT_PRIVATE_START + 1)
-#define UVC_EVENT_STREAMON             (V4L2_EVENT_PRIVATE_START + 2)
-#define UVC_EVENT_STREAMOFF            (V4L2_EVENT_PRIVATE_START + 3)
-#define UVC_EVENT_SETUP                        (V4L2_EVENT_PRIVATE_START + 4)
-#define UVC_EVENT_DATA                 (V4L2_EVENT_PRIVATE_START + 5)
-#define UVC_EVENT_LAST                 (V4L2_EVENT_PRIVATE_START + 5)
-
-struct uvc_request_data {
-       __s32 length;
-       __u8 data[60];
-};
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/usb/composite.h>
+#include <linux/videodev2.h>
 
-struct uvc_event {
-       union {
-               enum usb_device_speed speed;
-               struct usb_ctrlrequest req;
-               struct uvc_request_data data;
-       };
-};
+#include <media/v4l2-device.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-fh.h>
 
-#define UVCIOC_SEND_RESPONSE           _IOW('U', 1, struct uvc_request_data)
+#include "uvc_queue.h"
 
-#define UVC_INTF_CONTROL               0
-#define UVC_INTF_STREAMING             1
+struct usb_ep;
+struct usb_request;
+struct uvc_descriptor_header;
 
 /* ------------------------------------------------------------------------
  * Debugging, printing and logging
  */
 
-#ifdef __KERNEL__
-
-#include <linux/usb.h> /* For usb_endpoint_* */
-#include <linux/usb/composite.h>
-#include <linux/usb/gadget.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-fh.h>
-#include <media/v4l2-device.h>
-
-#include "uvc_queue.h"
-
 #define UVC_TRACE_PROBE                                (1 << 0)
 #define UVC_TRACE_DESCR                                (1 << 1)
 #define UVC_TRACE_CONTROL                      (1 << 2)
@@ -184,7 +158,4 @@ extern void uvc_endpoint_stream(struct uvc_device *dev);
 extern void uvc_function_connect(struct uvc_device *uvc);
 extern void uvc_function_disconnect(struct uvc_device *uvc);
 
-#endif /* __KERNEL__ */
-
 #endif /* _UVC_GADGET_H_ */
-
index c9b8cc4..b51f0d2 100644 (file)
@@ -31,7 +31,11 @@ static struct configfs_attribute prefix##attr_##cname = { \
        .show           = prefix##cname##_show,                         \
 }
 
-static inline struct f_uvc_opts *to_f_uvc_opts(struct config_item *item);
+static inline struct f_uvc_opts *to_f_uvc_opts(struct config_item *item)
+{
+       return container_of(to_config_group(item), struct f_uvc_opts,
+                           func_inst.group);
+}
 
 /* control/header/<NAME> */
 DECLARE_UVC_HEADER_DESCRIPTOR(1);
@@ -2105,12 +2109,6 @@ static const struct config_item_type uvcg_streaming_grp_type = {
        .ct_owner = THIS_MODULE,
 };
 
-static inline struct f_uvc_opts *to_f_uvc_opts(struct config_item *item)
-{
-       return container_of(to_config_group(item), struct f_uvc_opts,
-                           func_inst.group);
-}
-
 static void uvc_attr_release(struct config_item *item)
 {
        struct f_uvc_opts *opts = to_f_uvc_opts(item);
index f9f65b5..2f0fff7 100644 (file)
@@ -2,13 +2,15 @@
 #ifndef _UVC_QUEUE_H_
 #define _UVC_QUEUE_H_
 
-#ifdef __KERNEL__
-
-#include <linux/kernel.h>
+#include <linux/list.h>
 #include <linux/poll.h>
-#include <linux/videodev2.h>
+#include <linux/spinlock.h>
+
 #include <media/videobuf2-v4l2.h>
 
+struct file;
+struct mutex;
+
 /* Maximum frame size in bytes, for sanity checking. */
 #define UVC_MAX_FRAME_SIZE     (16*1024*1024)
 /* Maximum number of video buffers. */
@@ -91,7 +93,5 @@ struct uvc_buffer *uvcg_queue_next_buffer(struct uvc_video_queue *queue,
 
 struct uvc_buffer *uvcg_queue_head(struct uvc_video_queue *queue);
 
-#endif /* __KERNEL__ */
-
 #endif /* _UVC_QUEUE_H_ */
 
index 9a90196..7f1ca3b 100644 (file)
@@ -6,10 +6,11 @@
  *         Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  */
 
-#include <linux/kernel.h>
 #include <linux/device.h>
 #include <linux/errno.h>
+#include <linux/kernel.h>
 #include <linux/list.h>
+#include <linux/usb/g_uvc.h>
 #include <linux/videodev2.h>
 #include <linux/vmalloc.h>
 #include <linux/wait.h>
index 6c20aa7..7d77122 100644 (file)
@@ -12,6 +12,8 @@
 #ifndef __UVC_VIDEO_H__
 #define __UVC_VIDEO_H__
 
+struct uvc_video;
+
 int uvcg_video_pump(struct uvc_video *video);
 
 int uvcg_video_enable(struct uvc_video *video, int enable);
index 682bf99..4087022 100644 (file)
@@ -41,7 +41,7 @@ static struct usb_device_descriptor usbg_device_desc = {
 #define USB_G_STR_CONFIG USB_GADGET_FIRST_AVAIL_IDX
 
 static struct usb_string       usbg_us_strings[] = {
-       [USB_GADGET_MANUFACTURER_IDX].s = "Target Manufactor",
+       [USB_GADGET_MANUFACTURER_IDX].s = "Target Manufacturer",
        [USB_GADGET_PRODUCT_IDX].s      = "Target Product",
        [USB_GADGET_SERIAL_IDX].s       = "000000000001",
        [USB_G_STR_CONFIG].s            = "default config",
index 6b86568..a9f8eb8 100644 (file)
@@ -30,9 +30,6 @@ static unsigned int streaming_maxburst;
 module_param(streaming_maxburst, uint, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(streaming_maxburst, "0 - 15 (ss only)");
 
-static unsigned int trace;
-module_param(trace, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(trace, "Trace level bitmask");
 /* --------------------------------------------------------------------------
  * Device descriptor
  */
@@ -379,7 +376,6 @@ webcam_bind(struct usb_composite_dev *cdev)
        uvc_opts->streaming_interval = streaming_interval;
        uvc_opts->streaming_maxpacket = streaming_maxpacket;
        uvc_opts->streaming_maxburst = streaming_maxburst;
-       uvc_set_trace_param(trace);
 
        uvc_opts->fs_control = uvc_fs_control_cls;
        uvc_opts->ss_control = uvc_ss_control_cls;
index 1df4ded..0a16cbd 100644 (file)
@@ -193,6 +193,7 @@ config USB_RENESAS_USB3
        tristate 'Renesas USB3.0 Peripheral controller'
        depends on ARCH_RENESAS || COMPILE_TEST
        depends on EXTCON
+       select USB_ROLE_SWITCH
        help
           Renesas USB3.0 Peripheral controller is a USB peripheral controller
           that supports super, high, and full speed USB 3.0 data transfers.
index cab5e4f..af88b48 100644 (file)
@@ -87,6 +87,8 @@ EXPORT_SYMBOL_GPL(usb_ep_set_maxpacket_limit);
  * configurable, with more generic names like "ep-a".  (remember that for
  * USB, "in" means "towards the USB master".)
  *
+ * This routine must be called in process context.
+ *
  * returns zero, or a negative error code.
  */
 int usb_ep_enable(struct usb_ep *ep)
@@ -119,6 +121,8 @@ EXPORT_SYMBOL_GPL(usb_ep_enable);
  * gadget drivers must call usb_ep_enable() again before queueing
  * requests to the endpoint.
  *
+ * This routine must be called in process context.
+ *
  * returns zero, or a negative error code.
  */
 int usb_ep_disable(struct usb_ep *ep)
@@ -241,6 +245,8 @@ EXPORT_SYMBOL_GPL(usb_ep_free_request);
  * Note that @req's ->complete() callback must never be called from
  * within usb_ep_queue() as that can create deadlock situations.
  *
+ * This routine may be called in interrupt context.
+ *
  * Returns zero, or a negative error code.  Endpoints that are not enabled
  * report errors; errors will also be
  * reported when the usb peripheral is disconnected.
@@ -284,6 +290,8 @@ EXPORT_SYMBOL_GPL(usb_ep_queue);
  * at the head of the queue) except as part of disconnecting from usb. Such
  * restrictions prevent drivers from supporting configuration changes,
  * even to configuration zero (a "chapter 9" requirement).
+ *
+ * This routine may be called in interrupt context.
  */
 int usb_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
 {
@@ -311,6 +319,8 @@ EXPORT_SYMBOL_GPL(usb_ep_dequeue);
  * current altsetting, see usb_ep_clear_halt().  When switching altsettings,
  * it's simplest to use usb_ep_enable() or usb_ep_disable() for the endpoints.
  *
+ * This routine may be called in interrupt context.
+ *
  * Returns zero, or a negative error code.  On success, this call sets
  * underlying hardware state that blocks data transfers.
  * Attempts to halt IN endpoints will fail (returning -EAGAIN) if any
@@ -336,6 +346,8 @@ EXPORT_SYMBOL_GPL(usb_ep_set_halt);
  * for endpoints that aren't reconfigured, after clearing any other state
  * in the endpoint's i/o queue.
  *
+ * This routine may be called in interrupt context.
+ *
  * Returns zero, or a negative error code.  On success, this call clears
  * the underlying hardware state reflecting endpoint halt and data toggle.
  * Note that some hardware can't support this request (like pxa2xx_udc),
@@ -360,6 +372,8 @@ EXPORT_SYMBOL_GPL(usb_ep_clear_halt);
  * requests. If the gadget driver clears the halt status, it will
  * automatically unwedge the endpoint.
  *
+ * This routine may be called in interrupt context.
+ *
  * Returns zero on success, else negative errno.
  */
 int usb_ep_set_wedge(struct usb_ep *ep)
@@ -388,6 +402,8 @@ EXPORT_SYMBOL_GPL(usb_ep_set_wedge);
  * written OUT to it by the host.  Drivers that need precise handling for
  * fault reporting or recovery may need to use this call.
  *
+ * This routine may be called in interrupt context.
+ *
  * This returns the number of such bytes in the fifo, or a negative
  * errno if the endpoint doesn't use a FIFO or doesn't support such
  * precise handling.
@@ -415,6 +431,8 @@ EXPORT_SYMBOL_GPL(usb_ep_fifo_status);
  * an endpoint fifo after abnormal transaction terminations.  The call
  * must never be used except when endpoint is not being used for any
  * protocol translation.
+ *
+ * This routine may be called in interrupt context.
  */
 void usb_ep_fifo_flush(struct usb_ep *ep)
 {
index 7cf98c7..1f879b3 100644 (file)
@@ -23,6 +23,8 @@
 #include <linux/uaccess.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
+#include <linux/usb/of.h>
+#include <linux/usb/role.h>
 
 /* register definitions */
 #define USB3_AXI_INT_STA       0x008
@@ -335,6 +337,11 @@ struct renesas_usb3 {
        struct phy *phy;
        struct dentry *dentry;
 
+       struct usb_role_switch *role_sw;
+       struct device *host_dev;
+       struct work_struct role_work;
+       enum usb_role role;
+
        struct renesas_usb3_ep *usb3_ep;
        int num_usb3_eps;
 
@@ -651,6 +658,14 @@ static void usb3_check_vbus(struct renesas_usb3 *usb3)
        }
 }
 
+static void renesas_usb3_role_work(struct work_struct *work)
+{
+       struct renesas_usb3 *usb3 =
+                       container_of(work, struct renesas_usb3, role_work);
+
+       usb_role_switch_set_role(usb3->role_sw, usb3->role);
+}
+
 static void usb3_set_mode(struct renesas_usb3 *usb3, bool host)
 {
        if (host)
@@ -659,6 +674,16 @@ static void usb3_set_mode(struct renesas_usb3 *usb3, bool host)
                usb3_set_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON);
 }
 
+static void usb3_set_mode_by_role_sw(struct renesas_usb3 *usb3, bool host)
+{
+       if (usb3->role_sw) {
+               usb3->role = host ? USB_ROLE_HOST : USB_ROLE_DEVICE;
+               schedule_work(&usb3->role_work);
+       } else {
+               usb3_set_mode(usb3, host);
+       }
+}
+
 static void usb3_vbus_out(struct renesas_usb3 *usb3, bool enable)
 {
        if (enable)
@@ -672,7 +697,7 @@ static void usb3_mode_config(struct renesas_usb3 *usb3, bool host, bool a_dev)
        unsigned long flags;
 
        spin_lock_irqsave(&usb3->lock, flags);
-       usb3_set_mode(usb3, host);
+       usb3_set_mode_by_role_sw(usb3, host);
        usb3_vbus_out(usb3, a_dev);
        /* for A-Peripheral or forced B-device mode */
        if ((!host && a_dev) ||
@@ -2302,6 +2327,41 @@ static const struct usb_gadget_ops renesas_usb3_gadget_ops = {
        .set_selfpowered        = renesas_usb3_set_selfpowered,
 };
 
+static enum usb_role renesas_usb3_role_switch_get(struct device *dev)
+{
+       struct renesas_usb3 *usb3 = dev_get_drvdata(dev);
+       enum usb_role cur_role;
+
+       pm_runtime_get_sync(dev);
+       cur_role = usb3_is_host(usb3) ? USB_ROLE_HOST : USB_ROLE_DEVICE;
+       pm_runtime_put(dev);
+
+       return cur_role;
+}
+
+static int renesas_usb3_role_switch_set(struct device *dev,
+                                       enum usb_role role)
+{
+       struct renesas_usb3 *usb3 = dev_get_drvdata(dev);
+       struct device *host = usb3->host_dev;
+       enum usb_role cur_role = renesas_usb3_role_switch_get(dev);
+
+       pm_runtime_get_sync(dev);
+       if (cur_role == USB_ROLE_HOST && role == USB_ROLE_DEVICE) {
+               device_release_driver(host);
+               usb3_set_mode(usb3, false);
+       } else if (cur_role == USB_ROLE_DEVICE && role == USB_ROLE_HOST) {
+               /* Must set the mode before device_attach of the host */
+               usb3_set_mode(usb3, true);
+               /* This device_attach() might sleep */
+               if (device_attach(host) < 0)
+                       dev_err(dev, "device_attach(host) failed\n");
+       }
+       pm_runtime_put(dev);
+
+       return 0;
+}
+
 static ssize_t role_store(struct device *dev, struct device_attribute *attr,
                          const char *buf, size_t count)
 {
@@ -2405,6 +2465,8 @@ static int renesas_usb3_remove(struct platform_device *pdev)
        debugfs_remove_recursive(usb3->dentry);
        device_remove_file(&pdev->dev, &dev_attr_role);
 
+       usb_role_switch_unregister(usb3->role_sw);
+
        usb_del_gadget_udc(&usb3->gadget);
        renesas_usb3_dma_free_prd(usb3, &pdev->dev);
 
@@ -2562,6 +2624,12 @@ static const unsigned int renesas_usb3_cable[] = {
        EXTCON_NONE,
 };
 
+static const struct usb_role_switch_desc renesas_usb3_role_switch_desc = {
+       .set = renesas_usb3_role_switch_set,
+       .get = renesas_usb3_role_switch_get,
+       .allow_userspace_control = true,
+};
+
 static int renesas_usb3_probe(struct platform_device *pdev)
 {
        struct renesas_usb3 *usb3;
@@ -2647,6 +2715,20 @@ static int renesas_usb3_probe(struct platform_device *pdev)
        if (ret < 0)
                goto err_dev_create;
 
+       INIT_WORK(&usb3->role_work, renesas_usb3_role_work);
+       usb3->role_sw = usb_role_switch_register(&pdev->dev,
+                                       &renesas_usb3_role_switch_desc);
+       if (!IS_ERR(usb3->role_sw)) {
+               usb3->host_dev = usb_of_get_companion_dev(&pdev->dev);
+               if (!usb3->host_dev) {
+                       /* If not found, this driver will not use a role sw */
+                       usb_role_switch_unregister(usb3->role_sw);
+                       usb3->role_sw = NULL;
+               }
+       } else {
+               usb3->role_sw = NULL;
+       }
+
        usb3->workaround_for_vbus = priv->workaround_for_vbus;
 
        renesas_usb3_debugfs_init(usb3, &pdev->dev);
index 6e64d3a..1a4ea98 100644 (file)
@@ -192,6 +192,14 @@ config USB_EHCI_MXC
        ---help---
          Variation of ARC USB block used in some Freescale chips.
 
+config USB_EHCI_HCD_NPCM7XX
+       tristate "Support for Nuvoton NPCM7XX on-chip EHCI USB controller"
+       depends on (USB_EHCI_HCD && ARCH_NPCM7XX) || COMPILE_TEST
+       default y if (USB_EHCI_HCD && ARCH_NPCM7XX)
+       help
+         Enables support for the on-chip EHCI controller on
+         Nuvoton NPCM7XX chips.
+
 config USB_EHCI_HCD_OMAP
        tristate "EHCI support for OMAP3 and later chips"
        depends on ARCH_OMAP
index 9b669c9..e623526 100644 (file)
@@ -43,6 +43,7 @@ obj-$(CONFIG_USB_EHCI_HCD)    += ehci-hcd.o
 obj-$(CONFIG_USB_EHCI_PCI)     += ehci-pci.o
 obj-$(CONFIG_USB_EHCI_HCD_PLATFORM)    += ehci-platform.o
 obj-$(CONFIG_USB_EHCI_MXC)     += ehci-mxc.o
+obj-$(CONFIG_USB_EHCI_HCD_NPCM7XX)     += ehci-npcm7xx.o
 obj-$(CONFIG_USB_EHCI_HCD_OMAP)        += ehci-omap.o
 obj-$(CONFIG_USB_EHCI_HCD_ORION)       += ehci-orion.o
 obj-$(CONFIG_USB_EHCI_HCD_SPEAR)       += ehci-spear.o
index 89c47ae..8608ac5 100644 (file)
@@ -1226,6 +1226,7 @@ static const struct hc_driver ehci_hc_driver = {
        .bus_resume =           ehci_bus_resume,
        .relinquish_port =      ehci_relinquish_port,
        .port_handed_over =     ehci_port_handed_over,
+       .get_resuming_ports =   ehci_get_resuming_ports,
 
        /*
         * device support
index d7641cb..ce0eaf7 100644 (file)
@@ -512,10 +512,18 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
        return -ESHUTDOWN;
 }
 
+static unsigned long ehci_get_resuming_ports(struct usb_hcd *hcd)
+{
+       struct ehci_hcd         *ehci = hcd_to_ehci(hcd);
+
+       return ehci->resuming_ports;
+}
+
 #else
 
 #define ehci_bus_suspend       NULL
 #define ehci_bus_resume                NULL
+#define ehci_get_resuming_ports        NULL
 
 #endif /* CONFIG_PM */
 
diff --git a/drivers/usb/host/ehci-npcm7xx.c b/drivers/usb/host/ehci-npcm7xx.c
new file mode 100644 (file)
index 0000000..adaf8fb
--- /dev/null
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Nuvoton NPCM7xx driver for EHCI HCD
+ *
+ * Copyright (C) 2018 Nuvoton Technologies,
+ * Avi Fishman <avi.fishman@nuvoton.com> <avifishman70@gmail.com>
+ * Tomer Maimon <tomer.maimon@nuvoton.com> <tmaimon77@gmail.com>
+ *
+ * Based on various ehci-spear.c driver
+ */
+
+
+#include <linux/dma-mapping.h>
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+
+#include "ehci.h"
+
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+#define DRIVER_DESC "EHCI npcm7xx driver"
+
+static const char hcd_name[] = "npcm7xx-ehci";
+
+#define  USB2PHYCTL_OFFSET 0x144
+
+#define  IPSRST2_OFFSET 0x24
+#define  IPSRST3_OFFSET 0x34
+
+
+static struct hc_driver __read_mostly ehci_npcm7xx_hc_driver;
+
+#ifdef CONFIG_PM_SLEEP
+static int ehci_npcm7xx_drv_suspend(struct device *dev)
+{
+       struct usb_hcd *hcd = dev_get_drvdata(dev);
+       bool do_wakeup = device_may_wakeup(dev);
+
+       return ehci_suspend(hcd, do_wakeup);
+}
+
+static int ehci_npcm7xx_drv_resume(struct device *dev)
+{
+       struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+       ehci_resume(hcd, false);
+       return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(ehci_npcm7xx_pm_ops, ehci_npcm7xx_drv_suspend,
+               ehci_npcm7xx_drv_resume);
+
+static int npcm7xx_ehci_hcd_drv_probe(struct platform_device *pdev)
+{
+       struct usb_hcd *hcd;
+       struct resource *res;
+       struct regmap *gcr_regmap;
+       struct regmap *rst_regmap;
+       const struct hc_driver *driver = &ehci_npcm7xx_hc_driver;
+       int irq;
+       int retval;
+
+       dev_dbg(&pdev->dev,     "initializing npcm7xx ehci USB Controller\n");
+
+       gcr_regmap = syscon_regmap_lookup_by_compatible("nuvoton,npcm750-gcr");
+       if (IS_ERR(gcr_regmap)) {
+               dev_err(&pdev->dev, "%s: failed to find nuvoton,npcm750-gcr\n",
+                       __func__);
+               return PTR_ERR(gcr_regmap);
+       }
+
+       rst_regmap = syscon_regmap_lookup_by_compatible("nuvoton,npcm750-rst");
+       if (IS_ERR(rst_regmap)) {
+               dev_err(&pdev->dev, "%s: failed to find nuvoton,npcm750-rst\n",
+                       __func__);
+               return PTR_ERR(rst_regmap);
+       }
+
+       /********* phy init  ******/
+       // reset usb host
+       regmap_update_bits(rst_regmap, IPSRST2_OFFSET,
+                       (0x1 << 26), (0x1 << 26));
+       regmap_update_bits(rst_regmap, IPSRST3_OFFSET,
+                       (0x1 << 25), (0x1 << 25));
+       regmap_update_bits(gcr_regmap, USB2PHYCTL_OFFSET,
+                       (0x1 << 28), 0);
+
+       udelay(1);
+
+       // enable phy
+       regmap_update_bits(rst_regmap, IPSRST3_OFFSET,
+                       (0x1 << 25), 0);
+
+       udelay(50); // enable phy
+
+       regmap_update_bits(gcr_regmap, USB2PHYCTL_OFFSET,
+                       (0x1 << 28), (0x1 << 28));
+
+       // enable host
+       regmap_update_bits(rst_regmap, IPSRST2_OFFSET,
+                       (0x1 << 26), 0);
+
+       if (usb_disabled())
+               return -ENODEV;
+
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               retval = irq;
+               goto fail;
+       }
+
+       /*
+        * Right now device-tree probed devices don't get dma_mask set.
+        * Since shared usb code relies on it, set it here for now.
+        * Once we have dma capability bindings this can go away.
+        */
+       retval = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+       if (retval)
+               goto fail;
+
+       hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
+       if (!hcd) {
+               retval = -ENOMEM;
+               goto fail;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       hcd->regs = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(hcd->regs)) {
+               retval = PTR_ERR(hcd->regs);
+               goto err_put_hcd;
+       }
+       hcd->rsrc_start = res->start;
+       hcd->rsrc_len = resource_size(res);
+
+       /* registers start at offset 0x0 */
+       hcd_to_ehci(hcd)->caps = hcd->regs;
+
+       retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
+       if (retval)
+               goto err_put_hcd;
+
+       device_wakeup_enable(hcd->self.controller);
+       return retval;
+
+err_put_hcd:
+       usb_put_hcd(hcd);
+fail:
+       dev_err(&pdev->dev, "init fail, %d\n", retval);
+
+       return retval;
+}
+
+static int npcm7xx_ehci_hcd_drv_remove(struct platform_device *pdev)
+{
+       struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+       usb_remove_hcd(hcd);
+
+       usb_put_hcd(hcd);
+
+       return 0;
+}
+
+static const struct of_device_id npcm7xx_ehci_id_table[] = {
+       { .compatible = "nuvoton,npcm750-ehci" },
+       { },
+};
+MODULE_DEVICE_TABLE(of, npcm7xx_ehci_id_table);
+
+static struct platform_driver npcm7xx_ehci_hcd_driver = {
+       .probe          = npcm7xx_ehci_hcd_drv_probe,
+       .remove         = npcm7xx_ehci_hcd_drv_remove,
+       .shutdown       = usb_hcd_platform_shutdown,
+       .driver         = {
+               .name = "npcm7xx-ehci",
+               .bus = &platform_bus_type,
+               .pm = &ehci_npcm7xx_pm_ops,
+               .of_match_table = npcm7xx_ehci_id_table,
+       }
+};
+
+static int __init ehci_npcm7xx_init(void)
+{
+       if (usb_disabled())
+               return -ENODEV;
+
+       pr_info("%s: " DRIVER_DESC "\n", hcd_name);
+
+       ehci_init_driver(&ehci_npcm7xx_hc_driver, NULL);
+       return platform_driver_register(&npcm7xx_ehci_hcd_driver);
+}
+module_init(ehci_npcm7xx_init);
+
+static void __exit ehci_npcm7xx_cleanup(void)
+{
+       platform_driver_unregister(&npcm7xx_ehci_hcd_driver);
+}
+module_exit(ehci_npcm7xx_cleanup);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_ALIAS("platform:npcm7xx-ehci");
+MODULE_AUTHOR("Avi Fishman");
+MODULE_LICENSE("GPL v2");
index 1d87295..da7b00a 100644 (file)
@@ -1835,7 +1835,6 @@ static bool itd_complete(struct ehci_hcd *ehci, struct ehci_itd *itd)
        unsigned                                uframe;
        int                                     urb_index = -1;
        struct ehci_iso_stream                  *stream = itd->stream;
-       struct usb_device                       *dev;
        bool                                    retval = false;
 
        /* for each uframe with a packet */
@@ -1886,7 +1885,6 @@ static bool itd_complete(struct ehci_hcd *ehci, struct ehci_itd *itd)
         */
 
        /* give urb back to the driver; completion often (re)submits */
-       dev = urb->dev;
        ehci_urb_done(ehci, urb, 0);
        retval = true;
        urb = NULL;
@@ -2230,7 +2228,6 @@ static bool sitd_complete(struct ehci_hcd *ehci, struct ehci_sitd *sitd)
        u32                                     t;
        int                                     urb_index;
        struct ehci_iso_stream                  *stream = sitd->stream;
-       struct usb_device                       *dev;
        bool                                    retval = false;
 
        urb_index = sitd->index;
@@ -2268,7 +2265,6 @@ static bool sitd_complete(struct ehci_hcd *ehci, struct ehci_sitd *sitd)
         */
 
        /* give urb back to the driver; completion often (re)submits */
-       dev = urb->dev;
        ehci_urb_done(ehci, urb, 0);
        retval = true;
        urb = NULL;
index 032b865..072bd5d 100644 (file)
@@ -3062,7 +3062,6 @@ static int u132_probe(struct platform_device *pdev)
        int retval;
        u32 control;
        u32 rh_a = -1;
-       u32 num_ports;
 
        msleep(100);
        if (u132_exiting > 0)
@@ -3077,7 +3076,6 @@ static int u132_probe(struct platform_device *pdev)
        retval = ftdi_read_pcimem(pdev, roothub.a, &rh_a);
        if (retval)
                return retval;
-       num_ports = rh_a & RH_A_NDP;    /* refuse to confuse usbcore */
        if (pdev->dev.dma_mask)
                return -EINVAL;
 
index bb84366..ef52aeb 100644 (file)
@@ -96,9 +96,7 @@ static enum whc_update pzl_process_qset(struct whc *whc, struct whc_qset *qset)
 
        while (qset->ntds) {
                struct whc_qtd *td;
-               int t;
 
-               t = qset->td_start;
                td = &qset->qtd[qset->td_start];
                status = le32_to_cpu(td->status);
 
index 387f124..86cff5c 100644 (file)
@@ -913,11 +913,9 @@ static ssize_t dbc_store(struct device *dev,
                         struct device_attribute *attr,
                         const char *buf, size_t count)
 {
-       struct xhci_dbc         *dbc;
        struct xhci_hcd         *xhci;
 
        xhci = hcd_to_xhci(dev_get_drvdata(dev));
-       dbc = xhci->dbc;
 
        if (!strncmp(buf, "enable", 6))
                xhci_dbc_start(xhci);
index a4b95d0..7e2a531 100644 (file)
@@ -1684,4 +1684,15 @@ int xhci_bus_resume(struct usb_hcd *hcd)
        return 0;
 }
 
+unsigned long xhci_get_resuming_ports(struct usb_hcd *hcd)
+{
+       struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+       struct xhci_bus_state *bus_state;
+
+       bus_state = &xhci->bus_state[hcd_index(hcd)];
+
+       /* USB3 port wakeups are reported via usb_wakeup_notification() */
+       return bus_state->resuming_ports;       /* USB2 ports only */
+}
+
 #endif /* CONFIG_PM */
index c1b22fc..8dc77e3 100644 (file)
@@ -105,6 +105,7 @@ static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen2 = {
 };
 
 static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen3 = {
+       .firmware_name = XHCI_RCAR_FIRMWARE_NAME_V3,
        .init_quirk = xhci_rcar_init_quirk,
        .plat_start = xhci_rcar_start,
        .resume_quirk = xhci_rcar_resume_quirk,
index f33ffc2..a6e4637 100644 (file)
@@ -17,9 +17,8 @@
 #include "xhci-rcar.h"
 
 /*
-* - The V3 firmware is for r8a7796 (with good performance) and r8a7795 es2.0
-*   or later.
-* - The V2 firmware can be used on both r8a7795 (es1.x) and r8a7796.
+* - The V3 firmware is for almost all R-Car Gen3 (except r8a7795 ES1.x)
+* - The V2 firmware is for r8a7795 ES1.x.
 * - The V2 firmware is possible to use on R-Car Gen2. However, the V2 causes
 *   performance degradation. So, this driver continues to use the V1 if R-Car
 *   Gen2.
@@ -30,6 +29,7 @@ MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V2);
 MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V3);
 
 /*** Register Offset ***/
+#define RCAR_USB3_AXH_STA      0x104   /* AXI Host Control Status */
 #define RCAR_USB3_INT_ENA      0x224   /* Interrupt Enable */
 #define RCAR_USB3_DL_CTRL      0x250   /* FW Download Control & Status */
 #define RCAR_USB3_FW_DATA0     0x258   /* FW Data0 */
@@ -42,6 +42,12 @@ MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V3);
 #define RCAR_USB3_TX_POL       0xab8   /* USB3.0 TX Polarity */
 
 /*** Register Settings ***/
+/* AXI Host Control Status */
+#define RCAR_USB3_AXH_STA_B3_PLL_ACTIVE                0x00010000
+#define RCAR_USB3_AXH_STA_B2_PLL_ACTIVE                0x00000001
+#define RCAR_USB3_AXH_STA_PLL_ACTIVE_MASK (RCAR_USB3_AXH_STA_B3_PLL_ACTIVE | \
+                                          RCAR_USB3_AXH_STA_B2_PLL_ACTIVE)
+
 /* Interrupt Enable */
 #define RCAR_USB3_INT_XHC_ENA  0x00000001
 #define RCAR_USB3_INT_PME_ENA  0x00000002
@@ -75,18 +81,6 @@ static const struct soc_device_attribute rcar_quirks_match[]  = {
                .soc_id = "r8a7795", .revision = "ES1.*",
                .data = (void *)RCAR_XHCI_FIRMWARE_V2,
        },
-       {
-               .soc_id = "r8a7795",
-               .data = (void *)RCAR_XHCI_FIRMWARE_V3,
-       },
-       {
-               .soc_id = "r8a7796",
-               .data = (void *)RCAR_XHCI_FIRMWARE_V3,
-       },
-       {
-               .soc_id = "r8a77965",
-               .data = (void *)RCAR_XHCI_FIRMWARE_V3,
-       },
        { /* sentinel */ },
 };
 
@@ -213,6 +207,22 @@ static int xhci_rcar_download_firmware(struct usb_hcd *hcd)
        return retval;
 }
 
+static bool xhci_rcar_wait_for_pll_active(struct usb_hcd *hcd)
+{
+       int timeout = 1000;
+       u32 val, mask = RCAR_USB3_AXH_STA_PLL_ACTIVE_MASK;
+
+       while (timeout > 0) {
+               val = readl(hcd->regs + RCAR_USB3_AXH_STA);
+               if ((val & mask) == mask)
+                       return true;
+               udelay(1);
+               timeout--;
+       }
+
+       return false;
+}
+
 /* This function needs to initialize a "phy" of usb before */
 int xhci_rcar_init_quirk(struct usb_hcd *hcd)
 {
@@ -233,6 +243,9 @@ int xhci_rcar_init_quirk(struct usb_hcd *hcd)
                        xhci_rcar_is_gen3(hcd->self.controller))
                xhci->quirks |= XHCI_NO_64BIT_SUPPORT;
 
+       if (!xhci_rcar_wait_for_pll_active(hcd))
+               return -ETIMEDOUT;
+
        return xhci_rcar_download_firmware(hcd);
 }
 
index 68e6132..61f48b1 100644 (file)
@@ -5121,6 +5121,7 @@ static const struct hc_driver xhci_hc_driver = {
        .hub_status_data =      xhci_hub_status_data,
        .bus_suspend =          xhci_bus_suspend,
        .bus_resume =           xhci_bus_resume,
+       .get_resuming_ports =   xhci_get_resuming_ports,
 
        /*
         * call back when device connected and addressed
index 841e89f..6230a57 100644 (file)
@@ -2114,9 +2114,11 @@ void xhci_hc_died(struct xhci_hcd *xhci);
 #ifdef CONFIG_PM
 int xhci_bus_suspend(struct usb_hcd *hcd);
 int xhci_bus_resume(struct usb_hcd *hcd);
+unsigned long xhci_get_resuming_ports(struct usb_hcd *hcd);
 #else
 #define        xhci_bus_suspend        NULL
 #define        xhci_bus_resume         NULL
+#define        xhci_get_resuming_ports NULL
 #endif /* CONFIG_PM */
 
 u32 xhci_port_state_to_neutral(u32 state);
index 1045521..8142c6b 100644 (file)
@@ -1817,7 +1817,6 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
        u32 temp, status;
        unsigned long flags;
        int retval = 0;
-       unsigned selector;
 
        /*
         * FIXME:  support SetPortFeatures USB_PORT_FEAT_INDICATOR.
@@ -2010,7 +2009,6 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
                }
                break;
        case SetPortFeature:
-               selector = wIndex >> 8;
                wIndex &= 0xff;
                if (!wIndex || wIndex > ports)
                        goto error;
index b3160af..9465fb9 100644 (file)
@@ -155,11 +155,12 @@ static void adu_interrupt_in_callback(struct urb *urb)
 {
        struct adu_device *dev = urb->context;
        int status = urb->status;
+       unsigned long flags;
 
        adu_debug_data(&dev->udev->dev, __func__,
                       urb->actual_length, urb->transfer_buffer);
 
-       spin_lock(&dev->buflock);
+       spin_lock_irqsave(&dev->buflock, flags);
 
        if (status != 0) {
                if ((status != -ENOENT) && (status != -ECONNRESET) &&
@@ -190,7 +191,7 @@ static void adu_interrupt_in_callback(struct urb *urb)
 
 exit:
        dev->read_urb_finished = 1;
-       spin_unlock(&dev->buflock);
+       spin_unlock_irqrestore(&dev->buflock, flags);
        /* always wake up so we recover from errors */
        wake_up_interruptible(&dev->read_wait);
 }
@@ -199,6 +200,7 @@ static void adu_interrupt_out_callback(struct urb *urb)
 {
        struct adu_device *dev = urb->context;
        int status = urb->status;
+       unsigned long flags;
 
        adu_debug_data(&dev->udev->dev, __func__,
                       urb->actual_length, urb->transfer_buffer);
@@ -213,10 +215,10 @@ static void adu_interrupt_out_callback(struct urb *urb)
                return;
        }
 
-       spin_lock(&dev->buflock);
+       spin_lock_irqsave(&dev->buflock, flags);
        dev->out_urb_finished = 1;
        wake_up(&dev->write_wait);
-       spin_unlock(&dev->buflock);
+       spin_unlock_irqrestore(&dev->buflock, flags);
 }
 
 static int adu_open(struct inode *inode, struct file *file)
index b3eb8b9..d746c26 100644 (file)
@@ -89,6 +89,7 @@ static void appledisplay_complete(struct urb *urb)
                dev_err(dev,
                        "OVERFLOW with data length %d, actual length is %d\n",
                        ACD_URB_BUFFER_LEN, pdata->urb->actual_length);
+               /* fall through */
        case -ECONNRESET:
        case -ENOENT:
        case -ESHUTDOWN:
index 8d33187..c2991b8 100644 (file)
@@ -81,7 +81,6 @@ struct iowarrior {
        atomic_t write_busy;            /* number of write-urbs submitted */
        atomic_t read_idx;
        atomic_t intr_idx;
-       spinlock_t intr_idx_lock;       /* protects intr_idx */
        atomic_t overflow_flag;         /* signals an index 'rollover' */
        int present;                    /* this is 1 as long as the device is connected */
        int opened;                     /* this is 1 if the device is currently open */
@@ -166,7 +165,6 @@ static void iowarrior_callback(struct urb *urb)
                goto exit;
        }
 
-       spin_lock(&dev->intr_idx_lock);
        intr_idx = atomic_read(&dev->intr_idx);
        /* aux_idx become previous intr_idx */
        aux_idx = (intr_idx == 0) ? (MAX_INTERRUPT_BUFFER - 1) : (intr_idx - 1);
@@ -181,7 +179,6 @@ static void iowarrior_callback(struct urb *urb)
                    (dev->read_queue + offset, urb->transfer_buffer,
                     dev->report_size)) {
                        /* equal values on interface 0 will be ignored */
-                       spin_unlock(&dev->intr_idx_lock);
                        goto exit;
                }
        }
@@ -202,7 +199,6 @@ static void iowarrior_callback(struct urb *urb)
        *(dev->read_queue + offset + (dev->report_size)) = dev->serial_number++;
 
        atomic_set(&dev->intr_idx, aux_idx);
-       spin_unlock(&dev->intr_idx_lock);
        /* tell the blocking read about the new data */
        wake_up_interruptible(&dev->read_wait);
 
@@ -762,7 +758,6 @@ static int iowarrior_probe(struct usb_interface *interface,
 
        atomic_set(&dev->intr_idx, 0);
        atomic_set(&dev->read_idx, 0);
-       spin_lock_init(&dev->intr_idx_lock);
        atomic_set(&dev->overflow_flag, 0);
        init_waitqueue_head(&dev->read_wait);
        atomic_set(&dev->write_busy, 0);
index c2e255f..006762b 100644 (file)
@@ -225,6 +225,7 @@ static void ld_usb_interrupt_in_callback(struct urb *urb)
        size_t *actual_buffer;
        unsigned int next_ring_head;
        int status = urb->status;
+       unsigned long flags;
        int retval;
 
        if (status) {
@@ -236,12 +237,12 @@ static void ld_usb_interrupt_in_callback(struct urb *urb)
                        dev_dbg(&dev->intf->dev,
                                "%s: nonzero status received: %d\n", __func__,
                                status);
-                       spin_lock(&dev->rbsl);
+                       spin_lock_irqsave(&dev->rbsl, flags);
                        goto resubmit; /* maybe we can recover */
                }
        }
 
-       spin_lock(&dev->rbsl);
+       spin_lock_irqsave(&dev->rbsl, flags);
        if (urb->actual_length > 0) {
                next_ring_head = (dev->ring_head+1) % ring_buffer_size;
                if (next_ring_head != dev->ring_tail) {
@@ -270,7 +271,7 @@ resubmit:
                        dev->buffer_overflow = 1;
                }
        }
-       spin_unlock(&dev->rbsl);
+       spin_unlock_irqrestore(&dev->rbsl, flags);
 exit:
        dev->interrupt_in_done = 1;
        wake_up_interruptible(&dev->read_wait);
index bf47bd8..006cf13 100644 (file)
@@ -722,6 +722,7 @@ static void tower_interrupt_in_callback (struct urb *urb)
        struct lego_usb_tower *dev = urb->context;
        int status = urb->status;
        int retval;
+       unsigned long flags;
 
        lego_usb_tower_debug_data(&dev->udev->dev, __func__,
                                  urb->actual_length, urb->transfer_buffer);
@@ -740,7 +741,7 @@ static void tower_interrupt_in_callback (struct urb *urb)
        }
 
        if (urb->actual_length > 0) {
-               spin_lock (&dev->read_buffer_lock);
+               spin_lock_irqsave(&dev->read_buffer_lock, flags);
                if (dev->read_buffer_length + urb->actual_length < read_buffer_size) {
                        memcpy (dev->read_buffer + dev->read_buffer_length,
                                dev->interrupt_in_buffer,
@@ -753,7 +754,7 @@ static void tower_interrupt_in_callback (struct urb *urb)
                        pr_warn("read_buffer overflow, %d bytes dropped\n",
                                urb->actual_length);
                }
-               spin_unlock (&dev->read_buffer_lock);
+               spin_unlock_irqrestore(&dev->read_buffer_lock, flags);
        }
 
 resubmit:
index f92c5df..3198d04 100644 (file)
@@ -1750,7 +1750,7 @@ static int sisusb_setup_screen(struct sisusb_usb_data *sisusb,
 static int sisusb_set_default_mode(struct sisusb_usb_data *sisusb,
                int touchengines)
 {
-       int ret = 0, i, j, modex, modey, bpp, du;
+       int ret = 0, i, j, modex, bpp, du;
        u8 sr31, cr63, tmp8;
        static const char attrdata[] = {
                0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
@@ -1773,7 +1773,7 @@ static int sisusb_set_default_mode(struct sisusb_usb_data *sisusb,
                0x00
        };
 
-       modex = 640; modey = 480; bpp = 2;
+       modex = 640; bpp = 2;
 
        GETIREG(SISSR, 0x31, &sr31);
        GETIREG(SISCR, 0x63, &cr63);
index 9e1142b..c7f8231 100644 (file)
@@ -1082,11 +1082,12 @@ static void ctrl_complete(struct urb *urb)
        struct usb_ctrlrequest  *reqp;
        struct subcase          *subcase;
        int                     status = urb->status;
+       unsigned long           flags;
 
        reqp = (struct usb_ctrlrequest *)urb->setup_packet;
        subcase = container_of(reqp, struct subcase, setup);
 
-       spin_lock(&ctx->lock);
+       spin_lock_irqsave(&ctx->lock, flags);
        ctx->count--;
        ctx->pending--;
 
@@ -1185,7 +1186,7 @@ error:
        /* signal completion when nothing's queued */
        if (ctx->pending == 0)
                complete(&ctx->complete);
-       spin_unlock(&ctx->lock);
+       spin_unlock_irqrestore(&ctx->lock, flags);
 }
 
 static int
@@ -1917,8 +1918,9 @@ struct transfer_context {
 static void complicated_callback(struct urb *urb)
 {
        struct transfer_context *ctx = urb->context;
+       unsigned long flags;
 
-       spin_lock(&ctx->lock);
+       spin_lock_irqsave(&ctx->lock, flags);
        ctx->count--;
 
        ctx->packet_count += urb->number_of_packets;
@@ -1958,7 +1960,7 @@ static void complicated_callback(struct urb *urb)
                complete(&ctx->done);
        }
 done:
-       spin_unlock(&ctx->lock);
+       spin_unlock_irqrestore(&ctx->lock, flags);
 }
 
 static struct urb *iso_alloc_urb(
index de9a502..82f2206 100644 (file)
@@ -748,13 +748,11 @@ static void uss720_disconnect(struct usb_interface *intf)
 {
        struct parport *pp = usb_get_intfdata(intf);
        struct parport_uss720_private *priv;
-       struct usb_device *usbdev;
 
        dev_dbg(&intf->dev, "disconnect\n");
        usb_set_intfdata(intf, NULL);
        if (pp) {
                priv = pp->private_data;
-               usbdev = priv->usbdev;
                priv->usbdev = NULL;
                priv->pp = NULL;
                dev_dbg(&intf->dev, "parport_remove_port\n");
index ad2c082..ac2b4fc 100644 (file)
@@ -95,8 +95,8 @@ struct mon_bin_hdr {
        unsigned short busnum;  /* Bus number */
        char flag_setup;
        char flag_data;
-       s64 ts_sec;             /* getnstimeofday64 */
-       s32 ts_usec;            /* getnstimeofday64 */
+       s64 ts_sec;             /* ktime_get_real_ts64 */
+       s32 ts_usec;            /* ktime_get_real_ts64 */
        int status;
        unsigned int len_urb;   /* Length of data (submitted or actual) */
        unsigned int len_cap;   /* Delivered length */
@@ -497,7 +497,7 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
        struct mon_bin_hdr *ep;
        char data_tag = 0;
 
-       getnstimeofday64(&ts);
+       ktime_get_real_ts64(&ts);
 
        spin_lock_irqsave(&rp->b_lock, flags);
 
@@ -637,7 +637,7 @@ static void mon_bin_error(void *data, struct urb *urb, int error)
        unsigned int offset;
        struct mon_bin_hdr *ep;
 
-       getnstimeofday64(&ts);
+       ktime_get_real_ts64(&ts);
 
        spin_lock_irqsave(&rp->b_lock, flags);
 
index fb871ea..df827ff 100644 (file)
@@ -237,7 +237,7 @@ static int dsps_check_status(struct musb *musb, void *unused)
                }
                musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
                skip_session = 1;
-               /* fall */
+               /* fall through */
 
        case OTG_STATE_A_IDLE:
        case OTG_STATE_B_IDLE:
index 8000c7c..b59ce9a 100644 (file)
@@ -378,6 +378,7 @@ static void musb_advance_schedule(struct musb *musb, struct urb *urb,
                                qh = first_qh(head);
                                break;
                        }
+                       /* else: fall through */
 
                case USB_ENDPOINT_XFER_ISOC:
                case USB_ENDPOINT_XFER_INT:
index b26d7c3..7fdbff2 100644 (file)
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
 #
 # Renesas USBHS Controller Drivers
 #
index 33d059c..59cac40 100644 (file)
@@ -502,6 +502,7 @@ static int usbhsg_irq_ctrl_stage(struct usbhs_priv *priv,
        case READ_STATUS_STAGE:
        case WRITE_STATUS_STAGE:
                usbhs_dcp_control_transfer_done(pipe);
+               /* fall through */
        default:
                return ret;
        }
index 626a29d..c0777a3 100644 (file)
@@ -239,11 +239,14 @@ MODULE_DEVICE_TABLE(usb, id_table);
 struct cp210x_serial_private {
 #ifdef CONFIG_GPIOLIB
        struct gpio_chip        gc;
-       u8                      config;
-       u8                      gpio_mode;
        bool                    gpio_registered;
+       u8                      gpio_pushpull;
+       u8                      gpio_altfunc;
+       u8                      gpio_input;
 #endif
        u8                      partnum;
+       speed_t                 max_speed;
+       bool                    use_actual_rate;
 };
 
 struct cp210x_port_private {
@@ -356,6 +359,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
 #define CONTROL_WRITE_RTS      0x0200
 
 /* CP210X_VENDOR_SPECIFIC values */
+#define CP210X_READ_2NCONFIG   0x000E
 #define CP210X_READ_LATCH      0x00C2
 #define CP210X_GET_PARTNUM     0x370B
 #define CP210X_GET_PORTCONFIG  0x370C
@@ -369,6 +373,9 @@ static struct usb_serial_driver * const serial_drivers[] = {
 #define CP210X_PARTNUM_CP2104  0x04
 #define CP210X_PARTNUM_CP2105  0x05
 #define CP210X_PARTNUM_CP2108  0x08
+#define CP210X_PARTNUM_CP2102N_QFN28   0x20
+#define CP210X_PARTNUM_CP2102N_QFN24   0x21
+#define CP210X_PARTNUM_CP2102N_QFN20   0x22
 #define CP210X_PARTNUM_UNKNOWN 0xFF
 
 /* CP210X_GET_COMM_STATUS returns these 0x13 bytes */
@@ -462,6 +469,12 @@ struct cp210x_config {
 #define CP2105_GPIO1_RXLED_MODE                BIT(1)
 #define CP2105_GPIO1_RS485_MODE                BIT(2)
 
+/* CP2102N configuration array indices */
+#define CP210X_2NCONFIG_CONFIG_VERSION_IDX     2
+#define CP210X_2NCONFIG_GPIO_MODE_IDX          581
+#define CP210X_2NCONFIG_GPIO_RSTLATCH_IDX      587
+#define CP210X_2NCONFIG_GPIO_CONTROL_IDX       600
+
 /* CP210X_VENDOR_SPECIFIC, CP210X_WRITE_LATCH call writes these 0x2 bytes. */
 struct cp210x_gpio_write {
        u8      mask;
@@ -767,48 +780,6 @@ static int cp210x_get_line_ctl(struct usb_serial_port *port, u16 *ctl)
        return 0;
 }
 
-/*
- * cp210x_quantise_baudrate
- * Quantises the baud rate as per AN205 Table 1
- */
-static unsigned int cp210x_quantise_baudrate(unsigned int baud)
-{
-       if (baud <= 300)
-               baud = 300;
-       else if (baud <= 600)      baud = 600;
-       else if (baud <= 1200)     baud = 1200;
-       else if (baud <= 1800)     baud = 1800;
-       else if (baud <= 2400)     baud = 2400;
-       else if (baud <= 4000)     baud = 4000;
-       else if (baud <= 4803)     baud = 4800;
-       else if (baud <= 7207)     baud = 7200;
-       else if (baud <= 9612)     baud = 9600;
-       else if (baud <= 14428)    baud = 14400;
-       else if (baud <= 16062)    baud = 16000;
-       else if (baud <= 19250)    baud = 19200;
-       else if (baud <= 28912)    baud = 28800;
-       else if (baud <= 38601)    baud = 38400;
-       else if (baud <= 51558)    baud = 51200;
-       else if (baud <= 56280)    baud = 56000;
-       else if (baud <= 58053)    baud = 57600;
-       else if (baud <= 64111)    baud = 64000;
-       else if (baud <= 77608)    baud = 76800;
-       else if (baud <= 117028)   baud = 115200;
-       else if (baud <= 129347)   baud = 128000;
-       else if (baud <= 156868)   baud = 153600;
-       else if (baud <= 237832)   baud = 230400;
-       else if (baud <= 254234)   baud = 250000;
-       else if (baud <= 273066)   baud = 256000;
-       else if (baud <= 491520)   baud = 460800;
-       else if (baud <= 567138)   baud = 500000;
-       else if (baud <= 670254)   baud = 576000;
-       else if (baud < 1000000)
-               baud = 921600;
-       else if (baud > 2000000)
-               baud = 2000000;
-       return baud;
-}
-
 static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
        int result;
@@ -1028,6 +999,75 @@ static void cp210x_get_termios_port(struct usb_serial_port *port,
        *cflagp = cflag;
 }
 
+struct cp210x_rate {
+       speed_t rate;
+       speed_t high;
+};
+
+static const struct cp210x_rate cp210x_an205_table1[] = {
+       { 300, 300 },
+       { 600, 600 },
+       { 1200, 1200 },
+       { 1800, 1800 },
+       { 2400, 2400 },
+       { 4000, 4000 },
+       { 4800, 4803 },
+       { 7200, 7207 },
+       { 9600, 9612 },
+       { 14400, 14428 },
+       { 16000, 16062 },
+       { 19200, 19250 },
+       { 28800, 28912 },
+       { 38400, 38601 },
+       { 51200, 51558 },
+       { 56000, 56280 },
+       { 57600, 58053 },
+       { 64000, 64111 },
+       { 76800, 77608 },
+       { 115200, 117028 },
+       { 128000, 129347 },
+       { 153600, 156868 },
+       { 230400, 237832 },
+       { 250000, 254234 },
+       { 256000, 273066 },
+       { 460800, 491520 },
+       { 500000, 567138 },
+       { 576000, 670254 },
+       { 921600, UINT_MAX }
+};
+
+/*
+ * Quantises the baud rate as per AN205 Table 1
+ */
+static speed_t cp210x_get_an205_rate(speed_t baud)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(cp210x_an205_table1); ++i) {
+               if (baud <= cp210x_an205_table1[i].high)
+                       break;
+       }
+
+       return cp210x_an205_table1[i].rate;
+}
+
+static speed_t cp210x_get_actual_rate(struct usb_serial *serial, speed_t baud)
+{
+       struct cp210x_serial_private *priv = usb_get_serial_data(serial);
+       unsigned int prescale = 1;
+       unsigned int div;
+
+       baud = clamp(baud, 300u, priv->max_speed);
+
+       if (baud <= 365)
+               prescale = 4;
+
+       div = DIV_ROUND_CLOSEST(48000000, 2 * prescale * baud);
+       baud = 48000000 / (2 * prescale * div);
+
+       return baud;
+}
+
 /*
  * CP2101 supports the following baud rates:
  *
@@ -1057,16 +1097,24 @@ static void cp210x_get_termios_port(struct usb_serial_port *port,
 static void cp210x_change_speed(struct tty_struct *tty,
                struct usb_serial_port *port, struct ktermios *old_termios)
 {
+       struct usb_serial *serial = port->serial;
+       struct cp210x_serial_private *priv = usb_get_serial_data(serial);
        u32 baud;
 
        baud = tty->termios.c_ospeed;
 
-       /* This maps the requested rate to a rate valid on cp2102 or cp2103,
-        * or to an arbitrary rate in [1M,2M].
+       /*
+        * This maps the requested rate to the actual rate, a valid rate on
+        * cp2102 or cp2103, or to an arbitrary rate in [1M, max_speed].
         *
         * NOTE: B0 is not implemented.
         */
-       baud = cp210x_quantise_baudrate(baud);
+       if (priv->use_actual_rate)
+               baud = cp210x_get_actual_rate(serial, baud);
+       else if (baud < 1000000)
+               baud = cp210x_get_an205_rate(baud);
+       else if (baud > priv->max_speed)
+               baud = priv->max_speed;
 
        dev_dbg(&port->dev, "%s - setting baud rate to %u\n", __func__, baud);
        if (cp210x_write_u32_reg(port, CP210X_SET_BAUDRATE, baud)) {
@@ -1288,17 +1336,8 @@ static int cp210x_gpio_request(struct gpio_chip *gc, unsigned int offset)
        struct usb_serial *serial = gpiochip_get_data(gc);
        struct cp210x_serial_private *priv = usb_get_serial_data(serial);
 
-       switch (offset) {
-       case 0:
-               if (priv->config & CP2105_GPIO0_TXLED_MODE)
-                       return -ENODEV;
-               break;
-       case 1:
-               if (priv->config & (CP2105_GPIO1_RXLED_MODE |
-                                   CP2105_GPIO1_RS485_MODE))
-                       return -ENODEV;
-               break;
-       }
+       if (priv->gpio_altfunc & BIT(offset))
+               return -ENODEV;
 
        return 0;
 }
@@ -1306,10 +1345,15 @@ static int cp210x_gpio_request(struct gpio_chip *gc, unsigned int offset)
 static int cp210x_gpio_get(struct gpio_chip *gc, unsigned int gpio)
 {
        struct usb_serial *serial = gpiochip_get_data(gc);
+       struct cp210x_serial_private *priv = usb_get_serial_data(serial);
+       u8 req_type = REQTYPE_DEVICE_TO_HOST;
        int result;
        u8 buf;
 
-       result = cp210x_read_vendor_block(serial, REQTYPE_INTERFACE_TO_HOST,
+       if (priv->partnum == CP210X_PARTNUM_CP2105)
+               req_type = REQTYPE_INTERFACE_TO_HOST;
+
+       result = cp210x_read_vendor_block(serial, req_type,
                                          CP210X_READ_LATCH, &buf, sizeof(buf));
        if (result < 0)
                return result;
@@ -1320,7 +1364,9 @@ static int cp210x_gpio_get(struct gpio_chip *gc, unsigned int gpio)
 static void cp210x_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value)
 {
        struct usb_serial *serial = gpiochip_get_data(gc);
+       struct cp210x_serial_private *priv = usb_get_serial_data(serial);
        struct cp210x_gpio_write buf;
+       int result;
 
        if (value == 1)
                buf.state = BIT(gpio);
@@ -1329,25 +1375,68 @@ static void cp210x_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value)
 
        buf.mask = BIT(gpio);
 
-       cp210x_write_vendor_block(serial, REQTYPE_HOST_TO_INTERFACE,
-                                 CP210X_WRITE_LATCH, &buf, sizeof(buf));
+       if (priv->partnum == CP210X_PARTNUM_CP2105) {
+               result = cp210x_write_vendor_block(serial,
+                                                  REQTYPE_HOST_TO_INTERFACE,
+                                                  CP210X_WRITE_LATCH, &buf,
+                                                  sizeof(buf));
+       } else {
+               u16 wIndex = buf.state << 8 | buf.mask;
+
+               result = usb_control_msg(serial->dev,
+                                        usb_sndctrlpipe(serial->dev, 0),
+                                        CP210X_VENDOR_SPECIFIC,
+                                        REQTYPE_HOST_TO_DEVICE,
+                                        CP210X_WRITE_LATCH,
+                                        wIndex,
+                                        NULL, 0, USB_CTRL_SET_TIMEOUT);
+       }
+
+       if (result < 0) {
+               dev_err(&serial->interface->dev, "failed to set GPIO value: %d\n",
+                               result);
+       }
 }
 
 static int cp210x_gpio_direction_get(struct gpio_chip *gc, unsigned int gpio)
 {
-       /* Hardware does not support an input mode */
-       return 0;
+       struct usb_serial *serial = gpiochip_get_data(gc);
+       struct cp210x_serial_private *priv = usb_get_serial_data(serial);
+
+       return priv->gpio_input & BIT(gpio);
 }
 
 static int cp210x_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio)
 {
-       /* Hardware does not support an input mode */
-       return -ENOTSUPP;
+       struct usb_serial *serial = gpiochip_get_data(gc);
+       struct cp210x_serial_private *priv = usb_get_serial_data(serial);
+
+       if (priv->partnum == CP210X_PARTNUM_CP2105) {
+               /* hardware does not support an input mode */
+               return -ENOTSUPP;
+       }
+
+       /* push-pull pins cannot be changed to be inputs */
+       if (priv->gpio_pushpull & BIT(gpio))
+               return -EINVAL;
+
+       /* make sure to release pin if it is being driven low */
+       cp210x_gpio_set(gc, gpio, 1);
+
+       priv->gpio_input |= BIT(gpio);
+
+       return 0;
 }
 
 static int cp210x_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio,
                                        int value)
 {
+       struct usb_serial *serial = gpiochip_get_data(gc);
+       struct cp210x_serial_private *priv = usb_get_serial_data(serial);
+
+       priv->gpio_input &= ~BIT(gpio);
+       cp210x_gpio_set(gc, gpio, value);
+
        return 0;
 }
 
@@ -1360,11 +1449,11 @@ static int cp210x_gpio_set_config(struct gpio_chip *gc, unsigned int gpio,
 
        /* Succeed only if in correct mode (this can't be set at runtime) */
        if ((param == PIN_CONFIG_DRIVE_PUSH_PULL) &&
-           (priv->gpio_mode & BIT(gpio)))
+           (priv->gpio_pushpull & BIT(gpio)))
                return 0;
 
        if ((param == PIN_CONFIG_DRIVE_OPEN_DRAIN) &&
-           !(priv->gpio_mode & BIT(gpio)))
+           !(priv->gpio_pushpull & BIT(gpio)))
                return 0;
 
        return -ENOTSUPP;
@@ -1377,12 +1466,13 @@ static int cp210x_gpio_set_config(struct gpio_chip *gc, unsigned int gpio,
  * this driver that provide GPIO do so in a way that does not impact other
  * signals and are thus expected to have very different initialisation.
  */
-static int cp2105_shared_gpio_init(struct usb_serial *serial)
+static int cp2105_gpioconf_init(struct usb_serial *serial)
 {
        struct cp210x_serial_private *priv = usb_get_serial_data(serial);
        struct cp210x_pin_mode mode;
        struct cp210x_config config;
        u8 intf_num = cp210x_interface_num(serial);
+       u8 iface_config;
        int result;
 
        result = cp210x_read_vendor_block(serial, REQTYPE_DEVICE_TO_HOST,
@@ -1399,20 +1489,26 @@ static int cp2105_shared_gpio_init(struct usb_serial *serial)
 
        /*  2 banks of GPIO - One for the pins taken from each serial port */
        if (intf_num == 0) {
-               if (mode.eci == CP210X_PIN_MODE_MODEM)
+               if (mode.eci == CP210X_PIN_MODE_MODEM) {
+                       /* mark all GPIOs of this interface as reserved */
+                       priv->gpio_altfunc = 0xff;
                        return 0;
+               }
 
-               priv->config = config.eci_cfg;
-               priv->gpio_mode = (u8)((le16_to_cpu(config.gpio_mode) &
+               iface_config = config.eci_cfg;
+               priv->gpio_pushpull = (u8)((le16_to_cpu(config.gpio_mode) &
                                                CP210X_ECI_GPIO_MODE_MASK) >>
                                                CP210X_ECI_GPIO_MODE_OFFSET);
                priv->gc.ngpio = 2;
        } else if (intf_num == 1) {
-               if (mode.sci == CP210X_PIN_MODE_MODEM)
+               if (mode.sci == CP210X_PIN_MODE_MODEM) {
+                       /* mark all GPIOs of this interface as reserved */
+                       priv->gpio_altfunc = 0xff;
                        return 0;
+               }
 
-               priv->config = config.sci_cfg;
-               priv->gpio_mode = (u8)((le16_to_cpu(config.gpio_mode) &
+               iface_config = config.sci_cfg;
+               priv->gpio_pushpull = (u8)((le16_to_cpu(config.gpio_mode) &
                                                CP210X_SCI_GPIO_MODE_MASK) >>
                                                CP210X_SCI_GPIO_MODE_OFFSET);
                priv->gc.ngpio = 3;
@@ -1420,6 +1516,125 @@ static int cp2105_shared_gpio_init(struct usb_serial *serial)
                return -ENODEV;
        }
 
+       /* mark all pins which are not in GPIO mode */
+       if (iface_config & CP2105_GPIO0_TXLED_MODE)     /* GPIO 0 */
+               priv->gpio_altfunc |= BIT(0);
+       if (iface_config & (CP2105_GPIO1_RXLED_MODE |   /* GPIO 1 */
+                       CP2105_GPIO1_RS485_MODE))
+               priv->gpio_altfunc |= BIT(1);
+
+       /* driver implementation for CP2105 only supports outputs */
+       priv->gpio_input = 0;
+
+       return 0;
+}
+
+static int cp2102n_gpioconf_init(struct usb_serial *serial)
+{
+       struct cp210x_serial_private *priv = usb_get_serial_data(serial);
+       const u16 config_size = 0x02a6;
+       u8 gpio_rst_latch;
+       u8 config_version;
+       u8 gpio_pushpull;
+       u8 *config_buf;
+       u8 gpio_latch;
+       u8 gpio_ctrl;
+       int result;
+       u8 i;
+
+       /*
+        * Retrieve device configuration from the device.
+        * The array received contains all customization settings done at the
+        * factory/manufacturer. Format of the array is documented at the
+        * time of writing at:
+        * https://www.silabs.com/community/interface/knowledge-base.entry.html/2017/03/31/cp2102n_setconfig-xsfa
+        */
+       config_buf = kmalloc(config_size, GFP_KERNEL);
+       if (!config_buf)
+               return -ENOMEM;
+
+       result = cp210x_read_vendor_block(serial,
+                                         REQTYPE_DEVICE_TO_HOST,
+                                         CP210X_READ_2NCONFIG,
+                                         config_buf,
+                                         config_size);
+       if (result < 0) {
+               kfree(config_buf);
+               return result;
+       }
+
+       config_version = config_buf[CP210X_2NCONFIG_CONFIG_VERSION_IDX];
+       gpio_pushpull = config_buf[CP210X_2NCONFIG_GPIO_MODE_IDX];
+       gpio_ctrl = config_buf[CP210X_2NCONFIG_GPIO_CONTROL_IDX];
+       gpio_rst_latch = config_buf[CP210X_2NCONFIG_GPIO_RSTLATCH_IDX];
+
+       kfree(config_buf);
+
+       /* Make sure this is a config format we understand. */
+       if (config_version != 0x01)
+               return -ENOTSUPP;
+
+       /*
+        * We only support 4 GPIOs even on the QFN28 package, because
+        * config locations of GPIOs 4-6 determined using reverse
+        * engineering revealed conflicting offsets with other
+        * documented functions. So we'll just play it safe for now.
+        */
+       priv->gc.ngpio = 4;
+
+       /*
+        * Get default pin states after reset. Needed so we can determine
+        * the direction of an open-drain pin.
+        */
+       gpio_latch = (gpio_rst_latch >> 3) & 0x0f;
+
+       /* 0 indicates open-drain mode, 1 is push-pull */
+       priv->gpio_pushpull = (gpio_pushpull >> 3) & 0x0f;
+
+       /* 0 indicates GPIO mode, 1 is alternate function */
+       priv->gpio_altfunc = (gpio_ctrl >> 2) & 0x0f;
+
+       /*
+        * The CP2102N does not strictly has input and output pin modes,
+        * it only knows open-drain and push-pull modes which is set at
+        * factory. An open-drain pin can function both as an
+        * input or an output. We emulate input mode for open-drain pins
+        * by making sure they are not driven low, and we do not allow
+        * push-pull pins to be set as an input.
+        */
+       for (i = 0; i < priv->gc.ngpio; ++i) {
+               /*
+                * Set direction to "input" iff pin is open-drain and reset
+                * value is 1.
+                */
+               if (!(priv->gpio_pushpull & BIT(i)) && (gpio_latch & BIT(i)))
+                       priv->gpio_input |= BIT(i);
+       }
+
+       return 0;
+}
+
+static int cp210x_gpio_init(struct usb_serial *serial)
+{
+       struct cp210x_serial_private *priv = usb_get_serial_data(serial);
+       int result;
+
+       switch (priv->partnum) {
+       case CP210X_PARTNUM_CP2105:
+               result = cp2105_gpioconf_init(serial);
+               break;
+       case CP210X_PARTNUM_CP2102N_QFN28:
+       case CP210X_PARTNUM_CP2102N_QFN24:
+       case CP210X_PARTNUM_CP2102N_QFN20:
+               result = cp2102n_gpioconf_init(serial);
+               break;
+       default:
+               return 0;
+       }
+
+       if (result < 0)
+               return result;
+
        priv->gc.label = "cp210x";
        priv->gc.request = cp210x_gpio_request;
        priv->gc.get_direction = cp210x_gpio_direction_get;
@@ -1452,7 +1667,7 @@ static void cp210x_gpio_remove(struct usb_serial *serial)
 
 #else
 
-static int cp2105_shared_gpio_init(struct usb_serial *serial)
+static int cp210x_gpio_init(struct usb_serial *serial)
 {
        return 0;
 }
@@ -1497,6 +1712,50 @@ static int cp210x_port_remove(struct usb_serial_port *port)
        return 0;
 }
 
+static void cp210x_init_max_speed(struct usb_serial *serial)
+{
+       struct cp210x_serial_private *priv = usb_get_serial_data(serial);
+       bool use_actual_rate = false;
+       speed_t max;
+
+       switch (priv->partnum) {
+       case CP210X_PARTNUM_CP2101:
+               max = 921600;
+               break;
+       case CP210X_PARTNUM_CP2102:
+       case CP210X_PARTNUM_CP2103:
+               max = 1000000;
+               break;
+       case CP210X_PARTNUM_CP2104:
+               use_actual_rate = true;
+               max = 2000000;
+               break;
+       case CP210X_PARTNUM_CP2108:
+               max = 2000000;
+               break;
+       case CP210X_PARTNUM_CP2105:
+               if (cp210x_interface_num(serial) == 0) {
+                       use_actual_rate = true;
+                       max = 2000000;  /* ECI */
+               } else {
+                       max = 921600;   /* SCI */
+               }
+               break;
+       case CP210X_PARTNUM_CP2102N_QFN28:
+       case CP210X_PARTNUM_CP2102N_QFN24:
+       case CP210X_PARTNUM_CP2102N_QFN20:
+               use_actual_rate = true;
+               max = 3000000;
+               break;
+       default:
+               max = 2000000;
+               break;
+       }
+
+       priv->max_speed = max;
+       priv->use_actual_rate = use_actual_rate;
+}
+
 static int cp210x_attach(struct usb_serial *serial)
 {
        int result;
@@ -1517,12 +1776,12 @@ static int cp210x_attach(struct usb_serial *serial)
 
        usb_set_serial_data(serial, priv);
 
-       if (priv->partnum == CP210X_PARTNUM_CP2105) {
-               result = cp2105_shared_gpio_init(serial);
-               if (result < 0) {
-                       dev_err(&serial->interface->dev,
-                               "GPIO initialisation failed, continuing without GPIO support\n");
-               }
+       cp210x_init_max_speed(serial);
+
+       result = cp210x_gpio_init(serial);
+       if (result < 0) {
+               dev_err(&serial->interface->dev, "GPIO initialisation failed: %d\n",
+                               result);
        }
 
        return 0;
index dc67a2e..ebd76ab 100644 (file)
@@ -255,6 +255,7 @@ static void cyberjack_read_int_callback(struct urb *urb)
        struct device *dev = &port->dev;
        unsigned char *data = urb->transfer_buffer;
        int status = urb->status;
+       unsigned long flags;
        int result;
 
        /* the urb might have been killed. */
@@ -270,13 +271,13 @@ static void cyberjack_read_int_callback(struct urb *urb)
                /* This is a announcement of coming bulk_ins. */
                unsigned short size = ((unsigned short)data[3]<<8)+data[2]+3;
 
-               spin_lock(&priv->lock);
+               spin_lock_irqsave(&priv->lock, flags);
 
                old_rdtodo = priv->rdtodo;
 
                if (old_rdtodo > SHRT_MAX - size) {
                        dev_dbg(dev, "To many bulk_in urbs to do.\n");
-                       spin_unlock(&priv->lock);
+                       spin_unlock_irqrestore(&priv->lock, flags);
                        goto resubmit;
                }
 
@@ -285,7 +286,7 @@ static void cyberjack_read_int_callback(struct urb *urb)
 
                dev_dbg(dev, "%s - rdtodo: %d\n", __func__, priv->rdtodo);
 
-               spin_unlock(&priv->lock);
+               spin_unlock_irqrestore(&priv->lock, flags);
 
                if (!old_rdtodo) {
                        result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
@@ -309,6 +310,7 @@ static void cyberjack_read_bulk_callback(struct urb *urb)
        struct cyberjack_private *priv = usb_get_serial_port_data(port);
        struct device *dev = &port->dev;
        unsigned char *data = urb->transfer_buffer;
+       unsigned long flags;
        short todo;
        int result;
        int status = urb->status;
@@ -325,7 +327,7 @@ static void cyberjack_read_bulk_callback(struct urb *urb)
                tty_flip_buffer_push(&port->port);
        }
 
-       spin_lock(&priv->lock);
+       spin_lock_irqsave(&priv->lock, flags);
 
        /* Reduce urbs to do by one. */
        priv->rdtodo -= urb->actual_length;
@@ -334,7 +336,7 @@ static void cyberjack_read_bulk_callback(struct urb *urb)
                priv->rdtodo = 0;
        todo = priv->rdtodo;
 
-       spin_unlock(&priv->lock);
+       spin_unlock_irqrestore(&priv->lock, flags);
 
        dev_dbg(dev, "%s - rdtodo: %d\n", __func__, todo);
 
@@ -354,6 +356,7 @@ static void cyberjack_write_bulk_callback(struct urb *urb)
        struct cyberjack_private *priv = usb_get_serial_port_data(port);
        struct device *dev = &port->dev;
        int status = urb->status;
+       unsigned long flags;
 
        set_bit(0, &port->write_urbs_free);
        if (status) {
@@ -362,7 +365,7 @@ static void cyberjack_write_bulk_callback(struct urb *urb)
                return;
        }
 
-       spin_lock(&priv->lock);
+       spin_lock_irqsave(&priv->lock, flags);
 
        /* only do something if we have more data to send */
        if (priv->wrfilled) {
@@ -406,7 +409,7 @@ static void cyberjack_write_bulk_callback(struct urb *urb)
        }
 
 exit:
-       spin_unlock(&priv->lock);
+       spin_unlock_irqrestore(&priv->lock, flags);
        usb_serial_port_softint(port);
 }
 
index b052678..e7f244c 100644 (file)
@@ -984,6 +984,7 @@ static void digi_write_bulk_callback(struct urb *urb)
        struct usb_serial *serial;
        struct digi_port *priv;
        struct digi_serial *serial_priv;
+       unsigned long flags;
        int ret = 0;
        int status = urb->status;
 
@@ -1004,15 +1005,15 @@ static void digi_write_bulk_callback(struct urb *urb)
        /* handle oob callback */
        if (priv->dp_port_num == serial_priv->ds_oob_port_num) {
                dev_dbg(&port->dev, "digi_write_bulk_callback: oob callback\n");
-               spin_lock(&priv->dp_port_lock);
+               spin_lock_irqsave(&priv->dp_port_lock, flags);
                priv->dp_write_urb_in_use = 0;
                wake_up_interruptible(&port->write_wait);
-               spin_unlock(&priv->dp_port_lock);
+               spin_unlock_irqrestore(&priv->dp_port_lock, flags);
                return;
        }
 
        /* try to send any buffered data on this port */
-       spin_lock(&priv->dp_port_lock);
+       spin_lock_irqsave(&priv->dp_port_lock, flags);
        priv->dp_write_urb_in_use = 0;
        if (priv->dp_out_buf_len > 0) {
                *((unsigned char *)(port->write_urb->transfer_buffer))
@@ -1035,7 +1036,7 @@ static void digi_write_bulk_callback(struct urb *urb)
        /* lost the race in write_chan(). */
        schedule_work(&priv->dp_wakeup_work);
 
-       spin_unlock(&priv->dp_port_lock);
+       spin_unlock_irqrestore(&priv->dp_port_lock, flags);
        if (ret && ret != -EPERM)
                dev_err_console(port,
                        "%s: usb_submit_urb failed, ret=%d, port=%d\n",
@@ -1381,11 +1382,12 @@ static int digi_read_inb_callback(struct urb *urb)
        struct usb_serial_port *port = urb->context;
        struct digi_port *priv = usb_get_serial_port_data(port);
        unsigned char *buf = urb->transfer_buffer;
+       unsigned long flags;
        int opcode;
        int len;
        int port_status;
        unsigned char *data;
-       int flag, throttled;
+       int tty_flag, throttled;
 
        /* short/multiple packet check */
        if (urb->actual_length < 2) {
@@ -1407,7 +1409,7 @@ static int digi_read_inb_callback(struct urb *urb)
                return -1;
        }
 
-       spin_lock(&priv->dp_port_lock);
+       spin_lock_irqsave(&priv->dp_port_lock, flags);
 
        /* check for throttle; if set, do not resubmit read urb */
        /* indicate the read chain needs to be restarted on unthrottle */
@@ -1421,7 +1423,7 @@ static int digi_read_inb_callback(struct urb *urb)
                data = &buf[3];
 
                /* get flag from port_status */
-               flag = 0;
+               tty_flag = 0;
 
                /* overrun is special, not associated with a char */
                if (port_status & DIGI_OVERRUN_ERROR)
@@ -1430,21 +1432,21 @@ static int digi_read_inb_callback(struct urb *urb)
                /* break takes precedence over parity, */
                /* which takes precedence over framing errors */
                if (port_status & DIGI_BREAK_ERROR)
-                       flag = TTY_BREAK;
+                       tty_flag = TTY_BREAK;
                else if (port_status & DIGI_PARITY_ERROR)
-                       flag = TTY_PARITY;
+                       tty_flag = TTY_PARITY;
                else if (port_status & DIGI_FRAMING_ERROR)
-                       flag = TTY_FRAME;
+                       tty_flag = TTY_FRAME;
 
                /* data length is len-1 (one byte of len is port_status) */
                --len;
                if (len > 0) {
                        tty_insert_flip_string_fixed_flag(&port->port, data,
-                                       flag, len);
+                                       tty_flag, len);
                        tty_flip_buffer_push(&port->port);
                }
        }
-       spin_unlock(&priv->dp_port_lock);
+       spin_unlock_irqrestore(&priv->dp_port_lock, flags);
 
        if (opcode == DIGI_CMD_RECEIVE_DISABLE)
                dev_dbg(&port->dev, "%s: got RECEIVE_DISABLE\n", __func__);
@@ -1474,6 +1476,7 @@ static int digi_read_oob_callback(struct urb *urb)
        struct digi_port *priv = usb_get_serial_port_data(port);
        unsigned char *buf = urb->transfer_buffer;
        int opcode, line, status, val;
+       unsigned long flags;
        int i;
        unsigned int rts;
 
@@ -1506,7 +1509,7 @@ static int digi_read_oob_callback(struct urb *urb)
                        rts = C_CRTSCTS(tty);
 
                if (tty && opcode == DIGI_CMD_READ_INPUT_SIGNALS) {
-                       spin_lock(&priv->dp_port_lock);
+                       spin_lock_irqsave(&priv->dp_port_lock, flags);
                        /* convert from digi flags to termiox flags */
                        if (val & DIGI_READ_INPUT_SIGNALS_CTS) {
                                priv->dp_modem_signals |= TIOCM_CTS;
@@ -1530,12 +1533,12 @@ static int digi_read_oob_callback(struct urb *urb)
                        else
                                priv->dp_modem_signals &= ~TIOCM_CD;
 
-                       spin_unlock(&priv->dp_port_lock);
+                       spin_unlock_irqrestore(&priv->dp_port_lock, flags);
                } else if (opcode == DIGI_CMD_TRANSMIT_IDLE) {
-                       spin_lock(&priv->dp_port_lock);
+                       spin_lock_irqsave(&priv->dp_port_lock, flags);
                        priv->dp_transmit_idle = 1;
                        wake_up_interruptible(&priv->dp_transmit_idle_wait);
-                       spin_unlock(&priv->dp_port_lock);
+                       spin_unlock_irqrestore(&priv->dp_port_lock, flags);
                } else if (opcode == DIGI_CMD_IFLUSH_FIFO) {
                        wake_up_interruptible(&priv->dp_flush_wait);
                }
index 17283f4..97c69d3 100644 (file)
@@ -648,6 +648,7 @@ static void edge_interrupt_callback(struct urb *urb)
        struct usb_serial_port *port;
        unsigned char *data = urb->transfer_buffer;
        int length = urb->actual_length;
+       unsigned long flags;
        int bytes_avail;
        int position;
        int txCredits;
@@ -679,7 +680,7 @@ static void edge_interrupt_callback(struct urb *urb)
                if (length > 1) {
                        bytes_avail = data[0] | (data[1] << 8);
                        if (bytes_avail) {
-                               spin_lock(&edge_serial->es_lock);
+                               spin_lock_irqsave(&edge_serial->es_lock, flags);
                                edge_serial->rxBytesAvail += bytes_avail;
                                dev_dbg(dev,
                                        "%s - bytes_avail=%d, rxBytesAvail=%d, read_in_progress=%d\n",
@@ -702,7 +703,8 @@ static void edge_interrupt_callback(struct urb *urb)
                                                edge_serial->read_in_progress = false;
                                        }
                                }
-                               spin_unlock(&edge_serial->es_lock);
+                               spin_unlock_irqrestore(&edge_serial->es_lock,
+                                                      flags);
                        }
                }
                /* grab the txcredits for the ports if available */
@@ -715,9 +717,11 @@ static void edge_interrupt_callback(struct urb *urb)
                                port = edge_serial->serial->port[portNumber];
                                edge_port = usb_get_serial_port_data(port);
                                if (edge_port->open) {
-                                       spin_lock(&edge_port->ep_lock);
+                                       spin_lock_irqsave(&edge_port->ep_lock,
+                                                         flags);
                                        edge_port->txCredits += txCredits;
-                                       spin_unlock(&edge_port->ep_lock);
+                                       spin_unlock_irqrestore(&edge_port->ep_lock,
+                                                              flags);
                                        dev_dbg(dev, "%s - txcredits for port%d = %d\n",
                                                __func__, portNumber,
                                                edge_port->txCredits);
@@ -758,6 +762,7 @@ static void edge_bulk_in_callback(struct urb *urb)
        int                     retval;
        __u16                   raw_data_length;
        int status = urb->status;
+       unsigned long flags;
 
        if (status) {
                dev_dbg(&urb->dev->dev, "%s - nonzero read bulk status received: %d\n",
@@ -777,7 +782,7 @@ static void edge_bulk_in_callback(struct urb *urb)
 
        usb_serial_debug_data(dev, __func__, raw_data_length, data);
 
-       spin_lock(&edge_serial->es_lock);
+       spin_lock_irqsave(&edge_serial->es_lock, flags);
 
        /* decrement our rxBytes available by the number that we just got */
        edge_serial->rxBytesAvail -= raw_data_length;
@@ -801,7 +806,7 @@ static void edge_bulk_in_callback(struct urb *urb)
                edge_serial->read_in_progress = false;
        }
 
-       spin_unlock(&edge_serial->es_lock);
+       spin_unlock_irqrestore(&edge_serial->es_lock, flags);
 }
 
 
index 0fbadb3..6d1d6ef 100644 (file)
@@ -1729,6 +1729,7 @@ static void edge_bulk_in_callback(struct urb *urb)
        struct edgeport_port *edge_port = urb->context;
        struct device *dev = &edge_port->port->dev;
        unsigned char *data = urb->transfer_buffer;
+       unsigned long flags;
        int retval = 0;
        int port_number;
        int status = urb->status;
@@ -1780,13 +1781,13 @@ static void edge_bulk_in_callback(struct urb *urb)
 
 exit:
        /* continue read unless stopped */
-       spin_lock(&edge_port->ep_lock);
+       spin_lock_irqsave(&edge_port->ep_lock, flags);
        if (edge_port->ep_read_urb_state == EDGE_READ_URB_RUNNING)
                retval = usb_submit_urb(urb, GFP_ATOMIC);
        else if (edge_port->ep_read_urb_state == EDGE_READ_URB_STOPPING)
                edge_port->ep_read_urb_state = EDGE_READ_URB_STOPPED;
 
-       spin_unlock(&edge_port->ep_lock);
+       spin_unlock_irqrestore(&edge_port->ep_lock, flags);
        if (retval)
                dev_err(dev, "%s - usb_submit_urb failed with result %d\n", __func__, retval);
 }
index 24b06c7..7643716 100644 (file)
@@ -132,7 +132,7 @@ irda_usb_find_class_desc(struct usb_serial *serial, unsigned int ifnum)
                        0, ifnum, desc, sizeof(*desc), 1000);
 
        dev_dbg(&serial->dev->dev, "%s -  ret=%d\n", __func__, ret);
-       if (ret < sizeof(*desc)) {
+       if (ret < (int)sizeof(*desc)) {
                dev_dbg(&serial->dev->dev,
                        "%s - class descriptor read %s (%d)\n", __func__,
                        (ret < 0) ? "failed" : "too short", ret);
index 2fb7130..449e89d 100644 (file)
@@ -58,7 +58,6 @@ struct iuu_private {
        u8 *buf;                /* used for initialize speed */
        u8 len;
        int vcc;                /* vcc (either 3 or 5 V) */
-       u32 baud;
        u32 boost;
        u32 clk;
 };
@@ -963,9 +962,6 @@ static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port)
        struct iuu_private *priv = usb_get_serial_port_data(port);
 
        baud = tty->termios.c_ospeed;
-       tty->termios.c_ispeed = baud;
-       /* Re-encode speed */
-       tty_encode_baud_rate(tty, baud, baud);
 
        dev_dbg(dev, "%s - baud %d\n", __func__, baud);
        usb_clear_halt(serial->dev, port->write_urb->pipe);
@@ -991,7 +987,6 @@ static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port)
        if (boost < 100)
                boost = 100;
        priv->boost = boost;
-       priv->baud = baud;
        switch (clockmode) {
        case 2:         /*  3.680 Mhz */
                priv->clk = IUU_CLK_3680000;
index 5046ffd..5ee48b0 100644 (file)
@@ -67,7 +67,6 @@ static int klsi_105_prepare_write_buffer(struct usb_serial_port *port,
  */
 static const struct usb_device_id id_table[] = {
        { USB_DEVICE(PALMCONNECT_VID, PALMCONNECT_PID) },
-       { USB_DEVICE(KLSI_VID, KLSI_KL5KUSB105D_PID) },
        { }             /* Terminating entry */
 };
 
index 41c9bf6..dbe98d8 100644 (file)
@@ -7,9 +7,6 @@
 #define PALMCONNECT_VID                0x0830
 #define PALMCONNECT_PID                0x0080
 
-#define KLSI_VID               0x05e9
-#define KLSI_KL5KUSB105D_PID   0x00c0
-
 /* Vendor commands: */
 
 
index a31ea7e..e9882ba 100644 (file)
@@ -190,8 +190,10 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port)
                          KOBIL_TIMEOUT
        );
        dev_dbg(dev, "%s - Send get_HW_version URB returns: %i\n", __func__, result);
-       dev_dbg(dev, "Hardware version: %i.%i.%i\n", transfer_buffer[0],
-               transfer_buffer[1], transfer_buffer[2]);
+       if (result >= 3) {
+               dev_dbg(dev, "Hardware version: %i.%i.%i\n", transfer_buffer[0],
+                               transfer_buffer[1], transfer_buffer[2]);
+       }
 
        /* get firmware version */
        result = usb_control_msg(port->serial->dev,
@@ -205,8 +207,10 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port)
                          KOBIL_TIMEOUT
        );
        dev_dbg(dev, "%s - Send get_FW_version URB returns: %i\n", __func__, result);
-       dev_dbg(dev, "Firmware version: %i.%i.%i\n", transfer_buffer[0],
-               transfer_buffer[1], transfer_buffer[2]);
+       if (result >= 3) {
+               dev_dbg(dev, "Firmware version: %i.%i.%i\n", transfer_buffer[0],
+                               transfer_buffer[1], transfer_buffer[2]);
+       }
 
        if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID ||
                        priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) {
@@ -393,12 +397,20 @@ static int kobil_tiocmget(struct tty_struct *tty)
                          transfer_buffer_length,
                          KOBIL_TIMEOUT);
 
-       dev_dbg(&port->dev, "%s - Send get_status_line_state URB returns: %i. Statusline: %02x\n",
-               __func__, result, transfer_buffer[0]);
+       dev_dbg(&port->dev, "Send get_status_line_state URB returns: %i\n",
+                       result);
+       if (result < 1) {
+               if (result >= 0)
+                       result = -EIO;
+               goto out_free;
+       }
+
+       dev_dbg(&port->dev, "Statusline: %02x\n", transfer_buffer[0]);
 
        result = 0;
        if ((transfer_buffer[0] & SUSBCR_GSL_DSR) != 0)
                result = TIOCM_DSR;
+out_free:
        kfree(transfer_buffer);
        return result;
 }
index bd57630..2710952 100644 (file)
@@ -340,14 +340,15 @@ static void async_complete(struct urb *urb)
 {
        struct urbtracker *urbtrack = urb->context;
        int status = urb->status;
+       unsigned long flags;
 
        if (unlikely(status))
                dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d\n", __func__, status);
 
        /* remove the urbtracker from the active_urbs list */
-       spin_lock(&urbtrack->mos_parport->listlock);
+       spin_lock_irqsave(&urbtrack->mos_parport->listlock, flags);
        list_del(&urbtrack->urblist_entry);
-       spin_unlock(&urbtrack->mos_parport->listlock);
+       spin_unlock_irqrestore(&urbtrack->mos_parport->listlock, flags);
        kref_put(&urbtrack->ref_count, destroy_urbtracker);
 }
 
@@ -1526,8 +1527,6 @@ static void change_port_settings(struct tty_struct *tty,
        struct usb_serial *serial;
        int baud;
        unsigned cflag;
-       unsigned iflag;
-       __u8 mask = 0xff;
        __u8 lData;
        __u8 lParity;
        __u8 lStop;
@@ -1551,23 +1550,19 @@ static void change_port_settings(struct tty_struct *tty,
        lParity = 0x00; /* No parity */
 
        cflag = tty->termios.c_cflag;
-       iflag = tty->termios.c_iflag;
 
        /* Change the number of bits */
        switch (cflag & CSIZE) {
        case CS5:
                lData = UART_LCR_WLEN5;
-               mask = 0x1f;
                break;
 
        case CS6:
                lData = UART_LCR_WLEN6;
-               mask = 0x3f;
                break;
 
        case CS7:
                lData = UART_LCR_WLEN7;
-               mask = 0x7f;
                break;
        default:
        case CS8:
@@ -1685,11 +1680,8 @@ static void mos7720_set_termios(struct tty_struct *tty,
                struct usb_serial_port *port, struct ktermios *old_termios)
 {
        int status;
-       struct usb_serial *serial;
        struct moschip_port *mos7720_port;
 
-       serial = port->serial;
-
        mos7720_port = usb_get_serial_port_data(port);
 
        if (mos7720_port == NULL)
index b580b4c..b42bad8 100644 (file)
@@ -805,18 +805,19 @@ static void mos7840_bulk_out_data_callback(struct urb *urb)
        struct moschip_port *mos7840_port;
        struct usb_serial_port *port;
        int status = urb->status;
+       unsigned long flags;
        int i;
 
        mos7840_port = urb->context;
        port = mos7840_port->port;
-       spin_lock(&mos7840_port->pool_lock);
+       spin_lock_irqsave(&mos7840_port->pool_lock, flags);
        for (i = 0; i < NUM_URBS; i++) {
                if (urb == mos7840_port->write_urb_pool[i]) {
                        mos7840_port->busy[i] = 0;
                        break;
                }
        }
-       spin_unlock(&mos7840_port->pool_lock);
+       spin_unlock_irqrestore(&mos7840_port->pool_lock, flags);
 
        if (status) {
                dev_dbg(&port->dev, "nonzero write bulk status received:%d\n", status);
index 664e61f..0215b70 100644 (file)
@@ -196,6 +196,8 @@ static void option_instat_callback(struct urb *urb);
 #define DELL_PRODUCT_5800_V2_MINICARD_VZW      0x8196  /* Novatel E362 */
 #define DELL_PRODUCT_5804_MINICARD_ATT         0x819b  /* Novatel E371 */
 
+#define DELL_PRODUCT_5821E                     0x81d7
+
 #define KYOCERA_VENDOR_ID                      0x0c88
 #define KYOCERA_PRODUCT_KPC650                 0x17da
 #define KYOCERA_PRODUCT_KPC680                 0x180a
@@ -1030,6 +1032,8 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5800_MINICARD_VZW, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5800_V2_MINICARD_VZW, 0xff, 0xff, 0xff) },
        { USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5804_MINICARD_ATT, 0xff, 0xff, 0xff) },
+       { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5821E),
+         .driver_info = RSVD(0) | RSVD(1) | RSVD(6) },
        { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) },   /* ADU-E100, ADU-310 */
        { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) },
        { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_620UW) },
index 5d1a193..e41f725 100644 (file)
@@ -52,6 +52,8 @@ static const struct usb_device_id id_table[] = {
                .driver_info = PL2303_QUIRK_ENDPOINT_HACK },
        { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_UC485),
                .driver_info = PL2303_QUIRK_ENDPOINT_HACK },
+       { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_UC232B),
+               .driver_info = PL2303_QUIRK_ENDPOINT_HACK },
        { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID2) },
        { USB_DEVICE(ATEN_VENDOR_ID2, ATEN_PRODUCT_ID) },
        { USB_DEVICE(ELCOM_VENDOR_ID, ELCOM_PRODUCT_ID) },
index fcd7239..26965cc 100644 (file)
@@ -24,6 +24,7 @@
 #define ATEN_VENDOR_ID2                0x0547
 #define ATEN_PRODUCT_ID                0x2008
 #define ATEN_PRODUCT_UC485     0x2021
+#define ATEN_PRODUCT_UC232B    0x2022
 #define ATEN_PRODUCT_ID2       0x2118
 
 #define IODATA_VENDOR_ID       0x04bb
index 958e12e..b61c2a9 100644 (file)
@@ -194,7 +194,7 @@ static inline int qt2_getregister(struct usb_device *dev,
        ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
                              QT_SET_GET_REGISTER, 0xc0, reg,
                              uart, data, sizeof(*data), QT2_USB_TIMEOUT);
-       if (ret < sizeof(*data)) {
+       if (ret < (int)sizeof(*data)) {
                if (ret >= 0)
                        ret = -EIO;
        }
@@ -621,16 +621,17 @@ static void qt2_write_bulk_callback(struct urb *urb)
 {
        struct usb_serial_port *port;
        struct qt2_port_private *port_priv;
+       unsigned long flags;
 
        port = urb->context;
        port_priv = usb_get_serial_port_data(port);
 
-       spin_lock(&port_priv->urb_lock);
+       spin_lock_irqsave(&port_priv->urb_lock, flags);
 
        port_priv->urb_in_use = false;
        usb_serial_port_softint(port);
 
-       spin_unlock(&port_priv->urb_lock);
+       spin_unlock_irqrestore(&port_priv->urb_lock, flags);
 
 }
 
index d189f95..a43263a 100644 (file)
@@ -409,6 +409,7 @@ static void sierra_outdat_callback(struct urb *urb)
        struct sierra_port_private *portdata = usb_get_serial_port_data(port);
        struct sierra_intf_private *intfdata;
        int status = urb->status;
+       unsigned long flags;
 
        intfdata = usb_get_serial_data(port->serial);
 
@@ -419,12 +420,12 @@ static void sierra_outdat_callback(struct urb *urb)
                dev_dbg(&port->dev, "%s - nonzero write bulk status "
                    "received: %d\n", __func__, status);
 
-       spin_lock(&portdata->lock);
+       spin_lock_irqsave(&portdata->lock, flags);
        --portdata->outstanding_urbs;
-       spin_unlock(&portdata->lock);
-       spin_lock(&intfdata->susp_lock);
+       spin_unlock_irqrestore(&portdata->lock, flags);
+       spin_lock_irqsave(&intfdata->susp_lock, flags);
        --intfdata->in_flight;
-       spin_unlock(&intfdata->susp_lock);
+       spin_unlock_irqrestore(&intfdata->susp_lock, flags);
 
        usb_serial_port_softint(port);
 }
@@ -770,9 +771,9 @@ static void sierra_close(struct usb_serial_port *port)
                kfree(urb->transfer_buffer);
                usb_free_urb(urb);
                usb_autopm_put_interface_async(serial->interface);
-               spin_lock(&portdata->lock);
+               spin_lock_irq(&portdata->lock);
                portdata->outstanding_urbs--;
-               spin_unlock(&portdata->lock);
+               spin_unlock_irq(&portdata->lock);
        }
 
        sierra_stop_rx_urbs(port);
index 2083c26..0900b47 100644 (file)
@@ -104,7 +104,7 @@ static inline int ssu100_getregister(struct usb_device *dev,
        ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
                              QT_SET_GET_REGISTER, 0xc0, reg,
                              uart, data, sizeof(*data), 300);
-       if (ret < sizeof(*data)) {
+       if (ret < (int)sizeof(*data)) {
                if (ret >= 0)
                        ret = -EIO;
        }
index cd2f8dc..6ca24e8 100644 (file)
@@ -35,6 +35,7 @@ static void symbol_int_callback(struct urb *urb)
        struct symbol_private *priv = usb_get_serial_port_data(port);
        unsigned char *data = urb->transfer_buffer;
        int status = urb->status;
+       unsigned long flags;
        int result;
        int data_length;
 
@@ -73,7 +74,7 @@ static void symbol_int_callback(struct urb *urb)
        }
 
 exit:
-       spin_lock(&priv->lock);
+       spin_lock_irqsave(&priv->lock, flags);
 
        /* Continue trying to always read if we should */
        if (!priv->throttled) {
@@ -84,7 +85,7 @@ exit:
                                                        __func__, result);
        } else
                priv->actually_throttled = true;
-       spin_unlock(&priv->lock);
+       spin_unlock_irqrestore(&priv->lock, flags);
 }
 
 static int symbol_open(struct tty_struct *tty, struct usb_serial_port *port)
index 6b22857..3010878 100644 (file)
@@ -1215,6 +1215,7 @@ static void ti_bulk_in_callback(struct urb *urb)
        struct usb_serial_port *port = tport->tp_port;
        struct device *dev = &urb->dev->dev;
        int status = urb->status;
+       unsigned long flags;
        int retval = 0;
 
        switch (status) {
@@ -1247,20 +1248,20 @@ static void ti_bulk_in_callback(struct urb *urb)
                                __func__);
                else
                        ti_recv(port, urb->transfer_buffer, urb->actual_length);
-               spin_lock(&tport->tp_lock);
+               spin_lock_irqsave(&tport->tp_lock, flags);
                port->icount.rx += urb->actual_length;
-               spin_unlock(&tport->tp_lock);
+               spin_unlock_irqrestore(&tport->tp_lock, flags);
        }
 
 exit:
        /* continue to read unless stopping */
-       spin_lock(&tport->tp_lock);
+       spin_lock_irqsave(&tport->tp_lock, flags);
        if (tport->tp_read_urb_state == TI_READ_URB_RUNNING)
                retval = usb_submit_urb(urb, GFP_ATOMIC);
        else if (tport->tp_read_urb_state == TI_READ_URB_STOPPING)
                tport->tp_read_urb_state = TI_READ_URB_STOPPED;
 
-       spin_unlock(&tport->tp_lock);
+       spin_unlock_irqrestore(&tport->tp_lock, flags);
        if (retval)
                dev_err(dev, "%s - resubmit read urb failed, %d\n",
                        __func__, retval);
index 107e64c..912472f 100644 (file)
@@ -326,6 +326,7 @@ static void usb_wwan_outdat_callback(struct urb *urb)
        struct usb_serial_port *port;
        struct usb_wwan_port_private *portdata;
        struct usb_wwan_intf_private *intfdata;
+       unsigned long flags;
        int i;
 
        port = urb->context;
@@ -334,9 +335,9 @@ static void usb_wwan_outdat_callback(struct urb *urb)
        usb_serial_port_softint(port);
        usb_autopm_put_interface_async(port->serial->interface);
        portdata = usb_get_serial_port_data(port);
-       spin_lock(&intfdata->susp_lock);
+       spin_lock_irqsave(&intfdata->susp_lock, flags);
        intfdata->in_flight--;
-       spin_unlock(&intfdata->susp_lock);
+       spin_unlock_irqrestore(&intfdata->susp_lock, flags);
 
        for (i = 0; i < N_OUT_URB; ++i) {
                if (portdata->out_urbs[i] == urb) {
index 2c8eab1..00878c3 100644 (file)
@@ -56,6 +56,22 @@ config TYPEC_TCPM
 
 if TYPEC_TCPM
 
+config TYPEC_TCPCI
+       tristate "Type-C Port Controller Interface driver"
+       depends on I2C
+       select REGMAP_I2C
+       help
+         Type-C Port Controller driver for TCPCI-compliant controller.
+
+config TYPEC_RT1711H
+       tristate "Richtek RT1711H Type-C chip driver"
+       depends on I2C
+       select TYPEC_TCPCI
+       help
+         Richtek RT1711H Type-C chip driver that works with
+         Type-C Port Controller Manager to provide USB PD and USB
+         Type-C functionalities.
+
 source "drivers/usb/typec/fusb302/Kconfig"
 
 config TYPEC_WCOVE
@@ -88,4 +104,6 @@ config TYPEC_TPS6598X
 
 source "drivers/usb/typec/mux/Kconfig"
 
+source "drivers/usb/typec/altmodes/Kconfig"
+
 endif # TYPEC
index 1f599a6..45b0aef 100644 (file)
@@ -1,9 +1,12 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_TYPEC)            += typec.o
-typec-y                                := class.o mux.o
+typec-y                                := class.o mux.o bus.o
+obj-$(CONFIG_TYPEC)            += altmodes/
 obj-$(CONFIG_TYPEC_TCPM)       += tcpm.o
 obj-y                          += fusb302/
 obj-$(CONFIG_TYPEC_WCOVE)      += typec_wcove.o
 obj-$(CONFIG_TYPEC_UCSI)       += ucsi/
 obj-$(CONFIG_TYPEC_TPS6598X)   += tps6598x.o
 obj-$(CONFIG_TYPEC)            += mux/
+obj-$(CONFIG_TYPEC_TCPCI)      += tcpci.o
+obj-$(CONFIG_TYPEC_RT1711H)    += tcpci_rt1711h.o
diff --git a/drivers/usb/typec/altmodes/Kconfig b/drivers/usb/typec/altmodes/Kconfig
new file mode 100644 (file)
index 0000000..efef2a6
--- /dev/null
@@ -0,0 +1,14 @@
+
+menu "USB Type-C Alternate Mode drivers"
+
+config TYPEC_DP_ALTMODE
+       tristate "DisplayPort Alternate Mode driver"
+       help
+         DisplayPort USB Type-C Alternate Mode allows DisplayPort
+         displays and adapters to be attached to the USB Type-C
+         connectors on the system.
+
+         To compile this driver as a module, choose M here: the
+         module will be called typec_displayport.
+
+endmenu
diff --git a/drivers/usb/typec/altmodes/Makefile b/drivers/usb/typec/altmodes/Makefile
new file mode 100644 (file)
index 0000000..5caf094
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_TYPEC_DP_ALTMODE)         += typec_displayport.o
+typec_displayport-y                    := displayport.o
diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c
new file mode 100644 (file)
index 0000000..3f06e94
--- /dev/null
@@ -0,0 +1,580 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * USB Typec-C DisplayPort Alternate Mode driver
+ *
+ * Copyright (C) 2018 Intel Corporation
+ * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+ *
+ * DisplayPort is trademark of VESA (www.vesa.org)
+ */
+
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/usb/pd_vdo.h>
+#include <linux/usb/typec_dp.h>
+
+#define DP_HEADER(cmd)                 (VDO(USB_TYPEC_DP_SID, 1, cmd) | \
+                                        VDO_OPOS(USB_TYPEC_DP_MODE))
+
+enum {
+       DP_CONF_USB,
+       DP_CONF_DFP_D,
+       DP_CONF_UFP_D,
+       DP_CONF_DUAL_D,
+};
+
+/* Helper for setting/getting the pin assignement value to the configuration */
+#define DP_CONF_SET_PIN_ASSIGN(_a_)    ((_a_) << 8)
+#define DP_CONF_GET_PIN_ASSIGN(_conf_) (((_conf_) & GENMASK(15, 8)) >> 8)
+
+/* Pin assignments that use USB3.1 Gen2 signaling to carry DP protocol */
+#define DP_PIN_ASSIGN_GEN2_BR_MASK     (BIT(DP_PIN_ASSIGN_A) | \
+                                        BIT(DP_PIN_ASSIGN_B))
+
+/* Pin assignments that use DP v1.3 signaling to carry DP protocol */
+#define DP_PIN_ASSIGN_DP_BR_MASK       (BIT(DP_PIN_ASSIGN_C) | \
+                                        BIT(DP_PIN_ASSIGN_D) | \
+                                        BIT(DP_PIN_ASSIGN_E) | \
+                                        BIT(DP_PIN_ASSIGN_F))
+
+/* DP only pin assignments */
+#define DP_PIN_ASSIGN_DP_ONLY_MASK     (BIT(DP_PIN_ASSIGN_A) | \
+                                        BIT(DP_PIN_ASSIGN_C) | \
+                                        BIT(DP_PIN_ASSIGN_E))
+
+/* Pin assignments where one channel is for USB */
+#define DP_PIN_ASSIGN_MULTI_FUNC_MASK  (BIT(DP_PIN_ASSIGN_B) | \
+                                        BIT(DP_PIN_ASSIGN_D) | \
+                                        BIT(DP_PIN_ASSIGN_F))
+
+enum dp_state {
+       DP_STATE_IDLE,
+       DP_STATE_ENTER,
+       DP_STATE_UPDATE,
+       DP_STATE_CONFIGURE,
+       DP_STATE_EXIT,
+};
+
+struct dp_altmode {
+       struct typec_displayport_data data;
+
+       enum dp_state state;
+
+       struct mutex lock; /* device lock */
+       struct work_struct work;
+       struct typec_altmode *alt;
+       const struct typec_altmode *port;
+};
+
+static int dp_altmode_notify(struct dp_altmode *dp)
+{
+       u8 state = get_count_order(DP_CONF_GET_PIN_ASSIGN(dp->data.conf));
+
+       return typec_altmode_notify(dp->alt, TYPEC_MODAL_STATE(state),
+                                  &dp->data);
+}
+
+static int dp_altmode_configure(struct dp_altmode *dp, u8 con)
+{
+       u32 conf = DP_CONF_SIGNALING_DP; /* Only DP signaling supported */
+       u8 pin_assign = 0;
+
+       switch (con) {
+       case DP_STATUS_CON_DISABLED:
+               return 0;
+       case DP_STATUS_CON_DFP_D:
+               conf |= DP_CONF_UFP_U_AS_DFP_D;
+               pin_assign = DP_CAP_UFP_D_PIN_ASSIGN(dp->alt->vdo) &
+                            DP_CAP_DFP_D_PIN_ASSIGN(dp->port->vdo);
+               break;
+       case DP_STATUS_CON_UFP_D:
+       case DP_STATUS_CON_BOTH: /* NOTE: First acting as DP source */
+               conf |= DP_CONF_UFP_U_AS_UFP_D;
+               pin_assign = DP_CAP_DFP_D_PIN_ASSIGN(dp->alt->vdo) &
+                            DP_CAP_UFP_D_PIN_ASSIGN(dp->port->vdo);
+               break;
+       default:
+               break;
+       }
+
+       /* Determining the initial pin assignment. */
+       if (!DP_CONF_GET_PIN_ASSIGN(dp->data.conf)) {
+               /* Is USB together with DP preferred */
+               if (dp->data.status & DP_STATUS_PREFER_MULTI_FUNC &&
+                   pin_assign & DP_PIN_ASSIGN_MULTI_FUNC_MASK)
+                       pin_assign &= DP_PIN_ASSIGN_MULTI_FUNC_MASK;
+               else
+                       pin_assign &= DP_PIN_ASSIGN_DP_ONLY_MASK;
+
+               if (!pin_assign)
+                       return -EINVAL;
+
+               conf |= DP_CONF_SET_PIN_ASSIGN(pin_assign);
+       }
+
+       dp->data.conf = conf;
+
+       return 0;
+}
+
+static int dp_altmode_status_update(struct dp_altmode *dp)
+{
+       bool configured = !!DP_CONF_GET_PIN_ASSIGN(dp->data.conf);
+       u8 con = DP_STATUS_CONNECTION(dp->data.status);
+       int ret = 0;
+
+       if (configured && (dp->data.status & DP_STATUS_SWITCH_TO_USB)) {
+               dp->data.conf = 0;
+               dp->state = DP_STATE_CONFIGURE;
+       } else if (dp->data.status & DP_STATUS_EXIT_DP_MODE) {
+               dp->state = DP_STATE_EXIT;
+       } else if (!(con & DP_CONF_CURRENTLY(dp->data.conf))) {
+               ret = dp_altmode_configure(dp, con);
+               if (!ret)
+                       dp->state = DP_STATE_CONFIGURE;
+       }
+
+       return ret;
+}
+
+static int dp_altmode_configured(struct dp_altmode *dp)
+{
+       int ret;
+
+       sysfs_notify(&dp->alt->dev.kobj, "displayport", "configuration");
+
+       if (!dp->data.conf)
+               return typec_altmode_notify(dp->alt, TYPEC_STATE_USB,
+                                           &dp->data);
+
+       ret = dp_altmode_notify(dp);
+       if (ret)
+               return ret;
+
+       sysfs_notify(&dp->alt->dev.kobj, "displayport", "pin_assignment");
+
+       return 0;
+}
+
+static int dp_altmode_configure_vdm(struct dp_altmode *dp, u32 conf)
+{
+       u32 header = DP_HEADER(DP_CMD_CONFIGURE);
+       int ret;
+
+       ret = typec_altmode_notify(dp->alt, TYPEC_STATE_SAFE, &dp->data);
+       if (ret) {
+               dev_err(&dp->alt->dev,
+                       "unable to put to connector to safe mode\n");
+               return ret;
+       }
+
+       ret = typec_altmode_vdm(dp->alt, header, &conf, 2);
+       if (ret) {
+               if (DP_CONF_GET_PIN_ASSIGN(dp->data.conf))
+                       dp_altmode_notify(dp);
+               else
+                       typec_altmode_notify(dp->alt, TYPEC_STATE_USB,
+                                            &dp->data);
+       }
+
+       return ret;
+}
+
+static void dp_altmode_work(struct work_struct *work)
+{
+       struct dp_altmode *dp = container_of(work, struct dp_altmode, work);
+       u32 header;
+       u32 vdo;
+       int ret;
+
+       mutex_lock(&dp->lock);
+
+       switch (dp->state) {
+       case DP_STATE_ENTER:
+               ret = typec_altmode_enter(dp->alt);
+               if (ret)
+                       dev_err(&dp->alt->dev, "failed to enter mode\n");
+               break;
+       case DP_STATE_UPDATE:
+               header = DP_HEADER(DP_CMD_STATUS_UPDATE);
+               vdo = 1;
+               ret = typec_altmode_vdm(dp->alt, header, &vdo, 2);
+               if (ret)
+                       dev_err(&dp->alt->dev,
+                               "unable to send Status Update command (%d)\n",
+                               ret);
+               break;
+       case DP_STATE_CONFIGURE:
+               ret = dp_altmode_configure_vdm(dp, dp->data.conf);
+               if (ret)
+                       dev_err(&dp->alt->dev,
+                               "unable to send Configure command (%d)\n", ret);
+               break;
+       case DP_STATE_EXIT:
+               if (typec_altmode_exit(dp->alt))
+                       dev_err(&dp->alt->dev, "Exit Mode Failed!\n");
+               break;
+       default:
+               break;
+       }
+
+       dp->state = DP_STATE_IDLE;
+
+       mutex_unlock(&dp->lock);
+}
+
+static void dp_altmode_attention(struct typec_altmode *alt, const u32 vdo)
+{
+       struct dp_altmode *dp = typec_altmode_get_drvdata(alt);
+       u8 old_state;
+
+       mutex_lock(&dp->lock);
+
+       old_state = dp->state;
+       dp->data.status = vdo;
+
+       if (old_state != DP_STATE_IDLE)
+               dev_warn(&alt->dev, "ATTENTION while processing state %d\n",
+                        old_state);
+
+       if (dp_altmode_status_update(dp))
+               dev_warn(&alt->dev, "%s: status update failed\n", __func__);
+
+       if (dp_altmode_notify(dp))
+               dev_err(&alt->dev, "%s: notification failed\n", __func__);
+
+       if (old_state == DP_STATE_IDLE && dp->state != DP_STATE_IDLE)
+               schedule_work(&dp->work);
+
+       mutex_unlock(&dp->lock);
+}
+
+static int dp_altmode_vdm(struct typec_altmode *alt,
+                         const u32 hdr, const u32 *vdo, int count)
+{
+       struct dp_altmode *dp = typec_altmode_get_drvdata(alt);
+       int cmd_type = PD_VDO_CMDT(hdr);
+       int cmd = PD_VDO_CMD(hdr);
+       int ret = 0;
+
+       mutex_lock(&dp->lock);
+
+       if (dp->state != DP_STATE_IDLE) {
+               ret = -EBUSY;
+               goto err_unlock;
+       }
+
+       switch (cmd_type) {
+       case CMDT_RSP_ACK:
+               switch (cmd) {
+               case CMD_ENTER_MODE:
+                       dp->state = DP_STATE_UPDATE;
+                       break;
+               case CMD_EXIT_MODE:
+                       dp->data.status = 0;
+                       dp->data.conf = 0;
+                       break;
+               case DP_CMD_STATUS_UPDATE:
+                       dp->data.status = *vdo;
+                       ret = dp_altmode_status_update(dp);
+                       break;
+               case DP_CMD_CONFIGURE:
+                       ret = dp_altmode_configured(dp);
+                       break;
+               default:
+                       break;
+               }
+               break;
+       case CMDT_RSP_NAK:
+               switch (cmd) {
+               case DP_CMD_CONFIGURE:
+                       dp->data.conf = 0;
+                       ret = dp_altmode_configured(dp);
+                       break;
+               default:
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
+
+       if (dp->state != DP_STATE_IDLE)
+               schedule_work(&dp->work);
+
+err_unlock:
+       mutex_unlock(&dp->lock);
+       return ret;
+}
+
+static int dp_altmode_activate(struct typec_altmode *alt, int activate)
+{
+       return activate ? typec_altmode_enter(alt) : typec_altmode_exit(alt);
+}
+
+static const struct typec_altmode_ops dp_altmode_ops = {
+       .attention = dp_altmode_attention,
+       .vdm = dp_altmode_vdm,
+       .activate = dp_altmode_activate,
+};
+
+static const char * const configurations[] = {
+       [DP_CONF_USB]   = "USB",
+       [DP_CONF_DFP_D] = "source",
+       [DP_CONF_UFP_D] = "sink",
+};
+
+static ssize_t
+configuration_store(struct device *dev, struct device_attribute *attr,
+                   const char *buf, size_t size)
+{
+       struct dp_altmode *dp = dev_get_drvdata(dev);
+       u32 conf;
+       u32 cap;
+       int con;
+       int ret = 0;
+
+       con = sysfs_match_string(configurations, buf);
+       if (con < 0)
+               return con;
+
+       mutex_lock(&dp->lock);
+
+       if (dp->state != DP_STATE_IDLE) {
+               ret = -EBUSY;
+               goto err_unlock;
+       }
+
+       cap = DP_CAP_CAPABILITY(dp->alt->vdo);
+
+       if ((con == DP_CONF_DFP_D && !(cap & DP_CAP_DFP_D)) ||
+           (con == DP_CONF_UFP_D && !(cap & DP_CAP_UFP_D))) {
+               ret = -EINVAL;
+               goto err_unlock;
+       }
+
+       conf = dp->data.conf & ~DP_CONF_DUAL_D;
+       conf |= con;
+
+       if (dp->alt->active) {
+               ret = dp_altmode_configure_vdm(dp, conf);
+               if (ret)
+                       goto err_unlock;
+       }
+
+       dp->data.conf = conf;
+
+err_unlock:
+       mutex_unlock(&dp->lock);
+
+       return ret ? ret : size;
+}
+
+static ssize_t configuration_show(struct device *dev,
+                                 struct device_attribute *attr, char *buf)
+{
+       struct dp_altmode *dp = dev_get_drvdata(dev);
+       int len;
+       u8 cap;
+       u8 cur;
+       int i;
+
+       mutex_lock(&dp->lock);
+
+       cap = DP_CAP_CAPABILITY(dp->alt->vdo);
+       cur = DP_CONF_CURRENTLY(dp->data.conf);
+
+       len = sprintf(buf, "%s ", cur ? "USB" : "[USB]");
+
+       for (i = 1; i < ARRAY_SIZE(configurations); i++) {
+               if (i == cur)
+                       len += sprintf(buf + len, "[%s] ", configurations[i]);
+               else if ((i == DP_CONF_DFP_D && cap & DP_CAP_DFP_D) ||
+                        (i == DP_CONF_UFP_D && cap & DP_CAP_UFP_D))
+                       len += sprintf(buf + len, "%s ", configurations[i]);
+       }
+
+       mutex_unlock(&dp->lock);
+
+       buf[len - 1] = '\n';
+       return len;
+}
+static DEVICE_ATTR_RW(configuration);
+
+static const char * const pin_assignments[] = {
+       [DP_PIN_ASSIGN_A] = "A",
+       [DP_PIN_ASSIGN_B] = "B",
+       [DP_PIN_ASSIGN_C] = "C",
+       [DP_PIN_ASSIGN_D] = "D",
+       [DP_PIN_ASSIGN_E] = "E",
+       [DP_PIN_ASSIGN_F] = "F",
+};
+
+static ssize_t
+pin_assignment_store(struct device *dev, struct device_attribute *attr,
+                    const char *buf, size_t size)
+{
+       struct dp_altmode *dp = dev_get_drvdata(dev);
+       u8 assignments;
+       u32 conf;
+       int ret;
+
+       ret = sysfs_match_string(pin_assignments, buf);
+       if (ret < 0)
+               return ret;
+
+       conf = DP_CONF_SET_PIN_ASSIGN(BIT(ret));
+       ret = 0;
+
+       mutex_lock(&dp->lock);
+
+       if (conf & dp->data.conf)
+               goto out_unlock;
+
+       if (dp->state != DP_STATE_IDLE) {
+               ret = -EBUSY;
+               goto out_unlock;
+       }
+
+       if (DP_CONF_CURRENTLY(dp->data.conf) == DP_CONF_DFP_D)
+               assignments = DP_CAP_UFP_D_PIN_ASSIGN(dp->alt->vdo);
+       else
+               assignments = DP_CAP_DFP_D_PIN_ASSIGN(dp->alt->vdo);
+
+       if (!(DP_CONF_GET_PIN_ASSIGN(conf) & assignments)) {
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+
+       conf |= dp->data.conf & ~DP_CONF_PIN_ASSIGNEMENT_MASK;
+
+       /* Only send Configure command if a configuration has been set */
+       if (dp->alt->active && DP_CONF_CURRENTLY(dp->data.conf)) {
+               ret = dp_altmode_configure_vdm(dp, conf);
+               if (ret)
+                       goto out_unlock;
+       }
+
+       dp->data.conf = conf;
+
+out_unlock:
+       mutex_unlock(&dp->lock);
+
+       return ret ? ret : size;
+}
+
+static ssize_t pin_assignment_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       struct dp_altmode *dp = dev_get_drvdata(dev);
+       u8 assignments;
+       int len = 0;
+       u8 cur;
+       int i;
+
+       mutex_lock(&dp->lock);
+
+       cur = get_count_order(DP_CONF_GET_PIN_ASSIGN(dp->data.conf));
+
+       if (DP_CONF_CURRENTLY(dp->data.conf) == DP_CONF_DFP_D)
+               assignments = DP_CAP_UFP_D_PIN_ASSIGN(dp->alt->vdo);
+       else
+               assignments = DP_CAP_DFP_D_PIN_ASSIGN(dp->alt->vdo);
+
+       for (i = 0; assignments; assignments >>= 1, i++) {
+               if (assignments & 1) {
+                       if (i == cur)
+                               len += sprintf(buf + len, "[%s] ",
+                                              pin_assignments[i]);
+                       else
+                               len += sprintf(buf + len, "%s ",
+                                              pin_assignments[i]);
+               }
+       }
+
+       mutex_unlock(&dp->lock);
+
+       buf[len - 1] = '\n';
+       return len;
+}
+static DEVICE_ATTR_RW(pin_assignment);
+
+static struct attribute *dp_altmode_attrs[] = {
+       &dev_attr_configuration.attr,
+       &dev_attr_pin_assignment.attr,
+       NULL
+};
+
+static const struct attribute_group dp_altmode_group = {
+       .name = "displayport",
+       .attrs = dp_altmode_attrs,
+};
+
+static int dp_altmode_probe(struct typec_altmode *alt)
+{
+       const struct typec_altmode *port = typec_altmode_get_partner(alt);
+       struct dp_altmode *dp;
+       int ret;
+
+       /* FIXME: Port can only be DFP_U. */
+
+       /* Make sure we have compatiple pin configurations */
+       if (!(DP_CAP_DFP_D_PIN_ASSIGN(port->vdo) &
+             DP_CAP_UFP_D_PIN_ASSIGN(alt->vdo)) &&
+           !(DP_CAP_UFP_D_PIN_ASSIGN(port->vdo) &
+             DP_CAP_DFP_D_PIN_ASSIGN(alt->vdo)))
+               return -ENODEV;
+
+       ret = sysfs_create_group(&alt->dev.kobj, &dp_altmode_group);
+       if (ret)
+               return ret;
+
+       dp = devm_kzalloc(&alt->dev, sizeof(*dp), GFP_KERNEL);
+       if (!dp)
+               return -ENOMEM;
+
+       INIT_WORK(&dp->work, dp_altmode_work);
+       mutex_init(&dp->lock);
+       dp->port = port;
+       dp->alt = alt;
+
+       alt->desc = "DisplayPort";
+       alt->ops = &dp_altmode_ops;
+
+       typec_altmode_set_drvdata(alt, dp);
+
+       dp->state = DP_STATE_ENTER;
+       schedule_work(&dp->work);
+
+       return 0;
+}
+
+static void dp_altmode_remove(struct typec_altmode *alt)
+{
+       struct dp_altmode *dp = typec_altmode_get_drvdata(alt);
+
+       sysfs_remove_group(&alt->dev.kobj, &dp_altmode_group);
+       cancel_work_sync(&dp->work);
+}
+
+static const struct typec_device_id dp_typec_id[] = {
+       { USB_TYPEC_DP_SID, USB_TYPEC_DP_MODE },
+       { },
+};
+MODULE_DEVICE_TABLE(typec, dp_typec_id);
+
+static struct typec_altmode_driver dp_altmode_driver = {
+       .id_table = dp_typec_id,
+       .probe = dp_altmode_probe,
+       .remove = dp_altmode_remove,
+       .driver = {
+               .name = "typec_displayport",
+               .owner = THIS_MODULE,
+       },
+};
+module_typec_altmode_driver(dp_altmode_driver);
+
+MODULE_AUTHOR("Heikki Krogerus <heikki.krogerus@linux.intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("DisplayPort Alternate Mode");
diff --git a/drivers/usb/typec/bus.c b/drivers/usb/typec/bus.c
new file mode 100644 (file)
index 0000000..95a2b10
--- /dev/null
@@ -0,0 +1,402 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * Bus for USB Type-C Alternate Modes
+ *
+ * Copyright (C) 2018 Intel Corporation
+ * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+ */
+
+#include <linux/usb/pd_vdo.h>
+
+#include "bus.h"
+
+static inline int typec_altmode_set_mux(struct altmode *alt, u8 state)
+{
+       return alt->mux ? alt->mux->set(alt->mux, state) : 0;
+}
+
+static int typec_altmode_set_state(struct typec_altmode *adev, int state)
+{
+       bool is_port = is_typec_port(adev->dev.parent);
+       struct altmode *port_altmode;
+       int ret;
+
+       port_altmode = is_port ? to_altmode(adev) : to_altmode(adev)->partner;
+
+       ret = typec_altmode_set_mux(port_altmode, state);
+       if (ret)
+               return ret;
+
+       blocking_notifier_call_chain(&port_altmode->nh, state, NULL);
+
+       return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+/* Common API */
+
+/**
+ * typec_altmode_notify - Communication between the OS and alternate mode driver
+ * @adev: Handle to the alternate mode
+ * @conf: Alternate mode specific configuration value
+ * @data: Alternate mode specific data
+ *
+ * The primary purpose for this function is to allow the alternate mode drivers
+ * to tell which pin configuration has been negotiated with the partner. That
+ * information will then be used for example to configure the muxes.
+ * Communication to the other direction is also possible, and low level device
+ * drivers can also send notifications to the alternate mode drivers. The actual
+ * communication will be specific for every SVID.
+ */
+int typec_altmode_notify(struct typec_altmode *adev,
+                        unsigned long conf, void *data)
+{
+       bool is_port;
+       struct altmode *altmode;
+       struct altmode *partner;
+       int ret;
+
+       if (!adev)
+               return 0;
+
+       altmode = to_altmode(adev);
+
+       if (!altmode->partner)
+               return -ENODEV;
+
+       is_port = is_typec_port(adev->dev.parent);
+       partner = altmode->partner;
+
+       ret = typec_altmode_set_mux(is_port ? altmode : partner, (u8)conf);
+       if (ret)
+               return ret;
+
+       blocking_notifier_call_chain(is_port ? &altmode->nh : &partner->nh,
+                                    conf, data);
+
+       if (partner->adev.ops && partner->adev.ops->notify)
+               return partner->adev.ops->notify(&partner->adev, conf, data);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(typec_altmode_notify);
+
+/**
+ * typec_altmode_enter - Enter Mode
+ * @adev: The alternate mode
+ *
+ * The alternate mode drivers use this function to enter mode. The port drivers
+ * use this to inform the alternate mode drivers that the partner has initiated
+ * Enter Mode command.
+ */
+int typec_altmode_enter(struct typec_altmode *adev)
+{
+       struct altmode *partner = to_altmode(adev)->partner;
+       struct typec_altmode *pdev = &partner->adev;
+       int ret;
+
+       if (!adev || adev->active)
+               return 0;
+
+       if (!pdev->ops || !pdev->ops->enter)
+               return -EOPNOTSUPP;
+
+       /* Moving to USB Safe State */
+       ret = typec_altmode_set_state(adev, TYPEC_STATE_SAFE);
+       if (ret)
+               return ret;
+
+       /* Enter Mode */
+       return pdev->ops->enter(pdev);
+}
+EXPORT_SYMBOL_GPL(typec_altmode_enter);
+
+/**
+ * typec_altmode_exit - Exit Mode
+ * @adev: The alternate mode
+ *
+ * The partner of @adev has initiated Exit Mode command.
+ */
+int typec_altmode_exit(struct typec_altmode *adev)
+{
+       struct altmode *partner = to_altmode(adev)->partner;
+       struct typec_altmode *pdev = &partner->adev;
+       int ret;
+
+       if (!adev || !adev->active)
+               return 0;
+
+       if (!pdev->ops || !pdev->ops->enter)
+               return -EOPNOTSUPP;
+
+       /* Moving to USB Safe State */
+       ret = typec_altmode_set_state(adev, TYPEC_STATE_SAFE);
+       if (ret)
+               return ret;
+
+       /* Exit Mode command */
+       return pdev->ops->exit(pdev);
+}
+EXPORT_SYMBOL_GPL(typec_altmode_exit);
+
+/**
+ * typec_altmode_attention - Attention command
+ * @adev: The alternate mode
+ * @vdo: VDO for the Attention command
+ *
+ * Notifies the partner of @adev about Attention command.
+ */
+void typec_altmode_attention(struct typec_altmode *adev, u32 vdo)
+{
+       struct typec_altmode *pdev = &to_altmode(adev)->partner->adev;
+
+       if (pdev->ops && pdev->ops->attention)
+               pdev->ops->attention(pdev, vdo);
+}
+EXPORT_SYMBOL_GPL(typec_altmode_attention);
+
+/**
+ * typec_altmode_vdm - Send Vendor Defined Messages (VDM) to the partner
+ * @adev: Alternate mode handle
+ * @header: VDM Header
+ * @vdo: Array of Vendor Defined Data Objects
+ * @count: Number of Data Objects
+ *
+ * The alternate mode drivers use this function for SVID specific communication
+ * with the partner. The port drivers use it to deliver the Structured VDMs
+ * received from the partners to the alternate mode drivers.
+ */
+int typec_altmode_vdm(struct typec_altmode *adev,
+                     const u32 header, const u32 *vdo, int count)
+{
+       struct typec_altmode *pdev;
+       struct altmode *altmode;
+
+       if (!adev)
+               return 0;
+
+       altmode = to_altmode(adev);
+
+       if (!altmode->partner)
+               return -ENODEV;
+
+       pdev = &altmode->partner->adev;
+
+       if (!pdev->ops || !pdev->ops->vdm)
+               return -EOPNOTSUPP;
+
+       return pdev->ops->vdm(pdev, header, vdo, count);
+}
+EXPORT_SYMBOL_GPL(typec_altmode_vdm);
+
+const struct typec_altmode *
+typec_altmode_get_partner(struct typec_altmode *adev)
+{
+       return &to_altmode(adev)->partner->adev;
+}
+EXPORT_SYMBOL_GPL(typec_altmode_get_partner);
+
+/* -------------------------------------------------------------------------- */
+/* API for the alternate mode drivers */
+
+/**
+ * typec_altmode_get_plug - Find cable plug alternate mode
+ * @adev: Handle to partner alternate mode
+ * @index: Cable plug index
+ *
+ * Increment reference count for cable plug alternate mode device. Returns
+ * handle to the cable plug alternate mode, or NULL if none is found.
+ */
+struct typec_altmode *typec_altmode_get_plug(struct typec_altmode *adev,
+                                            enum typec_plug_index index)
+{
+       struct altmode *port = to_altmode(adev)->partner;
+
+       if (port->plug[index]) {
+               get_device(&port->plug[index]->adev.dev);
+               return &port->plug[index]->adev;
+       }
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(typec_altmode_get_plug);
+
+/**
+ * typec_altmode_put_plug - Decrement cable plug alternate mode reference count
+ * @plug: Handle to the cable plug alternate mode
+ */
+void typec_altmode_put_plug(struct typec_altmode *plug)
+{
+       if (plug)
+               put_device(&plug->dev);
+}
+EXPORT_SYMBOL_GPL(typec_altmode_put_plug);
+
+int __typec_altmode_register_driver(struct typec_altmode_driver *drv,
+                                   struct module *module)
+{
+       if (!drv->probe)
+               return -EINVAL;
+
+       drv->driver.owner = module;
+       drv->driver.bus = &typec_bus;
+
+       return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(__typec_altmode_register_driver);
+
+void typec_altmode_unregister_driver(struct typec_altmode_driver *drv)
+{
+       driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL_GPL(typec_altmode_unregister_driver);
+
+/* -------------------------------------------------------------------------- */
+/* API for the port drivers */
+
+/**
+ * typec_match_altmode - Match SVID to an array of alternate modes
+ * @altmodes: Array of alternate modes
+ * @n: Number of elements in the array, or -1 for NULL termiated arrays
+ * @svid: Standard or Vendor ID to match with
+ *
+ * Return pointer to an alternate mode with SVID mathing @svid, or NULL when no
+ * match is found.
+ */
+struct typec_altmode *typec_match_altmode(struct typec_altmode **altmodes,
+                                         size_t n, u16 svid, u8 mode)
+{
+       int i;
+
+       for (i = 0; i < n; i++) {
+               if (!altmodes[i])
+                       break;
+               if (altmodes[i]->svid == svid && altmodes[i]->mode == mode)
+                       return altmodes[i];
+       }
+
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(typec_match_altmode);
+
+/* -------------------------------------------------------------------------- */
+
+static ssize_t
+description_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct typec_altmode *alt = to_typec_altmode(dev);
+
+       return sprintf(buf, "%s\n", alt->desc ? alt->desc : "");
+}
+static DEVICE_ATTR_RO(description);
+
+static struct attribute *typec_attrs[] = {
+       &dev_attr_description.attr,
+       NULL
+};
+ATTRIBUTE_GROUPS(typec);
+
+static int typec_match(struct device *dev, struct device_driver *driver)
+{
+       struct typec_altmode_driver *drv = to_altmode_driver(driver);
+       struct typec_altmode *altmode = to_typec_altmode(dev);
+       const struct typec_device_id *id;
+
+       for (id = drv->id_table; id->svid; id++)
+               if (id->svid == altmode->svid &&
+                   (id->mode == TYPEC_ANY_MODE || id->mode == altmode->mode))
+                       return 1;
+       return 0;
+}
+
+static int typec_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+       struct typec_altmode *altmode = to_typec_altmode(dev);
+
+       if (add_uevent_var(env, "SVID=%04X", altmode->svid))
+               return -ENOMEM;
+
+       if (add_uevent_var(env, "MODE=%u", altmode->mode))
+               return -ENOMEM;
+
+       return add_uevent_var(env, "MODALIAS=typec:id%04Xm%02X",
+                             altmode->svid, altmode->mode);
+}
+
+static int typec_altmode_create_links(struct altmode *alt)
+{
+       struct device *port_dev = &alt->partner->adev.dev;
+       struct device *dev = &alt->adev.dev;
+       int err;
+
+       err = sysfs_create_link(&dev->kobj, &port_dev->kobj, "port");
+       if (err)
+               return err;
+
+       err = sysfs_create_link(&port_dev->kobj, &dev->kobj, "partner");
+       if (err)
+               sysfs_remove_link(&dev->kobj, "port");
+
+       return err;
+}
+
+static void typec_altmode_remove_links(struct altmode *alt)
+{
+       sysfs_remove_link(&alt->partner->adev.dev.kobj, "partner");
+       sysfs_remove_link(&alt->adev.dev.kobj, "port");
+}
+
+static int typec_probe(struct device *dev)
+{
+       struct typec_altmode_driver *drv = to_altmode_driver(dev->driver);
+       struct typec_altmode *adev = to_typec_altmode(dev);
+       struct altmode *altmode = to_altmode(adev);
+       int ret;
+
+       /* Fail if the port does not support the alternate mode */
+       if (!altmode->partner)
+               return -ENODEV;
+
+       ret = typec_altmode_create_links(altmode);
+       if (ret) {
+               dev_warn(dev, "failed to create symlinks\n");
+               return ret;
+       }
+
+       ret = drv->probe(adev);
+       if (ret)
+               typec_altmode_remove_links(altmode);
+
+       return ret;
+}
+
+static int typec_remove(struct device *dev)
+{
+       struct typec_altmode_driver *drv = to_altmode_driver(dev->driver);
+       struct typec_altmode *adev = to_typec_altmode(dev);
+       struct altmode *altmode = to_altmode(adev);
+
+       typec_altmode_remove_links(altmode);
+
+       if (drv->remove)
+               drv->remove(to_typec_altmode(dev));
+
+       if (adev->active) {
+               WARN_ON(typec_altmode_set_state(adev, TYPEC_STATE_SAFE));
+               typec_altmode_update_active(adev, false);
+       }
+
+       adev->desc = NULL;
+       adev->ops = NULL;
+
+       return 0;
+}
+
+struct bus_type typec_bus = {
+       .name = "typec",
+       .dev_groups = typec_groups,
+       .match = typec_match,
+       .uevent = typec_uevent,
+       .probe = typec_probe,
+       .remove = typec_remove,
+};
diff --git a/drivers/usb/typec/bus.h b/drivers/usb/typec/bus.h
new file mode 100644 (file)
index 0000000..db40e61
--- /dev/null
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __USB_TYPEC_ALTMODE_H__
+#define __USB_TYPEC_ALTMODE_H__
+
+#include <linux/usb/typec_altmode.h>
+#include <linux/usb/typec_mux.h>
+
+struct bus_type;
+
+struct altmode {
+       unsigned int                    id;
+       struct typec_altmode            adev;
+       struct typec_mux                *mux;
+
+       enum typec_port_data            roles;
+
+       struct attribute                *attrs[5];
+       char                            group_name[8];
+       struct attribute_group          group;
+       const struct attribute_group    *groups[2];
+
+       struct altmode                  *partner;
+       struct altmode                  *plug[2];
+
+       struct blocking_notifier_head   nh;
+};
+
+#define to_altmode(d) container_of(d, struct altmode, adev)
+
+extern struct bus_type typec_bus;
+extern const struct device_type typec_altmode_dev_type;
+extern const struct device_type typec_port_dev_type;
+
+#define is_typec_altmode(_dev_) (_dev_->type == &typec_altmode_dev_type)
+#define is_typec_port(_dev_) (_dev_->type == &typec_port_dev_type)
+
+#endif /* __USB_TYPEC_ALTMODE_H__ */
index 53df10d..c202975 100644 (file)
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
-#include <linux/usb/typec.h>
-#include <linux/usb/typec_mux.h>
 
-struct typec_mode {
-       int                             index;
-       u32                             vdo;
-       char                            *desc;
-       enum typec_port_type            roles;
-
-       struct typec_altmode            *alt_mode;
-
-       unsigned int                    active:1;
-
-       char                            group_name[6];
-       struct attribute_group          group;
-       struct attribute                *attrs[5];
-       struct device_attribute         vdo_attr;
-       struct device_attribute         desc_attr;
-       struct device_attribute         active_attr;
-       struct device_attribute         roles_attr;
-};
-
-struct typec_altmode {
-       struct device                   dev;
-       u16                             svid;
-       int                             n_modes;
-       struct typec_mode               modes[ALTMODE_MAX_MODES];
-       const struct attribute_group    *mode_groups[ALTMODE_MAX_MODES];
-};
+#include "bus.h"
 
 struct typec_plug {
        struct device                   dev;
        enum typec_plug_index           index;
+       struct ida                      mode_ids;
 };
 
 struct typec_cable {
@@ -57,11 +31,13 @@ struct typec_partner {
        unsigned int                    usb_pd:1;
        struct usb_pd_identity          *identity;
        enum typec_accessory            accessory;
+       struct ida                      mode_ids;
 };
 
 struct typec_port {
        unsigned int                    id;
        struct device                   dev;
+       struct ida                      mode_ids;
 
        int                             prefer_role;
        enum typec_data_role            data_role;
@@ -82,17 +58,14 @@ struct typec_port {
 #define to_typec_plug(_dev_) container_of(_dev_, struct typec_plug, dev)
 #define to_typec_cable(_dev_) container_of(_dev_, struct typec_cable, dev)
 #define to_typec_partner(_dev_) container_of(_dev_, struct typec_partner, dev)
-#define to_altmode(_dev_) container_of(_dev_, struct typec_altmode, dev)
 
 static const struct device_type typec_partner_dev_type;
 static const struct device_type typec_cable_dev_type;
 static const struct device_type typec_plug_dev_type;
-static const struct device_type typec_port_dev_type;
 
 #define is_typec_partner(_dev_) (_dev_->type == &typec_partner_dev_type)
 #define is_typec_cable(_dev_) (_dev_->type == &typec_cable_dev_type)
 #define is_typec_plug(_dev_) (_dev_->type == &typec_plug_dev_type)
-#define is_typec_port(_dev_) (_dev_->type == &typec_port_dev_type)
 
 static DEFINE_IDA(typec_index_ida);
 static struct class *typec_class;
@@ -174,28 +147,148 @@ static void typec_report_identity(struct device *dev)
 /* ------------------------------------------------------------------------- */
 /* Alternate Modes */
 
+static int altmode_match(struct device *dev, void *data)
+{
+       struct typec_altmode *adev = to_typec_altmode(dev);
+       struct typec_device_id *id = data;
+
+       if (!is_typec_altmode(dev))
+               return 0;
+
+       return ((adev->svid == id->svid) && (adev->mode == id->mode));
+}
+
+static void typec_altmode_set_partner(struct altmode *altmode)
+{
+       struct typec_altmode *adev = &altmode->adev;
+       struct typec_device_id id = { adev->svid, adev->mode, };
+       struct typec_port *port = typec_altmode2port(adev);
+       struct altmode *partner;
+       struct device *dev;
+
+       dev = device_find_child(&port->dev, &id, altmode_match);
+       if (!dev)
+               return;
+
+       /* Bind the port alt mode to the partner/plug alt mode. */
+       partner = to_altmode(to_typec_altmode(dev));
+       altmode->partner = partner;
+
+       /* Bind the partner/plug alt mode to the port alt mode. */
+       if (is_typec_plug(adev->dev.parent)) {
+               struct typec_plug *plug = to_typec_plug(adev->dev.parent);
+
+               partner->plug[plug->index] = altmode;
+       } else {
+               partner->partner = altmode;
+       }
+}
+
+static void typec_altmode_put_partner(struct altmode *altmode)
+{
+       struct altmode *partner = altmode->partner;
+       struct typec_altmode *adev;
+
+       if (!partner)
+               return;
+
+       adev = &partner->adev;
+
+       if (is_typec_plug(adev->dev.parent)) {
+               struct typec_plug *plug = to_typec_plug(adev->dev.parent);
+
+               partner->plug[plug->index] = NULL;
+       } else {
+               partner->partner = NULL;
+       }
+       put_device(&adev->dev);
+}
+
+static int __typec_port_match(struct device *dev, const void *name)
+{
+       return !strcmp((const char *)name, dev_name(dev));
+}
+
+static void *typec_port_match(struct device_connection *con, int ep, void *data)
+{
+       return class_find_device(typec_class, NULL, con->endpoint[ep],
+                                __typec_port_match);
+}
+
+struct typec_altmode *
+typec_altmode_register_notifier(struct device *dev, u16 svid, u8 mode,
+                               struct notifier_block *nb)
+{
+       struct typec_device_id id = { svid, mode, };
+       struct device *altmode_dev;
+       struct device *port_dev;
+       struct altmode *altmode;
+       int ret;
+
+       /* Find the port linked to the caller */
+       port_dev = device_connection_find_match(dev, NULL, NULL,
+                                               typec_port_match);
+       if (IS_ERR_OR_NULL(port_dev))
+               return port_dev ? ERR_CAST(port_dev) : ERR_PTR(-ENODEV);
+
+       /* Find the altmode with matching svid */
+       altmode_dev = device_find_child(port_dev, &id, altmode_match);
+
+       put_device(port_dev);
+
+       if (!altmode_dev)
+               return ERR_PTR(-ENODEV);
+
+       altmode = to_altmode(to_typec_altmode(altmode_dev));
+
+       /* Register notifier */
+       ret = blocking_notifier_chain_register(&altmode->nh, nb);
+       if (ret) {
+               put_device(altmode_dev);
+               return ERR_PTR(ret);
+       }
+
+       return &altmode->adev;
+}
+EXPORT_SYMBOL_GPL(typec_altmode_register_notifier);
+
+void typec_altmode_unregister_notifier(struct typec_altmode *adev,
+                                      struct notifier_block *nb)
+{
+       struct altmode *altmode = to_altmode(adev);
+
+       blocking_notifier_chain_unregister(&altmode->nh, nb);
+       put_device(&adev->dev);
+}
+EXPORT_SYMBOL_GPL(typec_altmode_unregister_notifier);
+
 /**
  * typec_altmode_update_active - Report Enter/Exit mode
- * @alt: Handle to the alternate mode
- * @mode: Mode index
+ * @adev: Handle to the alternate mode
  * @active: True when the mode has been entered
  *
  * If a partner or cable plug executes Enter/Exit Mode command successfully, the
  * drivers use this routine to report the updated state of the mode.
  */
-void typec_altmode_update_active(struct typec_altmode *alt, int mode,
-                                bool active)
+void typec_altmode_update_active(struct typec_altmode *adev, bool active)
 {
-       struct typec_mode *m = &alt->modes[mode];
        char dir[6];
 
-       if (m->active == active)
+       if (adev->active == active)
                return;
 
-       m->active = active;
-       snprintf(dir, sizeof(dir), "mode%d", mode);
-       sysfs_notify(&alt->dev.kobj, dir, "active");
-       kobject_uevent(&alt->dev.kobj, KOBJ_CHANGE);
+       if (!is_typec_port(adev->dev.parent)) {
+               if (!active)
+                       module_put(adev->dev.driver->owner);
+               else
+                       WARN_ON(!try_module_get(adev->dev.driver->owner));
+       }
+
+       adev->active = active;
+       snprintf(dir, sizeof(dir), "mode%d", adev->mode);
+       sysfs_notify(&adev->dev.kobj, dir, "active");
+       sysfs_notify(&adev->dev.kobj, NULL, "active");
+       kobject_uevent(&adev->dev.kobj, KOBJ_CHANGE);
 }
 EXPORT_SYMBOL_GPL(typec_altmode_update_active);
 
@@ -220,68 +313,78 @@ struct typec_port *typec_altmode2port(struct typec_altmode *alt)
 EXPORT_SYMBOL_GPL(typec_altmode2port);
 
 static ssize_t
-typec_altmode_vdo_show(struct device *dev, struct device_attribute *attr,
-                      char *buf)
+vdo_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct typec_mode *mode = container_of(attr, struct typec_mode,
-                                              vdo_attr);
+       struct typec_altmode *alt = to_typec_altmode(dev);
 
-       return sprintf(buf, "0x%08x\n", mode->vdo);
+       return sprintf(buf, "0x%08x\n", alt->vdo);
 }
+static DEVICE_ATTR_RO(vdo);
 
 static ssize_t
-typec_altmode_desc_show(struct device *dev, struct device_attribute *attr,
-                       char *buf)
+description_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct typec_mode *mode = container_of(attr, struct typec_mode,
-                                              desc_attr);
+       struct typec_altmode *alt = to_typec_altmode(dev);
 
-       return sprintf(buf, "%s\n", mode->desc ? mode->desc : "");
+       return sprintf(buf, "%s\n", alt->desc ? alt->desc : "");
 }
+static DEVICE_ATTR_RO(description);
 
 static ssize_t
-typec_altmode_active_show(struct device *dev, struct device_attribute *attr,
-                         char *buf)
+active_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct typec_mode *mode = container_of(attr, struct typec_mode,
-                                              active_attr);
+       struct typec_altmode *alt = to_typec_altmode(dev);
 
-       return sprintf(buf, "%s\n", mode->active ? "yes" : "no");
+       return sprintf(buf, "%s\n", alt->active ? "yes" : "no");
 }
 
-static ssize_t
-typec_altmode_active_store(struct device *dev, struct device_attribute *attr,
-                          const char *buf, size_t size)
+static ssize_t active_store(struct device *dev, struct device_attribute *attr,
+                           const char *buf, size_t size)
 {
-       struct typec_mode *mode = container_of(attr, struct typec_mode,
-                                              active_attr);
-       struct typec_port *port = typec_altmode2port(mode->alt_mode);
-       bool activate;
+       struct typec_altmode *adev = to_typec_altmode(dev);
+       struct altmode *altmode = to_altmode(adev);
+       bool enter;
        int ret;
 
-       if (!port->cap->activate_mode)
-               return -EOPNOTSUPP;
-
-       ret = kstrtobool(buf, &activate);
+       ret = kstrtobool(buf, &enter);
        if (ret)
                return ret;
 
-       ret = port->cap->activate_mode(port->cap, mode->index, activate);
-       if (ret)
-               return ret;
+       if (adev->active == enter)
+               return size;
+
+       if (is_typec_port(adev->dev.parent)) {
+               typec_altmode_update_active(adev, enter);
+
+               /* Make sure that the partner exits the mode before disabling */
+               if (altmode->partner && !enter && altmode->partner->adev.active)
+                       typec_altmode_exit(&altmode->partner->adev);
+       } else if (altmode->partner) {
+               if (enter && !altmode->partner->adev.active) {
+                       dev_warn(dev, "port has the mode disabled\n");
+                       return -EPERM;
+               }
+       }
+
+       /* Note: If there is no driver, the mode will not be entered */
+       if (adev->ops && adev->ops->activate) {
+               ret = adev->ops->activate(adev, enter);
+               if (ret)
+                       return ret;
+       }
 
        return size;
 }
+static DEVICE_ATTR_RW(active);
 
 static ssize_t
-typec_altmode_roles_show(struct device *dev, struct device_attribute *attr,
-                        char *buf)
+supported_roles_show(struct device *dev, struct device_attribute *attr,
+                    char *buf)
 {
-       struct typec_mode *mode = container_of(attr, struct typec_mode,
-                                              roles_attr);
+       struct altmode *alt = to_altmode(to_typec_altmode(dev));
        ssize_t ret;
 
-       switch (mode->roles) {
+       switch (alt->roles) {
        case TYPEC_PORT_SRC:
                ret = sprintf(buf, "source\n");
                break;
@@ -295,89 +398,74 @@ typec_altmode_roles_show(struct device *dev, struct device_attribute *attr,
        }
        return ret;
 }
+static DEVICE_ATTR_RO(supported_roles);
 
-static void typec_init_modes(struct typec_altmode *alt,
-                            const struct typec_mode_desc *desc, bool is_port)
+static ssize_t
+mode_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       int i;
-
-       for (i = 0; i < alt->n_modes; i++, desc++) {
-               struct typec_mode *mode = &alt->modes[i];
-
-               /* Not considering the human readable description critical */
-               mode->desc = kstrdup(desc->desc, GFP_KERNEL);
-               if (desc->desc && !mode->desc)
-                       dev_err(&alt->dev, "failed to copy mode%d desc\n", i);
-
-               mode->alt_mode = alt;
-               mode->vdo = desc->vdo;
-               mode->roles = desc->roles;
-               mode->index = desc->index;
-               sprintf(mode->group_name, "mode%d", desc->index);
-
-               sysfs_attr_init(&mode->vdo_attr.attr);
-               mode->vdo_attr.attr.name = "vdo";
-               mode->vdo_attr.attr.mode = 0444;
-               mode->vdo_attr.show = typec_altmode_vdo_show;
-
-               sysfs_attr_init(&mode->desc_attr.attr);
-               mode->desc_attr.attr.name = "description";
-               mode->desc_attr.attr.mode = 0444;
-               mode->desc_attr.show = typec_altmode_desc_show;
-
-               sysfs_attr_init(&mode->active_attr.attr);
-               mode->active_attr.attr.name = "active";
-               mode->active_attr.attr.mode = 0644;
-               mode->active_attr.show = typec_altmode_active_show;
-               mode->active_attr.store = typec_altmode_active_store;
-
-               mode->attrs[0] = &mode->vdo_attr.attr;
-               mode->attrs[1] = &mode->desc_attr.attr;
-               mode->attrs[2] = &mode->active_attr.attr;
-
-               /* With ports, list the roles that the mode is supported with */
-               if (is_port) {
-                       sysfs_attr_init(&mode->roles_attr.attr);
-                       mode->roles_attr.attr.name = "supported_roles";
-                       mode->roles_attr.attr.mode = 0444;
-                       mode->roles_attr.show = typec_altmode_roles_show;
-
-                       mode->attrs[3] = &mode->roles_attr.attr;
-               }
+       struct typec_altmode *adev = to_typec_altmode(dev);
 
-               mode->group.attrs = mode->attrs;
-               mode->group.name = mode->group_name;
-
-               alt->mode_groups[i] = &mode->group;
-       }
+       return sprintf(buf, "%u\n", adev->mode);
 }
+static DEVICE_ATTR_RO(mode);
 
-static ssize_t svid_show(struct device *dev, struct device_attribute *attr,
-                        char *buf)
+static ssize_t
+svid_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       struct typec_altmode *alt = to_altmode(dev);
+       struct typec_altmode *adev = to_typec_altmode(dev);
 
-       return sprintf(buf, "%04x\n", alt->svid);
+       return sprintf(buf, "%04x\n", adev->svid);
 }
 static DEVICE_ATTR_RO(svid);
 
 static struct attribute *typec_altmode_attrs[] = {
+       &dev_attr_active.attr,
+       &dev_attr_mode.attr,
        &dev_attr_svid.attr,
+       &dev_attr_vdo.attr,
        NULL
 };
 ATTRIBUTE_GROUPS(typec_altmode);
 
+static int altmode_id_get(struct device *dev)
+{
+       struct ida *ids;
+
+       if (is_typec_partner(dev))
+               ids = &to_typec_partner(dev)->mode_ids;
+       else if (is_typec_plug(dev))
+               ids = &to_typec_plug(dev)->mode_ids;
+       else
+               ids = &to_typec_port(dev)->mode_ids;
+
+       return ida_simple_get(ids, 0, 0, GFP_KERNEL);
+}
+
+static void altmode_id_remove(struct device *dev, int id)
+{
+       struct ida *ids;
+
+       if (is_typec_partner(dev))
+               ids = &to_typec_partner(dev)->mode_ids;
+       else if (is_typec_plug(dev))
+               ids = &to_typec_plug(dev)->mode_ids;
+       else
+               ids = &to_typec_port(dev)->mode_ids;
+
+       ida_simple_remove(ids, id);
+}
+
 static void typec_altmode_release(struct device *dev)
 {
-       struct typec_altmode *alt = to_altmode(dev);
-       int i;
+       struct altmode *alt = to_altmode(to_typec_altmode(dev));
+
+       typec_altmode_put_partner(alt);
 
-       for (i = 0; i < alt->n_modes; i++)
-               kfree(alt->modes[i].desc);
+       altmode_id_remove(alt->adev.dev.parent, alt->id);
        kfree(alt);
 }
 
-static const struct device_type typec_altmode_dev_type = {
+const struct device_type typec_altmode_dev_type = {
        .name = "typec_alternate_mode",
        .groups = typec_altmode_groups,
        .release = typec_altmode_release,
@@ -387,44 +475,74 @@ static struct typec_altmode *
 typec_register_altmode(struct device *parent,
                       const struct typec_altmode_desc *desc)
 {
-       struct typec_altmode *alt;
+       unsigned int id = altmode_id_get(parent);
+       bool is_port = is_typec_port(parent);
+       struct altmode *alt;
        int ret;
 
        alt = kzalloc(sizeof(*alt), GFP_KERNEL);
        if (!alt)
                return ERR_PTR(-ENOMEM);
 
-       alt->svid = desc->svid;
-       alt->n_modes = desc->n_modes;
-       typec_init_modes(alt, desc->modes, is_typec_port(parent));
+       alt->adev.svid = desc->svid;
+       alt->adev.mode = desc->mode;
+       alt->adev.vdo = desc->vdo;
+       alt->roles = desc->roles;
+       alt->id = id;
+
+       alt->attrs[0] = &dev_attr_vdo.attr;
+       alt->attrs[1] = &dev_attr_description.attr;
+       alt->attrs[2] = &dev_attr_active.attr;
+
+       if (is_port) {
+               alt->attrs[3] = &dev_attr_supported_roles.attr;
+               alt->adev.active = true; /* Enabled by default */
+       }
 
-       alt->dev.parent = parent;
-       alt->dev.groups = alt->mode_groups;
-       alt->dev.type = &typec_altmode_dev_type;
-       dev_set_name(&alt->dev, "svid-%04x", alt->svid);
+       sprintf(alt->group_name, "mode%d", desc->mode);
+       alt->group.name = alt->group_name;
+       alt->group.attrs = alt->attrs;
+       alt->groups[0] = &alt->group;
 
-       ret = device_register(&alt->dev);
+       alt->adev.dev.parent = parent;
+       alt->adev.dev.groups = alt->groups;
+       alt->adev.dev.type = &typec_altmode_dev_type;
+       dev_set_name(&alt->adev.dev, "%s.%u", dev_name(parent), id);
+
+       /* Link partners and plugs with the ports */
+       if (is_port)
+               BLOCKING_INIT_NOTIFIER_HEAD(&alt->nh);
+       else
+               typec_altmode_set_partner(alt);
+
+       /* The partners are bind to drivers */
+       if (is_typec_partner(parent))
+               alt->adev.dev.bus = &typec_bus;
+
+       ret = device_register(&alt->adev.dev);
        if (ret) {
                dev_err(parent, "failed to register alternate mode (%d)\n",
                        ret);
-               put_device(&alt->dev);
+               put_device(&alt->adev.dev);
                return ERR_PTR(ret);
        }
 
-       return alt;
+       return &alt->adev;
 }
 
 /**
  * typec_unregister_altmode - Unregister Alternate Mode
- * @alt: The alternate mode to be unregistered
+ * @adev: The alternate mode to be unregistered
  *
  * Unregister device created with typec_partner_register_altmode(),
  * typec_plug_register_altmode() or typec_port_register_altmode().
  */
-void typec_unregister_altmode(struct typec_altmode *alt)
+void typec_unregister_altmode(struct typec_altmode *adev)
 {
-       if (!IS_ERR_OR_NULL(alt))
-               device_unregister(&alt->dev);
+       if (IS_ERR_OR_NULL(adev))
+               return;
+       typec_mux_put(to_altmode(adev)->mux);
+       device_unregister(&adev->dev);
 }
 EXPORT_SYMBOL_GPL(typec_unregister_altmode);
 
@@ -462,6 +580,7 @@ static void typec_partner_release(struct device *dev)
 {
        struct typec_partner *partner = to_typec_partner(dev);
 
+       ida_destroy(&partner->mode_ids);
        kfree(partner);
 }
 
@@ -527,6 +646,7 @@ struct typec_partner *typec_register_partner(struct typec_port *port,
        if (!partner)
                return ERR_PTR(-ENOMEM);
 
+       ida_init(&partner->mode_ids);
        partner->usb_pd = desc->usb_pd;
        partner->accessory = desc->accessory;
 
@@ -575,6 +695,7 @@ static void typec_plug_release(struct device *dev)
 {
        struct typec_plug *plug = to_typec_plug(dev);
 
+       ida_destroy(&plug->mode_ids);
        kfree(plug);
 }
 
@@ -627,6 +748,7 @@ struct typec_plug *typec_register_plug(struct typec_cable *cable,
 
        sprintf(name, "plug%d", desc->index);
 
+       ida_init(&plug->mode_ids);
        plug->index = desc->index;
        plug->dev.class = typec_class;
        plug->dev.parent = &cable->dev;
@@ -796,12 +918,18 @@ static const char * const typec_data_roles[] = {
        [TYPEC_HOST]    = "host",
 };
 
-static const char * const typec_port_types[] = {
+static const char * const typec_port_power_roles[] = {
        [TYPEC_PORT_SRC] = "source",
        [TYPEC_PORT_SNK] = "sink",
        [TYPEC_PORT_DRP] = "dual",
 };
 
+static const char * const typec_port_data_roles[] = {
+       [TYPEC_PORT_DFP] = "host",
+       [TYPEC_PORT_UFP] = "device",
+       [TYPEC_PORT_DRD] = "dual",
+};
+
 static const char * const typec_port_types_drp[] = {
        [TYPEC_PORT_SRC] = "dual [source] sink",
        [TYPEC_PORT_SNK] = "dual source [sink]",
@@ -932,7 +1060,7 @@ static ssize_t power_role_store(struct device *dev,
        mutex_lock(&port->port_type_lock);
        if (port->port_type != TYPEC_PORT_DRP) {
                dev_dbg(dev, "port type fixed at \"%s\"",
-                            typec_port_types[port->port_type]);
+                            typec_port_power_roles[port->port_type]);
                ret = -EOPNOTSUPP;
                goto unlock_and_ret;
        }
@@ -973,7 +1101,7 @@ port_type_store(struct device *dev, struct device_attribute *attr,
                return -EOPNOTSUPP;
        }
 
-       ret = sysfs_match_string(typec_port_types, buf);
+       ret = sysfs_match_string(typec_port_power_roles, buf);
        if (ret < 0)
                return ret;
 
@@ -1007,7 +1135,7 @@ port_type_show(struct device *dev, struct device_attribute *attr,
                return sprintf(buf, "%s\n",
                               typec_port_types_drp[port->port_type]);
 
-       return sprintf(buf, "[%s]\n", typec_port_types[port->cap->type]);
+       return sprintf(buf, "[%s]\n", typec_port_power_roles[port->cap->type]);
 }
 static DEVICE_ATTR_RW(port_type);
 
@@ -1141,12 +1269,13 @@ static void typec_release(struct device *dev)
        struct typec_port *port = to_typec_port(dev);
 
        ida_simple_remove(&typec_index_ida, port->id);
+       ida_destroy(&port->mode_ids);
        typec_switch_put(port->sw);
        typec_mux_put(port->mux);
        kfree(port);
 }
 
-static const struct device_type typec_port_dev_type = {
+const struct device_type typec_port_dev_type = {
        .name = "typec_port",
        .groups = typec_groups,
        .uevent = typec_uevent,
@@ -1252,6 +1381,50 @@ void typec_set_pwr_opmode(struct typec_port *port,
 }
 EXPORT_SYMBOL_GPL(typec_set_pwr_opmode);
 
+/**
+ * typec_find_port_power_role - Get the typec port power capability
+ * @name: port power capability string
+ *
+ * This routine is used to find the typec_port_type by its string name.
+ *
+ * Returns typec_port_type if success, otherwise negative error code.
+ */
+int typec_find_port_power_role(const char *name)
+{
+       return match_string(typec_port_power_roles,
+                           ARRAY_SIZE(typec_port_power_roles), name);
+}
+EXPORT_SYMBOL_GPL(typec_find_port_power_role);
+
+/**
+ * typec_find_power_role - Find the typec one specific power role
+ * @name: power role string
+ *
+ * This routine is used to find the typec_role by its string name.
+ *
+ * Returns typec_role if success, otherwise negative error code.
+ */
+int typec_find_power_role(const char *name)
+{
+       return match_string(typec_roles, ARRAY_SIZE(typec_roles), name);
+}
+EXPORT_SYMBOL_GPL(typec_find_power_role);
+
+/**
+ * typec_find_port_data_role - Get the typec port data capability
+ * @name: port data capability string
+ *
+ * This routine is used to find the typec_port_data by its string name.
+ *
+ * Returns typec_port_data if success, otherwise negative error code.
+ */
+int typec_find_port_data_role(const char *name)
+{
+       return match_string(typec_port_data_roles,
+                           ARRAY_SIZE(typec_port_data_roles), name);
+}
+EXPORT_SYMBOL_GPL(typec_find_port_data_role);
+
 /* ------------------------------------------ */
 /* API for Multiplexer/DeMultiplexer Switches */
 
@@ -1280,12 +1453,24 @@ int typec_set_orientation(struct typec_port *port,
 EXPORT_SYMBOL_GPL(typec_set_orientation);
 
 /**
+ * typec_get_orientation - Get USB Type-C cable plug orientation
+ * @port: USB Type-C Port
+ *
+ * Get current cable plug orientation for @port.
+ */
+enum typec_orientation typec_get_orientation(struct typec_port *port)
+{
+       return port->orientation;
+}
+EXPORT_SYMBOL_GPL(typec_get_orientation);
+
+/**
  * typec_set_mode - Set mode of operation for USB Type-C connector
- * @port: USB Type-C port for the connector
- * @mode: Operation mode for the connector
+ * @port: USB Type-C connector
+ * @mode: Accessory Mode, USB Operation or Safe State
  *
- * Set mode @mode for @port. This function will configure the muxes needed to
- * enter @mode.
+ * Configure @port for Accessory Mode @mode. This function will configure the
+ * muxes needed for @mode.
  */
 int typec_set_mode(struct typec_port *port, int mode)
 {
@@ -1299,6 +1484,7 @@ EXPORT_SYMBOL_GPL(typec_set_mode);
  * typec_port_register_altmode - Register USB Type-C Port Alternate Mode
  * @port: USB Type-C Port that supports the alternate mode
  * @desc: Description of the alternate mode
+ * @drvdata: Private pointer to driver specific info
  *
  * This routine is used to register an alternate mode that @port is capable of
  * supporting.
@@ -1309,7 +1495,23 @@ struct typec_altmode *
 typec_port_register_altmode(struct typec_port *port,
                            const struct typec_altmode_desc *desc)
 {
-       return typec_register_altmode(&port->dev, desc);
+       struct typec_altmode *adev;
+       struct typec_mux *mux;
+       char id[10];
+
+       sprintf(id, "id%04xm%02x", desc->svid, desc->mode);
+
+       mux = typec_mux_get(port->dev.parent, id);
+       if (IS_ERR(mux))
+               return ERR_CAST(mux);
+
+       adev = typec_register_altmode(&port->dev, desc);
+       if (IS_ERR(adev))
+               typec_mux_put(mux);
+       else
+               to_altmode(adev)->mux = mux;
+
+       return adev;
 }
 EXPORT_SYMBOL_GPL(typec_port_register_altmode);
 
@@ -1345,7 +1547,7 @@ struct typec_port *typec_register_port(struct device *parent,
                goto err_switch;
        }
 
-       port->mux = typec_mux_get(cap->fwnode ? &port->dev : parent);
+       port->mux = typec_mux_get(parent, "typec-mux");
        if (IS_ERR(port->mux)) {
                ret = PTR_ERR(port->mux);
                goto err_mux;
@@ -1383,10 +1585,12 @@ struct typec_port *typec_register_port(struct device *parent,
                break;
        }
 
+       ida_init(&port->mode_ids);
+       mutex_init(&port->port_type_lock);
+
        port->id = id;
        port->cap = cap;
        port->port_type = cap->type;
-       mutex_init(&port->port_type_lock);
        port->prefer_role = cap->prefer_role;
 
        port->dev.class = typec_class;
@@ -1430,8 +1634,19 @@ EXPORT_SYMBOL_GPL(typec_unregister_port);
 
 static int __init typec_init(void)
 {
+       int ret;
+
+       ret = bus_register(&typec_bus);
+       if (ret)
+               return ret;
+
        typec_class = class_create(THIS_MODULE, "typec");
-       return PTR_ERR_OR_ZERO(typec_class);
+       if (IS_ERR(typec_class)) {
+               bus_unregister(&typec_bus);
+               return PTR_ERR(typec_class);
+       }
+
+       return 0;
 }
 subsys_initcall(typec_init);
 
@@ -1439,6 +1654,7 @@ static void __exit typec_exit(void)
 {
        class_destroy(typec_class);
        ida_destroy(&typec_index_ida);
+       bus_unregister(&typec_bus);
 }
 module_exit(typec_exit);
 
index 1e68da1..82bed98 100644 (file)
@@ -864,17 +864,6 @@ done:
        return ret;
 }
 
-static int tcpm_set_current_limit(struct tcpc_dev *dev, u32 max_ma, u32 mv)
-{
-       struct fusb302_chip *chip = container_of(dev, struct fusb302_chip,
-                                                tcpc_dev);
-
-       fusb302_log(chip, "current limit: %d ma, %d mv (not implemented)",
-                   max_ma, mv);
-
-       return 0;
-}
-
 static int fusb302_pd_tx_flush(struct fusb302_chip *chip)
 {
        return fusb302_i2c_set_bits(chip, FUSB_REG_CONTROL0,
@@ -1213,7 +1202,6 @@ static void init_tcpc_dev(struct tcpc_dev *fusb302_tcpc_dev)
        fusb302_tcpc_dev->set_polarity = tcpm_set_polarity;
        fusb302_tcpc_dev->set_vconn = tcpm_set_vconn;
        fusb302_tcpc_dev->set_vbus = tcpm_set_vbus;
-       fusb302_tcpc_dev->set_current_limit = tcpm_set_current_limit;
        fusb302_tcpc_dev->set_pd_rx = tcpm_set_pd_rx;
        fusb302_tcpc_dev->set_roles = tcpm_set_roles;
        fusb302_tcpc_dev->start_drp_toggling = tcpm_start_drp_toggling;
index 9d8330e..ddaac63 100644 (file)
@@ -123,19 +123,19 @@ static void *typec_mux_match(struct device_connection *con, int ep, void *data)
 /**
  * typec_mux_get - Find USB Type-C Multiplexer
  * @dev: The caller device
+ * @name: Mux identifier
  *
  * Finds a mux linked to the caller. This function is primarily meant for the
  * Type-C drivers. Returns a reference to the mux on success, NULL if no
  * matching connection was found, or ERR_PTR(-EPROBE_DEFER) when a connection
  * was found but the mux has not been enumerated yet.
  */
-struct typec_mux *typec_mux_get(struct device *dev)
+struct typec_mux *typec_mux_get(struct device *dev, const char *name)
 {
        struct typec_mux *mux;
 
        mutex_lock(&mux_lock);
-       mux = device_connection_find_match(dev, "typec-mux", NULL,
-                                          typec_mux_match);
+       mux = device_connection_find_match(dev, name, NULL, typec_mux_match);
        if (!IS_ERR_OR_NULL(mux))
                get_device(mux->dev);
        mutex_unlock(&mux_lock);
index b0e88db..64eb598 100644 (file)
@@ -9,7 +9,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mutex.h>
-#include <linux/usb/tcpm.h>
+#include <linux/usb/typec_dp.h>
 #include <linux/usb/typec_mux.h>
 
 #define PI3USB30532_CONF                       0x00
@@ -83,21 +83,24 @@ static int pi3usb30532_mux_set(struct typec_mux *mux, int state)
        new_conf = pi->conf;
 
        switch (state) {
-       case TYPEC_MUX_NONE:
+       case TYPEC_STATE_SAFE:
                new_conf = PI3USB30532_CONF_OPEN;
                break;
-       case TYPEC_MUX_USB:
+       case TYPEC_STATE_USB:
                new_conf = (new_conf & PI3USB30532_CONF_SWAP) |
                           PI3USB30532_CONF_USB3;
                break;
-       case TYPEC_MUX_DP:
+       case TYPEC_DP_STATE_C:
+       case TYPEC_DP_STATE_E:
                new_conf = (new_conf & PI3USB30532_CONF_SWAP) |
                           PI3USB30532_CONF_4LANE_DP;
                break;
-       case TYPEC_MUX_DOCK:
+       case TYPEC_DP_STATE_D:
                new_conf = (new_conf & PI3USB30532_CONF_SWAP) |
                           PI3USB30532_CONF_USB3_AND_2LANE_DP;
                break;
+       default:
+               break;
        }
 
        ret = pi3usb30532_set_conf(pi, new_conf);
similarity index 92%
rename from drivers/staging/typec/tcpci.c
rename to drivers/usb/typec/tcpci.c
index 076d97e..ac6b418 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/module.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
+#include <linux/property.h>
 #include <linux/regmap.h>
 #include <linux/usb/pd.h>
 #include <linux/usb/tcpm.h>
@@ -184,15 +185,25 @@ static int tcpci_set_polarity(struct tcpc_dev *tcpc,
                              enum typec_cc_polarity polarity)
 {
        struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
+       unsigned int reg;
        int ret;
 
-       ret = regmap_write(tcpci->regmap, TCPC_TCPC_CTRL,
-                          (polarity == TYPEC_POLARITY_CC2) ?
-                          TCPC_TCPC_CTRL_ORIENTATION : 0);
+       /* Keep the disconnect cc line open */
+       ret = regmap_read(tcpci->regmap, TCPC_ROLE_CTRL, &reg);
        if (ret < 0)
                return ret;
 
-       return 0;
+       if (polarity == TYPEC_POLARITY_CC2)
+               reg |= TCPC_ROLE_CTRL_CC_OPEN << TCPC_ROLE_CTRL_CC1_SHIFT;
+       else
+               reg |= TCPC_ROLE_CTRL_CC_OPEN << TCPC_ROLE_CTRL_CC2_SHIFT;
+       ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
+       if (ret < 0)
+               return ret;
+
+       return regmap_write(tcpci->regmap, TCPC_TCPC_CTRL,
+                          (polarity == TYPEC_POLARITY_CC2) ?
+                          TCPC_TCPC_CTRL_ORIENTATION : 0);
 }
 
 static int tcpci_set_vconn(struct tcpc_dev *tcpc, bool enable)
@@ -207,12 +218,9 @@ static int tcpci_set_vconn(struct tcpc_dev *tcpc, bool enable)
                        return ret;
        }
 
-       ret = regmap_write(tcpci->regmap, TCPC_POWER_CTRL,
-                          enable ? TCPC_POWER_CTRL_VCONN_ENABLE : 0);
-       if (ret < 0)
-               return ret;
-
-       return 0;
+       return regmap_update_bits(tcpci->regmap, TCPC_POWER_CTRL,
+                               TCPC_POWER_CTRL_VCONN_ENABLE,
+                               enable ? TCPC_POWER_CTRL_VCONN_ENABLE : 0);
 }
 
 static int tcpci_set_roles(struct tcpc_dev *tcpc, bool attached,
@@ -372,6 +380,12 @@ static int tcpci_init(struct tcpc_dev *tcpc)
        if (ret < 0)
                return ret;
 
+       /* Enable Vbus detection */
+       ret = regmap_write(tcpci->regmap, TCPC_COMMAND,
+                          TCPC_CMD_ENABLE_VBUS_DETECT);
+       if (ret < 0)
+               return ret;
+
        reg = TCPC_ALERT_TX_SUCCESS | TCPC_ALERT_TX_FAILED |
                TCPC_ALERT_TX_DISCARDED | TCPC_ALERT_RX_STATUS |
                TCPC_ALERT_RX_HARD_RST | TCPC_ALERT_CC_STATUS;
@@ -463,17 +477,16 @@ static const struct regmap_config tcpci_regmap_config = {
        .max_register = 0x7F, /* 0x80 .. 0xFF are vendor defined */
 };
 
-static const struct tcpc_config tcpci_tcpc_config = {
-       .type = TYPEC_PORT_DFP,
-       .default_role = TYPEC_SINK,
-};
-
 static int tcpci_parse_config(struct tcpci *tcpci)
 {
        tcpci->controls_vbus = true; /* XXX */
 
-       /* TODO: Populate struct tcpc_config from ACPI/device-tree */
-       tcpci->tcpc.config = &tcpci_tcpc_config;
+       tcpci->tcpc.fwnode = device_get_named_child_node(tcpci->dev,
+                                                        "connector");
+       if (!tcpci->tcpc.fwnode) {
+               dev_err(tcpci->dev, "Can't find connector node.\n");
+               return -EINVAL;
+       }
 
        return 0;
 }
@@ -509,7 +522,7 @@ struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data)
                return ERR_PTR(err);
 
        tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc);
-       if (PTR_ERR_OR_ZERO(tcpci->port))
+       if (IS_ERR(tcpci->port))
                return ERR_CAST(tcpci->port);
 
        return tcpci;
@@ -537,24 +550,27 @@ static int tcpci_probe(struct i2c_client *client,
        if (IS_ERR(chip->data.regmap))
                return PTR_ERR(chip->data.regmap);
 
+       i2c_set_clientdata(client, chip);
+
        /* Disable chip interrupts before requesting irq */
        err = regmap_raw_write(chip->data.regmap, TCPC_ALERT_MASK, &val,
                               sizeof(u16));
        if (err < 0)
                return err;
 
+       chip->tcpci = tcpci_register_port(&client->dev, &chip->data);
+       if (IS_ERR(chip->tcpci))
+               return PTR_ERR(chip->tcpci);
+
        err = devm_request_threaded_irq(&client->dev, client->irq, NULL,
                                        _tcpci_irq,
                                        IRQF_ONESHOT | IRQF_TRIGGER_LOW,
                                        dev_name(&client->dev), chip);
-       if (err < 0)
+       if (err < 0) {
+               tcpci_unregister_port(chip->tcpci);
                return err;
+       }
 
-       chip->tcpci = tcpci_register_port(&client->dev, &chip->data);
-       if (PTR_ERR_OR_ZERO(chip->tcpci))
-               return PTR_ERR(chip->tcpci);
-
-       i2c_set_clientdata(client, chip);
        return 0;
 }
 
@@ -575,7 +591,7 @@ MODULE_DEVICE_TABLE(i2c, tcpci_id);
 
 #ifdef CONFIG_OF
 static const struct of_device_id tcpci_of_match[] = {
-       { .compatible = "usb,tcpci", },
+       { .compatible = "nxp,ptn5110", },
        {},
 };
 MODULE_DEVICE_TABLE(of, tcpci_of_match);
index d1d2025..4f1f421 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/usb/pd_vdo.h>
 #include <linux/usb/role.h>
 #include <linux/usb/tcpm.h>
-#include <linux/usb/typec.h>
+#include <linux/usb/typec_altmode.h>
 #include <linux/workqueue.h>
 
 #define FOREACH_STATE(S)                       \
@@ -169,13 +169,14 @@ enum pd_msg_request {
 /* Alternate mode support */
 
 #define SVID_DISCOVERY_MAX     16
+#define ALTMODE_DISCOVERY_MAX  (SVID_DISCOVERY_MAX * MODE_DISCOVERY_MAX)
 
 struct pd_mode_data {
        int svid_index;         /* current SVID index           */
        int nsvids;
        u16 svids[SVID_DISCOVERY_MAX];
        int altmodes;           /* number of alternate modes    */
-       struct typec_altmode_desc altmode_desc[SVID_DISCOVERY_MAX];
+       struct typec_altmode_desc altmode_desc[ALTMODE_DISCOVERY_MAX];
 };
 
 struct pd_pps_data {
@@ -310,8 +311,8 @@ struct tcpm_port {
 
        /* Alternate mode data */
        struct pd_mode_data mode_data;
-       struct typec_altmode *partner_altmode[SVID_DISCOVERY_MAX];
-       struct typec_altmode *port_altmode[SVID_DISCOVERY_MAX];
+       struct typec_altmode *partner_altmode[ALTMODE_DISCOVERY_MAX];
+       struct typec_altmode *port_altmode[ALTMODE_DISCOVERY_MAX];
 
        /* Deadline in jiffies to exit src_try_wait state */
        unsigned long max_wait;
@@ -641,14 +642,14 @@ void tcpm_pd_transmit_complete(struct tcpm_port *port,
 }
 EXPORT_SYMBOL_GPL(tcpm_pd_transmit_complete);
 
-static int tcpm_mux_set(struct tcpm_port *port, enum tcpc_mux_mode mode,
+static int tcpm_mux_set(struct tcpm_port *port, int state,
                        enum usb_role usb_role,
                        enum typec_orientation orientation)
 {
        int ret;
 
-       tcpm_log(port, "Requesting mux mode %d, usb-role %d, orientation %d",
-                mode, usb_role, orientation);
+       tcpm_log(port, "Requesting mux state %d, usb-role %d, orientation %d",
+                state, usb_role, orientation);
 
        ret = typec_set_orientation(port->typec_port, orientation);
        if (ret)
@@ -660,7 +661,7 @@ static int tcpm_mux_set(struct tcpm_port *port, enum tcpc_mux_mode mode,
                        return ret;
        }
 
-       return typec_set_mode(port->typec_port, mode);
+       return typec_set_mode(port->typec_port, state);
 }
 
 static int tcpm_set_polarity(struct tcpm_port *port,
@@ -790,7 +791,7 @@ static int tcpm_set_roles(struct tcpm_port *port, bool attached,
        else
                usb_role = USB_ROLE_DEVICE;
 
-       ret = tcpm_mux_set(port, TYPEC_MUX_USB, usb_role, orientation);
+       ret = tcpm_mux_set(port, TYPEC_STATE_USB, usb_role, orientation);
        if (ret < 0)
                return ret;
 
@@ -998,7 +999,6 @@ static void svdm_consume_modes(struct tcpm_port *port, const __le32 *payload,
 {
        struct pd_mode_data *pmdata = &port->mode_data;
        struct typec_altmode_desc *paltmode;
-       struct typec_mode_desc *pmode;
        int i;
 
        if (pmdata->altmodes >= ARRAY_SIZE(port->partner_altmode)) {
@@ -1006,32 +1006,36 @@ static void svdm_consume_modes(struct tcpm_port *port, const __le32 *payload,
                return;
        }
 
-       paltmode = &pmdata->altmode_desc[pmdata->altmodes];
-       memset(paltmode, 0, sizeof(*paltmode));
+       for (i = 1; i < cnt; i++) {
+               paltmode = &pmdata->altmode_desc[pmdata->altmodes];
+               memset(paltmode, 0, sizeof(*paltmode));
 
-       paltmode->svid = pmdata->svids[pmdata->svid_index];
+               paltmode->svid = pmdata->svids[pmdata->svid_index];
+               paltmode->mode = i;
+               paltmode->vdo = le32_to_cpu(payload[i]);
 
-       tcpm_log(port, " Alternate mode %d: SVID 0x%04x",
-                pmdata->altmodes, paltmode->svid);
+               tcpm_log(port, " Alternate mode %d: SVID 0x%04x, VDO %d: 0x%08x",
+                        pmdata->altmodes, paltmode->svid,
+                        paltmode->mode, paltmode->vdo);
 
-       for (i = 1; i < cnt && paltmode->n_modes < ALTMODE_MAX_MODES; i++) {
-               pmode = &paltmode->modes[paltmode->n_modes];
-               memset(pmode, 0, sizeof(*pmode));
-               pmode->vdo = le32_to_cpu(payload[i]);
-               pmode->index = i - 1;
-               paltmode->n_modes++;
-               tcpm_log(port, "  VDO %d: 0x%08x",
-                        pmode->index, pmode->vdo);
+               pmdata->altmodes++;
        }
-       port->partner_altmode[pmdata->altmodes] =
-               typec_partner_register_altmode(port->partner, paltmode);
-       if (!port->partner_altmode[pmdata->altmodes]) {
-               tcpm_log(port,
-                        "Failed to register alternate modes for SVID 0x%04x",
-                        paltmode->svid);
-               return;
+}
+
+static void tcpm_register_partner_altmodes(struct tcpm_port *port)
+{
+       struct pd_mode_data *modep = &port->mode_data;
+       struct typec_altmode *altmode;
+       int i;
+
+       for (i = 0; i < modep->altmodes; i++) {
+               altmode = typec_partner_register_altmode(port->partner,
+                                               &modep->altmode_desc[i]);
+               if (!altmode)
+                       tcpm_log(port, "Failed to register partner SVID 0x%04x",
+                                modep->altmode_desc[i].svid);
+               port->partner_altmode[i] = altmode;
        }
-       pmdata->altmodes++;
 }
 
 #define supports_modal(port)   PD_IDH_MODAL_SUPP((port)->partner_ident.id_header)
@@ -1039,19 +1043,32 @@ static void svdm_consume_modes(struct tcpm_port *port, const __le32 *payload,
 static int tcpm_pd_svdm(struct tcpm_port *port, const __le32 *payload, int cnt,
                        u32 *response)
 {
-       u32 p0 = le32_to_cpu(payload[0]);
-       int cmd_type = PD_VDO_CMDT(p0);
-       int cmd = PD_VDO_CMD(p0);
+       struct typec_altmode *adev;
+       struct typec_altmode *pdev;
        struct pd_mode_data *modep;
+       u32 p[PD_MAX_PAYLOAD];
        int rlen = 0;
-       u16 svid;
+       int cmd_type;
+       int cmd;
        int i;
 
+       for (i = 0; i < cnt; i++)
+               p[i] = le32_to_cpu(payload[i]);
+
+       cmd_type = PD_VDO_CMDT(p[0]);
+       cmd = PD_VDO_CMD(p[0]);
+
        tcpm_log(port, "Rx VDM cmd 0x%x type %d cmd %d len %d",
-                p0, cmd_type, cmd, cnt);
+                p[0], cmd_type, cmd, cnt);
 
        modep = &port->mode_data;
 
+       adev = typec_match_altmode(port->port_altmode, ALTMODE_DISCOVERY_MAX,
+                                  PD_VDO_VID(p[0]), PD_VDO_OPOS(p[0]));
+
+       pdev = typec_match_altmode(port->partner_altmode, ALTMODE_DISCOVERY_MAX,
+                                  PD_VDO_VID(p[0]), PD_VDO_OPOS(p[0]));
+
        switch (cmd_type) {
        case CMDT_INIT:
                switch (cmd) {
@@ -1073,17 +1090,19 @@ static int tcpm_pd_svdm(struct tcpm_port *port, const __le32 *payload, int cnt,
                case CMD_EXIT_MODE:
                        break;
                case CMD_ATTENTION:
-                       break;
+                       /* Attention command does not have response */
+                       typec_altmode_attention(adev, p[1]);
+                       return 0;
                default:
                        break;
                }
                if (rlen >= 1) {
-                       response[0] = p0 | VDO_CMDT(CMDT_RSP_ACK);
+                       response[0] = p[0] | VDO_CMDT(CMDT_RSP_ACK);
                } else if (rlen == 0) {
-                       response[0] = p0 | VDO_CMDT(CMDT_RSP_NAK);
+                       response[0] = p[0] | VDO_CMDT(CMDT_RSP_NAK);
                        rlen = 1;
                } else {
-                       response[0] = p0 | VDO_CMDT(CMDT_RSP_BUSY);
+                       response[0] = p[0] | VDO_CMDT(CMDT_RSP_BUSY);
                        rlen = 1;
                }
                break;
@@ -1116,14 +1135,39 @@ static int tcpm_pd_svdm(struct tcpm_port *port, const __le32 *payload, int cnt,
                        svdm_consume_modes(port, payload, cnt);
                        modep->svid_index++;
                        if (modep->svid_index < modep->nsvids) {
-                               svid = modep->svids[modep->svid_index];
+                               u16 svid = modep->svids[modep->svid_index];
                                response[0] = VDO(svid, 1, CMD_DISCOVER_MODES);
                                rlen = 1;
                        } else {
-                               /* enter alternate mode if/when implemented */
+                               tcpm_register_partner_altmodes(port);
                        }
                        break;
                case CMD_ENTER_MODE:
+                       typec_altmode_update_active(pdev, true);
+
+                       if (typec_altmode_vdm(adev, p[0], &p[1], cnt)) {
+                               response[0] = VDO(adev->svid, 1, CMD_EXIT_MODE);
+                               response[0] |= VDO_OPOS(adev->mode);
+                               return 1;
+                       }
+                       return 0;
+               case CMD_EXIT_MODE:
+                       typec_altmode_update_active(pdev, false);
+
+                       /* Back to USB Operation */
+                       WARN_ON(typec_altmode_notify(adev, TYPEC_STATE_USB,
+                                                    NULL));
+                       break;
+               default:
+                       break;
+               }
+               break;
+       case CMDT_RSP_NAK:
+               switch (cmd) {
+               case CMD_ENTER_MODE:
+                       /* Back to USB Operation */
+                       WARN_ON(typec_altmode_notify(adev, TYPEC_STATE_USB,
+                                                    NULL));
                        break;
                default:
                        break;
@@ -1133,6 +1177,9 @@ static int tcpm_pd_svdm(struct tcpm_port *port, const __le32 *payload, int cnt,
                break;
        }
 
+       /* Informing the alternate mode drivers about everything */
+       typec_altmode_vdm(adev, p[0], &p[1], cnt);
+
        return rlen;
 }
 
@@ -1416,6 +1463,57 @@ static int tcpm_validate_caps(struct tcpm_port *port, const u32 *pdo,
        return 0;
 }
 
+static int tcpm_altmode_enter(struct typec_altmode *altmode)
+{
+       struct tcpm_port *port = typec_altmode_get_drvdata(altmode);
+       u32 header;
+
+       mutex_lock(&port->lock);
+       header = VDO(altmode->svid, 1, CMD_ENTER_MODE);
+       header |= VDO_OPOS(altmode->mode);
+
+       tcpm_queue_vdm(port, header, NULL, 0);
+       mod_delayed_work(port->wq, &port->vdm_state_machine, 0);
+       mutex_unlock(&port->lock);
+
+       return 0;
+}
+
+static int tcpm_altmode_exit(struct typec_altmode *altmode)
+{
+       struct tcpm_port *port = typec_altmode_get_drvdata(altmode);
+       u32 header;
+
+       mutex_lock(&port->lock);
+       header = VDO(altmode->svid, 1, CMD_EXIT_MODE);
+       header |= VDO_OPOS(altmode->mode);
+
+       tcpm_queue_vdm(port, header, NULL, 0);
+       mod_delayed_work(port->wq, &port->vdm_state_machine, 0);
+       mutex_unlock(&port->lock);
+
+       return 0;
+}
+
+static int tcpm_altmode_vdm(struct typec_altmode *altmode,
+                           u32 header, const u32 *data, int count)
+{
+       struct tcpm_port *port = typec_altmode_get_drvdata(altmode);
+
+       mutex_lock(&port->lock);
+       tcpm_queue_vdm(port, header, data, count - 1);
+       mod_delayed_work(port->wq, &port->vdm_state_machine, 0);
+       mutex_unlock(&port->lock);
+
+       return 0;
+}
+
+static const struct typec_altmode_ops tcpm_altmode_ops = {
+       .enter = tcpm_altmode_enter,
+       .exit = tcpm_altmode_exit,
+       .vdm = tcpm_altmode_vdm,
+};
+
 /*
  * PD (data, control) command handling functions
  */
@@ -2435,15 +2533,15 @@ static int tcpm_set_charge(struct tcpm_port *port, bool charge)
        return 0;
 }
 
-static bool tcpm_start_drp_toggling(struct tcpm_port *port)
+static bool tcpm_start_drp_toggling(struct tcpm_port *port,
+                                   enum typec_cc_status cc)
 {
        int ret;
 
        if (port->tcpc->start_drp_toggling &&
            port->port_type == TYPEC_PORT_DRP) {
                tcpm_log_force(port, "Start DRP toggling");
-               ret = port->tcpc->start_drp_toggling(port->tcpc,
-                                                    tcpm_rp_cc(port));
+               ret = port->tcpc->start_drp_toggling(port->tcpc, cc);
                if (!ret)
                        return true;
        }
@@ -2547,7 +2645,7 @@ out_disable_vconn:
 out_disable_pd:
        port->tcpc->set_pd_rx(port->tcpc, false);
 out_disable_mux:
-       tcpm_mux_set(port, TYPEC_MUX_NONE, USB_ROLE_NONE,
+       tcpm_mux_set(port, TYPEC_STATE_SAFE, USB_ROLE_NONE,
                     TYPEC_ORIENTATION_NONE);
        return ret;
 }
@@ -2593,7 +2691,7 @@ static void tcpm_reset_port(struct tcpm_port *port)
        tcpm_init_vconn(port);
        tcpm_set_current_limit(port, 0, 0);
        tcpm_set_polarity(port, TYPEC_POLARITY_CC1);
-       tcpm_mux_set(port, TYPEC_MUX_NONE, USB_ROLE_NONE,
+       tcpm_mux_set(port, TYPEC_STATE_SAFE, USB_ROLE_NONE,
                     TYPEC_ORIENTATION_NONE);
        tcpm_set_attached_state(port, false);
        port->try_src_count = 0;
@@ -2749,7 +2847,7 @@ static void run_state_machine(struct tcpm_port *port)
                if (!port->non_pd_role_swap)
                        tcpm_swap_complete(port, -ENOTCONN);
                tcpm_src_detach(port);
-               if (tcpm_start_drp_toggling(port)) {
+               if (tcpm_start_drp_toggling(port, tcpm_rp_cc(port))) {
                        tcpm_set_state(port, DRP_TOGGLING, 0);
                        break;
                }
@@ -2924,7 +3022,7 @@ static void run_state_machine(struct tcpm_port *port)
                        tcpm_swap_complete(port, -ENOTCONN);
                tcpm_pps_complete(port, -ENOTCONN);
                tcpm_snk_detach(port);
-               if (tcpm_start_drp_toggling(port)) {
+               if (tcpm_start_drp_toggling(port, TYPEC_CC_RD)) {
                        tcpm_set_state(port, DRP_TOGGLING, 0);
                        break;
                }
@@ -4239,6 +4337,81 @@ static int tcpm_copy_vdos(u32 *dest_vdo, const u32 *src_vdo,
        return nr_vdo;
 }
 
+static int tcpm_fw_get_caps(struct tcpm_port *port,
+                           struct fwnode_handle *fwnode)
+{
+       const char *cap_str;
+       int ret;
+       u32 mw;
+
+       if (!fwnode)
+               return -EINVAL;
+
+       /* USB data support is optional */
+       ret = fwnode_property_read_string(fwnode, "data-role", &cap_str);
+       if (ret == 0) {
+               port->typec_caps.data = typec_find_port_data_role(cap_str);
+               if (port->typec_caps.data < 0)
+                       return -EINVAL;
+       }
+
+       ret = fwnode_property_read_string(fwnode, "power-role", &cap_str);
+       if (ret < 0)
+               return ret;
+
+       port->typec_caps.type = typec_find_port_power_role(cap_str);
+       if (port->typec_caps.type < 0)
+               return -EINVAL;
+       port->port_type = port->typec_caps.type;
+
+       if (port->port_type == TYPEC_PORT_SNK)
+               goto sink;
+
+       /* Get source pdos */
+       ret = fwnode_property_read_u32_array(fwnode, "source-pdos",
+                                            NULL, 0);
+       if (ret <= 0)
+               return -EINVAL;
+
+       port->nr_src_pdo = min(ret, PDO_MAX_OBJECTS);
+       ret = fwnode_property_read_u32_array(fwnode, "source-pdos",
+                                            port->src_pdo, port->nr_src_pdo);
+       if ((ret < 0) || tcpm_validate_caps(port, port->src_pdo,
+                                           port->nr_src_pdo))
+               return -EINVAL;
+
+       if (port->port_type == TYPEC_PORT_SRC)
+               return 0;
+
+       /* Get the preferred power role for DRP */
+       ret = fwnode_property_read_string(fwnode, "try-power-role", &cap_str);
+       if (ret < 0)
+               return ret;
+
+       port->typec_caps.prefer_role = typec_find_power_role(cap_str);
+       if (port->typec_caps.prefer_role < 0)
+               return -EINVAL;
+sink:
+       /* Get sink pdos */
+       ret = fwnode_property_read_u32_array(fwnode, "sink-pdos",
+                                            NULL, 0);
+       if (ret <= 0)
+               return -EINVAL;
+
+       port->nr_snk_pdo = min(ret, PDO_MAX_OBJECTS);
+       ret = fwnode_property_read_u32_array(fwnode, "sink-pdos",
+                                            port->snk_pdo, port->nr_snk_pdo);
+       if ((ret < 0) || tcpm_validate_caps(port, port->snk_pdo,
+                                           port->nr_snk_pdo))
+               return -EINVAL;
+
+       if (fwnode_property_read_u32(fwnode, "op-sink-microwatt", &mw) < 0)
+               return -EINVAL;
+       port->operating_snk_mw = mw / 1000;
+
+       return 0;
+}
+
 int tcpm_update_source_capabilities(struct tcpm_port *port, const u32 *pdo,
                                    unsigned int nr_pdo)
 {
@@ -4524,12 +4697,36 @@ static int devm_tcpm_psy_register(struct tcpm_port *port)
        return PTR_ERR_OR_ZERO(port->psy);
 }
 
+static int tcpm_copy_caps(struct tcpm_port *port,
+                         const struct tcpc_config *tcfg)
+{
+       if (tcpm_validate_caps(port, tcfg->src_pdo, tcfg->nr_src_pdo) ||
+           tcpm_validate_caps(port, tcfg->snk_pdo, tcfg->nr_snk_pdo))
+               return -EINVAL;
+
+       port->nr_src_pdo = tcpm_copy_pdos(port->src_pdo, tcfg->src_pdo,
+                                         tcfg->nr_src_pdo);
+       port->nr_snk_pdo = tcpm_copy_pdos(port->snk_pdo, tcfg->snk_pdo,
+                                         tcfg->nr_snk_pdo);
+
+       port->nr_snk_vdo = tcpm_copy_vdos(port->snk_vdo, tcfg->snk_vdo,
+                                         tcfg->nr_snk_vdo);
+
+       port->operating_snk_mw = tcfg->operating_snk_mw;
+
+       port->typec_caps.prefer_role = tcfg->default_role;
+       port->typec_caps.type = tcfg->type;
+       port->typec_caps.data = tcfg->data;
+
+       return 0;
+}
+
 struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
 {
        struct tcpm_port *port;
        int i, err;
 
-       if (!dev || !tcpc || !tcpc->config ||
+       if (!dev || !tcpc ||
            !tcpc->get_vbus || !tcpc->set_cc || !tcpc->get_cc ||
            !tcpc->set_polarity || !tcpc->set_vconn || !tcpc->set_vbus ||
            !tcpc->set_pd_rx || !tcpc->set_roles || !tcpc->pd_transmit)
@@ -4559,29 +4756,18 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
        init_completion(&port->pps_complete);
        tcpm_debugfs_init(port);
 
-       if (tcpm_validate_caps(port, tcpc->config->src_pdo,
-                              tcpc->config->nr_src_pdo) ||
-           tcpm_validate_caps(port, tcpc->config->snk_pdo,
-                              tcpc->config->nr_snk_pdo)) {
-               err = -EINVAL;
+       err = tcpm_fw_get_caps(port, tcpc->fwnode);
+       if ((err < 0) && tcpc->config)
+               err = tcpm_copy_caps(port, tcpc->config);
+       if (err < 0)
                goto out_destroy_wq;
-       }
-       port->nr_src_pdo = tcpm_copy_pdos(port->src_pdo, tcpc->config->src_pdo,
-                                         tcpc->config->nr_src_pdo);
-       port->nr_snk_pdo = tcpm_copy_pdos(port->snk_pdo, tcpc->config->snk_pdo,
-                                         tcpc->config->nr_snk_pdo);
-       port->nr_snk_vdo = tcpm_copy_vdos(port->snk_vdo, tcpc->config->snk_vdo,
-                                         tcpc->config->nr_snk_vdo);
-
-       port->operating_snk_mw = tcpc->config->operating_snk_mw;
-       if (!tcpc->config->try_role_hw)
-               port->try_role = tcpc->config->default_role;
+
+       if (!tcpc->config || !tcpc->config->try_role_hw)
+               port->try_role = port->typec_caps.prefer_role;
        else
                port->try_role = TYPEC_NO_PREFERRED_ROLE;
 
-       port->typec_caps.prefer_role = tcpc->config->default_role;
-       port->typec_caps.type = tcpc->config->type;
-       port->typec_caps.data = tcpc->config->data;
+       port->typec_caps.fwnode = tcpc->fwnode;
        port->typec_caps.revision = 0x0120;     /* Type-C spec release 1.2 */
        port->typec_caps.pd_revision = 0x0300;  /* USB-PD spec release 3.0 */
        port->typec_caps.dr_set = tcpm_dr_set;
@@ -4591,7 +4777,7 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
        port->typec_caps.port_type_set = tcpm_port_type_set;
 
        port->partner_desc.identity = &port->partner_ident;
-       port->port_type = tcpc->config->type;
+       port->port_type = port->typec_caps.type;
 
        port->role_sw = usb_role_switch_get(port->dev);
        if (IS_ERR(port->role_sw)) {
@@ -4609,7 +4795,7 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
                goto out_destroy_wq;
        }
 
-       if (tcpc->config->alt_modes) {
+       if (tcpc->config && tcpc->config->alt_modes) {
                const struct typec_altmode_desc *paltmode = tcpc->config->alt_modes;
 
                i = 0;
@@ -4624,6 +4810,8 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc)
                                         dev_name(dev), paltmode->svid);
                                break;
                        }
+                       typec_altmode_set_drvdata(alt, port);
+                       alt->ops = &tcpm_altmode_ops;
                        port->port_altmode[i] = alt;
                        i++;
                        paltmode++;
index 4b4c8d2..c84c8c1 100644 (file)
@@ -81,12 +81,21 @@ struct tps6598x {
        struct typec_capability typec_cap;
 };
 
+/*
+ * Max data bytes for Data1, Data2, and other registers. See ch 1.3.2:
+ * http://www.ti.com/lit/ug/slvuan1a/slvuan1a.pdf
+ */
+#define TPS_MAX_LEN    64
+
 static int
 tps6598x_block_read(struct tps6598x *tps, u8 reg, void *val, size_t len)
 {
-       u8 data[len + 1];
+       u8 data[TPS_MAX_LEN + 1];
        int ret;
 
+       if (WARN_ON(len + 1 > sizeof(data)))
+               return -EINVAL;
+
        if (!tps->i2c_protocol)
                return regmap_raw_read(tps->regmap, reg, val, len);
 
index c3ddd0f..f101347 100644 (file)
@@ -159,10 +159,11 @@ static int skel_flush(struct file *file, fl_owner_t id)
 static void skel_read_bulk_callback(struct urb *urb)
 {
        struct usb_skel *dev;
+       unsigned long flags;
 
        dev = urb->context;
 
-       spin_lock(&dev->err_lock);
+       spin_lock_irqsave(&dev->err_lock, flags);
        /* sync/async unlink faults aren't errors */
        if (urb->status) {
                if (!(urb->status == -ENOENT ||
@@ -177,7 +178,7 @@ static void skel_read_bulk_callback(struct urb *urb)
                dev->bulk_in_filled = urb->actual_length;
        }
        dev->ongoing_read = 0;
-       spin_unlock(&dev->err_lock);
+       spin_unlock_irqrestore(&dev->err_lock, flags);
 
        wake_up_interruptible(&dev->bulk_in_wait);
 }
@@ -331,6 +332,7 @@ exit:
 static void skel_write_bulk_callback(struct urb *urb)
 {
        struct usb_skel *dev;
+       unsigned long flags;
 
        dev = urb->context;
 
@@ -343,9 +345,9 @@ static void skel_write_bulk_callback(struct urb *urb)
                                "%s - nonzero write bulk status received: %d\n",
                                __func__, urb->status);
 
-               spin_lock(&dev->err_lock);
+               spin_lock_irqsave(&dev->err_lock, flags);
                dev->errors = urb->status;
-               spin_unlock(&dev->err_lock);
+               spin_unlock_irqrestore(&dev->err_lock, flags);
        }
 
        /* free up our allocated buffer */
index 1b9a4f8..1634d86 100644 (file)
@@ -279,12 +279,10 @@ static int vep_disable(struct usb_ep *_ep)
 static struct usb_request *vep_alloc_request(struct usb_ep *_ep,
                gfp_t mem_flags)
 {
-       struct vep *ep;
        struct vrequest *req;
 
        if (!_ep)
                return NULL;
-       ep = to_vep(_ep);
 
        req = kzalloc(sizeof(*req), mem_flags);
        if (!req)
index 33d2f5d..14ac8c9 100644 (file)
@@ -217,7 +217,7 @@ int wusb_dev_sec_add(struct wusbhc *wusbhc,
 
        result = usb_get_descriptor(usb_dev, USB_DT_SECURITY,
                                    0, secd, sizeof(*secd));
-       if (result < sizeof(*secd)) {
+       if (result < (int)sizeof(*secd)) {
                dev_err(dev, "Can't read security descriptor or "
                        "not enough data: %d\n", result);
                goto out;
index 7fca4e7..01f2f21 100644 (file)
@@ -1918,7 +1918,7 @@ EXPORT_SYMBOL_GPL(wa_urb_enqueue);
  */
 int wa_urb_dequeue(struct wahc *wa, struct urb *urb, int status)
 {
-       unsigned long flags, flags2;
+       unsigned long flags;
        struct wa_xfer *xfer;
        struct wa_seg *seg;
        struct wa_rpipe *rpipe;
@@ -1964,10 +1964,10 @@ int wa_urb_dequeue(struct wahc *wa, struct urb *urb, int status)
                goto out_unlock;
        }
        /* Check the delayed list -> if there, release and complete */
-       spin_lock_irqsave(&wa->xfer_list_lock, flags2);
+       spin_lock(&wa->xfer_list_lock);
        if (!list_empty(&xfer->list_node) && xfer->seg == NULL)
                goto dequeue_delayed;
-       spin_unlock_irqrestore(&wa->xfer_list_lock, flags2);
+       spin_unlock(&wa->xfer_list_lock);
        if (xfer->seg == NULL)          /* still hasn't reached */
                goto out_unlock;        /* setup(), enqueue_b() completes */
        /* Ok, the xfer is in flight already, it's been setup and submitted.*/
@@ -2054,7 +2054,7 @@ out_unlock:
 
 dequeue_delayed:
        list_del_init(&xfer->list_node);
-       spin_unlock_irqrestore(&wa->xfer_list_lock, flags2);
+       spin_unlock(&wa->xfer_list_lock);
        xfer->result = urb->status;
        spin_unlock_irqrestore(&xfer->lock, flags);
        wa_xfer_giveback(xfer);
index 9a53912..5d3ba74 100644 (file)
@@ -873,6 +873,7 @@ error_get_version:
 error_rc_add:
        usb_put_intf(iface);
        usb_put_dev(hwarc->usb_dev);
+       kfree(hwarc);
 error_alloc:
        uwb_rc_put(uwb_rc);
 error_rc_alloc:
diff --git a/include/dt-bindings/usb/pd.h b/include/dt-bindings/usb/pd.h
new file mode 100644 (file)
index 0000000..7b7a92f
--- /dev/null
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __DT_POWER_DELIVERY_H
+#define __DT_POWER_DELIVERY_H
+
+/* Power delivery Power Data Object definitions */
+#define PDO_TYPE_FIXED         0
+#define PDO_TYPE_BATT          1
+#define PDO_TYPE_VAR           2
+#define PDO_TYPE_APDO          3
+
+#define PDO_TYPE_SHIFT         30
+#define PDO_TYPE_MASK          0x3
+
+#define PDO_TYPE(t)    ((t) << PDO_TYPE_SHIFT)
+
+#define PDO_VOLT_MASK          0x3ff
+#define PDO_CURR_MASK          0x3ff
+#define PDO_PWR_MASK           0x3ff
+
+#define PDO_FIXED_DUAL_ROLE    (1 << 29) /* Power role swap supported */
+#define PDO_FIXED_SUSPEND      (1 << 28) /* USB Suspend supported (Source) */
+#define PDO_FIXED_HIGHER_CAP   (1 << 28) /* Requires more than vSafe5V (Sink) */
+#define PDO_FIXED_EXTPOWER     (1 << 27) /* Externally powered */
+#define PDO_FIXED_USB_COMM     (1 << 26) /* USB communications capable */
+#define PDO_FIXED_DATA_SWAP    (1 << 25) /* Data role swap supported */
+#define PDO_FIXED_VOLT_SHIFT   10      /* 50mV units */
+#define PDO_FIXED_CURR_SHIFT   0       /* 10mA units */
+
+#define PDO_FIXED_VOLT(mv)     ((((mv) / 50) & PDO_VOLT_MASK) << PDO_FIXED_VOLT_SHIFT)
+#define PDO_FIXED_CURR(ma)     ((((ma) / 10) & PDO_CURR_MASK) << PDO_FIXED_CURR_SHIFT)
+
+#define PDO_FIXED(mv, ma, flags)                       \
+       (PDO_TYPE(PDO_TYPE_FIXED) | (flags) |           \
+        PDO_FIXED_VOLT(mv) | PDO_FIXED_CURR(ma))
+
+#define VSAFE5V 5000 /* mv units */
+
+#define PDO_BATT_MAX_VOLT_SHIFT        20      /* 50mV units */
+#define PDO_BATT_MIN_VOLT_SHIFT        10      /* 50mV units */
+#define PDO_BATT_MAX_PWR_SHIFT 0       /* 250mW units */
+
+#define PDO_BATT_MIN_VOLT(mv) ((((mv) / 50) & PDO_VOLT_MASK) << PDO_BATT_MIN_VOLT_SHIFT)
+#define PDO_BATT_MAX_VOLT(mv) ((((mv) / 50) & PDO_VOLT_MASK) << PDO_BATT_MAX_VOLT_SHIFT)
+#define PDO_BATT_MAX_POWER(mw) ((((mw) / 250) & PDO_PWR_MASK) << PDO_BATT_MAX_PWR_SHIFT)
+
+#define PDO_BATT(min_mv, max_mv, max_mw)                       \
+       (PDO_TYPE(PDO_TYPE_BATT) | PDO_BATT_MIN_VOLT(min_mv) |  \
+        PDO_BATT_MAX_VOLT(max_mv) | PDO_BATT_MAX_POWER(max_mw))
+
+#define PDO_VAR_MAX_VOLT_SHIFT 20      /* 50mV units */
+#define PDO_VAR_MIN_VOLT_SHIFT 10      /* 50mV units */
+#define PDO_VAR_MAX_CURR_SHIFT 0       /* 10mA units */
+
+#define PDO_VAR_MIN_VOLT(mv) ((((mv) / 50) & PDO_VOLT_MASK) << PDO_VAR_MIN_VOLT_SHIFT)
+#define PDO_VAR_MAX_VOLT(mv) ((((mv) / 50) & PDO_VOLT_MASK) << PDO_VAR_MAX_VOLT_SHIFT)
+#define PDO_VAR_MAX_CURR(ma) ((((ma) / 10) & PDO_CURR_MASK) << PDO_VAR_MAX_CURR_SHIFT)
+
+#define PDO_VAR(min_mv, max_mv, max_ma)                                \
+       (PDO_TYPE(PDO_TYPE_VAR) | PDO_VAR_MIN_VOLT(min_mv) |    \
+        PDO_VAR_MAX_VOLT(max_mv) | PDO_VAR_MAX_CURR(max_ma))
+
+ #endif /* __DT_POWER_DELIVERY_H */
index 96a71a6..1298a7d 100644 (file)
@@ -746,4 +746,19 @@ struct tb_service_id {
 #define TBSVC_MATCH_PROTOCOL_VERSION   0x0004
 #define TBSVC_MATCH_PROTOCOL_REVISION  0x0008
 
+/* USB Type-C Alternate Modes */
+
+#define TYPEC_ANY_MODE 0x7
+
+/**
+ * struct typec_device_id - USB Type-C alternate mode identifiers
+ * @svid: Standard or Vendor ID
+ * @mode: Mode index
+ */
+struct typec_device_id {
+       __u16 svid;
+       __u8 mode;
+       kernel_ulong_t driver_data;
+};
+
 #endif /* LINUX_MOD_DEVICETABLE_H */
index 34a6ded..97e2dde 100644 (file)
@@ -322,6 +322,7 @@ struct hc_driver {
        int     (*bus_suspend)(struct usb_hcd *);
        int     (*bus_resume)(struct usb_hcd *);
        int     (*start_port_reset)(struct usb_hcd *, unsigned port_num);
+       unsigned long   (*get_resuming_ports)(struct usb_hcd *);
 
                /* force handover of high-speed port to full-speed companion */
        void    (*relinquish_port)(struct usb_hcd *, int);
index 09b570f..f2162e0 100644 (file)
@@ -15,6 +15,7 @@
 #ifndef __LINUX_USB_PD_H
 #define __LINUX_USB_PD_H
 
+#include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/usb/typec.h>
 
index b231b93..7e7fbfb 100644 (file)
@@ -98,18 +98,10 @@ struct tcpc_config {
 #define TCPC_MUX_DP_ENABLED            BIT(1)  /* DP enabled */
 #define TCPC_MUX_POLARITY_INVERTED     BIT(2)  /* Polarity inverted */
 
-/* Mux modes, decoded to attributes */
-enum tcpc_mux_mode {
-       TYPEC_MUX_NONE  = 0,                            /* Open switch */
-       TYPEC_MUX_USB   = TCPC_MUX_USB_ENABLED,         /* USB only */
-       TYPEC_MUX_DP    = TCPC_MUX_DP_ENABLED,          /* DP only */
-       TYPEC_MUX_DOCK  = TCPC_MUX_USB_ENABLED |        /* Both USB and DP */
-                         TCPC_MUX_DP_ENABLED,
-};
-
 /**
  * struct tcpc_dev - Port configuration and callback functions
  * @config:    Pointer to port configuration
+ * @fwnode:    Pointer to port fwnode
  * @get_vbus:  Called to read current VBUS state
  * @get_current_limit:
  *             Optional; called by the tcpm core when configured as a snk
@@ -138,6 +130,7 @@ enum tcpc_mux_mode {
  */
 struct tcpc_dev {
        const struct tcpc_config *config;
+       struct fwnode_handle *fwnode;
 
        int (*init)(struct tcpc_dev *dev);
        int (*get_vbus)(struct tcpc_dev *dev);
index 672b39b..7df4eca 100644 (file)
@@ -5,21 +5,18 @@
 
 #include <linux/types.h>
 
-/* XXX: Once we have a header for USB Power Delivery, this belongs there */
-#define ALTMODE_MAX_MODES      6
-
 /* USB Type-C Specification releases */
 #define USB_TYPEC_REV_1_0      0x100 /* 1.0 */
 #define USB_TYPEC_REV_1_1      0x110 /* 1.1 */
 #define USB_TYPEC_REV_1_2      0x120 /* 1.2 */
 
-struct typec_altmode;
 struct typec_partner;
 struct typec_cable;
 struct typec_plug;
 struct typec_port;
 
 struct fwnode_handle;
+struct device;
 
 enum typec_port_type {
        TYPEC_PORT_SRC,
@@ -93,39 +90,21 @@ int typec_partner_set_identity(struct typec_partner *partner);
 int typec_cable_set_identity(struct typec_cable *cable);
 
 /*
- * struct typec_mode_desc - Individual Mode of an Alternate Mode
- * @index: Index of the Mode within the SVID
- * @vdo: VDO returned by Discover Modes USB PD command
- * @desc: Optional human readable description of the mode
- * @roles: Only for ports. DRP if the mode is available in both roles
- *
- * Description of a mode of an Alternate Mode which a connector, cable plug or
- * partner supports. Every mode will have it's own sysfs group. The details are
- * the VDO returned by discover modes command, description for the mode and
- * active flag telling has the mode being entered or not.
- */
-struct typec_mode_desc {
-       int                     index;
-       u32                     vdo;
-       char                    *desc;
-       /* Only used with ports */
-       enum typec_port_type    roles;
-};
-
-/*
  * struct typec_altmode_desc - USB Type-C Alternate Mode Descriptor
  * @svid: Standard or Vendor ID
- * @n_modes: Number of modes
- * @modes: Array of modes supported by the Alternate Mode
+ * @mode: Index of the Mode
+ * @vdo: VDO returned by Discover Modes USB PD command
+ * @roles: Only for ports. DRP if the mode is available in both roles
  *
- * Representation of an Alternate Mode that has SVID assigned by USB-IF. The
- * array of modes will list the modes of a particular SVID that are supported by
- * a connector, partner of a cable plug.
+ * Description of an Alternate Mode which a connector, cable plug or partner
+ * supports.
  */
 struct typec_altmode_desc {
        u16                     svid;
-       int                     n_modes;
-       struct typec_mode_desc  modes[ALTMODE_MAX_MODES];
+       u8                      mode;
+       u32                     vdo;
+       /* Only used with ports */
+       enum typec_port_data    roles;
 };
 
 struct typec_altmode
@@ -141,8 +120,7 @@ void typec_unregister_altmode(struct typec_altmode *altmode);
 
 struct typec_port *typec_altmode2port(struct typec_altmode *alt);
 
-void typec_altmode_update_active(struct typec_altmode *alt, int mode,
-                                bool active);
+void typec_altmode_update_active(struct typec_altmode *alt, bool active);
 
 enum typec_plug_index {
        TYPEC_PLUG_SOP_P,
@@ -205,7 +183,6 @@ struct typec_partner_desc {
  * @dr_set: Set Data Role
  * @pr_set: Set Power Role
  * @vconn_set: Set VCONN Role
- * @activate_mode: Enter/exit given Alternate Mode
  * @port_type_set: Set port type
  *
  * Static capabilities of a single USB Type-C port.
@@ -231,12 +208,8 @@ struct typec_capability {
                                  enum typec_role);
        int             (*vconn_set)(const struct typec_capability *,
                                     enum typec_role);
-
-       int             (*activate_mode)(const struct typec_capability *,
-                                        int mode, int activate);
        int             (*port_type_set)(const struct typec_capability *,
-                                       enum typec_port_type);
-
+                                        enum typec_port_type);
 };
 
 /* Specific to try_role(). Indicates the user want's to clear the preference. */
@@ -265,6 +238,10 @@ void typec_set_pwr_opmode(struct typec_port *port, enum typec_pwr_opmode mode);
 
 int typec_set_orientation(struct typec_port *port,
                          enum typec_orientation orientation);
+enum typec_orientation typec_get_orientation(struct typec_port *port);
 int typec_set_mode(struct typec_port *port, int mode);
 
+int typec_find_port_power_role(const char *name);
+int typec_find_power_role(const char *name);
+int typec_find_port_data_role(const char *name);
 #endif /* __LINUX_USB_TYPEC_H */
diff --git a/include/linux/usb/typec_altmode.h b/include/linux/usb/typec_altmode.h
new file mode 100644 (file)
index 0000000..9a88c74
--- /dev/null
@@ -0,0 +1,160 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __USB_TYPEC_ALTMODE_H
+#define __USB_TYPEC_ALTMODE_H
+
+#include <linux/mod_devicetable.h>
+#include <linux/usb/typec.h>
+#include <linux/device.h>
+
+#define MODE_DISCOVERY_MAX     6
+
+struct typec_altmode_ops;
+
+/**
+ * struct typec_altmode - USB Type-C alternate mode device
+ * @dev: Driver model's view of this device
+ * @svid: Standard or Vendor ID (SVID) of the alternate mode
+ * @mode: Index of the Mode
+ * @vdo: VDO returned by Discover Modes USB PD command
+ * @active: Tells has the mode been entered or not
+ * @desc: Optional human readable description of the mode
+ * @ops: Operations vector from the driver
+ */
+struct typec_altmode {
+       struct device                   dev;
+       u16                             svid;
+       int                             mode;
+       u32                             vdo;
+       unsigned int                    active:1;
+
+       char                            *desc;
+       const struct typec_altmode_ops  *ops;
+};
+
+#define to_typec_altmode(d) container_of(d, struct typec_altmode, dev)
+
+static inline void typec_altmode_set_drvdata(struct typec_altmode *altmode,
+                                            void *data)
+{
+       dev_set_drvdata(&altmode->dev, data);
+}
+
+static inline void *typec_altmode_get_drvdata(struct typec_altmode *altmode)
+{
+       return dev_get_drvdata(&altmode->dev);
+}
+
+/**
+ * struct typec_altmode_ops - Alternate mode specific operations vector
+ * @enter: Operations to be executed with Enter Mode Command
+ * @exit: Operations to be executed with Exit Mode Command
+ * @attention: Callback for Attention Command
+ * @vdm: Callback for SVID specific commands
+ * @notify: Communication channel for platform and the alternate mode
+ * @activate: User callback for Enter/Exit Mode
+ */
+struct typec_altmode_ops {
+       int (*enter)(struct typec_altmode *altmode);
+       int (*exit)(struct typec_altmode *altmode);
+       void (*attention)(struct typec_altmode *altmode, u32 vdo);
+       int (*vdm)(struct typec_altmode *altmode, const u32 hdr,
+                  const u32 *vdo, int cnt);
+       int (*notify)(struct typec_altmode *altmode, unsigned long conf,
+                     void *data);
+       int (*activate)(struct typec_altmode *altmode, int activate);
+};
+
+int typec_altmode_enter(struct typec_altmode *altmode);
+int typec_altmode_exit(struct typec_altmode *altmode);
+void typec_altmode_attention(struct typec_altmode *altmode, u32 vdo);
+int typec_altmode_vdm(struct typec_altmode *altmode,
+                     const u32 header, const u32 *vdo, int count);
+int typec_altmode_notify(struct typec_altmode *altmode, unsigned long conf,
+                        void *data);
+const struct typec_altmode *
+typec_altmode_get_partner(struct typec_altmode *altmode);
+
+/*
+ * These are the connector states (USB, Safe and Alt Mode) defined in USB Type-C
+ * Specification. SVID specific connector states are expected to follow and
+ * start from the value TYPEC_STATE_MODAL.
+ */
+enum {
+       TYPEC_STATE_SAFE,       /* USB Safe State */
+       TYPEC_STATE_USB,        /* USB Operation */
+       TYPEC_STATE_MODAL,      /* Alternate Modes */
+};
+
+/*
+ * For the muxes there is no difference between Accessory Modes and Alternate
+ * Modes, so the Accessory Modes are supplied with specific modal state values
+ * here. Unlike with Alternate Modes, where the mux will be linked with the
+ * alternate mode device, the mux for Accessory Modes will be linked with the
+ * port device instead.
+ *
+ * Port drivers can use TYPEC_MODE_AUDIO and TYPEC_MODE_DEBUG as the mode
+ * value for typec_set_mode() when accessory modes are supported.
+ */
+enum {
+       TYPEC_MODE_AUDIO = TYPEC_STATE_MODAL,   /* Audio Accessory */
+       TYPEC_MODE_DEBUG,                       /* Debug Accessory */
+};
+
+#define TYPEC_MODAL_STATE(_state_)     ((_state_) + TYPEC_STATE_MODAL)
+
+struct typec_altmode *typec_altmode_get_plug(struct typec_altmode *altmode,
+                                            enum typec_plug_index index);
+void typec_altmode_put_plug(struct typec_altmode *plug);
+
+struct typec_altmode *typec_match_altmode(struct typec_altmode **altmodes,
+                                         size_t n, u16 svid, u8 mode);
+
+struct typec_altmode *
+typec_altmode_register_notifier(struct device *dev, u16 svid, u8 mode,
+                               struct notifier_block *nb);
+
+void typec_altmode_unregister_notifier(struct typec_altmode *adev,
+                                      struct notifier_block *nb);
+
+/**
+ * typec_altmode_get_orientation - Get cable plug orientation
+ * altmode: Handle to the alternate mode
+ */
+static inline enum typec_orientation
+typec_altmode_get_orientation(struct typec_altmode *altmode)
+{
+       return typec_get_orientation(typec_altmode2port(altmode));
+}
+
+/**
+ * struct typec_altmode_driver - USB Type-C alternate mode device driver
+ * @id_table: Null terminated array of SVIDs
+ * @probe: Callback for device binding
+ * @remove: Callback for device unbinding
+ * @driver: Device driver model driver
+ *
+ * These drivers will be bind to the partner alternate mode devices. They will
+ * handle all SVID specific communication.
+ */
+struct typec_altmode_driver {
+       const struct typec_device_id *id_table;
+       int (*probe)(struct typec_altmode *altmode);
+       void (*remove)(struct typec_altmode *altmode);
+       struct device_driver driver;
+};
+
+#define to_altmode_driver(d) container_of(d, struct typec_altmode_driver, \
+                                         driver)
+
+#define typec_altmode_register_driver(drv) \
+               __typec_altmode_register_driver(drv, THIS_MODULE)
+int __typec_altmode_register_driver(struct typec_altmode_driver *drv,
+                                   struct module *module);
+void typec_altmode_unregister_driver(struct typec_altmode_driver *drv);
+
+#define module_typec_altmode_driver(__typec_altmode_driver) \
+       module_driver(__typec_altmode_driver, typec_altmode_register_driver, \
+                     typec_altmode_unregister_driver)
+
+#endif /* __USB_TYPEC_ALTMODE_H */
diff --git a/include/linux/usb/typec_dp.h b/include/linux/usb/typec_dp.h
new file mode 100644 (file)
index 0000000..55ae781
--- /dev/null
@@ -0,0 +1,95 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __USB_TYPEC_DP_H
+#define __USB_TYPEC_DP_H
+
+#include <linux/usb/typec_altmode.h>
+
+#define USB_TYPEC_DP_SID       0xff01
+#define USB_TYPEC_DP_MODE      1
+
+/*
+ * Connector states matching the pin assignments in DisplayPort Alt Mode
+ * Specification.
+ *
+ * These values are meant primarily to be used by the mux drivers, but they are
+ * also used as the "value" part in the alternate mode notification chain, so
+ * receivers of those notifications will always see them.
+ *
+ * Note. DisplayPort USB Type-C Alt Mode Specification version 1.0b deprecated
+ * pin assignments A, B and F, but they are still defined here for legacy
+ * purposes.
+ */
+enum {
+       TYPEC_DP_STATE_A = TYPEC_STATE_MODAL,   /* Not supported after v1.0b */
+       TYPEC_DP_STATE_B,                       /* Not supported after v1.0b */
+       TYPEC_DP_STATE_C,
+       TYPEC_DP_STATE_D,
+       TYPEC_DP_STATE_E,
+       TYPEC_DP_STATE_F,                       /* Not supported after v1.0b */
+};
+
+/*
+ * struct typec_displayport_data - DisplayPort Alt Mode specific data
+ * @status: Status Update command VDO content
+ * @conf: Configure command VDO content
+ *
+ * This structure is delivered as the data part with the notifications. It
+ * contains the VDOs from the two DisplayPort Type-C alternate mode specific
+ * commands: Status Update and Configure.
+ *
+ * @status will show for example the status of the HPD signal.
+ */
+struct typec_displayport_data {
+       u32 status;
+       u32 conf;
+};
+
+enum {
+       DP_PIN_ASSIGN_A, /* Not supported after v1.0b */
+       DP_PIN_ASSIGN_B, /* Not supported after v1.0b */
+       DP_PIN_ASSIGN_C,
+       DP_PIN_ASSIGN_D,
+       DP_PIN_ASSIGN_E,
+       DP_PIN_ASSIGN_F, /* Not supported after v1.0b */
+};
+
+/* DisplayPort alt mode specific commands */
+#define DP_CMD_STATUS_UPDATE           VDO_CMD_VENDOR(0)
+#define DP_CMD_CONFIGURE               VDO_CMD_VENDOR(1)
+
+/* DisplayPort Capabilities VDO bits (returned with Discover Modes) */
+#define DP_CAP_CAPABILITY(_cap_)       ((_cap_) & 3)
+#define   DP_CAP_UFP_D                 1
+#define   DP_CAP_DFP_D                 2
+#define   DP_CAP_DFP_D_AND_UFP_D       3
+#define DP_CAP_DP_SIGNALING            BIT(2) /* Always set */
+#define DP_CAP_GEN2                    BIT(3) /* Reserved after v1.0b */
+#define DP_CAP_RECEPTACLE              BIT(6)
+#define DP_CAP_USB                     BIT(7)
+#define DP_CAP_DFP_D_PIN_ASSIGN(_cap_) (((_cap_) & GENMASK(15, 8)) >> 8)
+#define DP_CAP_UFP_D_PIN_ASSIGN(_cap_) (((_cap_) & GENMASK(23, 16)) >> 16)
+
+/* DisplayPort Status Update VDO bits */
+#define DP_STATUS_CONNECTION(_status_) ((_status_) & 3)
+#define   DP_STATUS_CON_DISABLED       0
+#define   DP_STATUS_CON_DFP_D          1
+#define   DP_STATUS_CON_UFP_D          2
+#define   DP_STATUS_CON_BOTH           3
+#define DP_STATUS_POWER_LOW            BIT(2)
+#define DP_STATUS_ENABLED              BIT(3)
+#define DP_STATUS_PREFER_MULTI_FUNC    BIT(4)
+#define DP_STATUS_SWITCH_TO_USB                BIT(5)
+#define DP_STATUS_EXIT_DP_MODE         BIT(6)
+#define DP_STATUS_HPD_STATE            BIT(7) /* 0 = HPD_Low, 1 = HPD_High */
+#define DP_STATUS_IRQ_HPD              BIT(8)
+
+/* DisplayPort Configurations VDO bits */
+#define DP_CONF_CURRENTLY(_conf_)      ((_conf_) & 3)
+#define DP_CONF_UFP_U_AS_DFP_D         BIT(0)
+#define DP_CONF_UFP_U_AS_UFP_D         BIT(1)
+#define DP_CONF_SIGNALING_DP           BIT(2)
+#define DP_CONF_SIGNALING_GEN_2                BIT(3) /* Reserved after v1.0b */
+#define DP_CONF_PIN_ASSIGNEMENT_SHIFT  8
+#define DP_CONF_PIN_ASSIGNEMENT_MASK   GENMASK(15, 8)
+
+#endif /* __USB_TYPEC_DP_H */
index 12c1b05..79293f6 100644 (file)
@@ -47,7 +47,7 @@ void typec_switch_put(struct typec_switch *sw);
 int typec_switch_register(struct typec_switch *sw);
 void typec_switch_unregister(struct typec_switch *sw);
 
-struct typec_mux *typec_mux_get(struct device *dev);
+struct typec_mux *typec_mux_get(struct device *dev, const char *name);
 void typec_mux_put(struct typec_mux *mux);
 int typec_mux_register(struct typec_mux *mux);
 void typec_mux_unregister(struct typec_mux *mux);
diff --git a/include/uapi/linux/usb/g_uvc.h b/include/uapi/linux/usb/g_uvc.h
new file mode 100644 (file)
index 0000000..3c9ee30
--- /dev/null
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * g_uvc.h  --  USB Video Class Gadget driver API
+ *
+ * Copyright (C) 2009-2010 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ */
+
+#ifndef __LINUX_USB_G_UVC_H
+#define __LINUX_USB_G_UVC_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+#include <linux/usb/ch9.h>
+
+#define UVC_EVENT_FIRST                        (V4L2_EVENT_PRIVATE_START + 0)
+#define UVC_EVENT_CONNECT              (V4L2_EVENT_PRIVATE_START + 0)
+#define UVC_EVENT_DISCONNECT           (V4L2_EVENT_PRIVATE_START + 1)
+#define UVC_EVENT_STREAMON             (V4L2_EVENT_PRIVATE_START + 2)
+#define UVC_EVENT_STREAMOFF            (V4L2_EVENT_PRIVATE_START + 3)
+#define UVC_EVENT_SETUP                        (V4L2_EVENT_PRIVATE_START + 4)
+#define UVC_EVENT_DATA                 (V4L2_EVENT_PRIVATE_START + 5)
+#define UVC_EVENT_LAST                 (V4L2_EVENT_PRIVATE_START + 5)
+
+struct uvc_request_data {
+       __s32 length;
+       __u8 data[60];
+};
+
+struct uvc_event {
+       union {
+               enum usb_device_speed speed;
+               struct usb_ctrlrequest req;
+               struct uvc_request_data data;
+       };
+};
+
+#define UVCIOC_SEND_RESPONSE           _IOW('U', 1, struct uvc_request_data)
+
+#endif /* __LINUX_USB_G_UVC_H */
index 03f6adc..729af2f 100644 (file)
@@ -16,6 +16,8 @@
 #ifndef __LINUX_USB_TMC_H
 #define __LINUX_USB_TMC_H
 
+#include <linux/types.h>   /* __u8 etc */
+
 /* USB TMC status values */
 #define USBTMC_STATUS_SUCCESS                          0x01
 #define USBTMC_STATUS_PENDING                          0x02
 #define USBTMC488_REQUEST_GOTO_LOCAL                   161
 #define USBTMC488_REQUEST_LOCAL_LOCKOUT                        162
 
+struct usbtmc_termchar {
+       __u8 term_char;
+       __u8 term_char_enabled;
+} __attribute__ ((packed));
+
 /* Request values for USBTMC driver's ioctl entry point */
 #define USBTMC_IOC_NR                  91
 #define USBTMC_IOCTL_INDICATOR_PULSE   _IO(USBTMC_IOC_NR, 1)
 #define USBTMC_IOCTL_ABORT_BULK_IN     _IO(USBTMC_IOC_NR, 4)
 #define USBTMC_IOCTL_CLEAR_OUT_HALT    _IO(USBTMC_IOC_NR, 6)
 #define USBTMC_IOCTL_CLEAR_IN_HALT     _IO(USBTMC_IOC_NR, 7)
+#define USBTMC_IOCTL_GET_TIMEOUT       _IOR(USBTMC_IOC_NR, 9, __u32)
+#define USBTMC_IOCTL_SET_TIMEOUT       _IOW(USBTMC_IOC_NR, 10, __u32)
+#define USBTMC_IOCTL_EOM_ENABLE                _IOW(USBTMC_IOC_NR, 11, __u8)
+#define USBTMC_IOCTL_CONFIG_TERMCHAR   _IOW(USBTMC_IOC_NR, 12, struct usbtmc_termchar)
+
 #define USBTMC488_IOCTL_GET_CAPS       _IOR(USBTMC_IOC_NR, 17, unsigned char)
 #define USBTMC488_IOCTL_READ_STB       _IOR(USBTMC_IOC_NR, 18, unsigned char)
 #define USBTMC488_IOCTL_REN_CONTROL    _IOW(USBTMC_IOC_NR, 19, unsigned char)
 #define USBTMC488_IOCTL_GOTO_LOCAL     _IO(USBTMC_IOC_NR, 20)
 #define USBTMC488_IOCTL_LOCAL_LOCKOUT  _IO(USBTMC_IOC_NR, 21)
+#define USBTMC488_IOCTL_TRIGGER                _IO(USBTMC_IOC_NR, 22)
 
 /* Driver encoded usb488 capabilities */
 #define USBTMC488_CAPABILITY_TRIGGER         1
index 6667f7b..2930044 100644 (file)
@@ -221,5 +221,9 @@ int main(void)
        DEVID_FIELD(tb_service_id, protocol_version);
        DEVID_FIELD(tb_service_id, protocol_revision);
 
+       DEVID(typec_device_id);
+       DEVID_FIELD(typec_device_id, svid);
+       DEVID_FIELD(typec_device_id, mode);
+
        return 0;
 }
index 52fd54a..7be4369 100644 (file)
@@ -1352,6 +1352,19 @@ static int do_tbsvc_entry(const char *filename, void *symval, char *alias)
 }
 ADD_TO_DEVTABLE("tbsvc", tb_service_id, do_tbsvc_entry);
 
+/* Looks like: typec:idNmN */
+static int do_typec_entry(const char *filename, void *symval, char *alias)
+{
+       DEF_FIELD(symval, typec_device_id, svid);
+       DEF_FIELD(symval, typec_device_id, mode);
+
+       sprintf(alias, "typec:id%04X", svid);
+       ADD(alias, "m", mode != TYPEC_ANY_MODE, mode);
+
+       return 1;
+}
+ADD_TO_DEVTABLE("typec", typec_device_id, do_typec_entry);
+
 /* Does namelen bytes of name exactly match the symbol? */
 static bool sym_is(const char *name, unsigned namelen, const char *symbol)
 {
index 1893d0f..a72df93 100755 (executable)
@@ -46,7 +46,6 @@ if ! /sbin/modprobe -q -n usbip_host; then
 fi
 
 if /sbin/modprobe -q usbip_host; then
-       /sbin/modprobe -q -r test_bitmap
        echo "usbip_test: module usbip_host is loaded [OK]"
 else
        echo "usbip_test: module usbip_host failed to load [FAIL]"
@@ -56,7 +55,6 @@ fi
 
 echo "Load vhci_hcd module"
 if /sbin/modprobe -q vhci_hcd; then
-       /sbin/modprobe -q -r test_bitmap
        echo "usbip_test: module vhci_hcd is loaded [OK]"
 else
        echo "usbip_test: module vhci_hcd failed to load [FAIL]"