mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 21:38:32 +08:00
USB/PHY patches for 4.19-rc1
Here is the big USB and phy driver patch set for 4.19-rc1. Nothing huge but there was a lot of work that happened this development cycle: - lots of type-c work, with drivers graduating out of staging, and displayport support being added. - new PHY drivers - the normal collection of gadget driver updates and fixes - code churn to work on the urb handling path, using irqsave() everywhere in anticipation of making this codepath a lot simpler in the future. - usbserial driver fixes and reworks - other misc changes Full details are in the shortlog. All of these have been in linux-next with no reported issues for a while. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCW3hBPA8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+yloNwCggMZi9m8Krjq7d7aLw5oJJex/nIAAn0jeADOT NpoCgrtGHjwrATxN5/Ke =jXa3 -----END PGP SIGNATURE----- Merge tag 'usb-4.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB/PHY updates from Greg KH: "Here is the big USB and phy driver patch set for 4.19-rc1. Nothing huge but there was a lot of work that happened this development cycle: - lots of type-c work, with drivers graduating out of staging, and displayport support being added. - new PHY drivers - the normal collection of gadget driver updates and fixes - code churn to work on the urb handling path, using irqsave() everywhere in anticipation of making this codepath a lot simpler in the future. - usbserial driver fixes and reworks - other misc changes All of these have been in linux-next with no reported issues for a while" * tag 'usb-4.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (159 commits) USB: serial: pl2303: add a new device id for ATEN usb: renesas_usbhs: Kconfig: convert to SPDX identifiers usb: dwc3: gadget: Check MaxPacketSize from descriptor usb: dwc2: Turn on uframe_sched on "stm32f4x9_fsotg" platforms usb: dwc2: Turn on uframe_sched on "amlogic" platforms usb: dwc2: Turn on uframe_sched on "his" platforms usb: dwc2: Turn on uframe_sched on "bcm" platforms usb: dwc2: gadget: ISOC's starting flow improvement usb: dwc2: Make dwc2_readl/writel functions endianness-agnostic. usb: dwc3: core: Enable AutoRetry feature in the controller usb: dwc3: Set default mode for dwc_usb31 usb: gadget: udc: renesas_usb3: Add register of usb role switch usb: dwc2: replace ioread32/iowrite32_rep with dwc2_readl/writel_rep usb: dwc2: Modify dwc2_readl/writel functions prototype usb: dwc3: pci: Intel Merrifield can be host usb: dwc3: pci: Supply device properties via driver data arm64: dts: dwc3: description of incr burst type usb: dwc3: Enable undefined length INCR burst type usb: dwc3: add global soc bus configuration reg0 usb: dwc3: Describe 'wakeup_work' field of struct dwc3_pci ...
This commit is contained in:
commit
5695d5d197
48
Documentation/ABI/obsolete/sysfs-class-typec
Normal file
48
Documentation/ABI/obsolete/sysfs-class-typec
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
These files are deprecated and will be removed. The same files are available
|
||||||
|
under /sys/bus/typec (see Documentation/ABI/testing/sysfs-bus-typec).
|
||||||
|
|
||||||
|
What: /sys/class/typec/<port|partner|cable>/<dev>/svid
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
The SVID (Standard or Vendor ID) assigned by USB-IF for this
|
||||||
|
alternate mode.
|
||||||
|
|
||||||
|
What: /sys/class/typec/<port|partner|cable>/<dev>/mode<index>/
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
Every supported mode will have its own directory. The name of
|
||||||
|
a mode will be "mode<index>" (for example mode1), where <index>
|
||||||
|
is the actual index to the mode VDO returned by Discover Modes
|
||||||
|
USB power delivery command.
|
||||||
|
|
||||||
|
What: /sys/class/typec/<port|partner|cable>/<dev>/mode<index>/description
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
Shows description of the mode. The description is optional for
|
||||||
|
the drivers, just like with the Billboard Devices.
|
||||||
|
|
||||||
|
What: /sys/class/typec/<port|partner|cable>/<dev>/mode<index>/vdo
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
Shows the VDO in hexadecimal returned by Discover Modes command
|
||||||
|
for this mode.
|
||||||
|
|
||||||
|
What: /sys/class/typec/<port|partner|cable>/<dev>/mode<index>/active
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
Shows if the mode is active or not. The attribute can be used
|
||||||
|
for entering/exiting the mode with partners and cable plugs, and
|
||||||
|
with the port alternate modes it can be used for disabling
|
||||||
|
support for specific alternate modes. Entering/exiting modes is
|
||||||
|
supported as synchronous operation so write(2) to the attribute
|
||||||
|
does not return until the enter/exit mode operation has
|
||||||
|
finished. The attribute is notified when the mode is
|
||||||
|
entered/exited so poll(2) on the attribute wakes up.
|
||||||
|
Entering/exiting a mode will also generate uevent KOBJ_CHANGE.
|
||||||
|
|
||||||
|
Valid values: yes, no
|
@ -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
|
||||||
|
51
Documentation/ABI/testing/sysfs-bus-typec
Normal file
51
Documentation/ABI/testing/sysfs-bus-typec
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
What: /sys/bus/typec/devices/.../active
|
||||||
|
Date: July 2018
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
Shows if the mode is active or not. The attribute can be used
|
||||||
|
for entering/exiting the mode. Entering/exiting modes is
|
||||||
|
supported as synchronous operation so write(2) to the attribute
|
||||||
|
does not return until the enter/exit mode operation has
|
||||||
|
finished. The attribute is notified when the mode is
|
||||||
|
entered/exited so poll(2) on the attribute wakes up.
|
||||||
|
Entering/exiting a mode will also generate uevent KOBJ_CHANGE.
|
||||||
|
|
||||||
|
Valid values are boolean.
|
||||||
|
|
||||||
|
What: /sys/bus/typec/devices/.../description
|
||||||
|
Date: July 2018
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
Shows description of the mode. The description is optional for
|
||||||
|
the drivers, just like with the Billboard Devices.
|
||||||
|
|
||||||
|
What: /sys/bus/typec/devices/.../mode
|
||||||
|
Date: July 2018
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
The index number of the mode returned by Discover Modes USB
|
||||||
|
Power Delivery command. Depending on the alternate mode, the
|
||||||
|
mode index may be significant.
|
||||||
|
|
||||||
|
With some alternate modes (SVIDs), the mode index is assigned
|
||||||
|
for specific functionality in the specification for that
|
||||||
|
alternate mode.
|
||||||
|
|
||||||
|
With other alternate modes, the mode index values are not
|
||||||
|
assigned, and can not be therefore used for identification. When
|
||||||
|
the mode index is not assigned, identifying the alternate mode
|
||||||
|
must be done with either mode VDO or the description.
|
||||||
|
|
||||||
|
What: /sys/bus/typec/devices/.../svid
|
||||||
|
Date: July 2018
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
The Standard or Vendor ID (SVID) assigned by USB-IF for this
|
||||||
|
alternate mode.
|
||||||
|
|
||||||
|
What: /sys/bus/typec/devices/.../vdo
|
||||||
|
Date: July 2018
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
Shows the VDO in hexadecimal returned by Discover Modes command
|
||||||
|
for this mode.
|
@ -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
|
||||||
|
49
Documentation/ABI/testing/sysfs-driver-typec-displayport
Normal file
49
Documentation/ABI/testing/sysfs-driver-typec-displayport
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
What: /sys/bus/typec/devices/.../displayport/configuration
|
||||||
|
Date: July 2018
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
Shows the current DisplayPort configuration for the connector.
|
||||||
|
Valid values are USB, source and sink. Source means DisplayPort
|
||||||
|
source, and sink means DisplayPort sink.
|
||||||
|
|
||||||
|
All supported configurations are listed as space separated list
|
||||||
|
with the active one wrapped in square brackets.
|
||||||
|
|
||||||
|
Source example:
|
||||||
|
|
||||||
|
USB [source] sink
|
||||||
|
|
||||||
|
The configuration can be changed by writing to the file
|
||||||
|
|
||||||
|
Note. USB configuration does not equal to Exit Mode. It is
|
||||||
|
separate configuration defined in VESA DisplayPort Alt Mode on
|
||||||
|
USB Type-C Standard. Functionally it equals to the situation
|
||||||
|
where the mode has been exited (to exit the mode, see
|
||||||
|
Documentation/ABI/testing/sysfs-bus-typec, and use file
|
||||||
|
/sys/bus/typec/devices/.../active).
|
||||||
|
|
||||||
|
What: /sys/bus/typec/devices/.../displayport/pin_assignment
|
||||||
|
Date: July 2018
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
VESA DisplayPort Alt Mode on USB Type-C Standard defines six
|
||||||
|
different pin assignments for USB Type-C connector that are
|
||||||
|
labeled A, B, C, D, E, and F. The supported pin assignments are
|
||||||
|
listed as space separated list with the active one wrapped in
|
||||||
|
square brackets.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
C [D]
|
||||||
|
|
||||||
|
Pin assignment can be changed by writing to the file. It is
|
||||||
|
possible to set pin assignment before configuration has been
|
||||||
|
set, but the assignment will not be active before the
|
||||||
|
connector is actually configured.
|
||||||
|
|
||||||
|
Note. As of VESA DisplayPort Alt Mode on USB Type-C Standard
|
||||||
|
version 1.0b, pin assignments A, B, and F are deprecated. Only
|
||||||
|
pin assignment D can now carry simultaneously one channel of
|
||||||
|
USB SuperSpeed protocol. From user perspective pin assignments C
|
||||||
|
and E are equal, where all channels on the connector are used
|
||||||
|
for carrying DisplayPort protocol (allowing higher resolutions).
|
@ -15,6 +15,33 @@ Optional properties:
|
|||||||
- type: size of the connector, should be specified in case of USB-A, USB-B
|
- type: size of the connector, should be specified in case of USB-A, USB-B
|
||||||
non-fullsize connectors: "mini", "micro".
|
non-fullsize connectors: "mini", "micro".
|
||||||
|
|
||||||
|
Optional properties for usb-c-connector:
|
||||||
|
- power-role: should be one of "source", "sink" or "dual"(DRP) if typec
|
||||||
|
connector has power support.
|
||||||
|
- try-power-role: preferred power role if "dual"(DRP) can support Try.SNK
|
||||||
|
or Try.SRC, should be "sink" for Try.SNK or "source" for Try.SRC.
|
||||||
|
- data-role: should be one of "host", "device", "dual"(DRD) if typec
|
||||||
|
connector supports USB data.
|
||||||
|
|
||||||
|
Required properties for usb-c-connector with power delivery support:
|
||||||
|
- source-pdos: An array of u32 with each entry providing supported power
|
||||||
|
source data object(PDO), the detailed bit definitions of PDO can be found
|
||||||
|
in "Universal Serial Bus Power Delivery Specification" chapter 6.4.1.2
|
||||||
|
Source_Capabilities Message, the order of each entry(PDO) should follow
|
||||||
|
the PD spec chapter 6.4.1. Required for power source and power dual role.
|
||||||
|
User can specify the source PDO array via PDO_FIXED/BATT/VAR() defined in
|
||||||
|
dt-bindings/usb/pd.h.
|
||||||
|
- sink-pdos: An array of u32 with each entry providing supported power
|
||||||
|
sink data object(PDO), the detailed bit definitions of PDO can be found
|
||||||
|
in "Universal Serial Bus Power Delivery Specification" chapter 6.4.1.3
|
||||||
|
Sink Capabilities Message, the order of each entry(PDO) should follow
|
||||||
|
the PD spec chapter 6.4.1. Required for power sink and power dual role.
|
||||||
|
User can specify the sink PDO array via PDO_FIXED/BATT/VAR() defined in
|
||||||
|
dt-bindings/usb/pd.h.
|
||||||
|
- op-sink-microwatt: Sink required operating power in microwatt, if source
|
||||||
|
can't offer the power, Capability Mismatch is set. Required for power
|
||||||
|
sink and power dual role.
|
||||||
|
|
||||||
Required nodes:
|
Required nodes:
|
||||||
- any data bus to the connector should be modeled using the OF graph bindings
|
- any data bus to the connector should be modeled using the OF graph bindings
|
||||||
specified in bindings/graph.txt, unless the bus is between parent node and
|
specified in bindings/graph.txt, unless the bus is between parent node and
|
||||||
@ -73,3 +100,20 @@ ccic: s2mm005@33 {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
3. USB-C connector attached to a typec port controller(ptn5110), which has
|
||||||
|
power delivery support and enables drp.
|
||||||
|
|
||||||
|
typec: ptn5110@50 {
|
||||||
|
...
|
||||||
|
usb_con: connector {
|
||||||
|
compatible = "usb-c-connector";
|
||||||
|
label = "USB-C";
|
||||||
|
power-role = "dual";
|
||||||
|
try-power-role = "sink";
|
||||||
|
source-pdos = <PDO_FIXED(5000, 2000, PDO_FIXED_USB_COMM)>;
|
||||||
|
sink-pdos = <PDO_FIXED(5000, 2000, PDO_FIXED_USB_COMM)
|
||||||
|
PDO_VAR(5000, 12000, 2000)>;
|
||||||
|
op-sink-microwatt = <10000000>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
41
Documentation/devicetree/bindings/phy/brcm,sr-pcie-phy.txt
Normal file
41
Documentation/devicetree/bindings/phy/brcm,sr-pcie-phy.txt
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
Broadcom Stingray PCIe PHY
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: must be "brcm,sr-pcie-phy"
|
||||||
|
- reg: base address and length of the PCIe SS register space
|
||||||
|
- brcm,sr-cdru: phandle to the CDRU syscon node
|
||||||
|
- brcm,sr-mhb: phandle to the MHB syscon node
|
||||||
|
- #phy-cells: Must be 1, denotes the PHY index
|
||||||
|
|
||||||
|
For PAXB based root complex, one can have a configuration of up to 8 PHYs
|
||||||
|
PHY index goes from 0 to 7
|
||||||
|
|
||||||
|
For the internal PAXC based root complex, PHY index is always 8
|
||||||
|
|
||||||
|
Example:
|
||||||
|
mhb: syscon@60401000 {
|
||||||
|
compatible = "brcm,sr-mhb", "syscon";
|
||||||
|
reg = <0 0x60401000 0 0x38c>;
|
||||||
|
};
|
||||||
|
|
||||||
|
cdru: syscon@6641d000 {
|
||||||
|
compatible = "brcm,sr-cdru", "syscon";
|
||||||
|
reg = <0 0x6641d000 0 0x400>;
|
||||||
|
};
|
||||||
|
|
||||||
|
pcie_phy: phy@40000000 {
|
||||||
|
compatible = "brcm,sr-pcie-phy";
|
||||||
|
reg = <0 0x40000000 0 0x800>;
|
||||||
|
brcm,sr-cdru = <&cdru>;
|
||||||
|
brcm,sr-mhb = <&mhb>;
|
||||||
|
#phy-cells = <1>;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* users of the PCIe PHY */
|
||||||
|
|
||||||
|
pcie0: pcie@48000000 {
|
||||||
|
...
|
||||||
|
...
|
||||||
|
phys = <&pcie_phy 0>;
|
||||||
|
phy-names = "pcie-phy";
|
||||||
|
};
|
@ -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:
|
|||||||
"qcom,sdm845-qmp-usb3-phy" for USB3 QMP V3 phy on sdm845,
|
"qcom,sdm845-qmp-usb3-phy" for USB3 QMP V3 phy on sdm845,
|
||||||
"qcom,sdm845-qmp-usb3-uni-phy" for USB3 QMP V3 UNI phy on sdm845.
|
"qcom,sdm845-qmp-usb3-uni-phy" for USB3 QMP V3 UNI phy on sdm845.
|
||||||
|
|
||||||
- reg: offset and length of register set for PHY's common serdes block.
|
- reg:
|
||||||
|
- For "qcom,sdm845-qmp-usb3-phy":
|
||||||
|
- index 0: address and length of register set for PHY's common serdes
|
||||||
|
block.
|
||||||
|
- named register "dp_com" (using reg-names): address and length of the
|
||||||
|
DP_COM control block.
|
||||||
|
- For all others:
|
||||||
|
- offset and length of register set for PHY's common serdes block.
|
||||||
|
|
||||||
- #clock-cells: must be 1
|
- #clock-cells: must be 1
|
||||||
- Phy pll outputs a bunch of clocks for Tx, Rx and Pipe
|
- Phy pll outputs a bunch of clocks for Tx, Rx and Pipe
|
||||||
@ -60,7 +67,10 @@ Required nodes:
|
|||||||
|
|
||||||
Required properties for child node:
|
Required properties for child node:
|
||||||
- reg: list of offset and length pairs of register sets for PHY blocks -
|
- reg: list of offset and length pairs of register sets for PHY blocks -
|
||||||
tx, rx and pcs.
|
- index 0: tx
|
||||||
|
- index 1: rx
|
||||||
|
- index 2: pcs
|
||||||
|
- index 3: pcs_misc (optional)
|
||||||
|
|
||||||
- #phy-cells: must be 0
|
- #phy-cells: must be 0
|
||||||
|
|
||||||
|
24
Documentation/devicetree/bindings/phy/rcar-gen3-phy-pcie.txt
Normal file
24
Documentation/devicetree/bindings/phy/rcar-gen3-phy-pcie.txt
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
* Renesas R-Car generation 3 PCIe PHY
|
||||||
|
|
||||||
|
This file provides information on what the device node for the R-Car
|
||||||
|
generation 3 PCIe PHY contains.
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: "renesas,r8a77980-pcie-phy" if the device is a part of the
|
||||||
|
R8A77980 SoC.
|
||||||
|
- reg: offset and length of the register block.
|
||||||
|
- clocks: clock phandle and specifier pair.
|
||||||
|
- power-domains: power domain phandle and specifier pair.
|
||||||
|
- resets: reset phandle and specifier pair.
|
||||||
|
- #phy-cells: see phy-bindings.txt in the same directory, must be <0>.
|
||||||
|
|
||||||
|
Example (R-Car V3H):
|
||||||
|
|
||||||
|
pcie-phy@e65d0000 {
|
||||||
|
compatible = "renesas,r8a77980-pcie-phy";
|
||||||
|
reg = <0 0xe65d0000 0 0x8000>;
|
||||||
|
#phy-cells = <0>;
|
||||||
|
clocks = <&cpg CPG_MOD 319>;
|
||||||
|
power-domains = <&sysc 32>;
|
||||||
|
resets = <&cpg 319>;
|
||||||
|
};
|
@ -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:
|
|||||||
enable periodic ESS TX threshold.
|
enable periodic ESS TX threshold.
|
||||||
|
|
||||||
- <DEPRECATED> tx-fifo-resize: determines if the FIFO *has* to be reallocated.
|
- <DEPRECATED> tx-fifo-resize: determines if the FIFO *has* to be reallocated.
|
||||||
|
- snps,incr-burst-type-adjustment: Value for INCR burst type of GSBUSCFG0
|
||||||
|
register, undefined length INCR burst type enable and INCRx type.
|
||||||
|
When just one value, which means INCRX burst mode enabled. When
|
||||||
|
more than one value, which means undefined length INCR burst type
|
||||||
|
enabled. The values can be 1, 4, 8, 16, 32, 64, 128 and 256.
|
||||||
|
|
||||||
- in addition all properties from usb-xhci.txt from the current directory are
|
- in addition all properties from usb-xhci.txt from the current directory are
|
||||||
supported as well
|
supported as well
|
||||||
@ -108,4 +113,5 @@ dwc3@4a030000 {
|
|||||||
reg = <0x4a030000 0xcfff>;
|
reg = <0x4a030000 0xcfff>;
|
||||||
interrupts = <0 92 4>
|
interrupts = <0 92 4>
|
||||||
usb-phy = <&usb2_phy>, <&usb3,phy>;
|
usb-phy = <&usb2_phy>, <&usb3,phy>;
|
||||||
|
snps,incr-burst-type-adjustment = <1>, <4>, <8>, <16>;
|
||||||
};
|
};
|
||||||
|
18
Documentation/devicetree/bindings/usb/npcm7xx-usb.txt
Normal file
18
Documentation/devicetree/bindings/usb/npcm7xx-usb.txt
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
Nuvoton NPCM7XX SoC USB controllers:
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
EHCI:
|
||||||
|
-----
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: "nuvoton,npcm750-ehci"
|
||||||
|
- interrupts: Should contain the EHCI interrupt
|
||||||
|
- reg: Physical address and length of the register set for the device
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
ehci1: usb@f0806000 {
|
||||||
|
compatible = "nuvoton,npcm750-ehci";
|
||||||
|
reg = <0xf0806000 0x1000>;
|
||||||
|
interrupts = <0 61 4>;
|
||||||
|
};
|
49
Documentation/devicetree/bindings/usb/typec-tcpci.txt
Normal file
49
Documentation/devicetree/bindings/usb/typec-tcpci.txt
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
TCPCI(Typec port cotroller interface) binding
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: should be set one of following:
|
||||||
|
- "nxp,ptn5110" for NXP USB PD TCPC PHY IC ptn5110.
|
||||||
|
|
||||||
|
- reg: the i2c slave address of typec port controller device.
|
||||||
|
- interrupt-parent: the phandle to the interrupt controller which provides
|
||||||
|
the interrupt.
|
||||||
|
- interrupts: interrupt specification for tcpci alert.
|
||||||
|
|
||||||
|
Required sub-node:
|
||||||
|
- connector: The "usb-c-connector" attached to the tcpci chip, the bindings
|
||||||
|
of connector node are specified in
|
||||||
|
Documentation/devicetree/bindings/connector/usb-connector.txt
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
ptn5110@50 {
|
||||||
|
compatible = "nxp,ptn5110";
|
||||||
|
reg = <0x50>;
|
||||||
|
interrupt-parent = <&gpio3>;
|
||||||
|
interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
|
||||||
|
|
||||||
|
usb_con: connector {
|
||||||
|
compatible = "usb-c-connector";
|
||||||
|
label = "USB-C";
|
||||||
|
data-role = "dual";
|
||||||
|
power-role = "dual";
|
||||||
|
try-power-role = "sink";
|
||||||
|
source-pdos = <PDO_FIXED(5000, 2000, PDO_FIXED_USB_COMM)>;
|
||||||
|
sink-pdos = <PDO_FIXED(5000, 2000, PDO_FIXED_USB_COMM)
|
||||||
|
PDO_VAR(5000, 12000, 2000)>;
|
||||||
|
op-sink-microwatt = <10000000>;
|
||||||
|
|
||||||
|
ports {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
|
port@1 {
|
||||||
|
reg = <1>;
|
||||||
|
usb_con_ss: endpoint {
|
||||||
|
remote-endpoint = <&usb3_data_ss>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
@ -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
|
||||||
|
136
Documentation/driver-api/usb/typec_bus.rst
Normal file
136
Documentation/driver-api/usb/typec_bus.rst
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
|
||||||
|
API for USB Type-C Alternate Mode drivers
|
||||||
|
=========================================
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
------------
|
||||||
|
|
||||||
|
Alternate modes require communication with the partner using Vendor Defined
|
||||||
|
Messages (VDM) as defined in USB Type-C and USB Power Delivery Specifications.
|
||||||
|
The communication is SVID (Standard or Vendor ID) specific, i.e. specific for
|
||||||
|
every alternate mode, so every alternate mode will need a custom driver.
|
||||||
|
|
||||||
|
USB Type-C bus allows binding a driver to the discovered partner alternate
|
||||||
|
modes by using the SVID and the mode number.
|
||||||
|
|
||||||
|
USB Type-C Connector Class provides a device for every alternate mode a port
|
||||||
|
supports, and separate device for every alternate mode the partner supports.
|
||||||
|
The drivers for the alternate modes are bound to the partner alternate mode
|
||||||
|
devices, and the port alternate mode devices must be handled by the port
|
||||||
|
drivers.
|
||||||
|
|
||||||
|
When a new partner alternate mode device is registered, it is linked to the
|
||||||
|
alternate mode device of the port that the partner is attached to, that has
|
||||||
|
matching SVID and mode. Communication between the port driver and alternate mode
|
||||||
|
driver will happen using the same API.
|
||||||
|
|
||||||
|
The port alternate mode devices are used as a proxy between the partner and the
|
||||||
|
alternate mode drivers, so the port drivers are only expected to pass the SVID
|
||||||
|
specific commands from the alternate mode drivers to the partner, and from the
|
||||||
|
partners to the alternate mode drivers. No direct SVID specific communication is
|
||||||
|
needed from the port drivers, but the port drivers need to provide the operation
|
||||||
|
callbacks for the port alternate mode devices, just like the alternate mode
|
||||||
|
drivers need to provide them for the partner alternate mode devices.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
------
|
||||||
|
|
||||||
|
General
|
||||||
|
~~~~~~~
|
||||||
|
|
||||||
|
By default, the alternate mode drivers are responsible for entering the mode.
|
||||||
|
It is also possible to leave the decision about entering the mode to the user
|
||||||
|
space (See Documentation/ABI/testing/sysfs-class-typec). Port drivers should not
|
||||||
|
enter any modes on their own.
|
||||||
|
|
||||||
|
``->vdm`` is the most important callback in the operation callbacks vector. It
|
||||||
|
will be used to deliver all the SVID specific commands from the partner to the
|
||||||
|
alternate mode driver, and vice versa in case of port drivers. The drivers send
|
||||||
|
the SVID specific commands to each other using :c:func:`typec_altmode_vmd()`.
|
||||||
|
|
||||||
|
If the communication with the partner using the SVID specific commands results
|
||||||
|
in need to reconfigure the pins on the connector, the alternate mode driver
|
||||||
|
needs to notify the bus using :c:func:`typec_altmode_notify()`. The driver
|
||||||
|
passes the negotiated SVID specific pin configuration value to the function as
|
||||||
|
parameter. The bus driver will then configure the mux behind the connector using
|
||||||
|
that value as the state value for the mux, and also call blocking notification
|
||||||
|
chain to notify the external drivers about the state of the connector that need
|
||||||
|
to know it.
|
||||||
|
|
||||||
|
NOTE: The SVID specific pin configuration values must always start from
|
||||||
|
``TYPEC_STATE_MODAL``. USB Type-C specification defines two default states for
|
||||||
|
the connector: ``TYPEC_STATE_USB`` and ``TYPEC_STATE_SAFE``. These values are
|
||||||
|
reserved by the bus as the first possible values for the state. When the
|
||||||
|
alternate mode is entered, the bus will put the connector into
|
||||||
|
``TYPEC_STATE_SAFE`` before sending Enter or Exit Mode command as defined in USB
|
||||||
|
Type-C Specification, and also put the connector back to ``TYPEC_STATE_USB``
|
||||||
|
after the mode has been exited.
|
||||||
|
|
||||||
|
An example of working definitions for SVID specific pin configurations would
|
||||||
|
look like this:
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ALTMODEX_CONF_A = TYPEC_STATE_MODAL,
|
||||||
|
ALTMODEX_CONF_B,
|
||||||
|
...
|
||||||
|
};
|
||||||
|
|
||||||
|
Helper macro ``TYPEC_MODAL_STATE()`` can also be used:
|
||||||
|
|
||||||
|
#define ALTMODEX_CONF_A = TYPEC_MODAL_STATE(0);
|
||||||
|
#define ALTMODEX_CONF_B = TYPEC_MODAL_STATE(1);
|
||||||
|
|
||||||
|
Notification chain
|
||||||
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The drivers for the components that the alternate modes are designed for need to
|
||||||
|
get details regarding the results of the negotiation with the partner, and the
|
||||||
|
pin configuration of the connector. In case of DisplayPort alternate mode for
|
||||||
|
example, the GPU drivers will need to know those details. In case of
|
||||||
|
Thunderbolt alternate mode, the thunderbolt drivers will need to know them, and
|
||||||
|
so on.
|
||||||
|
|
||||||
|
The notification chain is designed for this purpose. The drivers can register
|
||||||
|
notifiers with :c:func:`typec_altmode_register_notifier()`.
|
||||||
|
|
||||||
|
Cable plug alternate modes
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The alternate mode drivers are not bound to cable plug alternate mode devices,
|
||||||
|
only to the partner alternate mode devices. If the alternate mode supports, or
|
||||||
|
requires, a cable that responds to SOP Prime, and optionally SOP Double Prime
|
||||||
|
messages, the driver for that alternate mode must request handle to the cable
|
||||||
|
plug alternate modes using :c:func:`typec_altmode_get_plug()`, and take over
|
||||||
|
their control.
|
||||||
|
|
||||||
|
Driver API
|
||||||
|
----------
|
||||||
|
|
||||||
|
Alternate mode driver registering/unregistering
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/usb/typec/bus.c
|
||||||
|
:functions: typec_altmode_register_driver typec_altmode_unregister_driver
|
||||||
|
|
||||||
|
Alternate mode driver operations
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/usb/typec/bus.c
|
||||||
|
:functions: typec_altmode_enter typec_altmode_exit typec_altmode_attention typec_altmode_vdm typec_altmode_notify
|
||||||
|
|
||||||
|
API for the port drivers
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/usb/typec/bus.c
|
||||||
|
:functions: typec_match_altmode
|
||||||
|
|
||||||
|
Cable Plug operations
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/usb/typec/bus.c
|
||||||
|
:functions: typec_altmode_get_plug typec_altmode_put_plug
|
||||||
|
|
||||||
|
Notifications
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
.. kernel-doc:: drivers/usb/typec/class.c
|
||||||
|
:functions: typec_altmode_register_notifier typec_altmode_unregister_notifier
|
@ -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.
|
||||||
|
|
||||||
|
15
MAINTAINERS
15
MAINTAINERS
@ -1665,7 +1665,8 @@ M: Chunfeng Yun <chunfeng.yun@mediatek.com>
|
|||||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||||
L: linux-mediatek@lists.infradead.org (moderated for non-subscribers)
|
L: linux-mediatek@lists.infradead.org (moderated for non-subscribers)
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/phy/mediatek/phy-mtk-tphy.c
|
F: drivers/phy/mediatek/
|
||||||
|
F: Documentation/devicetree/bindings/phy/phy-mtk-*
|
||||||
|
|
||||||
ARM/MICREL KS8695 ARCHITECTURE
|
ARM/MICREL KS8695 ARCHITECTURE
|
||||||
M: Greg Ungerer <gerg@uclinux.org>
|
M: Greg Ungerer <gerg@uclinux.org>
|
||||||
@ -15117,7 +15118,7 @@ L: linux-usb@vger.kernel.org
|
|||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/usb/typec/mux/pi3usb30532.c
|
F: drivers/usb/typec/mux/pi3usb30532.c
|
||||||
|
|
||||||
USB TYPEC SUBSYSTEM
|
USB TYPEC CLASS
|
||||||
M: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
M: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
L: linux-usb@vger.kernel.org
|
L: linux-usb@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
@ -15126,6 +15127,15 @@ F: Documentation/driver-api/usb/typec.rst
|
|||||||
F: drivers/usb/typec/
|
F: drivers/usb/typec/
|
||||||
F: include/linux/usb/typec.h
|
F: include/linux/usb/typec.h
|
||||||
|
|
||||||
|
USB TYPEC BUS FOR ALTERNATE MODES
|
||||||
|
M: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
L: linux-usb@vger.kernel.org
|
||||||
|
S: Maintained
|
||||||
|
F: Documentation/ABI/testing/sysfs-bus-typec
|
||||||
|
F: Documentation/driver-api/usb/typec_bus.rst
|
||||||
|
F: drivers/usb/typec/altmodes/
|
||||||
|
F: include/linux/usb/typec_altmode.h
|
||||||
|
|
||||||
USB UHCI DRIVER
|
USB UHCI DRIVER
|
||||||
M: Alan Stern <stern@rowland.harvard.edu>
|
M: Alan Stern <stern@rowland.harvard.edu>
|
||||||
L: linux-usb@vger.kernel.org
|
L: linux-usb@vger.kernel.org
|
||||||
@ -15156,6 +15166,7 @@ L: linux-usb@vger.kernel.org
|
|||||||
S: Maintained
|
S: Maintained
|
||||||
F: drivers/usb/gadget/function/*uvc*
|
F: drivers/usb/gadget/function/*uvc*
|
||||||
F: drivers/usb/gadget/legacy/webcam.c
|
F: drivers/usb/gadget/legacy/webcam.c
|
||||||
|
F: include/uapi/linux/usb/g_uvc.h
|
||||||
|
|
||||||
USB WIRELESS RNDIS DRIVER (rndis_wlan)
|
USB WIRELESS RNDIS DRIVER (rndis_wlan)
|
||||||
M: Jussi Kivilinna <jussi.kivilinna@iki.fi>
|
M: Jussi Kivilinna <jussi.kivilinna@iki.fi>
|
||||||
|
@ -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
|
|||||||
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
|
|||||||
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
|
||||||
|
305
drivers/phy/broadcom/phy-bcm-sr-pcie.c
Normal file
305
drivers/phy/broadcom/phy-bcm-sr-pcie.c
Normal file
@ -0,0 +1,305 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2016-2018 Broadcom
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/clk.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/mfd/syscon.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/phy/phy.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
|
||||||
|
/* we have up to 8 PAXB based RC. The 9th one is always PAXC */
|
||||||
|
#define SR_NR_PCIE_PHYS 9
|
||||||
|
#define SR_PAXC_PHY_IDX (SR_NR_PCIE_PHYS - 1)
|
||||||
|
|
||||||
|
#define PCIE_PIPEMUX_CFG_OFFSET 0x10c
|
||||||
|
#define PCIE_PIPEMUX_SELECT_STRAP 0xf
|
||||||
|
|
||||||
|
#define CDRU_STRAP_DATA_LSW_OFFSET 0x5c
|
||||||
|
#define PCIE_PIPEMUX_SHIFT 19
|
||||||
|
#define PCIE_PIPEMUX_MASK 0xf
|
||||||
|
|
||||||
|
#define MHB_MEM_PW_PAXC_OFFSET 0x1c0
|
||||||
|
#define MHB_PWR_ARR_POWERON 0x8
|
||||||
|
#define MHB_PWR_ARR_POWEROK 0x4
|
||||||
|
#define MHB_PWR_POWERON 0x2
|
||||||
|
#define MHB_PWR_POWEROK 0x1
|
||||||
|
#define MHB_PWR_STATUS_MASK (MHB_PWR_ARR_POWERON | \
|
||||||
|
MHB_PWR_ARR_POWEROK | \
|
||||||
|
MHB_PWR_POWERON | \
|
||||||
|
MHB_PWR_POWEROK)
|
||||||
|
|
||||||
|
struct sr_pcie_phy_core;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct sr_pcie_phy - Stingray PCIe PHY
|
||||||
|
*
|
||||||
|
* @core: pointer to the Stingray PCIe PHY core control
|
||||||
|
* @index: PHY index
|
||||||
|
* @phy: pointer to the kernel PHY device
|
||||||
|
*/
|
||||||
|
struct sr_pcie_phy {
|
||||||
|
struct sr_pcie_phy_core *core;
|
||||||
|
unsigned int index;
|
||||||
|
struct phy *phy;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct sr_pcie_phy_core - Stingray PCIe PHY core control
|
||||||
|
*
|
||||||
|
* @dev: pointer to device
|
||||||
|
* @base: base register of PCIe SS
|
||||||
|
* @cdru: regmap to the CDRU device
|
||||||
|
* @mhb: regmap to the MHB device
|
||||||
|
* @pipemux: pipemuex strap
|
||||||
|
* @phys: array of PCIe PHYs
|
||||||
|
*/
|
||||||
|
struct sr_pcie_phy_core {
|
||||||
|
struct device *dev;
|
||||||
|
void __iomem *base;
|
||||||
|
struct regmap *cdru;
|
||||||
|
struct regmap *mhb;
|
||||||
|
u32 pipemux;
|
||||||
|
struct sr_pcie_phy phys[SR_NR_PCIE_PHYS];
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PCIe PIPEMUX lookup table
|
||||||
|
*
|
||||||
|
* Each array index represents a PIPEMUX strap setting
|
||||||
|
* The array element represents a bitmap where a set bit means the PCIe
|
||||||
|
* core and associated serdes has been enabled as RC and is available for use
|
||||||
|
*/
|
||||||
|
static const u8 pipemux_table[] = {
|
||||||
|
/* PIPEMUX = 0, EP 1x16 */
|
||||||
|
0x00,
|
||||||
|
/* PIPEMUX = 1, EP 2x8 */
|
||||||
|
0x00,
|
||||||
|
/* PIPEMUX = 2, EP 4x4 */
|
||||||
|
0x00,
|
||||||
|
/* PIPEMUX = 3, RC 2x8, cores 0, 7 */
|
||||||
|
0x81,
|
||||||
|
/* PIPEMUX = 4, RC 4x4, cores 0, 1, 6, 7 */
|
||||||
|
0xc3,
|
||||||
|
/* PIPEMUX = 5, RC 8x2, all 8 cores */
|
||||||
|
0xff,
|
||||||
|
/* PIPEMUX = 6, RC 3x4 + 2x2, cores 0, 2, 3, 6, 7 */
|
||||||
|
0xcd,
|
||||||
|
/* PIPEMUX = 7, RC 1x4 + 6x2, cores 0, 2, 3, 4, 5, 6, 7 */
|
||||||
|
0xfd,
|
||||||
|
/* PIPEMUX = 8, EP 1x8 + RC 4x2, cores 4, 5, 6, 7 */
|
||||||
|
0xf0,
|
||||||
|
/* PIPEMUX = 9, EP 1x8 + RC 2x4, cores 6, 7 */
|
||||||
|
0xc0,
|
||||||
|
/* PIPEMUX = 10, EP 2x4 + RC 2x4, cores 1, 6 */
|
||||||
|
0x42,
|
||||||
|
/* PIPEMUX = 11, EP 2x4 + RC 4x2, cores 2, 3, 4, 5 */
|
||||||
|
0x3c,
|
||||||
|
/* PIPEMUX = 12, EP 1x4 + RC 6x2, cores 2, 3, 4, 5, 6, 7 */
|
||||||
|
0xfc,
|
||||||
|
/* PIPEMUX = 13, RC 2x4 + RC 1x4 + 2x2, cores 2, 3, 6 */
|
||||||
|
0x4c,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return true if the strap setting is valid
|
||||||
|
*/
|
||||||
|
static bool pipemux_strap_is_valid(u32 pipemux)
|
||||||
|
{
|
||||||
|
return !!(pipemux < ARRAY_SIZE(pipemux_table));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read the PCIe PIPEMUX from strap
|
||||||
|
*/
|
||||||
|
static u32 pipemux_strap_read(struct sr_pcie_phy_core *core)
|
||||||
|
{
|
||||||
|
u32 pipemux;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read PIPEMUX configuration register to determine the pipemux setting
|
||||||
|
*
|
||||||
|
* In the case when the value indicates using HW strap, fall back to
|
||||||
|
* use HW strap
|
||||||
|
*/
|
||||||
|
pipemux = readl(core->base + PCIE_PIPEMUX_CFG_OFFSET);
|
||||||
|
pipemux &= PCIE_PIPEMUX_MASK;
|
||||||
|
if (pipemux == PCIE_PIPEMUX_SELECT_STRAP) {
|
||||||
|
regmap_read(core->cdru, CDRU_STRAP_DATA_LSW_OFFSET, &pipemux);
|
||||||
|
pipemux >>= PCIE_PIPEMUX_SHIFT;
|
||||||
|
pipemux &= PCIE_PIPEMUX_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pipemux;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Given a PIPEMUX strap and PCIe core index, this function returns true if the
|
||||||
|
* PCIe core needs to be enabled
|
||||||
|
*/
|
||||||
|
static bool pcie_core_is_for_rc(struct sr_pcie_phy *phy)
|
||||||
|
{
|
||||||
|
struct sr_pcie_phy_core *core = phy->core;
|
||||||
|
unsigned int core_idx = phy->index;
|
||||||
|
|
||||||
|
return !!((pipemux_table[core->pipemux] >> core_idx) & 0x1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sr_pcie_phy_init(struct phy *p)
|
||||||
|
{
|
||||||
|
struct sr_pcie_phy *phy = phy_get_drvdata(p);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check whether this PHY is for root complex or not. If yes, return
|
||||||
|
* zero so the host driver can proceed to enumeration. If not, return
|
||||||
|
* an error and that will force the host driver to bail out
|
||||||
|
*/
|
||||||
|
if (pcie_core_is_for_rc(phy))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sr_paxc_phy_init(struct phy *p)
|
||||||
|
{
|
||||||
|
struct sr_pcie_phy *phy = phy_get_drvdata(p);
|
||||||
|
struct sr_pcie_phy_core *core = phy->core;
|
||||||
|
unsigned int core_idx = phy->index;
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
if (core_idx != SR_PAXC_PHY_IDX)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
regmap_read(core->mhb, MHB_MEM_PW_PAXC_OFFSET, &val);
|
||||||
|
if ((val & MHB_PWR_STATUS_MASK) != MHB_PWR_STATUS_MASK) {
|
||||||
|
dev_err(core->dev, "PAXC is not powered up\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct phy_ops sr_pcie_phy_ops = {
|
||||||
|
.init = sr_pcie_phy_init,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct phy_ops sr_paxc_phy_ops = {
|
||||||
|
.init = sr_paxc_phy_init,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct phy *sr_pcie_phy_xlate(struct device *dev,
|
||||||
|
struct of_phandle_args *args)
|
||||||
|
{
|
||||||
|
struct sr_pcie_phy_core *core;
|
||||||
|
int phy_idx;
|
||||||
|
|
||||||
|
core = dev_get_drvdata(dev);
|
||||||
|
if (!core)
|
||||||
|
return ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
|
phy_idx = args->args[0];
|
||||||
|
|
||||||
|
if (WARN_ON(phy_idx >= SR_NR_PCIE_PHYS))
|
||||||
|
return ERR_PTR(-ENODEV);
|
||||||
|
|
||||||
|
return core->phys[phy_idx].phy;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sr_pcie_phy_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct device_node *node = dev->of_node;
|
||||||
|
struct sr_pcie_phy_core *core;
|
||||||
|
struct resource *res;
|
||||||
|
struct phy_provider *provider;
|
||||||
|
unsigned int phy_idx = 0;
|
||||||
|
|
||||||
|
core = devm_kzalloc(dev, sizeof(*core), GFP_KERNEL);
|
||||||
|
if (!core)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
core->dev = dev;
|
||||||
|
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
core->base = devm_ioremap_resource(core->dev, res);
|
||||||
|
if (IS_ERR(core->base))
|
||||||
|
return PTR_ERR(core->base);
|
||||||
|
|
||||||
|
core->cdru = syscon_regmap_lookup_by_phandle(node, "brcm,sr-cdru");
|
||||||
|
if (IS_ERR(core->cdru)) {
|
||||||
|
dev_err(core->dev, "unable to find CDRU device\n");
|
||||||
|
return PTR_ERR(core->cdru);
|
||||||
|
}
|
||||||
|
|
||||||
|
core->mhb = syscon_regmap_lookup_by_phandle(node, "brcm,sr-mhb");
|
||||||
|
if (IS_ERR(core->mhb)) {
|
||||||
|
dev_err(core->dev, "unable to find MHB device\n");
|
||||||
|
return PTR_ERR(core->mhb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read the PCIe PIPEMUX strap setting */
|
||||||
|
core->pipemux = pipemux_strap_read(core);
|
||||||
|
if (!pipemux_strap_is_valid(core->pipemux)) {
|
||||||
|
dev_err(core->dev, "invalid PCIe PIPEMUX strap %u\n",
|
||||||
|
core->pipemux);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (phy_idx = 0; phy_idx < SR_NR_PCIE_PHYS; phy_idx++) {
|
||||||
|
struct sr_pcie_phy *p = &core->phys[phy_idx];
|
||||||
|
const struct phy_ops *ops;
|
||||||
|
|
||||||
|
if (phy_idx == SR_PAXC_PHY_IDX)
|
||||||
|
ops = &sr_paxc_phy_ops;
|
||||||
|
else
|
||||||
|
ops = &sr_pcie_phy_ops;
|
||||||
|
|
||||||
|
p->phy = devm_phy_create(dev, NULL, ops);
|
||||||
|
if (IS_ERR(p->phy)) {
|
||||||
|
dev_err(dev, "failed to create PCIe PHY\n");
|
||||||
|
return PTR_ERR(p->phy);
|
||||||
|
}
|
||||||
|
|
||||||
|
p->core = core;
|
||||||
|
p->index = phy_idx;
|
||||||
|
phy_set_drvdata(p->phy, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_set_drvdata(dev, core);
|
||||||
|
|
||||||
|
provider = devm_of_phy_provider_register(dev, sr_pcie_phy_xlate);
|
||||||
|
if (IS_ERR(provider)) {
|
||||||
|
dev_err(dev, "failed to register PHY provider\n");
|
||||||
|
return PTR_ERR(provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_info(dev, "Stingray PCIe PHY driver initialized\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id sr_pcie_phy_match_table[] = {
|
||||||
|
{ .compatible = "brcm,sr-pcie-phy" },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, sr_pcie_phy_match_table);
|
||||||
|
|
||||||
|
static struct platform_driver sr_pcie_phy_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "sr-pcie-phy",
|
||||||
|
.of_match_table = sr_pcie_phy_match_table,
|
||||||
|
},
|
||||||
|
.probe = sr_pcie_phy_probe,
|
||||||
|
};
|
||||||
|
module_platform_driver(sr_pcie_phy_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Ray Jui <ray.jui@broadcom.com>");
|
||||||
|
MODULE_DESCRIPTION("Broadcom Stingray PCIe PHY driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
@ -1,13 +1,10 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
/*
|
/*
|
||||||
* Marvell Berlin SATA PHY driver
|
* Marvell Berlin SATA PHY driver
|
||||||
*
|
*
|
||||||
* Copyright (C) 2014 Marvell Technology Group Ltd.
|
* Copyright (C) 2014 Marvell Technology Group Ltd.
|
||||||
*
|
*
|
||||||
* Antoine Ténart <antoine.tenart@free-electrons.com>
|
* Antoine Ténart <antoine.tenart@free-electrons.com>
|
||||||
*
|
|
||||||
* This file is licensed under the terms of the GNU General Public
|
|
||||||
* License version 2. This program is licensed "as is" without any
|
|
||||||
* warranty of any kind, whether express or implied.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2014 Marvell Technology Group Ltd.
|
* Copyright (C) 2014 Marvell Technology Group Ltd.
|
||||||
*
|
*
|
||||||
* Antoine Tenart <antoine.tenart@free-electrons.com>
|
* Antoine Tenart <antoine.tenart@free-electrons.com>
|
||||||
* Jisheng Zhang <jszhang@marvell.com>
|
* Jisheng Zhang <jszhang@marvell.com>
|
||||||
*
|
|
||||||
* This file is licensed under the terms of the GNU General Public
|
|
||||||
* License version 2. This program is licensed "as is" without any
|
|
||||||
* warranty of any kind, whether express or implied.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2017 Marvell
|
* Copyright (C) 2017 Marvell
|
||||||
*
|
*
|
||||||
* Antoine Tenart <antoine.tenart@free-electrons.com>
|
* Antoine Tenart <antoine.tenart@free-electrons.com>
|
||||||
*
|
|
||||||
* This file is licensed under the terms of the GNU General Public
|
|
||||||
* License version 2. This program is licensed "as is" without any
|
|
||||||
* warranty of any kind, whether express or implied.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
#
|
#
|
||||||
# Makefile for the phy drivers.
|
# Makefile for the phy drivers.
|
||||||
#
|
#
|
||||||
|
@ -1,16 +1,8 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2015 MediaTek Inc.
|
* Copyright (c) 2015 MediaTek Inc.
|
||||||
* Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
|
* Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
|
||||||
*
|
*
|
||||||
* This software is licensed under the terms of the GNU General Public
|
|
||||||
* License version 2, as published by the Free Software Foundation, and
|
|
||||||
* may be copied, distributed, and modified under those terms.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <dt-bindings/phy/phy.h>
|
#include <dt-bindings/phy/phy.h>
|
||||||
@ -50,6 +42,12 @@
|
|||||||
#define PA0_RG_U2PLL_FORCE_ON BIT(15)
|
#define PA0_RG_U2PLL_FORCE_ON BIT(15)
|
||||||
#define PA0_RG_USB20_INTR_EN BIT(5)
|
#define PA0_RG_USB20_INTR_EN BIT(5)
|
||||||
|
|
||||||
|
#define U3P_USBPHYACR1 0x004
|
||||||
|
#define PA1_RG_VRT_SEL GENMASK(14, 12)
|
||||||
|
#define PA1_RG_VRT_SEL_VAL(x) ((0x7 & (x)) << 12)
|
||||||
|
#define PA1_RG_TERM_SEL GENMASK(10, 8)
|
||||||
|
#define PA1_RG_TERM_SEL_VAL(x) ((0x7 & (x)) << 8)
|
||||||
|
|
||||||
#define U3P_USBPHYACR2 0x008
|
#define U3P_USBPHYACR2 0x008
|
||||||
#define PA2_RG_SIF_U2PLL_FORCE_EN BIT(18)
|
#define PA2_RG_SIF_U2PLL_FORCE_EN BIT(18)
|
||||||
|
|
||||||
@ -103,6 +101,9 @@
|
|||||||
#define P2C_RG_AVALID BIT(2)
|
#define P2C_RG_AVALID BIT(2)
|
||||||
#define P2C_RG_IDDIG BIT(1)
|
#define P2C_RG_IDDIG BIT(1)
|
||||||
|
|
||||||
|
#define U3P_U2PHYBC12C 0x080
|
||||||
|
#define P2C_RG_CHGDT_EN BIT(0)
|
||||||
|
|
||||||
#define U3P_U3_CHIP_GPIO_CTLD 0x0c
|
#define U3P_U3_CHIP_GPIO_CTLD 0x0c
|
||||||
#define P3C_REG_IP_SW_RST BIT(31)
|
#define P3C_REG_IP_SW_RST BIT(31)
|
||||||
#define P3C_MCU_BUS_CK_GATE_EN BIT(30)
|
#define P3C_MCU_BUS_CK_GATE_EN BIT(30)
|
||||||
@ -296,6 +297,10 @@ struct mtk_phy_instance {
|
|||||||
struct clk *ref_clk; /* reference clock of anolog phy */
|
struct clk *ref_clk; /* reference clock of anolog phy */
|
||||||
u32 index;
|
u32 index;
|
||||||
u8 type;
|
u8 type;
|
||||||
|
int eye_src;
|
||||||
|
int eye_vrt;
|
||||||
|
int eye_term;
|
||||||
|
bool bc12_en;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mtk_tphy {
|
struct mtk_tphy {
|
||||||
@ -320,6 +325,10 @@ static void hs_slew_rate_calibrate(struct mtk_tphy *tphy,
|
|||||||
int fm_out;
|
int fm_out;
|
||||||
u32 tmp;
|
u32 tmp;
|
||||||
|
|
||||||
|
/* use force value */
|
||||||
|
if (instance->eye_src)
|
||||||
|
return;
|
||||||
|
|
||||||
/* enable USB ring oscillator */
|
/* enable USB ring oscillator */
|
||||||
tmp = readl(com + U3P_USBPHYACR5);
|
tmp = readl(com + U3P_USBPHYACR5);
|
||||||
tmp |= PA5_RG_U2_HSTX_SRCAL_EN;
|
tmp |= PA5_RG_U2_HSTX_SRCAL_EN;
|
||||||
@ -826,6 +835,61 @@ static void phy_v2_banks_init(struct mtk_tphy *tphy,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void phy_parse_property(struct mtk_tphy *tphy,
|
||||||
|
struct mtk_phy_instance *instance)
|
||||||
|
{
|
||||||
|
struct device *dev = &instance->phy->dev;
|
||||||
|
|
||||||
|
if (instance->type != PHY_TYPE_USB2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
instance->bc12_en = device_property_read_bool(dev, "mediatek,bc12");
|
||||||
|
device_property_read_u32(dev, "mediatek,eye-src",
|
||||||
|
&instance->eye_src);
|
||||||
|
device_property_read_u32(dev, "mediatek,eye-vrt",
|
||||||
|
&instance->eye_vrt);
|
||||||
|
device_property_read_u32(dev, "mediatek,eye-term",
|
||||||
|
&instance->eye_term);
|
||||||
|
dev_dbg(dev, "bc12:%d, src:%d, vrt:%d, term:%d\n",
|
||||||
|
instance->bc12_en, instance->eye_src,
|
||||||
|
instance->eye_vrt, instance->eye_term);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void u2_phy_props_set(struct mtk_tphy *tphy,
|
||||||
|
struct mtk_phy_instance *instance)
|
||||||
|
{
|
||||||
|
struct u2phy_banks *u2_banks = &instance->u2_banks;
|
||||||
|
void __iomem *com = u2_banks->com;
|
||||||
|
u32 tmp;
|
||||||
|
|
||||||
|
if (instance->bc12_en) {
|
||||||
|
tmp = readl(com + U3P_U2PHYBC12C);
|
||||||
|
tmp |= P2C_RG_CHGDT_EN; /* BC1.2 path Enable */
|
||||||
|
writel(tmp, com + U3P_U2PHYBC12C);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instance->eye_src) {
|
||||||
|
tmp = readl(com + U3P_USBPHYACR5);
|
||||||
|
tmp &= ~PA5_RG_U2_HSTX_SRCTRL;
|
||||||
|
tmp |= PA5_RG_U2_HSTX_SRCTRL_VAL(instance->eye_src);
|
||||||
|
writel(tmp, com + U3P_USBPHYACR5);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instance->eye_vrt) {
|
||||||
|
tmp = readl(com + U3P_USBPHYACR1);
|
||||||
|
tmp &= ~PA1_RG_VRT_SEL;
|
||||||
|
tmp |= PA1_RG_VRT_SEL_VAL(instance->eye_vrt);
|
||||||
|
writel(tmp, com + U3P_USBPHYACR1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instance->eye_term) {
|
||||||
|
tmp = readl(com + U3P_USBPHYACR1);
|
||||||
|
tmp &= ~PA1_RG_TERM_SEL;
|
||||||
|
tmp |= PA1_RG_TERM_SEL_VAL(instance->eye_term);
|
||||||
|
writel(tmp, com + U3P_USBPHYACR1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int mtk_phy_init(struct phy *phy)
|
static int mtk_phy_init(struct phy *phy)
|
||||||
{
|
{
|
||||||
struct mtk_phy_instance *instance = phy_get_drvdata(phy);
|
struct mtk_phy_instance *instance = phy_get_drvdata(phy);
|
||||||
@ -847,6 +911,7 @@ static int mtk_phy_init(struct phy *phy)
|
|||||||
switch (instance->type) {
|
switch (instance->type) {
|
||||||
case PHY_TYPE_USB2:
|
case PHY_TYPE_USB2:
|
||||||
u2_phy_instance_init(tphy, instance);
|
u2_phy_instance_init(tphy, instance);
|
||||||
|
u2_phy_props_set(tphy, instance);
|
||||||
break;
|
break;
|
||||||
case PHY_TYPE_USB3:
|
case PHY_TYPE_USB3:
|
||||||
u3_phy_instance_init(tphy, instance);
|
u3_phy_instance_init(tphy, instance);
|
||||||
@ -959,6 +1024,8 @@ static struct phy *mtk_phy_xlate(struct device *dev,
|
|||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
phy_parse_property(tphy, instance);
|
||||||
|
|
||||||
return instance->phy;
|
return instance->phy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
|||||||
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
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
obj-$(CONFIG_PHY_RCAR_GEN2) += phy-rcar-gen2.o
|
obj-$(CONFIG_PHY_RCAR_GEN2) += phy-rcar-gen2.o
|
||||||
|
obj-$(CONFIG_PHY_RCAR_GEN3_PCIE) += phy-rcar-gen3-pcie.o
|
||||||
obj-$(CONFIG_PHY_RCAR_GEN3_USB2) += phy-rcar-gen3-usb2.o
|
obj-$(CONFIG_PHY_RCAR_GEN3_USB2) += phy-rcar-gen3-usb2.o
|
||||||
obj-$(CONFIG_PHY_RCAR_GEN3_USB3) += phy-rcar-gen3-usb3.o
|
obj-$(CONFIG_PHY_RCAR_GEN3_USB3) += phy-rcar-gen3-usb3.o
|
||||||
|
151
drivers/phy/renesas/phy-rcar-gen3-pcie.c
Normal file
151
drivers/phy/renesas/phy-rcar-gen3-pcie.c
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Renesas R-Car Gen3 PCIe PHY driver
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018 Cogent Embedded, Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/clk.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/phy/phy.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
|
||||||
|
#define PHY_CTRL 0x4000 /* R8A77980 only */
|
||||||
|
|
||||||
|
/* PHY control register (PHY_CTRL) */
|
||||||
|
#define PHY_CTRL_PHY_PWDN BIT(2)
|
||||||
|
|
||||||
|
struct rcar_gen3_phy {
|
||||||
|
struct phy *phy;
|
||||||
|
spinlock_t lock;
|
||||||
|
void __iomem *base;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void rcar_gen3_phy_pcie_modify_reg(struct phy *p, unsigned int reg,
|
||||||
|
u32 clear, u32 set)
|
||||||
|
{
|
||||||
|
struct rcar_gen3_phy *phy = phy_get_drvdata(p);
|
||||||
|
void __iomem *base = phy->base;
|
||||||
|
unsigned long flags;
|
||||||
|
u32 value;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&phy->lock, flags);
|
||||||
|
|
||||||
|
value = readl(base + reg);
|
||||||
|
value &= ~clear;
|
||||||
|
value |= set;
|
||||||
|
writel(value, base + reg);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&phy->lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int r8a77980_phy_pcie_power_on(struct phy *p)
|
||||||
|
{
|
||||||
|
/* Power on the PCIe PHY */
|
||||||
|
rcar_gen3_phy_pcie_modify_reg(p, PHY_CTRL, PHY_CTRL_PHY_PWDN, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int r8a77980_phy_pcie_power_off(struct phy *p)
|
||||||
|
{
|
||||||
|
/* Power off the PCIe PHY */
|
||||||
|
rcar_gen3_phy_pcie_modify_reg(p, PHY_CTRL, 0, PHY_CTRL_PHY_PWDN);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct phy_ops r8a77980_phy_pcie_ops = {
|
||||||
|
.power_on = r8a77980_phy_pcie_power_on,
|
||||||
|
.power_off = r8a77980_phy_pcie_power_off,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct of_device_id rcar_gen3_phy_pcie_match_table[] = {
|
||||||
|
{ .compatible = "renesas,r8a77980-pcie-phy" },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, rcar_gen3_phy_pcie_match_table);
|
||||||
|
|
||||||
|
static int rcar_gen3_phy_pcie_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct phy_provider *provider;
|
||||||
|
struct rcar_gen3_phy *phy;
|
||||||
|
struct resource *res;
|
||||||
|
void __iomem *base;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if (!dev->of_node) {
|
||||||
|
dev_err(dev,
|
||||||
|
"This driver must only be instantiated from the device tree\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
base = devm_ioremap_resource(dev, res);
|
||||||
|
if (IS_ERR(base))
|
||||||
|
return PTR_ERR(base);
|
||||||
|
|
||||||
|
phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
|
||||||
|
if (!phy)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
spin_lock_init(&phy->lock);
|
||||||
|
|
||||||
|
phy->base = base;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* devm_phy_create() will call pm_runtime_enable(&phy->dev);
|
||||||
|
* And then, phy-core will manage runtime PM for this device.
|
||||||
|
*/
|
||||||
|
pm_runtime_enable(dev);
|
||||||
|
|
||||||
|
phy->phy = devm_phy_create(dev, NULL, &r8a77980_phy_pcie_ops);
|
||||||
|
if (IS_ERR(phy->phy)) {
|
||||||
|
dev_err(dev, "Failed to create PCIe PHY\n");
|
||||||
|
error = PTR_ERR(phy->phy);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
phy_set_drvdata(phy->phy, phy);
|
||||||
|
|
||||||
|
provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||||
|
if (IS_ERR(provider)) {
|
||||||
|
dev_err(dev, "Failed to register PHY provider\n");
|
||||||
|
error = PTR_ERR(provider);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
pm_runtime_disable(dev);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rcar_gen3_phy_pcie_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_driver rcar_gen3_phy_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "phy_rcar_gen3_pcie",
|
||||||
|
.of_match_table = rcar_gen3_phy_pcie_match_table,
|
||||||
|
},
|
||||||
|
.probe = rcar_gen3_phy_pcie_probe,
|
||||||
|
.remove = rcar_gen3_phy_pcie_remove,
|
||||||
|
};
|
||||||
|
|
||||||
|
module_platform_driver(rcar_gen3_phy_driver);
|
||||||
|
|
||||||
|
MODULE_LICENSE("GPL v2");
|
||||||
|
MODULE_DESCRIPTION("Renesas R-Car Gen3 PCIe PHY");
|
||||||
|
MODULE_AUTHOR("Sergei Shtylyov <sergei.shtylyov@cogentembedded.com>");
|
@ -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 @@
|
|||||||
# 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/
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
menu "USB Power Delivery and Type-C drivers"
|
|
||||||
|
|
||||||
if TYPEC_TCPM
|
|
||||||
|
|
||||||
config TYPEC_TCPCI
|
|
||||||
tristate "Type-C Port Controller Interface driver"
|
|
||||||
depends on I2C
|
|
||||||
select REGMAP_I2C
|
|
||||||
help
|
|
||||||
Type-C Port Controller driver for TCPCI-compliant controller.
|
|
||||||
|
|
||||||
config TYPEC_RT1711H
|
|
||||||
tristate "Richtek RT1711H Type-C chip driver"
|
|
||||||
depends on I2C
|
|
||||||
select TYPEC_TCPCI
|
|
||||||
help
|
|
||||||
Richtek RT1711H Type-C chip driver that works with
|
|
||||||
Type-C Port Controller Manager to provide USB PD and USB
|
|
||||||
Type-C functionalities.
|
|
||||||
|
|
||||||
endif
|
|
||||||
|
|
||||||
endmenu
|
|
@ -1,2 +0,0 @@
|
|||||||
obj-$(CONFIG_TYPEC_TCPCI) += tcpci.o
|
|
||||||
obj-$(CONFIG_TYPEC_RT1711H) += tcpci_rt1711h.o
|
|
@ -1,5 +0,0 @@
|
|||||||
tcpci:
|
|
||||||
- Test with real hardware
|
|
||||||
|
|
||||||
Please send patches to Guenter Roeck <linux@roeck-us.net> and copy
|
|
||||||
Heikki Krogerus <heikki.krogerus@linux.intel.com>.
|
|
@ -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)
|
|||||||
{
|
{
|
||||||
int newctrl;
|
int newctrl;
|
||||||
int difference;
|
int difference;
|
||||||
|
unsigned long flags;
|
||||||
struct usb_cdc_notification *dr = (struct usb_cdc_notification *)buf;
|
struct usb_cdc_notification *dr = (struct usb_cdc_notification *)buf;
|
||||||
unsigned char *data = buf + sizeof(struct usb_cdc_notification);
|
unsigned char *data = buf + sizeof(struct usb_cdc_notification);
|
||||||
|
|
||||||
@ -303,7 +304,7 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
difference = acm->ctrlin ^ newctrl;
|
difference = acm->ctrlin ^ newctrl;
|
||||||
spin_lock(&acm->read_lock);
|
spin_lock_irqsave(&acm->read_lock, flags);
|
||||||
acm->ctrlin = newctrl;
|
acm->ctrlin = newctrl;
|
||||||
acm->oldcount = acm->iocount;
|
acm->oldcount = acm->iocount;
|
||||||
|
|
||||||
@ -321,7 +322,7 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf)
|
|||||||
acm->iocount.parity++;
|
acm->iocount.parity++;
|
||||||
if (difference & ACM_CTRL_OVERRUN)
|
if (difference & ACM_CTRL_OVERRUN)
|
||||||
acm->iocount.overrun++;
|
acm->iocount.overrun++;
|
||||||
spin_unlock(&acm->read_lock);
|
spin_unlock_irqrestore(&acm->read_lock, flags);
|
||||||
|
|
||||||
if (difference)
|
if (difference)
|
||||||
wake_up_all(&acm->wioctl);
|
wake_up_all(&acm->wioctl);
|
||||||
@ -1378,6 +1379,9 @@ made_compressed_probe:
|
|||||||
if (acm == NULL)
|
if (acm == NULL)
|
||||||
goto alloc_fail;
|
goto alloc_fail;
|
||||||
|
|
||||||
|
tty_port_init(&acm->port);
|
||||||
|
acm->port.ops = &acm_port_ops;
|
||||||
|
|
||||||
minor = acm_alloc_minor(acm);
|
minor = acm_alloc_minor(acm);
|
||||||
if (minor < 0)
|
if (minor < 0)
|
||||||
goto alloc_fail1;
|
goto alloc_fail1;
|
||||||
@ -1413,22 +1417,20 @@ made_compressed_probe:
|
|||||||
acm->out = usb_sndintpipe(usb_dev, epwrite->bEndpointAddress);
|
acm->out = usb_sndintpipe(usb_dev, epwrite->bEndpointAddress);
|
||||||
else
|
else
|
||||||
acm->out = usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress);
|
acm->out = usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress);
|
||||||
tty_port_init(&acm->port);
|
|
||||||
acm->port.ops = &acm_port_ops;
|
|
||||||
init_usb_anchor(&acm->delayed);
|
init_usb_anchor(&acm->delayed);
|
||||||
acm->quirks = quirks;
|
acm->quirks = quirks;
|
||||||
|
|
||||||
buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
|
buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
|
||||||
if (!buf)
|
if (!buf)
|
||||||
goto alloc_fail2;
|
goto alloc_fail1;
|
||||||
acm->ctrl_buffer = buf;
|
acm->ctrl_buffer = buf;
|
||||||
|
|
||||||
if (acm_write_buffers_alloc(acm) < 0)
|
if (acm_write_buffers_alloc(acm) < 0)
|
||||||
goto alloc_fail4;
|
goto alloc_fail2;
|
||||||
|
|
||||||
acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
|
acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
|
||||||
if (!acm->ctrlurb)
|
if (!acm->ctrlurb)
|
||||||
goto alloc_fail5;
|
goto alloc_fail3;
|
||||||
|
|
||||||
for (i = 0; i < num_rx_buf; i++) {
|
for (i = 0; i < num_rx_buf; i++) {
|
||||||
struct acm_rb *rb = &(acm->read_buffers[i]);
|
struct acm_rb *rb = &(acm->read_buffers[i]);
|
||||||
@ -1437,13 +1439,13 @@ made_compressed_probe:
|
|||||||
rb->base = usb_alloc_coherent(acm->dev, readsize, GFP_KERNEL,
|
rb->base = usb_alloc_coherent(acm->dev, readsize, GFP_KERNEL,
|
||||||
&rb->dma);
|
&rb->dma);
|
||||||
if (!rb->base)
|
if (!rb->base)
|
||||||
goto alloc_fail6;
|
goto alloc_fail4;
|
||||||
rb->index = i;
|
rb->index = i;
|
||||||
rb->instance = acm;
|
rb->instance = acm;
|
||||||
|
|
||||||
urb = usb_alloc_urb(0, GFP_KERNEL);
|
urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||||
if (!urb)
|
if (!urb)
|
||||||
goto alloc_fail6;
|
goto alloc_fail4;
|
||||||
|
|
||||||
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||||
urb->transfer_dma = rb->dma;
|
urb->transfer_dma = rb->dma;
|
||||||
@ -1465,7 +1467,7 @@ made_compressed_probe:
|
|||||||
|
|
||||||
snd->urb = usb_alloc_urb(0, GFP_KERNEL);
|
snd->urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||||
if (snd->urb == NULL)
|
if (snd->urb == NULL)
|
||||||
goto alloc_fail7;
|
goto alloc_fail5;
|
||||||
|
|
||||||
if (usb_endpoint_xfer_int(epwrite))
|
if (usb_endpoint_xfer_int(epwrite))
|
||||||
usb_fill_int_urb(snd->urb, usb_dev, acm->out,
|
usb_fill_int_urb(snd->urb, usb_dev, acm->out,
|
||||||
@ -1483,7 +1485,7 @@ made_compressed_probe:
|
|||||||
|
|
||||||
i = device_create_file(&intf->dev, &dev_attr_bmCapabilities);
|
i = device_create_file(&intf->dev, &dev_attr_bmCapabilities);
|
||||||
if (i < 0)
|
if (i < 0)
|
||||||
goto alloc_fail7;
|
goto alloc_fail5;
|
||||||
|
|
||||||
if (h.usb_cdc_country_functional_desc) { /* export the country data */
|
if (h.usb_cdc_country_functional_desc) { /* export the country data */
|
||||||
struct usb_cdc_country_functional_desc * cfd =
|
struct usb_cdc_country_functional_desc * cfd =
|
||||||
@ -1542,7 +1544,7 @@ skip_countries:
|
|||||||
&control_interface->dev);
|
&control_interface->dev);
|
||||||
if (IS_ERR(tty_dev)) {
|
if (IS_ERR(tty_dev)) {
|
||||||
rv = PTR_ERR(tty_dev);
|
rv = PTR_ERR(tty_dev);
|
||||||
goto alloc_fail8;
|
goto alloc_fail6;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (quirks & CLEAR_HALT_CONDITIONS) {
|
if (quirks & CLEAR_HALT_CONDITIONS) {
|
||||||
@ -1551,7 +1553,7 @@ skip_countries:
|
|||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
alloc_fail8:
|
alloc_fail6:
|
||||||
if (acm->country_codes) {
|
if (acm->country_codes) {
|
||||||
device_remove_file(&acm->control->dev,
|
device_remove_file(&acm->control->dev,
|
||||||
&dev_attr_wCountryCodes);
|
&dev_attr_wCountryCodes);
|
||||||
@ -1560,23 +1562,21 @@ alloc_fail8:
|
|||||||
kfree(acm->country_codes);
|
kfree(acm->country_codes);
|
||||||
}
|
}
|
||||||
device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities);
|
device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities);
|
||||||
alloc_fail7:
|
alloc_fail5:
|
||||||
usb_set_intfdata(intf, NULL);
|
usb_set_intfdata(intf, NULL);
|
||||||
for (i = 0; i < ACM_NW; i++)
|
for (i = 0; i < ACM_NW; i++)
|
||||||
usb_free_urb(acm->wb[i].urb);
|
usb_free_urb(acm->wb[i].urb);
|
||||||
alloc_fail6:
|
alloc_fail4:
|
||||||
for (i = 0; i < num_rx_buf; i++)
|
for (i = 0; i < num_rx_buf; i++)
|
||||||
usb_free_urb(acm->read_urbs[i]);
|
usb_free_urb(acm->read_urbs[i]);
|
||||||
acm_read_buffers_free(acm);
|
acm_read_buffers_free(acm);
|
||||||
usb_free_urb(acm->ctrlurb);
|
usb_free_urb(acm->ctrlurb);
|
||||||
alloc_fail5:
|
alloc_fail3:
|
||||||
acm_write_buffers_free(acm);
|
acm_write_buffers_free(acm);
|
||||||
alloc_fail4:
|
|
||||||
usb_free_coherent(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
|
|
||||||
alloc_fail2:
|
alloc_fail2:
|
||||||
acm_release_minor(acm);
|
usb_free_coherent(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
|
||||||
alloc_fail1:
|
alloc_fail1:
|
||||||
kfree(acm);
|
tty_port_put(&acm->port);
|
||||||
alloc_fail:
|
alloc_fail:
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
@ -96,6 +96,7 @@ struct wdm_device {
|
|||||||
struct mutex rlock;
|
struct mutex rlock;
|
||||||
wait_queue_head_t wait;
|
wait_queue_head_t wait;
|
||||||
struct work_struct rxwork;
|
struct work_struct rxwork;
|
||||||
|
struct work_struct service_outs_intr;
|
||||||
int werr;
|
int werr;
|
||||||
int rerr;
|
int rerr;
|
||||||
int resp_count;
|
int resp_count;
|
||||||
@ -141,26 +142,26 @@ found:
|
|||||||
static void wdm_out_callback(struct urb *urb)
|
static void wdm_out_callback(struct urb *urb)
|
||||||
{
|
{
|
||||||
struct wdm_device *desc;
|
struct wdm_device *desc;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
desc = urb->context;
|
desc = urb->context;
|
||||||
spin_lock(&desc->iuspin);
|
spin_lock_irqsave(&desc->iuspin, flags);
|
||||||
desc->werr = urb->status;
|
desc->werr = urb->status;
|
||||||
spin_unlock(&desc->iuspin);
|
spin_unlock_irqrestore(&desc->iuspin, flags);
|
||||||
kfree(desc->outbuf);
|
kfree(desc->outbuf);
|
||||||
desc->outbuf = NULL;
|
desc->outbuf = NULL;
|
||||||
clear_bit(WDM_IN_USE, &desc->flags);
|
clear_bit(WDM_IN_USE, &desc->flags);
|
||||||
wake_up(&desc->wait);
|
wake_up(&desc->wait);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* forward declaration */
|
|
||||||
static int service_outstanding_interrupt(struct wdm_device *desc);
|
|
||||||
|
|
||||||
static void wdm_in_callback(struct urb *urb)
|
static void wdm_in_callback(struct urb *urb)
|
||||||
{
|
{
|
||||||
|
unsigned long flags;
|
||||||
struct wdm_device *desc = urb->context;
|
struct wdm_device *desc = urb->context;
|
||||||
int status = urb->status;
|
int status = urb->status;
|
||||||
int length = urb->actual_length;
|
int length = urb->actual_length;
|
||||||
|
|
||||||
spin_lock(&desc->iuspin);
|
spin_lock_irqsave(&desc->iuspin, flags);
|
||||||
clear_bit(WDM_RESPONDING, &desc->flags);
|
clear_bit(WDM_RESPONDING, &desc->flags);
|
||||||
|
|
||||||
if (status) {
|
if (status) {
|
||||||
@ -209,8 +210,6 @@ static void wdm_in_callback(struct urb *urb)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
skip_error:
|
skip_error:
|
||||||
set_bit(WDM_READ, &desc->flags);
|
|
||||||
wake_up(&desc->wait);
|
|
||||||
|
|
||||||
if (desc->rerr) {
|
if (desc->rerr) {
|
||||||
/*
|
/*
|
||||||
@ -219,14 +218,17 @@ skip_error:
|
|||||||
* We should respond to further attempts from the device to send
|
* We should respond to further attempts from the device to send
|
||||||
* data, so that we can get unstuck.
|
* data, so that we can get unstuck.
|
||||||
*/
|
*/
|
||||||
service_outstanding_interrupt(desc);
|
schedule_work(&desc->service_outs_intr);
|
||||||
|
} else {
|
||||||
|
set_bit(WDM_READ, &desc->flags);
|
||||||
|
wake_up(&desc->wait);
|
||||||
}
|
}
|
||||||
|
spin_unlock_irqrestore(&desc->iuspin, flags);
|
||||||
spin_unlock(&desc->iuspin);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wdm_int_callback(struct urb *urb)
|
static void wdm_int_callback(struct urb *urb)
|
||||||
{
|
{
|
||||||
|
unsigned long flags;
|
||||||
int rv = 0;
|
int rv = 0;
|
||||||
int responding;
|
int responding;
|
||||||
int status = urb->status;
|
int status = urb->status;
|
||||||
@ -286,7 +288,7 @@ static void wdm_int_callback(struct urb *urb)
|
|||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock(&desc->iuspin);
|
spin_lock_irqsave(&desc->iuspin, flags);
|
||||||
responding = test_and_set_bit(WDM_RESPONDING, &desc->flags);
|
responding = test_and_set_bit(WDM_RESPONDING, &desc->flags);
|
||||||
if (!desc->resp_count++ && !responding
|
if (!desc->resp_count++ && !responding
|
||||||
&& !test_bit(WDM_DISCONNECTING, &desc->flags)
|
&& !test_bit(WDM_DISCONNECTING, &desc->flags)
|
||||||
@ -294,7 +296,7 @@ static void wdm_int_callback(struct urb *urb)
|
|||||||
rv = usb_submit_urb(desc->response, GFP_ATOMIC);
|
rv = usb_submit_urb(desc->response, GFP_ATOMIC);
|
||||||
dev_dbg(&desc->intf->dev, "submit response URB %d\n", rv);
|
dev_dbg(&desc->intf->dev, "submit response URB %d\n", rv);
|
||||||
}
|
}
|
||||||
spin_unlock(&desc->iuspin);
|
spin_unlock_irqrestore(&desc->iuspin, flags);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
clear_bit(WDM_RESPONDING, &desc->flags);
|
clear_bit(WDM_RESPONDING, &desc->flags);
|
||||||
if (rv == -EPERM)
|
if (rv == -EPERM)
|
||||||
@ -758,6 +760,21 @@ static void wdm_rxwork(struct work_struct *work)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void service_interrupt_work(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct wdm_device *desc;
|
||||||
|
|
||||||
|
desc = container_of(work, struct wdm_device, service_outs_intr);
|
||||||
|
|
||||||
|
spin_lock_irq(&desc->iuspin);
|
||||||
|
service_outstanding_interrupt(desc);
|
||||||
|
if (!desc->resp_count) {
|
||||||
|
set_bit(WDM_READ, &desc->flags);
|
||||||
|
wake_up(&desc->wait);
|
||||||
|
}
|
||||||
|
spin_unlock_irq(&desc->iuspin);
|
||||||
|
}
|
||||||
|
|
||||||
/* --- hotplug --- */
|
/* --- hotplug --- */
|
||||||
|
|
||||||
static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor *ep,
|
static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor *ep,
|
||||||
@ -779,6 +796,7 @@ static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor
|
|||||||
desc->inum = cpu_to_le16((u16)intf->cur_altsetting->desc.bInterfaceNumber);
|
desc->inum = cpu_to_le16((u16)intf->cur_altsetting->desc.bInterfaceNumber);
|
||||||
desc->intf = intf;
|
desc->intf = intf;
|
||||||
INIT_WORK(&desc->rxwork, wdm_rxwork);
|
INIT_WORK(&desc->rxwork, wdm_rxwork);
|
||||||
|
INIT_WORK(&desc->service_outs_intr, service_interrupt_work);
|
||||||
|
|
||||||
rv = -EINVAL;
|
rv = -EINVAL;
|
||||||
if (!usb_endpoint_is_int_in(ep))
|
if (!usb_endpoint_is_int_in(ep))
|
||||||
@ -964,6 +982,7 @@ static void wdm_disconnect(struct usb_interface *intf)
|
|||||||
mutex_lock(&desc->wlock);
|
mutex_lock(&desc->wlock);
|
||||||
kill_urbs(desc);
|
kill_urbs(desc);
|
||||||
cancel_work_sync(&desc->rxwork);
|
cancel_work_sync(&desc->rxwork);
|
||||||
|
cancel_work_sync(&desc->service_outs_intr);
|
||||||
mutex_unlock(&desc->wlock);
|
mutex_unlock(&desc->wlock);
|
||||||
mutex_unlock(&desc->rlock);
|
mutex_unlock(&desc->rlock);
|
||||||
|
|
||||||
@ -1006,6 +1025,7 @@ static int wdm_suspend(struct usb_interface *intf, pm_message_t message)
|
|||||||
/* callback submits work - order is essential */
|
/* callback submits work - order is essential */
|
||||||
kill_urbs(desc);
|
kill_urbs(desc);
|
||||||
cancel_work_sync(&desc->rxwork);
|
cancel_work_sync(&desc->rxwork);
|
||||||
|
cancel_work_sync(&desc->service_outs_intr);
|
||||||
}
|
}
|
||||||
if (!PMSG_IS_AUTO(message)) {
|
if (!PMSG_IS_AUTO(message)) {
|
||||||
mutex_unlock(&desc->wlock);
|
mutex_unlock(&desc->wlock);
|
||||||
@ -1065,6 +1085,7 @@ static int wdm_pre_reset(struct usb_interface *intf)
|
|||||||
mutex_lock(&desc->wlock);
|
mutex_lock(&desc->wlock);
|
||||||
kill_urbs(desc);
|
kill_urbs(desc);
|
||||||
cancel_work_sync(&desc->rxwork);
|
cancel_work_sync(&desc->rxwork);
|
||||||
|
cancel_work_sync(&desc->service_outs_intr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,6 +292,7 @@ static void usblp_bulk_read(struct urb *urb)
|
|||||||
{
|
{
|
||||||
struct usblp *usblp = urb->context;
|
struct usblp *usblp = urb->context;
|
||||||
int status = urb->status;
|
int status = urb->status;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
if (usblp->present && usblp->used) {
|
if (usblp->present && usblp->used) {
|
||||||
if (status)
|
if (status)
|
||||||
@ -299,14 +300,14 @@ static void usblp_bulk_read(struct urb *urb)
|
|||||||
"nonzero read bulk status received: %d\n",
|
"nonzero read bulk status received: %d\n",
|
||||||
usblp->minor, status);
|
usblp->minor, status);
|
||||||
}
|
}
|
||||||
spin_lock(&usblp->lock);
|
spin_lock_irqsave(&usblp->lock, flags);
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
usblp->rstatus = status;
|
usblp->rstatus = status;
|
||||||
else
|
else
|
||||||
usblp->rstatus = urb->actual_length;
|
usblp->rstatus = urb->actual_length;
|
||||||
usblp->rcomplete = 1;
|
usblp->rcomplete = 1;
|
||||||
wake_up(&usblp->rwait);
|
wake_up(&usblp->rwait);
|
||||||
spin_unlock(&usblp->lock);
|
spin_unlock_irqrestore(&usblp->lock, flags);
|
||||||
|
|
||||||
usb_free_urb(urb);
|
usb_free_urb(urb);
|
||||||
}
|
}
|
||||||
@ -315,6 +316,7 @@ static void usblp_bulk_write(struct urb *urb)
|
|||||||
{
|
{
|
||||||
struct usblp *usblp = urb->context;
|
struct usblp *usblp = urb->context;
|
||||||
int status = urb->status;
|
int status = urb->status;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
if (usblp->present && usblp->used) {
|
if (usblp->present && usblp->used) {
|
||||||
if (status)
|
if (status)
|
||||||
@ -322,7 +324,7 @@ static void usblp_bulk_write(struct urb *urb)
|
|||||||
"nonzero write bulk status received: %d\n",
|
"nonzero write bulk status received: %d\n",
|
||||||
usblp->minor, status);
|
usblp->minor, status);
|
||||||
}
|
}
|
||||||
spin_lock(&usblp->lock);
|
spin_lock_irqsave(&usblp->lock, flags);
|
||||||
if (status < 0)
|
if (status < 0)
|
||||||
usblp->wstatus = status;
|
usblp->wstatus = status;
|
||||||
else
|
else
|
||||||
@ -330,7 +332,7 @@ static void usblp_bulk_write(struct urb *urb)
|
|||||||
usblp->no_paper = 0;
|
usblp->no_paper = 0;
|
||||||
usblp->wcomplete = 1;
|
usblp->wcomplete = 1;
|
||||||
wake_up(&usblp->wwait);
|
wake_up(&usblp->wwait);
|
||||||
spin_unlock(&usblp->lock);
|
spin_unlock_irqrestore(&usblp->lock, flags);
|
||||||
|
|
||||||
usb_free_urb(urb);
|
usb_free_urb(urb);
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include <linux/poll.h>
|
#include <linux/poll.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/usb.h>
|
#include <linux/usb.h>
|
||||||
|
#include <linux/compat.h>
|
||||||
#include <linux/usb/tmc.h>
|
#include <linux/usb/tmc.h>
|
||||||
|
|
||||||
|
|
||||||
@ -30,6 +31,8 @@
|
|||||||
*/
|
*/
|
||||||
#define USBTMC_SIZE_IOBUFFER 2048
|
#define USBTMC_SIZE_IOBUFFER 2048
|
||||||
|
|
||||||
|
/* Minimum USB timeout (in milliseconds) */
|
||||||
|
#define USBTMC_MIN_TIMEOUT 100
|
||||||
/* Default USB timeout (in milliseconds) */
|
/* Default USB timeout (in milliseconds) */
|
||||||
#define USBTMC_TIMEOUT 5000
|
#define USBTMC_TIMEOUT 5000
|
||||||
|
|
||||||
@ -67,6 +70,7 @@ struct usbtmc_device_data {
|
|||||||
const struct usb_device_id *id;
|
const struct usb_device_id *id;
|
||||||
struct usb_device *usb_dev;
|
struct usb_device *usb_dev;
|
||||||
struct usb_interface *intf;
|
struct usb_interface *intf;
|
||||||
|
struct list_head file_list;
|
||||||
|
|
||||||
unsigned int bulk_in;
|
unsigned int bulk_in;
|
||||||
unsigned int bulk_out;
|
unsigned int bulk_out;
|
||||||
@ -87,7 +91,6 @@ struct usbtmc_device_data {
|
|||||||
int iin_interval;
|
int iin_interval;
|
||||||
struct urb *iin_urb;
|
struct urb *iin_urb;
|
||||||
u16 iin_wMaxPacketSize;
|
u16 iin_wMaxPacketSize;
|
||||||
atomic_t srq_asserted;
|
|
||||||
|
|
||||||
/* coalesced usb488_caps from usbtmc_dev_capabilities */
|
/* coalesced usb488_caps from usbtmc_dev_capabilities */
|
||||||
__u8 usb488_caps;
|
__u8 usb488_caps;
|
||||||
@ -104,9 +107,25 @@ struct usbtmc_device_data {
|
|||||||
struct mutex io_mutex; /* only one i/o function running at a time */
|
struct mutex io_mutex; /* only one i/o function running at a time */
|
||||||
wait_queue_head_t waitq;
|
wait_queue_head_t waitq;
|
||||||
struct fasync_struct *fasync;
|
struct fasync_struct *fasync;
|
||||||
|
spinlock_t dev_lock; /* lock for file_list */
|
||||||
};
|
};
|
||||||
#define to_usbtmc_data(d) container_of(d, struct usbtmc_device_data, kref)
|
#define to_usbtmc_data(d) container_of(d, struct usbtmc_device_data, kref)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This structure holds private data for each USBTMC file handle.
|
||||||
|
*/
|
||||||
|
struct usbtmc_file_data {
|
||||||
|
struct usbtmc_device_data *data;
|
||||||
|
struct list_head file_elem;
|
||||||
|
|
||||||
|
u32 timeout;
|
||||||
|
u8 srq_byte;
|
||||||
|
atomic_t srq_asserted;
|
||||||
|
u8 eom_val;
|
||||||
|
u8 term_char;
|
||||||
|
bool term_char_enabled;
|
||||||
|
};
|
||||||
|
|
||||||
/* Forward declarations */
|
/* Forward declarations */
|
||||||
static struct usb_driver usbtmc_driver;
|
static struct usb_driver usbtmc_driver;
|
||||||
|
|
||||||
@ -122,7 +141,7 @@ static int usbtmc_open(struct inode *inode, struct file *filp)
|
|||||||
{
|
{
|
||||||
struct usb_interface *intf;
|
struct usb_interface *intf;
|
||||||
struct usbtmc_device_data *data;
|
struct usbtmc_device_data *data;
|
||||||
int retval = 0;
|
struct usbtmc_file_data *file_data;
|
||||||
|
|
||||||
intf = usb_find_interface(&usbtmc_driver, iminor(inode));
|
intf = usb_find_interface(&usbtmc_driver, iminor(inode));
|
||||||
if (!intf) {
|
if (!intf) {
|
||||||
@ -130,21 +149,51 @@ static int usbtmc_open(struct inode *inode, struct file *filp)
|
|||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
file_data = kzalloc(sizeof(*file_data), GFP_KERNEL);
|
||||||
|
if (!file_data)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
data = usb_get_intfdata(intf);
|
data = usb_get_intfdata(intf);
|
||||||
/* Protect reference to data from file structure until release */
|
/* Protect reference to data from file structure until release */
|
||||||
kref_get(&data->kref);
|
kref_get(&data->kref);
|
||||||
|
|
||||||
/* Store pointer in file structure's private data field */
|
mutex_lock(&data->io_mutex);
|
||||||
filp->private_data = data;
|
file_data->data = data;
|
||||||
|
|
||||||
return retval;
|
/* copy default values from device settings */
|
||||||
|
file_data->timeout = USBTMC_TIMEOUT;
|
||||||
|
file_data->term_char = data->TermChar;
|
||||||
|
file_data->term_char_enabled = data->TermCharEnabled;
|
||||||
|
file_data->eom_val = 1;
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&file_data->file_elem);
|
||||||
|
spin_lock_irq(&data->dev_lock);
|
||||||
|
list_add_tail(&file_data->file_elem, &data->file_list);
|
||||||
|
spin_unlock_irq(&data->dev_lock);
|
||||||
|
mutex_unlock(&data->io_mutex);
|
||||||
|
|
||||||
|
/* Store pointer in file structure's private data field */
|
||||||
|
filp->private_data = file_data;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int usbtmc_release(struct inode *inode, struct file *file)
|
static int usbtmc_release(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct usbtmc_device_data *data = file->private_data;
|
struct usbtmc_file_data *file_data = file->private_data;
|
||||||
|
|
||||||
kref_put(&data->kref, usbtmc_delete);
|
/* prevent IO _AND_ usbtmc_interrupt */
|
||||||
|
mutex_lock(&file_data->data->io_mutex);
|
||||||
|
spin_lock_irq(&file_data->data->dev_lock);
|
||||||
|
|
||||||
|
list_del(&file_data->file_elem);
|
||||||
|
|
||||||
|
spin_unlock_irq(&file_data->data->dev_lock);
|
||||||
|
mutex_unlock(&file_data->data->io_mutex);
|
||||||
|
|
||||||
|
kref_put(&file_data->data->kref, usbtmc_delete);
|
||||||
|
file_data->data = NULL;
|
||||||
|
kfree(file_data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -369,10 +418,12 @@ exit:
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int usbtmc488_ioctl_read_stb(struct usbtmc_device_data *data,
|
static int usbtmc488_ioctl_read_stb(struct usbtmc_file_data *file_data,
|
||||||
void __user *arg)
|
void __user *arg)
|
||||||
{
|
{
|
||||||
|
struct usbtmc_device_data *data = file_data->data;
|
||||||
struct device *dev = &data->intf->dev;
|
struct device *dev = &data->intf->dev;
|
||||||
|
int srq_asserted = 0;
|
||||||
u8 *buffer;
|
u8 *buffer;
|
||||||
u8 tag;
|
u8 tag;
|
||||||
__u8 stb;
|
__u8 stb;
|
||||||
@ -381,15 +432,25 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_device_data *data,
|
|||||||
dev_dbg(dev, "Enter ioctl_read_stb iin_ep_present: %d\n",
|
dev_dbg(dev, "Enter ioctl_read_stb iin_ep_present: %d\n",
|
||||||
data->iin_ep_present);
|
data->iin_ep_present);
|
||||||
|
|
||||||
|
spin_lock_irq(&data->dev_lock);
|
||||||
|
srq_asserted = atomic_xchg(&file_data->srq_asserted, srq_asserted);
|
||||||
|
if (srq_asserted) {
|
||||||
|
/* a STB with SRQ is already received */
|
||||||
|
stb = file_data->srq_byte;
|
||||||
|
spin_unlock_irq(&data->dev_lock);
|
||||||
|
rv = put_user(stb, (__u8 __user *)arg);
|
||||||
|
dev_dbg(dev, "stb:0x%02x with srq received %d\n",
|
||||||
|
(unsigned int)stb, rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
spin_unlock_irq(&data->dev_lock);
|
||||||
|
|
||||||
buffer = kmalloc(8, GFP_KERNEL);
|
buffer = kmalloc(8, GFP_KERNEL);
|
||||||
if (!buffer)
|
if (!buffer)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
atomic_set(&data->iin_data_valid, 0);
|
atomic_set(&data->iin_data_valid, 0);
|
||||||
|
|
||||||
/* must issue read_stb before using poll or select */
|
|
||||||
atomic_set(&data->srq_asserted, 0);
|
|
||||||
|
|
||||||
rv = usb_control_msg(data->usb_dev,
|
rv = usb_control_msg(data->usb_dev,
|
||||||
usb_rcvctrlpipe(data->usb_dev, 0),
|
usb_rcvctrlpipe(data->usb_dev, 0),
|
||||||
USBTMC488_REQUEST_READ_STATUS_BYTE,
|
USBTMC488_REQUEST_READ_STATUS_BYTE,
|
||||||
@ -412,7 +473,7 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_device_data *data,
|
|||||||
rv = wait_event_interruptible_timeout(
|
rv = wait_event_interruptible_timeout(
|
||||||
data->waitq,
|
data->waitq,
|
||||||
atomic_read(&data->iin_data_valid) != 0,
|
atomic_read(&data->iin_data_valid) != 0,
|
||||||
USBTMC_TIMEOUT);
|
file_data->timeout);
|
||||||
if (rv < 0) {
|
if (rv < 0) {
|
||||||
dev_dbg(dev, "wait interrupted %d\n", rv);
|
dev_dbg(dev, "wait interrupted %d\n", rv);
|
||||||
goto exit;
|
goto exit;
|
||||||
@ -420,7 +481,7 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_device_data *data,
|
|||||||
|
|
||||||
if (rv == 0) {
|
if (rv == 0) {
|
||||||
dev_dbg(dev, "wait timed out\n");
|
dev_dbg(dev, "wait timed out\n");
|
||||||
rv = -ETIME;
|
rv = -ETIMEDOUT;
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -435,9 +496,8 @@ static int usbtmc488_ioctl_read_stb(struct usbtmc_device_data *data,
|
|||||||
stb = buffer[2];
|
stb = buffer[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = copy_to_user(arg, &stb, sizeof(stb));
|
rv = put_user(stb, (__u8 __user *)arg);
|
||||||
if (rv)
|
dev_dbg(dev, "stb:0x%02x received %d\n", (unsigned int)stb, rv);
|
||||||
rv = -EFAULT;
|
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
/* bump interrupt bTag */
|
/* bump interrupt bTag */
|
||||||
@ -505,6 +565,51 @@ static int usbtmc488_ioctl_simple(struct usbtmc_device_data *data,
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sends a TRIGGER Bulk-OUT command message
|
||||||
|
* See the USBTMC-USB488 specification, Table 2.
|
||||||
|
*
|
||||||
|
* Also updates bTag_last_write.
|
||||||
|
*/
|
||||||
|
static int usbtmc488_ioctl_trigger(struct usbtmc_file_data *file_data)
|
||||||
|
{
|
||||||
|
struct usbtmc_device_data *data = file_data->data;
|
||||||
|
int retval;
|
||||||
|
u8 *buffer;
|
||||||
|
int actual;
|
||||||
|
|
||||||
|
buffer = kzalloc(USBTMC_HEADER_SIZE, GFP_KERNEL);
|
||||||
|
if (!buffer)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
buffer[0] = 128;
|
||||||
|
buffer[1] = data->bTag;
|
||||||
|
buffer[2] = ~data->bTag;
|
||||||
|
|
||||||
|
retval = usb_bulk_msg(data->usb_dev,
|
||||||
|
usb_sndbulkpipe(data->usb_dev,
|
||||||
|
data->bulk_out),
|
||||||
|
buffer, USBTMC_HEADER_SIZE,
|
||||||
|
&actual, file_data->timeout);
|
||||||
|
|
||||||
|
/* Store bTag (in case we need to abort) */
|
||||||
|
data->bTag_last_write = data->bTag;
|
||||||
|
|
||||||
|
/* Increment bTag -- and increment again if zero */
|
||||||
|
data->bTag++;
|
||||||
|
if (!data->bTag)
|
||||||
|
data->bTag++;
|
||||||
|
|
||||||
|
kfree(buffer);
|
||||||
|
if (retval < 0) {
|
||||||
|
dev_err(&data->intf->dev, "%s returned %d\n",
|
||||||
|
__func__, retval);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sends a REQUEST_DEV_DEP_MSG_IN message on the Bulk-OUT endpoint.
|
* Sends a REQUEST_DEV_DEP_MSG_IN message on the Bulk-OUT endpoint.
|
||||||
* @transfer_size: number of bytes to request from the device.
|
* @transfer_size: number of bytes to request from the device.
|
||||||
@ -513,8 +618,10 @@ static int usbtmc488_ioctl_simple(struct usbtmc_device_data *data,
|
|||||||
*
|
*
|
||||||
* Also updates bTag_last_write.
|
* Also updates bTag_last_write.
|
||||||
*/
|
*/
|
||||||
static int send_request_dev_dep_msg_in(struct usbtmc_device_data *data, size_t transfer_size)
|
static int send_request_dev_dep_msg_in(struct usbtmc_file_data *file_data,
|
||||||
|
size_t transfer_size)
|
||||||
{
|
{
|
||||||
|
struct usbtmc_device_data *data = file_data->data;
|
||||||
int retval;
|
int retval;
|
||||||
u8 *buffer;
|
u8 *buffer;
|
||||||
int actual;
|
int actual;
|
||||||
@ -533,9 +640,9 @@ static int send_request_dev_dep_msg_in(struct usbtmc_device_data *data, size_t t
|
|||||||
buffer[5] = transfer_size >> 8;
|
buffer[5] = transfer_size >> 8;
|
||||||
buffer[6] = transfer_size >> 16;
|
buffer[6] = transfer_size >> 16;
|
||||||
buffer[7] = transfer_size >> 24;
|
buffer[7] = transfer_size >> 24;
|
||||||
buffer[8] = data->TermCharEnabled * 2;
|
buffer[8] = file_data->term_char_enabled * 2;
|
||||||
/* Use term character? */
|
/* Use term character? */
|
||||||
buffer[9] = data->TermChar;
|
buffer[9] = file_data->term_char;
|
||||||
buffer[10] = 0; /* Reserved */
|
buffer[10] = 0; /* Reserved */
|
||||||
buffer[11] = 0; /* Reserved */
|
buffer[11] = 0; /* Reserved */
|
||||||
|
|
||||||
@ -543,7 +650,8 @@ static int send_request_dev_dep_msg_in(struct usbtmc_device_data *data, size_t t
|
|||||||
retval = usb_bulk_msg(data->usb_dev,
|
retval = usb_bulk_msg(data->usb_dev,
|
||||||
usb_sndbulkpipe(data->usb_dev,
|
usb_sndbulkpipe(data->usb_dev,
|
||||||
data->bulk_out),
|
data->bulk_out),
|
||||||
buffer, USBTMC_HEADER_SIZE, &actual, USBTMC_TIMEOUT);
|
buffer, USBTMC_HEADER_SIZE,
|
||||||
|
&actual, file_data->timeout);
|
||||||
|
|
||||||
/* Store bTag (in case we need to abort) */
|
/* Store bTag (in case we need to abort) */
|
||||||
data->bTag_last_write = data->bTag;
|
data->bTag_last_write = data->bTag;
|
||||||
@ -565,6 +673,7 @@ static int send_request_dev_dep_msg_in(struct usbtmc_device_data *data, size_t t
|
|||||||
static ssize_t usbtmc_read(struct file *filp, char __user *buf,
|
static ssize_t usbtmc_read(struct file *filp, char __user *buf,
|
||||||
size_t count, loff_t *f_pos)
|
size_t count, loff_t *f_pos)
|
||||||
{
|
{
|
||||||
|
struct usbtmc_file_data *file_data;
|
||||||
struct usbtmc_device_data *data;
|
struct usbtmc_device_data *data;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
u32 n_characters;
|
u32 n_characters;
|
||||||
@ -576,7 +685,8 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
|
|||||||
size_t this_part;
|
size_t this_part;
|
||||||
|
|
||||||
/* Get pointer to private data structure */
|
/* Get pointer to private data structure */
|
||||||
data = filp->private_data;
|
file_data = filp->private_data;
|
||||||
|
data = file_data->data;
|
||||||
dev = &data->intf->dev;
|
dev = &data->intf->dev;
|
||||||
|
|
||||||
buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL);
|
buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL);
|
||||||
@ -591,7 +701,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
|
|||||||
|
|
||||||
dev_dbg(dev, "usb_bulk_msg_in: count(%zu)\n", count);
|
dev_dbg(dev, "usb_bulk_msg_in: count(%zu)\n", count);
|
||||||
|
|
||||||
retval = send_request_dev_dep_msg_in(data, count);
|
retval = send_request_dev_dep_msg_in(file_data, count);
|
||||||
|
|
||||||
if (retval < 0) {
|
if (retval < 0) {
|
||||||
if (data->auto_abort)
|
if (data->auto_abort)
|
||||||
@ -610,7 +720,7 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
|
|||||||
usb_rcvbulkpipe(data->usb_dev,
|
usb_rcvbulkpipe(data->usb_dev,
|
||||||
data->bulk_in),
|
data->bulk_in),
|
||||||
buffer, USBTMC_SIZE_IOBUFFER, &actual,
|
buffer, USBTMC_SIZE_IOBUFFER, &actual,
|
||||||
USBTMC_TIMEOUT);
|
file_data->timeout);
|
||||||
|
|
||||||
dev_dbg(dev, "usb_bulk_msg: retval(%u), done(%zu), remaining(%zu), actual(%d)\n", retval, done, remaining, actual);
|
dev_dbg(dev, "usb_bulk_msg: retval(%u), done(%zu), remaining(%zu), actual(%d)\n", retval, done, remaining, actual);
|
||||||
|
|
||||||
@ -721,6 +831,7 @@ exit:
|
|||||||
static ssize_t usbtmc_write(struct file *filp, const char __user *buf,
|
static ssize_t usbtmc_write(struct file *filp, const char __user *buf,
|
||||||
size_t count, loff_t *f_pos)
|
size_t count, loff_t *f_pos)
|
||||||
{
|
{
|
||||||
|
struct usbtmc_file_data *file_data;
|
||||||
struct usbtmc_device_data *data;
|
struct usbtmc_device_data *data;
|
||||||
u8 *buffer;
|
u8 *buffer;
|
||||||
int retval;
|
int retval;
|
||||||
@ -730,7 +841,8 @@ static ssize_t usbtmc_write(struct file *filp, const char __user *buf,
|
|||||||
int done;
|
int done;
|
||||||
int this_part;
|
int this_part;
|
||||||
|
|
||||||
data = filp->private_data;
|
file_data = filp->private_data;
|
||||||
|
data = file_data->data;
|
||||||
|
|
||||||
buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL);
|
buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL);
|
||||||
if (!buffer)
|
if (!buffer)
|
||||||
@ -751,7 +863,7 @@ static ssize_t usbtmc_write(struct file *filp, const char __user *buf,
|
|||||||
buffer[8] = 0;
|
buffer[8] = 0;
|
||||||
} else {
|
} else {
|
||||||
this_part = remaining;
|
this_part = remaining;
|
||||||
buffer[8] = 1;
|
buffer[8] = file_data->eom_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup IO buffer for DEV_DEP_MSG_OUT message */
|
/* Setup IO buffer for DEV_DEP_MSG_OUT message */
|
||||||
@ -781,7 +893,7 @@ static ssize_t usbtmc_write(struct file *filp, const char __user *buf,
|
|||||||
usb_sndbulkpipe(data->usb_dev,
|
usb_sndbulkpipe(data->usb_dev,
|
||||||
data->bulk_out),
|
data->bulk_out),
|
||||||
buffer, n_bytes,
|
buffer, n_bytes,
|
||||||
&actual, USBTMC_TIMEOUT);
|
&actual, file_data->timeout);
|
||||||
if (retval != 0)
|
if (retval != 0)
|
||||||
break;
|
break;
|
||||||
n_bytes -= actual;
|
n_bytes -= actual;
|
||||||
@ -1138,12 +1250,91 @@ exit:
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the usb timeout value
|
||||||
|
*/
|
||||||
|
static int usbtmc_ioctl_get_timeout(struct usbtmc_file_data *file_data,
|
||||||
|
void __user *arg)
|
||||||
|
{
|
||||||
|
u32 timeout;
|
||||||
|
|
||||||
|
timeout = file_data->timeout;
|
||||||
|
|
||||||
|
return put_user(timeout, (__u32 __user *)arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the usb timeout value
|
||||||
|
*/
|
||||||
|
static int usbtmc_ioctl_set_timeout(struct usbtmc_file_data *file_data,
|
||||||
|
void __user *arg)
|
||||||
|
{
|
||||||
|
u32 timeout;
|
||||||
|
|
||||||
|
if (get_user(timeout, (__u32 __user *)arg))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
/* Note that timeout = 0 means
|
||||||
|
* MAX_SCHEDULE_TIMEOUT in usb_control_msg
|
||||||
|
*/
|
||||||
|
if (timeout < USBTMC_MIN_TIMEOUT)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
file_data->timeout = timeout;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* enables/disables sending EOM on write
|
||||||
|
*/
|
||||||
|
static int usbtmc_ioctl_eom_enable(struct usbtmc_file_data *file_data,
|
||||||
|
void __user *arg)
|
||||||
|
{
|
||||||
|
u8 eom_enable;
|
||||||
|
|
||||||
|
if (copy_from_user(&eom_enable, arg, sizeof(eom_enable)))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if (eom_enable > 1)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
file_data->eom_val = eom_enable;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configure termination character for read()
|
||||||
|
*/
|
||||||
|
static int usbtmc_ioctl_config_termc(struct usbtmc_file_data *file_data,
|
||||||
|
void __user *arg)
|
||||||
|
{
|
||||||
|
struct usbtmc_termchar termc;
|
||||||
|
|
||||||
|
if (copy_from_user(&termc, arg, sizeof(termc)))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
if ((termc.term_char_enabled > 1) ||
|
||||||
|
(termc.term_char_enabled &&
|
||||||
|
!(file_data->data->capabilities.device_capabilities & 1)))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
file_data->term_char = termc.term_char;
|
||||||
|
file_data->term_char_enabled = termc.term_char_enabled;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
|
struct usbtmc_file_data *file_data;
|
||||||
struct usbtmc_device_data *data;
|
struct usbtmc_device_data *data;
|
||||||
int retval = -EBADRQC;
|
int retval = -EBADRQC;
|
||||||
|
|
||||||
data = file->private_data;
|
file_data = file->private_data;
|
||||||
|
data = file_data->data;
|
||||||
|
|
||||||
mutex_lock(&data->io_mutex);
|
mutex_lock(&data->io_mutex);
|
||||||
if (data->zombie) {
|
if (data->zombie) {
|
||||||
retval = -ENODEV;
|
retval = -ENODEV;
|
||||||
@ -1175,6 +1366,26 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||||||
retval = usbtmc_ioctl_abort_bulk_in(data);
|
retval = usbtmc_ioctl_abort_bulk_in(data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case USBTMC_IOCTL_GET_TIMEOUT:
|
||||||
|
retval = usbtmc_ioctl_get_timeout(file_data,
|
||||||
|
(void __user *)arg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USBTMC_IOCTL_SET_TIMEOUT:
|
||||||
|
retval = usbtmc_ioctl_set_timeout(file_data,
|
||||||
|
(void __user *)arg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USBTMC_IOCTL_EOM_ENABLE:
|
||||||
|
retval = usbtmc_ioctl_eom_enable(file_data,
|
||||||
|
(void __user *)arg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case USBTMC_IOCTL_CONFIG_TERMCHAR:
|
||||||
|
retval = usbtmc_ioctl_config_termc(file_data,
|
||||||
|
(void __user *)arg);
|
||||||
|
break;
|
||||||
|
|
||||||
case USBTMC488_IOCTL_GET_CAPS:
|
case USBTMC488_IOCTL_GET_CAPS:
|
||||||
retval = copy_to_user((void __user *)arg,
|
retval = copy_to_user((void __user *)arg,
|
||||||
&data->usb488_caps,
|
&data->usb488_caps,
|
||||||
@ -1184,7 +1395,8 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case USBTMC488_IOCTL_READ_STB:
|
case USBTMC488_IOCTL_READ_STB:
|
||||||
retval = usbtmc488_ioctl_read_stb(data, (void __user *)arg);
|
retval = usbtmc488_ioctl_read_stb(file_data,
|
||||||
|
(void __user *)arg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case USBTMC488_IOCTL_REN_CONTROL:
|
case USBTMC488_IOCTL_REN_CONTROL:
|
||||||
@ -1201,6 +1413,10 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||||||
retval = usbtmc488_ioctl_simple(data, (void __user *)arg,
|
retval = usbtmc488_ioctl_simple(data, (void __user *)arg,
|
||||||
USBTMC488_REQUEST_LOCAL_LOCKOUT);
|
USBTMC488_REQUEST_LOCAL_LOCKOUT);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case USBTMC488_IOCTL_TRIGGER:
|
||||||
|
retval = usbtmc488_ioctl_trigger(file_data);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
skip_io_on_zombie:
|
skip_io_on_zombie:
|
||||||
@ -1210,14 +1426,15 @@ skip_io_on_zombie:
|
|||||||
|
|
||||||
static int usbtmc_fasync(int fd, struct file *file, int on)
|
static int usbtmc_fasync(int fd, struct file *file, int on)
|
||||||
{
|
{
|
||||||
struct usbtmc_device_data *data = file->private_data;
|
struct usbtmc_file_data *file_data = file->private_data;
|
||||||
|
|
||||||
return fasync_helper(fd, file, on, &data->fasync);
|
return fasync_helper(fd, file, on, &file_data->data->fasync);
|
||||||
}
|
}
|
||||||
|
|
||||||
static __poll_t usbtmc_poll(struct file *file, poll_table *wait)
|
static __poll_t usbtmc_poll(struct file *file, poll_table *wait)
|
||||||
{
|
{
|
||||||
struct usbtmc_device_data *data = file->private_data;
|
struct usbtmc_file_data *file_data = file->private_data;
|
||||||
|
struct usbtmc_device_data *data = file_data->data;
|
||||||
__poll_t mask;
|
__poll_t mask;
|
||||||
|
|
||||||
mutex_lock(&data->io_mutex);
|
mutex_lock(&data->io_mutex);
|
||||||
@ -1229,7 +1446,7 @@ static __poll_t usbtmc_poll(struct file *file, poll_table *wait)
|
|||||||
|
|
||||||
poll_wait(file, &data->waitq, wait);
|
poll_wait(file, &data->waitq, wait);
|
||||||
|
|
||||||
mask = (atomic_read(&data->srq_asserted)) ? EPOLLIN | EPOLLRDNORM : 0;
|
mask = (atomic_read(&file_data->srq_asserted)) ? EPOLLPRI : 0;
|
||||||
|
|
||||||
no_poll:
|
no_poll:
|
||||||
mutex_unlock(&data->io_mutex);
|
mutex_unlock(&data->io_mutex);
|
||||||
@ -1243,6 +1460,9 @@ static const struct file_operations fops = {
|
|||||||
.open = usbtmc_open,
|
.open = usbtmc_open,
|
||||||
.release = usbtmc_release,
|
.release = usbtmc_release,
|
||||||
.unlocked_ioctl = usbtmc_ioctl,
|
.unlocked_ioctl = usbtmc_ioctl,
|
||||||
|
#ifdef CONFIG_COMPAT
|
||||||
|
.compat_ioctl = usbtmc_ioctl,
|
||||||
|
#endif
|
||||||
.fasync = usbtmc_fasync,
|
.fasync = usbtmc_fasync,
|
||||||
.poll = usbtmc_poll,
|
.poll = usbtmc_poll,
|
||||||
.llseek = default_llseek,
|
.llseek = default_llseek,
|
||||||
@ -1276,15 +1496,33 @@ static void usbtmc_interrupt(struct urb *urb)
|
|||||||
}
|
}
|
||||||
/* check for SRQ notification */
|
/* check for SRQ notification */
|
||||||
if (data->iin_buffer[0] == 0x81) {
|
if (data->iin_buffer[0] == 0x81) {
|
||||||
|
unsigned long flags;
|
||||||
|
struct list_head *elem;
|
||||||
|
|
||||||
if (data->fasync)
|
if (data->fasync)
|
||||||
kill_fasync(&data->fasync,
|
kill_fasync(&data->fasync,
|
||||||
SIGIO, POLL_IN);
|
SIGIO, POLL_PRI);
|
||||||
|
|
||||||
atomic_set(&data->srq_asserted, 1);
|
spin_lock_irqsave(&data->dev_lock, flags);
|
||||||
wake_up_interruptible(&data->waitq);
|
list_for_each(elem, &data->file_list) {
|
||||||
|
struct usbtmc_file_data *file_data;
|
||||||
|
|
||||||
|
file_data = list_entry(elem,
|
||||||
|
struct usbtmc_file_data,
|
||||||
|
file_elem);
|
||||||
|
file_data->srq_byte = data->iin_buffer[1];
|
||||||
|
atomic_set(&file_data->srq_asserted, 1);
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&data->dev_lock, flags);
|
||||||
|
|
||||||
|
dev_dbg(dev, "srq received bTag %x stb %x\n",
|
||||||
|
(unsigned int)data->iin_buffer[0],
|
||||||
|
(unsigned int)data->iin_buffer[1]);
|
||||||
|
wake_up_interruptible_all(&data->waitq);
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
dev_warn(dev, "invalid notification: %x\n", data->iin_buffer[0]);
|
dev_warn(dev, "invalid notification: %x\n",
|
||||||
|
data->iin_buffer[0]);
|
||||||
break;
|
break;
|
||||||
case -EOVERFLOW:
|
case -EOVERFLOW:
|
||||||
dev_err(dev, "overflow with length %d, actual length is %d\n",
|
dev_err(dev, "overflow with length %d, actual length is %d\n",
|
||||||
@ -1295,6 +1533,7 @@ static void usbtmc_interrupt(struct urb *urb)
|
|||||||
case -ESHUTDOWN:
|
case -ESHUTDOWN:
|
||||||
case -EILSEQ:
|
case -EILSEQ:
|
||||||
case -ETIME:
|
case -ETIME:
|
||||||
|
case -EPIPE:
|
||||||
/* urb terminated, clean up */
|
/* urb terminated, clean up */
|
||||||
dev_dbg(dev, "urb terminated, status: %d\n", status);
|
dev_dbg(dev, "urb terminated, status: %d\n", status);
|
||||||
return;
|
return;
|
||||||
@ -1339,7 +1578,9 @@ static int usbtmc_probe(struct usb_interface *intf,
|
|||||||
mutex_init(&data->io_mutex);
|
mutex_init(&data->io_mutex);
|
||||||
init_waitqueue_head(&data->waitq);
|
init_waitqueue_head(&data->waitq);
|
||||||
atomic_set(&data->iin_data_valid, 0);
|
atomic_set(&data->iin_data_valid, 0);
|
||||||
atomic_set(&data->srq_asserted, 0);
|
INIT_LIST_HEAD(&data->file_list);
|
||||||
|
spin_lock_init(&data->dev_lock);
|
||||||
|
|
||||||
data->zombie = 0;
|
data->zombie = 0;
|
||||||
|
|
||||||
/* Initialize USBTMC bTag and other fields */
|
/* Initialize USBTMC bTag and other fields */
|
||||||
@ -1442,17 +1683,14 @@ err_put:
|
|||||||
|
|
||||||
static void usbtmc_disconnect(struct usb_interface *intf)
|
static void usbtmc_disconnect(struct usb_interface *intf)
|
||||||
{
|
{
|
||||||
struct usbtmc_device_data *data;
|
struct usbtmc_device_data *data = usb_get_intfdata(intf);
|
||||||
|
|
||||||
dev_dbg(&intf->dev, "usbtmc_disconnect called\n");
|
|
||||||
|
|
||||||
data = usb_get_intfdata(intf);
|
|
||||||
usb_deregister_dev(intf, &usbtmc_class);
|
usb_deregister_dev(intf, &usbtmc_class);
|
||||||
sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp);
|
sysfs_remove_group(&intf->dev.kobj, &capability_attr_grp);
|
||||||
sysfs_remove_group(&intf->dev.kobj, &data_attr_grp);
|
sysfs_remove_group(&intf->dev.kobj, &data_attr_grp);
|
||||||
mutex_lock(&data->io_mutex);
|
mutex_lock(&data->io_mutex);
|
||||||
data->zombie = 1;
|
data->zombie = 1;
|
||||||
wake_up_all(&data->waitq);
|
wake_up_interruptible_all(&data->waitq);
|
||||||
mutex_unlock(&data->io_mutex);
|
mutex_unlock(&data->io_mutex);
|
||||||
usbtmc_free_int(data);
|
usbtmc_free_int(data);
|
||||||
kref_put(&data->kref, usbtmc_delete);
|
kref_put(&data->kref, usbtmc_delete);
|
||||||
|
@ -585,9 +585,10 @@ static void async_completed(struct urb *urb)
|
|||||||
struct siginfo sinfo;
|
struct siginfo sinfo;
|
||||||
struct pid *pid = NULL;
|
struct pid *pid = NULL;
|
||||||
const struct cred *cred = NULL;
|
const struct cred *cred = NULL;
|
||||||
|
unsigned long flags;
|
||||||
int signr;
|
int signr;
|
||||||
|
|
||||||
spin_lock(&ps->lock);
|
spin_lock_irqsave(&ps->lock, flags);
|
||||||
list_move_tail(&as->asynclist, &ps->async_completed);
|
list_move_tail(&as->asynclist, &ps->async_completed);
|
||||||
as->status = urb->status;
|
as->status = urb->status;
|
||||||
signr = as->signr;
|
signr = as->signr;
|
||||||
@ -611,7 +612,7 @@ static void async_completed(struct urb *urb)
|
|||||||
cancel_bulk_urbs(ps, as->bulk_addr);
|
cancel_bulk_urbs(ps, as->bulk_addr);
|
||||||
|
|
||||||
wake_up(&ps->wait);
|
wake_up(&ps->wait);
|
||||||
spin_unlock(&ps->lock);
|
spin_unlock_irqrestore(&ps->lock, flags);
|
||||||
|
|
||||||
if (signr) {
|
if (signr) {
|
||||||
kill_pid_info_as_cred(sinfo.si_signo, &sinfo, pid, cred);
|
kill_pid_info_as_cred(sinfo.si_signo, &sinfo, pid, cred);
|
||||||
|
@ -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)
|
|||||||
|
|
||||||
static void sg_complete(struct urb *urb)
|
static void sg_complete(struct urb *urb)
|
||||||
{
|
{
|
||||||
|
unsigned long flags;
|
||||||
struct usb_sg_request *io = urb->context;
|
struct usb_sg_request *io = urb->context;
|
||||||
int status = urb->status;
|
int status = urb->status;
|
||||||
|
|
||||||
spin_lock(&io->lock);
|
spin_lock_irqsave(&io->lock, flags);
|
||||||
|
|
||||||
/* In 2.5 we require hcds' endpoint queues not to progress after fault
|
/* In 2.5 we require hcds' endpoint queues not to progress after fault
|
||||||
* reports, until the completion callback (this!) returns. That lets
|
* reports, until the completion callback (this!) returns. That lets
|
||||||
@ -306,7 +307,7 @@ static void sg_complete(struct urb *urb)
|
|||||||
* unlink pending urbs so they won't rx/tx bad data.
|
* unlink pending urbs so they won't rx/tx bad data.
|
||||||
* careful: unlink can sometimes be synchronous...
|
* careful: unlink can sometimes be synchronous...
|
||||||
*/
|
*/
|
||||||
spin_unlock(&io->lock);
|
spin_unlock_irqrestore(&io->lock, flags);
|
||||||
for (i = 0, found = 0; i < io->entries; i++) {
|
for (i = 0, found = 0; i < io->entries; i++) {
|
||||||
if (!io->urbs[i])
|
if (!io->urbs[i])
|
||||||
continue;
|
continue;
|
||||||
@ -323,7 +324,7 @@ static void sg_complete(struct urb *urb)
|
|||||||
} else if (urb == io->urbs[i])
|
} else if (urb == io->urbs[i])
|
||||||
found = 1;
|
found = 1;
|
||||||
}
|
}
|
||||||
spin_lock(&io->lock);
|
spin_lock_irqsave(&io->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* on the last completion, signal usb_sg_wait() */
|
/* on the last completion, signal usb_sg_wait() */
|
||||||
@ -332,7 +333,7 @@ static void sg_complete(struct urb *urb)
|
|||||||
if (!io->count)
|
if (!io->count)
|
||||||
complete(&io->complete);
|
complete(&io->complete);
|
||||||
|
|
||||||
spin_unlock(&io->lock);
|
spin_unlock_irqrestore(&io->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -73,17 +73,17 @@ int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg)
|
|||||||
/* Backup global regs */
|
/* Backup global regs */
|
||||||
gr = &hsotg->gr_backup;
|
gr = &hsotg->gr_backup;
|
||||||
|
|
||||||
gr->gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
|
gr->gotgctl = dwc2_readl(hsotg, GOTGCTL);
|
||||||
gr->gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
|
gr->gintmsk = dwc2_readl(hsotg, GINTMSK);
|
||||||
gr->gahbcfg = dwc2_readl(hsotg->regs + GAHBCFG);
|
gr->gahbcfg = dwc2_readl(hsotg, GAHBCFG);
|
||||||
gr->gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
|
gr->gusbcfg = dwc2_readl(hsotg, GUSBCFG);
|
||||||
gr->grxfsiz = dwc2_readl(hsotg->regs + GRXFSIZ);
|
gr->grxfsiz = dwc2_readl(hsotg, GRXFSIZ);
|
||||||
gr->gnptxfsiz = dwc2_readl(hsotg->regs + GNPTXFSIZ);
|
gr->gnptxfsiz = dwc2_readl(hsotg, GNPTXFSIZ);
|
||||||
gr->gdfifocfg = dwc2_readl(hsotg->regs + GDFIFOCFG);
|
gr->gdfifocfg = dwc2_readl(hsotg, GDFIFOCFG);
|
||||||
gr->pcgcctl1 = dwc2_readl(hsotg->regs + PCGCCTL1);
|
gr->pcgcctl1 = dwc2_readl(hsotg, PCGCCTL1);
|
||||||
gr->glpmcfg = dwc2_readl(hsotg->regs + GLPMCFG);
|
gr->glpmcfg = dwc2_readl(hsotg, GLPMCFG);
|
||||||
gr->gi2cctl = dwc2_readl(hsotg->regs + GI2CCTL);
|
gr->gi2cctl = dwc2_readl(hsotg, GI2CCTL);
|
||||||
gr->pcgcctl = dwc2_readl(hsotg->regs + PCGCTL);
|
gr->pcgcctl = dwc2_readl(hsotg, PCGCTL);
|
||||||
|
|
||||||
gr->valid = true;
|
gr->valid = true;
|
||||||
return 0;
|
return 0;
|
||||||
@ -111,18 +111,18 @@ int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg)
|
|||||||
}
|
}
|
||||||
gr->valid = false;
|
gr->valid = false;
|
||||||
|
|
||||||
dwc2_writel(0xffffffff, hsotg->regs + GINTSTS);
|
dwc2_writel(hsotg, 0xffffffff, GINTSTS);
|
||||||
dwc2_writel(gr->gotgctl, hsotg->regs + GOTGCTL);
|
dwc2_writel(hsotg, gr->gotgctl, GOTGCTL);
|
||||||
dwc2_writel(gr->gintmsk, hsotg->regs + GINTMSK);
|
dwc2_writel(hsotg, gr->gintmsk, GINTMSK);
|
||||||
dwc2_writel(gr->gusbcfg, hsotg->regs + GUSBCFG);
|
dwc2_writel(hsotg, gr->gusbcfg, GUSBCFG);
|
||||||
dwc2_writel(gr->gahbcfg, hsotg->regs + GAHBCFG);
|
dwc2_writel(hsotg, gr->gahbcfg, GAHBCFG);
|
||||||
dwc2_writel(gr->grxfsiz, hsotg->regs + GRXFSIZ);
|
dwc2_writel(hsotg, gr->grxfsiz, GRXFSIZ);
|
||||||
dwc2_writel(gr->gnptxfsiz, hsotg->regs + GNPTXFSIZ);
|
dwc2_writel(hsotg, gr->gnptxfsiz, GNPTXFSIZ);
|
||||||
dwc2_writel(gr->gdfifocfg, hsotg->regs + GDFIFOCFG);
|
dwc2_writel(hsotg, gr->gdfifocfg, GDFIFOCFG);
|
||||||
dwc2_writel(gr->pcgcctl1, hsotg->regs + PCGCCTL1);
|
dwc2_writel(hsotg, gr->pcgcctl1, PCGCCTL1);
|
||||||
dwc2_writel(gr->glpmcfg, hsotg->regs + GLPMCFG);
|
dwc2_writel(hsotg, gr->glpmcfg, GLPMCFG);
|
||||||
dwc2_writel(gr->pcgcctl, hsotg->regs + PCGCTL);
|
dwc2_writel(hsotg, gr->pcgcctl, PCGCTL);
|
||||||
dwc2_writel(gr->gi2cctl, hsotg->regs + GI2CCTL);
|
dwc2_writel(hsotg, gr->gi2cctl, GI2CCTL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -141,17 +141,17 @@ int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, bool restore)
|
|||||||
if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_PARTIAL)
|
if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_PARTIAL)
|
||||||
return -ENOTSUPP;
|
return -ENOTSUPP;
|
||||||
|
|
||||||
pcgcctl = dwc2_readl(hsotg->regs + PCGCTL);
|
pcgcctl = dwc2_readl(hsotg, PCGCTL);
|
||||||
pcgcctl &= ~PCGCTL_STOPPCLK;
|
pcgcctl &= ~PCGCTL_STOPPCLK;
|
||||||
dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
|
dwc2_writel(hsotg, pcgcctl, PCGCTL);
|
||||||
|
|
||||||
pcgcctl = dwc2_readl(hsotg->regs + PCGCTL);
|
pcgcctl = dwc2_readl(hsotg, PCGCTL);
|
||||||
pcgcctl &= ~PCGCTL_PWRCLMP;
|
pcgcctl &= ~PCGCTL_PWRCLMP;
|
||||||
dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
|
dwc2_writel(hsotg, pcgcctl, PCGCTL);
|
||||||
|
|
||||||
pcgcctl = dwc2_readl(hsotg->regs + PCGCTL);
|
pcgcctl = dwc2_readl(hsotg, PCGCTL);
|
||||||
pcgcctl &= ~PCGCTL_RSTPDWNMODULE;
|
pcgcctl &= ~PCGCTL_RSTPDWNMODULE;
|
||||||
dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
|
dwc2_writel(hsotg, pcgcctl, PCGCTL);
|
||||||
|
|
||||||
udelay(100);
|
udelay(100);
|
||||||
if (restore) {
|
if (restore) {
|
||||||
@ -222,21 +222,21 @@ int dwc2_enter_partial_power_down(struct dwc2_hsotg *hsotg)
|
|||||||
* Clear any pending interrupts since dwc2 will not be able to
|
* Clear any pending interrupts since dwc2 will not be able to
|
||||||
* clear them after entering partial_power_down.
|
* clear them after entering partial_power_down.
|
||||||
*/
|
*/
|
||||||
dwc2_writel(0xffffffff, hsotg->regs + GINTSTS);
|
dwc2_writel(hsotg, 0xffffffff, GINTSTS);
|
||||||
|
|
||||||
/* Put the controller in low power state */
|
/* Put the controller in low power state */
|
||||||
pcgcctl = dwc2_readl(hsotg->regs + PCGCTL);
|
pcgcctl = dwc2_readl(hsotg, PCGCTL);
|
||||||
|
|
||||||
pcgcctl |= PCGCTL_PWRCLMP;
|
pcgcctl |= PCGCTL_PWRCLMP;
|
||||||
dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
|
dwc2_writel(hsotg, pcgcctl, PCGCTL);
|
||||||
ndelay(20);
|
ndelay(20);
|
||||||
|
|
||||||
pcgcctl |= PCGCTL_RSTPDWNMODULE;
|
pcgcctl |= PCGCTL_RSTPDWNMODULE;
|
||||||
dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
|
dwc2_writel(hsotg, pcgcctl, PCGCTL);
|
||||||
ndelay(20);
|
ndelay(20);
|
||||||
|
|
||||||
pcgcctl |= PCGCTL_STOPPCLK;
|
pcgcctl |= PCGCTL_STOPPCLK;
|
||||||
dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
|
dwc2_writel(hsotg, pcgcctl, PCGCTL);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -272,39 +272,39 @@ static void dwc2_restore_essential_regs(struct dwc2_hsotg *hsotg, int rmode,
|
|||||||
if (!(pcgcctl & PCGCTL_P2HD_DEV_ENUM_SPD_MASK))
|
if (!(pcgcctl & PCGCTL_P2HD_DEV_ENUM_SPD_MASK))
|
||||||
pcgcctl |= BIT(17);
|
pcgcctl |= BIT(17);
|
||||||
}
|
}
|
||||||
dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
|
dwc2_writel(hsotg, pcgcctl, PCGCTL);
|
||||||
|
|
||||||
/* Umnask global Interrupt in GAHBCFG and restore it */
|
/* Umnask global Interrupt in GAHBCFG and restore it */
|
||||||
dwc2_writel(gr->gahbcfg | GAHBCFG_GLBL_INTR_EN, hsotg->regs + GAHBCFG);
|
dwc2_writel(hsotg, gr->gahbcfg | GAHBCFG_GLBL_INTR_EN, GAHBCFG);
|
||||||
|
|
||||||
/* Clear all pending interupts */
|
/* Clear all pending interupts */
|
||||||
dwc2_writel(0xffffffff, hsotg->regs + GINTSTS);
|
dwc2_writel(hsotg, 0xffffffff, GINTSTS);
|
||||||
|
|
||||||
/* Unmask restore done interrupt */
|
/* Unmask restore done interrupt */
|
||||||
dwc2_writel(GINTSTS_RESTOREDONE, hsotg->regs + GINTMSK);
|
dwc2_writel(hsotg, GINTSTS_RESTOREDONE, GINTMSK);
|
||||||
|
|
||||||
/* Restore GUSBCFG and HCFG/DCFG */
|
/* Restore GUSBCFG and HCFG/DCFG */
|
||||||
dwc2_writel(gr->gusbcfg, hsotg->regs + GUSBCFG);
|
dwc2_writel(hsotg, gr->gusbcfg, GUSBCFG);
|
||||||
|
|
||||||
if (is_host) {
|
if (is_host) {
|
||||||
dwc2_writel(hr->hcfg, hsotg->regs + HCFG);
|
dwc2_writel(hsotg, hr->hcfg, HCFG);
|
||||||
if (rmode)
|
if (rmode)
|
||||||
pcgcctl |= PCGCTL_RESTOREMODE;
|
pcgcctl |= PCGCTL_RESTOREMODE;
|
||||||
dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
|
dwc2_writel(hsotg, pcgcctl, PCGCTL);
|
||||||
udelay(10);
|
udelay(10);
|
||||||
|
|
||||||
pcgcctl |= PCGCTL_ESS_REG_RESTORED;
|
pcgcctl |= PCGCTL_ESS_REG_RESTORED;
|
||||||
dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
|
dwc2_writel(hsotg, pcgcctl, PCGCTL);
|
||||||
udelay(10);
|
udelay(10);
|
||||||
} else {
|
} else {
|
||||||
dwc2_writel(dr->dcfg, hsotg->regs + DCFG);
|
dwc2_writel(hsotg, dr->dcfg, DCFG);
|
||||||
if (!rmode)
|
if (!rmode)
|
||||||
pcgcctl |= PCGCTL_RESTOREMODE | PCGCTL_RSTPDWNMODULE;
|
pcgcctl |= PCGCTL_RESTOREMODE | PCGCTL_RSTPDWNMODULE;
|
||||||
dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
|
dwc2_writel(hsotg, pcgcctl, PCGCTL);
|
||||||
udelay(10);
|
udelay(10);
|
||||||
|
|
||||||
pcgcctl |= PCGCTL_ESS_REG_RESTORED;
|
pcgcctl |= PCGCTL_ESS_REG_RESTORED;
|
||||||
dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
|
dwc2_writel(hsotg, pcgcctl, PCGCTL);
|
||||||
udelay(10);
|
udelay(10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -322,42 +322,42 @@ void dwc2_hib_restore_common(struct dwc2_hsotg *hsotg, int rem_wakeup,
|
|||||||
u32 gpwrdn;
|
u32 gpwrdn;
|
||||||
|
|
||||||
/* Switch-on voltage to the core */
|
/* Switch-on voltage to the core */
|
||||||
gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
|
gpwrdn = dwc2_readl(hsotg, GPWRDN);
|
||||||
gpwrdn &= ~GPWRDN_PWRDNSWTCH;
|
gpwrdn &= ~GPWRDN_PWRDNSWTCH;
|
||||||
dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
|
dwc2_writel(hsotg, gpwrdn, GPWRDN);
|
||||||
udelay(10);
|
udelay(10);
|
||||||
|
|
||||||
/* Reset core */
|
/* Reset core */
|
||||||
gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
|
gpwrdn = dwc2_readl(hsotg, GPWRDN);
|
||||||
gpwrdn &= ~GPWRDN_PWRDNRSTN;
|
gpwrdn &= ~GPWRDN_PWRDNRSTN;
|
||||||
dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
|
dwc2_writel(hsotg, gpwrdn, GPWRDN);
|
||||||
udelay(10);
|
udelay(10);
|
||||||
|
|
||||||
/* Enable restore from PMU */
|
/* Enable restore from PMU */
|
||||||
gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
|
gpwrdn = dwc2_readl(hsotg, GPWRDN);
|
||||||
gpwrdn |= GPWRDN_RESTORE;
|
gpwrdn |= GPWRDN_RESTORE;
|
||||||
dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
|
dwc2_writel(hsotg, gpwrdn, GPWRDN);
|
||||||
udelay(10);
|
udelay(10);
|
||||||
|
|
||||||
/* Disable Power Down Clamp */
|
/* Disable Power Down Clamp */
|
||||||
gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
|
gpwrdn = dwc2_readl(hsotg, GPWRDN);
|
||||||
gpwrdn &= ~GPWRDN_PWRDNCLMP;
|
gpwrdn &= ~GPWRDN_PWRDNCLMP;
|
||||||
dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
|
dwc2_writel(hsotg, gpwrdn, GPWRDN);
|
||||||
udelay(50);
|
udelay(50);
|
||||||
|
|
||||||
if (!is_host && rem_wakeup)
|
if (!is_host && rem_wakeup)
|
||||||
udelay(70);
|
udelay(70);
|
||||||
|
|
||||||
/* Deassert reset core */
|
/* Deassert reset core */
|
||||||
gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
|
gpwrdn = dwc2_readl(hsotg, GPWRDN);
|
||||||
gpwrdn |= GPWRDN_PWRDNRSTN;
|
gpwrdn |= GPWRDN_PWRDNRSTN;
|
||||||
dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
|
dwc2_writel(hsotg, gpwrdn, GPWRDN);
|
||||||
udelay(10);
|
udelay(10);
|
||||||
|
|
||||||
/* Disable PMU interrupt */
|
/* Disable PMU interrupt */
|
||||||
gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
|
gpwrdn = dwc2_readl(hsotg, GPWRDN);
|
||||||
gpwrdn &= ~GPWRDN_PMUINTSEL;
|
gpwrdn &= ~GPWRDN_PMUINTSEL;
|
||||||
dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
|
dwc2_writel(hsotg, gpwrdn, GPWRDN);
|
||||||
udelay(10);
|
udelay(10);
|
||||||
|
|
||||||
/* Set Restore Essential Regs bit in PCGCCTL register */
|
/* Set Restore Essential Regs bit in PCGCCTL register */
|
||||||
@ -431,7 +431,7 @@ static bool dwc2_iddig_filter_enabled(struct dwc2_hsotg *hsotg)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* Check if core configuration includes the IDDIG filter. */
|
/* Check if core configuration includes the IDDIG filter. */
|
||||||
ghwcfg4 = dwc2_readl(hsotg->regs + GHWCFG4);
|
ghwcfg4 = dwc2_readl(hsotg, GHWCFG4);
|
||||||
if (!(ghwcfg4 & GHWCFG4_IDDIG_FILT_EN))
|
if (!(ghwcfg4 & GHWCFG4_IDDIG_FILT_EN))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -439,9 +439,9 @@ static bool dwc2_iddig_filter_enabled(struct dwc2_hsotg *hsotg)
|
|||||||
* Check if the IDDIG debounce filter is bypassed. Available
|
* Check if the IDDIG debounce filter is bypassed. Available
|
||||||
* in core version >= 3.10a.
|
* in core version >= 3.10a.
|
||||||
*/
|
*/
|
||||||
gsnpsid = dwc2_readl(hsotg->regs + GSNPSID);
|
gsnpsid = dwc2_readl(hsotg, GSNPSID);
|
||||||
if (gsnpsid >= DWC2_CORE_REV_3_10a) {
|
if (gsnpsid >= DWC2_CORE_REV_3_10a) {
|
||||||
u32 gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
|
u32 gotgctl = dwc2_readl(hsotg, GOTGCTL);
|
||||||
|
|
||||||
if (gotgctl & GOTGCTL_DBNCE_FLTR_BYPASS)
|
if (gotgctl & GOTGCTL_DBNCE_FLTR_BYPASS)
|
||||||
return false;
|
return false;
|
||||||
@ -510,8 +510,8 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait)
|
|||||||
* reset and account for this delay after the reset.
|
* reset and account for this delay after the reset.
|
||||||
*/
|
*/
|
||||||
if (dwc2_iddig_filter_enabled(hsotg)) {
|
if (dwc2_iddig_filter_enabled(hsotg)) {
|
||||||
u32 gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
|
u32 gotgctl = dwc2_readl(hsotg, GOTGCTL);
|
||||||
u32 gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
|
u32 gusbcfg = dwc2_readl(hsotg, GUSBCFG);
|
||||||
|
|
||||||
if (!(gotgctl & GOTGCTL_CONID_B) ||
|
if (!(gotgctl & GOTGCTL_CONID_B) ||
|
||||||
(gusbcfg & GUSBCFG_FORCEHOSTMODE)) {
|
(gusbcfg & GUSBCFG_FORCEHOSTMODE)) {
|
||||||
@ -520,9 +520,9 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Core Soft Reset */
|
/* Core Soft Reset */
|
||||||
greset = dwc2_readl(hsotg->regs + GRSTCTL);
|
greset = dwc2_readl(hsotg, GRSTCTL);
|
||||||
greset |= GRSTCTL_CSFTRST;
|
greset |= GRSTCTL_CSFTRST;
|
||||||
dwc2_writel(greset, hsotg->regs + GRSTCTL);
|
dwc2_writel(hsotg, greset, GRSTCTL);
|
||||||
|
|
||||||
if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_CSFTRST, 50)) {
|
if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_CSFTRST, 50)) {
|
||||||
dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL GRSTCTL_CSFTRST\n",
|
dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL GRSTCTL_CSFTRST\n",
|
||||||
@ -594,14 +594,14 @@ void dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host)
|
|||||||
if (WARN_ON(!host && hsotg->dr_mode == USB_DR_MODE_HOST))
|
if (WARN_ON(!host && hsotg->dr_mode == USB_DR_MODE_HOST))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
|
gusbcfg = dwc2_readl(hsotg, GUSBCFG);
|
||||||
|
|
||||||
set = host ? GUSBCFG_FORCEHOSTMODE : GUSBCFG_FORCEDEVMODE;
|
set = host ? GUSBCFG_FORCEHOSTMODE : GUSBCFG_FORCEDEVMODE;
|
||||||
clear = host ? GUSBCFG_FORCEDEVMODE : GUSBCFG_FORCEHOSTMODE;
|
clear = host ? GUSBCFG_FORCEDEVMODE : GUSBCFG_FORCEHOSTMODE;
|
||||||
|
|
||||||
gusbcfg &= ~clear;
|
gusbcfg &= ~clear;
|
||||||
gusbcfg |= set;
|
gusbcfg |= set;
|
||||||
dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG);
|
dwc2_writel(hsotg, gusbcfg, GUSBCFG);
|
||||||
|
|
||||||
dwc2_wait_for_mode(hsotg, host);
|
dwc2_wait_for_mode(hsotg, host);
|
||||||
return;
|
return;
|
||||||
@ -627,10 +627,10 @@ static void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg)
|
|||||||
|
|
||||||
dev_dbg(hsotg->dev, "Clearing force mode bits\n");
|
dev_dbg(hsotg->dev, "Clearing force mode bits\n");
|
||||||
|
|
||||||
gusbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
|
gusbcfg = dwc2_readl(hsotg, GUSBCFG);
|
||||||
gusbcfg &= ~GUSBCFG_FORCEHOSTMODE;
|
gusbcfg &= ~GUSBCFG_FORCEHOSTMODE;
|
||||||
gusbcfg &= ~GUSBCFG_FORCEDEVMODE;
|
gusbcfg &= ~GUSBCFG_FORCEDEVMODE;
|
||||||
dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG);
|
dwc2_writel(hsotg, gusbcfg, GUSBCFG);
|
||||||
|
|
||||||
if (dwc2_iddig_filter_enabled(hsotg))
|
if (dwc2_iddig_filter_enabled(hsotg))
|
||||||
msleep(100);
|
msleep(100);
|
||||||
@ -670,11 +670,11 @@ void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg)
|
|||||||
void dwc2_enable_acg(struct dwc2_hsotg *hsotg)
|
void dwc2_enable_acg(struct dwc2_hsotg *hsotg)
|
||||||
{
|
{
|
||||||
if (hsotg->params.acg_enable) {
|
if (hsotg->params.acg_enable) {
|
||||||
u32 pcgcctl1 = dwc2_readl(hsotg->regs + PCGCCTL1);
|
u32 pcgcctl1 = dwc2_readl(hsotg, PCGCCTL1);
|
||||||
|
|
||||||
dev_dbg(hsotg->dev, "Enabling Active Clock Gating\n");
|
dev_dbg(hsotg->dev, "Enabling Active Clock Gating\n");
|
||||||
pcgcctl1 |= PCGCCTL1_GATEEN;
|
pcgcctl1 |= PCGCCTL1_GATEEN;
|
||||||
dwc2_writel(pcgcctl1, hsotg->regs + PCGCCTL1);
|
dwc2_writel(hsotg, pcgcctl1, PCGCCTL1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -695,56 +695,57 @@ void dwc2_dump_host_registers(struct dwc2_hsotg *hsotg)
|
|||||||
dev_dbg(hsotg->dev, "Host Global Registers\n");
|
dev_dbg(hsotg->dev, "Host Global Registers\n");
|
||||||
addr = hsotg->regs + HCFG;
|
addr = hsotg->regs + HCFG;
|
||||||
dev_dbg(hsotg->dev, "HCFG @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "HCFG @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, HCFG));
|
||||||
addr = hsotg->regs + HFIR;
|
addr = hsotg->regs + HFIR;
|
||||||
dev_dbg(hsotg->dev, "HFIR @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "HFIR @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, HFIR));
|
||||||
addr = hsotg->regs + HFNUM;
|
addr = hsotg->regs + HFNUM;
|
||||||
dev_dbg(hsotg->dev, "HFNUM @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "HFNUM @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, HFNUM));
|
||||||
addr = hsotg->regs + HPTXSTS;
|
addr = hsotg->regs + HPTXSTS;
|
||||||
dev_dbg(hsotg->dev, "HPTXSTS @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "HPTXSTS @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, HPTXSTS));
|
||||||
addr = hsotg->regs + HAINT;
|
addr = hsotg->regs + HAINT;
|
||||||
dev_dbg(hsotg->dev, "HAINT @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "HAINT @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, HAINT));
|
||||||
addr = hsotg->regs + HAINTMSK;
|
addr = hsotg->regs + HAINTMSK;
|
||||||
dev_dbg(hsotg->dev, "HAINTMSK @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "HAINTMSK @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, HAINTMSK));
|
||||||
if (hsotg->params.dma_desc_enable) {
|
if (hsotg->params.dma_desc_enable) {
|
||||||
addr = hsotg->regs + HFLBADDR;
|
addr = hsotg->regs + HFLBADDR;
|
||||||
dev_dbg(hsotg->dev, "HFLBADDR @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "HFLBADDR @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, HFLBADDR));
|
||||||
}
|
}
|
||||||
|
|
||||||
addr = hsotg->regs + HPRT0;
|
addr = hsotg->regs + HPRT0;
|
||||||
dev_dbg(hsotg->dev, "HPRT0 @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "HPRT0 @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, HPRT0));
|
||||||
|
|
||||||
for (i = 0; i < hsotg->params.host_channels; i++) {
|
for (i = 0; i < hsotg->params.host_channels; i++) {
|
||||||
dev_dbg(hsotg->dev, "Host Channel %d Specific Registers\n", i);
|
dev_dbg(hsotg->dev, "Host Channel %d Specific Registers\n", i);
|
||||||
addr = hsotg->regs + HCCHAR(i);
|
addr = hsotg->regs + HCCHAR(i);
|
||||||
dev_dbg(hsotg->dev, "HCCHAR @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "HCCHAR @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, HCCHAR(i)));
|
||||||
addr = hsotg->regs + HCSPLT(i);
|
addr = hsotg->regs + HCSPLT(i);
|
||||||
dev_dbg(hsotg->dev, "HCSPLT @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "HCSPLT @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, HCSPLT(i)));
|
||||||
addr = hsotg->regs + HCINT(i);
|
addr = hsotg->regs + HCINT(i);
|
||||||
dev_dbg(hsotg->dev, "HCINT @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "HCINT @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, HCINT(i)));
|
||||||
addr = hsotg->regs + HCINTMSK(i);
|
addr = hsotg->regs + HCINTMSK(i);
|
||||||
dev_dbg(hsotg->dev, "HCINTMSK @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "HCINTMSK @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, HCINTMSK(i)));
|
||||||
addr = hsotg->regs + HCTSIZ(i);
|
addr = hsotg->regs + HCTSIZ(i);
|
||||||
dev_dbg(hsotg->dev, "HCTSIZ @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "HCTSIZ @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, HCTSIZ(i)));
|
||||||
addr = hsotg->regs + HCDMA(i);
|
addr = hsotg->regs + HCDMA(i);
|
||||||
dev_dbg(hsotg->dev, "HCDMA @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "HCDMA @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, HCDMA(i)));
|
||||||
if (hsotg->params.dma_desc_enable) {
|
if (hsotg->params.dma_desc_enable) {
|
||||||
addr = hsotg->regs + HCDMAB(i);
|
addr = hsotg->regs + HCDMAB(i);
|
||||||
dev_dbg(hsotg->dev, "HCDMAB @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "HCDMAB @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg,
|
||||||
|
HCDMAB(i)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -766,80 +767,80 @@ void dwc2_dump_global_registers(struct dwc2_hsotg *hsotg)
|
|||||||
dev_dbg(hsotg->dev, "Core Global Registers\n");
|
dev_dbg(hsotg->dev, "Core Global Registers\n");
|
||||||
addr = hsotg->regs + GOTGCTL;
|
addr = hsotg->regs + GOTGCTL;
|
||||||
dev_dbg(hsotg->dev, "GOTGCTL @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "GOTGCTL @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, GOTGCTL));
|
||||||
addr = hsotg->regs + GOTGINT;
|
addr = hsotg->regs + GOTGINT;
|
||||||
dev_dbg(hsotg->dev, "GOTGINT @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "GOTGINT @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, GOTGINT));
|
||||||
addr = hsotg->regs + GAHBCFG;
|
addr = hsotg->regs + GAHBCFG;
|
||||||
dev_dbg(hsotg->dev, "GAHBCFG @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "GAHBCFG @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, GAHBCFG));
|
||||||
addr = hsotg->regs + GUSBCFG;
|
addr = hsotg->regs + GUSBCFG;
|
||||||
dev_dbg(hsotg->dev, "GUSBCFG @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "GUSBCFG @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, GUSBCFG));
|
||||||
addr = hsotg->regs + GRSTCTL;
|
addr = hsotg->regs + GRSTCTL;
|
||||||
dev_dbg(hsotg->dev, "GRSTCTL @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "GRSTCTL @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, GRSTCTL));
|
||||||
addr = hsotg->regs + GINTSTS;
|
addr = hsotg->regs + GINTSTS;
|
||||||
dev_dbg(hsotg->dev, "GINTSTS @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "GINTSTS @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, GINTSTS));
|
||||||
addr = hsotg->regs + GINTMSK;
|
addr = hsotg->regs + GINTMSK;
|
||||||
dev_dbg(hsotg->dev, "GINTMSK @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "GINTMSK @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, GINTMSK));
|
||||||
addr = hsotg->regs + GRXSTSR;
|
addr = hsotg->regs + GRXSTSR;
|
||||||
dev_dbg(hsotg->dev, "GRXSTSR @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "GRXSTSR @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, GRXSTSR));
|
||||||
addr = hsotg->regs + GRXFSIZ;
|
addr = hsotg->regs + GRXFSIZ;
|
||||||
dev_dbg(hsotg->dev, "GRXFSIZ @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "GRXFSIZ @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, GRXFSIZ));
|
||||||
addr = hsotg->regs + GNPTXFSIZ;
|
addr = hsotg->regs + GNPTXFSIZ;
|
||||||
dev_dbg(hsotg->dev, "GNPTXFSIZ @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "GNPTXFSIZ @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, GNPTXFSIZ));
|
||||||
addr = hsotg->regs + GNPTXSTS;
|
addr = hsotg->regs + GNPTXSTS;
|
||||||
dev_dbg(hsotg->dev, "GNPTXSTS @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "GNPTXSTS @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, GNPTXSTS));
|
||||||
addr = hsotg->regs + GI2CCTL;
|
addr = hsotg->regs + GI2CCTL;
|
||||||
dev_dbg(hsotg->dev, "GI2CCTL @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "GI2CCTL @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, GI2CCTL));
|
||||||
addr = hsotg->regs + GPVNDCTL;
|
addr = hsotg->regs + GPVNDCTL;
|
||||||
dev_dbg(hsotg->dev, "GPVNDCTL @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "GPVNDCTL @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, GPVNDCTL));
|
||||||
addr = hsotg->regs + GGPIO;
|
addr = hsotg->regs + GGPIO;
|
||||||
dev_dbg(hsotg->dev, "GGPIO @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "GGPIO @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, GGPIO));
|
||||||
addr = hsotg->regs + GUID;
|
addr = hsotg->regs + GUID;
|
||||||
dev_dbg(hsotg->dev, "GUID @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "GUID @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, GUID));
|
||||||
addr = hsotg->regs + GSNPSID;
|
addr = hsotg->regs + GSNPSID;
|
||||||
dev_dbg(hsotg->dev, "GSNPSID @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "GSNPSID @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, GSNPSID));
|
||||||
addr = hsotg->regs + GHWCFG1;
|
addr = hsotg->regs + GHWCFG1;
|
||||||
dev_dbg(hsotg->dev, "GHWCFG1 @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "GHWCFG1 @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, GHWCFG1));
|
||||||
addr = hsotg->regs + GHWCFG2;
|
addr = hsotg->regs + GHWCFG2;
|
||||||
dev_dbg(hsotg->dev, "GHWCFG2 @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "GHWCFG2 @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, GHWCFG2));
|
||||||
addr = hsotg->regs + GHWCFG3;
|
addr = hsotg->regs + GHWCFG3;
|
||||||
dev_dbg(hsotg->dev, "GHWCFG3 @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "GHWCFG3 @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, GHWCFG3));
|
||||||
addr = hsotg->regs + GHWCFG4;
|
addr = hsotg->regs + GHWCFG4;
|
||||||
dev_dbg(hsotg->dev, "GHWCFG4 @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "GHWCFG4 @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, GHWCFG4));
|
||||||
addr = hsotg->regs + GLPMCFG;
|
addr = hsotg->regs + GLPMCFG;
|
||||||
dev_dbg(hsotg->dev, "GLPMCFG @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "GLPMCFG @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, GLPMCFG));
|
||||||
addr = hsotg->regs + GPWRDN;
|
addr = hsotg->regs + GPWRDN;
|
||||||
dev_dbg(hsotg->dev, "GPWRDN @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "GPWRDN @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, GPWRDN));
|
||||||
addr = hsotg->regs + GDFIFOCFG;
|
addr = hsotg->regs + GDFIFOCFG;
|
||||||
dev_dbg(hsotg->dev, "GDFIFOCFG @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "GDFIFOCFG @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, GDFIFOCFG));
|
||||||
addr = hsotg->regs + HPTXFSIZ;
|
addr = hsotg->regs + HPTXFSIZ;
|
||||||
dev_dbg(hsotg->dev, "HPTXFSIZ @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "HPTXFSIZ @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, HPTXFSIZ));
|
||||||
|
|
||||||
addr = hsotg->regs + PCGCTL;
|
addr = hsotg->regs + PCGCTL;
|
||||||
dev_dbg(hsotg->dev, "PCGCTL @0x%08lX : 0x%08X\n",
|
dev_dbg(hsotg->dev, "PCGCTL @0x%08lX : 0x%08X\n",
|
||||||
(unsigned long)addr, dwc2_readl(addr));
|
(unsigned long)addr, dwc2_readl(hsotg, PCGCTL));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -862,7 +863,7 @@ void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num)
|
|||||||
|
|
||||||
greset = GRSTCTL_TXFFLSH;
|
greset = GRSTCTL_TXFFLSH;
|
||||||
greset |= num << GRSTCTL_TXFNUM_SHIFT & GRSTCTL_TXFNUM_MASK;
|
greset |= num << GRSTCTL_TXFNUM_SHIFT & GRSTCTL_TXFNUM_MASK;
|
||||||
dwc2_writel(greset, hsotg->regs + GRSTCTL);
|
dwc2_writel(hsotg, greset, GRSTCTL);
|
||||||
|
|
||||||
if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_TXFFLSH, 10000))
|
if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_TXFFLSH, 10000))
|
||||||
dev_warn(hsotg->dev, "%s: HANG! timeout GRSTCTL GRSTCTL_TXFFLSH\n",
|
dev_warn(hsotg->dev, "%s: HANG! timeout GRSTCTL GRSTCTL_TXFFLSH\n",
|
||||||
@ -889,7 +890,7 @@ void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg)
|
|||||||
__func__);
|
__func__);
|
||||||
|
|
||||||
greset = GRSTCTL_RXFFLSH;
|
greset = GRSTCTL_RXFFLSH;
|
||||||
dwc2_writel(greset, hsotg->regs + GRSTCTL);
|
dwc2_writel(hsotg, greset, GRSTCTL);
|
||||||
|
|
||||||
/* Wait for RxFIFO flush done */
|
/* Wait for RxFIFO flush done */
|
||||||
if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_RXFFLSH, 10000))
|
if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_RXFFLSH, 10000))
|
||||||
@ -902,7 +903,7 @@ void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg)
|
|||||||
|
|
||||||
bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg)
|
bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg)
|
||||||
{
|
{
|
||||||
if (dwc2_readl(hsotg->regs + GSNPSID) == 0xffffffff)
|
if (dwc2_readl(hsotg, GSNPSID) == 0xffffffff)
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
return true;
|
return true;
|
||||||
@ -916,10 +917,10 @@ bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg)
|
|||||||
*/
|
*/
|
||||||
void dwc2_enable_global_interrupts(struct dwc2_hsotg *hsotg)
|
void dwc2_enable_global_interrupts(struct dwc2_hsotg *hsotg)
|
||||||
{
|
{
|
||||||
u32 ahbcfg = dwc2_readl(hsotg->regs + GAHBCFG);
|
u32 ahbcfg = dwc2_readl(hsotg, GAHBCFG);
|
||||||
|
|
||||||
ahbcfg |= GAHBCFG_GLBL_INTR_EN;
|
ahbcfg |= GAHBCFG_GLBL_INTR_EN;
|
||||||
dwc2_writel(ahbcfg, hsotg->regs + GAHBCFG);
|
dwc2_writel(hsotg, ahbcfg, GAHBCFG);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -930,16 +931,16 @@ void dwc2_enable_global_interrupts(struct dwc2_hsotg *hsotg)
|
|||||||
*/
|
*/
|
||||||
void dwc2_disable_global_interrupts(struct dwc2_hsotg *hsotg)
|
void dwc2_disable_global_interrupts(struct dwc2_hsotg *hsotg)
|
||||||
{
|
{
|
||||||
u32 ahbcfg = dwc2_readl(hsotg->regs + GAHBCFG);
|
u32 ahbcfg = dwc2_readl(hsotg, GAHBCFG);
|
||||||
|
|
||||||
ahbcfg &= ~GAHBCFG_GLBL_INTR_EN;
|
ahbcfg &= ~GAHBCFG_GLBL_INTR_EN;
|
||||||
dwc2_writel(ahbcfg, hsotg->regs + GAHBCFG);
|
dwc2_writel(hsotg, ahbcfg, GAHBCFG);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns the controller's GHWCFG2.OTG_MODE. */
|
/* Returns the controller's GHWCFG2.OTG_MODE. */
|
||||||
unsigned int dwc2_op_mode(struct dwc2_hsotg *hsotg)
|
unsigned int dwc2_op_mode(struct dwc2_hsotg *hsotg)
|
||||||
{
|
{
|
||||||
u32 ghwcfg2 = dwc2_readl(hsotg->regs + GHWCFG2);
|
u32 ghwcfg2 = dwc2_readl(hsotg, GHWCFG2);
|
||||||
|
|
||||||
return (ghwcfg2 & GHWCFG2_OP_MODE_MASK) >>
|
return (ghwcfg2 & GHWCFG2_OP_MODE_MASK) >>
|
||||||
GHWCFG2_OP_MODE_SHIFT;
|
GHWCFG2_OP_MODE_SHIFT;
|
||||||
@ -988,7 +989,7 @@ int dwc2_hsotg_wait_bit_set(struct dwc2_hsotg *hsotg, u32 offset, u32 mask,
|
|||||||
u32 i;
|
u32 i;
|
||||||
|
|
||||||
for (i = 0; i < timeout; i++) {
|
for (i = 0; i < timeout; i++) {
|
||||||
if (dwc2_readl(hsotg->regs + offset) & mask)
|
if (dwc2_readl(hsotg, offset) & mask)
|
||||||
return 0;
|
return 0;
|
||||||
udelay(1);
|
udelay(1);
|
||||||
}
|
}
|
||||||
@ -1011,7 +1012,7 @@ int dwc2_hsotg_wait_bit_clear(struct dwc2_hsotg *hsotg, u32 offset, u32 mask,
|
|||||||
u32 i;
|
u32 i;
|
||||||
|
|
||||||
for (i = 0; i < timeout; i++) {
|
for (i = 0; i < timeout; i++) {
|
||||||
if (!(dwc2_readl(hsotg->regs + offset) & mask))
|
if (!(dwc2_readl(hsotg, offset) & mask))
|
||||||
return 0;
|
return 0;
|
||||||
udelay(1);
|
udelay(1);
|
||||||
}
|
}
|
||||||
|
@ -65,60 +65,6 @@
|
|||||||
DWC2_TRACE_SCHEDULER_VB(pr_fmt("%s: SCH: " fmt), \
|
DWC2_TRACE_SCHEDULER_VB(pr_fmt("%s: SCH: " fmt), \
|
||||||
dev_name(hsotg->dev), ##__VA_ARGS__)
|
dev_name(hsotg->dev), ##__VA_ARGS__)
|
||||||
|
|
||||||
#ifdef CONFIG_MIPS
|
|
||||||
/*
|
|
||||||
* There are some MIPS machines that can run in either big-endian
|
|
||||||
* or little-endian mode and that use the dwc2 register without
|
|
||||||
* a byteswap in both ways.
|
|
||||||
* Unlike other architectures, MIPS apparently does not require a
|
|
||||||
* barrier before the __raw_writel() to synchronize with DMA but does
|
|
||||||
* require the barrier after the __raw_writel() to serialize a set of
|
|
||||||
* writes. This set of operations was added specifically for MIPS and
|
|
||||||
* should only be used there.
|
|
||||||
*/
|
|
||||||
static inline u32 dwc2_readl(const void __iomem *addr)
|
|
||||||
{
|
|
||||||
u32 value = __raw_readl(addr);
|
|
||||||
|
|
||||||
/* In order to preserve endianness __raw_* operation is used. Therefore
|
|
||||||
* a barrier is needed to ensure IO access is not re-ordered across
|
|
||||||
* reads or writes
|
|
||||||
*/
|
|
||||||
mb();
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void dwc2_writel(u32 value, void __iomem *addr)
|
|
||||||
{
|
|
||||||
__raw_writel(value, addr);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* In order to preserve endianness __raw_* operation is used. Therefore
|
|
||||||
* a barrier is needed to ensure IO access is not re-ordered across
|
|
||||||
* reads or writes
|
|
||||||
*/
|
|
||||||
mb();
|
|
||||||
#ifdef DWC2_LOG_WRITES
|
|
||||||
pr_info("INFO:: wrote %08x to %p\n", value, addr);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
/* Normal architectures just use readl/write */
|
|
||||||
static inline u32 dwc2_readl(const void __iomem *addr)
|
|
||||||
{
|
|
||||||
return readl(addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void dwc2_writel(u32 value, void __iomem *addr)
|
|
||||||
{
|
|
||||||
writel(value, addr);
|
|
||||||
|
|
||||||
#ifdef DWC2_LOG_WRITES
|
|
||||||
pr_info("info:: wrote %08x to %p\n", value, addr);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Maximum number of Endpoints/HostChannels */
|
/* Maximum number of Endpoints/HostChannels */
|
||||||
#define MAX_EPS_CHANNELS 16
|
#define MAX_EPS_CHANNELS 16
|
||||||
|
|
||||||
@ -911,6 +857,7 @@ struct dwc2_hregs_backup {
|
|||||||
* @gr_backup: Backup of global registers during suspend
|
* @gr_backup: Backup of global registers during suspend
|
||||||
* @dr_backup: Backup of device registers during suspend
|
* @dr_backup: Backup of device registers during suspend
|
||||||
* @hr_backup: Backup of host registers during suspend
|
* @hr_backup: Backup of host registers during suspend
|
||||||
|
* @needs_byte_swap: Specifies whether the opposite endianness.
|
||||||
*
|
*
|
||||||
* These are for host mode:
|
* These are for host mode:
|
||||||
*
|
*
|
||||||
@ -1100,6 +1047,7 @@ struct dwc2_hsotg {
|
|||||||
|
|
||||||
struct dentry *debug_root;
|
struct dentry *debug_root;
|
||||||
struct debugfs_regset32 *regset;
|
struct debugfs_regset32 *regset;
|
||||||
|
bool needs_byte_swap;
|
||||||
|
|
||||||
/* DWC OTG HW Release versions */
|
/* DWC OTG HW Release versions */
|
||||||
#define DWC2_CORE_REV_2_71a 0x4f54271a
|
#define DWC2_CORE_REV_2_71a 0x4f54271a
|
||||||
@ -1215,6 +1163,55 @@ struct dwc2_hsotg {
|
|||||||
#endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */
|
#endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Normal architectures just use readl/write */
|
||||||
|
static inline u32 dwc2_readl(struct dwc2_hsotg *hsotg, u32 offset)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
val = readl(hsotg->regs + offset);
|
||||||
|
if (hsotg->needs_byte_swap)
|
||||||
|
return swab32(val);
|
||||||
|
else
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void dwc2_writel(struct dwc2_hsotg *hsotg, u32 value, u32 offset)
|
||||||
|
{
|
||||||
|
if (hsotg->needs_byte_swap)
|
||||||
|
writel(swab32(value), hsotg->regs + offset);
|
||||||
|
else
|
||||||
|
writel(value, hsotg->regs + offset);
|
||||||
|
|
||||||
|
#ifdef DWC2_LOG_WRITES
|
||||||
|
pr_info("info:: wrote %08x to %p\n", value, hsotg->regs + offset);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void dwc2_readl_rep(struct dwc2_hsotg *hsotg, u32 offset,
|
||||||
|
void *buffer, unsigned int count)
|
||||||
|
{
|
||||||
|
if (count) {
|
||||||
|
u32 *buf = buffer;
|
||||||
|
|
||||||
|
do {
|
||||||
|
u32 x = dwc2_readl(hsotg, offset);
|
||||||
|
*buf++ = x;
|
||||||
|
} while (--count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void dwc2_writel_rep(struct dwc2_hsotg *hsotg, u32 offset,
|
||||||
|
const void *buffer, unsigned int count)
|
||||||
|
{
|
||||||
|
if (count) {
|
||||||
|
const u32 *buf = buffer;
|
||||||
|
|
||||||
|
do {
|
||||||
|
dwc2_writel(hsotg, *buf++, offset);
|
||||||
|
} while (--count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Reasons for halting a host channel */
|
/* Reasons for halting a host channel */
|
||||||
enum dwc2_halt_status {
|
enum dwc2_halt_status {
|
||||||
DWC2_HC_XFER_NO_HALT_STATUS,
|
DWC2_HC_XFER_NO_HALT_STATUS,
|
||||||
@ -1320,12 +1317,12 @@ bool dwc2_hw_is_device(struct dwc2_hsotg *hsotg);
|
|||||||
*/
|
*/
|
||||||
static inline int dwc2_is_host_mode(struct dwc2_hsotg *hsotg)
|
static inline int dwc2_is_host_mode(struct dwc2_hsotg *hsotg)
|
||||||
{
|
{
|
||||||
return (dwc2_readl(hsotg->regs + GINTSTS) & GINTSTS_CURMODE_HOST) != 0;
|
return (dwc2_readl(hsotg, GINTSTS) & GINTSTS_CURMODE_HOST) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int dwc2_is_device_mode(struct dwc2_hsotg *hsotg)
|
static inline int dwc2_is_device_mode(struct dwc2_hsotg *hsotg)
|
||||||
{
|
{
|
||||||
return (dwc2_readl(hsotg->regs + GINTSTS) & GINTSTS_CURMODE_HOST) == 0;
|
return (dwc2_readl(hsotg, GINTSTS) & GINTSTS_CURMODE_HOST) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -81,11 +81,11 @@ static const char *dwc2_op_state_str(struct dwc2_hsotg *hsotg)
|
|||||||
*/
|
*/
|
||||||
static void dwc2_handle_usb_port_intr(struct dwc2_hsotg *hsotg)
|
static void dwc2_handle_usb_port_intr(struct dwc2_hsotg *hsotg)
|
||||||
{
|
{
|
||||||
u32 hprt0 = dwc2_readl(hsotg->regs + HPRT0);
|
u32 hprt0 = dwc2_readl(hsotg, HPRT0);
|
||||||
|
|
||||||
if (hprt0 & HPRT0_ENACHG) {
|
if (hprt0 & HPRT0_ENACHG) {
|
||||||
hprt0 &= ~HPRT0_ENA;
|
hprt0 &= ~HPRT0_ENA;
|
||||||
dwc2_writel(hprt0, hsotg->regs + HPRT0);
|
dwc2_writel(hsotg, hprt0, HPRT0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,7 +97,7 @@ static void dwc2_handle_usb_port_intr(struct dwc2_hsotg *hsotg)
|
|||||||
static void dwc2_handle_mode_mismatch_intr(struct dwc2_hsotg *hsotg)
|
static void dwc2_handle_mode_mismatch_intr(struct dwc2_hsotg *hsotg)
|
||||||
{
|
{
|
||||||
/* Clear interrupt */
|
/* Clear interrupt */
|
||||||
dwc2_writel(GINTSTS_MODEMIS, hsotg->regs + GINTSTS);
|
dwc2_writel(hsotg, GINTSTS_MODEMIS, GINTSTS);
|
||||||
|
|
||||||
dev_warn(hsotg->dev, "Mode Mismatch Interrupt: currently in %s mode\n",
|
dev_warn(hsotg->dev, "Mode Mismatch Interrupt: currently in %s mode\n",
|
||||||
dwc2_is_host_mode(hsotg) ? "Host" : "Device");
|
dwc2_is_host_mode(hsotg) ? "Host" : "Device");
|
||||||
@ -115,8 +115,8 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
|
|||||||
u32 gotgctl;
|
u32 gotgctl;
|
||||||
u32 gintmsk;
|
u32 gintmsk;
|
||||||
|
|
||||||
gotgint = dwc2_readl(hsotg->regs + GOTGINT);
|
gotgint = dwc2_readl(hsotg, GOTGINT);
|
||||||
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
|
gotgctl = dwc2_readl(hsotg, GOTGCTL);
|
||||||
dev_dbg(hsotg->dev, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint,
|
dev_dbg(hsotg->dev, "++OTG Interrupt gotgint=%0x [%s]\n", gotgint,
|
||||||
dwc2_op_state_str(hsotg));
|
dwc2_op_state_str(hsotg));
|
||||||
|
|
||||||
@ -124,7 +124,7 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
|
|||||||
dev_dbg(hsotg->dev,
|
dev_dbg(hsotg->dev,
|
||||||
" ++OTG Interrupt: Session End Detected++ (%s)\n",
|
" ++OTG Interrupt: Session End Detected++ (%s)\n",
|
||||||
dwc2_op_state_str(hsotg));
|
dwc2_op_state_str(hsotg));
|
||||||
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
|
gotgctl = dwc2_readl(hsotg, GOTGCTL);
|
||||||
|
|
||||||
if (dwc2_is_device_mode(hsotg))
|
if (dwc2_is_device_mode(hsotg))
|
||||||
dwc2_hsotg_disconnect(hsotg);
|
dwc2_hsotg_disconnect(hsotg);
|
||||||
@ -150,24 +150,24 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
|
|||||||
hsotg->lx_state = DWC2_L0;
|
hsotg->lx_state = DWC2_L0;
|
||||||
}
|
}
|
||||||
|
|
||||||
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
|
gotgctl = dwc2_readl(hsotg, GOTGCTL);
|
||||||
gotgctl &= ~GOTGCTL_DEVHNPEN;
|
gotgctl &= ~GOTGCTL_DEVHNPEN;
|
||||||
dwc2_writel(gotgctl, hsotg->regs + GOTGCTL);
|
dwc2_writel(hsotg, gotgctl, GOTGCTL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gotgint & GOTGINT_SES_REQ_SUC_STS_CHNG) {
|
if (gotgint & GOTGINT_SES_REQ_SUC_STS_CHNG) {
|
||||||
dev_dbg(hsotg->dev,
|
dev_dbg(hsotg->dev,
|
||||||
" ++OTG Interrupt: Session Request Success Status Change++\n");
|
" ++OTG Interrupt: Session Request Success Status Change++\n");
|
||||||
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
|
gotgctl = dwc2_readl(hsotg, GOTGCTL);
|
||||||
if (gotgctl & GOTGCTL_SESREQSCS) {
|
if (gotgctl & GOTGCTL_SESREQSCS) {
|
||||||
if (hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS &&
|
if (hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS &&
|
||||||
hsotg->params.i2c_enable) {
|
hsotg->params.i2c_enable) {
|
||||||
hsotg->srp_success = 1;
|
hsotg->srp_success = 1;
|
||||||
} else {
|
} else {
|
||||||
/* Clear Session Request */
|
/* Clear Session Request */
|
||||||
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
|
gotgctl = dwc2_readl(hsotg, GOTGCTL);
|
||||||
gotgctl &= ~GOTGCTL_SESREQ;
|
gotgctl &= ~GOTGCTL_SESREQ;
|
||||||
dwc2_writel(gotgctl, hsotg->regs + GOTGCTL);
|
dwc2_writel(hsotg, gotgctl, GOTGCTL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -177,7 +177,7 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
|
|||||||
* Print statements during the HNP interrupt handling
|
* Print statements during the HNP interrupt handling
|
||||||
* can cause it to fail
|
* can cause it to fail
|
||||||
*/
|
*/
|
||||||
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
|
gotgctl = dwc2_readl(hsotg, GOTGCTL);
|
||||||
/*
|
/*
|
||||||
* WA for 3.00a- HW is not setting cur_mode, even sometimes
|
* WA for 3.00a- HW is not setting cur_mode, even sometimes
|
||||||
* this does not help
|
* this does not help
|
||||||
@ -197,9 +197,9 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
|
|||||||
* interrupt does not get handled and Linux
|
* interrupt does not get handled and Linux
|
||||||
* complains loudly.
|
* complains loudly.
|
||||||
*/
|
*/
|
||||||
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
|
gintmsk = dwc2_readl(hsotg, GINTMSK);
|
||||||
gintmsk &= ~GINTSTS_SOF;
|
gintmsk &= ~GINTSTS_SOF;
|
||||||
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
|
dwc2_writel(hsotg, gintmsk, GINTMSK);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Call callback function with spin lock
|
* Call callback function with spin lock
|
||||||
@ -213,9 +213,9 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
|
|||||||
hsotg->op_state = OTG_STATE_B_HOST;
|
hsotg->op_state = OTG_STATE_B_HOST;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
gotgctl = dwc2_readl(hsotg->regs + GOTGCTL);
|
gotgctl = dwc2_readl(hsotg, GOTGCTL);
|
||||||
gotgctl &= ~(GOTGCTL_HNPREQ | GOTGCTL_DEVHNPEN);
|
gotgctl &= ~(GOTGCTL_HNPREQ | GOTGCTL_DEVHNPEN);
|
||||||
dwc2_writel(gotgctl, hsotg->regs + GOTGCTL);
|
dwc2_writel(hsotg, gotgctl, GOTGCTL);
|
||||||
dev_dbg(hsotg->dev, "HNP Failed\n");
|
dev_dbg(hsotg->dev, "HNP Failed\n");
|
||||||
dev_err(hsotg->dev,
|
dev_err(hsotg->dev,
|
||||||
"Device Not Connected/Responding\n");
|
"Device Not Connected/Responding\n");
|
||||||
@ -241,9 +241,9 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
|
|||||||
hsotg->op_state = OTG_STATE_A_PERIPHERAL;
|
hsotg->op_state = OTG_STATE_A_PERIPHERAL;
|
||||||
} else {
|
} else {
|
||||||
/* Need to disable SOF interrupt immediately */
|
/* Need to disable SOF interrupt immediately */
|
||||||
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
|
gintmsk = dwc2_readl(hsotg, GINTMSK);
|
||||||
gintmsk &= ~GINTSTS_SOF;
|
gintmsk &= ~GINTSTS_SOF;
|
||||||
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
|
dwc2_writel(hsotg, gintmsk, GINTMSK);
|
||||||
spin_unlock(&hsotg->lock);
|
spin_unlock(&hsotg->lock);
|
||||||
dwc2_hcd_start(hsotg);
|
dwc2_hcd_start(hsotg);
|
||||||
spin_lock(&hsotg->lock);
|
spin_lock(&hsotg->lock);
|
||||||
@ -258,7 +258,7 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg)
|
|||||||
dev_dbg(hsotg->dev, " ++OTG Interrupt: Debounce Done++\n");
|
dev_dbg(hsotg->dev, " ++OTG Interrupt: Debounce Done++\n");
|
||||||
|
|
||||||
/* Clear GOTGINT */
|
/* Clear GOTGINT */
|
||||||
dwc2_writel(gotgint, hsotg->regs + GOTGINT);
|
dwc2_writel(hsotg, gotgint, GOTGINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -276,12 +276,12 @@ static void dwc2_handle_conn_id_status_change_intr(struct dwc2_hsotg *hsotg)
|
|||||||
u32 gintmsk;
|
u32 gintmsk;
|
||||||
|
|
||||||
/* Clear interrupt */
|
/* Clear interrupt */
|
||||||
dwc2_writel(GINTSTS_CONIDSTSCHNG, hsotg->regs + GINTSTS);
|
dwc2_writel(hsotg, GINTSTS_CONIDSTSCHNG, GINTSTS);
|
||||||
|
|
||||||
/* Need to disable SOF interrupt immediately */
|
/* Need to disable SOF interrupt immediately */
|
||||||
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
|
gintmsk = dwc2_readl(hsotg, GINTMSK);
|
||||||
gintmsk &= ~GINTSTS_SOF;
|
gintmsk &= ~GINTSTS_SOF;
|
||||||
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
|
dwc2_writel(hsotg, gintmsk, GINTMSK);
|
||||||
|
|
||||||
dev_dbg(hsotg->dev, " ++Connector ID Status Change Interrupt++ (%s)\n",
|
dev_dbg(hsotg->dev, " ++Connector ID Status Change Interrupt++ (%s)\n",
|
||||||
dwc2_is_host_mode(hsotg) ? "Host" : "Device");
|
dwc2_is_host_mode(hsotg) ? "Host" : "Device");
|
||||||
@ -314,7 +314,7 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Clear interrupt */
|
/* Clear interrupt */
|
||||||
dwc2_writel(GINTSTS_SESSREQINT, hsotg->regs + GINTSTS);
|
dwc2_writel(hsotg, GINTSTS_SESSREQINT, GINTSTS);
|
||||||
|
|
||||||
dev_dbg(hsotg->dev, "Session request interrupt - lx_state=%d\n",
|
dev_dbg(hsotg->dev, "Session request interrupt - lx_state=%d\n",
|
||||||
hsotg->lx_state);
|
hsotg->lx_state);
|
||||||
@ -351,15 +351,15 @@ static void dwc2_wakeup_from_lpm_l1(struct dwc2_hsotg *hsotg)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
glpmcfg = dwc2_readl(hsotg->regs + GLPMCFG);
|
glpmcfg = dwc2_readl(hsotg, GLPMCFG);
|
||||||
if (dwc2_is_device_mode(hsotg)) {
|
if (dwc2_is_device_mode(hsotg)) {
|
||||||
dev_dbg(hsotg->dev, "Exit from L1 state\n");
|
dev_dbg(hsotg->dev, "Exit from L1 state\n");
|
||||||
glpmcfg &= ~GLPMCFG_ENBLSLPM;
|
glpmcfg &= ~GLPMCFG_ENBLSLPM;
|
||||||
glpmcfg &= ~GLPMCFG_HIRD_THRES_EN;
|
glpmcfg &= ~GLPMCFG_HIRD_THRES_EN;
|
||||||
dwc2_writel(glpmcfg, hsotg->regs + GLPMCFG);
|
dwc2_writel(hsotg, glpmcfg, GLPMCFG);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
glpmcfg = dwc2_readl(hsotg->regs + GLPMCFG);
|
glpmcfg = dwc2_readl(hsotg, GLPMCFG);
|
||||||
|
|
||||||
if (!(glpmcfg & (GLPMCFG_COREL1RES_MASK |
|
if (!(glpmcfg & (GLPMCFG_COREL1RES_MASK |
|
||||||
GLPMCFG_L1RESUMEOK | GLPMCFG_SLPSTS)))
|
GLPMCFG_L1RESUMEOK | GLPMCFG_SLPSTS)))
|
||||||
@ -398,7 +398,7 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Clear interrupt */
|
/* Clear interrupt */
|
||||||
dwc2_writel(GINTSTS_WKUPINT, hsotg->regs + GINTSTS);
|
dwc2_writel(hsotg, GINTSTS_WKUPINT, GINTSTS);
|
||||||
|
|
||||||
dev_dbg(hsotg->dev, "++Resume or Remote Wakeup Detected Interrupt++\n");
|
dev_dbg(hsotg->dev, "++Resume or Remote Wakeup Detected Interrupt++\n");
|
||||||
dev_dbg(hsotg->dev, "%s lxstate = %d\n", __func__, hsotg->lx_state);
|
dev_dbg(hsotg->dev, "%s lxstate = %d\n", __func__, hsotg->lx_state);
|
||||||
@ -410,13 +410,13 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
|
|||||||
|
|
||||||
if (dwc2_is_device_mode(hsotg)) {
|
if (dwc2_is_device_mode(hsotg)) {
|
||||||
dev_dbg(hsotg->dev, "DSTS=0x%0x\n",
|
dev_dbg(hsotg->dev, "DSTS=0x%0x\n",
|
||||||
dwc2_readl(hsotg->regs + DSTS));
|
dwc2_readl(hsotg, DSTS));
|
||||||
if (hsotg->lx_state == DWC2_L2) {
|
if (hsotg->lx_state == DWC2_L2) {
|
||||||
u32 dctl = dwc2_readl(hsotg->regs + DCTL);
|
u32 dctl = dwc2_readl(hsotg, DCTL);
|
||||||
|
|
||||||
/* Clear Remote Wakeup Signaling */
|
/* Clear Remote Wakeup Signaling */
|
||||||
dctl &= ~DCTL_RMTWKUPSIG;
|
dctl &= ~DCTL_RMTWKUPSIG;
|
||||||
dwc2_writel(dctl, hsotg->regs + DCTL);
|
dwc2_writel(hsotg, dctl, DCTL);
|
||||||
ret = dwc2_exit_partial_power_down(hsotg, true);
|
ret = dwc2_exit_partial_power_down(hsotg, true);
|
||||||
if (ret && (ret != -ENOTSUPP))
|
if (ret && (ret != -ENOTSUPP))
|
||||||
dev_err(hsotg->dev, "exit power_down failed\n");
|
dev_err(hsotg->dev, "exit power_down failed\n");
|
||||||
@ -430,11 +430,11 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (hsotg->lx_state != DWC2_L1) {
|
if (hsotg->lx_state != DWC2_L1) {
|
||||||
u32 pcgcctl = dwc2_readl(hsotg->regs + PCGCTL);
|
u32 pcgcctl = dwc2_readl(hsotg, PCGCTL);
|
||||||
|
|
||||||
/* Restart the Phy Clock */
|
/* Restart the Phy Clock */
|
||||||
pcgcctl &= ~PCGCTL_STOPPCLK;
|
pcgcctl &= ~PCGCTL_STOPPCLK;
|
||||||
dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
|
dwc2_writel(hsotg, pcgcctl, PCGCTL);
|
||||||
mod_timer(&hsotg->wkp_timer,
|
mod_timer(&hsotg->wkp_timer,
|
||||||
jiffies + msecs_to_jiffies(71));
|
jiffies + msecs_to_jiffies(71));
|
||||||
} else {
|
} else {
|
||||||
@ -450,7 +450,7 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg)
|
|||||||
*/
|
*/
|
||||||
static void dwc2_handle_disconnect_intr(struct dwc2_hsotg *hsotg)
|
static void dwc2_handle_disconnect_intr(struct dwc2_hsotg *hsotg)
|
||||||
{
|
{
|
||||||
dwc2_writel(GINTSTS_DISCONNINT, hsotg->regs + GINTSTS);
|
dwc2_writel(hsotg, GINTSTS_DISCONNINT, GINTSTS);
|
||||||
|
|
||||||
dev_dbg(hsotg->dev, "++Disconnect Detected Interrupt++ (%s) %s\n",
|
dev_dbg(hsotg->dev, "++Disconnect Detected Interrupt++ (%s) %s\n",
|
||||||
dwc2_is_host_mode(hsotg) ? "Host" : "Device",
|
dwc2_is_host_mode(hsotg) ? "Host" : "Device",
|
||||||
@ -474,7 +474,7 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Clear interrupt */
|
/* Clear interrupt */
|
||||||
dwc2_writel(GINTSTS_USBSUSP, hsotg->regs + GINTSTS);
|
dwc2_writel(hsotg, GINTSTS_USBSUSP, GINTSTS);
|
||||||
|
|
||||||
dev_dbg(hsotg->dev, "USB SUSPEND\n");
|
dev_dbg(hsotg->dev, "USB SUSPEND\n");
|
||||||
|
|
||||||
@ -483,7 +483,7 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg)
|
|||||||
* Check the Device status register to determine if the Suspend
|
* Check the Device status register to determine if the Suspend
|
||||||
* state is active
|
* state is active
|
||||||
*/
|
*/
|
||||||
dsts = dwc2_readl(hsotg->regs + DSTS);
|
dsts = dwc2_readl(hsotg, DSTS);
|
||||||
dev_dbg(hsotg->dev, "%s: DSTS=0x%0x\n", __func__, dsts);
|
dev_dbg(hsotg->dev, "%s: DSTS=0x%0x\n", __func__, dsts);
|
||||||
dev_dbg(hsotg->dev,
|
dev_dbg(hsotg->dev,
|
||||||
"DSTS.Suspend Status=%d HWCFG4.Power Optimize=%d HWCFG4.Hibernation=%d\n",
|
"DSTS.Suspend Status=%d HWCFG4.Power Optimize=%d HWCFG4.Hibernation=%d\n",
|
||||||
@ -563,9 +563,9 @@ static void dwc2_handle_lpm_intr(struct dwc2_hsotg *hsotg)
|
|||||||
u32 enslpm;
|
u32 enslpm;
|
||||||
|
|
||||||
/* Clear interrupt */
|
/* Clear interrupt */
|
||||||
dwc2_writel(GINTSTS_LPMTRANRCVD, hsotg->regs + GINTSTS);
|
dwc2_writel(hsotg, GINTSTS_LPMTRANRCVD, GINTSTS);
|
||||||
|
|
||||||
glpmcfg = dwc2_readl(hsotg->regs + GLPMCFG);
|
glpmcfg = dwc2_readl(hsotg, GLPMCFG);
|
||||||
|
|
||||||
if (!(glpmcfg & GLPMCFG_LPMCAP)) {
|
if (!(glpmcfg & GLPMCFG_LPMCAP)) {
|
||||||
dev_err(hsotg->dev, "Unexpected LPM interrupt\n");
|
dev_err(hsotg->dev, "Unexpected LPM interrupt\n");
|
||||||
@ -588,16 +588,16 @@ static void dwc2_handle_lpm_intr(struct dwc2_hsotg *hsotg)
|
|||||||
} else {
|
} else {
|
||||||
dev_dbg(hsotg->dev, "Entering Sleep with L1 Gating\n");
|
dev_dbg(hsotg->dev, "Entering Sleep with L1 Gating\n");
|
||||||
|
|
||||||
pcgcctl = dwc2_readl(hsotg->regs + PCGCTL);
|
pcgcctl = dwc2_readl(hsotg, PCGCTL);
|
||||||
pcgcctl |= PCGCTL_ENBL_SLEEP_GATING;
|
pcgcctl |= PCGCTL_ENBL_SLEEP_GATING;
|
||||||
dwc2_writel(pcgcctl, hsotg->regs + PCGCTL);
|
dwc2_writel(hsotg, pcgcctl, PCGCTL);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Examine prt_sleep_sts after TL1TokenTetry period max (10 us)
|
* Examine prt_sleep_sts after TL1TokenTetry period max (10 us)
|
||||||
*/
|
*/
|
||||||
udelay(10);
|
udelay(10);
|
||||||
|
|
||||||
glpmcfg = dwc2_readl(hsotg->regs + GLPMCFG);
|
glpmcfg = dwc2_readl(hsotg, GLPMCFG);
|
||||||
|
|
||||||
if (glpmcfg & GLPMCFG_SLPSTS) {
|
if (glpmcfg & GLPMCFG_SLPSTS) {
|
||||||
/* Save the current state */
|
/* Save the current state */
|
||||||
@ -627,9 +627,9 @@ static u32 dwc2_read_common_intr(struct dwc2_hsotg *hsotg)
|
|||||||
u32 gahbcfg;
|
u32 gahbcfg;
|
||||||
u32 gintmsk_common = GINTMSK_COMMON;
|
u32 gintmsk_common = GINTMSK_COMMON;
|
||||||
|
|
||||||
gintsts = dwc2_readl(hsotg->regs + GINTSTS);
|
gintsts = dwc2_readl(hsotg, GINTSTS);
|
||||||
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
|
gintmsk = dwc2_readl(hsotg, GINTMSK);
|
||||||
gahbcfg = dwc2_readl(hsotg->regs + GAHBCFG);
|
gahbcfg = dwc2_readl(hsotg, GAHBCFG);
|
||||||
|
|
||||||
/* If any common interrupts set */
|
/* If any common interrupts set */
|
||||||
if (gintsts & gintmsk_common)
|
if (gintsts & gintmsk_common)
|
||||||
@ -653,9 +653,9 @@ static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg *hsotg)
|
|||||||
u32 gpwrdn;
|
u32 gpwrdn;
|
||||||
int linestate;
|
int linestate;
|
||||||
|
|
||||||
gpwrdn = dwc2_readl(hsotg->regs + GPWRDN);
|
gpwrdn = dwc2_readl(hsotg, GPWRDN);
|
||||||
/* clear all interrupt */
|
/* clear all interrupt */
|
||||||
dwc2_writel(gpwrdn, hsotg->regs + GPWRDN);
|
dwc2_writel(hsotg, gpwrdn, GPWRDN);
|
||||||
linestate = (gpwrdn & GPWRDN_LINESTATE_MASK) >> GPWRDN_LINESTATE_SHIFT;
|
linestate = (gpwrdn & GPWRDN_LINESTATE_MASK) >> GPWRDN_LINESTATE_SHIFT;
|
||||||
dev_dbg(hsotg->dev,
|
dev_dbg(hsotg->dev,
|
||||||
"%s: dwc2_handle_gpwrdwn_intr called gpwrdn= %08x\n", __func__,
|
"%s: dwc2_handle_gpwrdwn_intr called gpwrdn= %08x\n", __func__,
|
||||||
@ -668,38 +668,38 @@ static void dwc2_handle_gpwrdn_intr(struct dwc2_hsotg *hsotg)
|
|||||||
dev_dbg(hsotg->dev, "%s: GPWRDN_DISCONN_DET\n", __func__);
|
dev_dbg(hsotg->dev, "%s: GPWRDN_DISCONN_DET\n", __func__);
|
||||||
|
|
||||||
/* Switch-on voltage to the core */
|
/* Switch-on voltage to the core */
|
||||||
gpwrdn_tmp = dwc2_readl(hsotg->regs + GPWRDN);
|
gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
|
||||||
gpwrdn_tmp &= ~GPWRDN_PWRDNSWTCH;
|
gpwrdn_tmp &= ~GPWRDN_PWRDNSWTCH;
|
||||||
dwc2_writel(gpwrdn_tmp, hsotg->regs + GPWRDN);
|
dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
|
||||||
udelay(10);
|
udelay(10);
|
||||||
|
|
||||||
/* Reset core */
|
/* Reset core */
|
||||||
gpwrdn_tmp = dwc2_readl(hsotg->regs + GPWRDN);
|
gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
|
||||||
gpwrdn_tmp &= ~GPWRDN_PWRDNRSTN;
|
gpwrdn_tmp &= ~GPWRDN_PWRDNRSTN;
|
||||||
dwc2_writel(gpwrdn_tmp, hsotg->regs + GPWRDN);
|
dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
|
||||||
udelay(10);
|
udelay(10);
|
||||||
|
|
||||||
/* Disable Power Down Clamp */
|
/* Disable Power Down Clamp */
|
||||||
gpwrdn_tmp = dwc2_readl(hsotg->regs + GPWRDN);
|
gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
|
||||||
gpwrdn_tmp &= ~GPWRDN_PWRDNCLMP;
|
gpwrdn_tmp &= ~GPWRDN_PWRDNCLMP;
|
||||||
dwc2_writel(gpwrdn_tmp, hsotg->regs + GPWRDN);
|
dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
|
||||||
udelay(10);
|
udelay(10);
|
||||||
|
|
||||||
/* Deassert reset core */
|
/* Deassert reset core */
|
||||||
gpwrdn_tmp = dwc2_readl(hsotg->regs + GPWRDN);
|
gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
|
||||||
gpwrdn_tmp |= GPWRDN_PWRDNRSTN;
|
gpwrdn_tmp |= GPWRDN_PWRDNRSTN;
|
||||||
dwc2_writel(gpwrdn_tmp, hsotg->regs + GPWRDN);
|
dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
|
||||||
udelay(10);
|
udelay(10);
|
||||||
|
|
||||||
/* Disable PMU interrupt */
|
/* Disable PMU interrupt */
|
||||||
gpwrdn_tmp = dwc2_readl(hsotg->regs + GPWRDN);
|
gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
|
||||||
gpwrdn_tmp &= ~GPWRDN_PMUINTSEL;
|
gpwrdn_tmp &= ~GPWRDN_PMUINTSEL;
|
||||||
dwc2_writel(gpwrdn_tmp, hsotg->regs + GPWRDN);
|
dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
|
||||||
|
|
||||||
/* De-assert Wakeup Logic */
|
/* De-assert Wakeup Logic */
|
||||||
gpwrdn_tmp = dwc2_readl(hsotg->regs + GPWRDN);
|
gpwrdn_tmp = dwc2_readl(hsotg, GPWRDN);
|
||||||
gpwrdn_tmp &= ~GPWRDN_PMUACTV;
|
gpwrdn_tmp &= ~GPWRDN_PMUACTV;
|
||||||
dwc2_writel(gpwrdn_tmp, hsotg->regs + GPWRDN);
|
dwc2_writel(hsotg, gpwrdn_tmp, GPWRDN);
|
||||||
|
|
||||||
hsotg->hibernated = 0;
|
hsotg->hibernated = 0;
|
||||||
|
|
||||||
@ -780,10 +780,10 @@ irqreturn_t dwc2_handle_common_intr(int irq, void *dev)
|
|||||||
|
|
||||||
/* Reading current frame number value in device or host modes. */
|
/* Reading current frame number value in device or host modes. */
|
||||||
if (dwc2_is_device_mode(hsotg))
|
if (dwc2_is_device_mode(hsotg))
|
||||||
hsotg->frame_number = (dwc2_readl(hsotg->regs + DSTS)
|
hsotg->frame_number = (dwc2_readl(hsotg, DSTS)
|
||||||
& DSTS_SOFFN_MASK) >> DSTS_SOFFN_SHIFT;
|
& DSTS_SOFFN_MASK) >> DSTS_SOFFN_SHIFT;
|
||||||
else
|
else
|
||||||
hsotg->frame_number = (dwc2_readl(hsotg->regs + HFNUM)
|
hsotg->frame_number = (dwc2_readl(hsotg, HFNUM)
|
||||||
& HFNUM_FRNUM_MASK) >> HFNUM_FRNUM_SHIFT;
|
& HFNUM_FRNUM_MASK) >> HFNUM_FRNUM_SHIFT;
|
||||||
|
|
||||||
gintsts = dwc2_read_common_intr(hsotg);
|
gintsts = dwc2_read_common_intr(hsotg);
|
||||||
|
@ -69,7 +69,7 @@ static int testmode_show(struct seq_file *s, void *unused)
|
|||||||
int dctl;
|
int dctl;
|
||||||
|
|
||||||
spin_lock_irqsave(&hsotg->lock, flags);
|
spin_lock_irqsave(&hsotg->lock, flags);
|
||||||
dctl = dwc2_readl(hsotg->regs + DCTL);
|
dctl = dwc2_readl(hsotg, DCTL);
|
||||||
dctl &= DCTL_TSTCTL_MASK;
|
dctl &= DCTL_TSTCTL_MASK;
|
||||||
dctl >>= DCTL_TSTCTL_SHIFT;
|
dctl >>= DCTL_TSTCTL_SHIFT;
|
||||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||||
@ -126,42 +126,41 @@ static const struct file_operations testmode_fops = {
|
|||||||
static int state_show(struct seq_file *seq, void *v)
|
static int state_show(struct seq_file *seq, void *v)
|
||||||
{
|
{
|
||||||
struct dwc2_hsotg *hsotg = seq->private;
|
struct dwc2_hsotg *hsotg = seq->private;
|
||||||
void __iomem *regs = hsotg->regs;
|
|
||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
seq_printf(seq, "DCFG=0x%08x, DCTL=0x%08x, DSTS=0x%08x\n",
|
seq_printf(seq, "DCFG=0x%08x, DCTL=0x%08x, DSTS=0x%08x\n",
|
||||||
dwc2_readl(regs + DCFG),
|
dwc2_readl(hsotg, DCFG),
|
||||||
dwc2_readl(regs + DCTL),
|
dwc2_readl(hsotg, DCTL),
|
||||||
dwc2_readl(regs + DSTS));
|
dwc2_readl(hsotg, DSTS));
|
||||||
|
|
||||||
seq_printf(seq, "DIEPMSK=0x%08x, DOEPMASK=0x%08x\n",
|
seq_printf(seq, "DIEPMSK=0x%08x, DOEPMASK=0x%08x\n",
|
||||||
dwc2_readl(regs + DIEPMSK), dwc2_readl(regs + DOEPMSK));
|
dwc2_readl(hsotg, DIEPMSK), dwc2_readl(hsotg, DOEPMSK));
|
||||||
|
|
||||||
seq_printf(seq, "GINTMSK=0x%08x, GINTSTS=0x%08x\n",
|
seq_printf(seq, "GINTMSK=0x%08x, GINTSTS=0x%08x\n",
|
||||||
dwc2_readl(regs + GINTMSK),
|
dwc2_readl(hsotg, GINTMSK),
|
||||||
dwc2_readl(regs + GINTSTS));
|
dwc2_readl(hsotg, GINTSTS));
|
||||||
|
|
||||||
seq_printf(seq, "DAINTMSK=0x%08x, DAINT=0x%08x\n",
|
seq_printf(seq, "DAINTMSK=0x%08x, DAINT=0x%08x\n",
|
||||||
dwc2_readl(regs + DAINTMSK),
|
dwc2_readl(hsotg, DAINTMSK),
|
||||||
dwc2_readl(regs + DAINT));
|
dwc2_readl(hsotg, DAINT));
|
||||||
|
|
||||||
seq_printf(seq, "GNPTXSTS=0x%08x, GRXSTSR=%08x\n",
|
seq_printf(seq, "GNPTXSTS=0x%08x, GRXSTSR=%08x\n",
|
||||||
dwc2_readl(regs + GNPTXSTS),
|
dwc2_readl(hsotg, GNPTXSTS),
|
||||||
dwc2_readl(regs + GRXSTSR));
|
dwc2_readl(hsotg, GRXSTSR));
|
||||||
|
|
||||||
seq_puts(seq, "\nEndpoint status:\n");
|
seq_puts(seq, "\nEndpoint status:\n");
|
||||||
|
|
||||||
for (idx = 0; idx < hsotg->num_of_eps; idx++) {
|
for (idx = 0; idx < hsotg->num_of_eps; idx++) {
|
||||||
u32 in, out;
|
u32 in, out;
|
||||||
|
|
||||||
in = dwc2_readl(regs + DIEPCTL(idx));
|
in = dwc2_readl(hsotg, DIEPCTL(idx));
|
||||||
out = dwc2_readl(regs + DOEPCTL(idx));
|
out = dwc2_readl(hsotg, DOEPCTL(idx));
|
||||||
|
|
||||||
seq_printf(seq, "ep%d: DIEPCTL=0x%08x, DOEPCTL=0x%08x",
|
seq_printf(seq, "ep%d: DIEPCTL=0x%08x, DOEPCTL=0x%08x",
|
||||||
idx, in, out);
|
idx, in, out);
|
||||||
|
|
||||||
in = dwc2_readl(regs + DIEPTSIZ(idx));
|
in = dwc2_readl(hsotg, DIEPTSIZ(idx));
|
||||||
out = dwc2_readl(regs + DOEPTSIZ(idx));
|
out = dwc2_readl(hsotg, DOEPTSIZ(idx));
|
||||||
|
|
||||||
seq_printf(seq, ", DIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x",
|
seq_printf(seq, ", DIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x",
|
||||||
in, out);
|
in, out);
|
||||||
@ -184,14 +183,13 @@ DEFINE_SHOW_ATTRIBUTE(state);
|
|||||||
static int fifo_show(struct seq_file *seq, void *v)
|
static int fifo_show(struct seq_file *seq, void *v)
|
||||||
{
|
{
|
||||||
struct dwc2_hsotg *hsotg = seq->private;
|
struct dwc2_hsotg *hsotg = seq->private;
|
||||||
void __iomem *regs = hsotg->regs;
|
|
||||||
u32 val;
|
u32 val;
|
||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
seq_puts(seq, "Non-periodic FIFOs:\n");
|
seq_puts(seq, "Non-periodic FIFOs:\n");
|
||||||
seq_printf(seq, "RXFIFO: Size %d\n", dwc2_readl(regs + GRXFSIZ));
|
seq_printf(seq, "RXFIFO: Size %d\n", dwc2_readl(hsotg, GRXFSIZ));
|
||||||
|
|
||||||
val = dwc2_readl(regs + GNPTXFSIZ);
|
val = dwc2_readl(hsotg, GNPTXFSIZ);
|
||||||
seq_printf(seq, "NPTXFIFO: Size %d, Start 0x%08x\n",
|
seq_printf(seq, "NPTXFIFO: Size %d, Start 0x%08x\n",
|
||||||
val >> FIFOSIZE_DEPTH_SHIFT,
|
val >> FIFOSIZE_DEPTH_SHIFT,
|
||||||
val & FIFOSIZE_STARTADDR_MASK);
|
val & FIFOSIZE_STARTADDR_MASK);
|
||||||
@ -199,7 +197,7 @@ static int fifo_show(struct seq_file *seq, void *v)
|
|||||||
seq_puts(seq, "\nPeriodic TXFIFOs:\n");
|
seq_puts(seq, "\nPeriodic TXFIFOs:\n");
|
||||||
|
|
||||||
for (idx = 1; idx < hsotg->num_of_eps; idx++) {
|
for (idx = 1; idx < hsotg->num_of_eps; idx++) {
|
||||||
val = dwc2_readl(regs + DPTXFSIZN(idx));
|
val = dwc2_readl(hsotg, DPTXFSIZN(idx));
|
||||||
|
|
||||||
seq_printf(seq, "\tDPTXFIFO%2d: Size %d, Start 0x%08x\n", idx,
|
seq_printf(seq, "\tDPTXFIFO%2d: Size %d, Start 0x%08x\n", idx,
|
||||||
val >> FIFOSIZE_DEPTH_SHIFT,
|
val >> FIFOSIZE_DEPTH_SHIFT,
|
||||||
@ -228,7 +226,6 @@ static int ep_show(struct seq_file *seq, void *v)
|
|||||||
struct dwc2_hsotg_ep *ep = seq->private;
|
struct dwc2_hsotg_ep *ep = seq->private;
|
||||||
struct dwc2_hsotg *hsotg = ep->parent;
|
struct dwc2_hsotg *hsotg = ep->parent;
|
||||||
struct dwc2_hsotg_req *req;
|
struct dwc2_hsotg_req *req;
|
||||||
void __iomem *regs = hsotg->regs;
|
|
||||||
int index = ep->index;
|
int index = ep->index;
|
||||||
int show_limit = 15;
|
int show_limit = 15;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
@ -239,20 +236,20 @@ static int ep_show(struct seq_file *seq, void *v)
|
|||||||
/* first show the register state */
|
/* first show the register state */
|
||||||
|
|
||||||
seq_printf(seq, "\tDIEPCTL=0x%08x, DOEPCTL=0x%08x\n",
|
seq_printf(seq, "\tDIEPCTL=0x%08x, DOEPCTL=0x%08x\n",
|
||||||
dwc2_readl(regs + DIEPCTL(index)),
|
dwc2_readl(hsotg, DIEPCTL(index)),
|
||||||
dwc2_readl(regs + DOEPCTL(index)));
|
dwc2_readl(hsotg, DOEPCTL(index)));
|
||||||
|
|
||||||
seq_printf(seq, "\tDIEPDMA=0x%08x, DOEPDMA=0x%08x\n",
|
seq_printf(seq, "\tDIEPDMA=0x%08x, DOEPDMA=0x%08x\n",
|
||||||
dwc2_readl(regs + DIEPDMA(index)),
|
dwc2_readl(hsotg, DIEPDMA(index)),
|
||||||
dwc2_readl(regs + DOEPDMA(index)));
|
dwc2_readl(hsotg, DOEPDMA(index)));
|
||||||
|
|
||||||
seq_printf(seq, "\tDIEPINT=0x%08x, DOEPINT=0x%08x\n",
|
seq_printf(seq, "\tDIEPINT=0x%08x, DOEPINT=0x%08x\n",
|
||||||
dwc2_readl(regs + DIEPINT(index)),
|
dwc2_readl(hsotg, DIEPINT(index)),
|
||||||
dwc2_readl(regs + DOEPINT(index)));
|
dwc2_readl(hsotg, DOEPINT(index)));
|
||||||
|
|
||||||
seq_printf(seq, "\tDIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x\n",
|
seq_printf(seq, "\tDIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x\n",
|
||||||
dwc2_readl(regs + DIEPTSIZ(index)),
|
dwc2_readl(hsotg, DIEPTSIZ(index)),
|
||||||
dwc2_readl(regs + DOEPTSIZ(index)));
|
dwc2_readl(hsotg, DOEPTSIZ(index)));
|
||||||
|
|
||||||
seq_puts(seq, "\n");
|
seq_puts(seq, "\n");
|
||||||
seq_printf(seq, "mps %d\n", ep->ep.maxpacket);
|
seq_printf(seq, "mps %d\n", ep->ep.maxpacket);
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -469,10 +469,10 @@ static inline struct usb_hcd *dwc2_hsotg_to_hcd(struct dwc2_hsotg *hsotg)
|
|||||||
*/
|
*/
|
||||||
static inline void disable_hc_int(struct dwc2_hsotg *hsotg, int chnum, u32 intr)
|
static inline void disable_hc_int(struct dwc2_hsotg *hsotg, int chnum, u32 intr)
|
||||||
{
|
{
|
||||||
u32 mask = dwc2_readl(hsotg->regs + HCINTMSK(chnum));
|
u32 mask = dwc2_readl(hsotg, HCINTMSK(chnum));
|
||||||
|
|
||||||
mask &= ~intr;
|
mask &= ~intr;
|
||||||
dwc2_writel(mask, hsotg->regs + HCINTMSK(chnum));
|
dwc2_writel(hsotg, mask, HCINTMSK(chnum));
|
||||||
}
|
}
|
||||||
|
|
||||||
void dwc2_hc_cleanup(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan);
|
void dwc2_hc_cleanup(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan);
|
||||||
@ -487,7 +487,7 @@ void dwc2_hc_start_transfer_ddma(struct dwc2_hsotg *hsotg,
|
|||||||
*/
|
*/
|
||||||
static inline u32 dwc2_read_hprt0(struct dwc2_hsotg *hsotg)
|
static inline u32 dwc2_read_hprt0(struct dwc2_hsotg *hsotg)
|
||||||
{
|
{
|
||||||
u32 hprt0 = dwc2_readl(hsotg->regs + HPRT0);
|
u32 hprt0 = dwc2_readl(hsotg, HPRT0);
|
||||||
|
|
||||||
hprt0 &= ~(HPRT0_ENA | HPRT0_CONNDET | HPRT0_ENACHG | HPRT0_OVRCURRCHG);
|
hprt0 &= ~(HPRT0_ENA | HPRT0_CONNDET | HPRT0_ENACHG | HPRT0_OVRCURRCHG);
|
||||||
return hprt0;
|
return hprt0;
|
||||||
@ -690,8 +690,8 @@ static inline u16 dwc2_micro_frame_num(u16 frame)
|
|||||||
*/
|
*/
|
||||||
static inline u32 dwc2_read_core_intr(struct dwc2_hsotg *hsotg)
|
static inline u32 dwc2_read_core_intr(struct dwc2_hsotg *hsotg)
|
||||||
{
|
{
|
||||||
return dwc2_readl(hsotg->regs + GINTSTS) &
|
return dwc2_readl(hsotg, GINTSTS) &
|
||||||
dwc2_readl(hsotg->regs + GINTMSK);
|
dwc2_readl(hsotg, GINTMSK);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u32 dwc2_hcd_urb_get_status(struct dwc2_hcd_urb *dwc2_urb)
|
static inline u32 dwc2_hcd_urb_get_status(struct dwc2_hcd_urb *dwc2_urb)
|
||||||
|
@ -185,19 +185,19 @@ static void dwc2_per_sched_enable(struct dwc2_hsotg *hsotg, u32 fr_list_en)
|
|||||||
|
|
||||||
spin_lock_irqsave(&hsotg->lock, flags);
|
spin_lock_irqsave(&hsotg->lock, flags);
|
||||||
|
|
||||||
hcfg = dwc2_readl(hsotg->regs + HCFG);
|
hcfg = dwc2_readl(hsotg, HCFG);
|
||||||
if (hcfg & HCFG_PERSCHEDENA) {
|
if (hcfg & HCFG_PERSCHEDENA) {
|
||||||
/* already enabled */
|
/* already enabled */
|
||||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dwc2_writel(hsotg->frame_list_dma, hsotg->regs + HFLBADDR);
|
dwc2_writel(hsotg, hsotg->frame_list_dma, HFLBADDR);
|
||||||
|
|
||||||
hcfg &= ~HCFG_FRLISTEN_MASK;
|
hcfg &= ~HCFG_FRLISTEN_MASK;
|
||||||
hcfg |= fr_list_en | HCFG_PERSCHEDENA;
|
hcfg |= fr_list_en | HCFG_PERSCHEDENA;
|
||||||
dev_vdbg(hsotg->dev, "Enabling Periodic schedule\n");
|
dev_vdbg(hsotg->dev, "Enabling Periodic schedule\n");
|
||||||
dwc2_writel(hcfg, hsotg->regs + HCFG);
|
dwc2_writel(hsotg, hcfg, HCFG);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||||
}
|
}
|
||||||
@ -209,7 +209,7 @@ static void dwc2_per_sched_disable(struct dwc2_hsotg *hsotg)
|
|||||||
|
|
||||||
spin_lock_irqsave(&hsotg->lock, flags);
|
spin_lock_irqsave(&hsotg->lock, flags);
|
||||||
|
|
||||||
hcfg = dwc2_readl(hsotg->regs + HCFG);
|
hcfg = dwc2_readl(hsotg, HCFG);
|
||||||
if (!(hcfg & HCFG_PERSCHEDENA)) {
|
if (!(hcfg & HCFG_PERSCHEDENA)) {
|
||||||
/* already disabled */
|
/* already disabled */
|
||||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||||
@ -218,7 +218,7 @@ static void dwc2_per_sched_disable(struct dwc2_hsotg *hsotg)
|
|||||||
|
|
||||||
hcfg &= ~HCFG_PERSCHEDENA;
|
hcfg &= ~HCFG_PERSCHEDENA;
|
||||||
dev_vdbg(hsotg->dev, "Disabling Periodic schedule\n");
|
dev_vdbg(hsotg->dev, "Disabling Periodic schedule\n");
|
||||||
dwc2_writel(hcfg, hsotg->regs + HCFG);
|
dwc2_writel(hsotg, hcfg, HCFG);
|
||||||
|
|
||||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||||
}
|
}
|
||||||
|
@ -144,7 +144,7 @@ static void dwc2_sof_intr(struct dwc2_hsotg *hsotg)
|
|||||||
enum dwc2_transaction_type tr_type;
|
enum dwc2_transaction_type tr_type;
|
||||||
|
|
||||||
/* Clear interrupt */
|
/* Clear interrupt */
|
||||||
dwc2_writel(GINTSTS_SOF, hsotg->regs + GINTSTS);
|
dwc2_writel(hsotg, GINTSTS_SOF, GINTSTS);
|
||||||
|
|
||||||
#ifdef DEBUG_SOF
|
#ifdef DEBUG_SOF
|
||||||
dev_vdbg(hsotg->dev, "--Start of Frame Interrupt--\n");
|
dev_vdbg(hsotg->dev, "--Start of Frame Interrupt--\n");
|
||||||
@ -191,7 +191,7 @@ static void dwc2_rx_fifo_level_intr(struct dwc2_hsotg *hsotg)
|
|||||||
if (dbg_perio())
|
if (dbg_perio())
|
||||||
dev_vdbg(hsotg->dev, "--RxFIFO Level Interrupt--\n");
|
dev_vdbg(hsotg->dev, "--RxFIFO Level Interrupt--\n");
|
||||||
|
|
||||||
grxsts = dwc2_readl(hsotg->regs + GRXSTSP);
|
grxsts = dwc2_readl(hsotg, GRXSTSP);
|
||||||
chnum = (grxsts & GRXSTS_HCHNUM_MASK) >> GRXSTS_HCHNUM_SHIFT;
|
chnum = (grxsts & GRXSTS_HCHNUM_MASK) >> GRXSTS_HCHNUM_SHIFT;
|
||||||
chan = hsotg->hc_ptr_array[chnum];
|
chan = hsotg->hc_ptr_array[chnum];
|
||||||
if (!chan) {
|
if (!chan) {
|
||||||
@ -274,11 +274,11 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
|
|||||||
dev_vdbg(hsotg->dev, "%s(%p)\n", __func__, hsotg);
|
dev_vdbg(hsotg->dev, "%s(%p)\n", __func__, hsotg);
|
||||||
|
|
||||||
/* Every time when port enables calculate HFIR.FrInterval */
|
/* Every time when port enables calculate HFIR.FrInterval */
|
||||||
hfir = dwc2_readl(hsotg->regs + HFIR);
|
hfir = dwc2_readl(hsotg, HFIR);
|
||||||
hfir &= ~HFIR_FRINT_MASK;
|
hfir &= ~HFIR_FRINT_MASK;
|
||||||
hfir |= dwc2_calc_frame_interval(hsotg) << HFIR_FRINT_SHIFT &
|
hfir |= dwc2_calc_frame_interval(hsotg) << HFIR_FRINT_SHIFT &
|
||||||
HFIR_FRINT_MASK;
|
HFIR_FRINT_MASK;
|
||||||
dwc2_writel(hfir, hsotg->regs + HFIR);
|
dwc2_writel(hsotg, hfir, HFIR);
|
||||||
|
|
||||||
/* Check if we need to adjust the PHY clock speed for low power */
|
/* Check if we need to adjust the PHY clock speed for low power */
|
||||||
if (!params->host_support_fs_ls_low_power) {
|
if (!params->host_support_fs_ls_low_power) {
|
||||||
@ -287,7 +287,7 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
usbcfg = dwc2_readl(hsotg->regs + GUSBCFG);
|
usbcfg = dwc2_readl(hsotg, GUSBCFG);
|
||||||
prtspd = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
|
prtspd = (hprt0 & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
|
||||||
|
|
||||||
if (prtspd == HPRT0_SPD_LOW_SPEED || prtspd == HPRT0_SPD_FULL_SPEED) {
|
if (prtspd == HPRT0_SPD_LOW_SPEED || prtspd == HPRT0_SPD_FULL_SPEED) {
|
||||||
@ -295,11 +295,11 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
|
|||||||
if (!(usbcfg & GUSBCFG_PHY_LP_CLK_SEL)) {
|
if (!(usbcfg & GUSBCFG_PHY_LP_CLK_SEL)) {
|
||||||
/* Set PHY low power clock select for FS/LS devices */
|
/* Set PHY low power clock select for FS/LS devices */
|
||||||
usbcfg |= GUSBCFG_PHY_LP_CLK_SEL;
|
usbcfg |= GUSBCFG_PHY_LP_CLK_SEL;
|
||||||
dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
|
dwc2_writel(hsotg, usbcfg, GUSBCFG);
|
||||||
do_reset = 1;
|
do_reset = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
hcfg = dwc2_readl(hsotg->regs + HCFG);
|
hcfg = dwc2_readl(hsotg, HCFG);
|
||||||
fslspclksel = (hcfg & HCFG_FSLSPCLKSEL_MASK) >>
|
fslspclksel = (hcfg & HCFG_FSLSPCLKSEL_MASK) >>
|
||||||
HCFG_FSLSPCLKSEL_SHIFT;
|
HCFG_FSLSPCLKSEL_SHIFT;
|
||||||
|
|
||||||
@ -312,7 +312,7 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
|
|||||||
fslspclksel = HCFG_FSLSPCLKSEL_6_MHZ;
|
fslspclksel = HCFG_FSLSPCLKSEL_6_MHZ;
|
||||||
hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
|
hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
|
||||||
hcfg |= fslspclksel << HCFG_FSLSPCLKSEL_SHIFT;
|
hcfg |= fslspclksel << HCFG_FSLSPCLKSEL_SHIFT;
|
||||||
dwc2_writel(hcfg, hsotg->regs + HCFG);
|
dwc2_writel(hsotg, hcfg, HCFG);
|
||||||
do_reset = 1;
|
do_reset = 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -323,7 +323,7 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
|
|||||||
fslspclksel = HCFG_FSLSPCLKSEL_48_MHZ;
|
fslspclksel = HCFG_FSLSPCLKSEL_48_MHZ;
|
||||||
hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
|
hcfg &= ~HCFG_FSLSPCLKSEL_MASK;
|
||||||
hcfg |= fslspclksel << HCFG_FSLSPCLKSEL_SHIFT;
|
hcfg |= fslspclksel << HCFG_FSLSPCLKSEL_SHIFT;
|
||||||
dwc2_writel(hcfg, hsotg->regs + HCFG);
|
dwc2_writel(hsotg, hcfg, HCFG);
|
||||||
do_reset = 1;
|
do_reset = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -331,14 +331,14 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0,
|
|||||||
/* Not low power */
|
/* Not low power */
|
||||||
if (usbcfg & GUSBCFG_PHY_LP_CLK_SEL) {
|
if (usbcfg & GUSBCFG_PHY_LP_CLK_SEL) {
|
||||||
usbcfg &= ~GUSBCFG_PHY_LP_CLK_SEL;
|
usbcfg &= ~GUSBCFG_PHY_LP_CLK_SEL;
|
||||||
dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
|
dwc2_writel(hsotg, usbcfg, GUSBCFG);
|
||||||
do_reset = 1;
|
do_reset = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (do_reset) {
|
if (do_reset) {
|
||||||
*hprt0_modify |= HPRT0_RST;
|
*hprt0_modify |= HPRT0_RST;
|
||||||
dwc2_writel(*hprt0_modify, hsotg->regs + HPRT0);
|
dwc2_writel(hsotg, *hprt0_modify, HPRT0);
|
||||||
queue_delayed_work(hsotg->wq_otg, &hsotg->reset_work,
|
queue_delayed_work(hsotg->wq_otg, &hsotg->reset_work,
|
||||||
msecs_to_jiffies(60));
|
msecs_to_jiffies(60));
|
||||||
} else {
|
} else {
|
||||||
@ -359,7 +359,7 @@ static void dwc2_port_intr(struct dwc2_hsotg *hsotg)
|
|||||||
|
|
||||||
dev_vdbg(hsotg->dev, "--Port Interrupt--\n");
|
dev_vdbg(hsotg->dev, "--Port Interrupt--\n");
|
||||||
|
|
||||||
hprt0 = dwc2_readl(hsotg->regs + HPRT0);
|
hprt0 = dwc2_readl(hsotg, HPRT0);
|
||||||
hprt0_modify = hprt0;
|
hprt0_modify = hprt0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -374,7 +374,7 @@ static void dwc2_port_intr(struct dwc2_hsotg *hsotg)
|
|||||||
* Set flag and clear if detected
|
* Set flag and clear if detected
|
||||||
*/
|
*/
|
||||||
if (hprt0 & HPRT0_CONNDET) {
|
if (hprt0 & HPRT0_CONNDET) {
|
||||||
dwc2_writel(hprt0_modify | HPRT0_CONNDET, hsotg->regs + HPRT0);
|
dwc2_writel(hsotg, hprt0_modify | HPRT0_CONNDET, HPRT0);
|
||||||
|
|
||||||
dev_vdbg(hsotg->dev,
|
dev_vdbg(hsotg->dev,
|
||||||
"--Port Interrupt HPRT0=0x%08x Port Connect Detected--\n",
|
"--Port Interrupt HPRT0=0x%08x Port Connect Detected--\n",
|
||||||
@ -392,7 +392,7 @@ static void dwc2_port_intr(struct dwc2_hsotg *hsotg)
|
|||||||
* Clear if detected - Set internal flag if disabled
|
* Clear if detected - Set internal flag if disabled
|
||||||
*/
|
*/
|
||||||
if (hprt0 & HPRT0_ENACHG) {
|
if (hprt0 & HPRT0_ENACHG) {
|
||||||
dwc2_writel(hprt0_modify | HPRT0_ENACHG, hsotg->regs + HPRT0);
|
dwc2_writel(hsotg, hprt0_modify | HPRT0_ENACHG, HPRT0);
|
||||||
dev_vdbg(hsotg->dev,
|
dev_vdbg(hsotg->dev,
|
||||||
" --Port Interrupt HPRT0=0x%08x Port Enable Changed (now %d)--\n",
|
" --Port Interrupt HPRT0=0x%08x Port Enable Changed (now %d)--\n",
|
||||||
hprt0, !!(hprt0 & HPRT0_ENA));
|
hprt0, !!(hprt0 & HPRT0_ENA));
|
||||||
@ -406,17 +406,17 @@ static void dwc2_port_intr(struct dwc2_hsotg *hsotg)
|
|||||||
|
|
||||||
hsotg->params.dma_desc_enable = false;
|
hsotg->params.dma_desc_enable = false;
|
||||||
hsotg->new_connection = false;
|
hsotg->new_connection = false;
|
||||||
hcfg = dwc2_readl(hsotg->regs + HCFG);
|
hcfg = dwc2_readl(hsotg, HCFG);
|
||||||
hcfg &= ~HCFG_DESCDMA;
|
hcfg &= ~HCFG_DESCDMA;
|
||||||
dwc2_writel(hcfg, hsotg->regs + HCFG);
|
dwc2_writel(hsotg, hcfg, HCFG);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Overcurrent Change Interrupt */
|
/* Overcurrent Change Interrupt */
|
||||||
if (hprt0 & HPRT0_OVRCURRCHG) {
|
if (hprt0 & HPRT0_OVRCURRCHG) {
|
||||||
dwc2_writel(hprt0_modify | HPRT0_OVRCURRCHG,
|
dwc2_writel(hsotg, hprt0_modify | HPRT0_OVRCURRCHG,
|
||||||
hsotg->regs + HPRT0);
|
HPRT0);
|
||||||
dev_vdbg(hsotg->dev,
|
dev_vdbg(hsotg->dev,
|
||||||
" --Port Interrupt HPRT0=0x%08x Port Overcurrent Changed--\n",
|
" --Port Interrupt HPRT0=0x%08x Port Overcurrent Changed--\n",
|
||||||
hprt0);
|
hprt0);
|
||||||
@ -441,7 +441,7 @@ static u32 dwc2_get_actual_xfer_length(struct dwc2_hsotg *hsotg,
|
|||||||
{
|
{
|
||||||
u32 hctsiz, count, length;
|
u32 hctsiz, count, length;
|
||||||
|
|
||||||
hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
|
hctsiz = dwc2_readl(hsotg, HCTSIZ(chnum));
|
||||||
|
|
||||||
if (halt_status == DWC2_HC_XFER_COMPLETE) {
|
if (halt_status == DWC2_HC_XFER_COMPLETE) {
|
||||||
if (chan->ep_is_in) {
|
if (chan->ep_is_in) {
|
||||||
@ -518,7 +518,7 @@ static int dwc2_update_urb_state(struct dwc2_hsotg *hsotg,
|
|||||||
urb->status = 0;
|
urb->status = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
|
hctsiz = dwc2_readl(hsotg, HCTSIZ(chnum));
|
||||||
dev_vdbg(hsotg->dev, "DWC_otg: %s: %s, channel %d\n",
|
dev_vdbg(hsotg->dev, "DWC_otg: %s: %s, channel %d\n",
|
||||||
__func__, (chan->ep_is_in ? "IN" : "OUT"), chnum);
|
__func__, (chan->ep_is_in ? "IN" : "OUT"), chnum);
|
||||||
dev_vdbg(hsotg->dev, " chan->xfer_len %d\n", chan->xfer_len);
|
dev_vdbg(hsotg->dev, " chan->xfer_len %d\n", chan->xfer_len);
|
||||||
@ -541,7 +541,7 @@ void dwc2_hcd_save_data_toggle(struct dwc2_hsotg *hsotg,
|
|||||||
struct dwc2_host_chan *chan, int chnum,
|
struct dwc2_host_chan *chan, int chnum,
|
||||||
struct dwc2_qtd *qtd)
|
struct dwc2_qtd *qtd)
|
||||||
{
|
{
|
||||||
u32 hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
|
u32 hctsiz = dwc2_readl(hsotg, HCTSIZ(chnum));
|
||||||
u32 pid = (hctsiz & TSIZ_SC_MC_PID_MASK) >> TSIZ_SC_MC_PID_SHIFT;
|
u32 pid = (hctsiz & TSIZ_SC_MC_PID_MASK) >> TSIZ_SC_MC_PID_SHIFT;
|
||||||
|
|
||||||
if (chan->ep_type != USB_ENDPOINT_XFER_CONTROL) {
|
if (chan->ep_type != USB_ENDPOINT_XFER_CONTROL) {
|
||||||
@ -780,9 +780,9 @@ cleanup:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
haintmsk = dwc2_readl(hsotg->regs + HAINTMSK);
|
haintmsk = dwc2_readl(hsotg, HAINTMSK);
|
||||||
haintmsk &= ~(1 << chan->hc_num);
|
haintmsk &= ~(1 << chan->hc_num);
|
||||||
dwc2_writel(haintmsk, hsotg->regs + HAINTMSK);
|
dwc2_writel(hsotg, haintmsk, HAINTMSK);
|
||||||
|
|
||||||
/* Try to queue more transfers now that there's a free channel */
|
/* Try to queue more transfers now that there's a free channel */
|
||||||
tr_type = dwc2_hcd_select_transactions(hsotg);
|
tr_type = dwc2_hcd_select_transactions(hsotg);
|
||||||
@ -829,9 +829,9 @@ static void dwc2_halt_channel(struct dwc2_hsotg *hsotg,
|
|||||||
* is enabled so that the non-periodic schedule will
|
* is enabled so that the non-periodic schedule will
|
||||||
* be processed
|
* be processed
|
||||||
*/
|
*/
|
||||||
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
|
gintmsk = dwc2_readl(hsotg, GINTMSK);
|
||||||
gintmsk |= GINTSTS_NPTXFEMP;
|
gintmsk |= GINTSTS_NPTXFEMP;
|
||||||
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
|
dwc2_writel(hsotg, gintmsk, GINTMSK);
|
||||||
} else {
|
} else {
|
||||||
dev_vdbg(hsotg->dev, "isoc/intr\n");
|
dev_vdbg(hsotg->dev, "isoc/intr\n");
|
||||||
/*
|
/*
|
||||||
@ -848,9 +848,9 @@ static void dwc2_halt_channel(struct dwc2_hsotg *hsotg,
|
|||||||
* enabled so that the periodic schedule will be
|
* enabled so that the periodic schedule will be
|
||||||
* processed
|
* processed
|
||||||
*/
|
*/
|
||||||
gintmsk = dwc2_readl(hsotg->regs + GINTMSK);
|
gintmsk = dwc2_readl(hsotg, GINTMSK);
|
||||||
gintmsk |= GINTSTS_PTXFEMP;
|
gintmsk |= GINTSTS_PTXFEMP;
|
||||||
dwc2_writel(gintmsk, hsotg->regs + GINTMSK);
|
dwc2_writel(hsotg, gintmsk, GINTMSK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -915,7 +915,7 @@ static void dwc2_complete_periodic_xfer(struct dwc2_hsotg *hsotg,
|
|||||||
struct dwc2_qtd *qtd,
|
struct dwc2_qtd *qtd,
|
||||||
enum dwc2_halt_status halt_status)
|
enum dwc2_halt_status halt_status)
|
||||||
{
|
{
|
||||||
u32 hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
|
u32 hctsiz = dwc2_readl(hsotg, HCTSIZ(chnum));
|
||||||
|
|
||||||
qtd->error_count = 0;
|
qtd->error_count = 0;
|
||||||
|
|
||||||
@ -959,7 +959,7 @@ static int dwc2_xfercomp_isoc_split_in(struct dwc2_hsotg *hsotg,
|
|||||||
|
|
||||||
qtd->isoc_split_offset += len;
|
qtd->isoc_split_offset += len;
|
||||||
|
|
||||||
hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
|
hctsiz = dwc2_readl(hsotg, HCTSIZ(chnum));
|
||||||
pid = (hctsiz & TSIZ_SC_MC_PID_MASK) >> TSIZ_SC_MC_PID_SHIFT;
|
pid = (hctsiz & TSIZ_SC_MC_PID_MASK) >> TSIZ_SC_MC_PID_SHIFT;
|
||||||
|
|
||||||
if (frame_desc->actual_length >= frame_desc->length || pid == 0) {
|
if (frame_desc->actual_length >= frame_desc->length || pid == 0) {
|
||||||
@ -1185,7 +1185,7 @@ static void dwc2_update_urb_state_abn(struct dwc2_hsotg *hsotg,
|
|||||||
|
|
||||||
urb->actual_length += xfer_length;
|
urb->actual_length += xfer_length;
|
||||||
|
|
||||||
hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
|
hctsiz = dwc2_readl(hsotg, HCTSIZ(chnum));
|
||||||
dev_vdbg(hsotg->dev, "DWC_otg: %s: %s, channel %d\n",
|
dev_vdbg(hsotg->dev, "DWC_otg: %s: %s, channel %d\n",
|
||||||
__func__, (chan->ep_is_in ? "IN" : "OUT"), chnum);
|
__func__, (chan->ep_is_in ? "IN" : "OUT"), chnum);
|
||||||
dev_vdbg(hsotg->dev, " chan->start_pkt_count %d\n",
|
dev_vdbg(hsotg->dev, " chan->start_pkt_count %d\n",
|
||||||
@ -1566,10 +1566,10 @@ static void dwc2_hc_ahberr_intr(struct dwc2_hsotg *hsotg,
|
|||||||
|
|
||||||
dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
|
dwc2_hc_handle_tt_clear(hsotg, chan, qtd);
|
||||||
|
|
||||||
hcchar = dwc2_readl(hsotg->regs + HCCHAR(chnum));
|
hcchar = dwc2_readl(hsotg, HCCHAR(chnum));
|
||||||
hcsplt = dwc2_readl(hsotg->regs + HCSPLT(chnum));
|
hcsplt = dwc2_readl(hsotg, HCSPLT(chnum));
|
||||||
hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
|
hctsiz = dwc2_readl(hsotg, HCTSIZ(chnum));
|
||||||
hc_dma = dwc2_readl(hsotg->regs + HCDMA(chnum));
|
hc_dma = dwc2_readl(hsotg, HCDMA(chnum));
|
||||||
|
|
||||||
dev_err(hsotg->dev, "AHB ERROR, Channel %d\n", chnum);
|
dev_err(hsotg->dev, "AHB ERROR, Channel %d\n", chnum);
|
||||||
dev_err(hsotg->dev, " hcchar 0x%08x, hcsplt 0x%08x\n", hcchar, hcsplt);
|
dev_err(hsotg->dev, " hcchar 0x%08x, hcsplt 0x%08x\n", hcchar, hcsplt);
|
||||||
@ -1781,10 +1781,10 @@ static bool dwc2_halt_status_ok(struct dwc2_hsotg *hsotg,
|
|||||||
* This code is here only as a check. This condition should
|
* This code is here only as a check. This condition should
|
||||||
* never happen. Ignore the halt if it does occur.
|
* never happen. Ignore the halt if it does occur.
|
||||||
*/
|
*/
|
||||||
hcchar = dwc2_readl(hsotg->regs + HCCHAR(chnum));
|
hcchar = dwc2_readl(hsotg, HCCHAR(chnum));
|
||||||
hctsiz = dwc2_readl(hsotg->regs + HCTSIZ(chnum));
|
hctsiz = dwc2_readl(hsotg, HCTSIZ(chnum));
|
||||||
hcintmsk = dwc2_readl(hsotg->regs + HCINTMSK(chnum));
|
hcintmsk = dwc2_readl(hsotg, HCINTMSK(chnum));
|
||||||
hcsplt = dwc2_readl(hsotg->regs + HCSPLT(chnum));
|
hcsplt = dwc2_readl(hsotg, HCSPLT(chnum));
|
||||||
dev_dbg(hsotg->dev,
|
dev_dbg(hsotg->dev,
|
||||||
"%s: chan->halt_status DWC2_HC_XFER_NO_HALT_STATUS,\n",
|
"%s: chan->halt_status DWC2_HC_XFER_NO_HALT_STATUS,\n",
|
||||||
__func__);
|
__func__);
|
||||||
@ -1808,7 +1808,7 @@ static bool dwc2_halt_status_ok(struct dwc2_hsotg *hsotg,
|
|||||||
* when the halt interrupt occurs. Halt the channel again if it does
|
* when the halt interrupt occurs. Halt the channel again if it does
|
||||||
* occur.
|
* occur.
|
||||||
*/
|
*/
|
||||||
hcchar = dwc2_readl(hsotg->regs + HCCHAR(chnum));
|
hcchar = dwc2_readl(hsotg, HCCHAR(chnum));
|
||||||
if (hcchar & HCCHAR_CHDIS) {
|
if (hcchar & HCCHAR_CHDIS) {
|
||||||
dev_warn(hsotg->dev,
|
dev_warn(hsotg->dev,
|
||||||
"%s: hcchar.chdis set unexpectedly, hcchar 0x%08x, trying to halt again\n",
|
"%s: hcchar.chdis set unexpectedly, hcchar 0x%08x, trying to halt again\n",
|
||||||
@ -1868,7 +1868,7 @@ static void dwc2_hc_chhltd_intr_dma(struct dwc2_hsotg *hsotg,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
hcintmsk = dwc2_readl(hsotg->regs + HCINTMSK(chnum));
|
hcintmsk = dwc2_readl(hsotg, HCINTMSK(chnum));
|
||||||
|
|
||||||
if (chan->hcint & HCINTMSK_XFERCOMPL) {
|
if (chan->hcint & HCINTMSK_XFERCOMPL) {
|
||||||
/*
|
/*
|
||||||
@ -1963,7 +1963,7 @@ static void dwc2_hc_chhltd_intr_dma(struct dwc2_hsotg *hsotg,
|
|||||||
dev_err(hsotg->dev,
|
dev_err(hsotg->dev,
|
||||||
"hcint 0x%08x, intsts 0x%08x\n",
|
"hcint 0x%08x, intsts 0x%08x\n",
|
||||||
chan->hcint,
|
chan->hcint,
|
||||||
dwc2_readl(hsotg->regs + GINTSTS));
|
dwc2_readl(hsotg, GINTSTS));
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2036,11 +2036,11 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum)
|
|||||||
|
|
||||||
chan = hsotg->hc_ptr_array[chnum];
|
chan = hsotg->hc_ptr_array[chnum];
|
||||||
|
|
||||||
hcint = dwc2_readl(hsotg->regs + HCINT(chnum));
|
hcint = dwc2_readl(hsotg, HCINT(chnum));
|
||||||
hcintmsk = dwc2_readl(hsotg->regs + HCINTMSK(chnum));
|
hcintmsk = dwc2_readl(hsotg, HCINTMSK(chnum));
|
||||||
if (!chan) {
|
if (!chan) {
|
||||||
dev_err(hsotg->dev, "## hc_ptr_array for channel is NULL ##\n");
|
dev_err(hsotg->dev, "## hc_ptr_array for channel is NULL ##\n");
|
||||||
dwc2_writel(hcint, hsotg->regs + HCINT(chnum));
|
dwc2_writel(hsotg, hcint, HCINT(chnum));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2052,7 +2052,7 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum)
|
|||||||
hcint, hcintmsk, hcint & hcintmsk);
|
hcint, hcintmsk, hcint & hcintmsk);
|
||||||
}
|
}
|
||||||
|
|
||||||
dwc2_writel(hcint, hsotg->regs + HCINT(chnum));
|
dwc2_writel(hsotg, hcint, HCINT(chnum));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we got an interrupt after someone called
|
* If we got an interrupt after someone called
|
||||||
@ -2187,7 +2187,7 @@ static void dwc2_hc_intr(struct dwc2_hsotg *hsotg)
|
|||||||
int i;
|
int i;
|
||||||
struct dwc2_host_chan *chan, *chan_tmp;
|
struct dwc2_host_chan *chan, *chan_tmp;
|
||||||
|
|
||||||
haint = dwc2_readl(hsotg->regs + HAINT);
|
haint = dwc2_readl(hsotg, HAINT);
|
||||||
if (dbg_perio()) {
|
if (dbg_perio()) {
|
||||||
dev_vdbg(hsotg->dev, "%s()\n", __func__);
|
dev_vdbg(hsotg->dev, "%s()\n", __func__);
|
||||||
|
|
||||||
@ -2271,8 +2271,8 @@ irqreturn_t dwc2_handle_hcd_intr(struct dwc2_hsotg *hsotg)
|
|||||||
"DWC OTG HCD Finished Servicing Interrupts\n");
|
"DWC OTG HCD Finished Servicing Interrupts\n");
|
||||||
dev_vdbg(hsotg->dev,
|
dev_vdbg(hsotg->dev,
|
||||||
"DWC OTG HCD gintsts=0x%08x gintmsk=0x%08x\n",
|
"DWC OTG HCD gintsts=0x%08x gintmsk=0x%08x\n",
|
||||||
dwc2_readl(hsotg->regs + GINTSTS),
|
dwc2_readl(hsotg, GINTSTS),
|
||||||
dwc2_readl(hsotg->regs + GINTMSK));
|
dwc2_readl(hsotg, GINTMSK));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1510,7 +1510,7 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh,
|
|||||||
bool ep_is_in = !!dwc2_hcd_is_pipe_in(&urb->pipe_info);
|
bool ep_is_in = !!dwc2_hcd_is_pipe_in(&urb->pipe_info);
|
||||||
bool ep_is_isoc = (ep_type == USB_ENDPOINT_XFER_ISOC);
|
bool ep_is_isoc = (ep_type == USB_ENDPOINT_XFER_ISOC);
|
||||||
bool ep_is_int = (ep_type == USB_ENDPOINT_XFER_INT);
|
bool ep_is_int = (ep_type == USB_ENDPOINT_XFER_INT);
|
||||||
u32 hprt = dwc2_readl(hsotg->regs + HPRT0);
|
u32 hprt = dwc2_readl(hsotg, HPRT0);
|
||||||
u32 prtspd = (hprt & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
|
u32 prtspd = (hprt & HPRT0_SPD_MASK) >> HPRT0_SPD_SHIFT;
|
||||||
bool do_split = (prtspd == HPRT0_SPD_HIGH_SPEED &&
|
bool do_split = (prtspd == HPRT0_SPD_HIGH_SPEED &&
|
||||||
dev_speed != USB_SPEED_HIGH);
|
dev_speed != USB_SPEED_HIGH);
|
||||||
@ -1747,9 +1747,9 @@ int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
|
|||||||
if (status)
|
if (status)
|
||||||
return status;
|
return status;
|
||||||
if (!hsotg->periodic_qh_count) {
|
if (!hsotg->periodic_qh_count) {
|
||||||
intr_mask = dwc2_readl(hsotg->regs + GINTMSK);
|
intr_mask = dwc2_readl(hsotg, GINTMSK);
|
||||||
intr_mask |= GINTSTS_SOF;
|
intr_mask |= GINTSTS_SOF;
|
||||||
dwc2_writel(intr_mask, hsotg->regs + GINTMSK);
|
dwc2_writel(hsotg, intr_mask, GINTMSK);
|
||||||
}
|
}
|
||||||
hsotg->periodic_qh_count++;
|
hsotg->periodic_qh_count++;
|
||||||
|
|
||||||
@ -1788,9 +1788,9 @@ void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh)
|
|||||||
hsotg->periodic_qh_count--;
|
hsotg->periodic_qh_count--;
|
||||||
if (!hsotg->periodic_qh_count &&
|
if (!hsotg->periodic_qh_count &&
|
||||||
!hsotg->params.dma_desc_enable) {
|
!hsotg->params.dma_desc_enable) {
|
||||||
intr_mask = dwc2_readl(hsotg->regs + GINTMSK);
|
intr_mask = dwc2_readl(hsotg, GINTMSK);
|
||||||
intr_mask &= ~GINTSTS_SOF;
|
intr_mask &= ~GINTSTS_SOF;
|
||||||
dwc2_writel(intr_mask, hsotg->regs + GINTMSK);
|
dwc2_writel(hsotg, intr_mask, GINTMSK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,6 @@ static void dwc2_set_bcm_params(struct dwc2_hsotg *hsotg)
|
|||||||
p->max_transfer_size = 65535;
|
p->max_transfer_size = 65535;
|
||||||
p->max_packet_count = 511;
|
p->max_packet_count = 511;
|
||||||
p->ahbcfg = 0x10;
|
p->ahbcfg = 0x10;
|
||||||
p->uframe_sched = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dwc2_set_his_params(struct dwc2_hsotg *hsotg)
|
static void dwc2_set_his_params(struct dwc2_hsotg *hsotg)
|
||||||
@ -68,7 +67,6 @@ static void dwc2_set_his_params(struct dwc2_hsotg *hsotg)
|
|||||||
p->reload_ctl = false;
|
p->reload_ctl = false;
|
||||||
p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 <<
|
p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 <<
|
||||||
GAHBCFG_HBSTLEN_SHIFT;
|
GAHBCFG_HBSTLEN_SHIFT;
|
||||||
p->uframe_sched = false;
|
|
||||||
p->change_speed_quirk = true;
|
p->change_speed_quirk = true;
|
||||||
p->power_down = false;
|
p->power_down = false;
|
||||||
}
|
}
|
||||||
@ -112,7 +110,6 @@ static void dwc2_set_amlogic_params(struct dwc2_hsotg *hsotg)
|
|||||||
p->phy_type = DWC2_PHY_TYPE_PARAM_UTMI;
|
p->phy_type = DWC2_PHY_TYPE_PARAM_UTMI;
|
||||||
p->ahbcfg = GAHBCFG_HBSTLEN_INCR8 <<
|
p->ahbcfg = GAHBCFG_HBSTLEN_INCR8 <<
|
||||||
GAHBCFG_HBSTLEN_SHIFT;
|
GAHBCFG_HBSTLEN_SHIFT;
|
||||||
p->uframe_sched = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dwc2_set_amcc_params(struct dwc2_hsotg *hsotg)
|
static void dwc2_set_amcc_params(struct dwc2_hsotg *hsotg)
|
||||||
@ -134,7 +131,6 @@ static void dwc2_set_stm32f4x9_fsotg_params(struct dwc2_hsotg *hsotg)
|
|||||||
p->max_packet_count = 256;
|
p->max_packet_count = 256;
|
||||||
p->phy_type = DWC2_PHY_TYPE_PARAM_FS;
|
p->phy_type = DWC2_PHY_TYPE_PARAM_FS;
|
||||||
p->i2c_enable = false;
|
p->i2c_enable = false;
|
||||||
p->uframe_sched = false;
|
|
||||||
p->activate_stm_fs_transceiver = true;
|
p->activate_stm_fs_transceiver = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -654,8 +650,8 @@ static void dwc2_get_host_hwparams(struct dwc2_hsotg *hsotg)
|
|||||||
|
|
||||||
dwc2_force_mode(hsotg, true);
|
dwc2_force_mode(hsotg, true);
|
||||||
|
|
||||||
gnptxfsiz = dwc2_readl(hsotg->regs + GNPTXFSIZ);
|
gnptxfsiz = dwc2_readl(hsotg, GNPTXFSIZ);
|
||||||
hptxfsiz = dwc2_readl(hsotg->regs + HPTXFSIZ);
|
hptxfsiz = dwc2_readl(hsotg, HPTXFSIZ);
|
||||||
|
|
||||||
hw->host_nperio_tx_fifo_size = (gnptxfsiz & FIFOSIZE_DEPTH_MASK) >>
|
hw->host_nperio_tx_fifo_size = (gnptxfsiz & FIFOSIZE_DEPTH_MASK) >>
|
||||||
FIFOSIZE_DEPTH_SHIFT;
|
FIFOSIZE_DEPTH_SHIFT;
|
||||||
@ -679,13 +675,13 @@ static void dwc2_get_dev_hwparams(struct dwc2_hsotg *hsotg)
|
|||||||
|
|
||||||
dwc2_force_mode(hsotg, false);
|
dwc2_force_mode(hsotg, false);
|
||||||
|
|
||||||
gnptxfsiz = dwc2_readl(hsotg->regs + GNPTXFSIZ);
|
gnptxfsiz = dwc2_readl(hsotg, GNPTXFSIZ);
|
||||||
|
|
||||||
fifo_count = dwc2_hsotg_tx_fifo_count(hsotg);
|
fifo_count = dwc2_hsotg_tx_fifo_count(hsotg);
|
||||||
|
|
||||||
for (fifo = 1; fifo <= fifo_count; fifo++) {
|
for (fifo = 1; fifo <= fifo_count; fifo++) {
|
||||||
hw->g_tx_fifo_size[fifo] =
|
hw->g_tx_fifo_size[fifo] =
|
||||||
(dwc2_readl(hsotg->regs + DPTXFSIZN(fifo)) &
|
(dwc2_readl(hsotg, DPTXFSIZN(fifo)) &
|
||||||
FIFOSIZE_DEPTH_MASK) >> FIFOSIZE_DEPTH_SHIFT;
|
FIFOSIZE_DEPTH_MASK) >> FIFOSIZE_DEPTH_SHIFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -713,7 +709,7 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
|
|||||||
* 0x45f4xxxx, 0x5531xxxx or 0x5532xxxx
|
* 0x45f4xxxx, 0x5531xxxx or 0x5532xxxx
|
||||||
*/
|
*/
|
||||||
|
|
||||||
hw->snpsid = dwc2_readl(hsotg->regs + GSNPSID);
|
hw->snpsid = dwc2_readl(hsotg, GSNPSID);
|
||||||
if ((hw->snpsid & GSNPSID_ID_MASK) != DWC2_OTG_ID &&
|
if ((hw->snpsid & GSNPSID_ID_MASK) != DWC2_OTG_ID &&
|
||||||
(hw->snpsid & GSNPSID_ID_MASK) != DWC2_FS_IOT_ID &&
|
(hw->snpsid & GSNPSID_ID_MASK) != DWC2_FS_IOT_ID &&
|
||||||
(hw->snpsid & GSNPSID_ID_MASK) != DWC2_HS_IOT_ID) {
|
(hw->snpsid & GSNPSID_ID_MASK) != DWC2_HS_IOT_ID) {
|
||||||
@ -726,11 +722,11 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
|
|||||||
hw->snpsid >> 12 & 0xf, hw->snpsid >> 8 & 0xf,
|
hw->snpsid >> 12 & 0xf, hw->snpsid >> 8 & 0xf,
|
||||||
hw->snpsid >> 4 & 0xf, hw->snpsid & 0xf, hw->snpsid);
|
hw->snpsid >> 4 & 0xf, hw->snpsid & 0xf, hw->snpsid);
|
||||||
|
|
||||||
hwcfg1 = dwc2_readl(hsotg->regs + GHWCFG1);
|
hwcfg1 = dwc2_readl(hsotg, GHWCFG1);
|
||||||
hwcfg2 = dwc2_readl(hsotg->regs + GHWCFG2);
|
hwcfg2 = dwc2_readl(hsotg, GHWCFG2);
|
||||||
hwcfg3 = dwc2_readl(hsotg->regs + GHWCFG3);
|
hwcfg3 = dwc2_readl(hsotg, GHWCFG3);
|
||||||
hwcfg4 = dwc2_readl(hsotg->regs + GHWCFG4);
|
hwcfg4 = dwc2_readl(hsotg, GHWCFG4);
|
||||||
grxfsiz = dwc2_readl(hsotg->regs + GRXFSIZ);
|
grxfsiz = dwc2_readl(hsotg, GRXFSIZ);
|
||||||
|
|
||||||
/* hwcfg1 */
|
/* hwcfg1 */
|
||||||
hw->dev_ep_dirs = hwcfg1;
|
hw->dev_ep_dirs = hwcfg1;
|
||||||
|
@ -352,6 +352,23 @@ static void dwc2_driver_shutdown(struct platform_device *dev)
|
|||||||
disable_irq(hsotg->irq);
|
disable_irq(hsotg->irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dwc2_check_core_endianness() - Returns true if core and AHB have
|
||||||
|
* opposite endianness.
|
||||||
|
* @hsotg: Programming view of the DWC_otg controller.
|
||||||
|
*/
|
||||||
|
static bool dwc2_check_core_endianness(struct dwc2_hsotg *hsotg)
|
||||||
|
{
|
||||||
|
u32 snpsid;
|
||||||
|
|
||||||
|
snpsid = ioread32(hsotg->regs + GSNPSID);
|
||||||
|
if ((snpsid & GSNPSID_ID_MASK) == DWC2_OTG_ID ||
|
||||||
|
(snpsid & GSNPSID_ID_MASK) == DWC2_FS_IOT_ID ||
|
||||||
|
(snpsid & GSNPSID_ID_MASK) == DWC2_HS_IOT_ID)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* dwc2_driver_probe() - Called when the DWC_otg core is bound to the DWC_otg
|
* dwc2_driver_probe() - Called when the DWC_otg core is bound to the DWC_otg
|
||||||
* driver
|
* driver
|
||||||
@ -395,6 +412,8 @@ static int dwc2_driver_probe(struct platform_device *dev)
|
|||||||
dev_dbg(&dev->dev, "mapped PA %08lx to VA %p\n",
|
dev_dbg(&dev->dev, "mapped PA %08lx to VA %p\n",
|
||||||
(unsigned long)res->start, hsotg->regs);
|
(unsigned long)res->start, hsotg->regs);
|
||||||
|
|
||||||
|
hsotg->needs_byte_swap = dwc2_check_core_endianness(hsotg);
|
||||||
|
|
||||||
retval = dwc2_lowlevel_hw_init(hsotg);
|
retval = dwc2_lowlevel_hw_init(hsotg);
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
@ -74,11 +74,16 @@ config USB_DWC3_PCI
|
|||||||
depends on USB_PCI && ACPI
|
depends on USB_PCI && ACPI
|
||||||
default USB_DWC3
|
default USB_DWC3
|
||||||
help
|
help
|
||||||
If you're using the DesignWare Core IP with a PCIe, please say
|
If you're using the DesignWare Core IP with a PCIe (but not HAPS
|
||||||
'Y' or 'M' here.
|
platform), please say 'Y' or 'M' here.
|
||||||
|
|
||||||
One such PCIe-based platform is Synopsys' PCIe HAPS model of
|
config USB_DWC3_HAPS
|
||||||
this IP.
|
tristate "Synopsys PCIe-based HAPS Platforms"
|
||||||
|
depends on USB_PCI
|
||||||
|
default USB_DWC3
|
||||||
|
help
|
||||||
|
If you're using the DesignWare Core IP with a Synopsys PCIe HAPS
|
||||||
|
platform, please say 'Y' or 'M' here.
|
||||||
|
|
||||||
config USB_DWC3_KEYSTONE
|
config USB_DWC3_KEYSTONE
|
||||||
tristate "Texas Instruments Keystone2 Platforms"
|
tristate "Texas Instruments Keystone2 Platforms"
|
||||||
|
@ -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
|
||||||
|
@ -78,6 +78,14 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc)
|
|||||||
mode = USB_DR_MODE_HOST;
|
mode = USB_DR_MODE_HOST;
|
||||||
else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
|
else if (IS_ENABLED(CONFIG_USB_DWC3_GADGET))
|
||||||
mode = USB_DR_MODE_PERIPHERAL;
|
mode = USB_DR_MODE_PERIPHERAL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* dwc_usb31 does not support OTG mode. If the controller
|
||||||
|
* supports DRD but the dr_mode is not specified or set to OTG,
|
||||||
|
* then set the mode to peripheral.
|
||||||
|
*/
|
||||||
|
if (mode == USB_DR_MODE_OTG && dwc3_is_usb31(dwc))
|
||||||
|
mode = USB_DR_MODE_PERIPHERAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode != dwc->dr_mode) {
|
if (mode != dwc->dr_mode) {
|
||||||
@ -778,6 +786,98 @@ static void dwc3_core_setup_global_control(struct dwc3 *dwc)
|
|||||||
static int dwc3_core_get_phy(struct dwc3 *dwc);
|
static int dwc3_core_get_phy(struct dwc3 *dwc);
|
||||||
static int dwc3_core_ulpi_init(struct dwc3 *dwc);
|
static int dwc3_core_ulpi_init(struct dwc3 *dwc);
|
||||||
|
|
||||||
|
/* set global incr burst type configuration registers */
|
||||||
|
static void dwc3_set_incr_burst_type(struct dwc3 *dwc)
|
||||||
|
{
|
||||||
|
struct device *dev = dwc->dev;
|
||||||
|
/* incrx_mode : for INCR burst type. */
|
||||||
|
bool incrx_mode;
|
||||||
|
/* incrx_size : for size of INCRX burst. */
|
||||||
|
u32 incrx_size;
|
||||||
|
u32 *vals;
|
||||||
|
u32 cfg;
|
||||||
|
int ntype;
|
||||||
|
int ret;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
cfg = dwc3_readl(dwc->regs, DWC3_GSBUSCFG0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle property "snps,incr-burst-type-adjustment".
|
||||||
|
* Get the number of value from this property:
|
||||||
|
* result <= 0, means this property is not supported.
|
||||||
|
* result = 1, means INCRx burst mode supported.
|
||||||
|
* result > 1, means undefined length burst mode supported.
|
||||||
|
*/
|
||||||
|
ntype = device_property_read_u32_array(dev,
|
||||||
|
"snps,incr-burst-type-adjustment", NULL, 0);
|
||||||
|
if (ntype <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
vals = kcalloc(ntype, sizeof(u32), GFP_KERNEL);
|
||||||
|
if (!vals) {
|
||||||
|
dev_err(dev, "Error to get memory\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get INCR burst type, and parse it */
|
||||||
|
ret = device_property_read_u32_array(dev,
|
||||||
|
"snps,incr-burst-type-adjustment", vals, ntype);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "Error to get property\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
incrx_size = *vals;
|
||||||
|
|
||||||
|
if (ntype > 1) {
|
||||||
|
/* INCRX (undefined length) burst mode */
|
||||||
|
incrx_mode = INCRX_UNDEF_LENGTH_BURST_MODE;
|
||||||
|
for (i = 1; i < ntype; i++) {
|
||||||
|
if (vals[i] > incrx_size)
|
||||||
|
incrx_size = vals[i];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* INCRX burst mode */
|
||||||
|
incrx_mode = INCRX_BURST_MODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enable Undefined Length INCR Burst and Enable INCRx Burst */
|
||||||
|
cfg &= ~DWC3_GSBUSCFG0_INCRBRST_MASK;
|
||||||
|
if (incrx_mode)
|
||||||
|
cfg |= DWC3_GSBUSCFG0_INCRBRSTENA;
|
||||||
|
switch (incrx_size) {
|
||||||
|
case 256:
|
||||||
|
cfg |= DWC3_GSBUSCFG0_INCR256BRSTENA;
|
||||||
|
break;
|
||||||
|
case 128:
|
||||||
|
cfg |= DWC3_GSBUSCFG0_INCR128BRSTENA;
|
||||||
|
break;
|
||||||
|
case 64:
|
||||||
|
cfg |= DWC3_GSBUSCFG0_INCR64BRSTENA;
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
cfg |= DWC3_GSBUSCFG0_INCR32BRSTENA;
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
cfg |= DWC3_GSBUSCFG0_INCR16BRSTENA;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
cfg |= DWC3_GSBUSCFG0_INCR8BRSTENA;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
cfg |= DWC3_GSBUSCFG0_INCR4BRSTENA;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dev_err(dev, "Invalid property\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
dwc3_writel(dwc->regs, DWC3_GSBUSCFG0, cfg);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* dwc3_core_init - Low-level initialization of DWC3 Core
|
* dwc3_core_init - Low-level initialization of DWC3 Core
|
||||||
* @dwc: Pointer to our controller context structure
|
* @dwc: Pointer to our controller context structure
|
||||||
@ -840,6 +940,8 @@ static int dwc3_core_init(struct dwc3 *dwc)
|
|||||||
/* Adjust Frame Length */
|
/* Adjust Frame Length */
|
||||||
dwc3_frame_length_adjustment(dwc);
|
dwc3_frame_length_adjustment(dwc);
|
||||||
|
|
||||||
|
dwc3_set_incr_burst_type(dwc);
|
||||||
|
|
||||||
usb_phy_set_suspend(dwc->usb2_phy, 0);
|
usb_phy_set_suspend(dwc->usb2_phy, 0);
|
||||||
usb_phy_set_suspend(dwc->usb3_phy, 0);
|
usb_phy_set_suspend(dwc->usb3_phy, 0);
|
||||||
ret = phy_power_on(dwc->usb2_generic_phy);
|
ret = phy_power_on(dwc->usb2_generic_phy);
|
||||||
@ -883,6 +985,22 @@ static int dwc3_core_init(struct dwc3 *dwc)
|
|||||||
dwc3_writel(dwc->regs, DWC3_GUCTL1, reg);
|
dwc3_writel(dwc->regs, DWC3_GUCTL1, reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dwc->dr_mode == USB_DR_MODE_HOST ||
|
||||||
|
dwc->dr_mode == USB_DR_MODE_OTG) {
|
||||||
|
reg = dwc3_readl(dwc->regs, DWC3_GUCTL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enable Auto retry Feature to make the controller operating in
|
||||||
|
* Host mode on seeing transaction errors(CRC errors or internal
|
||||||
|
* overrun scenerios) on IN transfers to reply to the device
|
||||||
|
* with a non-terminating retry ACK (i.e, an ACK transcation
|
||||||
|
* packet with Retry=1 & Nump != 0)
|
||||||
|
*/
|
||||||
|
reg |= DWC3_GUCTL_HSTINAUTORETRY;
|
||||||
|
|
||||||
|
dwc3_writel(dwc->regs, DWC3_GUCTL, reg);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Must config both number of packets and max burst settings to enable
|
* Must config both number of packets and max burst settings to enable
|
||||||
* RX and/or TX threshold.
|
* RX and/or TX threshold.
|
||||||
|
@ -163,6 +163,17 @@
|
|||||||
|
|
||||||
/* Bit fields */
|
/* Bit fields */
|
||||||
|
|
||||||
|
/* Global SoC Bus Configuration INCRx Register 0 */
|
||||||
|
#define DWC3_GSBUSCFG0_INCR256BRSTENA (1 << 7) /* INCR256 burst */
|
||||||
|
#define DWC3_GSBUSCFG0_INCR128BRSTENA (1 << 6) /* INCR128 burst */
|
||||||
|
#define DWC3_GSBUSCFG0_INCR64BRSTENA (1 << 5) /* INCR64 burst */
|
||||||
|
#define DWC3_GSBUSCFG0_INCR32BRSTENA (1 << 4) /* INCR32 burst */
|
||||||
|
#define DWC3_GSBUSCFG0_INCR16BRSTENA (1 << 3) /* INCR16 burst */
|
||||||
|
#define DWC3_GSBUSCFG0_INCR8BRSTENA (1 << 2) /* INCR8 burst */
|
||||||
|
#define DWC3_GSBUSCFG0_INCR4BRSTENA (1 << 1) /* INCR4 burst */
|
||||||
|
#define DWC3_GSBUSCFG0_INCRBRSTENA (1 << 0) /* undefined length enable */
|
||||||
|
#define DWC3_GSBUSCFG0_INCRBRST_MASK 0xff
|
||||||
|
|
||||||
/* Global Debug Queue/FIFO Space Available Register */
|
/* Global Debug Queue/FIFO Space Available Register */
|
||||||
#define DWC3_GDBGFIFOSPACE_NUM(n) ((n) & 0x1f)
|
#define DWC3_GDBGFIFOSPACE_NUM(n) ((n) & 0x1f)
|
||||||
#define DWC3_GDBGFIFOSPACE_TYPE(n) (((n) << 5) & 0x1e0)
|
#define DWC3_GDBGFIFOSPACE_TYPE(n) (((n) << 5) & 0x1e0)
|
||||||
@ -227,6 +238,9 @@
|
|||||||
#define DWC3_GCTL_GBLHIBERNATIONEN BIT(1)
|
#define DWC3_GCTL_GBLHIBERNATIONEN BIT(1)
|
||||||
#define DWC3_GCTL_DSBLCLKGTNG BIT(0)
|
#define DWC3_GCTL_DSBLCLKGTNG BIT(0)
|
||||||
|
|
||||||
|
/* Global User Control Register */
|
||||||
|
#define DWC3_GUCTL_HSTINAUTORETRY BIT(14)
|
||||||
|
|
||||||
/* Global User Control 1 Register */
|
/* Global User Control 1 Register */
|
||||||
#define DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS BIT(28)
|
#define DWC3_GUCTL1_TX_IPGAP_LINECHECK_DIS BIT(28)
|
||||||
#define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW BIT(24)
|
#define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW BIT(24)
|
||||||
@ -1157,6 +1171,9 @@ struct dwc3 {
|
|||||||
u16 imod_interval;
|
u16 imod_interval;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define INCRX_BURST_MODE 0
|
||||||
|
#define INCRX_UNDEF_LENGTH_BURST_MODE 1
|
||||||
|
|
||||||
#define work_to_dwc(w) (container_of((w), struct dwc3, drd_work))
|
#define work_to_dwc(w) (container_of((w), struct dwc3, drd_work))
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
|
137
drivers/usb/dwc3/dwc3-haps.c
Normal file
137
drivers/usb/dwc3/dwc3-haps.c
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/**
|
||||||
|
* dwc3-haps.c - Synopsys HAPS PCI Specific glue layer
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018 Synopsys, Inc.
|
||||||
|
*
|
||||||
|
* Authors: Thinh Nguyen <thinhn@synopsys.com>,
|
||||||
|
* John Youn <johnyoun@synopsys.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/pci.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/property.h>
|
||||||
|
|
||||||
|
#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd
|
||||||
|
#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI 0xabce
|
||||||
|
#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31 0xabcf
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct dwc3_haps - Driver private structure
|
||||||
|
* @dwc3: child dwc3 platform_device
|
||||||
|
* @pci: our link to PCI bus
|
||||||
|
*/
|
||||||
|
struct dwc3_haps {
|
||||||
|
struct platform_device *dwc3;
|
||||||
|
struct pci_dev *pci;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct property_entry initial_properties[] = {
|
||||||
|
PROPERTY_ENTRY_BOOL("snps,usb3_lpm_capable"),
|
||||||
|
PROPERTY_ENTRY_BOOL("snps,has-lpm-erratum"),
|
||||||
|
PROPERTY_ENTRY_BOOL("snps,dis_enblslpm_quirk"),
|
||||||
|
PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
|
||||||
|
static int dwc3_haps_probe(struct pci_dev *pci,
|
||||||
|
const struct pci_device_id *id)
|
||||||
|
{
|
||||||
|
struct dwc3_haps *dwc;
|
||||||
|
struct device *dev = &pci->dev;
|
||||||
|
struct resource res[2];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = pcim_enable_device(pci);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "failed to enable pci device\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
pci_set_master(pci);
|
||||||
|
|
||||||
|
dwc = devm_kzalloc(dev, sizeof(*dwc), GFP_KERNEL);
|
||||||
|
if (!dwc)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
dwc->dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
|
||||||
|
if (!dwc->dwc3)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
|
||||||
|
|
||||||
|
res[0].start = pci_resource_start(pci, 0);
|
||||||
|
res[0].end = pci_resource_end(pci, 0);
|
||||||
|
res[0].name = "dwc_usb3";
|
||||||
|
res[0].flags = IORESOURCE_MEM;
|
||||||
|
|
||||||
|
res[1].start = pci->irq;
|
||||||
|
res[1].name = "dwc_usb3";
|
||||||
|
res[1].flags = IORESOURCE_IRQ;
|
||||||
|
|
||||||
|
ret = platform_device_add_resources(dwc->dwc3, res, ARRAY_SIZE(res));
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "couldn't add resources to dwc3 device\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
dwc->pci = pci;
|
||||||
|
dwc->dwc3->dev.parent = dev;
|
||||||
|
|
||||||
|
ret = platform_device_add_properties(dwc->dwc3, initial_properties);
|
||||||
|
if (ret)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
ret = platform_device_add(dwc->dwc3);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "failed to register dwc3 device\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
pci_set_drvdata(pci, dwc);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
err:
|
||||||
|
platform_device_put(dwc->dwc3);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dwc3_haps_remove(struct pci_dev *pci)
|
||||||
|
{
|
||||||
|
struct dwc3_haps *dwc = pci_get_drvdata(pci);
|
||||||
|
|
||||||
|
platform_device_unregister(dwc->dwc3);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct pci_device_id dwc3_haps_id_table[] = {
|
||||||
|
{
|
||||||
|
PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
|
||||||
|
PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
|
||||||
|
PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
|
||||||
|
PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31),
|
||||||
|
},
|
||||||
|
{ } /* Terminating Entry */
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(pci, dwc3_haps_id_table);
|
||||||
|
|
||||||
|
static struct pci_driver dwc3_haps_driver = {
|
||||||
|
.name = "dwc3-haps",
|
||||||
|
.id_table = dwc3_haps_id_table,
|
||||||
|
.probe = dwc3_haps_probe,
|
||||||
|
.remove = dwc3_haps_remove,
|
||||||
|
};
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Thinh Nguyen <thinhn@synopsys.com>");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
||||||
|
MODULE_DESCRIPTION("Synopsys HAPS PCI Glue Layer");
|
||||||
|
|
||||||
|
module_pci_driver(dwc3_haps_driver);
|
@ -28,6 +28,7 @@ struct dwc3_of_simple {
|
|||||||
int num_clocks;
|
int num_clocks;
|
||||||
struct reset_control *resets;
|
struct reset_control *resets;
|
||||||
bool pulse_resets;
|
bool pulse_resets;
|
||||||
|
bool need_reset;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int dwc3_of_simple_clk_init(struct dwc3_of_simple *simple, int count)
|
static int dwc3_of_simple_clk_init(struct dwc3_of_simple *simple, int count)
|
||||||
@ -93,6 +94,13 @@ static int dwc3_of_simple_probe(struct platform_device *pdev)
|
|||||||
platform_set_drvdata(pdev, simple);
|
platform_set_drvdata(pdev, simple);
|
||||||
simple->dev = dev;
|
simple->dev = dev;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some controllers need to toggle the usb3-otg reset before trying to
|
||||||
|
* initialize the PHY, otherwise the PHY times out.
|
||||||
|
*/
|
||||||
|
if (of_device_is_compatible(np, "rockchip,rk3399-dwc3"))
|
||||||
|
simple->need_reset = true;
|
||||||
|
|
||||||
if (of_device_is_compatible(np, "amlogic,meson-axg-dwc3") ||
|
if (of_device_is_compatible(np, "amlogic,meson-axg-dwc3") ||
|
||||||
of_device_is_compatible(np, "amlogic,meson-gxl-dwc3")) {
|
of_device_is_compatible(np, "amlogic,meson-gxl-dwc3")) {
|
||||||
shared_resets = true;
|
shared_resets = true;
|
||||||
@ -201,9 +209,30 @@ static int dwc3_of_simple_runtime_resume(struct device *dev)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int dwc3_of_simple_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
struct dwc3_of_simple *simple = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
if (simple->need_reset)
|
||||||
|
reset_control_assert(simple->resets);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dwc3_of_simple_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct dwc3_of_simple *simple = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
if (simple->need_reset)
|
||||||
|
reset_control_deassert(simple->resets);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static const struct dev_pm_ops dwc3_of_simple_dev_pm_ops = {
|
static const struct dev_pm_ops dwc3_of_simple_dev_pm_ops = {
|
||||||
|
SET_SYSTEM_SLEEP_PM_OPS(dwc3_of_simple_suspend, dwc3_of_simple_resume)
|
||||||
SET_RUNTIME_PM_OPS(dwc3_of_simple_runtime_suspend,
|
SET_RUNTIME_PM_OPS(dwc3_of_simple_runtime_suspend,
|
||||||
dwc3_of_simple_runtime_resume, NULL)
|
dwc3_of_simple_runtime_resume, NULL)
|
||||||
};
|
};
|
||||||
|
@ -16,12 +16,10 @@
|
|||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/gpio/consumer.h>
|
#include <linux/gpio/consumer.h>
|
||||||
|
#include <linux/gpio/machine.h>
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
|
|
||||||
#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd
|
|
||||||
#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI 0xabce
|
|
||||||
#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31 0xabcf
|
|
||||||
#define PCI_DEVICE_ID_INTEL_BYT 0x0f37
|
#define PCI_DEVICE_ID_INTEL_BYT 0x0f37
|
||||||
#define PCI_DEVICE_ID_INTEL_MRFLD 0x119e
|
#define PCI_DEVICE_ID_INTEL_MRFLD 0x119e
|
||||||
#define PCI_DEVICE_ID_INTEL_BSW 0x22b7
|
#define PCI_DEVICE_ID_INTEL_BSW 0x22b7
|
||||||
@ -41,12 +39,17 @@
|
|||||||
#define PCI_INTEL_BXT_STATE_D0 0
|
#define PCI_INTEL_BXT_STATE_D0 0
|
||||||
#define PCI_INTEL_BXT_STATE_D3 3
|
#define PCI_INTEL_BXT_STATE_D3 3
|
||||||
|
|
||||||
|
#define GP_RWBAR 1
|
||||||
|
#define GP_RWREG1 0xa0
|
||||||
|
#define GP_RWREG1_ULPI_REFCLK_DISABLE (1 << 17)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct dwc3_pci - Driver private structure
|
* struct dwc3_pci - Driver private structure
|
||||||
* @dwc3: child dwc3 platform_device
|
* @dwc3: child dwc3 platform_device
|
||||||
* @pci: our link to PCI bus
|
* @pci: our link to PCI bus
|
||||||
* @guid: _DSM GUID
|
* @guid: _DSM GUID
|
||||||
* @has_dsm_for_pm: true for devices which need to run _DSM on runtime PM
|
* @has_dsm_for_pm: true for devices which need to run _DSM on runtime PM
|
||||||
|
* @wakeup_work: work for asynchronous resume
|
||||||
*/
|
*/
|
||||||
struct dwc3_pci {
|
struct dwc3_pci {
|
||||||
struct platform_device *dwc3;
|
struct platform_device *dwc3;
|
||||||
@ -67,52 +70,74 @@ static const struct acpi_gpio_mapping acpi_dwc3_byt_gpios[] = {
|
|||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct gpiod_lookup_table platform_bytcr_gpios = {
|
||||||
|
.dev_id = "0000:00:16.0",
|
||||||
|
.table = {
|
||||||
|
GPIO_LOOKUP("INT33FC:00", 54, "reset", GPIO_ACTIVE_HIGH),
|
||||||
|
GPIO_LOOKUP("INT33FC:02", 14, "cs", GPIO_ACTIVE_HIGH),
|
||||||
|
{}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static int dwc3_byt_enable_ulpi_refclock(struct pci_dev *pci)
|
||||||
|
{
|
||||||
|
void __iomem *reg;
|
||||||
|
u32 value;
|
||||||
|
|
||||||
|
reg = pcim_iomap(pci, GP_RWBAR, 0);
|
||||||
|
if (IS_ERR(reg))
|
||||||
|
return PTR_ERR(reg);
|
||||||
|
|
||||||
|
value = readl(reg + GP_RWREG1);
|
||||||
|
if (!(value & GP_RWREG1_ULPI_REFCLK_DISABLE))
|
||||||
|
goto unmap; /* ULPI refclk already enabled */
|
||||||
|
|
||||||
|
value &= ~GP_RWREG1_ULPI_REFCLK_DISABLE;
|
||||||
|
writel(value, reg + GP_RWREG1);
|
||||||
|
/* This comes from the Intel Android x86 tree w/o any explanation */
|
||||||
|
msleep(100);
|
||||||
|
unmap:
|
||||||
|
pcim_iounmap(pci, reg);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct property_entry dwc3_pci_intel_properties[] = {
|
||||||
|
PROPERTY_ENTRY_STRING("dr_mode", "peripheral"),
|
||||||
|
PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct property_entry dwc3_pci_mrfld_properties[] = {
|
||||||
|
PROPERTY_ENTRY_STRING("dr_mode", "otg"),
|
||||||
|
PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct property_entry dwc3_pci_amd_properties[] = {
|
||||||
|
PROPERTY_ENTRY_BOOL("snps,has-lpm-erratum"),
|
||||||
|
PROPERTY_ENTRY_U8("snps,lpm-nyet-threshold", 0xf),
|
||||||
|
PROPERTY_ENTRY_BOOL("snps,u2exit_lfps_quirk"),
|
||||||
|
PROPERTY_ENTRY_BOOL("snps,u2ss_inp3_quirk"),
|
||||||
|
PROPERTY_ENTRY_BOOL("snps,req_p1p2p3_quirk"),
|
||||||
|
PROPERTY_ENTRY_BOOL("snps,del_p1p2p3_quirk"),
|
||||||
|
PROPERTY_ENTRY_BOOL("snps,del_phy_power_chg_quirk"),
|
||||||
|
PROPERTY_ENTRY_BOOL("snps,lfps_filter_quirk"),
|
||||||
|
PROPERTY_ENTRY_BOOL("snps,rx_detect_poll_quirk"),
|
||||||
|
PROPERTY_ENTRY_BOOL("snps,tx_de_emphasis_quirk"),
|
||||||
|
PROPERTY_ENTRY_U8("snps,tx_de_emphasis", 1),
|
||||||
|
/* FIXME these quirks should be removed when AMD NL tapes out */
|
||||||
|
PROPERTY_ENTRY_BOOL("snps,disable_scramble_quirk"),
|
||||||
|
PROPERTY_ENTRY_BOOL("snps,dis_u3_susphy_quirk"),
|
||||||
|
PROPERTY_ENTRY_BOOL("snps,dis_u2_susphy_quirk"),
|
||||||
|
PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
static int dwc3_pci_quirks(struct dwc3_pci *dwc)
|
static int dwc3_pci_quirks(struct dwc3_pci *dwc)
|
||||||
{
|
{
|
||||||
struct platform_device *dwc3 = dwc->dwc3;
|
|
||||||
struct pci_dev *pdev = dwc->pci;
|
struct pci_dev *pdev = dwc->pci;
|
||||||
|
|
||||||
if (pdev->vendor == PCI_VENDOR_ID_AMD &&
|
|
||||||
pdev->device == PCI_DEVICE_ID_AMD_NL_USB) {
|
|
||||||
struct property_entry properties[] = {
|
|
||||||
PROPERTY_ENTRY_BOOL("snps,has-lpm-erratum"),
|
|
||||||
PROPERTY_ENTRY_U8("snps,lpm-nyet-threshold", 0xf),
|
|
||||||
PROPERTY_ENTRY_BOOL("snps,u2exit_lfps_quirk"),
|
|
||||||
PROPERTY_ENTRY_BOOL("snps,u2ss_inp3_quirk"),
|
|
||||||
PROPERTY_ENTRY_BOOL("snps,req_p1p2p3_quirk"),
|
|
||||||
PROPERTY_ENTRY_BOOL("snps,del_p1p2p3_quirk"),
|
|
||||||
PROPERTY_ENTRY_BOOL("snps,del_phy_power_chg_quirk"),
|
|
||||||
PROPERTY_ENTRY_BOOL("snps,lfps_filter_quirk"),
|
|
||||||
PROPERTY_ENTRY_BOOL("snps,rx_detect_poll_quirk"),
|
|
||||||
PROPERTY_ENTRY_BOOL("snps,tx_de_emphasis_quirk"),
|
|
||||||
PROPERTY_ENTRY_U8("snps,tx_de_emphasis", 1),
|
|
||||||
/*
|
|
||||||
* FIXME these quirks should be removed when AMD NL
|
|
||||||
* tapes out
|
|
||||||
*/
|
|
||||||
PROPERTY_ENTRY_BOOL("snps,disable_scramble_quirk"),
|
|
||||||
PROPERTY_ENTRY_BOOL("snps,dis_u3_susphy_quirk"),
|
|
||||||
PROPERTY_ENTRY_BOOL("snps,dis_u2_susphy_quirk"),
|
|
||||||
PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
|
|
||||||
{ },
|
|
||||||
};
|
|
||||||
|
|
||||||
return platform_device_add_properties(dwc3, properties);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
|
if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
|
||||||
int ret;
|
|
||||||
|
|
||||||
struct property_entry properties[] = {
|
|
||||||
PROPERTY_ENTRY_STRING("dr_mode", "peripheral"),
|
|
||||||
PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
|
|
||||||
{ }
|
|
||||||
};
|
|
||||||
|
|
||||||
ret = platform_device_add_properties(dwc3, properties);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
if (pdev->device == PCI_DEVICE_ID_INTEL_BXT ||
|
if (pdev->device == PCI_DEVICE_ID_INTEL_BXT ||
|
||||||
pdev->device == PCI_DEVICE_ID_INTEL_BXT_M) {
|
pdev->device == PCI_DEVICE_ID_INTEL_BXT_M) {
|
||||||
guid_parse(PCI_INTEL_BXT_DSM_GUID, &dwc->guid);
|
guid_parse(PCI_INTEL_BXT_DSM_GUID, &dwc->guid);
|
||||||
@ -121,51 +146,49 @@ static int dwc3_pci_quirks(struct dwc3_pci *dwc)
|
|||||||
|
|
||||||
if (pdev->device == PCI_DEVICE_ID_INTEL_BYT) {
|
if (pdev->device == PCI_DEVICE_ID_INTEL_BYT) {
|
||||||
struct gpio_desc *gpio;
|
struct gpio_desc *gpio;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* On BYT the FW does not always enable the refclock */
|
||||||
|
ret = dwc3_byt_enable_ulpi_refclock(pdev);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
ret = devm_acpi_dev_add_driver_gpios(&pdev->dev,
|
ret = devm_acpi_dev_add_driver_gpios(&pdev->dev,
|
||||||
acpi_dwc3_byt_gpios);
|
acpi_dwc3_byt_gpios);
|
||||||
if (ret)
|
if (ret)
|
||||||
dev_dbg(&pdev->dev, "failed to add mapping table\n");
|
dev_dbg(&pdev->dev, "failed to add mapping table\n");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A lot of BYT devices lack ACPI resource entries for
|
||||||
|
* the GPIOs, add a fallback mapping to the reference
|
||||||
|
* design GPIOs which all boards seem to use.
|
||||||
|
*/
|
||||||
|
gpiod_add_lookup_table(&platform_bytcr_gpios);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These GPIOs will turn on the USB2 PHY. Note that we have to
|
* These GPIOs will turn on the USB2 PHY. Note that we have to
|
||||||
* put the gpio descriptors again here because the phy driver
|
* put the gpio descriptors again here because the phy driver
|
||||||
* might want to grab them, too.
|
* might want to grab them, too.
|
||||||
*/
|
*/
|
||||||
gpio = gpiod_get_optional(&pdev->dev, "cs", GPIOD_OUT_LOW);
|
gpio = devm_gpiod_get_optional(&pdev->dev, "cs",
|
||||||
|
GPIOD_OUT_LOW);
|
||||||
if (IS_ERR(gpio))
|
if (IS_ERR(gpio))
|
||||||
return PTR_ERR(gpio);
|
return PTR_ERR(gpio);
|
||||||
|
|
||||||
gpiod_set_value_cansleep(gpio, 1);
|
gpiod_set_value_cansleep(gpio, 1);
|
||||||
gpiod_put(gpio);
|
|
||||||
|
|
||||||
gpio = gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW);
|
gpio = devm_gpiod_get_optional(&pdev->dev, "reset",
|
||||||
|
GPIOD_OUT_LOW);
|
||||||
if (IS_ERR(gpio))
|
if (IS_ERR(gpio))
|
||||||
return PTR_ERR(gpio);
|
return PTR_ERR(gpio);
|
||||||
|
|
||||||
if (gpio) {
|
if (gpio) {
|
||||||
gpiod_set_value_cansleep(gpio, 1);
|
gpiod_set_value_cansleep(gpio, 1);
|
||||||
gpiod_put(gpio);
|
|
||||||
usleep_range(10000, 11000);
|
usleep_range(10000, 11000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pdev->vendor == PCI_VENDOR_ID_SYNOPSYS &&
|
|
||||||
(pdev->device == PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 ||
|
|
||||||
pdev->device == PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI ||
|
|
||||||
pdev->device == PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31)) {
|
|
||||||
struct property_entry properties[] = {
|
|
||||||
PROPERTY_ENTRY_BOOL("snps,usb3_lpm_capable"),
|
|
||||||
PROPERTY_ENTRY_BOOL("snps,has-lpm-erratum"),
|
|
||||||
PROPERTY_ENTRY_BOOL("snps,dis_enblslpm_quirk"),
|
|
||||||
PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
|
|
||||||
{ },
|
|
||||||
};
|
|
||||||
|
|
||||||
return platform_device_add_properties(dwc3, properties);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,9 +208,9 @@ static void dwc3_pci_resume_work(struct work_struct *work)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int dwc3_pci_probe(struct pci_dev *pci,
|
static int dwc3_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)
|
||||||
const struct pci_device_id *id)
|
|
||||||
{
|
{
|
||||||
|
struct property_entry *p = (struct property_entry *)id->driver_data;
|
||||||
struct dwc3_pci *dwc;
|
struct dwc3_pci *dwc;
|
||||||
struct resource res[2];
|
struct resource res[2];
|
||||||
int ret;
|
int ret;
|
||||||
@ -230,6 +253,10 @@ static int dwc3_pci_probe(struct pci_dev *pci,
|
|||||||
dwc->dwc3->dev.parent = dev;
|
dwc->dwc3->dev.parent = dev;
|
||||||
ACPI_COMPANION_SET(&dwc->dwc3->dev, ACPI_COMPANION(dev));
|
ACPI_COMPANION_SET(&dwc->dwc3->dev, ACPI_COMPANION(dev));
|
||||||
|
|
||||||
|
ret = platform_device_add_properties(dwc->dwc3, p);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
ret = dwc3_pci_quirks(dwc);
|
ret = dwc3_pci_quirks(dwc);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err;
|
goto err;
|
||||||
@ -257,6 +284,7 @@ static void dwc3_pci_remove(struct pci_dev *pci)
|
|||||||
{
|
{
|
||||||
struct dwc3_pci *dwc = pci_get_drvdata(pci);
|
struct dwc3_pci *dwc = pci_get_drvdata(pci);
|
||||||
|
|
||||||
|
gpiod_remove_lookup_table(&platform_bytcr_gpios);
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
cancel_work_sync(&dwc->wakeup_work);
|
cancel_work_sync(&dwc->wakeup_work);
|
||||||
#endif
|
#endif
|
||||||
@ -266,32 +294,47 @@ static void dwc3_pci_remove(struct pci_dev *pci)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct pci_device_id dwc3_pci_id_table[] = {
|
static const struct pci_device_id dwc3_pci_id_table[] = {
|
||||||
{
|
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BSW),
|
||||||
PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
|
(kernel_ulong_t) &dwc3_pci_intel_properties },
|
||||||
PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),
|
|
||||||
},
|
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BYT),
|
||||||
{
|
(kernel_ulong_t) &dwc3_pci_intel_properties, },
|
||||||
PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
|
|
||||||
PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3_AXI),
|
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MRFLD),
|
||||||
},
|
(kernel_ulong_t) &dwc3_pci_mrfld_properties, },
|
||||||
{
|
|
||||||
PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
|
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SPTLP),
|
||||||
PCI_DEVICE_ID_SYNOPSYS_HAPSUSB31),
|
(kernel_ulong_t) &dwc3_pci_intel_properties, },
|
||||||
},
|
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW), },
|
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SPTH),
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), },
|
(kernel_ulong_t) &dwc3_pci_intel_properties, },
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), },
|
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTLP), },
|
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BXT),
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTH), },
|
(kernel_ulong_t) &dwc3_pci_intel_properties, },
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT), },
|
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BXT_M), },
|
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BXT_M),
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_APL), },
|
(kernel_ulong_t) &dwc3_pci_intel_properties, },
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KBP), },
|
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GLK), },
|
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_APL),
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CNPLP), },
|
(kernel_ulong_t) &dwc3_pci_intel_properties, },
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CNPH), },
|
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICLLP), },
|
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_KBP),
|
||||||
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB), },
|
(kernel_ulong_t) &dwc3_pci_intel_properties, },
|
||||||
|
|
||||||
|
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_GLK),
|
||||||
|
(kernel_ulong_t) &dwc3_pci_intel_properties, },
|
||||||
|
|
||||||
|
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPLP),
|
||||||
|
(kernel_ulong_t) &dwc3_pci_intel_properties, },
|
||||||
|
|
||||||
|
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPH),
|
||||||
|
(kernel_ulong_t) &dwc3_pci_intel_properties, },
|
||||||
|
|
||||||
|
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICLLP),
|
||||||
|
(kernel_ulong_t) &dwc3_pci_intel_properties, },
|
||||||
|
|
||||||
|
{ PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_NL_USB),
|
||||||
|
(kernel_ulong_t) &dwc3_pci_amd_properties, },
|
||||||
{ } /* Terminating Entry */
|
{ } /* Terminating Entry */
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
|
MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
|
||||||
|
@ -1121,7 +1121,7 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
|
|||||||
req->request.short_not_ok,
|
req->request.short_not_ok,
|
||||||
req->request.no_interrupt);
|
req->request.no_interrupt);
|
||||||
} else if (req->request.zero && req->request.length &&
|
} else if (req->request.zero && req->request.length &&
|
||||||
(IS_ALIGNED(req->request.length,dep->endpoint.maxpacket))) {
|
(IS_ALIGNED(req->request.length, maxp))) {
|
||||||
struct dwc3 *dwc = dep->dwc;
|
struct dwc3 *dwc = dep->dwc;
|
||||||
struct dwc3_trb *trb;
|
struct dwc3_trb *trb;
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ struct dwc3;
|
|||||||
#define DWC3_DEPCFG_XFER_IN_PROGRESS_EN BIT(9)
|
#define DWC3_DEPCFG_XFER_IN_PROGRESS_EN BIT(9)
|
||||||
#define DWC3_DEPCFG_XFER_NOT_READY_EN BIT(10)
|
#define DWC3_DEPCFG_XFER_NOT_READY_EN BIT(10)
|
||||||
#define DWC3_DEPCFG_FIFO_ERROR_EN BIT(11)
|
#define DWC3_DEPCFG_FIFO_ERROR_EN BIT(11)
|
||||||
#define DWC3_DEPCFG_STREAM_EVENT_EN BIT(12)
|
#define DWC3_DEPCFG_STREAM_EVENT_EN BIT(13)
|
||||||
#define DWC3_DEPCFG_BINTERVAL_M1(n) (((n) & 0xff) << 16)
|
#define DWC3_DEPCFG_BINTERVAL_M1(n) (((n) & 0xff) << 16)
|
||||||
#define DWC3_DEPCFG_STREAM_CAPABLE BIT(24)
|
#define DWC3_DEPCFG_STREAM_CAPABLE BIT(24)
|
||||||
#define DWC3_DEPCFG_EP_NUMBER(n) (((n) & 0x1f) << 25)
|
#define DWC3_DEPCFG_EP_NUMBER(n) (((n) & 0x1f) << 25)
|
||||||
|
@ -1217,8 +1217,8 @@ static void purge_configs_funcs(struct gadget_info *gi)
|
|||||||
list_move_tail(&f->list, &cfg->func_list);
|
list_move_tail(&f->list, &cfg->func_list);
|
||||||
if (f->unbind) {
|
if (f->unbind) {
|
||||||
dev_dbg(&gi->cdev.gadget->dev,
|
dev_dbg(&gi->cdev.gadget->dev,
|
||||||
"unbind function '%s'/%p\n",
|
"unbind function '%s'/%p\n",
|
||||||
f->name, f);
|
f->name, f);
|
||||||
f->unbind(c, f);
|
f->unbind(c, f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -206,7 +206,6 @@
|
|||||||
#include <linux/fcntl.h>
|
#include <linux/fcntl.h>
|
||||||
#include <linux/file.h>
|
#include <linux/file.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/kref.h>
|
|
||||||
#include <linux/kthread.h>
|
#include <linux/kthread.h>
|
||||||
#include <linux/sched/signal.h>
|
#include <linux/sched/signal.h>
|
||||||
#include <linux/limits.h>
|
#include <linux/limits.h>
|
||||||
@ -312,8 +311,6 @@ struct fsg_common {
|
|||||||
void *private_data;
|
void *private_data;
|
||||||
|
|
||||||
char inquiry_string[INQUIRY_STRING_LEN];
|
char inquiry_string[INQUIRY_STRING_LEN];
|
||||||
|
|
||||||
struct kref ref;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fsg_dev {
|
struct fsg_dev {
|
||||||
@ -2551,25 +2548,11 @@ static DEVICE_ATTR(file, 0, file_show, file_store);
|
|||||||
|
|
||||||
/****************************** FSG COMMON ******************************/
|
/****************************** FSG COMMON ******************************/
|
||||||
|
|
||||||
static void fsg_common_release(struct kref *ref);
|
|
||||||
|
|
||||||
static void fsg_lun_release(struct device *dev)
|
static void fsg_lun_release(struct device *dev)
|
||||||
{
|
{
|
||||||
/* Nothing needs to be done */
|
/* Nothing needs to be done */
|
||||||
}
|
}
|
||||||
|
|
||||||
void fsg_common_get(struct fsg_common *common)
|
|
||||||
{
|
|
||||||
kref_get(&common->ref);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(fsg_common_get);
|
|
||||||
|
|
||||||
void fsg_common_put(struct fsg_common *common)
|
|
||||||
{
|
|
||||||
kref_put(&common->ref, fsg_common_release);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(fsg_common_put);
|
|
||||||
|
|
||||||
static struct fsg_common *fsg_common_setup(struct fsg_common *common)
|
static struct fsg_common *fsg_common_setup(struct fsg_common *common)
|
||||||
{
|
{
|
||||||
if (!common) {
|
if (!common) {
|
||||||
@ -2582,7 +2565,6 @@ static struct fsg_common *fsg_common_setup(struct fsg_common *common)
|
|||||||
}
|
}
|
||||||
init_rwsem(&common->filesem);
|
init_rwsem(&common->filesem);
|
||||||
spin_lock_init(&common->lock);
|
spin_lock_init(&common->lock);
|
||||||
kref_init(&common->ref);
|
|
||||||
init_completion(&common->thread_notifier);
|
init_completion(&common->thread_notifier);
|
||||||
init_waitqueue_head(&common->io_wait);
|
init_waitqueue_head(&common->io_wait);
|
||||||
init_waitqueue_head(&common->fsg_wait);
|
init_waitqueue_head(&common->fsg_wait);
|
||||||
@ -2870,9 +2852,8 @@ void fsg_common_set_inquiry_string(struct fsg_common *common, const char *vn,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(fsg_common_set_inquiry_string);
|
EXPORT_SYMBOL_GPL(fsg_common_set_inquiry_string);
|
||||||
|
|
||||||
static void fsg_common_release(struct kref *ref)
|
static void fsg_common_release(struct fsg_common *common)
|
||||||
{
|
{
|
||||||
struct fsg_common *common = container_of(ref, struct fsg_common, ref);
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* If the thread isn't already dead, tell it to exit now */
|
/* If the thread isn't already dead, tell it to exit now */
|
||||||
@ -3308,7 +3289,9 @@ static ssize_t fsg_opts_num_buffers_store(struct config_item *item,
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
fsg_common_set_num_buffers(opts->common, num);
|
ret = fsg_common_set_num_buffers(opts->common, num);
|
||||||
|
if (ret)
|
||||||
|
goto end;
|
||||||
ret = len;
|
ret = len;
|
||||||
|
|
||||||
end:
|
end:
|
||||||
@ -3344,7 +3327,7 @@ static void fsg_free_inst(struct usb_function_instance *fi)
|
|||||||
struct fsg_opts *opts;
|
struct fsg_opts *opts;
|
||||||
|
|
||||||
opts = fsg_opts_from_func_inst(fi);
|
opts = fsg_opts_from_func_inst(fi);
|
||||||
fsg_common_put(opts->common);
|
fsg_common_release(opts->common);
|
||||||
kfree(opts);
|
kfree(opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3368,7 +3351,7 @@ static struct usb_function_instance *fsg_alloc_inst(void)
|
|||||||
rc = fsg_common_set_num_buffers(opts->common,
|
rc = fsg_common_set_num_buffers(opts->common,
|
||||||
CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS);
|
CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto release_opts;
|
goto release_common;
|
||||||
|
|
||||||
pr_info(FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n");
|
pr_info(FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n");
|
||||||
|
|
||||||
@ -3391,6 +3374,8 @@ static struct usb_function_instance *fsg_alloc_inst(void)
|
|||||||
|
|
||||||
release_buffers:
|
release_buffers:
|
||||||
fsg_common_free_buffers(opts->common);
|
fsg_common_free_buffers(opts->common);
|
||||||
|
release_common:
|
||||||
|
kfree(opts->common);
|
||||||
release_opts:
|
release_opts:
|
||||||
kfree(opts);
|
kfree(opts);
|
||||||
return ERR_PTR(rc);
|
return ERR_PTR(rc);
|
||||||
|
@ -115,10 +115,6 @@ fsg_opts_from_func_inst(const struct usb_function_instance *fi)
|
|||||||
return container_of(fi, struct fsg_opts, func_inst);
|
return container_of(fi, struct fsg_opts, func_inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fsg_common_get(struct fsg_common *common);
|
|
||||||
|
|
||||||
void fsg_common_put(struct fsg_common *common);
|
|
||||||
|
|
||||||
void fsg_common_set_sysfs(struct fsg_common *common, bool sysfs);
|
void fsg_common_set_sysfs(struct fsg_common *common, bool sysfs);
|
||||||
|
|
||||||
int fsg_common_set_num_buffers(struct fsg_common *common, unsigned int n);
|
int fsg_common_set_num_buffers(struct fsg_common *common, unsigned int n);
|
||||||
|
@ -6,16 +6,17 @@
|
|||||||
* Laurent Pinchart (laurent.pinchart@ideasonboard.com)
|
* Laurent Pinchart (laurent.pinchart@ideasonboard.com)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
|
#include <linux/module.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/usb/ch9.h>
|
#include <linux/usb/ch9.h>
|
||||||
#include <linux/usb/gadget.h>
|
#include <linux/usb/gadget.h>
|
||||||
|
#include <linux/usb/g_uvc.h>
|
||||||
#include <linux/usb/video.h>
|
#include <linux/usb/video.h>
|
||||||
#include <linux/vmalloc.h>
|
#include <linux/vmalloc.h>
|
||||||
#include <linux/wait.h>
|
#include <linux/wait.h>
|
||||||
@ -30,6 +31,8 @@
|
|||||||
#include "uvc_video.h"
|
#include "uvc_video.h"
|
||||||
|
|
||||||
unsigned int uvc_gadget_trace_param;
|
unsigned int uvc_gadget_trace_param;
|
||||||
|
module_param_named(trace, uvc_gadget_trace_param, uint, 0644);
|
||||||
|
MODULE_PARM_DESC(trace, "Trace level bitmask");
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------
|
||||||
* Function descriptors
|
* Function descriptors
|
||||||
@ -410,10 +413,21 @@ uvc_function_disconnect(struct uvc_device *uvc)
|
|||||||
* USB probe and disconnect
|
* USB probe and disconnect
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static ssize_t function_name_show(struct device *dev,
|
||||||
|
struct device_attribute *attr, char *buf)
|
||||||
|
{
|
||||||
|
struct uvc_device *uvc = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
return sprintf(buf, "%s\n", uvc->func.fi->group.cg_item.ci_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEVICE_ATTR_RO(function_name);
|
||||||
|
|
||||||
static int
|
static int
|
||||||
uvc_register_video(struct uvc_device *uvc)
|
uvc_register_video(struct uvc_device *uvc)
|
||||||
{
|
{
|
||||||
struct usb_composite_dev *cdev = uvc->func.config->cdev;
|
struct usb_composite_dev *cdev = uvc->func.config->cdev;
|
||||||
|
int ret;
|
||||||
|
|
||||||
/* TODO reference counting. */
|
/* TODO reference counting. */
|
||||||
uvc->vdev.v4l2_dev = &uvc->v4l2_dev;
|
uvc->vdev.v4l2_dev = &uvc->v4l2_dev;
|
||||||
@ -426,7 +440,17 @@ uvc_register_video(struct uvc_device *uvc)
|
|||||||
|
|
||||||
video_set_drvdata(&uvc->vdev, uvc);
|
video_set_drvdata(&uvc->vdev, uvc);
|
||||||
|
|
||||||
return video_register_device(&uvc->vdev, VFL_TYPE_GRABBER, -1);
|
ret = video_register_device(&uvc->vdev, VFL_TYPE_GRABBER, -1);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = device_create_file(&uvc->vdev.dev, &dev_attr_function_name);
|
||||||
|
if (ret < 0) {
|
||||||
|
video_unregister_device(&uvc->vdev);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define UVC_COPY_DESCRIPTOR(mem, dst, desc) \
|
#define UVC_COPY_DESCRIPTOR(mem, dst, desc) \
|
||||||
@ -864,6 +888,7 @@ static void uvc_unbind(struct usb_configuration *c, struct usb_function *f)
|
|||||||
|
|
||||||
INFO(cdev, "%s\n", __func__);
|
INFO(cdev, "%s\n", __func__);
|
||||||
|
|
||||||
|
device_remove_file(&uvc->vdev.dev, &dev_attr_function_name);
|
||||||
video_unregister_device(&uvc->vdev);
|
video_unregister_device(&uvc->vdev);
|
||||||
v4l2_device_unregister(&uvc->v4l2_dev);
|
v4l2_device_unregister(&uvc->v4l2_dev);
|
||||||
|
|
||||||
|
@ -9,10 +9,7 @@
|
|||||||
#ifndef _F_UVC_H_
|
#ifndef _F_UVC_H_
|
||||||
#define _F_UVC_H_
|
#define _F_UVC_H_
|
||||||
|
|
||||||
#include <linux/usb/composite.h>
|
struct uvc_device;
|
||||||
#include <linux/usb/video.h>
|
|
||||||
|
|
||||||
#include "uvc.h"
|
|
||||||
|
|
||||||
void uvc_function_setup_continue(struct uvc_device *uvc);
|
void uvc_function_setup_continue(struct uvc_device *uvc);
|
||||||
|
|
||||||
@ -21,4 +18,3 @@ void uvc_function_connect(struct uvc_device *uvc);
|
|||||||
void uvc_function_disconnect(struct uvc_device *uvc);
|
void uvc_function_disconnect(struct uvc_device *uvc);
|
||||||
|
|
||||||
#endif /* _F_UVC_H_ */
|
#endif /* _F_UVC_H_ */
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#ifndef U_UVC_H
|
#ifndef U_UVC_H
|
||||||
#define U_UVC_H
|
#define U_UVC_H
|
||||||
|
|
||||||
|
#include <linux/mutex.h>
|
||||||
#include <linux/usb/composite.h>
|
#include <linux/usb/composite.h>
|
||||||
#include <linux/usb/video.h>
|
#include <linux/usb/video.h>
|
||||||
|
|
||||||
@ -20,7 +21,6 @@
|
|||||||
|
|
||||||
struct f_uvc_opts {
|
struct f_uvc_opts {
|
||||||
struct usb_function_instance func_inst;
|
struct usb_function_instance func_inst;
|
||||||
unsigned int uvc_gadget_trace_param;
|
|
||||||
unsigned int streaming_interval;
|
unsigned int streaming_interval;
|
||||||
unsigned int streaming_maxpacket;
|
unsigned int streaming_maxpacket;
|
||||||
unsigned int streaming_maxburst;
|
unsigned int streaming_maxburst;
|
||||||
@ -80,7 +80,4 @@ struct f_uvc_opts {
|
|||||||
int refcnt;
|
int refcnt;
|
||||||
};
|
};
|
||||||
|
|
||||||
void uvc_set_trace_param(unsigned int trace);
|
|
||||||
|
|
||||||
#endif /* U_UVC_H */
|
#endif /* U_UVC_H */
|
||||||
|
|
||||||
|
@ -9,52 +9,26 @@
|
|||||||
#ifndef _UVC_GADGET_H_
|
#ifndef _UVC_GADGET_H_
|
||||||
#define _UVC_GADGET_H_
|
#define _UVC_GADGET_H_
|
||||||
|
|
||||||
#include <linux/ioctl.h>
|
#include <linux/list.h>
|
||||||
#include <linux/types.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/usb/ch9.h>
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/usb/composite.h>
|
||||||
|
#include <linux/videodev2.h>
|
||||||
|
|
||||||
#define UVC_EVENT_FIRST (V4L2_EVENT_PRIVATE_START + 0)
|
#include <media/v4l2-device.h>
|
||||||
#define UVC_EVENT_CONNECT (V4L2_EVENT_PRIVATE_START + 0)
|
#include <media/v4l2-dev.h>
|
||||||
#define UVC_EVENT_DISCONNECT (V4L2_EVENT_PRIVATE_START + 1)
|
#include <media/v4l2-fh.h>
|
||||||
#define UVC_EVENT_STREAMON (V4L2_EVENT_PRIVATE_START + 2)
|
|
||||||
#define UVC_EVENT_STREAMOFF (V4L2_EVENT_PRIVATE_START + 3)
|
|
||||||
#define UVC_EVENT_SETUP (V4L2_EVENT_PRIVATE_START + 4)
|
|
||||||
#define UVC_EVENT_DATA (V4L2_EVENT_PRIVATE_START + 5)
|
|
||||||
#define UVC_EVENT_LAST (V4L2_EVENT_PRIVATE_START + 5)
|
|
||||||
|
|
||||||
struct uvc_request_data {
|
#include "uvc_queue.h"
|
||||||
__s32 length;
|
|
||||||
__u8 data[60];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct uvc_event {
|
struct usb_ep;
|
||||||
union {
|
struct usb_request;
|
||||||
enum usb_device_speed speed;
|
struct uvc_descriptor_header;
|
||||||
struct usb_ctrlrequest req;
|
|
||||||
struct uvc_request_data data;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
#define UVCIOC_SEND_RESPONSE _IOW('U', 1, struct uvc_request_data)
|
|
||||||
|
|
||||||
#define UVC_INTF_CONTROL 0
|
|
||||||
#define UVC_INTF_STREAMING 1
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------
|
/* ------------------------------------------------------------------------
|
||||||
* Debugging, printing and logging
|
* Debugging, printing and logging
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef __KERNEL__
|
|
||||||
|
|
||||||
#include <linux/usb.h> /* For usb_endpoint_* */
|
|
||||||
#include <linux/usb/composite.h>
|
|
||||||
#include <linux/usb/gadget.h>
|
|
||||||
#include <linux/videodev2.h>
|
|
||||||
#include <media/v4l2-fh.h>
|
|
||||||
#include <media/v4l2-device.h>
|
|
||||||
|
|
||||||
#include "uvc_queue.h"
|
|
||||||
|
|
||||||
#define UVC_TRACE_PROBE (1 << 0)
|
#define UVC_TRACE_PROBE (1 << 0)
|
||||||
#define UVC_TRACE_DESCR (1 << 1)
|
#define UVC_TRACE_DESCR (1 << 1)
|
||||||
#define UVC_TRACE_CONTROL (1 << 2)
|
#define UVC_TRACE_CONTROL (1 << 2)
|
||||||
@ -184,7 +158,4 @@ extern void uvc_endpoint_stream(struct uvc_device *dev);
|
|||||||
extern void uvc_function_connect(struct uvc_device *uvc);
|
extern void uvc_function_connect(struct uvc_device *uvc);
|
||||||
extern void uvc_function_disconnect(struct uvc_device *uvc);
|
extern void uvc_function_disconnect(struct uvc_device *uvc);
|
||||||
|
|
||||||
#endif /* __KERNEL__ */
|
|
||||||
|
|
||||||
#endif /* _UVC_GADGET_H_ */
|
#endif /* _UVC_GADGET_H_ */
|
||||||
|
|
||||||
|
@ -31,7 +31,11 @@ static struct configfs_attribute prefix##attr_##cname = { \
|
|||||||
.show = prefix##cname##_show, \
|
.show = prefix##cname##_show, \
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct f_uvc_opts *to_f_uvc_opts(struct config_item *item);
|
static inline struct f_uvc_opts *to_f_uvc_opts(struct config_item *item)
|
||||||
|
{
|
||||||
|
return container_of(to_config_group(item), struct f_uvc_opts,
|
||||||
|
func_inst.group);
|
||||||
|
}
|
||||||
|
|
||||||
/* control/header/<NAME> */
|
/* control/header/<NAME> */
|
||||||
DECLARE_UVC_HEADER_DESCRIPTOR(1);
|
DECLARE_UVC_HEADER_DESCRIPTOR(1);
|
||||||
@ -2105,12 +2109,6 @@ static const struct config_item_type uvcg_streaming_grp_type = {
|
|||||||
.ct_owner = THIS_MODULE,
|
.ct_owner = THIS_MODULE,
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline struct f_uvc_opts *to_f_uvc_opts(struct config_item *item)
|
|
||||||
{
|
|
||||||
return container_of(to_config_group(item), struct f_uvc_opts,
|
|
||||||
func_inst.group);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void uvc_attr_release(struct config_item *item)
|
static void uvc_attr_release(struct config_item *item)
|
||||||
{
|
{
|
||||||
struct f_uvc_opts *opts = to_f_uvc_opts(item);
|
struct f_uvc_opts *opts = to_f_uvc_opts(item);
|
||||||
|
@ -2,13 +2,15 @@
|
|||||||
#ifndef _UVC_QUEUE_H_
|
#ifndef _UVC_QUEUE_H_
|
||||||
#define _UVC_QUEUE_H_
|
#define _UVC_QUEUE_H_
|
||||||
|
|
||||||
#ifdef __KERNEL__
|
#include <linux/list.h>
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/poll.h>
|
#include <linux/poll.h>
|
||||||
#include <linux/videodev2.h>
|
#include <linux/spinlock.h>
|
||||||
|
|
||||||
#include <media/videobuf2-v4l2.h>
|
#include <media/videobuf2-v4l2.h>
|
||||||
|
|
||||||
|
struct file;
|
||||||
|
struct mutex;
|
||||||
|
|
||||||
/* Maximum frame size in bytes, for sanity checking. */
|
/* Maximum frame size in bytes, for sanity checking. */
|
||||||
#define UVC_MAX_FRAME_SIZE (16*1024*1024)
|
#define UVC_MAX_FRAME_SIZE (16*1024*1024)
|
||||||
/* Maximum number of video buffers. */
|
/* Maximum number of video buffers. */
|
||||||
@ -91,7 +93,5 @@ struct uvc_buffer *uvcg_queue_next_buffer(struct uvc_video_queue *queue,
|
|||||||
|
|
||||||
struct uvc_buffer *uvcg_queue_head(struct uvc_video_queue *queue);
|
struct uvc_buffer *uvcg_queue_head(struct uvc_video_queue *queue);
|
||||||
|
|
||||||
#endif /* __KERNEL__ */
|
|
||||||
|
|
||||||
#endif /* _UVC_QUEUE_H_ */
|
#endif /* _UVC_QUEUE_H_ */
|
||||||
|
|
||||||
|
@ -6,10 +6,11 @@
|
|||||||
* Laurent Pinchart (laurent.pinchart@ideasonboard.com)
|
* Laurent Pinchart (laurent.pinchart@ideasonboard.com)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
|
#include <linux/usb/g_uvc.h>
|
||||||
#include <linux/videodev2.h>
|
#include <linux/videodev2.h>
|
||||||
#include <linux/vmalloc.h>
|
#include <linux/vmalloc.h>
|
||||||
#include <linux/wait.h>
|
#include <linux/wait.h>
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
#ifndef __UVC_VIDEO_H__
|
#ifndef __UVC_VIDEO_H__
|
||||||
#define __UVC_VIDEO_H__
|
#define __UVC_VIDEO_H__
|
||||||
|
|
||||||
|
struct uvc_video;
|
||||||
|
|
||||||
int uvcg_video_pump(struct uvc_video *video);
|
int uvcg_video_pump(struct uvc_video *video);
|
||||||
|
|
||||||
int uvcg_video_enable(struct uvc_video *video, int enable);
|
int uvcg_video_enable(struct uvc_video *video, int enable);
|
||||||
|
@ -41,7 +41,7 @@ static struct usb_device_descriptor usbg_device_desc = {
|
|||||||
#define USB_G_STR_CONFIG USB_GADGET_FIRST_AVAIL_IDX
|
#define USB_G_STR_CONFIG USB_GADGET_FIRST_AVAIL_IDX
|
||||||
|
|
||||||
static struct usb_string usbg_us_strings[] = {
|
static struct usb_string usbg_us_strings[] = {
|
||||||
[USB_GADGET_MANUFACTURER_IDX].s = "Target Manufactor",
|
[USB_GADGET_MANUFACTURER_IDX].s = "Target Manufacturer",
|
||||||
[USB_GADGET_PRODUCT_IDX].s = "Target Product",
|
[USB_GADGET_PRODUCT_IDX].s = "Target Product",
|
||||||
[USB_GADGET_SERIAL_IDX].s = "000000000001",
|
[USB_GADGET_SERIAL_IDX].s = "000000000001",
|
||||||
[USB_G_STR_CONFIG].s = "default config",
|
[USB_G_STR_CONFIG].s = "default config",
|
||||||
|
@ -30,9 +30,6 @@ static unsigned int streaming_maxburst;
|
|||||||
module_param(streaming_maxburst, uint, S_IRUGO|S_IWUSR);
|
module_param(streaming_maxburst, uint, S_IRUGO|S_IWUSR);
|
||||||
MODULE_PARM_DESC(streaming_maxburst, "0 - 15 (ss only)");
|
MODULE_PARM_DESC(streaming_maxburst, "0 - 15 (ss only)");
|
||||||
|
|
||||||
static unsigned int trace;
|
|
||||||
module_param(trace, uint, S_IRUGO|S_IWUSR);
|
|
||||||
MODULE_PARM_DESC(trace, "Trace level bitmask");
|
|
||||||
/* --------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------
|
||||||
* Device descriptor
|
* Device descriptor
|
||||||
*/
|
*/
|
||||||
@ -379,7 +376,6 @@ webcam_bind(struct usb_composite_dev *cdev)
|
|||||||
uvc_opts->streaming_interval = streaming_interval;
|
uvc_opts->streaming_interval = streaming_interval;
|
||||||
uvc_opts->streaming_maxpacket = streaming_maxpacket;
|
uvc_opts->streaming_maxpacket = streaming_maxpacket;
|
||||||
uvc_opts->streaming_maxburst = streaming_maxburst;
|
uvc_opts->streaming_maxburst = streaming_maxburst;
|
||||||
uvc_set_trace_param(trace);
|
|
||||||
|
|
||||||
uvc_opts->fs_control = uvc_fs_control_cls;
|
uvc_opts->fs_control = uvc_fs_control_cls;
|
||||||
uvc_opts->ss_control = uvc_ss_control_cls;
|
uvc_opts->ss_control = uvc_ss_control_cls;
|
||||||
|
@ -193,6 +193,7 @@ config USB_RENESAS_USB3
|
|||||||
tristate 'Renesas USB3.0 Peripheral controller'
|
tristate 'Renesas USB3.0 Peripheral controller'
|
||||||
depends on ARCH_RENESAS || COMPILE_TEST
|
depends on ARCH_RENESAS || COMPILE_TEST
|
||||||
depends on EXTCON
|
depends on EXTCON
|
||||||
|
select USB_ROLE_SWITCH
|
||||||
help
|
help
|
||||||
Renesas USB3.0 Peripheral controller is a USB peripheral controller
|
Renesas USB3.0 Peripheral controller is a USB peripheral controller
|
||||||
that supports super, high, and full speed USB 3.0 data transfers.
|
that supports super, high, and full speed USB 3.0 data transfers.
|
||||||
|
@ -87,6 +87,8 @@ EXPORT_SYMBOL_GPL(usb_ep_set_maxpacket_limit);
|
|||||||
* configurable, with more generic names like "ep-a". (remember that for
|
* configurable, with more generic names like "ep-a". (remember that for
|
||||||
* USB, "in" means "towards the USB master".)
|
* USB, "in" means "towards the USB master".)
|
||||||
*
|
*
|
||||||
|
* This routine must be called in process context.
|
||||||
|
*
|
||||||
* returns zero, or a negative error code.
|
* returns zero, or a negative error code.
|
||||||
*/
|
*/
|
||||||
int usb_ep_enable(struct usb_ep *ep)
|
int usb_ep_enable(struct usb_ep *ep)
|
||||||
@ -119,6 +121,8 @@ EXPORT_SYMBOL_GPL(usb_ep_enable);
|
|||||||
* gadget drivers must call usb_ep_enable() again before queueing
|
* gadget drivers must call usb_ep_enable() again before queueing
|
||||||
* requests to the endpoint.
|
* requests to the endpoint.
|
||||||
*
|
*
|
||||||
|
* This routine must be called in process context.
|
||||||
|
*
|
||||||
* returns zero, or a negative error code.
|
* returns zero, or a negative error code.
|
||||||
*/
|
*/
|
||||||
int usb_ep_disable(struct usb_ep *ep)
|
int usb_ep_disable(struct usb_ep *ep)
|
||||||
@ -241,6 +245,8 @@ EXPORT_SYMBOL_GPL(usb_ep_free_request);
|
|||||||
* Note that @req's ->complete() callback must never be called from
|
* Note that @req's ->complete() callback must never be called from
|
||||||
* within usb_ep_queue() as that can create deadlock situations.
|
* within usb_ep_queue() as that can create deadlock situations.
|
||||||
*
|
*
|
||||||
|
* This routine may be called in interrupt context.
|
||||||
|
*
|
||||||
* Returns zero, or a negative error code. Endpoints that are not enabled
|
* Returns zero, or a negative error code. Endpoints that are not enabled
|
||||||
* report errors; errors will also be
|
* report errors; errors will also be
|
||||||
* reported when the usb peripheral is disconnected.
|
* reported when the usb peripheral is disconnected.
|
||||||
@ -284,6 +290,8 @@ EXPORT_SYMBOL_GPL(usb_ep_queue);
|
|||||||
* at the head of the queue) except as part of disconnecting from usb. Such
|
* at the head of the queue) except as part of disconnecting from usb. Such
|
||||||
* restrictions prevent drivers from supporting configuration changes,
|
* restrictions prevent drivers from supporting configuration changes,
|
||||||
* even to configuration zero (a "chapter 9" requirement).
|
* even to configuration zero (a "chapter 9" requirement).
|
||||||
|
*
|
||||||
|
* This routine may be called in interrupt context.
|
||||||
*/
|
*/
|
||||||
int usb_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
|
int usb_ep_dequeue(struct usb_ep *ep, struct usb_request *req)
|
||||||
{
|
{
|
||||||
@ -311,6 +319,8 @@ EXPORT_SYMBOL_GPL(usb_ep_dequeue);
|
|||||||
* current altsetting, see usb_ep_clear_halt(). When switching altsettings,
|
* current altsetting, see usb_ep_clear_halt(). When switching altsettings,
|
||||||
* it's simplest to use usb_ep_enable() or usb_ep_disable() for the endpoints.
|
* it's simplest to use usb_ep_enable() or usb_ep_disable() for the endpoints.
|
||||||
*
|
*
|
||||||
|
* This routine may be called in interrupt context.
|
||||||
|
*
|
||||||
* Returns zero, or a negative error code. On success, this call sets
|
* Returns zero, or a negative error code. On success, this call sets
|
||||||
* underlying hardware state that blocks data transfers.
|
* underlying hardware state that blocks data transfers.
|
||||||
* Attempts to halt IN endpoints will fail (returning -EAGAIN) if any
|
* Attempts to halt IN endpoints will fail (returning -EAGAIN) if any
|
||||||
@ -336,6 +346,8 @@ EXPORT_SYMBOL_GPL(usb_ep_set_halt);
|
|||||||
* for endpoints that aren't reconfigured, after clearing any other state
|
* for endpoints that aren't reconfigured, after clearing any other state
|
||||||
* in the endpoint's i/o queue.
|
* in the endpoint's i/o queue.
|
||||||
*
|
*
|
||||||
|
* This routine may be called in interrupt context.
|
||||||
|
*
|
||||||
* Returns zero, or a negative error code. On success, this call clears
|
* Returns zero, or a negative error code. On success, this call clears
|
||||||
* the underlying hardware state reflecting endpoint halt and data toggle.
|
* the underlying hardware state reflecting endpoint halt and data toggle.
|
||||||
* Note that some hardware can't support this request (like pxa2xx_udc),
|
* Note that some hardware can't support this request (like pxa2xx_udc),
|
||||||
@ -360,6 +372,8 @@ EXPORT_SYMBOL_GPL(usb_ep_clear_halt);
|
|||||||
* requests. If the gadget driver clears the halt status, it will
|
* requests. If the gadget driver clears the halt status, it will
|
||||||
* automatically unwedge the endpoint.
|
* automatically unwedge the endpoint.
|
||||||
*
|
*
|
||||||
|
* This routine may be called in interrupt context.
|
||||||
|
*
|
||||||
* Returns zero on success, else negative errno.
|
* Returns zero on success, else negative errno.
|
||||||
*/
|
*/
|
||||||
int usb_ep_set_wedge(struct usb_ep *ep)
|
int usb_ep_set_wedge(struct usb_ep *ep)
|
||||||
@ -388,6 +402,8 @@ EXPORT_SYMBOL_GPL(usb_ep_set_wedge);
|
|||||||
* written OUT to it by the host. Drivers that need precise handling for
|
* written OUT to it by the host. Drivers that need precise handling for
|
||||||
* fault reporting or recovery may need to use this call.
|
* fault reporting or recovery may need to use this call.
|
||||||
*
|
*
|
||||||
|
* This routine may be called in interrupt context.
|
||||||
|
*
|
||||||
* This returns the number of such bytes in the fifo, or a negative
|
* This returns the number of such bytes in the fifo, or a negative
|
||||||
* errno if the endpoint doesn't use a FIFO or doesn't support such
|
* errno if the endpoint doesn't use a FIFO or doesn't support such
|
||||||
* precise handling.
|
* precise handling.
|
||||||
@ -415,6 +431,8 @@ EXPORT_SYMBOL_GPL(usb_ep_fifo_status);
|
|||||||
* an endpoint fifo after abnormal transaction terminations. The call
|
* an endpoint fifo after abnormal transaction terminations. The call
|
||||||
* must never be used except when endpoint is not being used for any
|
* must never be used except when endpoint is not being used for any
|
||||||
* protocol translation.
|
* protocol translation.
|
||||||
|
*
|
||||||
|
* This routine may be called in interrupt context.
|
||||||
*/
|
*/
|
||||||
void usb_ep_fifo_flush(struct usb_ep *ep)
|
void usb_ep_fifo_flush(struct usb_ep *ep)
|
||||||
{
|
{
|
||||||
|
@ -23,6 +23,8 @@
|
|||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
#include <linux/usb/ch9.h>
|
#include <linux/usb/ch9.h>
|
||||||
#include <linux/usb/gadget.h>
|
#include <linux/usb/gadget.h>
|
||||||
|
#include <linux/usb/of.h>
|
||||||
|
#include <linux/usb/role.h>
|
||||||
|
|
||||||
/* register definitions */
|
/* register definitions */
|
||||||
#define USB3_AXI_INT_STA 0x008
|
#define USB3_AXI_INT_STA 0x008
|
||||||
@ -335,6 +337,11 @@ struct renesas_usb3 {
|
|||||||
struct phy *phy;
|
struct phy *phy;
|
||||||
struct dentry *dentry;
|
struct dentry *dentry;
|
||||||
|
|
||||||
|
struct usb_role_switch *role_sw;
|
||||||
|
struct device *host_dev;
|
||||||
|
struct work_struct role_work;
|
||||||
|
enum usb_role role;
|
||||||
|
|
||||||
struct renesas_usb3_ep *usb3_ep;
|
struct renesas_usb3_ep *usb3_ep;
|
||||||
int num_usb3_eps;
|
int num_usb3_eps;
|
||||||
|
|
||||||
@ -651,6 +658,14 @@ static void usb3_check_vbus(struct renesas_usb3 *usb3)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void renesas_usb3_role_work(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct renesas_usb3 *usb3 =
|
||||||
|
container_of(work, struct renesas_usb3, role_work);
|
||||||
|
|
||||||
|
usb_role_switch_set_role(usb3->role_sw, usb3->role);
|
||||||
|
}
|
||||||
|
|
||||||
static void usb3_set_mode(struct renesas_usb3 *usb3, bool host)
|
static void usb3_set_mode(struct renesas_usb3 *usb3, bool host)
|
||||||
{
|
{
|
||||||
if (host)
|
if (host)
|
||||||
@ -659,6 +674,16 @@ static void usb3_set_mode(struct renesas_usb3 *usb3, bool host)
|
|||||||
usb3_set_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON);
|
usb3_set_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void usb3_set_mode_by_role_sw(struct renesas_usb3 *usb3, bool host)
|
||||||
|
{
|
||||||
|
if (usb3->role_sw) {
|
||||||
|
usb3->role = host ? USB_ROLE_HOST : USB_ROLE_DEVICE;
|
||||||
|
schedule_work(&usb3->role_work);
|
||||||
|
} else {
|
||||||
|
usb3_set_mode(usb3, host);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void usb3_vbus_out(struct renesas_usb3 *usb3, bool enable)
|
static void usb3_vbus_out(struct renesas_usb3 *usb3, bool enable)
|
||||||
{
|
{
|
||||||
if (enable)
|
if (enable)
|
||||||
@ -672,7 +697,7 @@ static void usb3_mode_config(struct renesas_usb3 *usb3, bool host, bool a_dev)
|
|||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&usb3->lock, flags);
|
spin_lock_irqsave(&usb3->lock, flags);
|
||||||
usb3_set_mode(usb3, host);
|
usb3_set_mode_by_role_sw(usb3, host);
|
||||||
usb3_vbus_out(usb3, a_dev);
|
usb3_vbus_out(usb3, a_dev);
|
||||||
/* for A-Peripheral or forced B-device mode */
|
/* for A-Peripheral or forced B-device mode */
|
||||||
if ((!host && a_dev) ||
|
if ((!host && a_dev) ||
|
||||||
@ -2302,6 +2327,41 @@ static const struct usb_gadget_ops renesas_usb3_gadget_ops = {
|
|||||||
.set_selfpowered = renesas_usb3_set_selfpowered,
|
.set_selfpowered = renesas_usb3_set_selfpowered,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static enum usb_role renesas_usb3_role_switch_get(struct device *dev)
|
||||||
|
{
|
||||||
|
struct renesas_usb3 *usb3 = dev_get_drvdata(dev);
|
||||||
|
enum usb_role cur_role;
|
||||||
|
|
||||||
|
pm_runtime_get_sync(dev);
|
||||||
|
cur_role = usb3_is_host(usb3) ? USB_ROLE_HOST : USB_ROLE_DEVICE;
|
||||||
|
pm_runtime_put(dev);
|
||||||
|
|
||||||
|
return cur_role;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int renesas_usb3_role_switch_set(struct device *dev,
|
||||||
|
enum usb_role role)
|
||||||
|
{
|
||||||
|
struct renesas_usb3 *usb3 = dev_get_drvdata(dev);
|
||||||
|
struct device *host = usb3->host_dev;
|
||||||
|
enum usb_role cur_role = renesas_usb3_role_switch_get(dev);
|
||||||
|
|
||||||
|
pm_runtime_get_sync(dev);
|
||||||
|
if (cur_role == USB_ROLE_HOST && role == USB_ROLE_DEVICE) {
|
||||||
|
device_release_driver(host);
|
||||||
|
usb3_set_mode(usb3, false);
|
||||||
|
} else if (cur_role == USB_ROLE_DEVICE && role == USB_ROLE_HOST) {
|
||||||
|
/* Must set the mode before device_attach of the host */
|
||||||
|
usb3_set_mode(usb3, true);
|
||||||
|
/* This device_attach() might sleep */
|
||||||
|
if (device_attach(host) < 0)
|
||||||
|
dev_err(dev, "device_attach(host) failed\n");
|
||||||
|
}
|
||||||
|
pm_runtime_put(dev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t role_store(struct device *dev, struct device_attribute *attr,
|
static ssize_t role_store(struct device *dev, struct device_attribute *attr,
|
||||||
const char *buf, size_t count)
|
const char *buf, size_t count)
|
||||||
{
|
{
|
||||||
@ -2405,6 +2465,8 @@ static int renesas_usb3_remove(struct platform_device *pdev)
|
|||||||
debugfs_remove_recursive(usb3->dentry);
|
debugfs_remove_recursive(usb3->dentry);
|
||||||
device_remove_file(&pdev->dev, &dev_attr_role);
|
device_remove_file(&pdev->dev, &dev_attr_role);
|
||||||
|
|
||||||
|
usb_role_switch_unregister(usb3->role_sw);
|
||||||
|
|
||||||
usb_del_gadget_udc(&usb3->gadget);
|
usb_del_gadget_udc(&usb3->gadget);
|
||||||
renesas_usb3_dma_free_prd(usb3, &pdev->dev);
|
renesas_usb3_dma_free_prd(usb3, &pdev->dev);
|
||||||
|
|
||||||
@ -2562,6 +2624,12 @@ static const unsigned int renesas_usb3_cable[] = {
|
|||||||
EXTCON_NONE,
|
EXTCON_NONE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct usb_role_switch_desc renesas_usb3_role_switch_desc = {
|
||||||
|
.set = renesas_usb3_role_switch_set,
|
||||||
|
.get = renesas_usb3_role_switch_get,
|
||||||
|
.allow_userspace_control = true,
|
||||||
|
};
|
||||||
|
|
||||||
static int renesas_usb3_probe(struct platform_device *pdev)
|
static int renesas_usb3_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct renesas_usb3 *usb3;
|
struct renesas_usb3 *usb3;
|
||||||
@ -2647,6 +2715,20 @@ static int renesas_usb3_probe(struct platform_device *pdev)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto err_dev_create;
|
goto err_dev_create;
|
||||||
|
|
||||||
|
INIT_WORK(&usb3->role_work, renesas_usb3_role_work);
|
||||||
|
usb3->role_sw = usb_role_switch_register(&pdev->dev,
|
||||||
|
&renesas_usb3_role_switch_desc);
|
||||||
|
if (!IS_ERR(usb3->role_sw)) {
|
||||||
|
usb3->host_dev = usb_of_get_companion_dev(&pdev->dev);
|
||||||
|
if (!usb3->host_dev) {
|
||||||
|
/* If not found, this driver will not use a role sw */
|
||||||
|
usb_role_switch_unregister(usb3->role_sw);
|
||||||
|
usb3->role_sw = NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
usb3->role_sw = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
usb3->workaround_for_vbus = priv->workaround_for_vbus;
|
usb3->workaround_for_vbus = priv->workaround_for_vbus;
|
||||||
|
|
||||||
renesas_usb3_debugfs_init(usb3, &pdev->dev);
|
renesas_usb3_debugfs_init(usb3, &pdev->dev);
|
||||||
|
@ -192,6 +192,14 @@ config USB_EHCI_MXC
|
|||||||
---help---
|
---help---
|
||||||
Variation of ARC USB block used in some Freescale chips.
|
Variation of ARC USB block used in some Freescale chips.
|
||||||
|
|
||||||
|
config USB_EHCI_HCD_NPCM7XX
|
||||||
|
tristate "Support for Nuvoton NPCM7XX on-chip EHCI USB controller"
|
||||||
|
depends on (USB_EHCI_HCD && ARCH_NPCM7XX) || COMPILE_TEST
|
||||||
|
default y if (USB_EHCI_HCD && ARCH_NPCM7XX)
|
||||||
|
help
|
||||||
|
Enables support for the on-chip EHCI controller on
|
||||||
|
Nuvoton NPCM7XX chips.
|
||||||
|
|
||||||
config USB_EHCI_HCD_OMAP
|
config USB_EHCI_HCD_OMAP
|
||||||
tristate "EHCI support for OMAP3 and later chips"
|
tristate "EHCI support for OMAP3 and later chips"
|
||||||
depends on ARCH_OMAP
|
depends on ARCH_OMAP
|
||||||
|
@ -43,6 +43,7 @@ obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
|
|||||||
obj-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o
|
obj-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o
|
||||||
obj-$(CONFIG_USB_EHCI_HCD_PLATFORM) += ehci-platform.o
|
obj-$(CONFIG_USB_EHCI_HCD_PLATFORM) += ehci-platform.o
|
||||||
obj-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o
|
obj-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o
|
||||||
|
obj-$(CONFIG_USB_EHCI_HCD_NPCM7XX) += ehci-npcm7xx.o
|
||||||
obj-$(CONFIG_USB_EHCI_HCD_OMAP) += ehci-omap.o
|
obj-$(CONFIG_USB_EHCI_HCD_OMAP) += ehci-omap.o
|
||||||
obj-$(CONFIG_USB_EHCI_HCD_ORION) += ehci-orion.o
|
obj-$(CONFIG_USB_EHCI_HCD_ORION) += ehci-orion.o
|
||||||
obj-$(CONFIG_USB_EHCI_HCD_SPEAR) += ehci-spear.o
|
obj-$(CONFIG_USB_EHCI_HCD_SPEAR) += ehci-spear.o
|
||||||
|
@ -1226,6 +1226,7 @@ static const struct hc_driver ehci_hc_driver = {
|
|||||||
.bus_resume = ehci_bus_resume,
|
.bus_resume = ehci_bus_resume,
|
||||||
.relinquish_port = ehci_relinquish_port,
|
.relinquish_port = ehci_relinquish_port,
|
||||||
.port_handed_over = ehci_port_handed_over,
|
.port_handed_over = ehci_port_handed_over,
|
||||||
|
.get_resuming_ports = ehci_get_resuming_ports,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* device support
|
* device support
|
||||||
|
@ -512,10 +512,18 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
|
|||||||
return -ESHUTDOWN;
|
return -ESHUTDOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned long ehci_get_resuming_ports(struct usb_hcd *hcd)
|
||||||
|
{
|
||||||
|
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||||
|
|
||||||
|
return ehci->resuming_ports;
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#define ehci_bus_suspend NULL
|
#define ehci_bus_suspend NULL
|
||||||
#define ehci_bus_resume NULL
|
#define ehci_bus_resume NULL
|
||||||
|
#define ehci_get_resuming_ports NULL
|
||||||
|
|
||||||
#endif /* CONFIG_PM */
|
#endif /* CONFIG_PM */
|
||||||
|
|
||||||
|
212
drivers/usb/host/ehci-npcm7xx.c
Normal file
212
drivers/usb/host/ehci-npcm7xx.c
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Nuvoton NPCM7xx driver for EHCI HCD
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018 Nuvoton Technologies,
|
||||||
|
* Avi Fishman <avi.fishman@nuvoton.com> <avifishman70@gmail.com>
|
||||||
|
* Tomer Maimon <tomer.maimon@nuvoton.com> <tmaimon77@gmail.com>
|
||||||
|
*
|
||||||
|
* Based on various ehci-spear.c driver
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <linux/dma-mapping.h>
|
||||||
|
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/pm.h>
|
||||||
|
#include <linux/usb.h>
|
||||||
|
#include <linux/usb/hcd.h>
|
||||||
|
|
||||||
|
#include "ehci.h"
|
||||||
|
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
#include <linux/mfd/syscon.h>
|
||||||
|
|
||||||
|
#define DRIVER_DESC "EHCI npcm7xx driver"
|
||||||
|
|
||||||
|
static const char hcd_name[] = "npcm7xx-ehci";
|
||||||
|
|
||||||
|
#define USB2PHYCTL_OFFSET 0x144
|
||||||
|
|
||||||
|
#define IPSRST2_OFFSET 0x24
|
||||||
|
#define IPSRST3_OFFSET 0x34
|
||||||
|
|
||||||
|
|
||||||
|
static struct hc_driver __read_mostly ehci_npcm7xx_hc_driver;
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM_SLEEP
|
||||||
|
static int ehci_npcm7xx_drv_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||||
|
bool do_wakeup = device_may_wakeup(dev);
|
||||||
|
|
||||||
|
return ehci_suspend(hcd, do_wakeup);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ehci_npcm7xx_drv_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
ehci_resume(hcd, false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_PM_SLEEP */
|
||||||
|
|
||||||
|
static SIMPLE_DEV_PM_OPS(ehci_npcm7xx_pm_ops, ehci_npcm7xx_drv_suspend,
|
||||||
|
ehci_npcm7xx_drv_resume);
|
||||||
|
|
||||||
|
static int npcm7xx_ehci_hcd_drv_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct usb_hcd *hcd;
|
||||||
|
struct resource *res;
|
||||||
|
struct regmap *gcr_regmap;
|
||||||
|
struct regmap *rst_regmap;
|
||||||
|
const struct hc_driver *driver = &ehci_npcm7xx_hc_driver;
|
||||||
|
int irq;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
dev_dbg(&pdev->dev, "initializing npcm7xx ehci USB Controller\n");
|
||||||
|
|
||||||
|
gcr_regmap = syscon_regmap_lookup_by_compatible("nuvoton,npcm750-gcr");
|
||||||
|
if (IS_ERR(gcr_regmap)) {
|
||||||
|
dev_err(&pdev->dev, "%s: failed to find nuvoton,npcm750-gcr\n",
|
||||||
|
__func__);
|
||||||
|
return PTR_ERR(gcr_regmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
rst_regmap = syscon_regmap_lookup_by_compatible("nuvoton,npcm750-rst");
|
||||||
|
if (IS_ERR(rst_regmap)) {
|
||||||
|
dev_err(&pdev->dev, "%s: failed to find nuvoton,npcm750-rst\n",
|
||||||
|
__func__);
|
||||||
|
return PTR_ERR(rst_regmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/********* phy init ******/
|
||||||
|
// reset usb host
|
||||||
|
regmap_update_bits(rst_regmap, IPSRST2_OFFSET,
|
||||||
|
(0x1 << 26), (0x1 << 26));
|
||||||
|
regmap_update_bits(rst_regmap, IPSRST3_OFFSET,
|
||||||
|
(0x1 << 25), (0x1 << 25));
|
||||||
|
regmap_update_bits(gcr_regmap, USB2PHYCTL_OFFSET,
|
||||||
|
(0x1 << 28), 0);
|
||||||
|
|
||||||
|
udelay(1);
|
||||||
|
|
||||||
|
// enable phy
|
||||||
|
regmap_update_bits(rst_regmap, IPSRST3_OFFSET,
|
||||||
|
(0x1 << 25), 0);
|
||||||
|
|
||||||
|
udelay(50); // enable phy
|
||||||
|
|
||||||
|
regmap_update_bits(gcr_regmap, USB2PHYCTL_OFFSET,
|
||||||
|
(0x1 << 28), (0x1 << 28));
|
||||||
|
|
||||||
|
// enable host
|
||||||
|
regmap_update_bits(rst_regmap, IPSRST2_OFFSET,
|
||||||
|
(0x1 << 26), 0);
|
||||||
|
|
||||||
|
if (usb_disabled())
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
irq = platform_get_irq(pdev, 0);
|
||||||
|
if (irq < 0) {
|
||||||
|
retval = irq;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Right now device-tree probed devices don't get dma_mask set.
|
||||||
|
* Since shared usb code relies on it, set it here for now.
|
||||||
|
* Once we have dma capability bindings this can go away.
|
||||||
|
*/
|
||||||
|
retval = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
|
||||||
|
if (retval)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
|
||||||
|
if (!hcd) {
|
||||||
|
retval = -ENOMEM;
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
hcd->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||||
|
if (IS_ERR(hcd->regs)) {
|
||||||
|
retval = PTR_ERR(hcd->regs);
|
||||||
|
goto err_put_hcd;
|
||||||
|
}
|
||||||
|
hcd->rsrc_start = res->start;
|
||||||
|
hcd->rsrc_len = resource_size(res);
|
||||||
|
|
||||||
|
/* registers start at offset 0x0 */
|
||||||
|
hcd_to_ehci(hcd)->caps = hcd->regs;
|
||||||
|
|
||||||
|
retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
||||||
|
if (retval)
|
||||||
|
goto err_put_hcd;
|
||||||
|
|
||||||
|
device_wakeup_enable(hcd->self.controller);
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
err_put_hcd:
|
||||||
|
usb_put_hcd(hcd);
|
||||||
|
fail:
|
||||||
|
dev_err(&pdev->dev, "init fail, %d\n", retval);
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int npcm7xx_ehci_hcd_drv_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
usb_remove_hcd(hcd);
|
||||||
|
|
||||||
|
usb_put_hcd(hcd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct of_device_id npcm7xx_ehci_id_table[] = {
|
||||||
|
{ .compatible = "nuvoton,npcm750-ehci" },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, npcm7xx_ehci_id_table);
|
||||||
|
|
||||||
|
static struct platform_driver npcm7xx_ehci_hcd_driver = {
|
||||||
|
.probe = npcm7xx_ehci_hcd_drv_probe,
|
||||||
|
.remove = npcm7xx_ehci_hcd_drv_remove,
|
||||||
|
.shutdown = usb_hcd_platform_shutdown,
|
||||||
|
.driver = {
|
||||||
|
.name = "npcm7xx-ehci",
|
||||||
|
.bus = &platform_bus_type,
|
||||||
|
.pm = &ehci_npcm7xx_pm_ops,
|
||||||
|
.of_match_table = npcm7xx_ehci_id_table,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init ehci_npcm7xx_init(void)
|
||||||
|
{
|
||||||
|
if (usb_disabled())
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
pr_info("%s: " DRIVER_DESC "\n", hcd_name);
|
||||||
|
|
||||||
|
ehci_init_driver(&ehci_npcm7xx_hc_driver, NULL);
|
||||||
|
return platform_driver_register(&npcm7xx_ehci_hcd_driver);
|
||||||
|
}
|
||||||
|
module_init(ehci_npcm7xx_init);
|
||||||
|
|
||||||
|
static void __exit ehci_npcm7xx_cleanup(void)
|
||||||
|
{
|
||||||
|
platform_driver_unregister(&npcm7xx_ehci_hcd_driver);
|
||||||
|
}
|
||||||
|
module_exit(ehci_npcm7xx_cleanup);
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||||
|
MODULE_ALIAS("platform:npcm7xx-ehci");
|
||||||
|
MODULE_AUTHOR("Avi Fishman");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
@ -1835,7 +1835,6 @@ static bool itd_complete(struct ehci_hcd *ehci, struct ehci_itd *itd)
|
|||||||
unsigned uframe;
|
unsigned uframe;
|
||||||
int urb_index = -1;
|
int urb_index = -1;
|
||||||
struct ehci_iso_stream *stream = itd->stream;
|
struct ehci_iso_stream *stream = itd->stream;
|
||||||
struct usb_device *dev;
|
|
||||||
bool retval = false;
|
bool retval = false;
|
||||||
|
|
||||||
/* for each uframe with a packet */
|
/* for each uframe with a packet */
|
||||||
@ -1886,7 +1885,6 @@ static bool itd_complete(struct ehci_hcd *ehci, struct ehci_itd *itd)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* give urb back to the driver; completion often (re)submits */
|
/* give urb back to the driver; completion often (re)submits */
|
||||||
dev = urb->dev;
|
|
||||||
ehci_urb_done(ehci, urb, 0);
|
ehci_urb_done(ehci, urb, 0);
|
||||||
retval = true;
|
retval = true;
|
||||||
urb = NULL;
|
urb = NULL;
|
||||||
@ -2230,7 +2228,6 @@ static bool sitd_complete(struct ehci_hcd *ehci, struct ehci_sitd *sitd)
|
|||||||
u32 t;
|
u32 t;
|
||||||
int urb_index;
|
int urb_index;
|
||||||
struct ehci_iso_stream *stream = sitd->stream;
|
struct ehci_iso_stream *stream = sitd->stream;
|
||||||
struct usb_device *dev;
|
|
||||||
bool retval = false;
|
bool retval = false;
|
||||||
|
|
||||||
urb_index = sitd->index;
|
urb_index = sitd->index;
|
||||||
@ -2268,7 +2265,6 @@ static bool sitd_complete(struct ehci_hcd *ehci, struct ehci_sitd *sitd)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* give urb back to the driver; completion often (re)submits */
|
/* give urb back to the driver; completion often (re)submits */
|
||||||
dev = urb->dev;
|
|
||||||
ehci_urb_done(ehci, urb, 0);
|
ehci_urb_done(ehci, urb, 0);
|
||||||
retval = true;
|
retval = true;
|
||||||
urb = NULL;
|
urb = NULL;
|
||||||
|
@ -3062,7 +3062,6 @@ static int u132_probe(struct platform_device *pdev)
|
|||||||
int retval;
|
int retval;
|
||||||
u32 control;
|
u32 control;
|
||||||
u32 rh_a = -1;
|
u32 rh_a = -1;
|
||||||
u32 num_ports;
|
|
||||||
|
|
||||||
msleep(100);
|
msleep(100);
|
||||||
if (u132_exiting > 0)
|
if (u132_exiting > 0)
|
||||||
@ -3077,7 +3076,6 @@ static int u132_probe(struct platform_device *pdev)
|
|||||||
retval = ftdi_read_pcimem(pdev, roothub.a, &rh_a);
|
retval = ftdi_read_pcimem(pdev, roothub.a, &rh_a);
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
num_ports = rh_a & RH_A_NDP; /* refuse to confuse usbcore */
|
|
||||||
if (pdev->dev.dma_mask)
|
if (pdev->dev.dma_mask)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
@ -96,9 +96,7 @@ static enum whc_update pzl_process_qset(struct whc *whc, struct whc_qset *qset)
|
|||||||
|
|
||||||
while (qset->ntds) {
|
while (qset->ntds) {
|
||||||
struct whc_qtd *td;
|
struct whc_qtd *td;
|
||||||
int t;
|
|
||||||
|
|
||||||
t = qset->td_start;
|
|
||||||
td = &qset->qtd[qset->td_start];
|
td = &qset->qtd[qset->td_start];
|
||||||
status = le32_to_cpu(td->status);
|
status = le32_to_cpu(td->status);
|
||||||
|
|
||||||
|
@ -913,11 +913,9 @@ static ssize_t dbc_store(struct device *dev,
|
|||||||
struct device_attribute *attr,
|
struct device_attribute *attr,
|
||||||
const char *buf, size_t count)
|
const char *buf, size_t count)
|
||||||
{
|
{
|
||||||
struct xhci_dbc *dbc;
|
|
||||||
struct xhci_hcd *xhci;
|
struct xhci_hcd *xhci;
|
||||||
|
|
||||||
xhci = hcd_to_xhci(dev_get_drvdata(dev));
|
xhci = hcd_to_xhci(dev_get_drvdata(dev));
|
||||||
dbc = xhci->dbc;
|
|
||||||
|
|
||||||
if (!strncmp(buf, "enable", 6))
|
if (!strncmp(buf, "enable", 6))
|
||||||
xhci_dbc_start(xhci);
|
xhci_dbc_start(xhci);
|
||||||
|
@ -1684,4 +1684,15 @@ int xhci_bus_resume(struct usb_hcd *hcd)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned long xhci_get_resuming_ports(struct usb_hcd *hcd)
|
||||||
|
{
|
||||||
|
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||||
|
struct xhci_bus_state *bus_state;
|
||||||
|
|
||||||
|
bus_state = &xhci->bus_state[hcd_index(hcd)];
|
||||||
|
|
||||||
|
/* USB3 port wakeups are reported via usb_wakeup_notification() */
|
||||||
|
return bus_state->resuming_ports; /* USB2 ports only */
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_PM */
|
#endif /* CONFIG_PM */
|
||||||
|
@ -105,6 +105,7 @@ static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen2 = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen3 = {
|
static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen3 = {
|
||||||
|
.firmware_name = XHCI_RCAR_FIRMWARE_NAME_V3,
|
||||||
.init_quirk = xhci_rcar_init_quirk,
|
.init_quirk = xhci_rcar_init_quirk,
|
||||||
.plat_start = xhci_rcar_start,
|
.plat_start = xhci_rcar_start,
|
||||||
.resume_quirk = xhci_rcar_resume_quirk,
|
.resume_quirk = xhci_rcar_resume_quirk,
|
||||||
|
@ -17,9 +17,8 @@
|
|||||||
#include "xhci-rcar.h"
|
#include "xhci-rcar.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* - The V3 firmware is for r8a7796 (with good performance) and r8a7795 es2.0
|
* - The V3 firmware is for almost all R-Car Gen3 (except r8a7795 ES1.x)
|
||||||
* or later.
|
* - The V2 firmware is for r8a7795 ES1.x.
|
||||||
* - The V2 firmware can be used on both r8a7795 (es1.x) and r8a7796.
|
|
||||||
* - The V2 firmware is possible to use on R-Car Gen2. However, the V2 causes
|
* - The V2 firmware is possible to use on R-Car Gen2. However, the V2 causes
|
||||||
* performance degradation. So, this driver continues to use the V1 if R-Car
|
* performance degradation. So, this driver continues to use the V1 if R-Car
|
||||||
* Gen2.
|
* Gen2.
|
||||||
@ -30,6 +29,7 @@ MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V2);
|
|||||||
MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V3);
|
MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V3);
|
||||||
|
|
||||||
/*** Register Offset ***/
|
/*** Register Offset ***/
|
||||||
|
#define RCAR_USB3_AXH_STA 0x104 /* AXI Host Control Status */
|
||||||
#define RCAR_USB3_INT_ENA 0x224 /* Interrupt Enable */
|
#define RCAR_USB3_INT_ENA 0x224 /* Interrupt Enable */
|
||||||
#define RCAR_USB3_DL_CTRL 0x250 /* FW Download Control & Status */
|
#define RCAR_USB3_DL_CTRL 0x250 /* FW Download Control & Status */
|
||||||
#define RCAR_USB3_FW_DATA0 0x258 /* FW Data0 */
|
#define RCAR_USB3_FW_DATA0 0x258 /* FW Data0 */
|
||||||
@ -42,6 +42,12 @@ MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V3);
|
|||||||
#define RCAR_USB3_TX_POL 0xab8 /* USB3.0 TX Polarity */
|
#define RCAR_USB3_TX_POL 0xab8 /* USB3.0 TX Polarity */
|
||||||
|
|
||||||
/*** Register Settings ***/
|
/*** Register Settings ***/
|
||||||
|
/* AXI Host Control Status */
|
||||||
|
#define RCAR_USB3_AXH_STA_B3_PLL_ACTIVE 0x00010000
|
||||||
|
#define RCAR_USB3_AXH_STA_B2_PLL_ACTIVE 0x00000001
|
||||||
|
#define RCAR_USB3_AXH_STA_PLL_ACTIVE_MASK (RCAR_USB3_AXH_STA_B3_PLL_ACTIVE | \
|
||||||
|
RCAR_USB3_AXH_STA_B2_PLL_ACTIVE)
|
||||||
|
|
||||||
/* Interrupt Enable */
|
/* Interrupt Enable */
|
||||||
#define RCAR_USB3_INT_XHC_ENA 0x00000001
|
#define RCAR_USB3_INT_XHC_ENA 0x00000001
|
||||||
#define RCAR_USB3_INT_PME_ENA 0x00000002
|
#define RCAR_USB3_INT_PME_ENA 0x00000002
|
||||||
@ -75,18 +81,6 @@ static const struct soc_device_attribute rcar_quirks_match[] = {
|
|||||||
.soc_id = "r8a7795", .revision = "ES1.*",
|
.soc_id = "r8a7795", .revision = "ES1.*",
|
||||||
.data = (void *)RCAR_XHCI_FIRMWARE_V2,
|
.data = (void *)RCAR_XHCI_FIRMWARE_V2,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
.soc_id = "r8a7795",
|
|
||||||
.data = (void *)RCAR_XHCI_FIRMWARE_V3,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.soc_id = "r8a7796",
|
|
||||||
.data = (void *)RCAR_XHCI_FIRMWARE_V3,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.soc_id = "r8a77965",
|
|
||||||
.data = (void *)RCAR_XHCI_FIRMWARE_V3,
|
|
||||||
},
|
|
||||||
{ /* sentinel */ },
|
{ /* sentinel */ },
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -213,6 +207,22 @@ static int xhci_rcar_download_firmware(struct usb_hcd *hcd)
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool xhci_rcar_wait_for_pll_active(struct usb_hcd *hcd)
|
||||||
|
{
|
||||||
|
int timeout = 1000;
|
||||||
|
u32 val, mask = RCAR_USB3_AXH_STA_PLL_ACTIVE_MASK;
|
||||||
|
|
||||||
|
while (timeout > 0) {
|
||||||
|
val = readl(hcd->regs + RCAR_USB3_AXH_STA);
|
||||||
|
if ((val & mask) == mask)
|
||||||
|
return true;
|
||||||
|
udelay(1);
|
||||||
|
timeout--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* This function needs to initialize a "phy" of usb before */
|
/* This function needs to initialize a "phy" of usb before */
|
||||||
int xhci_rcar_init_quirk(struct usb_hcd *hcd)
|
int xhci_rcar_init_quirk(struct usb_hcd *hcd)
|
||||||
{
|
{
|
||||||
@ -233,6 +243,9 @@ int xhci_rcar_init_quirk(struct usb_hcd *hcd)
|
|||||||
xhci_rcar_is_gen3(hcd->self.controller))
|
xhci_rcar_is_gen3(hcd->self.controller))
|
||||||
xhci->quirks |= XHCI_NO_64BIT_SUPPORT;
|
xhci->quirks |= XHCI_NO_64BIT_SUPPORT;
|
||||||
|
|
||||||
|
if (!xhci_rcar_wait_for_pll_active(hcd))
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
|
||||||
return xhci_rcar_download_firmware(hcd);
|
return xhci_rcar_download_firmware(hcd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5121,6 +5121,7 @@ static const struct hc_driver xhci_hc_driver = {
|
|||||||
.hub_status_data = xhci_hub_status_data,
|
.hub_status_data = xhci_hub_status_data,
|
||||||
.bus_suspend = xhci_bus_suspend,
|
.bus_suspend = xhci_bus_suspend,
|
||||||
.bus_resume = xhci_bus_resume,
|
.bus_resume = xhci_bus_resume,
|
||||||
|
.get_resuming_ports = xhci_get_resuming_ports,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call back when device connected and addressed
|
* call back when device connected and addressed
|
||||||
|
@ -2114,9 +2114,11 @@ void xhci_hc_died(struct xhci_hcd *xhci);
|
|||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
int xhci_bus_suspend(struct usb_hcd *hcd);
|
int xhci_bus_suspend(struct usb_hcd *hcd);
|
||||||
int xhci_bus_resume(struct usb_hcd *hcd);
|
int xhci_bus_resume(struct usb_hcd *hcd);
|
||||||
|
unsigned long xhci_get_resuming_ports(struct usb_hcd *hcd);
|
||||||
#else
|
#else
|
||||||
#define xhci_bus_suspend NULL
|
#define xhci_bus_suspend NULL
|
||||||
#define xhci_bus_resume NULL
|
#define xhci_bus_resume NULL
|
||||||
|
#define xhci_get_resuming_ports NULL
|
||||||
#endif /* CONFIG_PM */
|
#endif /* CONFIG_PM */
|
||||||
|
|
||||||
u32 xhci_port_state_to_neutral(u32 state);
|
u32 xhci_port_state_to_neutral(u32 state);
|
||||||
|
@ -1817,7 +1817,6 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
|
|||||||
u32 temp, status;
|
u32 temp, status;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
unsigned selector;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR.
|
* FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR.
|
||||||
@ -2010,7 +2009,6 @@ static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SetPortFeature:
|
case SetPortFeature:
|
||||||
selector = wIndex >> 8;
|
|
||||||
wIndex &= 0xff;
|
wIndex &= 0xff;
|
||||||
if (!wIndex || wIndex > ports)
|
if (!wIndex || wIndex > ports)
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -155,11 +155,12 @@ static void adu_interrupt_in_callback(struct urb *urb)
|
|||||||
{
|
{
|
||||||
struct adu_device *dev = urb->context;
|
struct adu_device *dev = urb->context;
|
||||||
int status = urb->status;
|
int status = urb->status;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
adu_debug_data(&dev->udev->dev, __func__,
|
adu_debug_data(&dev->udev->dev, __func__,
|
||||||
urb->actual_length, urb->transfer_buffer);
|
urb->actual_length, urb->transfer_buffer);
|
||||||
|
|
||||||
spin_lock(&dev->buflock);
|
spin_lock_irqsave(&dev->buflock, flags);
|
||||||
|
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
if ((status != -ENOENT) && (status != -ECONNRESET) &&
|
if ((status != -ENOENT) && (status != -ECONNRESET) &&
|
||||||
@ -190,7 +191,7 @@ static void adu_interrupt_in_callback(struct urb *urb)
|
|||||||
|
|
||||||
exit:
|
exit:
|
||||||
dev->read_urb_finished = 1;
|
dev->read_urb_finished = 1;
|
||||||
spin_unlock(&dev->buflock);
|
spin_unlock_irqrestore(&dev->buflock, flags);
|
||||||
/* always wake up so we recover from errors */
|
/* always wake up so we recover from errors */
|
||||||
wake_up_interruptible(&dev->read_wait);
|
wake_up_interruptible(&dev->read_wait);
|
||||||
}
|
}
|
||||||
@ -199,6 +200,7 @@ static void adu_interrupt_out_callback(struct urb *urb)
|
|||||||
{
|
{
|
||||||
struct adu_device *dev = urb->context;
|
struct adu_device *dev = urb->context;
|
||||||
int status = urb->status;
|
int status = urb->status;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
adu_debug_data(&dev->udev->dev, __func__,
|
adu_debug_data(&dev->udev->dev, __func__,
|
||||||
urb->actual_length, urb->transfer_buffer);
|
urb->actual_length, urb->transfer_buffer);
|
||||||
@ -213,10 +215,10 @@ static void adu_interrupt_out_callback(struct urb *urb)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock(&dev->buflock);
|
spin_lock_irqsave(&dev->buflock, flags);
|
||||||
dev->out_urb_finished = 1;
|
dev->out_urb_finished = 1;
|
||||||
wake_up(&dev->write_wait);
|
wake_up(&dev->write_wait);
|
||||||
spin_unlock(&dev->buflock);
|
spin_unlock_irqrestore(&dev->buflock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int adu_open(struct inode *inode, struct file *file)
|
static int adu_open(struct inode *inode, struct file *file)
|
||||||
|
@ -89,6 +89,7 @@ static void appledisplay_complete(struct urb *urb)
|
|||||||
dev_err(dev,
|
dev_err(dev,
|
||||||
"OVERFLOW with data length %d, actual length is %d\n",
|
"OVERFLOW with data length %d, actual length is %d\n",
|
||||||
ACD_URB_BUFFER_LEN, pdata->urb->actual_length);
|
ACD_URB_BUFFER_LEN, pdata->urb->actual_length);
|
||||||
|
/* fall through */
|
||||||
case -ECONNRESET:
|
case -ECONNRESET:
|
||||||
case -ENOENT:
|
case -ENOENT:
|
||||||
case -ESHUTDOWN:
|
case -ESHUTDOWN:
|
||||||
|
@ -81,7 +81,6 @@ struct iowarrior {
|
|||||||
atomic_t write_busy; /* number of write-urbs submitted */
|
atomic_t write_busy; /* number of write-urbs submitted */
|
||||||
atomic_t read_idx;
|
atomic_t read_idx;
|
||||||
atomic_t intr_idx;
|
atomic_t intr_idx;
|
||||||
spinlock_t intr_idx_lock; /* protects intr_idx */
|
|
||||||
atomic_t overflow_flag; /* signals an index 'rollover' */
|
atomic_t overflow_flag; /* signals an index 'rollover' */
|
||||||
int present; /* this is 1 as long as the device is connected */
|
int present; /* this is 1 as long as the device is connected */
|
||||||
int opened; /* this is 1 if the device is currently open */
|
int opened; /* this is 1 if the device is currently open */
|
||||||
@ -166,7 +165,6 @@ static void iowarrior_callback(struct urb *urb)
|
|||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock(&dev->intr_idx_lock);
|
|
||||||
intr_idx = atomic_read(&dev->intr_idx);
|
intr_idx = atomic_read(&dev->intr_idx);
|
||||||
/* aux_idx become previous intr_idx */
|
/* aux_idx become previous intr_idx */
|
||||||
aux_idx = (intr_idx == 0) ? (MAX_INTERRUPT_BUFFER - 1) : (intr_idx - 1);
|
aux_idx = (intr_idx == 0) ? (MAX_INTERRUPT_BUFFER - 1) : (intr_idx - 1);
|
||||||
@ -181,7 +179,6 @@ static void iowarrior_callback(struct urb *urb)
|
|||||||
(dev->read_queue + offset, urb->transfer_buffer,
|
(dev->read_queue + offset, urb->transfer_buffer,
|
||||||
dev->report_size)) {
|
dev->report_size)) {
|
||||||
/* equal values on interface 0 will be ignored */
|
/* equal values on interface 0 will be ignored */
|
||||||
spin_unlock(&dev->intr_idx_lock);
|
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -202,7 +199,6 @@ static void iowarrior_callback(struct urb *urb)
|
|||||||
*(dev->read_queue + offset + (dev->report_size)) = dev->serial_number++;
|
*(dev->read_queue + offset + (dev->report_size)) = dev->serial_number++;
|
||||||
|
|
||||||
atomic_set(&dev->intr_idx, aux_idx);
|
atomic_set(&dev->intr_idx, aux_idx);
|
||||||
spin_unlock(&dev->intr_idx_lock);
|
|
||||||
/* tell the blocking read about the new data */
|
/* tell the blocking read about the new data */
|
||||||
wake_up_interruptible(&dev->read_wait);
|
wake_up_interruptible(&dev->read_wait);
|
||||||
|
|
||||||
@ -762,7 +758,6 @@ static int iowarrior_probe(struct usb_interface *interface,
|
|||||||
|
|
||||||
atomic_set(&dev->intr_idx, 0);
|
atomic_set(&dev->intr_idx, 0);
|
||||||
atomic_set(&dev->read_idx, 0);
|
atomic_set(&dev->read_idx, 0);
|
||||||
spin_lock_init(&dev->intr_idx_lock);
|
|
||||||
atomic_set(&dev->overflow_flag, 0);
|
atomic_set(&dev->overflow_flag, 0);
|
||||||
init_waitqueue_head(&dev->read_wait);
|
init_waitqueue_head(&dev->read_wait);
|
||||||
atomic_set(&dev->write_busy, 0);
|
atomic_set(&dev->write_busy, 0);
|
||||||
|
@ -225,6 +225,7 @@ static void ld_usb_interrupt_in_callback(struct urb *urb)
|
|||||||
size_t *actual_buffer;
|
size_t *actual_buffer;
|
||||||
unsigned int next_ring_head;
|
unsigned int next_ring_head;
|
||||||
int status = urb->status;
|
int status = urb->status;
|
||||||
|
unsigned long flags;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
if (status) {
|
if (status) {
|
||||||
@ -236,12 +237,12 @@ static void ld_usb_interrupt_in_callback(struct urb *urb)
|
|||||||
dev_dbg(&dev->intf->dev,
|
dev_dbg(&dev->intf->dev,
|
||||||
"%s: nonzero status received: %d\n", __func__,
|
"%s: nonzero status received: %d\n", __func__,
|
||||||
status);
|
status);
|
||||||
spin_lock(&dev->rbsl);
|
spin_lock_irqsave(&dev->rbsl, flags);
|
||||||
goto resubmit; /* maybe we can recover */
|
goto resubmit; /* maybe we can recover */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock(&dev->rbsl);
|
spin_lock_irqsave(&dev->rbsl, flags);
|
||||||
if (urb->actual_length > 0) {
|
if (urb->actual_length > 0) {
|
||||||
next_ring_head = (dev->ring_head+1) % ring_buffer_size;
|
next_ring_head = (dev->ring_head+1) % ring_buffer_size;
|
||||||
if (next_ring_head != dev->ring_tail) {
|
if (next_ring_head != dev->ring_tail) {
|
||||||
@ -270,7 +271,7 @@ resubmit:
|
|||||||
dev->buffer_overflow = 1;
|
dev->buffer_overflow = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spin_unlock(&dev->rbsl);
|
spin_unlock_irqrestore(&dev->rbsl, flags);
|
||||||
exit:
|
exit:
|
||||||
dev->interrupt_in_done = 1;
|
dev->interrupt_in_done = 1;
|
||||||
wake_up_interruptible(&dev->read_wait);
|
wake_up_interruptible(&dev->read_wait);
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user