Commit 5695d5d1 authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents 1f7a4c73 29c692c9
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
...@@ -263,3 +263,8 @@ Description: Specific streaming header descriptors ...@@ -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
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.
...@@ -222,70 +222,12 @@ Description: ...@@ -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
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).
...@@ -15,6 +15,33 @@ Optional properties: ...@@ -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 { ...@@ -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>;
};
};
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";
};
...@@ -47,6 +47,12 @@ Required properties (port (child) node): ...@@ -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 {
......
...@@ -12,7 +12,14 @@ Required properties: ...@@ -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: ...@@ -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
......
* 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>;
};
...@@ -10,6 +10,8 @@ Required properties: ...@@ -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.
......
...@@ -96,6 +96,11 @@ Optional properties: ...@@ -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 { ...@@ -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>;
}; };
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>;
};
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>;
};
};
};
};
};
...@@ -14,6 +14,7 @@ Required properties: ...@@ -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
......
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
...@@ -418,15 +418,6 @@ Current status: ...@@ -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.
......
...@@ -1665,7 +1665,8 @@ M: Chunfeng Yun <chunfeng.yun@mediatek.com> ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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>
......
...@@ -160,13 +160,14 @@ static void nfcmrvl_tx_complete(struct urb *urb) ...@@ -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);
......
...@@ -80,3 +80,13 @@ config PHY_BRCM_USB ...@@ -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.
...@@ -9,3 +9,5 @@ obj-$(CONFIG_PHY_BRCM_SATA) += phy-brcm-sata.o ...@@ -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
// 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");
// 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>
......
// 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>
......
// 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>
......
# SPDX-License-Identifier: GPL-2.0
# #
# Makefile for the phy drivers. # Makefile for the phy drivers.
# #
......
// 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 @@ ...@@ -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 @@ ...@@ -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 { ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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;
} }
......
...@@ -55,6 +55,7 @@ static int qcom_usb_hs_phy_set_mode(struct phy *phy, enum phy_mode mode) ...@@ -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:
......
...@@ -8,6 +8,13 @@ config PHY_RCAR_GEN2 ...@@ -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
......
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
// 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>");
...@@ -106,8 +106,6 @@ source "drivers/staging/greybus/Kconfig" ...@@ -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"
......
...@@ -2,7 +2,6 @@ ...@@ -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/
......
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
obj-$(CONFIG_TYPEC_TCPCI) += tcpci.o
obj-$(CONFIG_TYPEC_RT1711H) += tcpci_rt1711h.o
tcpci:
- Test with real hardware
Please send patches to Guenter Roeck <linux@roeck-us.net> and copy
Heikki Krogerus <heikki.krogerus@linux.intel.com>.
...@@ -33,11 +33,11 @@ static const struct tegra_udc_soc_info tegra30_udc_soc_info = { ...@@ -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[] = {
......
...@@ -276,6 +276,7 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf) ...@@ -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) ...@@ -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) ...@@ -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 @@ static int acm_probe(struct usb_interface *intf, ...@@ -1378,6 +1379,9 @@ static int acm_probe(struct usb_interface *intf,
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 @@ static int acm_probe(struct usb_interface *intf, ...@@ -1413,22 +1417,20 @@ static int acm_probe(struct usb_interface *intf,
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 @@ static int acm_probe(struct usb_interface *intf, ...@@ -1437,13 +1439,13 @@ static int acm_probe(struct usb_interface *intf,
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 @@ static int acm_probe(struct usb_interface *intf, ...@@ -1465,7 +1467,7 @@ static int acm_probe(struct usb_interface *intf,
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 @@ static int acm_probe(struct usb_interface *intf, ...@@ -1483,7 +1485,7 @@ static int acm_probe(struct usb_interface *intf,
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 @@ static int acm_probe(struct usb_interface *intf, ...@@ -1542,7 +1544,7 @@ static int acm_probe(struct usb_interface *intf,
&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 @@ static int acm_probe(struct usb_interface *intf, ...@@ -1551,7 +1553,7 @@ static int acm_probe(struct usb_interface *intf,
} }
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 @@ static int acm_probe(struct usb_interface *intf, ...@@ -1560,23 +1562,21 @@ static int acm_probe(struct usb_interface *intf,
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;
} }
......
...@@ -96,6 +96,7 @@ struct wdm_device { ...@@ -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 @@ static struct wdm_device *wdm_find_device_by_minor(int minor) ...@@ -141,26 +142,26 @@ static struct wdm_device *wdm_find_device_by_minor(int minor)
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) ...@@ -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 @@ static void wdm_in_callback(struct urb *urb) ...@@ -219,14 +218,17 @@ static void wdm_in_callback(struct urb *urb)
* 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) ...@@ -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) ...@@ -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) ...@@ -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 ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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;
} }
......
...@@ -292,6 +292,7 @@ static void usblp_bulk_read(struct urb *urb) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
} }
......
This diff is collapsed.
...@@ -585,9 +585,10 @@ static void async_completed(struct urb *urb) ...@@ -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) ...@@ -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);
......
...@@ -3660,12 +3660,54 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) ...@@ -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;
} }
......
...@@ -269,10 +269,11 @@ static void sg_clean(struct usb_sg_request *io) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
} }
......
This diff is collapsed.
...@@ -65,60 +65,6 @@ ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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); ...@@ -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;
} }
/* /*
......
This diff is collapsed.
...@@ -69,7 +69,7 @@ static int testmode_show(struct seq_file *s, void *unused) ...@@ -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 = { ...@@ -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); ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
......
This diff is collapsed.
This diff is collapsed.
...@@ -469,10 +469,10 @@ static inline struct usb_hcd *dwc2_hsotg_to_hcd(struct dwc2_hsotg *hsotg) ...@@ -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, ...@@ -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) ...@@ -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)
......
...@@ -185,19 +185,19 @@ static void dwc2_per_sched_enable(struct dwc2_hsotg *hsotg, u32 fr_list_en) ...@@ -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) ...@@ -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) ...@@ -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);
} }
......
This diff is collapsed.
...@@ -1510,7 +1510,7 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, ...@@ -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) ...@@ -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) ...@@ -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);
} }
} }
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -45,6 +45,7 @@ endif ...@@ -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
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment