1
0
Fork 0

USB/PHY patches for 4.19-rc1

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
 
 Full details are in the shortlog.
 
 All of these have been in linux-next with no reported issues for a
 while.
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 
 iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCW3hBPA8cZ3JlZ0Brcm9h
 aC5jb20ACgkQMUfUDdst+yloNwCggMZi9m8Krjq7d7aLw5oJJex/nIAAn0jeADOT
 NpoCgrtGHjwrATxN5/Ke
 =jXa3
 -----END PGP SIGNATURE-----

Merge tag 'usb-4.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

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
  ...
This commit is contained in:
Linus Torvalds 2018-08-18 10:21:49 -07:00
commit 5695d5d197
165 changed files with 5849 additions and 1815 deletions

View file

@ -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

View file

@ -263,3 +263,8 @@ Description: Specific streaming header descriptors
is connected is connected
bmInfo - capabilities of this video streaming bmInfo - capabilities of this video streaming
interface 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

View file

@ -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.

View file

@ -222,70 +222,12 @@ Description:
available. The value can be polled. 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. What: /sys/class/typec/<port>/<alt mode>/supported_roles
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
Date: April 2017 Date: April 2017
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com> Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Description: Description:
Space separated list of the supported roles. 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 Valid values: source, sink

View file

@ -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).

View file

@ -15,6 +15,33 @@ Optional properties:
- type: size of the connector, should be specified in case of USB-A, USB-B - type: size of the connector, should be specified in case of USB-A, USB-B
non-fullsize connectors: "mini", "micro". 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: Required nodes:
- any data bus to the connector should be modeled using the OF graph bindings - 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 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>;
};
};

View file

@ -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";
};

View file

@ -47,6 +47,12 @@ Required properties (port (child) node):
- PHY_TYPE_PCIE - PHY_TYPE_PCIE
- PHY_TYPE_SATA - 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: Example:
u3phy: usb-phy@11290000 { u3phy: usb-phy@11290000 {

View file

@ -12,7 +12,14 @@ Required properties:
"qcom,sdm845-qmp-usb3-phy" for USB3 QMP V3 phy on sdm845, "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. "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 - #clock-cells: must be 1
- Phy pll outputs a bunch of clocks for Tx, Rx and Pipe - Phy pll outputs a bunch of clocks for Tx, Rx and Pipe
@ -60,7 +67,10 @@ Required nodes:
Required properties for child node: Required properties for child node:
- reg: list of offset and length pairs of register sets for PHY blocks - - 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 - #phy-cells: must be 0

View file

@ -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>;
};

View file

@ -10,6 +10,8 @@ Required properties:
SoC. SoC.
"renesas,usb2-phy-r8a77965" if the device is a part of an "renesas,usb2-phy-r8a77965" if the device is a part of an
R8A77965 SoC. 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 "renesas,usb2-phy-r8a77995" if the device is a part of an
R8A77995 SoC. R8A77995 SoC.
"renesas,rcar-gen3-usb2-phy" for a generic R-Car Gen3 compatible device. "renesas,rcar-gen3-usb2-phy" for a generic R-Car Gen3 compatible device.

View file

@ -96,6 +96,11 @@ Optional properties:
enable periodic ESS TX threshold. enable periodic ESS TX threshold.
- <DEPRECATED> tx-fifo-resize: determines if the FIFO *has* to be reallocated. - <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 - in addition all properties from usb-xhci.txt from the current directory are
supported as well supported as well
@ -108,4 +113,5 @@ dwc3@4a030000 {
reg = <0x4a030000 0xcfff>; reg = <0x4a030000 0xcfff>;
interrupts = <0 92 4> interrupts = <0 92 4>
usb-phy = <&usb2_phy>, <&usb3,phy>; usb-phy = <&usb2_phy>, <&usb3,phy>;
snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
}; };

View file

@ -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>;
};

View file

@ -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>;
};
};
};
};
};

View file

@ -14,6 +14,7 @@ Required properties:
- "renesas,xhci-r8a7795" for r8a7795 SoC - "renesas,xhci-r8a7795" for r8a7795 SoC
- "renesas,xhci-r8a7796" for r8a7796 SoC - "renesas,xhci-r8a7796" for r8a7796 SoC
- "renesas,xhci-r8a77965" for r8a77965 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 - "renesas,rcar-gen2-xhci" for a generic R-Car Gen2 or RZ/G1 compatible
device device
- "renesas,rcar-gen3-xhci" for a generic R-Car Gen3 compatible device - "renesas,rcar-gen3-xhci" for a generic R-Car Gen3 compatible device

View file

@ -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

View file

@ -418,15 +418,6 @@ Current status:
why it is wise to cut down on the rate used is wise for large why it is wise to cut down on the rate used is wise for large
transfers until this is settled. 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 See http://www.uuhaus.de/linux/palmconnect.html for up-to-date
information on this driver. information on this driver.

View 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-arm-kernel@lists.infradead.org (moderated for non-subscribers)
L: linux-mediatek@lists.infradead.org (moderated for non-subscribers) L: linux-mediatek@lists.infradead.org (moderated for non-subscribers)
S: Maintained 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 ARM/MICREL KS8695 ARCHITECTURE
M: Greg Ungerer <gerg@uclinux.org> M: Greg Ungerer <gerg@uclinux.org>
@ -15117,7 +15118,7 @@ L: linux-usb@vger.kernel.org
S: Maintained S: Maintained
F: drivers/usb/typec/mux/pi3usb30532.c F: drivers/usb/typec/mux/pi3usb30532.c
USB TYPEC SUBSYSTEM USB TYPEC CLASS
M: Heikki Krogerus <heikki.krogerus@linux.intel.com> M: Heikki Krogerus <heikki.krogerus@linux.intel.com>
L: linux-usb@vger.kernel.org L: linux-usb@vger.kernel.org
S: Maintained S: Maintained
@ -15126,6 +15127,15 @@ F: Documentation/driver-api/usb/typec.rst
F: drivers/usb/typec/ F: drivers/usb/typec/
F: include/linux/usb/typec.h 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 USB UHCI DRIVER
M: Alan Stern <stern@rowland.harvard.edu> M: Alan Stern <stern@rowland.harvard.edu>
L: linux-usb@vger.kernel.org L: linux-usb@vger.kernel.org
@ -15156,6 +15166,7 @@ L: linux-usb@vger.kernel.org
S: Maintained S: Maintained
F: drivers/usb/gadget/function/*uvc* F: drivers/usb/gadget/function/*uvc*
F: drivers/usb/gadget/legacy/webcam.c F: drivers/usb/gadget/legacy/webcam.c
F: include/uapi/linux/usb/g_uvc.h
USB WIRELESS RNDIS DRIVER (rndis_wlan) USB WIRELESS RNDIS DRIVER (rndis_wlan)
M: Jussi Kivilinna <jussi.kivilinna@iki.fi> M: Jussi Kivilinna <jussi.kivilinna@iki.fi>

View file

@ -160,13 +160,14 @@ static void nfcmrvl_tx_complete(struct urb *urb)
struct nci_dev *ndev = (struct nci_dev *)skb->dev; struct nci_dev *ndev = (struct nci_dev *)skb->dev;
struct nfcmrvl_private *priv = nci_get_drvdata(ndev); struct nfcmrvl_private *priv = nci_get_drvdata(ndev);
struct nfcmrvl_usb_drv_data *drv_data = priv->drv_data; struct nfcmrvl_usb_drv_data *drv_data = priv->drv_data;
unsigned long flags;
nfc_info(priv->dev, "urb %p status %d count %d\n", nfc_info(priv->dev, "urb %p status %d count %d\n",
urb, urb->status, urb->actual_length); urb, urb->status, urb->actual_length);
spin_lock(&drv_data->txlock); spin_lock_irqsave(&drv_data->txlock, flags);
drv_data->tx_in_flight--; drv_data->tx_in_flight--;
spin_unlock(&drv_data->txlock); spin_unlock_irqrestore(&drv_data->txlock, flags);
kfree(urb->setup_packet); kfree(urb->setup_packet);
kfree_skb(skb); kfree_skb(skb);

View file

@ -80,3 +80,13 @@ config PHY_BRCM_USB
This driver is required by the USB XHCI, EHCI and OHCI This driver is required by the USB XHCI, EHCI and OHCI
drivers. drivers.
If unsure, say N. 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.

View file

@ -9,3 +9,5 @@ obj-$(CONFIG_PHY_BRCM_SATA) += phy-brcm-sata.o
obj-$(CONFIG_PHY_BRCM_USB) += phy-brcm-usb-dvr.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 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

View file

@ -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");

View file

@ -1,13 +1,10 @@
// SPDX-License-Identifier: GPL-2.0
/* /*
* Marvell Berlin SATA PHY driver * Marvell Berlin SATA PHY driver
* *
* Copyright (C) 2014 Marvell Technology Group Ltd. * Copyright (C) 2014 Marvell Technology Group Ltd.
* *
* Antoine Ténart <antoine.tenart@free-electrons.com> * 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> #include <linux/clk.h>

View file

@ -1,12 +1,9 @@
// SPDX-License-Identifier: GPL-2.0
/* /*
* Copyright (C) 2014 Marvell Technology Group Ltd. * Copyright (C) 2014 Marvell Technology Group Ltd.
* *
* Antoine Tenart <antoine.tenart@free-electrons.com> * Antoine Tenart <antoine.tenart@free-electrons.com>
* Jisheng Zhang <jszhang@marvell.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> #include <linux/io.h>

View file

@ -1,11 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
/* /*
* Copyright (C) 2017 Marvell * Copyright (C) 2017 Marvell
* *
* Antoine Tenart <antoine.tenart@free-electrons.com> * 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> #include <linux/io.h>

View file

@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
# #
# Makefile for the phy drivers. # Makefile for the phy drivers.
# #

View file

@ -1,16 +1,8 @@
// SPDX-License-Identifier: GPL-2.0
/* /*
* Copyright (c) 2015 MediaTek Inc. * Copyright (c) 2015 MediaTek Inc.
* Author: Chunfeng Yun <chunfeng.yun@mediatek.com> * 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> #include <dt-bindings/phy/phy.h>
@ -50,6 +42,12 @@
#define PA0_RG_U2PLL_FORCE_ON BIT(15) #define PA0_RG_U2PLL_FORCE_ON BIT(15)
#define PA0_RG_USB20_INTR_EN BIT(5) #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 U3P_USBPHYACR2 0x008
#define PA2_RG_SIF_U2PLL_FORCE_EN BIT(18) #define PA2_RG_SIF_U2PLL_FORCE_EN BIT(18)
@ -103,6 +101,9 @@
#define P2C_RG_AVALID BIT(2) #define P2C_RG_AVALID BIT(2)
#define P2C_RG_IDDIG BIT(1) #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 U3P_U3_CHIP_GPIO_CTLD 0x0c
#define P3C_REG_IP_SW_RST BIT(31) #define P3C_REG_IP_SW_RST BIT(31)
#define P3C_MCU_BUS_CK_GATE_EN BIT(30) #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 */ struct clk *ref_clk; /* reference clock of anolog phy */
u32 index; u32 index;
u8 type; u8 type;
int eye_src;
int eye_vrt;
int eye_term;
bool bc12_en;
}; };
struct mtk_tphy { struct mtk_tphy {
@ -320,6 +325,10 @@ static void hs_slew_rate_calibrate(struct mtk_tphy *tphy,
int fm_out; int fm_out;
u32 tmp; u32 tmp;
/* use force value */
if (instance->eye_src)
return;
/* enable USB ring oscillator */ /* enable USB ring oscillator */
tmp = readl(com + U3P_USBPHYACR5); tmp = readl(com + U3P_USBPHYACR5);
tmp |= PA5_RG_U2_HSTX_SRCAL_EN; 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) static int mtk_phy_init(struct phy *phy)
{ {
struct mtk_phy_instance *instance = phy_get_drvdata(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) { switch (instance->type) {
case PHY_TYPE_USB2: case PHY_TYPE_USB2:
u2_phy_instance_init(tphy, instance); u2_phy_instance_init(tphy, instance);
u2_phy_props_set(tphy, instance);
break; break;
case PHY_TYPE_USB3: case PHY_TYPE_USB3:
u3_phy_instance_init(tphy, instance); u3_phy_instance_init(tphy, instance);
@ -959,6 +1024,8 @@ static struct phy *mtk_phy_xlate(struct device *dev,
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
} }
phy_parse_property(tphy, instance);
return instance->phy; return instance->phy;
} }

View 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_OTG:
case PHY_MODE_USB_HOST: case PHY_MODE_USB_HOST:
val |= ULPI_INT_IDGRD; val |= ULPI_INT_IDGRD;
/* fall through */
case PHY_MODE_USB_DEVICE: case PHY_MODE_USB_DEVICE:
val |= ULPI_INT_SESS_VALID; val |= ULPI_INT_SESS_VALID;
default: default:

View file

@ -8,6 +8,13 @@ config PHY_RCAR_GEN2
help help
Support for USB PHY found on Renesas R-Car generation 2 SoCs. 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 config PHY_RCAR_GEN3_USB2
tristate "Renesas R-Car generation 3 USB 2.0 PHY driver" tristate "Renesas R-Car generation 3 USB 2.0 PHY driver"
depends on ARCH_RENESAS depends on ARCH_RENESAS

View file

@ -1,3 +1,4 @@
obj-$(CONFIG_PHY_RCAR_GEN2) += phy-rcar-gen2.o 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_USB2) += phy-rcar-gen3-usb2.o
obj-$(CONFIG_PHY_RCAR_GEN3_USB3) += phy-rcar-gen3-usb3.o obj-$(CONFIG_PHY_RCAR_GEN3_USB3) += phy-rcar-gen3-usb3.o

View file

@ -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>");

View file

@ -106,8 +106,6 @@ source "drivers/staging/greybus/Kconfig"
source "drivers/staging/vc04_services/Kconfig" source "drivers/staging/vc04_services/Kconfig"
source "drivers/staging/typec/Kconfig"
source "drivers/staging/vboxvideo/Kconfig" source "drivers/staging/vboxvideo/Kconfig"
source "drivers/staging/pi433/Kconfig" source "drivers/staging/pi433/Kconfig"

View file

@ -2,7 +2,6 @@
# Makefile for staging directory # Makefile for staging directory
obj-y += media/ obj-y += media/
obj-y += typec/
obj-$(CONFIG_PRISM2_USB) += wlan-ng/ obj-$(CONFIG_PRISM2_USB) += wlan-ng/
obj-$(CONFIG_COMEDI) += comedi/ obj-$(CONFIG_COMEDI) += comedi/
obj-$(CONFIG_FB_OLPC_DCON) += olpc_dcon/ obj-$(CONFIG_FB_OLPC_DCON) += olpc_dcon/

View file

@ -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

View file

@ -1,2 +0,0 @@
obj-$(CONFIG_TYPEC_TCPCI) += tcpci.o
obj-$(CONFIG_TYPEC_RT1711H) += tcpci_rt1711h.o

View file

@ -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>.

View 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 = { 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 = { 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[] = { static const struct of_device_id tegra_udc_of_match[] = {

View file

@ -276,6 +276,7 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf)
{ {
int newctrl; int newctrl;
int difference; int difference;
unsigned long flags;
struct usb_cdc_notification *dr = (struct usb_cdc_notification *)buf; struct usb_cdc_notification *dr = (struct usb_cdc_notification *)buf;
unsigned char *data = buf + sizeof(struct usb_cdc_notification); 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; difference = acm->ctrlin ^ newctrl;
spin_lock(&acm->read_lock); spin_lock_irqsave(&acm->read_lock, flags);
acm->ctrlin = newctrl; acm->ctrlin = newctrl;
acm->oldcount = acm->iocount; acm->oldcount = acm->iocount;
@ -321,7 +322,7 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf)
acm->iocount.parity++; acm->iocount.parity++;
if (difference & ACM_CTRL_OVERRUN) if (difference & ACM_CTRL_OVERRUN)
acm->iocount.overrun++; acm->iocount.overrun++;
spin_unlock(&acm->read_lock); spin_unlock_irqrestore(&acm->read_lock, flags);
if (difference) if (difference)
wake_up_all(&acm->wioctl); wake_up_all(&acm->wioctl);
@ -1378,6 +1379,9 @@ made_compressed_probe:
if (acm == NULL) if (acm == NULL)
goto alloc_fail; goto alloc_fail;
tty_port_init(&acm->port);
acm->port.ops = &acm_port_ops;
minor = acm_alloc_minor(acm); minor = acm_alloc_minor(acm);
if (minor < 0) if (minor < 0)
goto alloc_fail1; goto alloc_fail1;
@ -1413,22 +1417,20 @@ made_compressed_probe:
acm->out = usb_sndintpipe(usb_dev, epwrite->bEndpointAddress); acm->out = usb_sndintpipe(usb_dev, epwrite->bEndpointAddress);
else else
acm->out = usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress); acm->out = usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress);
tty_port_init(&acm->port);
acm->port.ops = &acm_port_ops;
init_usb_anchor(&acm->delayed); init_usb_anchor(&acm->delayed);
acm->quirks = quirks; acm->quirks = quirks;
buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma); buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
if (!buf) if (!buf)
goto alloc_fail2; goto alloc_fail1;
acm->ctrl_buffer = buf; acm->ctrl_buffer = buf;
if (acm_write_buffers_alloc(acm) < 0) if (acm_write_buffers_alloc(acm) < 0)
goto alloc_fail4; goto alloc_fail2;
acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL); acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
if (!acm->ctrlurb) if (!acm->ctrlurb)
goto alloc_fail5; goto alloc_fail3;
for (i = 0; i < num_rx_buf; i++) { for (i = 0; i < num_rx_buf; i++) {
struct acm_rb *rb = &(acm->read_buffers[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->base = usb_alloc_coherent(acm->dev, readsize, GFP_KERNEL,
&rb->dma); &rb->dma);
if (!rb->base) if (!rb->base)
goto alloc_fail6; goto alloc_fail4;
rb->index = i; rb->index = i;
rb->instance = acm; rb->instance = acm;
urb = usb_alloc_urb(0, GFP_KERNEL); urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) if (!urb)
goto alloc_fail6; goto alloc_fail4;
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
urb->transfer_dma = rb->dma; urb->transfer_dma = rb->dma;
@ -1465,7 +1467,7 @@ made_compressed_probe:
snd->urb = usb_alloc_urb(0, GFP_KERNEL); snd->urb = usb_alloc_urb(0, GFP_KERNEL);
if (snd->urb == NULL) if (snd->urb == NULL)
goto alloc_fail7; goto alloc_fail5;
if (usb_endpoint_xfer_int(epwrite)) if (usb_endpoint_xfer_int(epwrite))
usb_fill_int_urb(snd->urb, usb_dev, acm->out, 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); i = device_create_file(&intf->dev, &dev_attr_bmCapabilities);
if (i < 0) if (i < 0)
goto alloc_fail7; goto alloc_fail5;
if (h.usb_cdc_country_functional_desc) { /* export the country data */ if (h.usb_cdc_country_functional_desc) { /* export the country data */
struct usb_cdc_country_functional_desc * cfd = struct usb_cdc_country_functional_desc * cfd =
@ -1542,7 +1544,7 @@ skip_countries:
&control_interface->dev); &control_interface->dev);
if (IS_ERR(tty_dev)) { if (IS_ERR(tty_dev)) {
rv = PTR_ERR(tty_dev); rv = PTR_ERR(tty_dev);
goto alloc_fail8; goto alloc_fail6;
} }
if (quirks & CLEAR_HALT_CONDITIONS) { if (quirks & CLEAR_HALT_CONDITIONS) {
@ -1551,7 +1553,7 @@ skip_countries:
} }
return 0; return 0;
alloc_fail8: alloc_fail6:
if (acm->country_codes) { if (acm->country_codes) {
device_remove_file(&acm->control->dev, device_remove_file(&acm->control->dev,
&dev_attr_wCountryCodes); &dev_attr_wCountryCodes);
@ -1560,23 +1562,21 @@ alloc_fail8:
kfree(acm->country_codes); kfree(acm->country_codes);
} }
device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities); device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities);
alloc_fail7: alloc_fail5:
usb_set_intfdata(intf, NULL); usb_set_intfdata(intf, NULL);
for (i = 0; i < ACM_NW; i++) for (i = 0; i < ACM_NW; i++)
usb_free_urb(acm->wb[i].urb); usb_free_urb(acm->wb[i].urb);
alloc_fail6: alloc_fail4:
for (i = 0; i < num_rx_buf; i++) for (i = 0; i < num_rx_buf; i++)
usb_free_urb(acm->read_urbs[i]); usb_free_urb(acm->read_urbs[i]);
acm_read_buffers_free(acm); acm_read_buffers_free(acm);
usb_free_urb(acm->ctrlurb); usb_free_urb(acm->ctrlurb);
alloc_fail5: alloc_fail3:
acm_write_buffers_free(acm); acm_write_buffers_free(acm);
alloc_fail4:
usb_free_coherent(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
alloc_fail2: alloc_fail2:
acm_release_minor(acm); usb_free_coherent(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
alloc_fail1: alloc_fail1:
kfree(acm); tty_port_put(&acm->port);
alloc_fail: alloc_fail:
return rv; return rv;
} }

View file

@ -96,6 +96,7 @@ struct wdm_device {
struct mutex rlock; struct mutex rlock;
wait_queue_head_t wait; wait_queue_head_t wait;
struct work_struct rxwork; struct work_struct rxwork;
struct work_struct service_outs_intr;
int werr; int werr;
int rerr; int rerr;
int resp_count; int resp_count;
@ -141,26 +142,26 @@ found:
static void wdm_out_callback(struct urb *urb) static void wdm_out_callback(struct urb *urb)
{ {
struct wdm_device *desc; struct wdm_device *desc;
unsigned long flags;
desc = urb->context; desc = urb->context;
spin_lock(&desc->iuspin); spin_lock_irqsave(&desc->iuspin, flags);
desc->werr = urb->status; desc->werr = urb->status;
spin_unlock(&desc->iuspin); spin_unlock_irqrestore(&desc->iuspin, flags);
kfree(desc->outbuf); kfree(desc->outbuf);
desc->outbuf = NULL; desc->outbuf = NULL;
clear_bit(WDM_IN_USE, &desc->flags); clear_bit(WDM_IN_USE, &desc->flags);
wake_up(&desc->wait); wake_up(&desc->wait);
} }
/* forward declaration */
static int service_outstanding_interrupt(struct wdm_device *desc);
static void wdm_in_callback(struct urb *urb) static void wdm_in_callback(struct urb *urb)
{ {
unsigned long flags;
struct wdm_device *desc = urb->context; struct wdm_device *desc = urb->context;
int status = urb->status; int status = urb->status;
int length = urb->actual_length; int length = urb->actual_length;
spin_lock(&desc->iuspin); spin_lock_irqsave(&desc->iuspin, flags);
clear_bit(WDM_RESPONDING, &desc->flags); clear_bit(WDM_RESPONDING, &desc->flags);
if (status) { if (status) {
@ -209,8 +210,6 @@ static void wdm_in_callback(struct urb *urb)
} }
} }
skip_error: skip_error:
set_bit(WDM_READ, &desc->flags);
wake_up(&desc->wait);
if (desc->rerr) { if (desc->rerr) {
/* /*
@ -219,14 +218,17 @@ skip_error:
* We should respond to further attempts from the device to send * We should respond to further attempts from the device to send
* data, so that we can get unstuck. * 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_irqrestore(&desc->iuspin, flags);
spin_unlock(&desc->iuspin);
} }
static void wdm_int_callback(struct urb *urb) static void wdm_int_callback(struct urb *urb)
{ {
unsigned long flags;
int rv = 0; int rv = 0;
int responding; int responding;
int status = urb->status; int status = urb->status;
@ -286,7 +288,7 @@ static void wdm_int_callback(struct urb *urb)
goto exit; goto exit;
} }
spin_lock(&desc->iuspin); spin_lock_irqsave(&desc->iuspin, flags);
responding = test_and_set_bit(WDM_RESPONDING, &desc->flags); responding = test_and_set_bit(WDM_RESPONDING, &desc->flags);
if (!desc->resp_count++ && !responding if (!desc->resp_count++ && !responding
&& !test_bit(WDM_DISCONNECTING, &desc->flags) && !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); rv = usb_submit_urb(desc->response, GFP_ATOMIC);
dev_dbg(&desc->intf->dev, "submit response URB %d\n", rv); dev_dbg(&desc->intf->dev, "submit response URB %d\n", rv);
} }
spin_unlock(&desc->iuspin); spin_unlock_irqrestore(&desc->iuspin, flags);
if (rv < 0) { if (rv < 0) {
clear_bit(WDM_RESPONDING, &desc->flags); clear_bit(WDM_RESPONDING, &desc->flags);
if (rv == -EPERM) 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 --- */ /* --- hotplug --- */
static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor *ep, 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->inum = cpu_to_le16((u16)intf->cur_altsetting->desc.bInterfaceNumber);
desc->intf = intf; desc->intf = intf;
INIT_WORK(&desc->rxwork, wdm_rxwork); INIT_WORK(&desc->rxwork, wdm_rxwork);
INIT_WORK(&desc->service_outs_intr, service_interrupt_work);
rv = -EINVAL; rv = -EINVAL;
if (!usb_endpoint_is_int_in(ep)) if (!usb_endpoint_is_int_in(ep))
@ -964,6 +982,7 @@ static void wdm_disconnect(struct usb_interface *intf)
mutex_lock(&desc->wlock); mutex_lock(&desc->wlock);
kill_urbs(desc); kill_urbs(desc);
cancel_work_sync(&desc->rxwork); cancel_work_sync(&desc->rxwork);
cancel_work_sync(&desc->service_outs_intr);
mutex_unlock(&desc->wlock); mutex_unlock(&desc->wlock);
mutex_unlock(&desc->rlock); 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 */ /* callback submits work - order is essential */
kill_urbs(desc); kill_urbs(desc);
cancel_work_sync(&desc->rxwork); cancel_work_sync(&desc->rxwork);
cancel_work_sync(&desc->service_outs_intr);
} }
if (!PMSG_IS_AUTO(message)) { if (!PMSG_IS_AUTO(message)) {
mutex_unlock(&desc->wlock); mutex_unlock(&desc->wlock);
@ -1065,6 +1085,7 @@ static int wdm_pre_reset(struct usb_interface *intf)
mutex_lock(&desc->wlock); mutex_lock(&desc->wlock);
kill_urbs(desc); kill_urbs(desc);
cancel_work_sync(&desc->rxwork); cancel_work_sync(&desc->rxwork);
cancel_work_sync(&desc->service_outs_intr);
return 0; return 0;
} }

View file

@ -292,6 +292,7 @@ static void usblp_bulk_read(struct urb *urb)
{ {
struct usblp *usblp = urb->context; struct usblp *usblp = urb->context;
int status = urb->status; int status = urb->status;
unsigned long flags;
if (usblp->present && usblp->used) { if (usblp->present && usblp->used) {
if (status) if (status)
@ -299,14 +300,14 @@ static void usblp_bulk_read(struct urb *urb)
"nonzero read bulk status received: %d\n", "nonzero read bulk status received: %d\n",
usblp->minor, status); usblp->minor, status);
} }
spin_lock(&usblp->lock); spin_lock_irqsave(&usblp->lock, flags);
if (status < 0) if (status < 0)
usblp->rstatus = status; usblp->rstatus = status;
else else
usblp->rstatus = urb->actual_length; usblp->rstatus = urb->actual_length;
usblp->rcomplete = 1; usblp->rcomplete = 1;
wake_up(&usblp->rwait); wake_up(&usblp->rwait);
spin_unlock(&usblp->lock); spin_unlock_irqrestore(&usblp->lock, flags);
usb_free_urb(urb); usb_free_urb(urb);
} }
@ -315,6 +316,7 @@ static void usblp_bulk_write(struct urb *urb)
{ {
struct usblp *usblp = urb->context; struct usblp *usblp = urb->context;
int status = urb->status; int status = urb->status;
unsigned long flags;
if (usblp->present && usblp->used) { if (usblp->present && usblp->used) {
if (status) if (status)
@ -322,7 +324,7 @@ static void usblp_bulk_write(struct urb *urb)
"nonzero write bulk status received: %d\n", "nonzero write bulk status received: %d\n",
usblp->minor, status); usblp->minor, status);
} }
spin_lock(&usblp->lock); spin_lock_irqsave(&usblp->lock, flags);
if (status < 0) if (status < 0)
usblp->wstatus = status; usblp->wstatus = status;
else else
@ -330,7 +332,7 @@ static void usblp_bulk_write(struct urb *urb)
usblp->no_paper = 0; usblp->no_paper = 0;
usblp->wcomplete = 1; usblp->wcomplete = 1;
wake_up(&usblp->wwait); wake_up(&usblp->wwait);
spin_unlock(&usblp->lock); spin_unlock_irqrestore(&usblp->lock, flags);
usb_free_urb(urb); usb_free_urb(urb);
} }

View file

@ -18,6 +18,7 @@
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/compat.h>
#include <linux/usb/tmc.h> #include <linux/usb/tmc.h>
@ -30,6 +31,8 @@
*/ */
#define USBTMC_SIZE_IOBUFFER 2048 #define USBTMC_SIZE_IOBUFFER 2048
/* Minimum USB timeout (in milliseconds) */
#define USBTMC_MIN_TIMEOUT 100
/* Default USB timeout (in milliseconds) */ /* Default USB timeout (in milliseconds) */
#define USBTMC_TIMEOUT 5000 #define USBTMC_TIMEOUT 5000
@ -67,6 +70,7 @@ struct usbtmc_device_data {
const struct usb_device_id *id; const struct usb_device_id *id;
struct usb_device *usb_dev; struct usb_device *usb_dev;
struct usb_interface *intf; struct usb_interface *intf;
struct list_head file_list;
unsigned int bulk_in; unsigned int bulk_in;
unsigned int bulk_out; unsigned int bulk_out;
@ -87,7 +91,6 @@ struct usbtmc_device_data {
int iin_interval; int iin_interval;
struct urb *iin_urb; struct urb *iin_urb;
u16 iin_wMaxPacketSize; u16 iin_wMaxPacketSize;
atomic_t srq_asserted;
/* coalesced usb488_caps from usbtmc_dev_capabilities */ /* coalesced usb488_caps from usbtmc_dev_capabilities */
__u8 usb488_caps; __u8 usb488_caps;
@ -104,9 +107,25 @@ struct usbtmc_device_data {
struct mutex io_mutex; /* only one i/o function running at a time */ struct mutex io_mutex; /* only one i/o function running at a time */
wait_queue_head_t waitq; wait_queue_head_t waitq;
struct fasync_struct *fasync; 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) #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 */ /* Forward declarations */
static struct usb_driver usbtmc_driver; 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 usb_interface *intf;
struct usbtmc_device_data *data; struct usbtmc_device_data *data;
int retval = 0; struct usbtmc_file_data *file_data;
intf = usb_find_interface(&usbtmc_driver, iminor(inode)); intf = usb_find_interface(&usbtmc_driver, iminor(inode));
if (!intf) { if (!intf) {
@ -130,21 +149,51 @@ static int usbtmc_open(struct inode *inode, struct file *filp)
return -ENODEV; return -ENODEV;
} }
file_data = kzalloc(sizeof(*file_data), GFP_KERNEL);
if (!file_data)
return -ENOMEM;
data = usb_get_intfdata(intf); data = usb_get_intfdata(intf);
/* Protect reference to data from file structure until release */ /* Protect reference to data from file structure until release */
kref_get(&data->kref); kref_get(&data->kref);
/* Store pointer in file structure's private data field */ mutex_lock(&data->io_mutex);
filp->private_data = data; file_data->data = data;
return retval; /* 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 = file_data;
return 0;
} }
static int usbtmc_release(struct inode *inode, struct file *file) 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; return 0;
} }
@ -369,10 +418,12 @@ exit:
return rv; 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) void __user *arg)
{ {
struct usbtmc_device_data *data = file_data->data;
struct device *dev = &data->intf->dev; struct device *dev = &data->intf->dev;
int srq_asserted = 0;
u8 *buffer; u8 *buffer;
u8 tag; u8 tag;
__u8 stb; __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", dev_dbg(dev, "Enter ioctl_read_stb iin_ep_present: %d\n",
data->iin_ep_present); 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); buffer = kmalloc(8, GFP_KERNEL);
if (!buffer) if (!buffer)
return -ENOMEM; return -ENOMEM;
atomic_set(&data->iin_data_valid, 0); 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, rv = usb_control_msg(data->usb_dev,
usb_rcvctrlpipe(data->usb_dev, 0), usb_rcvctrlpipe(data->usb_dev, 0),
USBTMC488_REQUEST_READ_STATUS_BYTE, 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( rv = wait_event_interruptible_timeout(
data->waitq, data->waitq,
atomic_read(&data->iin_data_valid) != 0, atomic_read(&data->iin_data_valid) != 0,
USBTMC_TIMEOUT); file_data->timeout);
if (rv < 0) { if (rv < 0) {
dev_dbg(dev, "wait interrupted %d\n", rv); dev_dbg(dev, "wait interrupted %d\n", rv);
goto exit; goto exit;
@ -420,7 +481,7 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_device_data *data,
if (rv == 0) { if (rv == 0) {
dev_dbg(dev, "wait timed out\n"); dev_dbg(dev, "wait timed out\n");
rv = -ETIME; rv = -ETIMEDOUT;
goto exit; goto exit;
} }
@ -435,9 +496,8 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_device_data *data,
stb = buffer[2]; stb = buffer[2];
} }
rv = copy_to_user(arg, &stb, sizeof(stb)); rv = put_user(stb, (__u8 __user *)arg);
if (rv) dev_dbg(dev, "stb:0x%02x received %d\n", (unsigned int)stb, rv);
rv = -EFAULT;
exit: exit:
/* bump interrupt bTag */ /* bump interrupt bTag */
@ -505,6 +565,51 @@ static int usbtmc488_ioctl_simple(struct usbtmc_device_data *data,
return rv; return rv;
} }
/*
* 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. * Sends a REQUEST_DEV_DEP_MSG_IN message on the Bulk-OUT endpoint.
* @transfer_size: number of bytes to request from the device. * @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. * 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; int retval;
u8 *buffer; u8 *buffer;
int actual; 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[5] = transfer_size >> 8;
buffer[6] = transfer_size >> 16; buffer[6] = transfer_size >> 16;
buffer[7] = transfer_size >> 24; buffer[7] = transfer_size >> 24;
buffer[8] = data->TermCharEnabled * 2; buffer[8] = file_data->term_char_enabled * 2;
/* Use term character? */ /* Use term character? */
buffer[9] = data->TermChar; buffer[9] = file_data->term_char;
buffer[10] = 0; /* Reserved */ buffer[10] = 0; /* Reserved */
buffer[11] = 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, retval = usb_bulk_msg(data->usb_dev,
usb_sndbulkpipe(data->usb_dev, usb_sndbulkpipe(data->usb_dev,
data->bulk_out), 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) */ /* Store bTag (in case we need to abort) */
data->bTag_last_write = data->bTag; 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, static ssize_t usbtmc_read(struct file *filp, char __user *buf,
size_t count, loff_t *f_pos) size_t count, loff_t *f_pos)
{ {
struct usbtmc_file_data *file_data;
struct usbtmc_device_data *data; struct usbtmc_device_data *data;
struct device *dev; struct device *dev;
u32 n_characters; u32 n_characters;
@ -576,7 +685,8 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
size_t this_part; size_t this_part;
/* Get pointer to private data structure */ /* Get pointer to private data structure */
data = filp->private_data; file_data = filp->private_data;
data = file_data->data;
dev = &data->intf->dev; dev = &data->intf->dev;
buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL); 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); 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 (retval < 0) {
if (data->auto_abort) if (data->auto_abort)
@ -610,7 +720,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
usb_rcvbulkpipe(data->usb_dev, usb_rcvbulkpipe(data->usb_dev,
data->bulk_in), data->bulk_in),
buffer, USBTMC_SIZE_IOBUFFER, &actual, 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); 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, static ssize_t usbtmc_write(struct file *filp, const char __user *buf,
size_t count, loff_t *f_pos) size_t count, loff_t *f_pos)
{ {
struct usbtmc_file_data *file_data;
struct usbtmc_device_data *data; struct usbtmc_device_data *data;
u8 *buffer; u8 *buffer;
int retval; int retval;
@ -730,7 +841,8 @@ static ssize_t usbtmc_write(struct file *filp, const char __user *buf,
int done; int done;
int this_part; int this_part;
data = filp->private_data; file_data = filp->private_data;
data = file_data->data;
buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL); buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL);
if (!buffer) if (!buffer)
@ -751,7 +863,7 @@ static ssize_t usbtmc_write(struct file *filp, const char __user *buf,
buffer[8] = 0; buffer[8] = 0;
} else { } else {
this_part = remaining; this_part = remaining;
buffer[8] = 1; buffer[8] = file_data->eom_val;
} }
/* Setup IO buffer for DEV_DEP_MSG_OUT message */ /* 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, usb_sndbulkpipe(data->usb_dev,
data->bulk_out), data->bulk_out),
buffer, n_bytes, buffer, n_bytes,
&actual, USBTMC_TIMEOUT); &actual, file_data->timeout);
if (retval != 0) if (retval != 0)
break; break;
n_bytes -= actual; n_bytes -= actual;
@ -1138,12 +1250,91 @@ exit:
return rv; 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) static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{ {
struct usbtmc_file_data *file_data;
struct usbtmc_device_data *data; struct usbtmc_device_data *data;
int retval = -EBADRQC; int retval = -EBADRQC;
data = file->private_data; file_data = file->private_data;
data = file_data->data;
mutex_lock(&data->io_mutex); mutex_lock(&data->io_mutex);
if (data->zombie) { if (data->zombie) {
retval = -ENODEV; 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); retval = usbtmc_ioctl_abort_bulk_in(data);
break; 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: case USBTMC488_IOCTL_GET_CAPS:
retval = copy_to_user((void __user *)arg, retval = copy_to_user((void __user *)arg,
&data->usb488_caps, &data->usb488_caps,
@ -1184,7 +1395,8 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break; break;
case USBTMC488_IOCTL_READ_STB: 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; break;
case USBTMC488_IOCTL_REN_CONTROL: 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, retval = usbtmc488_ioctl_simple(data, (void __user *)arg,
USBTMC488_REQUEST_LOCAL_LOCKOUT); USBTMC488_REQUEST_LOCAL_LOCKOUT);
break; break;
case USBTMC488_IOCTL_TRIGGER:
retval = usbtmc488_ioctl_trigger(file_data);
break;
} }
skip_io_on_zombie: skip_io_on_zombie:
@ -1210,14 +1426,15 @@ skip_io_on_zombie:
static int usbtmc_fasync(int fd, struct file *file, int on) 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) 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; __poll_t mask;
mutex_lock(&data->io_mutex); 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); 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: no_poll:
mutex_unlock(&data->io_mutex); mutex_unlock(&data->io_mutex);
@ -1243,6 +1460,9 @@ static const struct file_operations fops = {
.open = usbtmc_open, .open = usbtmc_open,
.release = usbtmc_release, .release = usbtmc_release,
.unlocked_ioctl = usbtmc_ioctl, .unlocked_ioctl = usbtmc_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = usbtmc_ioctl,
#endif
.fasync = usbtmc_fasync, .fasync = usbtmc_fasync,
.poll = usbtmc_poll, .poll = usbtmc_poll,
.llseek = default_llseek, .llseek = default_llseek,
@ -1276,15 +1496,33 @@ static void usbtmc_interrupt(struct urb *urb)
} }
/* check for SRQ notification */ /* check for SRQ notification */
if (data->iin_buffer[0] == 0x81) { if (data->iin_buffer[0] == 0x81) {
unsigned long flags;
struct list_head *elem;
if (data->fasync) if (data->fasync)
kill_fasync(&data->fasync, kill_fasync(&data->fasync,
SIGIO, POLL_IN); SIGIO, POLL_PRI);
atomic_set(&data->srq_asserted, 1); spin_lock_irqsave(&data->dev_lock, flags);
wake_up_interruptible(&data->waitq); 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; 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; break;
case -EOVERFLOW: case -EOVERFLOW:
dev_err(dev, "overflow with length %d, actual length is %d\n", 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 -ESHUTDOWN:
case -EILSEQ: case -EILSEQ:
case -ETIME: case -ETIME:
case -EPIPE:
/* urb terminated, clean up */ /* urb terminated, clean up */
dev_dbg(dev, "urb terminated, status: %d\n", status); dev_dbg(dev, "urb terminated, status: %d\n", status);
return; return;
@ -1339,7 +1578,9 @@ static int usbtmc_probe(struct usb_interface *intf,
mutex_init(&data->io_mutex); mutex_init(&data->io_mutex);
init_waitqueue_head(&data->waitq); init_waitqueue_head(&data->waitq);
atomic_set(&data->iin_data_valid, 0); 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; data->zombie = 0;
/* Initialize USBTMC bTag and other fields */ /* Initialize USBTMC bTag and other fields */
@ -1442,17 +1683,14 @@ err_put:
static void usbtmc_disconnect(struct usb_interface *intf) static void usbtmc_disconnect(struct usb_interface *intf)
{ {
struct usbtmc_device_data *data; struct usbtmc_device_data *data = usb_get_intfdata(intf);
dev_dbg(&intf->dev, "usbtmc_disconnect called\n");
data = usb_get_intfdata(intf);
usb_deregister_dev(intf, &usbtmc_class); usb_deregister_dev(intf, &usbtmc_class);
sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp); sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp);
sysfs_remove_group(&intf->dev.kobj, &data_attr_grp); sysfs_remove_group(&intf->dev.kobj, &data_attr_grp);
mutex_lock(&data->io_mutex); mutex_lock(&data->io_mutex);
data->zombie = 1; data->zombie = 1;
wake_up_all(&data->waitq); wake_up_interruptible_all(&data->waitq);
mutex_unlock(&data->io_mutex); mutex_unlock(&data->io_mutex);
usbtmc_free_int(data); usbtmc_free_int(data);
kref_put(&data->kref, usbtmc_delete); kref_put(&data->kref, usbtmc_delete);

View file

@ -585,9 +585,10 @@ static void async_completed(struct urb *urb)
struct siginfo sinfo; struct siginfo sinfo;
struct pid *pid = NULL; struct pid *pid = NULL;
const struct cred *cred = NULL; const struct cred *cred = NULL;
unsigned long flags;
int signr; int signr;
spin_lock(&ps->lock); spin_lock_irqsave(&ps->lock, flags);
list_move_tail(&as->asynclist, &ps->async_completed); list_move_tail(&as->asynclist, &ps->async_completed);
as->status = urb->status; as->status = urb->status;
signr = as->signr; signr = as->signr;
@ -611,7 +612,7 @@ static void async_completed(struct urb *urb)
cancel_bulk_urbs(ps, as->bulk_addr); cancel_bulk_urbs(ps, as->bulk_addr);
wake_up(&ps->wait); wake_up(&ps->wait);
spin_unlock(&ps->lock); spin_unlock_irqrestore(&ps->lock, flags);
if (signr) { if (signr) {
kill_pid_info_as_cred(sinfo.si_signo, &sinfo, pid, cred); kill_pid_info_as_cred(sinfo.si_signo, &sinfo, pid, cred);

View file

@ -3660,12 +3660,54 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
return 0; 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) static int hub_resume(struct usb_interface *intf)
{ {
struct usb_hub *hub = usb_get_intfdata(intf); struct usb_hub *hub = usb_get_intfdata(intf);
dev_dbg(&intf->dev, "%s\n", __func__); dev_dbg(&intf->dev, "%s\n", __func__);
hub_activate(hub, HUB_RESUME); 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; return 0;
} }

View file

@ -269,10 +269,11 @@ static void sg_clean(struct usb_sg_request *io)
static void sg_complete(struct urb *urb) static void sg_complete(struct urb *urb)
{ {
unsigned long flags;
struct usb_sg_request *io = urb->context; struct usb_sg_request *io = urb->context;
int status = urb->status; 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 /* In 2.5 we require hcds' endpoint queues not to progress after fault
* reports, until the completion callback (this!) returns. That lets * 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. * unlink pending urbs so they won't rx/tx bad data.
* careful: unlink can sometimes be synchronous... * 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++) { for (i = 0, found = 0; i < io->entries; i++) {
if (!io->urbs[i]) if (!io->urbs[i])
continue; continue;
@ -323,7 +324,7 @@ static void sg_complete(struct urb *urb)
} else if (urb == io->urbs[i]) } else if (urb == io->urbs[i])
found = 1; found = 1;
} }
spin_lock(&io->lock); spin_lock_irqsave(&io->lock, flags);
} }
/* on the last completion, signal usb_sg_wait() */ /* on the last completion, signal usb_sg_wait() */
@ -332,7 +333,7 @@ static void sg_complete(struct urb *urb)
if (!io->count) if (!io->count)
complete(&io->complete); complete(&io->complete);
spin_unlock(&io->lock); spin_unlock_irqrestore(&io->lock, flags);
} }

View file

@ -73,17 +73,17 @@ int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg)
/* Backup global regs */ /* Backup global regs */
gr = &hsotg->gr_backup; gr = &hsotg->gr_backup;
gr->gotgctl = dwc2_readl(hsotg->regs + GOTGCTL); gr->gotgctl = dwc2_readl(hsotg, GOTGCTL);
gr->gintmsk = dwc2_readl(hsotg->regs + GINTMSK); gr->gintmsk = dwc2_readl(hsotg, GINTMSK);
gr->gahbcfg = dwc2_readl(hsotg->regs + GAHBCFG); gr->gahbcfg = dwc2_readl(hsotg, GAHBCFG);
gr->gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG); gr->gusbcfg = dwc2_readl(hsotg, GUSBCFG);
gr->grxfsiz = dwc2_readl(hsotg->regs + GRXFSIZ); gr->grxfsiz = dwc2_readl(hsotg, GRXFSIZ);
gr->gnptxfsiz = dwc2_readl(hsotg->regs + GNPTXFSIZ); gr->gnptxfsiz = dwc2_readl(hsotg, GNPTXFSIZ);
gr->gdfifocfg = dwc2_readl(hsotg->regs + GDFIFOCFG); gr->gdfifocfg = dwc2_readl(hsotg, GDFIFOCFG);
gr->pcgcctl1 = dwc2_readl(hsotg->regs + PCGCCTL1); gr->pcgcctl1 = dwc2_readl(hsotg, PCGCCTL1);
gr->glpmcfg = dwc2_readl(hsotg->regs + GLPMCFG); gr->glpmcfg = dwc2_readl(hsotg, GLPMCFG);
gr->gi2cctl = dwc2_readl(hsotg->regs + GI2CCTL); gr->gi2cctl = dwc2_readl(hsotg, GI2CCTL);
gr->pcgcctl = dwc2_readl(hsotg->regs + PCGCTL); gr->pcgcctl = dwc2_readl(hsotg, PCGCTL);
gr->valid = true; gr->valid = true;
return 0; return 0;
@ -111,18 +111,18 @@ int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg)
} }
gr->valid = false; gr->valid = false;
dwc2_writel(0xffffffff, hsotg->regs + GINTSTS); dwc2_writel(hsotg, 0xffffffff, GINTSTS);
dwc2_writel(gr->gotgctl, hsotg->regs + GOTGCTL); dwc2_writel(hsotg, gr->gotgctl, GOTGCTL);
dwc2_writel(gr->gintmsk, hsotg->regs + GINTMSK); dwc2_writel(hsotg, gr->gintmsk, GINTMSK);
dwc2_writel(gr->gusbcfg, hsotg->regs + GUSBCFG); dwc2_writel(hsotg, gr->gusbcfg, GUSBCFG);
dwc2_writel(gr->gahbcfg, hsotg->regs + GAHBCFG); dwc2_writel(hsotg, gr->gahbcfg, GAHBCFG);
dwc2_writel(gr->grxfsiz, hsotg->regs + GRXFSIZ); dwc2_writel(hsotg, gr->grxfsiz, GRXFSIZ);
dwc2_writel(gr->gnptxfsiz, hsotg->regs + GNPTXFSIZ); dwc2_writel(hsotg, gr->gnptxfsiz, GNPTXFSIZ);
dwc2_writel(gr->gdfifocfg, hsotg->regs + GDFIFOCFG); dwc2_writel(hsotg, gr->gdfifocfg, GDFIFOCFG);
dwc2_writel(gr->pcgcctl1, hsotg->regs + PCGCCTL1); dwc2_writel(hsotg, gr->pcgcctl1, PCGCCTL1);
dwc2_writel(gr->glpmcfg, hsotg->regs + GLPMCFG); dwc2_writel(hsotg, gr->glpmcfg, GLPMCFG);
dwc2_writel(gr->pcgcctl, hsotg->regs + PCGCTL); dwc2_writel(hsotg, gr->pcgcctl, PCGCTL);
dwc2_writel(gr->gi2cctl, hsotg->regs + GI2CCTL); dwc2_writel(hsotg, gr->gi2cctl, GI2CCTL);
return 0; 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) if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_PARTIAL)
return -ENOTSUPP; return -ENOTSUPP;
pcgcctl = dwc2_readl(hsotg->regs + PCGCTL); pcgcctl = dwc2_readl(hsotg, PCGCTL);
pcgcctl &= ~PCGCTL_STOPPCLK; 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; 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; pcgcctl &= ~PCGCTL_RSTPDWNMODULE;
dwc2_writel(pcgcctl, hsotg->regs + PCGCTL); dwc2_writel(hsotg, pcgcctl, PCGCTL);
udelay(100); udelay(100);
if (restore) { 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 any pending interrupts since dwc2 will not be able to
* clear them after entering partial_power_down. * 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 */ /* Put the controller in low power state */
pcgcctl = dwc2_readl(hsotg->regs + PCGCTL); pcgcctl = dwc2_readl(hsotg, PCGCTL);
pcgcctl |= PCGCTL_PWRCLMP; pcgcctl |= PCGCTL_PWRCLMP;
dwc2_writel(pcgcctl, hsotg->regs + PCGCTL); dwc2_writel(hsotg, pcgcctl, PCGCTL);
ndelay(20); ndelay(20);
pcgcctl |= PCGCTL_RSTPDWNMODULE; pcgcctl |= PCGCTL_RSTPDWNMODULE;
dwc2_writel(pcgcctl, hsotg->regs + PCGCTL); dwc2_writel(hsotg, pcgcctl, PCGCTL);
ndelay(20); ndelay(20);
pcgcctl |= PCGCTL_STOPPCLK; pcgcctl |= PCGCTL_STOPPCLK;
dwc2_writel(pcgcctl, hsotg->regs + PCGCTL); dwc2_writel(hsotg, pcgcctl, PCGCTL);
return ret; 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)) if (!(pcgcctl & PCGCTL_P2HD_DEV_ENUM_SPD_MASK))
pcgcctl |= BIT(17); pcgcctl |= BIT(17);
} }
dwc2_writel(pcgcctl, hsotg->regs + PCGCTL); dwc2_writel(hsotg, pcgcctl, PCGCTL);
/* Umnask global Interrupt in GAHBCFG and restore it */ /* 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 */ /* Clear all pending interupts */
dwc2_writel(0xffffffff, hsotg->regs + GINTSTS); dwc2_writel(hsotg, 0xffffffff, GINTSTS);
/* Unmask restore done interrupt */ /* Unmask restore done interrupt */
dwc2_writel(GINTSTS_RESTOREDONE, hsotg->regs + GINTMSK); dwc2_writel(hsotg, GINTSTS_RESTOREDONE, GINTMSK);
/* Restore GUSBCFG and HCFG/DCFG */ /* Restore GUSBCFG and HCFG/DCFG */
dwc2_writel(gr->gusbcfg, hsotg->regs + GUSBCFG); dwc2_writel(hsotg, gr->gusbcfg, GUSBCFG);
if (is_host) { if (is_host) {
dwc2_writel(hr->hcfg, hsotg->regs + HCFG); dwc2_writel(hsotg, hr->hcfg, HCFG);
if (rmode) if (rmode)
pcgcctl |= PCGCTL_RESTOREMODE; pcgcctl |= PCGCTL_RESTOREMODE;
dwc2_writel(pcgcctl, hsotg->regs + PCGCTL); dwc2_writel(hsotg, pcgcctl, PCGCTL);
udelay(10); udelay(10);
pcgcctl |= PCGCTL_ESS_REG_RESTORED; pcgcctl |= PCGCTL_ESS_REG_RESTORED;
dwc2_writel(pcgcctl, hsotg->regs + PCGCTL); dwc2_writel(hsotg, pcgcctl, PCGCTL);
udelay(10); udelay(10);
} else { } else {
dwc2_writel(dr->dcfg, hsotg->regs + DCFG); dwc2_writel(hsotg, dr->dcfg, DCFG);
if (!rmode) if (!rmode)
pcgcctl |= PCGCTL_RESTOREMODE | PCGCTL_RSTPDWNMODULE; pcgcctl |= PCGCTL_RESTOREMODE | PCGCTL_RSTPDWNMODULE;
dwc2_writel(pcgcctl, hsotg->regs + PCGCTL); dwc2_writel(hsotg, pcgcctl, PCGCTL);
udelay(10); udelay(10);
pcgcctl |= PCGCTL_ESS_REG_RESTORED; pcgcctl |= PCGCTL_ESS_REG_RESTORED;
dwc2_writel(pcgcctl, hsotg->regs + PCGCTL); dwc2_writel(hsotg, pcgcctl, PCGCTL);
udelay(10); udelay(10);
} }
} }
@ -322,42 +322,42 @@ void dwc2_hib_restore_common(struct dwc2_hsotg *hsotg, int rem_wakeup,
u32 gpwrdn; u32 gpwrdn;
/* Switch-on voltage to the core */ /* Switch-on voltage to the core */
gpwrdn = dwc2_readl(hsotg->regs + GPWRDN); gpwrdn = dwc2_readl(hsotg, GPWRDN);
gpwrdn &= ~GPWRDN_PWRDNSWTCH; gpwrdn &= ~GPWRDN_PWRDNSWTCH;
dwc2_writel(gpwrdn, hsotg->regs + GPWRDN); dwc2_writel(hsotg, gpwrdn, GPWRDN);
udelay(10); udelay(10);
/* Reset core */ /* Reset core */
gpwrdn = dwc2_readl(hsotg->regs + GPWRDN); gpwrdn = dwc2_readl(hsotg, GPWRDN);
gpwrdn &= ~GPWRDN_PWRDNRSTN; gpwrdn &= ~GPWRDN_PWRDNRSTN;
dwc2_writel(gpwrdn, hsotg->regs + GPWRDN); dwc2_writel(hsotg, gpwrdn, GPWRDN);
udelay(10); udelay(10);
/* Enable restore from PMU */ /* Enable restore from PMU */
gpwrdn = dwc2_readl(hsotg->regs + GPWRDN); gpwrdn = dwc2_readl(hsotg, GPWRDN);
gpwrdn |= GPWRDN_RESTORE; gpwrdn |= GPWRDN_RESTORE;
dwc2_writel(gpwrdn, hsotg->regs + GPWRDN); dwc2_writel(hsotg, gpwrdn, GPWRDN);
udelay(10); udelay(10);
/* Disable Power Down Clamp */ /* Disable Power Down Clamp */
gpwrdn = dwc2_readl(hsotg->regs + GPWRDN); gpwrdn = dwc2_readl(hsotg, GPWRDN);
gpwrdn &= ~GPWRDN_PWRDNCLMP; gpwrdn &= ~GPWRDN_PWRDNCLMP;
dwc2_writel(gpwrdn, hsotg->regs + GPWRDN); dwc2_writel(hsotg, gpwrdn, GPWRDN);
udelay(50); udelay(50);
if (!is_host && rem_wakeup) if (!is_host && rem_wakeup)
udelay(70); udelay(70);
/* Deassert reset core */ /* Deassert reset core */
gpwrdn = dwc2_readl(hsotg->regs + GPWRDN); gpwrdn = dwc2_readl(hsotg, GPWRDN);
gpwrdn |= GPWRDN_PWRDNRSTN; gpwrdn |= GPWRDN_PWRDNRSTN;
dwc2_writel(gpwrdn, hsotg->regs + GPWRDN); dwc2_writel(hsotg, gpwrdn, GPWRDN);
udelay(10); udelay(10);
/* Disable PMU interrupt */ /* Disable PMU interrupt */
gpwrdn = dwc2_readl(hsotg->regs + GPWRDN); gpwrdn = dwc2_readl(hsotg, GPWRDN);
gpwrdn &= ~GPWRDN_PMUINTSEL; gpwrdn &= ~GPWRDN_PMUINTSEL;
dwc2_writel(gpwrdn, hsotg->regs + GPWRDN); dwc2_writel(hsotg, gpwrdn, GPWRDN);
udelay(10); udelay(10);
/* Set Restore Essential Regs bit in PCGCCTL register */ /* Set Restore Essential Regs bit in PCGCCTL register */
@ -431,7 +431,7 @@ static bool dwc2_iddig_filter_enabled(struct dwc2_hsotg *hsotg)
return false; return false;
/* Check if core configuration includes the IDDIG filter. */ /* 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)) if (!(ghwcfg4 & GHWCFG4_IDDIG_FILT_EN))
return false; 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 * Check if the IDDIG debounce filter is bypassed. Available
* in core version >= 3.10a. * in core version >= 3.10a.
*/ */
gsnpsid = dwc2_readl(hsotg->regs + GSNPSID); gsnpsid = dwc2_readl(hsotg, GSNPSID);
if (gsnpsid >= DWC2_CORE_REV_3_10a) { 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) if (gotgctl & GOTGCTL_DBNCE_FLTR_BYPASS)
return false; 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. * reset and account for this delay after the reset.
*/ */
if (dwc2_iddig_filter_enabled(hsotg)) { if (dwc2_iddig_filter_enabled(hsotg)) {
u32 gotgctl = dwc2_readl(hsotg->regs + GOTGCTL); u32 gotgctl = dwc2_readl(hsotg, GOTGCTL);
u32 gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG); u32 gusbcfg = dwc2_readl(hsotg, GUSBCFG);
if (!(gotgctl & GOTGCTL_CONID_B) || if (!(gotgctl & GOTGCTL_CONID_B) ||
(gusbcfg & GUSBCFG_FORCEHOSTMODE)) { (gusbcfg & GUSBCFG_FORCEHOSTMODE)) {
@ -520,9 +520,9 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait)
} }
/* Core Soft Reset */ /* Core Soft Reset */
greset = dwc2_readl(hsotg->regs + GRSTCTL); greset = dwc2_readl(hsotg, GRSTCTL);
greset |= GRSTCTL_CSFTRST; 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)) { if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_CSFTRST, 50)) {
dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL GRSTCTL_CSFTRST\n", 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)) if (WARN_ON(!host && hsotg->dr_mode == USB_DR_MODE_HOST))
return; return;
gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG); gusbcfg = dwc2_readl(hsotg, GUSBCFG);
set = host ? GUSBCFG_FORCEHOSTMODE : GUSBCFG_FORCEDEVMODE; set = host ? GUSBCFG_FORCEHOSTMODE : GUSBCFG_FORCEDEVMODE;
clear = host ? GUSBCFG_FORCEDEVMODE : GUSBCFG_FORCEHOSTMODE; clear = host ? GUSBCFG_FORCEDEVMODE : GUSBCFG_FORCEHOSTMODE;
gusbcfg &= ~clear; gusbcfg &= ~clear;
gusbcfg |= set; gusbcfg |= set;
dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG); dwc2_writel(hsotg, gusbcfg, GUSBCFG);
dwc2_wait_for_mode(hsotg, host); dwc2_wait_for_mode(hsotg, host);
return; return;
@ -627,10 +627,10 @@ static void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg)
dev_dbg(hsotg->dev, "Clearing force mode bits\n"); 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_FORCEHOSTMODE;
gusbcfg &= ~GUSBCFG_FORCEDEVMODE; gusbcfg &= ~GUSBCFG_FORCEDEVMODE;
dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG); dwc2_writel(hsotg, gusbcfg, GUSBCFG);
if (dwc2_iddig_filter_enabled(hsotg)) if (dwc2_iddig_filter_enabled(hsotg))
msleep(100); msleep(100);
@ -670,11 +670,11 @@ void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg)
void dwc2_enable_acg(struct dwc2_hsotg *hsotg) void dwc2_enable_acg(struct dwc2_hsotg *hsotg)
{ {
if (hsotg->params.acg_enable) { 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"); dev_dbg(hsotg->dev, "Enabling Active Clock Gating\n");
pcgcctl1 |= PCGCCTL1_GATEEN; 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"); dev_dbg(hsotg->dev, "Host Global Registers\n");
addr = hsotg->regs + HCFG; addr = hsotg->regs + HCFG;
dev_dbg(hsotg->dev, "HCFG @0x%08lX : 0x%08X\n", 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; addr = hsotg->regs + HFIR;
dev_dbg(hsotg->dev, "HFIR @0x%08lX : 0x%08X\n", 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; addr = hsotg->regs + HFNUM;
dev_dbg(hsotg->dev, "HFNUM @0x%08lX : 0x%08X\n", 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; addr = hsotg->regs + HPTXSTS;
dev_dbg(hsotg->dev, "HPTXSTS @0x%08lX : 0x%08X\n", 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; addr = hsotg->regs + HAINT;
dev_dbg(hsotg->dev, "HAINT @0x%08lX : 0x%08X\n", 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; addr = hsotg->regs + HAINTMSK;
dev_dbg(hsotg->dev, "HAINTMSK @0x%08lX : 0x%08X\n", 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) { if (hsotg->params.dma_desc_enable) {
addr = hsotg->regs + HFLBADDR; addr = hsotg->regs + HFLBADDR;
dev_dbg(hsotg->dev, "HFLBADDR @0x%08lX : 0x%08X\n", 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; addr = hsotg->regs + HPRT0;
dev_dbg(hsotg->dev, "HPRT0 @0x%08lX : 0x%08X\n", 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++) { for (i = 0; i < hsotg->params.host_channels; i++) {
dev_dbg(hsotg->dev, "Host Channel %d Specific Registers\n", i); dev_dbg(hsotg->dev, "Host Channel %d Specific Registers\n", i);
addr = hsotg->regs + HCCHAR(i); addr = hsotg->regs + HCCHAR(i);
dev_dbg(hsotg->dev, "HCCHAR @0x%08lX : 0x%08X\n", 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); addr = hsotg->regs + HCSPLT(i);
dev_dbg(hsotg->dev, "HCSPLT @0x%08lX : 0x%08X\n", 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); addr = hsotg->regs + HCINT(i);
dev_dbg(hsotg->dev, "HCINT @0x%08lX : 0x%08X\n", 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); addr = hsotg->regs + HCINTMSK(i);
dev_dbg(hsotg->dev, "HCINTMSK @0x%08lX : 0x%08X\n", 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); addr = hsotg->regs + HCTSIZ(i);
dev_dbg(hsotg->dev, "HCTSIZ @0x%08lX : 0x%08X\n", 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); addr = hsotg->regs + HCDMA(i);
dev_dbg(hsotg->dev, "HCDMA @0x%08lX : 0x%08X\n", 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) { if (hsotg->params.dma_desc_enable) {
addr = hsotg->regs + HCDMAB(i); addr = hsotg->regs + HCDMAB(i);
dev_dbg(hsotg->dev, "HCDMAB @0x%08lX : 0x%08X\n", 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 #endif
@ -766,80 +767,80 @@ void dwc2_dump_global_registers(struct dwc2_hsotg *hsotg)
dev_dbg(hsotg->dev, "Core Global Registers\n"); dev_dbg(hsotg->dev, "Core Global Registers\n");
addr = hsotg->regs + GOTGCTL; addr = hsotg->regs + GOTGCTL;
dev_dbg(hsotg->dev, "GOTGCTL @0x%08lX : 0x%08X\n", 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; addr = hsotg->regs + GOTGINT;
dev_dbg(hsotg->dev, "GOTGINT @0x%08lX : 0x%08X\n", 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; addr = hsotg->regs + GAHBCFG;
dev_dbg(hsotg->dev, "GAHBCFG @0x%08lX : 0x%08X\n", 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; addr = hsotg->regs + GUSBCFG;
dev_dbg(hsotg->dev, "GUSBCFG @0x%08lX : 0x%08X\n", 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; addr = hsotg->regs + GRSTCTL;
dev_dbg(hsotg->dev, "GRSTCTL @0x%08lX : 0x%08X\n", 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; addr = hsotg->regs + GINTSTS;
dev_dbg(hsotg->dev, "GINTSTS @0x%08lX : 0x%08X\n", 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; addr = hsotg->regs + GINTMSK;
dev_dbg(hsotg->dev, "GINTMSK @0x%08lX : 0x%08X\n", 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; addr = hsotg->regs + GRXSTSR;
dev_dbg(hsotg->dev, "GRXSTSR @0x%08lX : 0x%08X\n", 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; addr = hsotg->regs + GRXFSIZ;
dev_dbg(hsotg->dev, "GRXFSIZ @0x%08lX : 0x%08X\n", 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; addr = hsotg->regs + GNPTXFSIZ;
dev_dbg(hsotg->dev, "GNPTXFSIZ @0x%08lX : 0x%08X\n", 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; addr = hsotg->regs + GNPTXSTS;
dev_dbg(hsotg->dev, "GNPTXSTS @0x%08lX : 0x%08X\n", 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; addr = hsotg->regs + GI2CCTL;
dev_dbg(hsotg->dev, "GI2CCTL @0x%08lX : 0x%08X\n", 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; addr = hsotg->regs + GPVNDCTL;
dev_dbg(hsotg->dev, "GPVNDCTL @0x%08lX : 0x%08X\n", 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; addr = hsotg->regs + GGPIO;
dev_dbg(hsotg->dev, "GGPIO @0x%08lX : 0x%08X\n", 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; addr = hsotg->regs + GUID;
dev_dbg(hsotg->dev, "GUID @0x%08lX : 0x%08X\n", 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; addr = hsotg->regs + GSNPSID;
dev_dbg(hsotg->dev, "GSNPSID @0x%08lX : 0x%08X\n", 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; addr = hsotg->regs + GHWCFG1;
dev_dbg(hsotg->dev, "GHWCFG1 @0x%08lX : 0x%08X\n", 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; addr = hsotg->regs + GHWCFG2;
dev_dbg(hsotg->dev, "GHWCFG2 @0x%08lX : 0x%08X\n", 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; addr = hsotg->regs + GHWCFG3;
dev_dbg(hsotg->dev, "GHWCFG3 @0x%08lX : 0x%08X\n", 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; addr = hsotg->regs + GHWCFG4;
dev_dbg(hsotg->dev, "GHWCFG4 @0x%08lX : 0x%08X\n", 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; addr = hsotg->regs + GLPMCFG;
dev_dbg(hsotg->dev, "GLPMCFG @0x%08lX : 0x%08X\n", 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; addr = hsotg->regs + GPWRDN;
dev_dbg(hsotg->dev, "GPWRDN @0x%08lX : 0x%08X\n", 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; addr = hsotg->regs + GDFIFOCFG;
dev_dbg(hsotg->dev, "GDFIFOCFG @0x%08lX : 0x%08X\n", 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; addr = hsotg->regs + HPTXFSIZ;
dev_dbg(hsotg->dev, "HPTXFSIZ @0x%08lX : 0x%08X\n", 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; addr = hsotg->regs + PCGCTL;
dev_dbg(hsotg->dev, "PCGCTL @0x%08lX : 0x%08X\n", dev_dbg(hsotg->dev, "PCGCTL @0x%08lX : 0x%08X\n",
(unsigned long)addr, dwc2_readl(addr)); (unsigned long)addr, dwc2_readl(hsotg, PCGCTL));
#endif #endif
} }
@ -862,7 +863,7 @@ void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num)
greset = GRSTCTL_TXFFLSH; greset = GRSTCTL_TXFFLSH;
greset |= num << GRSTCTL_TXFNUM_SHIFT & GRSTCTL_TXFNUM_MASK; 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)) if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_TXFFLSH, 10000))
dev_warn(hsotg->dev, "%s: HANG! timeout GRSTCTL GRSTCTL_TXFFLSH\n", 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__); __func__);
greset = GRSTCTL_RXFFLSH; greset = GRSTCTL_RXFFLSH;
dwc2_writel(greset, hsotg->regs + GRSTCTL); dwc2_writel(hsotg, greset, GRSTCTL);
/* Wait for RxFIFO flush done */ /* Wait for RxFIFO flush done */
if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_RXFFLSH, 10000)) 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) bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg)
{ {
if (dwc2_readl(hsotg->regs + GSNPSID) == 0xffffffff) if (dwc2_readl(hsotg, GSNPSID) == 0xffffffff)
return false; return false;
else else
return true; return true;
@ -916,10 +917,10 @@ bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg)
*/ */
void dwc2_enable_global_interrupts(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; 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) 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; ahbcfg &= ~GAHBCFG_GLBL_INTR_EN;
dwc2_writel(ahbcfg, hsotg->regs + GAHBCFG); dwc2_writel(hsotg, ahbcfg, GAHBCFG);
} }
/* Returns the controller's GHWCFG2.OTG_MODE. */ /* Returns the controller's GHWCFG2.OTG_MODE. */
unsigned int dwc2_op_mode(struct dwc2_hsotg *hsotg) 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) >> return (ghwcfg2 & GHWCFG2_OP_MODE_MASK) >>
GHWCFG2_OP_MODE_SHIFT; GHWCFG2_OP_MODE_SHIFT;
@ -988,7 +989,7 @@ int dwc2_hsotg_wait_bit_set(struct dwc2_hsotg *hsotg, u32 offset, u32 mask,
u32 i; u32 i;
for (i = 0; i < timeout; i++) { for (i = 0; i < timeout; i++) {
if (dwc2_readl(hsotg->regs + offset) & mask) if (dwc2_readl(hsotg, offset) & mask)
return 0; return 0;
udelay(1); udelay(1);
} }
@ -1011,7 +1012,7 @@ int dwc2_hsotg_wait_bit_clear(struct dwc2_hsotg *hsotg, u32 offset, u32 mask,
u32 i; u32 i;
for (i = 0; i < timeout; i++) { for (i = 0; i < timeout; i++) {
if (!(dwc2_readl(hsotg->regs + offset) & mask)) if (!(dwc2_readl(hsotg, offset) & mask))
return 0; return 0;
udelay(1); udelay(1);
} }

View file

@ -65,60 +65,6 @@
DWC2_TRACE_SCHEDULER_VB(pr_fmt("%s: SCH: " fmt), \ DWC2_TRACE_SCHEDULER_VB(pr_fmt("%s: SCH: " fmt), \
dev_name(hsotg->dev), ##__VA_ARGS__) 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 */ /* Maximum number of Endpoints/HostChannels */
#define MAX_EPS_CHANNELS 16 #define MAX_EPS_CHANNELS 16
@ -911,6 +857,7 @@ struct dwc2_hregs_backup {
* @gr_backup: Backup of global registers during suspend * @gr_backup: Backup of global registers during suspend
* @dr_backup: Backup of device registers during suspend * @dr_backup: Backup of device registers during suspend
* @hr_backup: Backup of host registers during suspend * @hr_backup: Backup of host registers during suspend
* @needs_byte_swap: Specifies whether the opposite endianness.
* *
* These are for host mode: * These are for host mode:
* *
@ -1100,6 +1047,7 @@ struct dwc2_hsotg {
struct dentry *debug_root; struct dentry *debug_root;
struct debugfs_regset32 *regset; struct debugfs_regset32 *regset;
bool needs_byte_swap;
/* DWC OTG HW Release versions */ /* DWC OTG HW Release versions */
#define DWC2_CORE_REV_2_71a 0x4f54271a #define DWC2_CORE_REV_2_71a 0x4f54271a
@ -1215,6 +1163,55 @@ struct dwc2_hsotg {
#endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */ #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 */ /* Reasons for halting a host channel */
enum dwc2_halt_status { enum dwc2_halt_status {
DWC2_HC_XFER_NO_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) 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) 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;
} }
/* /*

View 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) 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) { if (hprt0 & HPRT0_ENACHG) {
hprt0 &= ~HPRT0_ENA; 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) static void dwc2_handle_mode_mismatch_intr(struct dwc2_hsotg *hsotg)
{ {
/* Clear interrupt */ /* 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", dev_warn(hsotg->dev, "Mode Mismatch Interrupt: currently in %s mode\n",
dwc2_is_host_mode(hsotg) ? "Host" : "Device"); dwc2_is_host_mode(hsotg) ? "Host" : "Device");
@ -115,8 +115,8 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
u32 gotgctl; u32 gotgctl;
u32 gintmsk; u32 gintmsk;
gotgint = dwc2_readl(hsotg->regs + GOTGINT); gotgint = dwc2_readl(hsotg, GOTGINT);
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL); gotgctl = dwc2_readl(hsotg, GOTGCTL);
dev_dbg(hsotg->dev, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint, dev_dbg(hsotg->dev, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint,
dwc2_op_state_str(hsotg)); dwc2_op_state_str(hsotg));
@ -124,7 +124,7 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
dev_dbg(hsotg->dev, dev_dbg(hsotg->dev,
" ++OTG Interrupt: Session End Detected++ (%s)\n", " ++OTG Interrupt: Session End Detected++ (%s)\n",
dwc2_op_state_str(hsotg)); dwc2_op_state_str(hsotg));
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL); gotgctl = dwc2_readl(hsotg, GOTGCTL);
if (dwc2_is_device_mode(hsotg)) if (dwc2_is_device_mode(hsotg))
dwc2_hsotg_disconnect(hsotg); dwc2_hsotg_disconnect(hsotg);
@ -150,24 +150,24 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
hsotg->lx_state = DWC2_L0; hsotg->lx_state = DWC2_L0;
} }
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL); gotgctl = dwc2_readl(hsotg, GOTGCTL);
gotgctl &= ~GOTGCTL_DEVHNPEN; gotgctl &= ~GOTGCTL_DEVHNPEN;
dwc2_writel(gotgctl, hsotg->regs + GOTGCTL); dwc2_writel(hsotg, gotgctl, GOTGCTL);
} }
if (gotgint & GOTGINT_SES_REQ_SUC_STS_CHNG) { if (gotgint & GOTGINT_SES_REQ_SUC_STS_CHNG) {
dev_dbg(hsotg->dev, dev_dbg(hsotg->dev,
" ++OTG Interrupt: Session Request Success Status Change++\n"); " ++OTG Interrupt: Session Request Success Status Change++\n");
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL); gotgctl = dwc2_readl(hsotg, GOTGCTL);
if (gotgctl & GOTGCTL_SESREQSCS) { if (gotgctl & GOTGCTL_SESREQSCS) {
if (hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS && if (hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS &&
hsotg->params.i2c_enable) { hsotg->params.i2c_enable) {
hsotg->srp_success = 1; hsotg->srp_success = 1;
} else { } else {
/* Clear Session Request */ /* Clear Session Request */
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL); gotgctl = dwc2_readl(hsotg, GOTGCTL);
gotgctl &= ~GOTGCTL_SESREQ; 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 * Print statements during the HNP interrupt handling
* can cause it to fail * 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 * WA for 3.00a- HW is not setting cur_mode, even sometimes
* this does not help * 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 * interrupt does not get handled and Linux
* complains loudly. * complains loudly.
*/ */
gintmsk = dwc2_readl(hsotg->regs + GINTMSK); gintmsk = dwc2_readl(hsotg, GINTMSK);
gintmsk &= ~GINTSTS_SOF; gintmsk &= ~GINTSTS_SOF;
dwc2_writel(gintmsk, hsotg->regs + GINTMSK); dwc2_writel(hsotg, gintmsk, GINTMSK);
/* /*
* Call callback function with spin lock * 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; hsotg->op_state = OTG_STATE_B_HOST;
} }
} else { } else {
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL); gotgctl = dwc2_readl(hsotg, GOTGCTL);
gotgctl &= ~(GOTGCTL_HNPREQ | GOTGCTL_DEVHNPEN); gotgctl &= ~(GOTGCTL_HNPREQ | GOTGCTL_DEVHNPEN);
dwc2_writel(gotgctl, hsotg->regs + GOTGCTL); dwc2_writel(hsotg, gotgctl, GOTGCTL);
dev_dbg(hsotg->dev, "HNP Failed\n"); dev_dbg(hsotg->dev, "HNP Failed\n");
dev_err(hsotg->dev, dev_err(hsotg->dev,
"Device Not Connected/Responding\n"); "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; hsotg->op_state = OTG_STATE_A_PERIPHERAL;
} else { } else {
/* Need to disable SOF interrupt immediately */ /* Need to disable SOF interrupt immediately */
gintmsk = dwc2_readl(hsotg->regs + GINTMSK); gintmsk = dwc2_readl(hsotg, GINTMSK);
gintmsk &= ~GINTSTS_SOF; gintmsk &= ~GINTSTS_SOF;
dwc2_writel(gintmsk, hsotg->regs + GINTMSK); dwc2_writel(hsotg, gintmsk, GINTMSK);
spin_unlock(&hsotg->lock); spin_unlock(&hsotg->lock);
dwc2_hcd_start(hsotg); dwc2_hcd_start(hsotg);
spin_lock(&hsotg->lock); 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"); dev_dbg(hsotg->dev, " ++OTG Interrupt: Debounce Done++\n");
/* Clear GOTGINT */ /* 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; u32 gintmsk;
/* Clear interrupt */ /* Clear interrupt */
dwc2_writel(GINTSTS_CONIDSTSCHNG, hsotg->regs + GINTSTS); dwc2_writel(hsotg, GINTSTS_CONIDSTSCHNG, GINTSTS);
/* Need to disable SOF interrupt immediately */ /* Need to disable SOF interrupt immediately */
gintmsk = dwc2_readl(hsotg->regs + GINTMSK); gintmsk = dwc2_readl(hsotg, GINTMSK);
gintmsk &= ~GINTSTS_SOF; 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", dev_dbg(hsotg->dev, " ++Connector ID Status Change Interrupt++ (%s)\n",
dwc2_is_host_mode(hsotg) ? "Host" : "Device"); dwc2_is_host_mode(hsotg) ? "Host" : "Device");
@ -314,7 +314,7 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
int ret; int ret;
/* Clear interrupt */ /* 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", dev_dbg(hsotg->dev, "Session request interrupt - lx_state=%d\n",
hsotg->lx_state); hsotg->lx_state);
@ -351,15 +351,15 @@ static void dwc2_wakeup_from_lpm_l1(struct dwc2_hsotg *hsotg)
return; return;
} }
glpmcfg = dwc2_readl(hsotg->regs + GLPMCFG); glpmcfg = dwc2_readl(hsotg, GLPMCFG);
if (dwc2_is_device_mode(hsotg)) { if (dwc2_is_device_mode(hsotg)) {
dev_dbg(hsotg->dev, "Exit from L1 state\n"); dev_dbg(hsotg->dev, "Exit from L1 state\n");
glpmcfg &= ~GLPMCFG_ENBLSLPM; glpmcfg &= ~GLPMCFG_ENBLSLPM;
glpmcfg &= ~GLPMCFG_HIRD_THRES_EN; glpmcfg &= ~GLPMCFG_HIRD_THRES_EN;
dwc2_writel(glpmcfg, hsotg->regs + GLPMCFG); dwc2_writel(hsotg, glpmcfg, GLPMCFG);
do { do {
glpmcfg = dwc2_readl(hsotg->regs + GLPMCFG); glpmcfg = dwc2_readl(hsotg, GLPMCFG);
if (!(glpmcfg & (GLPMCFG_COREL1RES_MASK | if (!(glpmcfg & (GLPMCFG_COREL1RES_MASK |
GLPMCFG_L1RESUMEOK | GLPMCFG_SLPSTS))) GLPMCFG_L1RESUMEOK | GLPMCFG_SLPSTS)))
@ -398,7 +398,7 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
int ret; int ret;
/* Clear interrupt */ /* 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, "++Resume or Remote Wakeup Detected Interrupt++\n");
dev_dbg(hsotg->dev, "%s lxstate = %d\n", __func__, hsotg->lx_state); 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)) { if (dwc2_is_device_mode(hsotg)) {
dev_dbg(hsotg->dev, "DSTS=0x%0x\n", dev_dbg(hsotg->dev, "DSTS=0x%0x\n",
dwc2_readl(hsotg->regs + DSTS)); dwc2_readl(hsotg, DSTS));
if (hsotg->lx_state == DWC2_L2) { if (hsotg->lx_state == DWC2_L2) {
u32 dctl = dwc2_readl(hsotg->regs + DCTL); u32 dctl = dwc2_readl(hsotg, DCTL);
/* Clear Remote Wakeup Signaling */ /* Clear Remote Wakeup Signaling */
dctl &= ~DCTL_RMTWKUPSIG; dctl &= ~DCTL_RMTWKUPSIG;
dwc2_writel(dctl, hsotg->regs + DCTL); dwc2_writel(hsotg, dctl, DCTL);
ret = dwc2_exit_partial_power_down(hsotg, true); ret = dwc2_exit_partial_power_down(hsotg, true);
if (ret && (ret != -ENOTSUPP)) if (ret && (ret != -ENOTSUPP))
dev_err(hsotg->dev, "exit power_down failed\n"); 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; return;
if (hsotg->lx_state != DWC2_L1) { if (hsotg->lx_state != DWC2_L1) {
u32 pcgcctl = dwc2_readl(hsotg->regs + PCGCTL); u32 pcgcctl = dwc2_readl(hsotg, PCGCTL);
/* Restart the Phy Clock */ /* Restart the Phy Clock */
pcgcctl &= ~PCGCTL_STOPPCLK; pcgcctl &= ~PCGCTL_STOPPCLK;
dwc2_writel(pcgcctl, hsotg->regs + PCGCTL); dwc2_writel(hsotg, pcgcctl, PCGCTL);
mod_timer(&hsotg->wkp_timer, mod_timer(&hsotg->wkp_timer,
jiffies + msecs_to_jiffies(71)); jiffies + msecs_to_jiffies(71));
} else { } 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) 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", dev_dbg(hsotg->dev, "++Disconnect Detected Interrupt++ (%s) %s\n",
dwc2_is_host_mode(hsotg) ? "Host" : "Device", dwc2_is_host_mode(hsotg) ? "Host" : "Device",
@ -474,7 +474,7 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
int ret; int ret;
/* Clear interrupt */ /* Clear interrupt */
dwc2_writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS); dwc2_writel(hsotg, GINTSTS_USBSUSP, GINTSTS);
dev_dbg(hsotg->dev, "USB SUSPEND\n"); 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 * Check the Device status register to determine if the Suspend
* state is active * 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, "%s: DSTS=0x%0x\n", __func__, dsts);
dev_dbg(hsotg->dev, dev_dbg(hsotg->dev,
"DSTS.Suspend Status=%d HWCFG4.Power Optimize=%d HWCFG4.Hibernation=%d\n", "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; u32 enslpm;
/* Clear interrupt */ /* 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)) { if (!(glpmcfg & GLPMCFG_LPMCAP)) {
dev_err(hsotg->dev, "Unexpected LPM interrupt\n"); dev_err(hsotg->dev, "Unexpected LPM interrupt\n");
@ -588,16 +588,16 @@ static void dwc2_handle_lpm_intr(struct dwc2_hsotg *hsotg)
} else { } else {
dev_dbg(hsotg->dev, "Entering Sleep with L1 Gating\n"); 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; 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) * Examine prt_sleep_sts after TL1TokenTetry period max (10 us)
*/ */
udelay(10); udelay(10);
glpmcfg = dwc2_readl(hsotg->regs + GLPMCFG); glpmcfg = dwc2_readl(hsotg, GLPMCFG);
if (glpmcfg & GLPMCFG_SLPSTS) { if (glpmcfg & GLPMCFG_SLPSTS) {
/* Save the current state */ /* Save the current state */
@ -627,9 +627,9 @@ static u32 dwc2_read_common_intr(struct dwc2_hsotg *hsotg)
u32 gahbcfg; u32 gahbcfg;
u32 gintmsk_common = GINTMSK_COMMON; u32 gintmsk_common = GINTMSK_COMMON;
gintsts = dwc2_readl(hsotg->regs + GINTSTS); gintsts = dwc2_readl(hsotg, GINTSTS);
gintmsk = dwc2_readl(hsotg->regs + GINTMSK); gintmsk = dwc2_readl(hsotg, GINTMSK);
gahbcfg = dwc2_readl(hsotg->regs + GAHBCFG); gahbcfg = dwc2_readl(hsotg, GAHBCFG);
/* If any common interrupts set */ /* If any common interrupts set */
if (gintsts & gintmsk_common) if (gintsts & gintmsk_common)
@ -653,9 +653,9 @@ static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg *hsotg)
u32 gpwrdn; u32 gpwrdn;
int linestate; int linestate;
gpwrdn = dwc2_readl(hsotg->regs + GPWRDN); gpwrdn = dwc2_readl(hsotg, GPWRDN);
/* clear all interrupt */ /* clear all interrupt */
dwc2_writel(gpwrdn, hsotg->regs + GPWRDN); dwc2_writel(hsotg, gpwrdn, GPWRDN);
linestate = (gpwrdn & GPWRDN_LINESTATE_MASK) >> GPWRDN_LINESTATE_SHIFT; linestate = (gpwrdn & GPWRDN_LINESTATE_MASK) >> GPWRDN_LINESTATE_SHIFT;
dev_dbg(hsotg->dev, dev_dbg(hsotg->dev,
"%s: dwc2_handle_gpwrdwn_intr called gpwrdn= %08x\n", __func__, "%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__); dev_dbg(hsotg->dev, "%s: GPWRDN_DISCONN_DET\n", __func__);
/* Switch-on voltage to the core */ /* Switch-on voltage to the core */
gpwrdn_tmp = dwc2_readl(hsotg->regs + GPWRDN); gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
gpwrdn_tmp &= ~GPWRDN_PWRDNSWTCH; gpwrdn_tmp &= ~GPWRDN_PWRDNSWTCH;
dwc2_writel(gpwrdn_tmp, hsotg->regs + GPWRDN); dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
udelay(10); udelay(10);
/* Reset core */ /* Reset core */
gpwrdn_tmp = dwc2_readl(hsotg->regs + GPWRDN); gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
gpwrdn_tmp &= ~GPWRDN_PWRDNRSTN; gpwrdn_tmp &= ~GPWRDN_PWRDNRSTN;
dwc2_writel(gpwrdn_tmp, hsotg->regs + GPWRDN); dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
udelay(10); udelay(10);
/* Disable Power Down Clamp */ /* Disable Power Down Clamp */
gpwrdn_tmp = dwc2_readl(hsotg->regs + GPWRDN); gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
gpwrdn_tmp &= ~GPWRDN_PWRDNCLMP; gpwrdn_tmp &= ~GPWRDN_PWRDNCLMP;
dwc2_writel(gpwrdn_tmp, hsotg->regs + GPWRDN); dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
udelay(10); udelay(10);
/* Deassert reset core */ /* Deassert reset core */
gpwrdn_tmp = dwc2_readl(hsotg->regs + GPWRDN); gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
gpwrdn_tmp |= GPWRDN_PWRDNRSTN; gpwrdn_tmp |= GPWRDN_PWRDNRSTN;
dwc2_writel(gpwrdn_tmp, hsotg->regs + GPWRDN); dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
udelay(10); udelay(10);
/* Disable PMU interrupt */ /* Disable PMU interrupt */
gpwrdn_tmp = dwc2_readl(hsotg->regs + GPWRDN); gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
gpwrdn_tmp &= ~GPWRDN_PMUINTSEL; gpwrdn_tmp &= ~GPWRDN_PMUINTSEL;
dwc2_writel(gpwrdn_tmp, hsotg->regs + GPWRDN); dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
/* De-assert Wakeup Logic */ /* De-assert Wakeup Logic */
gpwrdn_tmp = dwc2_readl(hsotg->regs + GPWRDN); gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
gpwrdn_tmp &= ~GPWRDN_PMUACTV; gpwrdn_tmp &= ~GPWRDN_PMUACTV;
dwc2_writel(gpwrdn_tmp, hsotg->regs + GPWRDN); dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
hsotg->hibernated = 0; 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. */ /* Reading current frame number value in device or host modes. */
if (dwc2_is_device_mode(hsotg)) 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; & DSTS_SOFFN_MASK) >> DSTS_SOFFN_SHIFT;
else else
hsotg->frame_number = (dwc2_readl(hsotg->regs + HFNUM) hsotg->frame_number = (dwc2_readl(hsotg, HFNUM)
& HFNUM_FRNUM_MASK) >> HFNUM_FRNUM_SHIFT; & HFNUM_FRNUM_MASK) >> HFNUM_FRNUM_SHIFT;
gintsts = dwc2_read_common_intr(hsotg); gintsts = dwc2_read_common_intr(hsotg);

View file

@ -69,7 +69,7 @@ static int testmode_show(struct seq_file *s, void *unused)
int dctl; int dctl;
spin_lock_irqsave(&hsotg->lock, flags); spin_lock_irqsave(&hsotg->lock, flags);
dctl = dwc2_readl(hsotg->regs + DCTL); dctl = dwc2_readl(hsotg, DCTL);
dctl &= DCTL_TSTCTL_MASK; dctl &= DCTL_TSTCTL_MASK;
dctl >>= DCTL_TSTCTL_SHIFT; dctl >>= DCTL_TSTCTL_SHIFT;
spin_unlock_irqrestore(&hsotg->lock, flags); 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) static int state_show(struct seq_file *seq, void *v)
{ {
struct dwc2_hsotg *hsotg = seq->private; struct dwc2_hsotg *hsotg = seq->private;
void __iomem *regs = hsotg->regs;
int idx; int idx;
seq_printf(seq, "DCFG=0x%08x, DCTL=0x%08x, DSTS=0x%08x\n", seq_printf(seq, "DCFG=0x%08x, DCTL=0x%08x, DSTS=0x%08x\n",
dwc2_readl(regs + DCFG), dwc2_readl(hsotg, DCFG),
dwc2_readl(regs + DCTL), dwc2_readl(hsotg, DCTL),
dwc2_readl(regs + DSTS)); dwc2_readl(hsotg, DSTS));
seq_printf(seq, "DIEPMSK=0x%08x, DOEPMASK=0x%08x\n", 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", seq_printf(seq, "GINTMSK=0x%08x, GINTSTS=0x%08x\n",
dwc2_readl(regs + GINTMSK), dwc2_readl(hsotg, GINTMSK),
dwc2_readl(regs + GINTSTS)); dwc2_readl(hsotg, GINTSTS));
seq_printf(seq, "DAINTMSK=0x%08x, DAINT=0x%08x\n", seq_printf(seq, "DAINTMSK=0x%08x, DAINT=0x%08x\n",
dwc2_readl(regs + DAINTMSK), dwc2_readl(hsotg, DAINTMSK),
dwc2_readl(regs + DAINT)); dwc2_readl(hsotg, DAINT));
seq_printf(seq, "GNPTXSTS=0x%08x, GRXSTSR=%08x\n", seq_printf(seq, "GNPTXSTS=0x%08x, GRXSTSR=%08x\n",
dwc2_readl(regs + GNPTXSTS), dwc2_readl(hsotg, GNPTXSTS),
dwc2_readl(regs + GRXSTSR)); dwc2_readl(hsotg, GRXSTSR));
seq_puts(seq, "\nEndpoint status:\n"); seq_puts(seq, "\nEndpoint status:\n");
for (idx = 0; idx < hsotg->num_of_eps; idx++) { for (idx = 0; idx < hsotg->num_of_eps; idx++) {
u32 in, out; u32 in, out;
in = dwc2_readl(regs + DIEPCTL(idx)); in = dwc2_readl(hsotg, DIEPCTL(idx));
out = dwc2_readl(regs + DOEPCTL(idx)); out = dwc2_readl(hsotg, DOEPCTL(idx));
seq_printf(seq, "ep%d: DIEPCTL=0x%08x, DOEPCTL=0x%08x", seq_printf(seq, "ep%d: DIEPCTL=0x%08x, DOEPCTL=0x%08x",
idx, in, out); idx, in, out);
in = dwc2_readl(regs + DIEPTSIZ(idx)); in = dwc2_readl(hsotg, DIEPTSIZ(idx));
out = dwc2_readl(regs + DOEPTSIZ(idx)); out = dwc2_readl(hsotg, DOEPTSIZ(idx));
seq_printf(seq, ", DIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x", seq_printf(seq, ", DIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x",
in, out); in, out);
@ -184,14 +183,13 @@ DEFINE_SHOW_ATTRIBUTE(state);
static int fifo_show(struct seq_file *seq, void *v) static int fifo_show(struct seq_file *seq, void *v)
{ {
struct dwc2_hsotg *hsotg = seq->private; struct dwc2_hsotg *hsotg = seq->private;
void __iomem *regs = hsotg->regs;
u32 val; u32 val;
int idx; int idx;
seq_puts(seq, "Non-periodic FIFOs:\n"); 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", seq_printf(seq, "NPTXFIFO: Size %d, Start 0x%08x\n",
val >> FIFOSIZE_DEPTH_SHIFT, val >> FIFOSIZE_DEPTH_SHIFT,
val & FIFOSIZE_STARTADDR_MASK); val & FIFOSIZE_STARTADDR_MASK);
@ -199,7 +197,7 @@ static int fifo_show(struct seq_file *seq, void *v)
seq_puts(seq, "\nPeriodic TXFIFOs:\n"); seq_puts(seq, "\nPeriodic TXFIFOs:\n");
for (idx = 1; idx < hsotg->num_of_eps; idx++) { 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, seq_printf(seq, "\tDPTXFIFO%2d: Size %d, Start 0x%08x\n", idx,
val >> FIFOSIZE_DEPTH_SHIFT, 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_ep *ep = seq->private;
struct dwc2_hsotg *hsotg = ep->parent; struct dwc2_hsotg *hsotg = ep->parent;
struct dwc2_hsotg_req *req; struct dwc2_hsotg_req *req;
void __iomem *regs = hsotg->regs;
int index = ep->index; int index = ep->index;
int show_limit = 15; int show_limit = 15;
unsigned long flags; unsigned long flags;
@ -239,20 +236,20 @@ static int ep_show(struct seq_file *seq, void *v)
/* first show the register state */ /* first show the register state */
seq_printf(seq, "\tDIEPCTL=0x%08x, DOEPCTL=0x%08x\n", seq_printf(seq, "\tDIEPCTL=0x%08x, DOEPCTL=0x%08x\n",
dwc2_readl(regs + DIEPCTL(index)), dwc2_readl(hsotg, DIEPCTL(index)),
dwc2_readl(regs + DOEPCTL(index))); dwc2_readl(hsotg, DOEPCTL(index)));
seq_printf(seq, "\tDIEPDMA=0x%08x, DOEPDMA=0x%08x\n", seq_printf(seq, "\tDIEPDMA=0x%08x, DOEPDMA=0x%08x\n",
dwc2_readl(regs + DIEPDMA(index)), dwc2_readl(hsotg, DIEPDMA(index)),
dwc2_readl(regs + DOEPDMA(index))); dwc2_readl(hsotg, DOEPDMA(index)));
seq_printf(seq, "\tDIEPINT=0x%08x, DOEPINT=0x%08x\n", seq_printf(seq, "\tDIEPINT=0x%08x, DOEPINT=0x%08x\n",
dwc2_readl(regs + DIEPINT(index)), dwc2_readl(hsotg, DIEPINT(index)),
dwc2_readl(regs + DOEPINT(index))); dwc2_readl(hsotg, DOEPINT(index)));
seq_printf(seq, "\tDIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x\n", seq_printf(seq, "\tDIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x\n",
dwc2_readl(regs + DIEPTSIZ(index)), dwc2_readl(hsotg, DIEPTSIZ(index)),
dwc2_readl(regs + DOEPTSIZ(index))); dwc2_readl(hsotg, DOEPTSIZ(index)));
seq_puts(seq, "\n"); seq_puts(seq, "\n");
seq_printf(seq, "mps %d\n", ep->ep.maxpacket); seq_printf(seq, "mps %d\n", ep->ep.maxpacket);

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View 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) 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; 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); 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) 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); hprt0 &= ~(HPRT0_ENA | HPRT0_CONNDET | HPRT0_ENACHG | HPRT0_OVRCURRCHG);
return hprt0; 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) static inline u32 dwc2_read_core_intr(struct dwc2_hsotg *hsotg)
{ {
return dwc2_readl(hsotg->regs + GINTSTS) & return dwc2_readl(hsotg, GINTSTS) &
dwc2_readl(hsotg->regs + GINTMSK); dwc2_readl(hsotg, GINTMSK);
} }
static inline u32 dwc2_hcd_urb_get_status(struct dwc2_hcd_urb *dwc2_urb) static inline u32 dwc2_hcd_urb_get_status(struct dwc2_hcd_urb *dwc2_urb)

View 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); spin_lock_irqsave(&hsotg->lock, flags);
hcfg = dwc2_readl(hsotg->regs + HCFG); hcfg = dwc2_readl(hsotg, HCFG);
if (hcfg & HCFG_PERSCHEDENA) { if (hcfg & HCFG_PERSCHEDENA) {
/* already enabled */ /* already enabled */
spin_unlock_irqrestore(&hsotg->lock, flags); spin_unlock_irqrestore(&hsotg->lock, flags);
return; return;
} }
dwc2_writel(hsotg->frame_list_dma, hsotg->regs + HFLBADDR); dwc2_writel(hsotg, hsotg->frame_list_dma, HFLBADDR);
hcfg &= ~HCFG_FRLISTEN_MASK; hcfg &= ~HCFG_FRLISTEN_MASK;
hcfg |= fr_list_en | HCFG_PERSCHEDENA; hcfg |= fr_list_en | HCFG_PERSCHEDENA;
dev_vdbg(hsotg->dev, "Enabling Periodic schedule\n"); 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); 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); spin_lock_irqsave(&hsotg->lock, flags);
hcfg = dwc2_readl(hsotg->regs + HCFG); hcfg = dwc2_readl(hsotg, HCFG);
if (!(hcfg & HCFG_PERSCHEDENA)) { if (!(hcfg & HCFG_PERSCHEDENA)) {
/* already disabled */ /* already disabled */
spin_unlock_irqrestore(&hsotg->lock, flags); spin_unlock_irqrestore(&hsotg->lock, flags);
@ -218,7 +218,7 @@ static void dwc2_per_sched_disable(struct dwc2_hsotg *hsotg)
hcfg &= ~HCFG_PERSCHEDENA; hcfg &= ~HCFG_PERSCHEDENA;
dev_vdbg(hsotg->dev, "Disabling Periodic schedule\n"); 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); spin_unlock_irqrestore(&hsotg->lock, flags);
} }

View file

@ -144,7 +144,7 @@ static void dwc2_sof_intr(struct dwc2_hsotg *hsotg)
enum dwc2_transaction_type tr_type; enum dwc2_transaction_type tr_type;
/* Clear interrupt */ /* Clear interrupt */
dwc2_writel(GINTSTS_SOF, hsotg->regs + GINTSTS); dwc2_writel(hsotg, GINTSTS_SOF, GINTSTS);
#ifdef DEBUG_SOF #ifdef DEBUG_SOF
dev_vdbg(hsotg->dev, "--Start of Frame Interrupt--\n"); 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()) if (dbg_perio())
dev_vdbg(hsotg->dev, "--RxFIFO Level Interrupt--\n"); 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; chnum = (grxsts & GRXSTS_HCHNUM_MASK) >> GRXSTS_HCHNUM_SHIFT;
chan = hsotg->hc_ptr_array[chnum]; chan = hsotg->hc_ptr_array[chnum];
if (!chan) { 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); dev_vdbg(hsotg->dev, "%s(%p)\n", __func__, hsotg);
/* Every time when port enables calculate HFIR.FrInterval */ /* Every time when port enables calculate HFIR.FrInterval */
hfir = dwc2_readl(hsotg->regs + HFIR); hfir = dwc2_readl(hsotg, HFIR);
hfir &= ~HFIR_FRINT_MASK; hfir &= ~HFIR_FRINT_MASK;
hfir |= dwc2_calc_frame_interval(hsotg) << HFIR_FRINT_SHIFT & hfir |= dwc2_calc_frame_interval(hsotg) << HFIR_FRINT_SHIFT &
HFIR_FRINT_MASK; 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 */ /* Check if we need to adjust the PHY clock speed for low power */
if (!params->host_support_fs_ls_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; return;
} }
usbcfg = dwc2_readl(hsotg->regs + GUSBCFG); usbcfg = dwc2_readl(hsotg, GUSBCFG);
prtspd = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT; prtspd = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
if (prtspd == HPRT0_SPD_LOW_SPEED || prtspd == HPRT0_SPD_FULL_SPEED) { 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)) { if (!(usbcfg & GUSBCFG_PHY_LP_CLK_SEL)) {
/* Set PHY low power clock select for FS/LS devices */ /* Set PHY low power clock select for FS/LS devices */
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; do_reset = 1;
} }
hcfg = dwc2_readl(hsotg->regs + HCFG); hcfg = dwc2_readl(hsotg, HCFG);
fslspclksel = (hcfg & HCFG_FSLSPCLKSEL_MASK) >> fslspclksel = (hcfg & HCFG_FSLSPCLKSEL_MASK) >>
HCFG_FSLSPCLKSEL_SHIFT; HCFG_FSLSPCLKSEL_SHIFT;
@ -312,7 +312,7 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
fslspclksel = HCFG_FSLSPCLKSEL_6_MHZ; fslspclksel = HCFG_FSLSPCLKSEL_6_MHZ;
hcfg &= ~HCFG_FSLSPCLKSEL_MASK; hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
hcfg |= fslspclksel << HCFG_FSLSPCLKSEL_SHIFT; hcfg |= fslspclksel << HCFG_FSLSPCLKSEL_SHIFT;
dwc2_writel(hcfg, hsotg->regs + HCFG); dwc2_writel(hsotg, hcfg, HCFG);
do_reset = 1; do_reset = 1;
} }
} else { } else {
@ -323,7 +323,7 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
fslspclksel = HCFG_FSLSPCLKSEL_48_MHZ; fslspclksel = HCFG_FSLSPCLKSEL_48_MHZ;
hcfg &= ~HCFG_FSLSPCLKSEL_MASK; hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
hcfg |= fslspclksel << HCFG_FSLSPCLKSEL_SHIFT; hcfg |= fslspclksel << HCFG_FSLSPCLKSEL_SHIFT;
dwc2_writel(hcfg, hsotg->regs + HCFG); dwc2_writel(hsotg, hcfg, HCFG);
do_reset = 1; do_reset = 1;
} }
} }
@ -331,14 +331,14 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
/* Not low power */ /* Not low power */
if (usbcfg & GUSBCFG_PHY_LP_CLK_SEL) { if (usbcfg & GUSBCFG_PHY_LP_CLK_SEL) {
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; do_reset = 1;
} }
} }
if (do_reset) { if (do_reset) {
*hprt0_modify |= HPRT0_RST; *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, queue_delayed_work(hsotg->wq_otg, &hsotg->reset_work,
msecs_to_jiffies(60)); msecs_to_jiffies(60));
} else { } else {
@ -359,7 +359,7 @@ static void dwc2_port_intr(struct dwc2_hsotg *hsotg)
dev_vdbg(hsotg->dev, "--Port Interrupt--\n"); dev_vdbg(hsotg->dev, "--Port Interrupt--\n");
hprt0 = dwc2_readl(hsotg->regs + HPRT0); hprt0 = dwc2_readl(hsotg, HPRT0);
hprt0_modify = hprt0; hprt0_modify = hprt0;
/* /*
@ -374,7 +374,7 @@ static void dwc2_port_intr(struct dwc2_hsotg *hsotg)
* Set flag and clear if detected * Set flag and clear if detected
*/ */
if (hprt0 & HPRT0_CONNDET) { 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, dev_vdbg(hsotg->dev,
"--Port Interrupt HPRT0=0x%08x Port Connect Detected--\n", "--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 * Clear if detected - Set internal flag if disabled
*/ */
if (hprt0 & HPRT0_ENACHG) { 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, dev_vdbg(hsotg->dev,
" --Port Interrupt HPRT0=0x%08x Port Enable Changed (now %d)--\n", " --Port Interrupt HPRT0=0x%08x Port Enable Changed (now %d)--\n",
hprt0, !!(hprt0 & HPRT0_ENA)); hprt0, !!(hprt0 & HPRT0_ENA));
@ -406,17 +406,17 @@ static void dwc2_port_intr(struct dwc2_hsotg *hsotg)
hsotg->params.dma_desc_enable = false; hsotg->params.dma_desc_enable = false;
hsotg->new_connection = false; hsotg->new_connection = false;
hcfg = dwc2_readl(hsotg->regs + HCFG); hcfg = dwc2_readl(hsotg, HCFG);
hcfg &= ~HCFG_DESCDMA; hcfg &= ~HCFG_DESCDMA;
dwc2_writel(hcfg, hsotg->regs + HCFG); dwc2_writel(hsotg, hcfg, HCFG);
} }
} }
} }
/* Overcurrent Change Interrupt */ /* Overcurrent Change Interrupt */
if (hprt0 & HPRT0_OVRCURRCHG) { if (hprt0 & HPRT0_OVRCURRCHG) {
dwc2_writel(hprt0_modify | HPRT0_OVRCURRCHG, dwc2_writel(hsotg, hprt0_modify | HPRT0_OVRCURRCHG,
hsotg->regs + HPRT0); HPRT0);
dev_vdbg(hsotg->dev, dev_vdbg(hsotg->dev,
" --Port Interrupt HPRT0=0x%08x Port Overcurrent Changed--\n", " --Port Interrupt HPRT0=0x%08x Port Overcurrent Changed--\n",
hprt0); hprt0);
@ -441,7 +441,7 @@ static u32 dwc2_get_actual_xfer_length(struct dwc2_hsotg *hsotg,
{ {
u32 hctsiz, count, length; 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 (halt_status == DWC2_HC_XFER_COMPLETE) {
if (chan->ep_is_in) { if (chan->ep_is_in) {
@ -518,7 +518,7 @@ static int dwc2_update_urb_state(struct dwc2_hsotg *hsotg,
urb->status = 0; 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", dev_vdbg(hsotg->dev, "DWC_otg: %s: %s, channel %d\n",
__func__, (chan->ep_is_in ? "IN" : "OUT"), chnum); __func__, (chan->ep_is_in ? "IN" : "OUT"), chnum);
dev_vdbg(hsotg->dev, " chan->xfer_len %d\n", chan->xfer_len); 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_host_chan *chan, int chnum,
struct dwc2_qtd *qtd) 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; u32 pid = (hctsiz & TSIZ_SC_MC_PID_MASK) >> TSIZ_SC_MC_PID_SHIFT;
if (chan->ep_type != USB_ENDPOINT_XFER_CONTROL) { 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); 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 */ /* Try to queue more transfers now that there's a free channel */
tr_type = dwc2_hcd_select_transactions(hsotg); 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 * is enabled so that the non-periodic schedule will
* be processed * be processed
*/ */
gintmsk = dwc2_readl(hsotg->regs + GINTMSK); gintmsk = dwc2_readl(hsotg, GINTMSK);
gintmsk |= GINTSTS_NPTXFEMP; gintmsk |= GINTSTS_NPTXFEMP;
dwc2_writel(gintmsk, hsotg->regs + GINTMSK); dwc2_writel(hsotg, gintmsk, GINTMSK);
} else { } else {
dev_vdbg(hsotg->dev, "isoc/intr\n"); 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 * enabled so that the periodic schedule will be
* processed * processed
*/ */
gintmsk = dwc2_readl(hsotg->regs + GINTMSK); gintmsk = dwc2_readl(hsotg, GINTMSK);
gintmsk |= GINTSTS_PTXFEMP; 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, struct dwc2_qtd *qtd,
enum dwc2_halt_status halt_status) 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; qtd->error_count = 0;
@ -959,7 +959,7 @@ static int dwc2_xfercomp_isoc_split_in(struct dwc2_hsotg *hsotg,
qtd->isoc_split_offset += len; 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; pid = (hctsiz & TSIZ_SC_MC_PID_MASK) >> TSIZ_SC_MC_PID_SHIFT;
if (frame_desc->actual_length >= frame_desc->length || pid == 0) { 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; 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", dev_vdbg(hsotg->dev, "DWC_otg: %s: %s, channel %d\n",
__func__, (chan->ep_is_in ? "IN" : "OUT"), chnum); __func__, (chan->ep_is_in ? "IN" : "OUT"), chnum);
dev_vdbg(hsotg->dev, " chan->start_pkt_count %d\n", 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); dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
hcchar = dwc2_readl(hsotg->regs + HCCHAR(chnum)); hcchar = dwc2_readl(hsotg, HCCHAR(chnum));
hcsplt = dwc2_readl(hsotg->regs + HCSPLT(chnum)); hcsplt = dwc2_readl(hsotg, HCSPLT(chnum));
hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum)); hctsiz = dwc2_readl(hsotg, HCTSIZ(chnum));
hc_dma = dwc2_readl(hsotg->regs + HCDMA(chnum)); hc_dma = dwc2_readl(hsotg, HCDMA(chnum));
dev_err(hsotg->dev, "AHB ERROR, Channel %d\n", chnum); dev_err(hsotg->dev, "AHB ERROR, Channel %d\n", chnum);
dev_err(hsotg->dev, " hcchar 0x%08x, hcsplt 0x%08x\n", hcchar, hcsplt); 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 * This code is here only as a check. This condition should
* never happen. Ignore the halt if it does occur. * never happen. Ignore the halt if it does occur.
*/ */
hcchar = dwc2_readl(hsotg->regs + HCCHAR(chnum)); hcchar = dwc2_readl(hsotg, HCCHAR(chnum));
hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum)); hctsiz = dwc2_readl(hsotg, HCTSIZ(chnum));
hcintmsk = dwc2_readl(hsotg->regs + HCINTMSK(chnum)); hcintmsk = dwc2_readl(hsotg, HCINTMSK(chnum));
hcsplt = dwc2_readl(hsotg->regs + HCSPLT(chnum)); hcsplt = dwc2_readl(hsotg, HCSPLT(chnum));
dev_dbg(hsotg->dev, dev_dbg(hsotg->dev,
"%s: chan->halt_status DWC2_HC_XFER_NO_HALT_STATUS,\n", "%s: chan->halt_status DWC2_HC_XFER_NO_HALT_STATUS,\n",
__func__); __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 * when the halt interrupt occurs. Halt the channel again if it does
* occur. * occur.
*/ */
hcchar = dwc2_readl(hsotg->regs + HCCHAR(chnum)); hcchar = dwc2_readl(hsotg, HCCHAR(chnum));
if (hcchar & HCCHAR_CHDIS) { if (hcchar & HCCHAR_CHDIS) {
dev_warn(hsotg->dev, dev_warn(hsotg->dev,
"%s: hcchar.chdis set unexpectedly, hcchar 0x%08x, trying to halt again\n", "%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; return;
} }
hcintmsk = dwc2_readl(hsotg->regs + HCINTMSK(chnum)); hcintmsk = dwc2_readl(hsotg, HCINTMSK(chnum));
if (chan->hcint & HCINTMSK_XFERCOMPL) { if (chan->hcint & HCINTMSK_XFERCOMPL) {
/* /*
@ -1963,7 +1963,7 @@ static void dwc2_hc_chhltd_intr_dma(struct dwc2_hsotg *hsotg,
dev_err(hsotg->dev, dev_err(hsotg->dev,
"hcint 0x%08x, intsts 0x%08x\n", "hcint 0x%08x, intsts 0x%08x\n",
chan->hcint, chan->hcint,
dwc2_readl(hsotg->regs + GINTSTS)); dwc2_readl(hsotg, GINTSTS));
goto error; goto error;
} }
} }
@ -2036,11 +2036,11 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum)
chan = hsotg->hc_ptr_array[chnum]; chan = hsotg->hc_ptr_array[chnum];
hcint = dwc2_readl(hsotg->regs + HCINT(chnum)); hcint = dwc2_readl(hsotg, HCINT(chnum));
hcintmsk = dwc2_readl(hsotg->regs + HCINTMSK(chnum)); hcintmsk = dwc2_readl(hsotg, HCINTMSK(chnum));
if (!chan) { if (!chan) {
dev_err(hsotg->dev, "## hc_ptr_array for channel is NULL ##\n"); 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; return;
} }
@ -2052,7 +2052,7 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum)
hcint, hcintmsk, hcint & hcintmsk); 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 * If we got an interrupt after someone called
@ -2187,7 +2187,7 @@ static void dwc2_hc_intr(struct dwc2_hsotg *hsotg)
int i; int i;
struct dwc2_host_chan *chan, *chan_tmp; struct dwc2_host_chan *chan, *chan_tmp;
haint = dwc2_readl(hsotg->regs + HAINT); haint = dwc2_readl(hsotg, HAINT);
if (dbg_perio()) { if (dbg_perio()) {
dev_vdbg(hsotg->dev, "%s()\n", __func__); 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"); "DWC OTG HCD Finished Servicing Interrupts\n");
dev_vdbg(hsotg->dev, dev_vdbg(hsotg->dev,
"DWC OTG HCD gintsts=0x%08x gintmsk=0x%08x\n", "DWC OTG HCD gintsts=0x%08x gintmsk=0x%08x\n",
dwc2_readl(hsotg->regs + GINTSTS), dwc2_readl(hsotg, GINTSTS),
dwc2_readl(hsotg->regs + GINTMSK)); dwc2_readl(hsotg, GINTMSK));
} }
} }

View 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_in = !!dwc2_hcd_is_pipe_in(&urb->pipe_info);
bool ep_is_isoc = (ep_type == USB_ENDPOINT_XFER_ISOC); bool ep_is_isoc = (ep_type == USB_ENDPOINT_XFER_ISOC);
bool ep_is_int = (ep_type == USB_ENDPOINT_XFER_INT); 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; u32 prtspd = (hprt & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
bool do_split = (prtspd == HPRT0_SPD_HIGH_SPEED && bool do_split = (prtspd == HPRT0_SPD_HIGH_SPEED &&
dev_speed != USB_SPEED_HIGH); dev_speed != USB_SPEED_HIGH);
@ -1747,9 +1747,9 @@ int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
if (status) if (status)
return status; return status;
if (!hsotg->periodic_qh_count) { if (!hsotg->periodic_qh_count) {
intr_mask = dwc2_readl(hsotg->regs + GINTMSK); intr_mask = dwc2_readl(hsotg, GINTMSK);
intr_mask |= GINTSTS_SOF; intr_mask |= GINTSTS_SOF;
dwc2_writel(intr_mask, hsotg->regs + GINTMSK); dwc2_writel(hsotg, intr_mask, GINTMSK);
} }
hsotg->periodic_qh_count++; 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--; hsotg->periodic_qh_count--;
if (!hsotg->periodic_qh_count && if (!hsotg->periodic_qh_count &&
!hsotg->params.dma_desc_enable) { !hsotg->params.dma_desc_enable) {
intr_mask = dwc2_readl(hsotg->regs + GINTMSK); intr_mask = dwc2_readl(hsotg, GINTMSK);
intr_mask &= ~GINTSTS_SOF; intr_mask &= ~GINTSTS_SOF;
dwc2_writel(intr_mask, hsotg->regs + GINTMSK); dwc2_writel(hsotg, intr_mask, GINTMSK);
} }
} }

View file

@ -47,7 +47,6 @@ static void dwc2_set_bcm_params(struct dwc2_hsotg *hsotg)
p->max_transfer_size = 65535; p->max_transfer_size = 65535;
p->max_packet_count = 511; p->max_packet_count = 511;
p->ahbcfg = 0x10; p->ahbcfg = 0x10;
p->uframe_sched = false;
} }
static void dwc2_set_his_params(struct dwc2_hsotg *hsotg) 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->reload_ctl = false;
p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 <<
GAHBCFG_HBSTLEN_SHIFT; GAHBCFG_HBSTLEN_SHIFT;
p->uframe_sched = false;
p->change_speed_quirk = true; p->change_speed_quirk = true;
p->power_down = false; 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->phy_type = DWC2_PHY_TYPE_PARAM_UTMI;
p->ahbcfg = GAHBCFG_HBSTLEN_INCR8 << p->ahbcfg = GAHBCFG_HBSTLEN_INCR8 <<
GAHBCFG_HBSTLEN_SHIFT; GAHBCFG_HBSTLEN_SHIFT;
p->uframe_sched = false;
} }
static void dwc2_set_amcc_params(struct dwc2_hsotg *hsotg) 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->max_packet_count = 256;
p->phy_type = DWC2_PHY_TYPE_PARAM_FS; p->phy_type = DWC2_PHY_TYPE_PARAM_FS;
p->i2c_enable = false; p->i2c_enable = false;
p->uframe_sched = false;
p->activate_stm_fs_transceiver = true; 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); dwc2_force_mode(hsotg, true);
gnptxfsiz = dwc2_readl(hsotg->regs + GNPTXFSIZ); gnptxfsiz = dwc2_readl(hsotg, GNPTXFSIZ);
hptxfsiz = dwc2_readl(hsotg->regs + HPTXFSIZ); hptxfsiz = dwc2_readl(hsotg, HPTXFSIZ);
hw->host_nperio_tx_fifo_size = (gnptxfsiz & FIFOSIZE_DEPTH_MASK) >> hw->host_nperio_tx_fifo_size = (gnptxfsiz & FIFOSIZE_DEPTH_MASK) >>
FIFOSIZE_DEPTH_SHIFT; FIFOSIZE_DEPTH_SHIFT;
@ -679,13 +675,13 @@ static void dwc2_get_dev_hwparams(struct dwc2_hsotg *hsotg)
dwc2_force_mode(hsotg, false); dwc2_force_mode(hsotg, false);
gnptxfsiz = dwc2_readl(hsotg->regs + GNPTXFSIZ); gnptxfsiz = dwc2_readl(hsotg, GNPTXFSIZ);
fifo_count = dwc2_hsotg_tx_fifo_count(hsotg); fifo_count = dwc2_hsotg_tx_fifo_count(hsotg);
for (fifo = 1; fifo <= fifo_count; fifo++) { for (fifo = 1; fifo <= fifo_count; fifo++) {
hw->g_tx_fifo_size[fifo] = hw->g_tx_fifo_size[fifo] =
(dwc2_readl(hsotg->regs + DPTXFSIZN(fifo)) & (dwc2_readl(hsotg, DPTXFSIZN(fifo)) &
FIFOSIZE_DEPTH_MASK) >> FIFOSIZE_DEPTH_SHIFT; FIFOSIZE_DEPTH_MASK) >> FIFOSIZE_DEPTH_SHIFT;
} }
@ -713,7 +709,7 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
* 0x45f4xxxx, 0x5531xxxx or 0x5532xxxx * 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 && if ((hw->snpsid & GSNPSID_ID_MASK) != DWC2_OTG_ID &&
(hw->snpsid & GSNPSID_ID_MASK) != DWC2_FS_IOT_ID && (hw->snpsid & GSNPSID_ID_MASK) != DWC2_FS_IOT_ID &&
(hw->snpsid & GSNPSID_ID_MASK) != DWC2_HS_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 >> 12 & 0xf, hw->snpsid >> 8 & 0xf,
hw->snpsid >> 4 & 0xf, hw->snpsid & 0xf, hw->snpsid); hw->snpsid >> 4 & 0xf, hw->snpsid & 0xf, hw->snpsid);
hwcfg1 = dwc2_readl(hsotg->regs + GHWCFG1); hwcfg1 = dwc2_readl(hsotg, GHWCFG1);
hwcfg2 = dwc2_readl(hsotg->regs + GHWCFG2); hwcfg2 = dwc2_readl(hsotg, GHWCFG2);
hwcfg3 = dwc2_readl(hsotg->regs + GHWCFG3); hwcfg3 = dwc2_readl(hsotg, GHWCFG3);
hwcfg4 = dwc2_readl(hsotg->regs + GHWCFG4); hwcfg4 = dwc2_readl(hsotg, GHWCFG4);
grxfsiz = dwc2_readl(hsotg->regs + GRXFSIZ); grxfsiz = dwc2_readl(hsotg, GRXFSIZ);
/* hwcfg1 */ /* hwcfg1 */
hw->dev_ep_dirs = hwcfg1; hw->dev_ep_dirs = hwcfg1;

View file

@ -352,6 +352,23 @@ static void dwc2_driver_shutdown(struct platform_device *dev)
disable_irq(hsotg->irq); disable_irq(hsotg->irq);
} }
/**
* 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 * dwc2_driver_probe() - Called when the DWC_otg core is bound to the DWC_otg
* driver * 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", dev_dbg(&dev->dev, "mapped PA %08lx to VA %p\n",
(unsigned long)res->start, hsotg->regs); (unsigned long)res->start, hsotg->regs);
hsotg->needs_byte_swap = dwc2_check_core_endianness(hsotg);
retval = dwc2_lowlevel_hw_init(hsotg); retval = dwc2_lowlevel_hw_init(hsotg);
if (retval) if (retval)
return retval; return retval;

View file

@ -74,11 +74,16 @@ config USB_DWC3_PCI
depends on USB_PCI && ACPI depends on USB_PCI && ACPI
default USB_DWC3 default USB_DWC3
help help
If you're using the DesignWare Core IP with a PCIe, please say If you're using the DesignWare Core IP with a PCIe (but not HAPS
'Y' or 'M' here. platform), please say 'Y' or 'M' here.
One such PCIe-based platform is Synopsys' PCIe HAPS model of config USB_DWC3_HAPS
this IP. 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 config USB_DWC3_KEYSTONE
tristate "Texas Instruments Keystone2 Platforms" tristate "Texas Instruments Keystone2 Platforms"

View file

@ -45,6 +45,7 @@ endif
obj-$(CONFIG_USB_DWC3_OMAP) += dwc3-omap.o obj-$(CONFIG_USB_DWC3_OMAP) += dwc3-omap.o
obj-$(CONFIG_USB_DWC3_EXYNOS) += dwc3-exynos.o obj-$(CONFIG_USB_DWC3_EXYNOS) += dwc3-exynos.o
obj-$(CONFIG_USB_DWC3_PCI) += dwc3-pci.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_KEYSTONE) += dwc3-keystone.o
obj-$(CONFIG_USB_DWC3_OF_SIMPLE) += dwc3-of-simple.o obj-$(CONFIG_USB_DWC3_OF_SIMPLE) += dwc3-of-simple.o
obj-$(CONFIG_USB_DWC3_ST) += dwc3-st.o obj-$(CONFIG_USB_DWC3_ST) += dwc3-st.o

View file

@ -78,6 +78,14 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc)
mode = USB_DR_MODE_HOST; mode = USB_DR_MODE_HOST;
else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET)) else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
mode = USB_DR_MODE_PERIPHERAL; 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) { 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_get_phy(struct dwc3 *dwc);
static int dwc3_core_ulpi_init(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 * dwc3_core_init - Low-level initialization of DWC3 Core
* @dwc: Pointer to our controller context structure * @dwc: Pointer to our controller context structure
@ -840,6 +940,8 @@ static int dwc3_core_init(struct dwc3 *dwc)
/* Adjust Frame Length */ /* Adjust Frame Length */
dwc3_frame_length_adjustment(dwc); dwc3_frame_length_adjustment(dwc);
dwc3_set_incr_burst_type(dwc);
usb_phy_set_suspend(dwc->usb2_phy, 0); usb_phy_set_suspend(dwc->usb2_phy, 0);
usb_phy_set_suspend(dwc->usb3_phy, 0); usb_phy_set_suspend(dwc->usb3_phy, 0);
ret = phy_power_on(dwc->usb2_generic_phy); 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); 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 * Must config both number of packets and max burst settings to enable
* RX and/or TX threshold. * RX and/or TX threshold.

View file

@ -163,6 +163,17 @@
/* Bit fields */ /* 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 */ /* Global Debug Queue/FIFO Space Available Register */
#define DWC3_GDBGFIFOSPACE_NUM(n) ((n) & 0x1f) #define DWC3_GDBGFIFOSPACE_NUM(n) ((n) & 0x1f)
#define DWC3_GDBGFIFOSPACE_TYPE(n) (((n) << 5) & 0x1e0) #define DWC3_GDBGFIFOSPACE_TYPE(n) (((n) << 5) & 0x1e0)
@ -227,6 +238,9 @@
#define DWC3_GCTL_GBLHIBERNATIONEN BIT(1) #define DWC3_GCTL_GBLHIBERNATIONEN BIT(1)
#define DWC3_GCTL_DSBLCLKGTNG BIT(0) #define DWC3_GCTL_DSBLCLKGTNG BIT(0)
/* Global User Control Register */
#define DWC3_GUCTL_HSTINAUTORETRY BIT(14)
/* Global User Control 1 Register */ /* Global User Control 1 Register */
#define DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS BIT(28) #define DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS BIT(28)
#define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW BIT(24) #define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW BIT(24)
@ -1157,6 +1171,9 @@ struct dwc3 {
u16 imod_interval; 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)) #define work_to_dwc(w) (container_of((w), struct dwc3, drd_work))
/* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */

View file

@ -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);

View file

@ -28,6 +28,7 @@ struct dwc3_of_simple {
int num_clocks; int num_clocks;
struct reset_control *resets; struct reset_control *resets;
bool pulse_resets; bool pulse_resets;
bool need_reset;
}; };
static int dwc3_of_simple_clk_init(struct dwc3_of_simple *simple, int count) 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); platform_set_drvdata(pdev, simple);
simple->dev = dev; 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") || if (of_device_is_compatible(np, "amlogic,meson-axg-dwc3") ||
of_device_is_compatible(np, "amlogic,meson-gxl-dwc3")) { of_device_is_compatible(np, "amlogic,meson-gxl-dwc3")) {
shared_resets = true; shared_resets = true;
@ -201,9 +209,30 @@ static int dwc3_of_simple_runtime_resume(struct device *dev)
return 0; 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 #endif
static const struct dev_pm_ops dwc3_of_simple_dev_pm_ops = { 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, SET_RUNTIME_PM_OPS(dwc3_of_simple_runtime_suspend,
dwc3_of_simple_runtime_resume, NULL) dwc3_of_simple_runtime_resume, NULL)
}; };

View file

@ -16,12 +16,10 @@
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
#include <linux/gpio/machine.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/delay.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_BYT 0x0f37
#define PCI_DEVICE_ID_INTEL_MRFLD 0x119e #define PCI_DEVICE_ID_INTEL_MRFLD 0x119e
#define PCI_DEVICE_ID_INTEL_BSW 0x22b7 #define PCI_DEVICE_ID_INTEL_BSW 0x22b7
@ -41,12 +39,17 @@
#define PCI_INTEL_BXT_STATE_D0 0 #define PCI_INTEL_BXT_STATE_D0 0
#define PCI_INTEL_BXT_STATE_D3 3 #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 * struct dwc3_pci - Driver private structure
* @dwc3: child dwc3 platform_device * @dwc3: child dwc3 platform_device
* @pci: our link to PCI bus * @pci: our link to PCI bus
* @guid: _DSM GUID * @guid: _DSM GUID
* @has_dsm_for_pm: true for devices which need to run _DSM on runtime PM * @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 dwc3_pci {
struct platform_device *dwc3; struct platform_device *dwc3;
@ -67,52 +70,74 @@ static const struct acpi_gpio_mapping acpi_dwc3_byt_gpios[] = {
{ }, { },
}; };
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)
{
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;
}
static const struct property_entry dwc3_pci_intel_properties[] = {
PROPERTY_ENTRY_STRING("dr_mode", "peripheral"),
PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
{}
};
static const struct property_entry dwc3_pci_mrfld_properties[] = {
PROPERTY_ENTRY_STRING("dr_mode", "otg"),
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"),
{}
};
static int dwc3_pci_quirks(struct dwc3_pci *dwc) static int dwc3_pci_quirks(struct dwc3_pci *dwc)
{ {
struct platform_device *dwc3 = dwc->dwc3;
struct pci_dev *pdev = dwc->pci; struct pci_dev *pdev = dwc->pci;
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);
}
if (pdev->vendor == PCI_VENDOR_ID_INTEL) { if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
int ret;
struct property_entry properties[] = {
PROPERTY_ENTRY_STRING("dr_mode", "peripheral"),
PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
{ }
};
ret = platform_device_add_properties(dwc3, properties);
if (ret < 0)
return ret;
if (pdev->device == PCI_DEVICE_ID_INTEL_BXT || if (pdev->device == PCI_DEVICE_ID_INTEL_BXT ||
pdev->device == PCI_DEVICE_ID_INTEL_BXT_M) { pdev->device == PCI_DEVICE_ID_INTEL_BXT_M) {
guid_parse(PCI_INTEL_BXT_DSM_GUID, &dwc->guid); guid_parse(PCI_INTEL_BXT_DSM_GUID, &dwc->guid);
@ -121,51 +146,49 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc)
if (pdev->device == PCI_DEVICE_ID_INTEL_BYT) { if (pdev->device == PCI_DEVICE_ID_INTEL_BYT) {
struct gpio_desc *gpio; 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, ret = devm_acpi_dev_add_driver_gpios(&pdev->dev,
acpi_dwc3_byt_gpios); acpi_dwc3_byt_gpios);
if (ret) if (ret)
dev_dbg(&pdev->dev, "failed to add mapping table\n"); 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 * These GPIOs will turn on the USB2 PHY. Note that we have to
* put the gpio descriptors again here because the phy driver * put the gpio descriptors again here because the phy driver
* might want to grab them, too. * 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)) if (IS_ERR(gpio))
return PTR_ERR(gpio); return PTR_ERR(gpio);
gpiod_set_value_cansleep(gpio, 1); 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)) if (IS_ERR(gpio))
return PTR_ERR(gpio); return PTR_ERR(gpio);
if (gpio) { if (gpio) {
gpiod_set_value_cansleep(gpio, 1); gpiod_set_value_cansleep(gpio, 1);
gpiod_put(gpio);
usleep_range(10000, 11000); 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; return 0;
} }
@ -185,9 +208,9 @@ static void dwc3_pci_resume_work(struct work_struct *work)
} }
#endif #endif
static int dwc3_pci_probe(struct pci_dev *pci, static int dwc3_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
const struct pci_device_id *id)
{ {
struct property_entry *p = (struct property_entry *)id->driver_data;
struct dwc3_pci *dwc; struct dwc3_pci *dwc;
struct resource res[2]; struct resource res[2];
int ret; int ret;
@ -230,6 +253,10 @@ static int dwc3_pci_probe(struct pci_dev *pci,
dwc->dwc3->dev.parent = dev; dwc->dwc3->dev.parent = dev;
ACPI_COMPANION_SET(&dwc->dwc3->dev, ACPI_COMPANION(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); ret = dwc3_pci_quirks(dwc);
if (ret) if (ret)
goto err; goto err;
@ -257,6 +284,7 @@ static void dwc3_pci_remove(struct pci_dev *pci)
{ {
struct dwc3_pci *dwc = pci_get_drvdata(pci); struct dwc3_pci *dwc = pci_get_drvdata(pci);
gpiod_remove_lookup_table(&platform_bytcr_gpios);
#ifdef CONFIG_PM #ifdef CONFIG_PM
cancel_work_sync(&dwc->wakeup_work); cancel_work_sync(&dwc->wakeup_work);
#endif #endif
@ -266,32 +294,47 @@ static void dwc3_pci_remove(struct pci_dev *pci)
} }
static const struct pci_device_id dwc3_pci_id_table[] = { static const struct pci_device_id dwc3_pci_id_table[] = {
{ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BSW),
PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, (kernel_ulong_t) &dwc3_pci_intel_properties },
PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),
}, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BYT),
{ (kernel_ulong_t) &dwc3_pci_intel_properties, },
PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI), { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MRFLD),
}, (kernel_ulong_t) &dwc3_pci_mrfld_properties, },
{
PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SPTLP),
PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31), (kernel_ulong_t) &dwc3_pci_intel_properties, },
},
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW), }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SPTH),
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), }, (kernel_ulong_t) &dwc3_pci_intel_properties, },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTLP), }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BXT),
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTH), }, (kernel_ulong_t) &dwc3_pci_intel_properties, },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT), },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT_M), }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BXT_M),
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_APL), }, (kernel_ulong_t) &dwc3_pci_intel_properties, },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KBP), },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GLK), }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_APL),
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CNPLP), }, (kernel_ulong_t) &dwc3_pci_intel_properties, },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CNPH), },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICLLP), }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_KBP),
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB), }, (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 */ { } /* Terminating Entry */
}; };
MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table); MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);

View file

@ -1121,7 +1121,7 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
req->request.short_not_ok, req->request.short_not_ok,
req->request.no_interrupt); req->request.no_interrupt);
} else if (req->request.zero && req->request.length && } 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 *dwc = dep->dwc;
struct dwc3_trb *trb; struct dwc3_trb *trb;

View file

@ -25,7 +25,7 @@ struct dwc3;
#define DWC3_DEPCFG_XFER_IN_PROGRESS_EN BIT(9) #define DWC3_DEPCFG_XFER_IN_PROGRESS_EN BIT(9)
#define DWC3_DEPCFG_XFER_NOT_READY_EN BIT(10) #define DWC3_DEPCFG_XFER_NOT_READY_EN BIT(10)
#define DWC3_DEPCFG_FIFO_ERROR_EN BIT(11) #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_BINTERVAL_M1(n) (((n) & 0xff) << 16)
#define DWC3_DEPCFG_STREAM_CAPABLE BIT(24) #define DWC3_DEPCFG_STREAM_CAPABLE BIT(24)
#define DWC3_DEPCFG_EP_NUMBER(n) (((n) & 0x1f) << 25) #define DWC3_DEPCFG_EP_NUMBER(n) (((n) & 0x1f) << 25)

View file

@ -1217,8 +1217,8 @@ static void purge_configs_funcs(struct gadget_info *gi)
list_move_tail(&f->list, &cfg->func_list); list_move_tail(&f->list, &cfg->func_list);
if (f->unbind) { if (f->unbind) {
dev_dbg(&gi->cdev.gadget->dev, dev_dbg(&gi->cdev.gadget->dev,
"unbind function '%s'/%p\n", "unbind function '%s'/%p\n",
f->name, f); f->name, f);
f->unbind(c, f); f->unbind(c, f);
} }
} }

View file

@ -206,7 +206,6 @@
#include <linux/fcntl.h> #include <linux/fcntl.h>
#include <linux/file.h> #include <linux/file.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/kref.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/sched/signal.h> #include <linux/sched/signal.h>
#include <linux/limits.h> #include <linux/limits.h>
@ -312,8 +311,6 @@ struct fsg_common {
void *private_data; void *private_data;
char inquiry_string[INQUIRY_STRING_LEN]; char inquiry_string[INQUIRY_STRING_LEN];
struct kref ref;
}; };
struct fsg_dev { struct fsg_dev {
@ -2551,25 +2548,11 @@ static DEVICE_ATTR(file, 0, file_show, file_store);
/****************************** FSG COMMON ******************************/ /****************************** FSG COMMON ******************************/
static void fsg_common_release(struct kref *ref);
static void fsg_lun_release(struct device *dev) static void fsg_lun_release(struct device *dev)
{ {
/* Nothing needs to be done */ /* 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) static struct fsg_common *fsg_common_setup(struct fsg_common *common)
{ {
if (!common) { if (!common) {
@ -2582,7 +2565,6 @@ static struct fsg_common *fsg_common_setup(struct fsg_common *common)
} }
init_rwsem(&common->filesem); init_rwsem(&common->filesem);
spin_lock_init(&common->lock); spin_lock_init(&common->lock);
kref_init(&common->ref);
init_completion(&common->thread_notifier); init_completion(&common->thread_notifier);
init_waitqueue_head(&common->io_wait); init_waitqueue_head(&common->io_wait);
init_waitqueue_head(&common->fsg_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); 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; int i;
/* If the thread isn't already dead, tell it to exit now */ /* 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) if (ret)
goto end; 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; ret = len;
end: end:
@ -3344,7 +3327,7 @@ static void fsg_free_inst(struct usb_function_instance *fi)
struct fsg_opts *opts; struct fsg_opts *opts;
opts = fsg_opts_from_func_inst(fi); opts = fsg_opts_from_func_inst(fi);
fsg_common_put(opts->common); fsg_common_release(opts->common);
kfree(opts); kfree(opts);
} }
@ -3368,7 +3351,7 @@ static struct usb_function_instance *fsg_alloc_inst(void)
rc = fsg_common_set_num_buffers(opts->common, rc = fsg_common_set_num_buffers(opts->common,
CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS); CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS);
if (rc) if (rc)
goto release_opts; goto release_common;
pr_info(FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n"); 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: release_buffers:
fsg_common_free_buffers(opts->common); fsg_common_free_buffers(opts->common);
release_common:
kfree(opts->common);
release_opts: release_opts:
kfree(opts); kfree(opts);
return ERR_PTR(rc); return ERR_PTR(rc);

View 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); 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); void fsg_common_set_sysfs(struct fsg_common *common, bool sysfs);
int fsg_common_set_num_buffers(struct fsg_common *common, unsigned int n); int fsg_common_set_num_buffers(struct fsg_common *common, unsigned int n);

View file

@ -6,16 +6,17 @@
* Laurent Pinchart (laurent.pinchart@ideasonboard.com) * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*/ */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/module.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/usb/ch9.h> #include <linux/usb/ch9.h>
#include <linux/usb/gadget.h> #include <linux/usb/gadget.h>
#include <linux/usb/g_uvc.h>
#include <linux/usb/video.h> #include <linux/usb/video.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/wait.h> #include <linux/wait.h>
@ -30,6 +31,8 @@
#include "uvc_video.h" #include "uvc_video.h"
unsigned int uvc_gadget_trace_param; 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 * Function descriptors
@ -410,10 +413,21 @@ uvc_function_disconnect(struct uvc_device *uvc)
* USB probe and disconnect * 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 static int
uvc_register_video(struct uvc_device *uvc) uvc_register_video(struct uvc_device *uvc)
{ {
struct usb_composite_dev *cdev = uvc->func.config->cdev; struct usb_composite_dev *cdev = uvc->func.config->cdev;
int ret;
/* TODO reference counting. */ /* TODO reference counting. */
uvc->vdev.v4l2_dev = &uvc->v4l2_dev; uvc->vdev.v4l2_dev = &uvc->v4l2_dev;
@ -426,7 +440,17 @@ uvc_register_video(struct uvc_device *uvc)
video_set_drvdata(&uvc->vdev, 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) \ #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__); INFO(cdev, "%s\n", __func__);
device_remove_file(&uvc->vdev.dev, &dev_attr_function_name);
video_unregister_device(&uvc->vdev); video_unregister_device(&uvc->vdev);
v4l2_device_unregister(&uvc->v4l2_dev); v4l2_device_unregister(&uvc->v4l2_dev);

View file

@ -9,10 +9,7 @@
#ifndef _F_UVC_H_ #ifndef _F_UVC_H_
#define _F_UVC_H_ #define _F_UVC_H_
#include <linux/usb/composite.h> struct uvc_device;
#include <linux/usb/video.h>
#include "uvc.h"
void uvc_function_setup_continue(struct uvc_device *uvc); 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); void uvc_function_disconnect(struct uvc_device *uvc);
#endif /* _F_UVC_H_ */ #endif /* _F_UVC_H_ */

View file

@ -13,6 +13,7 @@
#ifndef U_UVC_H #ifndef U_UVC_H
#define U_UVC_H #define U_UVC_H
#include <linux/mutex.h>
#include <linux/usb/composite.h> #include <linux/usb/composite.h>
#include <linux/usb/video.h> #include <linux/usb/video.h>
@ -20,7 +21,6 @@
struct f_uvc_opts { struct f_uvc_opts {
struct usb_function_instance func_inst; struct usb_function_instance func_inst;
unsigned int uvc_gadget_trace_param;
unsigned int streaming_interval; unsigned int streaming_interval;
unsigned int streaming_maxpacket; unsigned int streaming_maxpacket;
unsigned int streaming_maxburst; unsigned int streaming_maxburst;
@ -80,7 +80,4 @@ struct f_uvc_opts {
int refcnt; int refcnt;
}; };
void uvc_set_trace_param(unsigned int trace);
#endif /* U_UVC_H */ #endif /* U_UVC_H */

View file

@ -9,52 +9,26 @@
#ifndef _UVC_GADGET_H_ #ifndef _UVC_GADGET_H_
#define _UVC_GADGET_H_ #define _UVC_GADGET_H_
#include <linux/ioctl.h> #include <linux/list.h>
#include <linux/types.h> #include <linux/mutex.h>
#include <linux/usb/ch9.h> #include <linux/spinlock.h>
#include <linux/usb/composite.h>
#include <linux/videodev2.h>
#define UVC_EVENT_FIRST (V4L2_EVENT_PRIVATE_START + 0) #include <media/v4l2-device.h>
#define UVC_EVENT_CONNECT (V4L2_EVENT_PRIVATE_START + 0) #include <media/v4l2-dev.h>
#define UVC_EVENT_DISCONNECT (V4L2_EVENT_PRIVATE_START + 1) #include <media/v4l2-fh.h>
#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 { #include "uvc_queue.h"
__s32 length;
__u8 data[60];
};
struct uvc_event { struct usb_ep;
union { struct usb_request;
enum usb_device_speed speed; struct uvc_descriptor_header;
struct usb_ctrlrequest req;
struct uvc_request_data data;
};
};
#define UVCIOC_SEND_RESPONSE _IOW('U', 1, struct uvc_request_data)
#define UVC_INTF_CONTROL 0
#define UVC_INTF_STREAMING 1
/* ------------------------------------------------------------------------ /* ------------------------------------------------------------------------
* Debugging, printing and logging * 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_PROBE (1 << 0)
#define UVC_TRACE_DESCR (1 << 1) #define UVC_TRACE_DESCR (1 << 1)
#define UVC_TRACE_CONTROL (1 << 2) #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_connect(struct uvc_device *uvc);
extern void uvc_function_disconnect(struct uvc_device *uvc); extern void uvc_function_disconnect(struct uvc_device *uvc);
#endif /* __KERNEL__ */
#endif /* _UVC_GADGET_H_ */ #endif /* _UVC_GADGET_H_ */

View file

@ -31,7 +31,11 @@ static struct configfs_attribute prefix##attr_##cname = { \
.show = prefix##cname##_show, \ .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> */ /* control/header/<NAME> */
DECLARE_UVC_HEADER_DESCRIPTOR(1); DECLARE_UVC_HEADER_DESCRIPTOR(1);
@ -2105,12 +2109,6 @@ static const struct config_item_type uvcg_streaming_grp_type = {
.ct_owner = THIS_MODULE, .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) static void uvc_attr_release(struct config_item *item)
{ {
struct f_uvc_opts *opts = to_f_uvc_opts(item); struct f_uvc_opts *opts = to_f_uvc_opts(item);

View file

@ -2,13 +2,15 @@
#ifndef _UVC_QUEUE_H_ #ifndef _UVC_QUEUE_H_
#define _UVC_QUEUE_H_ #define _UVC_QUEUE_H_
#ifdef __KERNEL__ #include <linux/list.h>
#include <linux/kernel.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/videodev2.h> #include <linux/spinlock.h>
#include <media/videobuf2-v4l2.h> #include <media/videobuf2-v4l2.h>
struct file;
struct mutex;
/* Maximum frame size in bytes, for sanity checking. */ /* Maximum frame size in bytes, for sanity checking. */
#define UVC_MAX_FRAME_SIZE (16*1024*1024) #define UVC_MAX_FRAME_SIZE (16*1024*1024)
/* Maximum number of video buffers. */ /* 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); struct uvc_buffer *uvcg_queue_head(struct uvc_video_queue *queue);
#endif /* __KERNEL__ */
#endif /* _UVC_QUEUE_H_ */ #endif /* _UVC_QUEUE_H_ */

View file

@ -6,10 +6,11 @@
* Laurent Pinchart (laurent.pinchart@ideasonboard.com) * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
*/ */
#include <linux/kernel.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/usb/g_uvc.h>
#include <linux/videodev2.h> #include <linux/videodev2.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/wait.h> #include <linux/wait.h>

View file

@ -12,6 +12,8 @@
#ifndef __UVC_VIDEO_H__ #ifndef __UVC_VIDEO_H__
#define __UVC_VIDEO_H__ #define __UVC_VIDEO_H__
struct uvc_video;
int uvcg_video_pump(struct uvc_video *video); int uvcg_video_pump(struct uvc_video *video);
int uvcg_video_enable(struct uvc_video *video, int enable); int uvcg_video_enable(struct uvc_video *video, int enable);

View file

@ -41,7 +41,7 @@ static struct usb_device_descriptor usbg_device_desc = {
#define USB_G_STR_CONFIG USB_GADGET_FIRST_AVAIL_IDX #define USB_G_STR_CONFIG USB_GADGET_FIRST_AVAIL_IDX
static struct usb_string usbg_us_strings[] = { 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_PRODUCT_IDX].s = "Target Product",
[USB_GADGET_SERIAL_IDX].s = "000000000001", [USB_GADGET_SERIAL_IDX].s = "000000000001",
[USB_G_STR_CONFIG].s = "default config", [USB_G_STR_CONFIG].s = "default config",

View file

@ -30,9 +30,6 @@ static unsigned int streaming_maxburst;
module_param(streaming_maxburst, uint, S_IRUGO|S_IWUSR); module_param(streaming_maxburst, uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(streaming_maxburst, "0 - 15 (ss only)"); 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 * Device descriptor
*/ */
@ -379,7 +376,6 @@ webcam_bind(struct usb_composite_dev *cdev)
uvc_opts->streaming_interval = streaming_interval; uvc_opts->streaming_interval = streaming_interval;
uvc_opts->streaming_maxpacket = streaming_maxpacket; uvc_opts->streaming_maxpacket = streaming_maxpacket;
uvc_opts->streaming_maxburst = streaming_maxburst; uvc_opts->streaming_maxburst = streaming_maxburst;
uvc_set_trace_param(trace);
uvc_opts->fs_control = uvc_fs_control_cls; uvc_opts->fs_control = uvc_fs_control_cls;
uvc_opts->ss_control = uvc_ss_control_cls; uvc_opts->ss_control = uvc_ss_control_cls;

View file

@ -193,6 +193,7 @@ config USB_RENESAS_USB3
tristate 'Renesas USB3.0 Peripheral controller' tristate 'Renesas USB3.0 Peripheral controller'
depends on ARCH_RENESAS || COMPILE_TEST depends on ARCH_RENESAS || COMPILE_TEST
depends on EXTCON depends on EXTCON
select USB_ROLE_SWITCH
help help
Renesas USB3.0 Peripheral controller is a USB peripheral controller Renesas USB3.0 Peripheral controller is a USB peripheral controller
that supports super, high, and full speed USB 3.0 data transfers. that supports super, high, and full speed USB 3.0 data transfers.

View file

@ -87,6 +87,8 @@ EXPORT_SYMBOL_GPL(usb_ep_set_maxpacket_limit);
* configurable, with more generic names like "ep-a". (remember that for * configurable, with more generic names like "ep-a". (remember that for
* USB, "in" means "towards the USB master".) * USB, "in" means "towards the USB master".)
* *
* This routine must be called in process context.
*
* returns zero, or a negative error code. * returns zero, or a negative error code.
*/ */
int usb_ep_enable(struct usb_ep *ep) 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 * gadget drivers must call usb_ep_enable() again before queueing
* requests to the endpoint. * requests to the endpoint.
* *
* This routine must be called in process context.
*
* returns zero, or a negative error code. * returns zero, or a negative error code.
*/ */
int usb_ep_disable(struct usb_ep *ep) 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 * Note that @req's ->complete() callback must never be called from
* within usb_ep_queue() as that can create deadlock situations. * 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 * Returns zero, or a negative error code. Endpoints that are not enabled
* report errors; errors will also be * report errors; errors will also be
* reported when the usb peripheral is disconnected. * 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 * at the head of the queue) except as part of disconnecting from usb. Such
* restrictions prevent drivers from supporting configuration changes, * restrictions prevent drivers from supporting configuration changes,
* even to configuration zero (a "chapter 9" requirement). * 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) 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, * 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. * 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 * Returns zero, or a negative error code. On success, this call sets
* underlying hardware state that blocks data transfers. * underlying hardware state that blocks data transfers.
* Attempts to halt IN endpoints will fail (returning -EAGAIN) if any * 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 * for endpoints that aren't reconfigured, after clearing any other state
* in the endpoint's i/o queue. * 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 * Returns zero, or a negative error code. On success, this call clears
* the underlying hardware state reflecting endpoint halt and data toggle. * the underlying hardware state reflecting endpoint halt and data toggle.
* Note that some hardware can't support this request (like pxa2xx_udc), * 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 * requests. If the gadget driver clears the halt status, it will
* automatically unwedge the endpoint. * automatically unwedge the endpoint.
* *
* This routine may be called in interrupt context.
*
* Returns zero on success, else negative errno. * Returns zero on success, else negative errno.
*/ */
int usb_ep_set_wedge(struct usb_ep *ep) 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 * written OUT to it by the host. Drivers that need precise handling for
* fault reporting or recovery may need to use this call. * 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 * 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 * errno if the endpoint doesn't use a FIFO or doesn't support such
* precise handling. * precise handling.
@ -415,6 +431,8 @@ EXPORT_SYMBOL_GPL(usb_ep_fifo_status);
* an endpoint fifo after abnormal transaction terminations. The call * an endpoint fifo after abnormal transaction terminations. The call
* must never be used except when endpoint is not being used for any * must never be used except when endpoint is not being used for any
* protocol translation. * protocol translation.
*
* This routine may be called in interrupt context.
*/ */
void usb_ep_fifo_flush(struct usb_ep *ep) void usb_ep_fifo_flush(struct usb_ep *ep)
{ {

View file

@ -23,6 +23,8 @@
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/usb/ch9.h> #include <linux/usb/ch9.h>
#include <linux/usb/gadget.h> #include <linux/usb/gadget.h>
#include <linux/usb/of.h>
#include <linux/usb/role.h>
/* register definitions */ /* register definitions */
#define USB3_AXI_INT_STA 0x008 #define USB3_AXI_INT_STA 0x008
@ -335,6 +337,11 @@ struct renesas_usb3 {
struct phy *phy; struct phy *phy;
struct dentry *dentry; 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; struct renesas_usb3_ep *usb3_ep;
int num_usb3_eps; 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) static void usb3_set_mode(struct renesas_usb3 *usb3, bool host)
{ {
if (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); 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) static void usb3_vbus_out(struct renesas_usb3 *usb3, bool enable)
{ {
if (enable) if (enable)
@ -672,7 +697,7 @@ static void usb3_mode_config(struct renesas_usb3 *usb3, bool host, bool a_dev)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&usb3->lock, 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); usb3_vbus_out(usb3, a_dev);
/* for A-Peripheral or forced B-device mode */ /* for A-Peripheral or forced B-device mode */
if ((!host && a_dev) || if ((!host && a_dev) ||
@ -2302,6 +2327,41 @@ static const struct usb_gadget_ops renesas_usb3_gadget_ops = {
.set_selfpowered = renesas_usb3_set_selfpowered, .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, static ssize_t role_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
@ -2405,6 +2465,8 @@ static int renesas_usb3_remove(struct platform_device *pdev)
debugfs_remove_recursive(usb3->dentry); debugfs_remove_recursive(usb3->dentry);
device_remove_file(&pdev->dev, &dev_attr_role); device_remove_file(&pdev->dev, &dev_attr_role);
usb_role_switch_unregister(usb3->role_sw);
usb_del_gadget_udc(&usb3->gadget); usb_del_gadget_udc(&usb3->gadget);
renesas_usb3_dma_free_prd(usb3, &pdev->dev); renesas_usb3_dma_free_prd(usb3, &pdev->dev);
@ -2562,6 +2624,12 @@ static const unsigned int renesas_usb3_cable[] = {
EXTCON_NONE, 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) static int renesas_usb3_probe(struct platform_device *pdev)
{ {
struct renesas_usb3 *usb3; struct renesas_usb3 *usb3;
@ -2647,6 +2715,20 @@ static int renesas_usb3_probe(struct platform_device *pdev)
if (ret < 0) if (ret < 0)
goto err_dev_create; 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; usb3->workaround_for_vbus = priv->workaround_for_vbus;
renesas_usb3_debugfs_init(usb3, &pdev->dev); renesas_usb3_debugfs_init(usb3, &pdev->dev);

View file

@ -192,6 +192,14 @@ config USB_EHCI_MXC
---help--- ---help---
Variation of ARC USB block used in some Freescale chips. 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 config USB_EHCI_HCD_OMAP
tristate "EHCI support for OMAP3 and later chips" tristate "EHCI support for OMAP3 and later chips"
depends on ARCH_OMAP depends on ARCH_OMAP

View 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_PCI) += ehci-pci.o
obj-$(CONFIG_USB_EHCI_HCD_PLATFORM) += ehci-platform.o obj-$(CONFIG_USB_EHCI_HCD_PLATFORM) += ehci-platform.o
obj-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.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_OMAP) += ehci-omap.o
obj-$(CONFIG_USB_EHCI_HCD_ORION) += ehci-orion.o obj-$(CONFIG_USB_EHCI_HCD_ORION) += ehci-orion.o
obj-$(CONFIG_USB_EHCI_HCD_SPEAR) += ehci-spear.o obj-$(CONFIG_USB_EHCI_HCD_SPEAR) += ehci-spear.o

View file

@ -1226,6 +1226,7 @@ static const struct hc_driver ehci_hc_driver = {
.bus_resume = ehci_bus_resume, .bus_resume = ehci_bus_resume,
.relinquish_port = ehci_relinquish_port, .relinquish_port = ehci_relinquish_port,
.port_handed_over = ehci_port_handed_over, .port_handed_over = ehci_port_handed_over,
.get_resuming_ports = ehci_get_resuming_ports,
/* /*
* device support * device support

View file

@ -512,10 +512,18 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
return -ESHUTDOWN; 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 #else
#define ehci_bus_suspend NULL #define ehci_bus_suspend NULL
#define ehci_bus_resume NULL #define ehci_bus_resume NULL
#define ehci_get_resuming_ports NULL
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */

View file

@ -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");

View file

@ -1835,7 +1835,6 @@ static bool itd_complete(struct ehci_hcd *ehci, struct ehci_itd *itd)
unsigned uframe; unsigned uframe;
int urb_index = -1; int urb_index = -1;
struct ehci_iso_stream *stream = itd->stream; struct ehci_iso_stream *stream = itd->stream;
struct usb_device *dev;
bool retval = false; bool retval = false;
/* for each uframe with a packet */ /* 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 */ /* give urb back to the driver; completion often (re)submits */
dev = urb->dev;
ehci_urb_done(ehci, urb, 0); ehci_urb_done(ehci, urb, 0);
retval = true; retval = true;
urb = NULL; urb = NULL;
@ -2230,7 +2228,6 @@ static bool sitd_complete(struct ehci_hcd *ehci, struct ehci_sitd *sitd)
u32 t; u32 t;
int urb_index; int urb_index;
struct ehci_iso_stream *stream = sitd->stream; struct ehci_iso_stream *stream = sitd->stream;
struct usb_device *dev;
bool retval = false; bool retval = false;
urb_index = sitd->index; 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 */ /* give urb back to the driver; completion often (re)submits */
dev = urb->dev;
ehci_urb_done(ehci, urb, 0); ehci_urb_done(ehci, urb, 0);
retval = true; retval = true;
urb = NULL; urb = NULL;

View file

@ -3062,7 +3062,6 @@ static int u132_probe(struct platform_device *pdev)
int retval; int retval;
u32 control; u32 control;
u32 rh_a = -1; u32 rh_a = -1;
u32 num_ports;
msleep(100); msleep(100);
if (u132_exiting > 0) 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); retval = ftdi_read_pcimem(pdev, roothub.a, &rh_a);
if (retval) if (retval)
return retval; return retval;
num_ports = rh_a & RH_A_NDP; /* refuse to confuse usbcore */
if (pdev->dev.dma_mask) if (pdev->dev.dma_mask)
return -EINVAL; return -EINVAL;

View file

@ -96,9 +96,7 @@ static enum whc_update pzl_process_qset(struct whc *whc, struct whc_qset *qset)
while (qset->ntds) { while (qset->ntds) {
struct whc_qtd *td; struct whc_qtd *td;
int t;
t = qset->td_start;
td = &qset->qtd[qset->td_start]; td = &qset->qtd[qset->td_start];
status = le32_to_cpu(td->status); status = le32_to_cpu(td->status);

View file

@ -913,11 +913,9 @@ static ssize_t dbc_store(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct xhci_dbc *dbc;
struct xhci_hcd *xhci; struct xhci_hcd *xhci;
xhci = hcd_to_xhci(dev_get_drvdata(dev)); xhci = hcd_to_xhci(dev_get_drvdata(dev));
dbc = xhci->dbc;
if (!strncmp(buf, "enable", 6)) if (!strncmp(buf, "enable", 6))
xhci_dbc_start(xhci); xhci_dbc_start(xhci);

View file

@ -1684,4 +1684,15 @@ int xhci_bus_resume(struct usb_hcd *hcd)
return 0; 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 */ #endif /* CONFIG_PM */

View 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 = { static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen3 = {
.firmware_name = XHCI_RCAR_FIRMWARE_NAME_V3,
.init_quirk = xhci_rcar_init_quirk, .init_quirk = xhci_rcar_init_quirk,
.plat_start = xhci_rcar_start, .plat_start = xhci_rcar_start,
.resume_quirk = xhci_rcar_resume_quirk, .resume_quirk = xhci_rcar_resume_quirk,

View file

@ -17,9 +17,8 @@
#include "xhci-rcar.h" #include "xhci-rcar.h"
/* /*
* - The V3 firmware is for r8a7796 (with good performance) and r8a7795 es2.0 * - The V3 firmware is for almost all R-Car Gen3 (except r8a7795 ES1.x)
* or later. * - The V2 firmware is for r8a7795 ES1.x.
* - The V2 firmware can be used on both r8a7795 (es1.x) and r8a7796.
* - The V2 firmware is possible to use on R-Car Gen2. However, the V2 causes * - 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 * performance degradation. So, this driver continues to use the V1 if R-Car
* Gen2. * Gen2.
@ -30,6 +29,7 @@ MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V2);
MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V3); MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V3);
/*** Register Offset ***/ /*** Register Offset ***/
#define RCAR_USB3_AXH_STA 0x104 /* AXI Host Control Status */
#define RCAR_USB3_INT_ENA 0x224 /* Interrupt Enable */ #define RCAR_USB3_INT_ENA 0x224 /* Interrupt Enable */
#define RCAR_USB3_DL_CTRL 0x250 /* FW Download Control & Status */ #define RCAR_USB3_DL_CTRL 0x250 /* FW Download Control & Status */
#define RCAR_USB3_FW_DATA0 0x258 /* FW Data0 */ #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 */ #define RCAR_USB3_TX_POL 0xab8 /* USB3.0 TX Polarity */
/*** Register Settings ***/ /*** 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 */ /* Interrupt Enable */
#define RCAR_USB3_INT_XHC_ENA 0x00000001 #define RCAR_USB3_INT_XHC_ENA 0x00000001
#define RCAR_USB3_INT_PME_ENA 0x00000002 #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.*", .soc_id = "r8a7795", .revision = "ES1.*",
.data = (void *)RCAR_XHCI_FIRMWARE_V2, .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 */ }, { /* sentinel */ },
}; };
@ -213,6 +207,22 @@ static int xhci_rcar_download_firmware(struct usb_hcd *hcd)
return retval; 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 */ /* This function needs to initialize a "phy" of usb before */
int xhci_rcar_init_quirk(struct usb_hcd *hcd) 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_rcar_is_gen3(hcd->self.controller))
xhci->quirks |= XHCI_NO_64BIT_SUPPORT; xhci->quirks |= XHCI_NO_64BIT_SUPPORT;
if (!xhci_rcar_wait_for_pll_active(hcd))
return -ETIMEDOUT;
return xhci_rcar_download_firmware(hcd); return xhci_rcar_download_firmware(hcd);
} }

View file

@ -5121,6 +5121,7 @@ static const struct hc_driver xhci_hc_driver = {
.hub_status_data = xhci_hub_status_data, .hub_status_data = xhci_hub_status_data,
.bus_suspend = xhci_bus_suspend, .bus_suspend = xhci_bus_suspend,
.bus_resume = xhci_bus_resume, .bus_resume = xhci_bus_resume,
.get_resuming_ports = xhci_get_resuming_ports,
/* /*
* call back when device connected and addressed * call back when device connected and addressed

View file

@ -2114,9 +2114,11 @@ void xhci_hc_died(struct xhci_hcd *xhci);
#ifdef CONFIG_PM #ifdef CONFIG_PM
int xhci_bus_suspend(struct usb_hcd *hcd); int xhci_bus_suspend(struct usb_hcd *hcd);
int xhci_bus_resume(struct usb_hcd *hcd); int xhci_bus_resume(struct usb_hcd *hcd);
unsigned long xhci_get_resuming_ports(struct usb_hcd *hcd);
#else #else
#define xhci_bus_suspend NULL #define xhci_bus_suspend NULL
#define xhci_bus_resume NULL #define xhci_bus_resume NULL
#define xhci_get_resuming_ports NULL
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
u32 xhci_port_state_to_neutral(u32 state); u32 xhci_port_state_to_neutral(u32 state);

View file

@ -1817,7 +1817,6 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
u32 temp, status; u32 temp, status;
unsigned long flags; unsigned long flags;
int retval = 0; int retval = 0;
unsigned selector;
/* /*
* FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR. * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR.
@ -2010,7 +2009,6 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
} }
break; break;
case SetPortFeature: case SetPortFeature:
selector = wIndex >> 8;
wIndex &= 0xff; wIndex &= 0xff;
if (!wIndex || wIndex > ports) if (!wIndex || wIndex > ports)
goto error; goto error;

View file

@ -155,11 +155,12 @@ static void adu_interrupt_in_callback(struct urb *urb)
{ {
struct adu_device *dev = urb->context; struct adu_device *dev = urb->context;
int status = urb->status; int status = urb->status;
unsigned long flags;
adu_debug_data(&dev->udev->dev, __func__, adu_debug_data(&dev->udev->dev, __func__,
urb->actual_length, urb->transfer_buffer); urb->actual_length, urb->transfer_buffer);
spin_lock(&dev->buflock); spin_lock_irqsave(&dev->buflock, flags);
if (status != 0) { if (status != 0) {
if ((status != -ENOENT) && (status != -ECONNRESET) && if ((status != -ENOENT) && (status != -ECONNRESET) &&
@ -190,7 +191,7 @@ static void adu_interrupt_in_callback(struct urb *urb)
exit: exit:
dev->read_urb_finished = 1; dev->read_urb_finished = 1;
spin_unlock(&dev->buflock); spin_unlock_irqrestore(&dev->buflock, flags);
/* always wake up so we recover from errors */ /* always wake up so we recover from errors */
wake_up_interruptible(&dev->read_wait); 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; struct adu_device *dev = urb->context;
int status = urb->status; int status = urb->status;
unsigned long flags;
adu_debug_data(&dev->udev->dev, __func__, adu_debug_data(&dev->udev->dev, __func__,
urb->actual_length, urb->transfer_buffer); urb->actual_length, urb->transfer_buffer);
@ -213,10 +215,10 @@ static void adu_interrupt_out_callback(struct urb *urb)
return; return;
} }
spin_lock(&dev->buflock); spin_lock_irqsave(&dev->buflock, flags);
dev->out_urb_finished = 1; dev->out_urb_finished = 1;
wake_up(&dev->write_wait); 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) static int adu_open(struct inode *inode, struct file *file)

View file

@ -89,6 +89,7 @@ static void appledisplay_complete(struct urb *urb)
dev_err(dev, dev_err(dev,
"OVERFLOW with data length %d, actual length is %d\n", "OVERFLOW with data length %d, actual length is %d\n",
ACD_URB_BUFFER_LEN, pdata->urb->actual_length); ACD_URB_BUFFER_LEN, pdata->urb->actual_length);
/* fall through */
case -ECONNRESET: case -ECONNRESET:
case -ENOENT: case -ENOENT:
case -ESHUTDOWN: case -ESHUTDOWN:

View file

@ -81,7 +81,6 @@ struct iowarrior {
atomic_t write_busy; /* number of write-urbs submitted */ atomic_t write_busy; /* number of write-urbs submitted */
atomic_t read_idx; atomic_t read_idx;
atomic_t intr_idx; atomic_t intr_idx;
spinlock_t intr_idx_lock; /* protects intr_idx */
atomic_t overflow_flag; /* signals an index 'rollover' */ atomic_t overflow_flag; /* signals an index 'rollover' */
int present; /* this is 1 as long as the device is connected */ int present; /* this is 1 as long as the device is connected */
int opened; /* this is 1 if the device is currently open */ int opened; /* this is 1 if the device is currently open */
@ -166,7 +165,6 @@ static void iowarrior_callback(struct urb *urb)
goto exit; goto exit;
} }
spin_lock(&dev->intr_idx_lock);
intr_idx = atomic_read(&dev->intr_idx); intr_idx = atomic_read(&dev->intr_idx);
/* aux_idx become previous intr_idx */ /* aux_idx become previous intr_idx */
aux_idx = (intr_idx == 0) ? (MAX_INTERRUPT_BUFFER - 1) : (intr_idx - 1); 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->read_queue + offset, urb->transfer_buffer,
dev->report_size)) { dev->report_size)) {
/* equal values on interface 0 will be ignored */ /* equal values on interface 0 will be ignored */
spin_unlock(&dev->intr_idx_lock);
goto exit; goto exit;
} }
} }
@ -202,7 +199,6 @@ static void iowarrior_callback(struct urb *urb)
*(dev->read_queue + offset + (dev->report_size)) = dev->serial_number++; *(dev->read_queue + offset + (dev->report_size)) = dev->serial_number++;
atomic_set(&dev->intr_idx, aux_idx); atomic_set(&dev->intr_idx, aux_idx);
spin_unlock(&dev->intr_idx_lock);
/* tell the blocking read about the new data */ /* tell the blocking read about the new data */
wake_up_interruptible(&dev->read_wait); 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->intr_idx, 0);
atomic_set(&dev->read_idx, 0); atomic_set(&dev->read_idx, 0);
spin_lock_init(&dev->intr_idx_lock);
atomic_set(&dev->overflow_flag, 0); atomic_set(&dev->overflow_flag, 0);
init_waitqueue_head(&dev->read_wait); init_waitqueue_head(&dev->read_wait);
atomic_set(&dev->write_busy, 0); atomic_set(&dev->write_busy, 0);

View file

@ -225,6 +225,7 @@ static void ld_usb_interrupt_in_callback(struct urb *urb)
size_t *actual_buffer; size_t *actual_buffer;
unsigned int next_ring_head; unsigned int next_ring_head;
int status = urb->status; int status = urb->status;
unsigned long flags;
int retval; int retval;
if (status) { if (status) {
@ -236,12 +237,12 @@ static void ld_usb_interrupt_in_callback(struct urb *urb)
dev_dbg(&dev->intf->dev, dev_dbg(&dev->intf->dev,
"%s: nonzero status received: %d\n", __func__, "%s: nonzero status received: %d\n", __func__,
status); status);
spin_lock(&dev->rbsl); spin_lock_irqsave(&dev->rbsl, flags);
goto resubmit; /* maybe we can recover */ goto resubmit; /* maybe we can recover */
} }
} }
spin_lock(&dev->rbsl); spin_lock_irqsave(&dev->rbsl, flags);
if (urb->actual_length > 0) { if (urb->actual_length > 0) {
next_ring_head = (dev->ring_head+1) % ring_buffer_size; next_ring_head = (dev->ring_head+1) % ring_buffer_size;
if (next_ring_head != dev->ring_tail) { if (next_ring_head != dev->ring_tail) {
@ -270,7 +271,7 @@ resubmit:
dev->buffer_overflow = 1; dev->buffer_overflow = 1;
} }
} }
spin_unlock(&dev->rbsl); spin_unlock_irqrestore(&dev->rbsl, flags);
exit: exit:
dev->interrupt_in_done = 1; dev->interrupt_in_done = 1;
wake_up_interruptible(&dev->read_wait); wake_up_interruptible(&dev->read_wait);

Some files were not shown because too many files have changed in this diff Show more