USB patches for 4.12-rc1
Here is the big USB patchset for 4.12-rc1. Lots of good stuff here, after many many many attempts, the kernel finally has a working typeC interface, many thanks to the Heikki and Guenter and others who have taken the time to get this merged. It wasn't an easy path for them at all. There's also a staging driver that uses this new api, which is why it's coming in through this tree. Along with that, there's the usual huge number of changes for gadget drivers, xhci, and other stuff. Johan also finally refactored pretty much every driver that was looking at USB endpoints to do it in a common way, which will help prevent any "badly-formed" devices from causing problems in drivers. That too wasn't a simple task. All of these have been in linux-next for a while with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCWQvEIQ8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+yny4gCePCXxnrQdMWE+IMXf1H1hMubLkVkAn0ZWgQkq BspgO7ZmGb+9Fpf6YvNz =nwAu -----END PGP SIGNATURE----- Merge tag 'usb-4.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB updates from Greg KH: "Here is the big USB patchset for 4.12-rc1. Lots of good stuff here, after many many many attempts, the kernel finally has a working typeC interface, many thanks to Heikki and Guenter and others who have taken the time to get this merged. It wasn't an easy path for them at all. There's also a staging driver that uses this new api, which is why it's coming in through this tree. Along with that, there's the usual huge number of changes for gadget drivers, xhci, and other stuff. Johan also finally refactored pretty much every driver that was looking at USB endpoints to do it in a common way, which will help prevent any "badly-formed" devices from causing problems in drivers. That too wasn't a simple task. All of these have been in linux-next for a while with no reported issues" * tag 'usb-4.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (263 commits) staging: typec: Fairchild FUSB302 Type-c chip driver staging: typec: Type-C Port Controller Interface driver (tcpci) staging: typec: USB Type-C Port Manager (tcpm) usb: host: xhci: remove #ifdef around PM functions usb: musb: don't mark of_dev_auxdata as initdata usb: misc: legousbtower: Fix buffers on stack USB: Revert "cdc-wdm: fix "out-of-sync" due to missing notifications" usb: Make sure usb/phy/of gets built-in USB: storage: e-mail update in drivers/usb/storage/unusual_devs.h usb: host: xhci: print correct command ring address usb: host: xhci: delete sp_dma_buffers for scratchpad usb: host: xhci: using correct specification chapter reference for DCBAAP xhci: switch to pci_alloc_irq_vectors usb: host: xhci-plat: set resume_quirk() for R-Car controllers usb: host: xhci-plat: add resume_quirk() usb: host: xhci-plat: enable clk in resume timing usb: host: plat: Enable xHCI plat runtime PM USB: serial: ftdi_sio: add device ID for Microsemi/Arrow SF2PLUS Dev Kit USB: serial: constify static arrays usb: fix some references for /proc/bus/usb ...
This commit is contained in:
commit
8f28472a73
276
Documentation/ABI/testing/sysfs-class-typec
Normal file
276
Documentation/ABI/testing/sysfs-class-typec
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
USB Type-C port devices (eg. /sys/class/typec/port0/)
|
||||||
|
|
||||||
|
What: /sys/class/typec/<port>/data_role
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
The supported USB data roles. This attribute can be used for
|
||||||
|
requesting data role swapping on the port. Swapping is supported
|
||||||
|
as synchronous operation, so write(2) to the attribute will not
|
||||||
|
return until the operation has finished. The attribute is
|
||||||
|
notified about role changes so that poll(2) on the attribute
|
||||||
|
wakes up. Change on the role will also generate uevent
|
||||||
|
KOBJ_CHANGE on the port. The current role is show in brackets,
|
||||||
|
for example "[host] device" when DRP port is in host mode.
|
||||||
|
|
||||||
|
Valid values: host, device
|
||||||
|
|
||||||
|
What: /sys/class/typec/<port>/power_role
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
The supported power roles. This attribute can be used to request
|
||||||
|
power role swap on the port when the port supports USB Power
|
||||||
|
Delivery. Swapping is supported as synchronous operation, so
|
||||||
|
write(2) to the attribute will not return until the operation
|
||||||
|
has finished. The attribute is notified about role changes so
|
||||||
|
that poll(2) on the attribute wakes up. Change on the role will
|
||||||
|
also generate uevent KOBJ_CHANGE. The current role is show in
|
||||||
|
brackets, for example "[source] sink" when in source mode.
|
||||||
|
|
||||||
|
Valid values: source, sink
|
||||||
|
|
||||||
|
What: /sys/class/typec/<port>/vconn_source
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
Shows is the port VCONN Source. This attribute can be used to
|
||||||
|
request VCONN swap to change the VCONN Source during connection
|
||||||
|
when both the port and the partner support USB Power Delivery.
|
||||||
|
Swapping is supported as synchronous operation, so write(2) to
|
||||||
|
the attribute will not return until the operation has finished.
|
||||||
|
The attribute is notified about VCONN source changes so that
|
||||||
|
poll(2) on the attribute wakes up. Change on VCONN source also
|
||||||
|
generates uevent KOBJ_CHANGE.
|
||||||
|
|
||||||
|
Valid values:
|
||||||
|
- "no" when the port is not the VCONN Source
|
||||||
|
- "yes" when the port is the VCONN Source
|
||||||
|
|
||||||
|
What: /sys/class/typec/<port>/power_operation_mode
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
Shows the current power operational mode the port is in. The
|
||||||
|
power operation mode means current level for VBUS. In case USB
|
||||||
|
Power Delivery communication is used for negotiating the levels,
|
||||||
|
power operation mode should show "usb_power_delivery".
|
||||||
|
|
||||||
|
Valid values:
|
||||||
|
- default
|
||||||
|
- 1.5A
|
||||||
|
- 3.0A
|
||||||
|
- usb_power_delivery
|
||||||
|
|
||||||
|
What: /sys/class/typec/<port>/preferred_role
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
The user space can notify the driver about the preferred role.
|
||||||
|
It should be handled as enabling of Try.SRC or Try.SNK, as
|
||||||
|
defined in USB Type-C specification, in the port drivers. By
|
||||||
|
default the preferred role should come from the platform.
|
||||||
|
|
||||||
|
Valid values: source, sink, none (to remove preference)
|
||||||
|
|
||||||
|
What: /sys/class/typec/<port>/supported_accessory_modes
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
Space separated list of accessory modes, defined in the USB
|
||||||
|
Type-C specification, the port supports.
|
||||||
|
|
||||||
|
What: /sys/class/typec/<port>/usb_power_delivery_revision
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
Revision number of the supported USB Power Delivery
|
||||||
|
specification, or 0 when USB Power Delivery is not supported.
|
||||||
|
|
||||||
|
What: /sys/class/typec/<port>/usb_typec_revision
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
Revision number of the supported USB Type-C specification.
|
||||||
|
|
||||||
|
|
||||||
|
USB Type-C partner devices (eg. /sys/class/typec/port0-partner/)
|
||||||
|
|
||||||
|
What: /sys/class/typec/<port>-partner/accessory_mode
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
Shows the Accessory Mode name when the partner is an Accessory.
|
||||||
|
The Accessory Modes are defined in USB Type-C Specification.
|
||||||
|
|
||||||
|
What: /sys/class/typec/<port>-partner/supports_usb_power_delivery
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
Shows if the partner supports USB Power Delivery communication:
|
||||||
|
Valid values: yes, no
|
||||||
|
|
||||||
|
What: /sys/class/typec/<port>-partner>/identity/
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
This directory appears only if the port device driver is capable
|
||||||
|
of showing the result of Discover Identity USB power delivery
|
||||||
|
command. That will not always be possible even when USB power
|
||||||
|
delivery is supported, for example when USB power delivery
|
||||||
|
communication for the port is mostly handled in firmware. If the
|
||||||
|
directory exists, it will have an attribute file for every VDO
|
||||||
|
in Discover Identity command result.
|
||||||
|
|
||||||
|
What: /sys/class/typec/<port>-partner/identity/id_header
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
ID Header VDO part of Discover Identity command result. The
|
||||||
|
value will show 0 until Discover Identity command result becomes
|
||||||
|
available. The value can be polled.
|
||||||
|
|
||||||
|
What: /sys/class/typec/<port>-partner/identity/cert_stat
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
Cert Stat VDO part of Discover Identity command result. The
|
||||||
|
value will show 0 until Discover Identity command result becomes
|
||||||
|
available. The value can be polled.
|
||||||
|
|
||||||
|
What: /sys/class/typec/<port>-partner/identity/product
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
Product VDO part of Discover Identity command result. The value
|
||||||
|
will show 0 until Discover Identity command result becomes
|
||||||
|
available. The value can be polled.
|
||||||
|
|
||||||
|
|
||||||
|
USB Type-C cable devices (eg. /sys/class/typec/port0-cable/)
|
||||||
|
|
||||||
|
Note: Electronically Marked Cables will have a device also for one cable plug
|
||||||
|
(eg. /sys/class/typec/port0-plug0). If the cable is active and has also SOP
|
||||||
|
Double Prime controller (USB Power Deliver specification ch. 2.4) it will have
|
||||||
|
second device also for the other plug. Both plugs may have alternate modes as
|
||||||
|
described in USB Type-C and USB Power Delivery specifications.
|
||||||
|
|
||||||
|
What: /sys/class/typec/<port>-cable/type
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
Shows if the cable is active.
|
||||||
|
Valid values: active, passive
|
||||||
|
|
||||||
|
What: /sys/class/typec/<port>-cable/plug_type
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
Shows type of the plug on the cable:
|
||||||
|
- type-a - Standard A
|
||||||
|
- type-b - Standard B
|
||||||
|
- type-c
|
||||||
|
- captive
|
||||||
|
|
||||||
|
What: /sys/class/typec/<port>-cable/identity/
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
This directory appears only if the port device driver is capable
|
||||||
|
of showing the result of Discover Identity USB power delivery
|
||||||
|
command. That will not always be possible even when USB power
|
||||||
|
delivery is supported. If the directory exists, it will have an
|
||||||
|
attribute for every VDO returned by Discover Identity command.
|
||||||
|
|
||||||
|
What: /sys/class/typec/<port>-cable/identity/id_header
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
ID Header VDO part of Discover Identity command result. The
|
||||||
|
value will show 0 until Discover Identity command result becomes
|
||||||
|
available. The value can be polled.
|
||||||
|
|
||||||
|
What: /sys/class/typec/<port>-cable/identity/cert_stat
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
Cert Stat VDO part of Discover Identity command result. The
|
||||||
|
value will show 0 until Discover Identity command result becomes
|
||||||
|
available. The value can be polled.
|
||||||
|
|
||||||
|
What: /sys/class/typec/<port>-cable/identity/product
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
Product VDO part of Discover Identity command result. The value
|
||||||
|
will show 0 until Discover Identity command result becomes
|
||||||
|
available. The value can be polled.
|
||||||
|
|
||||||
|
|
||||||
|
Alternate Mode devices.
|
||||||
|
|
||||||
|
The alternate modes will have Standard or Vendor ID (SVID) assigned by USB-IF.
|
||||||
|
The ports, partners and cable plugs can have alternate modes. A supported SVID
|
||||||
|
will consist of a set of modes. Every SVID a port/partner/plug supports will
|
||||||
|
have a device created for it, and every supported mode for a supported SVID will
|
||||||
|
have its own directory under that device. Below <dev> refers to the device for
|
||||||
|
the alternate mode.
|
||||||
|
|
||||||
|
What: /sys/class/typec/<port|partner|cable>/<dev>/svid
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
The SVID (Standard or Vendor ID) assigned by USB-IF for this
|
||||||
|
alternate mode.
|
||||||
|
|
||||||
|
What: /sys/class/typec/<port|partner|cable>/<dev>/mode<index>/
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
Every supported mode will have its own directory. The name of
|
||||||
|
a mode will be "mode<index>" (for example mode1), where <index>
|
||||||
|
is the actual index to the mode VDO returned by Discover Modes
|
||||||
|
USB power delivery command.
|
||||||
|
|
||||||
|
What: /sys/class/typec/<port|partner|cable>/<dev>/mode<index>/description
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
Shows description of the mode. The description is optional for
|
||||||
|
the drivers, just like with the Billboard Devices.
|
||||||
|
|
||||||
|
What: /sys/class/typec/<port|partner|cable>/<dev>/mode<index>/vdo
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
Shows the VDO in hexadecimal returned by Discover Modes command
|
||||||
|
for this mode.
|
||||||
|
|
||||||
|
What: /sys/class/typec/<port|partner|cable>/<dev>/mode<index>/active
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
Shows if the mode is active or not. The attribute can be used
|
||||||
|
for entering/exiting the mode with partners and cable plugs, and
|
||||||
|
with the port alternate modes it can be used for disabling
|
||||||
|
support for specific alternate modes. Entering/exiting modes is
|
||||||
|
supported as synchronous operation so write(2) to the attribute
|
||||||
|
does not return until the enter/exit mode operation has
|
||||||
|
finished. The attribute is notified when the mode is
|
||||||
|
entered/exited so poll(2) on the attribute wakes up.
|
||||||
|
Entering/exiting a mode will also generate uevent KOBJ_CHANGE.
|
||||||
|
|
||||||
|
Valid values: yes, no
|
||||||
|
|
||||||
|
What: /sys/class/typec/<port>/<dev>/mode<index>/supported_roles
|
||||||
|
Date: April 2017
|
||||||
|
Contact: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
Description:
|
||||||
|
Space separated list of the supported roles.
|
||||||
|
|
||||||
|
This attribute is available for the devices describing the
|
||||||
|
alternate modes a port supports, and it will not be exposed with
|
||||||
|
the devices presenting the alternate modes the partners or cable
|
||||||
|
plugs support.
|
||||||
|
|
||||||
|
Valid values: source, sink
|
9
Documentation/ABI/testing/sysfs-platform-chipidea-usb2
Normal file
9
Documentation/ABI/testing/sysfs-platform-chipidea-usb2
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
What: /sys/bus/platform/devices/ci_hdrc.0/role
|
||||||
|
Date: Mar 2017
|
||||||
|
Contact: Peter Chen <peter.chen@nxp.com>
|
||||||
|
Description:
|
||||||
|
It returns string "gadget" or "host" when read it, it indicates
|
||||||
|
current controller role.
|
||||||
|
|
||||||
|
It will do role switch when write "gadget" or "host" to it.
|
||||||
|
Only controller at dual-role configuration supports writing.
|
15
Documentation/ABI/testing/sysfs-platform-renesas_usb3
Normal file
15
Documentation/ABI/testing/sysfs-platform-renesas_usb3
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
What: /sys/devices/platform/<renesas_usb3's name>/role
|
||||||
|
Date: March 2017
|
||||||
|
KernelVersion: 4.13
|
||||||
|
Contact: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
|
||||||
|
Description:
|
||||||
|
This file can be read and write.
|
||||||
|
The file can show/change the drd mode of usb.
|
||||||
|
|
||||||
|
Write the following string to change the mode:
|
||||||
|
"host" - switching mode from peripheral to host.
|
||||||
|
"peripheral" - switching mode from host to peripheral.
|
||||||
|
|
||||||
|
Read the file, then it shows the following strings:
|
||||||
|
"host" - The mode is host now.
|
||||||
|
"peripheral" - The mode is peripheral now.
|
@ -6,12 +6,11 @@ This binding describes a usb3.0 phy for mt65xx platforms of Medaitek SoC.
|
|||||||
Required properties (controller (parent) node):
|
Required properties (controller (parent) node):
|
||||||
- compatible : should be one of
|
- compatible : should be one of
|
||||||
"mediatek,mt2701-u3phy"
|
"mediatek,mt2701-u3phy"
|
||||||
|
"mediatek,mt2712-u3phy"
|
||||||
"mediatek,mt8173-u3phy"
|
"mediatek,mt8173-u3phy"
|
||||||
- reg : offset and length of register for phy, exclude port's
|
- clocks : (deprecated, use port's clocks instead) a list of phandle +
|
||||||
register.
|
clock-specifier pairs, one for each entry in clock-names
|
||||||
- clocks : a list of phandle + clock-specifier pairs, one for each
|
- clock-names : (deprecated, use port's one instead) must contain
|
||||||
entry in clock-names
|
|
||||||
- clock-names : must contain
|
|
||||||
"u3phya_ref": for reference clock of usb3.0 analog phy.
|
"u3phya_ref": for reference clock of usb3.0 analog phy.
|
||||||
|
|
||||||
Required nodes : a sub-node is required for each port the controller
|
Required nodes : a sub-node is required for each port the controller
|
||||||
@ -19,8 +18,19 @@ Required nodes : a sub-node is required for each port the controller
|
|||||||
'reg' property is used inside these nodes to describe
|
'reg' property is used inside these nodes to describe
|
||||||
the controller's topology.
|
the controller's topology.
|
||||||
|
|
||||||
|
Optional properties (controller (parent) node):
|
||||||
|
- reg : offset and length of register shared by multiple ports,
|
||||||
|
exclude port's private register. It is needed on mt2701
|
||||||
|
and mt8173, but not on mt2712.
|
||||||
|
|
||||||
Required properties (port (child) node):
|
Required properties (port (child) node):
|
||||||
- reg : address and length of the register set for the port.
|
- reg : address and length of the register set for the port.
|
||||||
|
- clocks : a list of phandle + clock-specifier pairs, one for each
|
||||||
|
entry in clock-names
|
||||||
|
- clock-names : must contain
|
||||||
|
"ref": 48M reference clock for HighSpeed analog phy; and 26M
|
||||||
|
reference clock for SuperSpeed analog phy, sometimes is
|
||||||
|
24M, 25M or 27M, depended on platform.
|
||||||
- #phy-cells : should be 1 (See second example)
|
- #phy-cells : should be 1 (See second example)
|
||||||
cell after port phandle is phy type from:
|
cell after port phandle is phy type from:
|
||||||
- PHY_TYPE_USB2
|
- PHY_TYPE_USB2
|
||||||
@ -31,21 +41,31 @@ Example:
|
|||||||
u3phy: usb-phy@11290000 {
|
u3phy: usb-phy@11290000 {
|
||||||
compatible = "mediatek,mt8173-u3phy";
|
compatible = "mediatek,mt8173-u3phy";
|
||||||
reg = <0 0x11290000 0 0x800>;
|
reg = <0 0x11290000 0 0x800>;
|
||||||
clocks = <&apmixedsys CLK_APMIXED_REF2USB_TX>;
|
|
||||||
clock-names = "u3phya_ref";
|
|
||||||
#address-cells = <2>;
|
#address-cells = <2>;
|
||||||
#size-cells = <2>;
|
#size-cells = <2>;
|
||||||
ranges;
|
ranges;
|
||||||
status = "okay";
|
status = "okay";
|
||||||
|
|
||||||
phy_port0: port@11290800 {
|
u2port0: usb-phy@11290800 {
|
||||||
reg = <0 0x11290800 0 0x800>;
|
reg = <0 0x11290800 0 0x100>;
|
||||||
|
clocks = <&apmixedsys CLK_APMIXED_REF2USB_TX>;
|
||||||
|
clock-names = "ref";
|
||||||
#phy-cells = <1>;
|
#phy-cells = <1>;
|
||||||
status = "okay";
|
status = "okay";
|
||||||
};
|
};
|
||||||
|
|
||||||
phy_port1: port@11291000 {
|
u3port0: usb-phy@11290900 {
|
||||||
reg = <0 0x11291000 0 0x800>;
|
reg = <0 0x11290800 0 0x700>;
|
||||||
|
clocks = <&clk26m>;
|
||||||
|
clock-names = "ref";
|
||||||
|
#phy-cells = <1>;
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
u2port1: usb-phy@11291000 {
|
||||||
|
reg = <0 0x11291000 0 0x100>;
|
||||||
|
clocks = <&apmixedsys CLK_APMIXED_REF2USB_TX>;
|
||||||
|
clock-names = "ref";
|
||||||
#phy-cells = <1>;
|
#phy-cells = <1>;
|
||||||
status = "okay";
|
status = "okay";
|
||||||
};
|
};
|
||||||
@ -64,7 +84,54 @@ Example:
|
|||||||
|
|
||||||
usb30: usb@11270000 {
|
usb30: usb@11270000 {
|
||||||
...
|
...
|
||||||
phys = <&phy_port0 PHY_TYPE_USB3>;
|
phys = <&u2port0 PHY_TYPE_USB2>, <&u3port0 PHY_TYPE_USB3>;
|
||||||
phy-names = "usb3-0";
|
phy-names = "usb2-0", "usb3-0";
|
||||||
...
|
...
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Layout differences of banks between mt8173/mt2701 and mt2712
|
||||||
|
-------------------------------------------------------------
|
||||||
|
mt8173 and mt2701:
|
||||||
|
port offset bank
|
||||||
|
shared 0x0000 SPLLC
|
||||||
|
0x0100 FMREG
|
||||||
|
u2 port0 0x0800 U2PHY_COM
|
||||||
|
u3 port0 0x0900 U3PHYD
|
||||||
|
0x0a00 U3PHYD_BANK2
|
||||||
|
0x0b00 U3PHYA
|
||||||
|
0x0c00 U3PHYA_DA
|
||||||
|
u2 port1 0x1000 U2PHY_COM
|
||||||
|
u3 port1 0x1100 U3PHYD
|
||||||
|
0x1200 U3PHYD_BANK2
|
||||||
|
0x1300 U3PHYA
|
||||||
|
0x1400 U3PHYA_DA
|
||||||
|
u2 port2 0x1800 U2PHY_COM
|
||||||
|
...
|
||||||
|
|
||||||
|
mt2712:
|
||||||
|
port offset bank
|
||||||
|
u2 port0 0x0000 MISC
|
||||||
|
0x0100 FMREG
|
||||||
|
0x0300 U2PHY_COM
|
||||||
|
u3 port0 0x0700 SPLLC
|
||||||
|
0x0800 CHIP
|
||||||
|
0x0900 U3PHYD
|
||||||
|
0x0a00 U3PHYD_BANK2
|
||||||
|
0x0b00 U3PHYA
|
||||||
|
0x0c00 U3PHYA_DA
|
||||||
|
u2 port1 0x1000 MISC
|
||||||
|
0x1100 FMREG
|
||||||
|
0x1300 U2PHY_COM
|
||||||
|
u3 port1 0x1700 SPLLC
|
||||||
|
0x1800 CHIP
|
||||||
|
0x1900 U3PHYD
|
||||||
|
0x1a00 U3PHYD_BANK2
|
||||||
|
0x1b00 U3PHYA
|
||||||
|
0x1c00 U3PHYA_DA
|
||||||
|
u2 port2 0x2000 MISC
|
||||||
|
...
|
||||||
|
|
||||||
|
SPLLC shared by u3 ports and FMREG shared by u2 ports on
|
||||||
|
mt8173/mt2701 are put back into each port; a new bank MISC for
|
||||||
|
u2 ports and CHIP for u3 ports are added on mt2712.
|
||||||
|
@ -2,6 +2,7 @@ ROCKCHIP USB2.0 PHY WITH INNO IP BLOCK
|
|||||||
|
|
||||||
Required properties (phy (parent) node):
|
Required properties (phy (parent) node):
|
||||||
- compatible : should be one of the listed compatibles:
|
- compatible : should be one of the listed compatibles:
|
||||||
|
* "rockchip,rk3328-usb2phy"
|
||||||
* "rockchip,rk3366-usb2phy"
|
* "rockchip,rk3366-usb2phy"
|
||||||
* "rockchip,rk3399-usb2phy"
|
* "rockchip,rk3399-usb2phy"
|
||||||
- reg : the address offset of grf for usb-phy configuration.
|
- reg : the address offset of grf for usb-phy configuration.
|
||||||
@ -11,6 +12,11 @@ Required properties (phy (parent) node):
|
|||||||
Optional properties:
|
Optional properties:
|
||||||
- clocks : phandle + phy specifier pair, for the input clock of phy.
|
- clocks : phandle + phy specifier pair, for the input clock of phy.
|
||||||
- clock-names : input clock name of phy, must be "phyclk".
|
- clock-names : input clock name of phy, must be "phyclk".
|
||||||
|
- assigned-clocks : phandle of usb 480m clock.
|
||||||
|
- assigned-clock-parents : parent of usb 480m clock, select between
|
||||||
|
usb-phy output 480m and xin24m.
|
||||||
|
Refer to clk/clock-bindings.txt for generic clock
|
||||||
|
consumer properties.
|
||||||
|
|
||||||
Required nodes : a sub-node is required for each port the phy provides.
|
Required nodes : a sub-node is required for each port the phy provides.
|
||||||
The sub-node name is used to identify host or otg port,
|
The sub-node name is used to identify host or otg port,
|
||||||
|
106
Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt
Normal file
106
Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
Qualcomm QMP PHY controller
|
||||||
|
===========================
|
||||||
|
|
||||||
|
QMP phy controller supports physical layer functionality for a number of
|
||||||
|
controllers on Qualcomm chipsets, such as, PCIe, UFS, and USB.
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: compatible list, contains:
|
||||||
|
"qcom,msm8996-qmp-pcie-phy" for 14nm PCIe phy on msm8996,
|
||||||
|
"qcom,msm8996-qmp-usb3-phy" for 14nm USB3 phy on msm8996.
|
||||||
|
|
||||||
|
- reg: offset and length of register set for PHY's common serdes block.
|
||||||
|
|
||||||
|
- #clock-cells: must be 1
|
||||||
|
- Phy pll outputs a bunch of clocks for Tx, Rx and Pipe
|
||||||
|
interface (for pipe based PHYs). These clock are then gate-controlled
|
||||||
|
by gcc.
|
||||||
|
- #address-cells: must be 1
|
||||||
|
- #size-cells: must be 1
|
||||||
|
- ranges: must be present
|
||||||
|
|
||||||
|
- clocks: a list of phandles and clock-specifier pairs,
|
||||||
|
one for each entry in clock-names.
|
||||||
|
- clock-names: "cfg_ahb" for phy config clock,
|
||||||
|
"aux" for phy aux clock,
|
||||||
|
"ref" for 19.2 MHz ref clk,
|
||||||
|
For "qcom,msm8996-qmp-pcie-phy" must contain:
|
||||||
|
"aux", "cfg_ahb", "ref".
|
||||||
|
For "qcom,msm8996-qmp-usb3-phy" must contain:
|
||||||
|
"aux", "cfg_ahb", "ref".
|
||||||
|
|
||||||
|
- resets: a list of phandles and reset controller specifier pairs,
|
||||||
|
one for each entry in reset-names.
|
||||||
|
- reset-names: "phy" for reset of phy block,
|
||||||
|
"common" for phy common block reset,
|
||||||
|
"cfg" for phy's ahb cfg block reset (Optional).
|
||||||
|
For "qcom,msm8996-qmp-pcie-phy" must contain:
|
||||||
|
"phy", "common", "cfg".
|
||||||
|
For "qcom,msm8996-qmp-usb3-phy" must contain
|
||||||
|
"phy", "common".
|
||||||
|
|
||||||
|
- vdda-phy-supply: Phandle to a regulator supply to PHY core block.
|
||||||
|
- vdda-pll-supply: Phandle to 1.8V regulator supply to PHY refclk pll block.
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
- vddp-ref-clk-supply: Phandle to a regulator supply to any specific refclk
|
||||||
|
pll block.
|
||||||
|
|
||||||
|
Required nodes:
|
||||||
|
- Each device node of QMP phy is required to have as many child nodes as
|
||||||
|
the number of lanes the PHY has.
|
||||||
|
|
||||||
|
Required properties for child node:
|
||||||
|
- reg: list of offset and length pairs of register sets for PHY blocks -
|
||||||
|
tx, rx and pcs.
|
||||||
|
|
||||||
|
- #phy-cells: must be 0
|
||||||
|
|
||||||
|
- clocks: a list of phandles and clock-specifier pairs,
|
||||||
|
one for each entry in clock-names.
|
||||||
|
- clock-names: Must contain following for pcie and usb qmp phys:
|
||||||
|
"pipe<lane-number>" for pipe clock specific to each lane.
|
||||||
|
|
||||||
|
- resets: a list of phandles and reset controller specifier pairs,
|
||||||
|
one for each entry in reset-names.
|
||||||
|
- reset-names: Must contain following for pcie qmp phys:
|
||||||
|
"lane<lane-number>" for reset specific to each lane.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
phy@34000 {
|
||||||
|
compatible = "qcom,msm8996-qmp-pcie-phy";
|
||||||
|
reg = <0x34000 0x488>;
|
||||||
|
#clock-cells = <1>;
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <1>;
|
||||||
|
ranges;
|
||||||
|
|
||||||
|
clocks = <&gcc GCC_PCIE_PHY_AUX_CLK>,
|
||||||
|
<&gcc GCC_PCIE_PHY_CFG_AHB_CLK>,
|
||||||
|
<&gcc GCC_PCIE_CLKREF_CLK>;
|
||||||
|
clock-names = "aux", "cfg_ahb", "ref";
|
||||||
|
|
||||||
|
vdda-phy-supply = <&pm8994_l28>;
|
||||||
|
vdda-pll-supply = <&pm8994_l12>;
|
||||||
|
|
||||||
|
resets = <&gcc GCC_PCIE_PHY_BCR>,
|
||||||
|
<&gcc GCC_PCIE_PHY_COM_BCR>,
|
||||||
|
<&gcc GCC_PCIE_PHY_COM_NOCSR_BCR>;
|
||||||
|
reset-names = "phy", "common", "cfg";
|
||||||
|
|
||||||
|
pciephy_0: lane@35000 {
|
||||||
|
reg = <0x35000 0x130>,
|
||||||
|
<0x35200 0x200>,
|
||||||
|
<0x35400 0x1dc>;
|
||||||
|
#phy-cells = <0>;
|
||||||
|
|
||||||
|
clocks = <&gcc GCC_PCIE_0_PIPE_CLK>;
|
||||||
|
clock-names = "pipe0";
|
||||||
|
resets = <&gcc GCC_PCIE_0_PHY_BCR>;
|
||||||
|
reset-names = "lane0";
|
||||||
|
};
|
||||||
|
|
||||||
|
pciephy_1: lane@36000 {
|
||||||
|
...
|
||||||
|
...
|
||||||
|
};
|
43
Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt
Normal file
43
Documentation/devicetree/bindings/phy/qcom-qusb2-phy.txt
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
Qualcomm QUSB2 phy controller
|
||||||
|
=============================
|
||||||
|
|
||||||
|
QUSB2 controller supports LS/FS/HS usb connectivity on Qualcomm chipsets.
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: compatible list, contains "qcom,msm8996-qusb2-phy".
|
||||||
|
- reg: offset and length of the PHY register set.
|
||||||
|
- #phy-cells: must be 0.
|
||||||
|
|
||||||
|
- clocks: a list of phandles and clock-specifier pairs,
|
||||||
|
one for each entry in clock-names.
|
||||||
|
- clock-names: must be "cfg_ahb" for phy config clock,
|
||||||
|
"ref" for 19.2 MHz ref clk,
|
||||||
|
"iface" for phy interface clock (Optional).
|
||||||
|
|
||||||
|
- vdda-pll-supply: Phandle to 1.8V regulator supply to PHY refclk pll block.
|
||||||
|
- vdda-phy-dpdm-supply: Phandle to 3.1V regulator supply to Dp/Dm port signals.
|
||||||
|
|
||||||
|
- resets: Phandle to reset to phy block.
|
||||||
|
|
||||||
|
Optional properties:
|
||||||
|
- nvmem-cells: Phandle to nvmem cell that contains 'HS Tx trim'
|
||||||
|
tuning parameter value for qusb2 phy.
|
||||||
|
|
||||||
|
- qcom,tcsr-syscon: Phandle to TCSR syscon register region.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
hsusb_phy: phy@7411000 {
|
||||||
|
compatible = "qcom,msm8996-qusb2-phy";
|
||||||
|
reg = <0x7411000 0x180>;
|
||||||
|
#phy-cells = <0>;
|
||||||
|
|
||||||
|
clocks = <&gcc GCC_USB_PHY_CFG_AHB2PHY_CLK>,
|
||||||
|
<&gcc GCC_RX1_USB2_CLKREF_CLK>,
|
||||||
|
clock-names = "cfg_ahb", "ref";
|
||||||
|
|
||||||
|
vdda-pll-supply = <&pm8994_l12>;
|
||||||
|
vdda-phy-dpdm-supply = <&pm8994_l24>;
|
||||||
|
|
||||||
|
resets = <&gcc GCC_QUSB2PHY_PRIM_BCR>;
|
||||||
|
nvmem-cells = <&qusb2p_hstx_trim>;
|
||||||
|
};
|
@ -30,6 +30,7 @@ Optional Properties:
|
|||||||
- reset-names: Only allow the following entries:
|
- reset-names: Only allow the following entries:
|
||||||
- phy-reset
|
- phy-reset
|
||||||
- resets: Must contain an entry for each entry in reset-names.
|
- resets: Must contain an entry for each entry in reset-names.
|
||||||
|
- vbus-supply: power-supply phandle for vbus power source
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ Required properties:
|
|||||||
- reg : a list of offset + length pairs
|
- reg : a list of offset + length pairs
|
||||||
- reg-names :
|
- reg-names :
|
||||||
* "phy_ctrl"
|
* "phy_ctrl"
|
||||||
|
* "pmu0" for H3, V3s and A64
|
||||||
* "pmu1"
|
* "pmu1"
|
||||||
* "pmu2" for sun4i, sun6i or sun7i
|
* "pmu2" for sun4i, sun6i or sun7i
|
||||||
- #phy-cells : from the generic phy bindings, must be 1
|
- #phy-cells : from the generic phy bindings, must be 1
|
||||||
|
@ -8,6 +8,8 @@ From RK3368 SoCs, the GRF is divided into two sections,
|
|||||||
- SGRF, used for general secure system,
|
- SGRF, used for general secure system,
|
||||||
- PMUGRF, used for always on system
|
- PMUGRF, used for always on system
|
||||||
|
|
||||||
|
On RK3328 SoCs, the GRF adds a section for USB2PHYGRF,
|
||||||
|
|
||||||
Required Properties:
|
Required Properties:
|
||||||
|
|
||||||
- compatible: GRF should be one of the following:
|
- compatible: GRF should be one of the following:
|
||||||
@ -23,6 +25,8 @@ Required Properties:
|
|||||||
- "rockchip,rk3399-pmugrf", "syscon": for rk3399
|
- "rockchip,rk3399-pmugrf", "syscon": for rk3399
|
||||||
- compatible: SGRF should be one of the following
|
- compatible: SGRF should be one of the following
|
||||||
- "rockchip,rk3288-sgrf", "syscon": for rk3288
|
- "rockchip,rk3288-sgrf", "syscon": for rk3288
|
||||||
|
- compatible: USB2PHYGRF should be one of the followings
|
||||||
|
- "rockchip,rk3328-usb2phy-grf", "syscon": for rk3328
|
||||||
- reg: physical base address of the controller and length of memory mapped
|
- reg: physical base address of the controller and length of memory mapped
|
||||||
region.
|
region.
|
||||||
|
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
* EHCI controller, Orion Marvell variants
|
* EHCI controller, Orion Marvell variants
|
||||||
|
|
||||||
Required properties:
|
Required properties:
|
||||||
- compatible: must be "marvell,orion-ehci"
|
- compatible: must be one of the following
|
||||||
|
"marvell,orion-ehci"
|
||||||
|
"marvell,armada-3700-ehci"
|
||||||
- reg: physical base address of the controller and length of memory mapped
|
- reg: physical base address of the controller and length of memory mapped
|
||||||
region.
|
region.
|
||||||
- interrupts: The EHCI interrupt
|
- interrupts: The EHCI interrupt
|
||||||
|
@ -22,6 +22,7 @@ Optional properties:
|
|||||||
property is used if any real OTG features(HNP/SRP/ADP)
|
property is used if any real OTG features(HNP/SRP/ADP)
|
||||||
is enabled, if ADP is required, otg-rev should be
|
is enabled, if ADP is required, otg-rev should be
|
||||||
0x0200 or above.
|
0x0200 or above.
|
||||||
|
- companion: phandle of a companion
|
||||||
- hnp-disable: tells OTG controllers we want to disable OTG HNP, normally HNP
|
- hnp-disable: tells OTG controllers we want to disable OTG HNP, normally HNP
|
||||||
is the basic function of real OTG except you want it
|
is the basic function of real OTG except you want it
|
||||||
to be a srp-capable only B device.
|
to be a srp-capable only B device.
|
||||||
|
@ -145,8 +145,8 @@ dev_hint
|
|||||||
|
|
||||||
A camera is specified by its type (the number from the camera model,
|
A camera is specified by its type (the number from the camera model,
|
||||||
like PCA645, PCVC750VC, etc) and optionally the serial number (visible
|
like PCA645, PCVC750VC, etc) and optionally the serial number (visible
|
||||||
in /proc/bus/usb/devices). A hint consists of a string with the following
|
in /sys/kernel/debug/usb/devices). A hint consists of a string with the
|
||||||
format::
|
following format::
|
||||||
|
|
||||||
[type[.serialnumber]:]node
|
[type[.serialnumber]:]node
|
||||||
|
|
||||||
|
184
Documentation/usb/typec.rst
Normal file
184
Documentation/usb/typec.rst
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
|
||||||
|
USB Type-C connector class
|
||||||
|
==========================
|
||||||
|
|
||||||
|
Introduction
|
||||||
|
------------
|
||||||
|
|
||||||
|
The typec class is meant for describing the USB Type-C ports in a system to the
|
||||||
|
user space in unified fashion. The class is designed to provide nothing else
|
||||||
|
except the user space interface implementation in hope that it can be utilized
|
||||||
|
on as many platforms as possible.
|
||||||
|
|
||||||
|
The platforms are expected to register every USB Type-C port they have with the
|
||||||
|
class. In a normal case the registration will be done by a USB Type-C or PD PHY
|
||||||
|
driver, but it may be a driver for firmware interface such as UCSI, driver for
|
||||||
|
USB PD controller or even driver for Thunderbolt3 controller. This document
|
||||||
|
considers the component registering the USB Type-C ports with the class as "port
|
||||||
|
driver".
|
||||||
|
|
||||||
|
On top of showing the capabilities, the class also offer user space control over
|
||||||
|
the roles and alternate modes of ports, partners and cable plugs when the port
|
||||||
|
driver is capable of supporting those features.
|
||||||
|
|
||||||
|
The class provides an API for the port drivers described in this document. The
|
||||||
|
attributes are described in Documentation/ABI/testing/sysfs-class-typec.
|
||||||
|
|
||||||
|
User space interface
|
||||||
|
--------------------
|
||||||
|
Every port will be presented as its own device under /sys/class/typec/. The
|
||||||
|
first port will be named "port0", the second "port1" and so on.
|
||||||
|
|
||||||
|
When connected, the partner will be presented also as its own device under
|
||||||
|
/sys/class/typec/. The parent of the partner device will always be the port it
|
||||||
|
is attached to. The partner attached to port "port0" will be named
|
||||||
|
"port0-partner". Full path to the device would be
|
||||||
|
/sys/class/typec/port0/port0-partner/.
|
||||||
|
|
||||||
|
The cable and the two plugs on it may also be optionally presented as their own
|
||||||
|
devices under /sys/class/typec/. The cable attached to the port "port0" port
|
||||||
|
will be named port0-cable and the plug on the SOP Prime end (see USB Power
|
||||||
|
Delivery Specification ch. 2.4) will be named "port0-plug0" and on the SOP
|
||||||
|
Double Prime end "port0-plug1". The parent of a cable will always be the port,
|
||||||
|
and the parent of the cable plugs will always be the cable.
|
||||||
|
|
||||||
|
If the port, partner or cable plug supports Alternate Modes, every supported
|
||||||
|
Alternate Mode SVID will have their own device describing them. Note that the
|
||||||
|
Alternate Mode devices will not be attached to the typec class. The parent of an
|
||||||
|
alternate mode will be the device that supports it, so for example an alternate
|
||||||
|
mode of port0-partner will be presented under /sys/class/typec/port0-partner/.
|
||||||
|
Every mode that is supported will have its own group under the Alternate Mode
|
||||||
|
device named "mode<index>", for example /sys/class/typec/port0/<alternate
|
||||||
|
mode>/mode1/. The requests for entering/exiting a mode can be done with "active"
|
||||||
|
attribute file in that group.
|
||||||
|
|
||||||
|
Driver API
|
||||||
|
----------
|
||||||
|
|
||||||
|
Registering the ports
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The port drivers will describe every Type-C port they control with struct
|
||||||
|
typec_capability data structure, and register them with the following API:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/usb/typec/typec.c
|
||||||
|
:functions: typec_register_port typec_unregister_port
|
||||||
|
|
||||||
|
When registering the ports, the prefer_role member in struct typec_capability
|
||||||
|
deserves special notice. If the port that is being registered does not have
|
||||||
|
initial role preference, which means the port does not execute Try.SNK or
|
||||||
|
Try.SRC by default, the member must have value TYPEC_NO_PREFERRED_ROLE.
|
||||||
|
Otherwise if the port executes Try.SNK by default, the member must have value
|
||||||
|
TYPEC_DEVICE, and with Try.SRC the value must be TYPEC_HOST.
|
||||||
|
|
||||||
|
Registering Partners
|
||||||
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
After successful connection of a partner, the port driver needs to register the
|
||||||
|
partner with the class. Details about the partner need to be described in struct
|
||||||
|
typec_partner_desc. The class copies the details of the partner during
|
||||||
|
registration. The class offers the following API for registering/unregistering
|
||||||
|
partners.
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/usb/typec/typec.c
|
||||||
|
:functions: typec_register_partner typec_unregister_partner
|
||||||
|
|
||||||
|
The class will provide a handle to struct typec_partner if the registration was
|
||||||
|
successful, or NULL.
|
||||||
|
|
||||||
|
If the partner is USB Power Delivery capable, and the port driver is able to
|
||||||
|
show the result of Discover Identity command, the partner descriptor structure
|
||||||
|
should include handle to struct usb_pd_identity instance. The class will then
|
||||||
|
create a sysfs directory for the identity under the partner device. The result
|
||||||
|
of Discover Identity command can then be reported with the following API:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/usb/typec/typec.c
|
||||||
|
:functions: typec_partner_set_identity
|
||||||
|
|
||||||
|
Registering Cables
|
||||||
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
After successful connection of a cable that supports USB Power Delivery
|
||||||
|
Structured VDM "Discover Identity", the port driver needs to register the cable
|
||||||
|
and one or two plugs, depending if there is CC Double Prime controller present
|
||||||
|
in the cable or not. So a cable capable of SOP Prime communication, but not SOP
|
||||||
|
Double Prime communication, should only have one plug registered. For more
|
||||||
|
information about SOP communication, please read chapter about it from the
|
||||||
|
latest USB Power Delivery specification.
|
||||||
|
|
||||||
|
The plugs are represented as their own devices. The cable is registered first,
|
||||||
|
followed by registration of the cable plugs. The cable will be the parent device
|
||||||
|
for the plugs. Details about the cable need to be described in struct
|
||||||
|
typec_cable_desc and about a plug in struct typec_plug_desc. The class copies
|
||||||
|
the details during registration. The class offers the following API for
|
||||||
|
registering/unregistering cables and their plugs:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/usb/typec/typec.c
|
||||||
|
:functions: typec_register_cable typec_unregister_cable typec_register_plug
|
||||||
|
typec_unregister_plug
|
||||||
|
|
||||||
|
The class will provide a handle to struct typec_cable and struct typec_plug if
|
||||||
|
the registration is successful, or NULL if it isn't.
|
||||||
|
|
||||||
|
If the cable is USB Power Delivery capable, and the port driver is able to show
|
||||||
|
the result of Discover Identity command, the cable descriptor structure should
|
||||||
|
include handle to struct usb_pd_identity instance. The class will then create a
|
||||||
|
sysfs directory for the identity under the cable device. The result of Discover
|
||||||
|
Identity command can then be reported with the following API:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/usb/typec/typec.c
|
||||||
|
:functions: typec_cable_set_identity
|
||||||
|
|
||||||
|
Notifications
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
When the partner has executed a role change, or when the default roles change
|
||||||
|
during connection of a partner or cable, the port driver must use the following
|
||||||
|
APIs to report it to the class:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/usb/typec/typec.c
|
||||||
|
:functions: typec_set_data_role typec_set_pwr_role typec_set_vconn_role
|
||||||
|
typec_set_pwr_opmode
|
||||||
|
|
||||||
|
Alternate Modes
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
USB Type-C ports, partners and cable plugs may support Alternate Modes. Each
|
||||||
|
Alternate Mode will have identifier called SVID, which is either a Standard ID
|
||||||
|
given by USB-IF or vendor ID, and each supported SVID can have 1 - 6 modes. The
|
||||||
|
class provides struct typec_mode_desc for describing individual mode of a SVID,
|
||||||
|
and struct typec_altmode_desc which is a container for all the supported modes.
|
||||||
|
|
||||||
|
Ports that support Alternate Modes need to register each SVID they support with
|
||||||
|
the following API:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/usb/typec/typec.c
|
||||||
|
:functions: typec_port_register_altmode
|
||||||
|
|
||||||
|
If a partner or cable plug provides a list of SVIDs as response to USB Power
|
||||||
|
Delivery Structured VDM Discover SVIDs message, each SVID needs to be
|
||||||
|
registered.
|
||||||
|
|
||||||
|
API for the partners:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/usb/typec/typec.c
|
||||||
|
:functions: typec_partner_register_altmode
|
||||||
|
|
||||||
|
API for the Cable Plugs:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/usb/typec/typec.c
|
||||||
|
:functions: typec_plug_register_altmode
|
||||||
|
|
||||||
|
So ports, partners and cable plugs will register the alternate modes with their
|
||||||
|
own functions, but the registration will always return a handle to struct
|
||||||
|
typec_altmode on success, or NULL. The unregistration will happen with the same
|
||||||
|
function:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/usb/typec/typec.c
|
||||||
|
:functions: typec_unregister_altmode
|
||||||
|
|
||||||
|
If a partner or cable plug enters or exits a mode, the port driver needs to
|
||||||
|
notify the class with the following API:
|
||||||
|
|
||||||
|
.. kernel-doc:: drivers/usb/typec/typec.c
|
||||||
|
:functions: typec_altmode_update_active
|
@ -13248,6 +13248,15 @@ F: drivers/usb/
|
|||||||
F: include/linux/usb.h
|
F: include/linux/usb.h
|
||||||
F: include/linux/usb/
|
F: include/linux/usb/
|
||||||
|
|
||||||
|
USB TYPEC SUBSYSTEM
|
||||||
|
M: Heikki Krogerus <heikki.krogerus@linux.intel.com>
|
||||||
|
L: linux-usb@vger.kernel.org
|
||||||
|
S: Maintained
|
||||||
|
F: Documentation/ABI/testing/sysfs-class-typec
|
||||||
|
F: Documentation/usb/typec.rst
|
||||||
|
F: drivers/usb/typec/
|
||||||
|
F: include/linux/usb/typec.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
|
||||||
|
@ -116,6 +116,12 @@
|
|||||||
status = "okay";
|
status = "okay";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* CON27 */
|
||||||
|
&usb2 {
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
&mdio {
|
&mdio {
|
||||||
status = "okay";
|
status = "okay";
|
||||||
phy0: ethernet-phy@0 {
|
phy0: ethernet-phy@0 {
|
||||||
|
@ -200,6 +200,13 @@
|
|||||||
status = "disabled";
|
status = "disabled";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
usb2: usb@5e000 {
|
||||||
|
compatible = "marvell,armada-3700-ehci";
|
||||||
|
reg = <0x5e000 0x2000>;
|
||||||
|
interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
status = "disabled";
|
||||||
|
};
|
||||||
|
|
||||||
xor@60900 {
|
xor@60900 {
|
||||||
compatible = "marvell,armada-3700-xor";
|
compatible = "marvell,armada-3700-xor";
|
||||||
reg = <0x60900 0x100
|
reg = <0x60900 0x100
|
||||||
|
@ -104,6 +104,7 @@ obj-$(CONFIG_USB_PHY) += usb/
|
|||||||
obj-$(CONFIG_USB) += usb/
|
obj-$(CONFIG_USB) += usb/
|
||||||
obj-$(CONFIG_PCI) += usb/
|
obj-$(CONFIG_PCI) += usb/
|
||||||
obj-$(CONFIG_USB_GADGET) += usb/
|
obj-$(CONFIG_USB_GADGET) += usb/
|
||||||
|
obj-$(CONFIG_OF) += usb/
|
||||||
obj-$(CONFIG_SERIO) += input/serio/
|
obj-$(CONFIG_SERIO) += input/serio/
|
||||||
obj-$(CONFIG_GAMEPORT) += input/gameport/
|
obj-$(CONFIG_GAMEPORT) += input/gameport/
|
||||||
obj-$(CONFIG_INPUT) += input/
|
obj-$(CONFIG_INPUT) += input/
|
||||||
|
@ -439,6 +439,25 @@ config PHY_STIH407_USB
|
|||||||
Enable this support to enable the picoPHY device used by USB2
|
Enable this support to enable the picoPHY device used by USB2
|
||||||
and USB3 controllers on STMicroelectronics STiH407 SoC families.
|
and USB3 controllers on STMicroelectronics STiH407 SoC families.
|
||||||
|
|
||||||
|
config PHY_QCOM_QMP
|
||||||
|
tristate "Qualcomm QMP PHY Driver"
|
||||||
|
depends on OF && COMMON_CLK && (ARCH_QCOM || COMPILE_TEST)
|
||||||
|
select GENERIC_PHY
|
||||||
|
help
|
||||||
|
Enable this to support the QMP PHY transceiver that is used
|
||||||
|
with controllers such as PCIe, UFS, and USB on Qualcomm chips.
|
||||||
|
|
||||||
|
config PHY_QCOM_QUSB2
|
||||||
|
tristate "Qualcomm QUSB2 PHY Driver"
|
||||||
|
depends on OF && (ARCH_QCOM || COMPILE_TEST)
|
||||||
|
depends on NVMEM || !NVMEM
|
||||||
|
select GENERIC_PHY
|
||||||
|
help
|
||||||
|
Enable this to support the HighSpeed QUSB2 PHY transceiver for USB
|
||||||
|
controllers on Qualcomm chips. This driver supports the high-speed
|
||||||
|
PHY which is usually paired with either the ChipIdea or Synopsys DWC3
|
||||||
|
USB IPs on MSM SOCs.
|
||||||
|
|
||||||
config PHY_QCOM_UFS
|
config PHY_QCOM_UFS
|
||||||
tristate "Qualcomm UFS PHY driver"
|
tristate "Qualcomm UFS PHY driver"
|
||||||
depends on OF && ARCH_QCOM
|
depends on OF && ARCH_QCOM
|
||||||
|
@ -50,6 +50,8 @@ obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY) += phy-spear1310-miphy.o
|
|||||||
obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY) += phy-spear1340-miphy.o
|
obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY) += phy-spear1340-miphy.o
|
||||||
obj-$(CONFIG_PHY_XGENE) += phy-xgene.o
|
obj-$(CONFIG_PHY_XGENE) += phy-xgene.o
|
||||||
obj-$(CONFIG_PHY_STIH407_USB) += phy-stih407-usb.o
|
obj-$(CONFIG_PHY_STIH407_USB) += phy-stih407-usb.o
|
||||||
|
obj-$(CONFIG_PHY_QCOM_QMP) += phy-qcom-qmp.o
|
||||||
|
obj-$(CONFIG_PHY_QCOM_QUSB2) += phy-qcom-qusb2.o
|
||||||
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o
|
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o
|
||||||
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o
|
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o
|
||||||
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o
|
obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
* Broadcom Northstar USB 3.0 PHY Driver
|
* Broadcom Northstar USB 3.0 PHY Driver
|
||||||
*
|
*
|
||||||
* Copyright (C) 2016 Rafał Miłecki <rafal@milecki.pl>
|
* Copyright (C) 2016 Rafał Miłecki <rafal@milecki.pl>
|
||||||
|
* Copyright (C) 2016 Broadcom
|
||||||
*
|
*
|
||||||
* All magic values used for initialization (and related comments) were obtained
|
* All magic values used for initialization (and related comments) were obtained
|
||||||
* from Broadcom's SDK:
|
* from Broadcom's SDK:
|
||||||
@ -23,6 +24,23 @@
|
|||||||
|
|
||||||
#define BCM_NS_USB3_MII_MNG_TIMEOUT_US 1000 /* usecs */
|
#define BCM_NS_USB3_MII_MNG_TIMEOUT_US 1000 /* usecs */
|
||||||
|
|
||||||
|
#define BCM_NS_USB3_PHY_BASE_ADDR_REG 0x1f
|
||||||
|
#define BCM_NS_USB3_PHY_PLL30_BLOCK 0x8000
|
||||||
|
#define BCM_NS_USB3_PHY_TX_PMD_BLOCK 0x8040
|
||||||
|
#define BCM_NS_USB3_PHY_PIPE_BLOCK 0x8060
|
||||||
|
|
||||||
|
/* Registers of PLL30 block */
|
||||||
|
#define BCM_NS_USB3_PLL_CONTROL 0x01
|
||||||
|
#define BCM_NS_USB3_PLLA_CONTROL0 0x0a
|
||||||
|
#define BCM_NS_USB3_PLLA_CONTROL1 0x0b
|
||||||
|
|
||||||
|
/* Registers of TX PMD block */
|
||||||
|
#define BCM_NS_USB3_TX_PMD_CONTROL1 0x01
|
||||||
|
|
||||||
|
/* Registers of PIPE block */
|
||||||
|
#define BCM_NS_USB3_LFPS_CMP 0x02
|
||||||
|
#define BCM_NS_USB3_LFPS_DEGLITCH 0x03
|
||||||
|
|
||||||
enum bcm_ns_family {
|
enum bcm_ns_family {
|
||||||
BCM_NS_UNKNOWN,
|
BCM_NS_UNKNOWN,
|
||||||
BCM_NS_AX,
|
BCM_NS_AX,
|
||||||
@ -76,8 +94,10 @@ static inline int bcm_ns_usb3_mii_mng_wait_idle(struct bcm_ns_usb3 *usb3)
|
|||||||
usecs_to_jiffies(BCM_NS_USB3_MII_MNG_TIMEOUT_US));
|
usecs_to_jiffies(BCM_NS_USB3_MII_MNG_TIMEOUT_US));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int bcm_ns_usb3_mii_mng_write32(struct bcm_ns_usb3 *usb3, u32 value)
|
static int bcm_ns_usb3_mdio_phy_write(struct bcm_ns_usb3 *usb3, u16 reg,
|
||||||
|
u16 value)
|
||||||
{
|
{
|
||||||
|
u32 tmp = 0;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = bcm_ns_usb3_mii_mng_wait_idle(usb3);
|
err = bcm_ns_usb3_mii_mng_wait_idle(usb3);
|
||||||
@ -86,7 +106,11 @@ static int bcm_ns_usb3_mii_mng_write32(struct bcm_ns_usb3 *usb3, u32 value)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
writel(value, usb3->ccb_mii + BCMA_CCB_MII_MNG_CMD_DATA);
|
/* TODO: Use a proper MDIO bus layer */
|
||||||
|
tmp |= 0x58020000; /* Magic value for MDIO PHY write */
|
||||||
|
tmp |= reg << 18;
|
||||||
|
tmp |= value;
|
||||||
|
writel(tmp, usb3->ccb_mii + BCMA_CCB_MII_MNG_CMD_DATA);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -102,21 +126,22 @@ static int bcm_ns_usb3_phy_init_ns_bx(struct bcm_ns_usb3 *usb3)
|
|||||||
udelay(2);
|
udelay(2);
|
||||||
|
|
||||||
/* USB3 PLL Block */
|
/* USB3 PLL Block */
|
||||||
err = bcm_ns_usb3_mii_mng_write32(usb3, 0x587e8000);
|
err = bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PHY_BASE_ADDR_REG,
|
||||||
|
BCM_NS_USB3_PHY_PLL30_BLOCK);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
/* Assert Ana_Pllseq start */
|
/* Assert Ana_Pllseq start */
|
||||||
bcm_ns_usb3_mii_mng_write32(usb3, 0x58061000);
|
bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PLL_CONTROL, 0x1000);
|
||||||
|
|
||||||
/* Assert CML Divider ratio to 26 */
|
/* Assert CML Divider ratio to 26 */
|
||||||
bcm_ns_usb3_mii_mng_write32(usb3, 0x582a6400);
|
bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PLLA_CONTROL0, 0x6400);
|
||||||
|
|
||||||
/* Asserting PLL Reset */
|
/* Asserting PLL Reset */
|
||||||
bcm_ns_usb3_mii_mng_write32(usb3, 0x582ec000);
|
bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PLLA_CONTROL1, 0xc000);
|
||||||
|
|
||||||
/* Deaaserting PLL Reset */
|
/* Deaaserting PLL Reset */
|
||||||
bcm_ns_usb3_mii_mng_write32(usb3, 0x582e8000);
|
bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PLLA_CONTROL1, 0x8000);
|
||||||
|
|
||||||
/* Waiting MII Mgt interface idle */
|
/* Waiting MII Mgt interface idle */
|
||||||
bcm_ns_usb3_mii_mng_wait_idle(usb3);
|
bcm_ns_usb3_mii_mng_wait_idle(usb3);
|
||||||
@ -125,22 +150,24 @@ static int bcm_ns_usb3_phy_init_ns_bx(struct bcm_ns_usb3 *usb3)
|
|||||||
writel(0, usb3->dmp + BCMA_RESET_CTL);
|
writel(0, usb3->dmp + BCMA_RESET_CTL);
|
||||||
|
|
||||||
/* PLL frequency monitor enable */
|
/* PLL frequency monitor enable */
|
||||||
bcm_ns_usb3_mii_mng_write32(usb3, 0x58069000);
|
bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PLL_CONTROL, 0x9000);
|
||||||
|
|
||||||
/* PIPE Block */
|
/* PIPE Block */
|
||||||
bcm_ns_usb3_mii_mng_write32(usb3, 0x587e8060);
|
bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PHY_BASE_ADDR_REG,
|
||||||
|
BCM_NS_USB3_PHY_PIPE_BLOCK);
|
||||||
|
|
||||||
/* CMPMAX & CMPMINTH setting */
|
/* CMPMAX & CMPMINTH setting */
|
||||||
bcm_ns_usb3_mii_mng_write32(usb3, 0x580af30d);
|
bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_LFPS_CMP, 0xf30d);
|
||||||
|
|
||||||
/* DEGLITCH MIN & MAX setting */
|
/* DEGLITCH MIN & MAX setting */
|
||||||
bcm_ns_usb3_mii_mng_write32(usb3, 0x580e6302);
|
bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_LFPS_DEGLITCH, 0x6302);
|
||||||
|
|
||||||
/* TXPMD block */
|
/* TXPMD block */
|
||||||
bcm_ns_usb3_mii_mng_write32(usb3, 0x587e8040);
|
bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PHY_BASE_ADDR_REG,
|
||||||
|
BCM_NS_USB3_PHY_TX_PMD_BLOCK);
|
||||||
|
|
||||||
/* Enabling SSC */
|
/* Enabling SSC */
|
||||||
bcm_ns_usb3_mii_mng_write32(usb3, 0x58061003);
|
bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_TX_PMD_CONTROL1, 0x1003);
|
||||||
|
|
||||||
/* Waiting MII Mgt interface idle */
|
/* Waiting MII Mgt interface idle */
|
||||||
bcm_ns_usb3_mii_mng_wait_idle(usb3);
|
bcm_ns_usb3_mii_mng_wait_idle(usb3);
|
||||||
@ -159,22 +186,24 @@ static int bcm_ns_usb3_phy_init_ns_ax(struct bcm_ns_usb3 *usb3)
|
|||||||
udelay(2);
|
udelay(2);
|
||||||
|
|
||||||
/* PLL30 block */
|
/* PLL30 block */
|
||||||
err = bcm_ns_usb3_mii_mng_write32(usb3, 0x587e8000);
|
err = bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PHY_BASE_ADDR_REG,
|
||||||
|
BCM_NS_USB3_PHY_PLL30_BLOCK);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
bcm_ns_usb3_mii_mng_write32(usb3, 0x582a6400);
|
bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PLLA_CONTROL0, 0x6400);
|
||||||
|
|
||||||
bcm_ns_usb3_mii_mng_write32(usb3, 0x587e80e0);
|
bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PHY_BASE_ADDR_REG, 0x80e0);
|
||||||
|
|
||||||
bcm_ns_usb3_mii_mng_write32(usb3, 0x580a009c);
|
bcm_ns_usb3_mdio_phy_write(usb3, 0x02, 0x009c);
|
||||||
|
|
||||||
/* Enable SSC */
|
/* Enable SSC */
|
||||||
bcm_ns_usb3_mii_mng_write32(usb3, 0x587e8040);
|
bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PHY_BASE_ADDR_REG,
|
||||||
|
BCM_NS_USB3_PHY_TX_PMD_BLOCK);
|
||||||
|
|
||||||
bcm_ns_usb3_mii_mng_write32(usb3, 0x580a21d3);
|
bcm_ns_usb3_mdio_phy_write(usb3, 0x02, 0x21d3);
|
||||||
|
|
||||||
bcm_ns_usb3_mii_mng_write32(usb3, 0x58061003);
|
bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_TX_PMD_CONTROL1, 0x1003);
|
||||||
|
|
||||||
/* Waiting MII Mgt interface idle */
|
/* Waiting MII Mgt interface idle */
|
||||||
bcm_ns_usb3_mii_mng_wait_idle(usb3);
|
bcm_ns_usb3_mii_mng_wait_idle(usb3);
|
||||||
|
@ -14,12 +14,12 @@
|
|||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/mfd/syscon.h>
|
#include <linux/mfd/syscon.h>
|
||||||
#include <linux/mfd/syscon/exynos5-pmu.h>
|
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
#include <linux/phy/phy.h>
|
#include <linux/phy/phy.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
|
#include <linux/soc/samsung/exynos-regs-pmu.h>
|
||||||
|
|
||||||
struct exynos_dp_video_phy_drvdata {
|
struct exynos_dp_video_phy_drvdata {
|
||||||
u32 phy_ctrl_offset;
|
u32 phy_ctrl_offset;
|
||||||
@ -36,7 +36,7 @@ static int exynos_dp_video_phy_power_on(struct phy *phy)
|
|||||||
|
|
||||||
/* Disable power isolation on DP-PHY */
|
/* Disable power isolation on DP-PHY */
|
||||||
return regmap_update_bits(state->regs, state->drvdata->phy_ctrl_offset,
|
return regmap_update_bits(state->regs, state->drvdata->phy_ctrl_offset,
|
||||||
EXYNOS5_PHY_ENABLE, EXYNOS5_PHY_ENABLE);
|
EXYNOS4_PHY_ENABLE, EXYNOS4_PHY_ENABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int exynos_dp_video_phy_power_off(struct phy *phy)
|
static int exynos_dp_video_phy_power_off(struct phy *phy)
|
||||||
@ -45,7 +45,7 @@ static int exynos_dp_video_phy_power_off(struct phy *phy)
|
|||||||
|
|
||||||
/* Enable power isolation on DP-PHY */
|
/* Enable power isolation on DP-PHY */
|
||||||
return regmap_update_bits(state->regs, state->drvdata->phy_ctrl_offset,
|
return regmap_update_bits(state->regs, state->drvdata->phy_ctrl_offset,
|
||||||
EXYNOS5_PHY_ENABLE, 0);
|
EXYNOS4_PHY_ENABLE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct phy_ops exynos_dp_video_phy_ops = {
|
static const struct phy_ops exynos_dp_video_phy_ops = {
|
||||||
|
@ -12,8 +12,6 @@
|
|||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/mfd/syscon/exynos4-pmu.h>
|
|
||||||
#include <linux/mfd/syscon/exynos5-pmu.h>
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
@ -21,6 +19,7 @@
|
|||||||
#include <linux/phy/phy.h>
|
#include <linux/phy/phy.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/soc/samsung/exynos-regs-pmu.h>
|
||||||
#include <linux/mfd/syscon.h>
|
#include <linux/mfd/syscon.h>
|
||||||
|
|
||||||
enum exynos_mipi_phy_id {
|
enum exynos_mipi_phy_id {
|
||||||
@ -64,7 +63,7 @@ static const struct mipi_phy_device_desc s5pv210_mipi_phy = {
|
|||||||
{
|
{
|
||||||
/* EXYNOS_MIPI_PHY_ID_CSIS0 */
|
/* EXYNOS_MIPI_PHY_ID_CSIS0 */
|
||||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0,
|
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0,
|
||||||
.enable_val = EXYNOS4_MIPI_PHY_ENABLE,
|
.enable_val = EXYNOS4_PHY_ENABLE,
|
||||||
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(0),
|
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(0),
|
||||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||||
.resetn_val = EXYNOS4_MIPI_PHY_SRESETN,
|
.resetn_val = EXYNOS4_MIPI_PHY_SRESETN,
|
||||||
@ -73,7 +72,7 @@ static const struct mipi_phy_device_desc s5pv210_mipi_phy = {
|
|||||||
}, {
|
}, {
|
||||||
/* EXYNOS_MIPI_PHY_ID_DSIM0 */
|
/* EXYNOS_MIPI_PHY_ID_DSIM0 */
|
||||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0,
|
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0,
|
||||||
.enable_val = EXYNOS4_MIPI_PHY_ENABLE,
|
.enable_val = EXYNOS4_PHY_ENABLE,
|
||||||
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(0),
|
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(0),
|
||||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||||
.resetn_val = EXYNOS4_MIPI_PHY_MRESETN,
|
.resetn_val = EXYNOS4_MIPI_PHY_MRESETN,
|
||||||
@ -82,7 +81,7 @@ static const struct mipi_phy_device_desc s5pv210_mipi_phy = {
|
|||||||
}, {
|
}, {
|
||||||
/* EXYNOS_MIPI_PHY_ID_CSIS1 */
|
/* EXYNOS_MIPI_PHY_ID_CSIS1 */
|
||||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM1,
|
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM1,
|
||||||
.enable_val = EXYNOS4_MIPI_PHY_ENABLE,
|
.enable_val = EXYNOS4_PHY_ENABLE,
|
||||||
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(1),
|
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(1),
|
||||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||||
.resetn_val = EXYNOS4_MIPI_PHY_SRESETN,
|
.resetn_val = EXYNOS4_MIPI_PHY_SRESETN,
|
||||||
@ -91,7 +90,7 @@ static const struct mipi_phy_device_desc s5pv210_mipi_phy = {
|
|||||||
}, {
|
}, {
|
||||||
/* EXYNOS_MIPI_PHY_ID_DSIM1 */
|
/* EXYNOS_MIPI_PHY_ID_DSIM1 */
|
||||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS1,
|
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS1,
|
||||||
.enable_val = EXYNOS4_MIPI_PHY_ENABLE,
|
.enable_val = EXYNOS4_PHY_ENABLE,
|
||||||
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(1),
|
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(1),
|
||||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||||
.resetn_val = EXYNOS4_MIPI_PHY_MRESETN,
|
.resetn_val = EXYNOS4_MIPI_PHY_MRESETN,
|
||||||
@ -109,47 +108,47 @@ static const struct mipi_phy_device_desc exynos5420_mipi_phy = {
|
|||||||
{
|
{
|
||||||
/* EXYNOS_MIPI_PHY_ID_CSIS0 */
|
/* EXYNOS_MIPI_PHY_ID_CSIS0 */
|
||||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0,
|
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0,
|
||||||
.enable_val = EXYNOS5_PHY_ENABLE,
|
.enable_val = EXYNOS4_PHY_ENABLE,
|
||||||
.enable_reg = EXYNOS5420_MIPI_PHY0_CONTROL,
|
.enable_reg = EXYNOS5420_MIPI_PHY_CONTROL(0),
|
||||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||||
.resetn_val = EXYNOS5_MIPI_PHY_S_RESETN,
|
.resetn_val = EXYNOS4_MIPI_PHY_SRESETN,
|
||||||
.resetn_reg = EXYNOS5420_MIPI_PHY0_CONTROL,
|
.resetn_reg = EXYNOS5420_MIPI_PHY_CONTROL(0),
|
||||||
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
|
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||||
}, {
|
}, {
|
||||||
/* EXYNOS_MIPI_PHY_ID_DSIM0 */
|
/* EXYNOS_MIPI_PHY_ID_DSIM0 */
|
||||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0,
|
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0,
|
||||||
.enable_val = EXYNOS5_PHY_ENABLE,
|
.enable_val = EXYNOS4_PHY_ENABLE,
|
||||||
.enable_reg = EXYNOS5420_MIPI_PHY0_CONTROL,
|
.enable_reg = EXYNOS5420_MIPI_PHY_CONTROL(0),
|
||||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||||
.resetn_val = EXYNOS5_MIPI_PHY_M_RESETN,
|
.resetn_val = EXYNOS4_MIPI_PHY_MRESETN,
|
||||||
.resetn_reg = EXYNOS5420_MIPI_PHY0_CONTROL,
|
.resetn_reg = EXYNOS5420_MIPI_PHY_CONTROL(0),
|
||||||
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
|
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||||
}, {
|
}, {
|
||||||
/* EXYNOS_MIPI_PHY_ID_CSIS1 */
|
/* EXYNOS_MIPI_PHY_ID_CSIS1 */
|
||||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM1,
|
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM1,
|
||||||
.enable_val = EXYNOS5_PHY_ENABLE,
|
.enable_val = EXYNOS4_PHY_ENABLE,
|
||||||
.enable_reg = EXYNOS5420_MIPI_PHY1_CONTROL,
|
.enable_reg = EXYNOS5420_MIPI_PHY_CONTROL(1),
|
||||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||||
.resetn_val = EXYNOS5_MIPI_PHY_S_RESETN,
|
.resetn_val = EXYNOS4_MIPI_PHY_SRESETN,
|
||||||
.resetn_reg = EXYNOS5420_MIPI_PHY1_CONTROL,
|
.resetn_reg = EXYNOS5420_MIPI_PHY_CONTROL(1),
|
||||||
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
|
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||||
}, {
|
}, {
|
||||||
/* EXYNOS_MIPI_PHY_ID_DSIM1 */
|
/* EXYNOS_MIPI_PHY_ID_DSIM1 */
|
||||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS1,
|
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS1,
|
||||||
.enable_val = EXYNOS5_PHY_ENABLE,
|
.enable_val = EXYNOS4_PHY_ENABLE,
|
||||||
.enable_reg = EXYNOS5420_MIPI_PHY1_CONTROL,
|
.enable_reg = EXYNOS5420_MIPI_PHY_CONTROL(1),
|
||||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||||
.resetn_val = EXYNOS5_MIPI_PHY_M_RESETN,
|
.resetn_val = EXYNOS4_MIPI_PHY_MRESETN,
|
||||||
.resetn_reg = EXYNOS5420_MIPI_PHY1_CONTROL,
|
.resetn_reg = EXYNOS5420_MIPI_PHY_CONTROL(1),
|
||||||
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
|
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||||
}, {
|
}, {
|
||||||
/* EXYNOS_MIPI_PHY_ID_CSIS2 */
|
/* EXYNOS_MIPI_PHY_ID_CSIS2 */
|
||||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,
|
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,
|
||||||
.enable_val = EXYNOS5_PHY_ENABLE,
|
.enable_val = EXYNOS4_PHY_ENABLE,
|
||||||
.enable_reg = EXYNOS5420_MIPI_PHY2_CONTROL,
|
.enable_reg = EXYNOS5420_MIPI_PHY_CONTROL(2),
|
||||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||||
.resetn_val = EXYNOS5_MIPI_PHY_S_RESETN,
|
.resetn_val = EXYNOS4_MIPI_PHY_SRESETN,
|
||||||
.resetn_reg = EXYNOS5420_MIPI_PHY2_CONTROL,
|
.resetn_reg = EXYNOS5420_MIPI_PHY_CONTROL(2),
|
||||||
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
|
.resetn_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -172,8 +171,8 @@ static const struct mipi_phy_device_desc exynos5433_mipi_phy = {
|
|||||||
{
|
{
|
||||||
/* EXYNOS_MIPI_PHY_ID_CSIS0 */
|
/* EXYNOS_MIPI_PHY_ID_CSIS0 */
|
||||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0,
|
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_DSIM0,
|
||||||
.enable_val = EXYNOS5_PHY_ENABLE,
|
.enable_val = EXYNOS4_PHY_ENABLE,
|
||||||
.enable_reg = EXYNOS5433_MIPI_PHY0_CONTROL,
|
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(0),
|
||||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||||
.resetn_val = BIT(0),
|
.resetn_val = BIT(0),
|
||||||
.resetn_reg = EXYNOS5433_SYSREG_CAM0_MIPI_DPHY_CON,
|
.resetn_reg = EXYNOS5433_SYSREG_CAM0_MIPI_DPHY_CON,
|
||||||
@ -181,8 +180,8 @@ static const struct mipi_phy_device_desc exynos5433_mipi_phy = {
|
|||||||
}, {
|
}, {
|
||||||
/* EXYNOS_MIPI_PHY_ID_DSIM0 */
|
/* EXYNOS_MIPI_PHY_ID_DSIM0 */
|
||||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0,
|
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_CSIS0,
|
||||||
.enable_val = EXYNOS5_PHY_ENABLE,
|
.enable_val = EXYNOS4_PHY_ENABLE,
|
||||||
.enable_reg = EXYNOS5433_MIPI_PHY0_CONTROL,
|
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(0),
|
||||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||||
.resetn_val = BIT(0),
|
.resetn_val = BIT(0),
|
||||||
.resetn_reg = EXYNOS5433_SYSREG_DISP_MIPI_PHY,
|
.resetn_reg = EXYNOS5433_SYSREG_DISP_MIPI_PHY,
|
||||||
@ -190,8 +189,8 @@ static const struct mipi_phy_device_desc exynos5433_mipi_phy = {
|
|||||||
}, {
|
}, {
|
||||||
/* EXYNOS_MIPI_PHY_ID_CSIS1 */
|
/* EXYNOS_MIPI_PHY_ID_CSIS1 */
|
||||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,
|
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,
|
||||||
.enable_val = EXYNOS5_PHY_ENABLE,
|
.enable_val = EXYNOS4_PHY_ENABLE,
|
||||||
.enable_reg = EXYNOS5433_MIPI_PHY1_CONTROL,
|
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(1),
|
||||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||||
.resetn_val = BIT(1),
|
.resetn_val = BIT(1),
|
||||||
.resetn_reg = EXYNOS5433_SYSREG_CAM0_MIPI_DPHY_CON,
|
.resetn_reg = EXYNOS5433_SYSREG_CAM0_MIPI_DPHY_CON,
|
||||||
@ -199,8 +198,8 @@ static const struct mipi_phy_device_desc exynos5433_mipi_phy = {
|
|||||||
}, {
|
}, {
|
||||||
/* EXYNOS_MIPI_PHY_ID_DSIM1 */
|
/* EXYNOS_MIPI_PHY_ID_DSIM1 */
|
||||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,
|
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,
|
||||||
.enable_val = EXYNOS5_PHY_ENABLE,
|
.enable_val = EXYNOS4_PHY_ENABLE,
|
||||||
.enable_reg = EXYNOS5433_MIPI_PHY1_CONTROL,
|
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(1),
|
||||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||||
.resetn_val = BIT(1),
|
.resetn_val = BIT(1),
|
||||||
.resetn_reg = EXYNOS5433_SYSREG_DISP_MIPI_PHY,
|
.resetn_reg = EXYNOS5433_SYSREG_DISP_MIPI_PHY,
|
||||||
@ -208,8 +207,8 @@ static const struct mipi_phy_device_desc exynos5433_mipi_phy = {
|
|||||||
}, {
|
}, {
|
||||||
/* EXYNOS_MIPI_PHY_ID_CSIS2 */
|
/* EXYNOS_MIPI_PHY_ID_CSIS2 */
|
||||||
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,
|
.coupled_phy_id = EXYNOS_MIPI_PHY_ID_NONE,
|
||||||
.enable_val = EXYNOS5_PHY_ENABLE,
|
.enable_val = EXYNOS4_PHY_ENABLE,
|
||||||
.enable_reg = EXYNOS5433_MIPI_PHY2_CONTROL,
|
.enable_reg = EXYNOS4_MIPI_PHY_CONTROL(2),
|
||||||
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
.enable_map = EXYNOS_MIPI_REGMAP_PMU,
|
||||||
.resetn_val = BIT(0),
|
.resetn_val = BIT(0),
|
||||||
.resetn_reg = EXYNOS5433_SYSREG_CAM1_MIPI_DPHY_CON,
|
.resetn_reg = EXYNOS5433_SYSREG_CAM1_MIPI_DPHY_CON,
|
||||||
|
@ -14,8 +14,8 @@
|
|||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/iopoll.h>
|
#include <linux/iopoll.h>
|
||||||
|
#include <linux/init.h>
|
||||||
#include <linux/mfd/syscon.h>
|
#include <linux/mfd/syscon.h>
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
#include <linux/of_platform.h>
|
#include <linux/of_platform.h>
|
||||||
@ -228,7 +228,6 @@ static const struct of_device_id exynos_pcie_phy_match[] = {
|
|||||||
},
|
},
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, exynos_pcie_phy_match);
|
|
||||||
|
|
||||||
static int exynos_pcie_phy_probe(struct platform_device *pdev)
|
static int exynos_pcie_phy_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
@ -278,8 +277,5 @@ static struct platform_driver exynos_pcie_phy_driver = {
|
|||||||
.name = "exynos_pcie_phy",
|
.name = "exynos_pcie_phy",
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
module_platform_driver(exynos_pcie_phy_driver);
|
|
||||||
|
|
||||||
MODULE_DESCRIPTION("Samsung S5P/EXYNOS SoC PCIe PHY driver");
|
builtin_platform_driver(exynos_pcie_phy_driver);
|
||||||
MODULE_AUTHOR("Jaehoon Chung <jh80.chung@samsung.com>");
|
|
||||||
MODULE_LICENSE("GPL v2");
|
|
||||||
|
@ -22,9 +22,9 @@
|
|||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/mfd/syscon.h>
|
#include <linux/mfd/syscon.h>
|
||||||
#include <linux/mfd/syscon/exynos5-pmu.h>
|
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
|
#include <linux/soc/samsung/exynos-regs-pmu.h>
|
||||||
|
|
||||||
/* Exynos USB PHY registers */
|
/* Exynos USB PHY registers */
|
||||||
#define EXYNOS5_FSEL_9MHZ6 0x0
|
#define EXYNOS5_FSEL_9MHZ6 0x0
|
||||||
@ -235,10 +235,10 @@ static void exynos5_usbdrd_phy_isol(struct phy_usb_instance *inst,
|
|||||||
if (!inst->reg_pmu)
|
if (!inst->reg_pmu)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
val = on ? 0 : EXYNOS5_PHY_ENABLE;
|
val = on ? 0 : EXYNOS4_PHY_ENABLE;
|
||||||
|
|
||||||
regmap_update_bits(inst->reg_pmu, inst->pmu_offset,
|
regmap_update_bits(inst->reg_pmu, inst->pmu_offset,
|
||||||
EXYNOS5_PHY_ENABLE, val);
|
EXYNOS4_PHY_ENABLE, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -81,9 +81,9 @@
|
|||||||
#define REG_ADP_BC_ACA_PIN_GND BIT(25)
|
#define REG_ADP_BC_ACA_PIN_GND BIT(25)
|
||||||
#define REG_ADP_BC_ACA_PIN_FLOAT BIT(26)
|
#define REG_ADP_BC_ACA_PIN_FLOAT BIT(26)
|
||||||
|
|
||||||
#define REG_DBG_UART 0x14
|
#define REG_DBG_UART 0x10
|
||||||
|
|
||||||
#define REG_TEST 0x18
|
#define REG_TEST 0x14
|
||||||
#define REG_TEST_DATA_IN_MASK GENMASK(3, 0)
|
#define REG_TEST_DATA_IN_MASK GENMASK(3, 0)
|
||||||
#define REG_TEST_EN_MASK GENMASK(7, 4)
|
#define REG_TEST_EN_MASK GENMASK(7, 4)
|
||||||
#define REG_TEST_ADDR_MASK GENMASK(11, 8)
|
#define REG_TEST_ADDR_MASK GENMASK(11, 8)
|
||||||
@ -93,7 +93,7 @@
|
|||||||
#define REG_TEST_DATA_OUT_MASK GENMASK(19, 16)
|
#define REG_TEST_DATA_OUT_MASK GENMASK(19, 16)
|
||||||
#define REG_TEST_DISABLE_ID_PULLUP BIT(20)
|
#define REG_TEST_DISABLE_ID_PULLUP BIT(20)
|
||||||
|
|
||||||
#define REG_TUNE 0x1c
|
#define REG_TUNE 0x18
|
||||||
#define REG_TUNE_TX_RES_TUNE_MASK GENMASK(1, 0)
|
#define REG_TUNE_TX_RES_TUNE_MASK GENMASK(1, 0)
|
||||||
#define REG_TUNE_TX_HSXV_TUNE_MASK GENMASK(3, 2)
|
#define REG_TUNE_TX_HSXV_TUNE_MASK GENMASK(3, 2)
|
||||||
#define REG_TUNE_TX_VREF_TUNE_MASK GENMASK(7, 4)
|
#define REG_TUNE_TX_VREF_TUNE_MASK GENMASK(7, 4)
|
||||||
|
@ -23,47 +23,55 @@
|
|||||||
#include <linux/phy/phy.h>
|
#include <linux/phy/phy.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
|
||||||
/*
|
/* version V1 sub-banks offset base address */
|
||||||
* for sifslv2 register, but exclude port's;
|
/* banks shared by multiple phys */
|
||||||
* relative to USB3_SIF2_BASE base address
|
#define SSUSB_SIFSLV_V1_SPLLC 0x000 /* shared by u3 phys */
|
||||||
*/
|
#define SSUSB_SIFSLV_V1_U2FREQ 0x100 /* shared by u2 phys */
|
||||||
#define SSUSB_SIFSLV_SPLLC 0x0000
|
/* u2 phy bank */
|
||||||
#define SSUSB_SIFSLV_U2FREQ 0x0100
|
#define SSUSB_SIFSLV_V1_U2PHY_COM 0x000
|
||||||
|
/* u3 phy banks */
|
||||||
|
#define SSUSB_SIFSLV_V1_U3PHYD 0x000
|
||||||
|
#define SSUSB_SIFSLV_V1_U3PHYA 0x200
|
||||||
|
|
||||||
/* offsets of sub-segment in each port registers */
|
/* version V2 sub-banks offset base address */
|
||||||
#define SSUSB_SIFSLV_U2PHY_COM_BASE 0x0000
|
/* u2 phy banks */
|
||||||
#define SSUSB_SIFSLV_U3PHYD_BASE 0x0100
|
#define SSUSB_SIFSLV_V2_MISC 0x000
|
||||||
#define SSUSB_USB30_PHYA_SIV_B_BASE 0x0300
|
#define SSUSB_SIFSLV_V2_U2FREQ 0x100
|
||||||
#define SSUSB_SIFSLV_U3PHYA_DA_BASE 0x0400
|
#define SSUSB_SIFSLV_V2_U2PHY_COM 0x300
|
||||||
|
/* u3 phy banks */
|
||||||
|
#define SSUSB_SIFSLV_V2_SPLLC 0x000
|
||||||
|
#define SSUSB_SIFSLV_V2_CHIP 0x100
|
||||||
|
#define SSUSB_SIFSLV_V2_U3PHYD 0x200
|
||||||
|
#define SSUSB_SIFSLV_V2_U3PHYA 0x400
|
||||||
|
|
||||||
#define U3P_USBPHYACR0 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0000)
|
#define U3P_USBPHYACR0 0x000
|
||||||
#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 U3P_USBPHYACR2 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0008)
|
#define U3P_USBPHYACR2 0x008
|
||||||
#define PA2_RG_SIF_U2PLL_FORCE_EN BIT(18)
|
#define PA2_RG_SIF_U2PLL_FORCE_EN BIT(18)
|
||||||
|
|
||||||
#define U3P_USBPHYACR5 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0014)
|
#define U3P_USBPHYACR5 0x014
|
||||||
#define PA5_RG_U2_HSTX_SRCAL_EN BIT(15)
|
#define PA5_RG_U2_HSTX_SRCAL_EN BIT(15)
|
||||||
#define PA5_RG_U2_HSTX_SRCTRL GENMASK(14, 12)
|
#define PA5_RG_U2_HSTX_SRCTRL GENMASK(14, 12)
|
||||||
#define PA5_RG_U2_HSTX_SRCTRL_VAL(x) ((0x7 & (x)) << 12)
|
#define PA5_RG_U2_HSTX_SRCTRL_VAL(x) ((0x7 & (x)) << 12)
|
||||||
#define PA5_RG_U2_HS_100U_U3_EN BIT(11)
|
#define PA5_RG_U2_HS_100U_U3_EN BIT(11)
|
||||||
|
|
||||||
#define U3P_USBPHYACR6 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0018)
|
#define U3P_USBPHYACR6 0x018
|
||||||
#define PA6_RG_U2_ISO_EN BIT(31)
|
|
||||||
#define PA6_RG_U2_BC11_SW_EN BIT(23)
|
#define PA6_RG_U2_BC11_SW_EN BIT(23)
|
||||||
#define PA6_RG_U2_OTG_VBUSCMP_EN BIT(20)
|
#define PA6_RG_U2_OTG_VBUSCMP_EN BIT(20)
|
||||||
#define PA6_RG_U2_SQTH GENMASK(3, 0)
|
#define PA6_RG_U2_SQTH GENMASK(3, 0)
|
||||||
#define PA6_RG_U2_SQTH_VAL(x) (0xf & (x))
|
#define PA6_RG_U2_SQTH_VAL(x) (0xf & (x))
|
||||||
|
|
||||||
#define U3P_U2PHYACR4 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0020)
|
#define U3P_U2PHYACR4 0x020
|
||||||
#define P2C_RG_USB20_GPIO_CTL BIT(9)
|
#define P2C_RG_USB20_GPIO_CTL BIT(9)
|
||||||
#define P2C_USB20_GPIO_MODE BIT(8)
|
#define P2C_USB20_GPIO_MODE BIT(8)
|
||||||
#define P2C_U2_GPIO_CTR_MSK (P2C_RG_USB20_GPIO_CTL | P2C_USB20_GPIO_MODE)
|
#define P2C_U2_GPIO_CTR_MSK (P2C_RG_USB20_GPIO_CTL | P2C_USB20_GPIO_MODE)
|
||||||
|
|
||||||
#define U3D_U2PHYDCR0 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0060)
|
#define U3D_U2PHYDCR0 0x060
|
||||||
#define P2C_RG_SIF_U2PLL_FORCE_ON BIT(24)
|
#define P2C_RG_SIF_U2PLL_FORCE_ON BIT(24)
|
||||||
|
|
||||||
#define U3P_U2PHYDTM0 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x0068)
|
#define U3P_U2PHYDTM0 0x068
|
||||||
#define P2C_FORCE_UART_EN BIT(26)
|
#define P2C_FORCE_UART_EN BIT(26)
|
||||||
#define P2C_FORCE_DATAIN BIT(23)
|
#define P2C_FORCE_DATAIN BIT(23)
|
||||||
#define P2C_FORCE_DM_PULLDOWN BIT(21)
|
#define P2C_FORCE_DM_PULLDOWN BIT(21)
|
||||||
@ -85,47 +93,56 @@
|
|||||||
P2C_FORCE_TERMSEL | P2C_RG_DMPULLDOWN | \
|
P2C_FORCE_TERMSEL | P2C_RG_DMPULLDOWN | \
|
||||||
P2C_RG_DPPULLDOWN | P2C_RG_TERMSEL)
|
P2C_RG_DPPULLDOWN | P2C_RG_TERMSEL)
|
||||||
|
|
||||||
#define U3P_U2PHYDTM1 (SSUSB_SIFSLV_U2PHY_COM_BASE + 0x006C)
|
#define U3P_U2PHYDTM1 0x06C
|
||||||
#define P2C_RG_UART_EN BIT(16)
|
#define P2C_RG_UART_EN BIT(16)
|
||||||
#define P2C_RG_VBUSVALID BIT(5)
|
#define P2C_RG_VBUSVALID BIT(5)
|
||||||
#define P2C_RG_SESSEND BIT(4)
|
#define P2C_RG_SESSEND BIT(4)
|
||||||
#define P2C_RG_AVALID BIT(2)
|
#define P2C_RG_AVALID BIT(2)
|
||||||
|
|
||||||
#define U3P_U3_PHYA_REG0 (SSUSB_USB30_PHYA_SIV_B_BASE + 0x0000)
|
#define U3P_U3_PHYA_REG6 0x018
|
||||||
#define P3A_RG_U3_VUSB10_ON BIT(5)
|
|
||||||
|
|
||||||
#define U3P_U3_PHYA_REG6 (SSUSB_USB30_PHYA_SIV_B_BASE + 0x0018)
|
|
||||||
#define P3A_RG_TX_EIDLE_CM GENMASK(31, 28)
|
#define P3A_RG_TX_EIDLE_CM GENMASK(31, 28)
|
||||||
#define P3A_RG_TX_EIDLE_CM_VAL(x) ((0xf & (x)) << 28)
|
#define P3A_RG_TX_EIDLE_CM_VAL(x) ((0xf & (x)) << 28)
|
||||||
|
|
||||||
#define U3P_U3_PHYA_REG9 (SSUSB_USB30_PHYA_SIV_B_BASE + 0x0024)
|
#define U3P_U3_PHYA_REG9 0x024
|
||||||
#define P3A_RG_RX_DAC_MUX GENMASK(5, 1)
|
#define P3A_RG_RX_DAC_MUX GENMASK(5, 1)
|
||||||
#define P3A_RG_RX_DAC_MUX_VAL(x) ((0x1f & (x)) << 1)
|
#define P3A_RG_RX_DAC_MUX_VAL(x) ((0x1f & (x)) << 1)
|
||||||
|
|
||||||
#define U3P_U3PHYA_DA_REG0 (SSUSB_SIFSLV_U3PHYA_DA_BASE + 0x0000)
|
#define U3P_U3_PHYA_DA_REG0 0x100
|
||||||
#define P3A_RG_XTAL_EXT_EN_U3 GENMASK(11, 10)
|
#define P3A_RG_XTAL_EXT_EN_U3 GENMASK(11, 10)
|
||||||
#define P3A_RG_XTAL_EXT_EN_U3_VAL(x) ((0x3 & (x)) << 10)
|
#define P3A_RG_XTAL_EXT_EN_U3_VAL(x) ((0x3 & (x)) << 10)
|
||||||
|
|
||||||
#define U3P_PHYD_CDR1 (SSUSB_SIFSLV_U3PHYD_BASE + 0x005c)
|
#define U3P_U3_PHYD_LFPS1 0x00c
|
||||||
|
#define P3D_RG_FWAKE_TH GENMASK(21, 16)
|
||||||
|
#define P3D_RG_FWAKE_TH_VAL(x) ((0x3f & (x)) << 16)
|
||||||
|
|
||||||
|
#define U3P_U3_PHYD_CDR1 0x05c
|
||||||
#define P3D_RG_CDR_BIR_LTD1 GENMASK(28, 24)
|
#define P3D_RG_CDR_BIR_LTD1 GENMASK(28, 24)
|
||||||
#define P3D_RG_CDR_BIR_LTD1_VAL(x) ((0x1f & (x)) << 24)
|
#define P3D_RG_CDR_BIR_LTD1_VAL(x) ((0x1f & (x)) << 24)
|
||||||
#define P3D_RG_CDR_BIR_LTD0 GENMASK(12, 8)
|
#define P3D_RG_CDR_BIR_LTD0 GENMASK(12, 8)
|
||||||
#define P3D_RG_CDR_BIR_LTD0_VAL(x) ((0x1f & (x)) << 8)
|
#define P3D_RG_CDR_BIR_LTD0_VAL(x) ((0x1f & (x)) << 8)
|
||||||
|
|
||||||
#define U3P_XTALCTL3 (SSUSB_SIFSLV_SPLLC + 0x0018)
|
#define U3P_U3_PHYD_RXDET1 0x128
|
||||||
|
#define P3D_RG_RXDET_STB2_SET GENMASK(17, 9)
|
||||||
|
#define P3D_RG_RXDET_STB2_SET_VAL(x) ((0x1ff & (x)) << 9)
|
||||||
|
|
||||||
|
#define U3P_U3_PHYD_RXDET2 0x12c
|
||||||
|
#define P3D_RG_RXDET_STB2_SET_P3 GENMASK(8, 0)
|
||||||
|
#define P3D_RG_RXDET_STB2_SET_P3_VAL(x) (0x1ff & (x))
|
||||||
|
|
||||||
|
#define U3P_SPLLC_XTALCTL3 0x018
|
||||||
#define XC3_RG_U3_XTAL_RX_PWD BIT(9)
|
#define XC3_RG_U3_XTAL_RX_PWD BIT(9)
|
||||||
#define XC3_RG_U3_FRC_XTAL_RX_PWD BIT(8)
|
#define XC3_RG_U3_FRC_XTAL_RX_PWD BIT(8)
|
||||||
|
|
||||||
#define U3P_U2FREQ_FMCR0 (SSUSB_SIFSLV_U2FREQ + 0x00)
|
#define U3P_U2FREQ_FMCR0 0x00
|
||||||
#define P2F_RG_MONCLK_SEL GENMASK(27, 26)
|
#define P2F_RG_MONCLK_SEL GENMASK(27, 26)
|
||||||
#define P2F_RG_MONCLK_SEL_VAL(x) ((0x3 & (x)) << 26)
|
#define P2F_RG_MONCLK_SEL_VAL(x) ((0x3 & (x)) << 26)
|
||||||
#define P2F_RG_FREQDET_EN BIT(24)
|
#define P2F_RG_FREQDET_EN BIT(24)
|
||||||
#define P2F_RG_CYCLECNT GENMASK(23, 0)
|
#define P2F_RG_CYCLECNT GENMASK(23, 0)
|
||||||
#define P2F_RG_CYCLECNT_VAL(x) ((P2F_RG_CYCLECNT) & (x))
|
#define P2F_RG_CYCLECNT_VAL(x) ((P2F_RG_CYCLECNT) & (x))
|
||||||
|
|
||||||
#define U3P_U2FREQ_VALUE (SSUSB_SIFSLV_U2FREQ + 0x0c)
|
#define U3P_U2FREQ_VALUE 0x0c
|
||||||
|
|
||||||
#define U3P_U2FREQ_FMMONR1 (SSUSB_SIFSLV_U2FREQ + 0x10)
|
#define U3P_U2FREQ_FMMONR1 0x10
|
||||||
#define P2F_USB_FM_VALID BIT(0)
|
#define P2F_USB_FM_VALID BIT(0)
|
||||||
#define P2F_RG_FRCK_EN BIT(8)
|
#define P2F_RG_FRCK_EN BIT(8)
|
||||||
|
|
||||||
@ -134,21 +151,46 @@
|
|||||||
#define U3P_SR_COEF_DIVISOR 1000
|
#define U3P_SR_COEF_DIVISOR 1000
|
||||||
#define U3P_FM_DET_CYCLE_CNT 1024
|
#define U3P_FM_DET_CYCLE_CNT 1024
|
||||||
|
|
||||||
|
enum mt_phy_version {
|
||||||
|
MT_PHY_V1 = 1,
|
||||||
|
MT_PHY_V2,
|
||||||
|
};
|
||||||
|
|
||||||
struct mt65xx_phy_pdata {
|
struct mt65xx_phy_pdata {
|
||||||
/* avoid RX sensitivity level degradation only for mt8173 */
|
/* avoid RX sensitivity level degradation only for mt8173 */
|
||||||
bool avoid_rx_sen_degradation;
|
bool avoid_rx_sen_degradation;
|
||||||
|
enum mt_phy_version version;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct u2phy_banks {
|
||||||
|
void __iomem *misc;
|
||||||
|
void __iomem *fmreg;
|
||||||
|
void __iomem *com;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct u3phy_banks {
|
||||||
|
void __iomem *spllc;
|
||||||
|
void __iomem *chip;
|
||||||
|
void __iomem *phyd; /* include u3phyd_bank2 */
|
||||||
|
void __iomem *phya; /* include u3phya_da */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mt65xx_phy_instance {
|
struct mt65xx_phy_instance {
|
||||||
struct phy *phy;
|
struct phy *phy;
|
||||||
void __iomem *port_base;
|
void __iomem *port_base;
|
||||||
|
union {
|
||||||
|
struct u2phy_banks u2_banks;
|
||||||
|
struct u3phy_banks u3_banks;
|
||||||
|
};
|
||||||
|
struct clk *ref_clk; /* reference clock of anolog phy */
|
||||||
u32 index;
|
u32 index;
|
||||||
u8 type;
|
u8 type;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mt65xx_u3phy {
|
struct mt65xx_u3phy {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
void __iomem *sif_base; /* include sif2, but exclude port's */
|
void __iomem *sif_base; /* only shared sif */
|
||||||
|
/* deprecated, use @ref_clk instead in phy instance */
|
||||||
struct clk *u3phya_ref; /* reference clock of usb3 anolog phy */
|
struct clk *u3phya_ref; /* reference clock of usb3 anolog phy */
|
||||||
const struct mt65xx_phy_pdata *pdata;
|
const struct mt65xx_phy_pdata *pdata;
|
||||||
struct mt65xx_phy_instance **phys;
|
struct mt65xx_phy_instance **phys;
|
||||||
@ -158,49 +200,53 @@ struct mt65xx_u3phy {
|
|||||||
static void hs_slew_rate_calibrate(struct mt65xx_u3phy *u3phy,
|
static void hs_slew_rate_calibrate(struct mt65xx_u3phy *u3phy,
|
||||||
struct mt65xx_phy_instance *instance)
|
struct mt65xx_phy_instance *instance)
|
||||||
{
|
{
|
||||||
void __iomem *sif_base = u3phy->sif_base;
|
struct u2phy_banks *u2_banks = &instance->u2_banks;
|
||||||
|
void __iomem *fmreg = u2_banks->fmreg;
|
||||||
|
void __iomem *com = u2_banks->com;
|
||||||
int calibration_val;
|
int calibration_val;
|
||||||
int fm_out;
|
int fm_out;
|
||||||
u32 tmp;
|
u32 tmp;
|
||||||
|
|
||||||
/* enable USB ring oscillator */
|
/* enable USB ring oscillator */
|
||||||
tmp = readl(instance->port_base + U3P_USBPHYACR5);
|
tmp = readl(com + U3P_USBPHYACR5);
|
||||||
tmp |= PA5_RG_U2_HSTX_SRCAL_EN;
|
tmp |= PA5_RG_U2_HSTX_SRCAL_EN;
|
||||||
writel(tmp, instance->port_base + U3P_USBPHYACR5);
|
writel(tmp, com + U3P_USBPHYACR5);
|
||||||
udelay(1);
|
udelay(1);
|
||||||
|
|
||||||
/*enable free run clock */
|
/*enable free run clock */
|
||||||
tmp = readl(sif_base + U3P_U2FREQ_FMMONR1);
|
tmp = readl(fmreg + U3P_U2FREQ_FMMONR1);
|
||||||
tmp |= P2F_RG_FRCK_EN;
|
tmp |= P2F_RG_FRCK_EN;
|
||||||
writel(tmp, sif_base + U3P_U2FREQ_FMMONR1);
|
writel(tmp, fmreg + U3P_U2FREQ_FMMONR1);
|
||||||
|
|
||||||
/* set cycle count as 1024, and select u2 channel */
|
/* set cycle count as 1024, and select u2 channel */
|
||||||
tmp = readl(sif_base + U3P_U2FREQ_FMCR0);
|
tmp = readl(fmreg + U3P_U2FREQ_FMCR0);
|
||||||
tmp &= ~(P2F_RG_CYCLECNT | P2F_RG_MONCLK_SEL);
|
tmp &= ~(P2F_RG_CYCLECNT | P2F_RG_MONCLK_SEL);
|
||||||
tmp |= P2F_RG_CYCLECNT_VAL(U3P_FM_DET_CYCLE_CNT);
|
tmp |= P2F_RG_CYCLECNT_VAL(U3P_FM_DET_CYCLE_CNT);
|
||||||
tmp |= P2F_RG_MONCLK_SEL_VAL(instance->index);
|
if (u3phy->pdata->version == MT_PHY_V1)
|
||||||
writel(tmp, sif_base + U3P_U2FREQ_FMCR0);
|
tmp |= P2F_RG_MONCLK_SEL_VAL(instance->index >> 1);
|
||||||
|
|
||||||
|
writel(tmp, fmreg + U3P_U2FREQ_FMCR0);
|
||||||
|
|
||||||
/* enable frequency meter */
|
/* enable frequency meter */
|
||||||
tmp = readl(sif_base + U3P_U2FREQ_FMCR0);
|
tmp = readl(fmreg + U3P_U2FREQ_FMCR0);
|
||||||
tmp |= P2F_RG_FREQDET_EN;
|
tmp |= P2F_RG_FREQDET_EN;
|
||||||
writel(tmp, sif_base + U3P_U2FREQ_FMCR0);
|
writel(tmp, fmreg + U3P_U2FREQ_FMCR0);
|
||||||
|
|
||||||
/* ignore return value */
|
/* ignore return value */
|
||||||
readl_poll_timeout(sif_base + U3P_U2FREQ_FMMONR1, tmp,
|
readl_poll_timeout(fmreg + U3P_U2FREQ_FMMONR1, tmp,
|
||||||
(tmp & P2F_USB_FM_VALID), 10, 200);
|
(tmp & P2F_USB_FM_VALID), 10, 200);
|
||||||
|
|
||||||
fm_out = readl(sif_base + U3P_U2FREQ_VALUE);
|
fm_out = readl(fmreg + U3P_U2FREQ_VALUE);
|
||||||
|
|
||||||
/* disable frequency meter */
|
/* disable frequency meter */
|
||||||
tmp = readl(sif_base + U3P_U2FREQ_FMCR0);
|
tmp = readl(fmreg + U3P_U2FREQ_FMCR0);
|
||||||
tmp &= ~P2F_RG_FREQDET_EN;
|
tmp &= ~P2F_RG_FREQDET_EN;
|
||||||
writel(tmp, sif_base + U3P_U2FREQ_FMCR0);
|
writel(tmp, fmreg + U3P_U2FREQ_FMCR0);
|
||||||
|
|
||||||
/*disable free run clock */
|
/*disable free run clock */
|
||||||
tmp = readl(sif_base + U3P_U2FREQ_FMMONR1);
|
tmp = readl(fmreg + U3P_U2FREQ_FMMONR1);
|
||||||
tmp &= ~P2F_RG_FRCK_EN;
|
tmp &= ~P2F_RG_FRCK_EN;
|
||||||
writel(tmp, sif_base + U3P_U2FREQ_FMMONR1);
|
writel(tmp, fmreg + U3P_U2FREQ_FMMONR1);
|
||||||
|
|
||||||
if (fm_out) {
|
if (fm_out) {
|
||||||
/* ( 1024 / FM_OUT ) x reference clock frequency x 0.028 */
|
/* ( 1024 / FM_OUT ) x reference clock frequency x 0.028 */
|
||||||
@ -215,85 +261,125 @@ static void hs_slew_rate_calibrate(struct mt65xx_u3phy *u3phy,
|
|||||||
instance->index, fm_out, calibration_val);
|
instance->index, fm_out, calibration_val);
|
||||||
|
|
||||||
/* set HS slew rate */
|
/* set HS slew rate */
|
||||||
tmp = readl(instance->port_base + U3P_USBPHYACR5);
|
tmp = readl(com + U3P_USBPHYACR5);
|
||||||
tmp &= ~PA5_RG_U2_HSTX_SRCTRL;
|
tmp &= ~PA5_RG_U2_HSTX_SRCTRL;
|
||||||
tmp |= PA5_RG_U2_HSTX_SRCTRL_VAL(calibration_val);
|
tmp |= PA5_RG_U2_HSTX_SRCTRL_VAL(calibration_val);
|
||||||
writel(tmp, instance->port_base + U3P_USBPHYACR5);
|
writel(tmp, com + U3P_USBPHYACR5);
|
||||||
|
|
||||||
/* disable USB ring oscillator */
|
/* disable USB ring oscillator */
|
||||||
tmp = readl(instance->port_base + U3P_USBPHYACR5);
|
tmp = readl(com + U3P_USBPHYACR5);
|
||||||
tmp &= ~PA5_RG_U2_HSTX_SRCAL_EN;
|
tmp &= ~PA5_RG_U2_HSTX_SRCAL_EN;
|
||||||
writel(tmp, instance->port_base + U3P_USBPHYACR5);
|
writel(tmp, com + U3P_USBPHYACR5);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void u3_phy_instance_init(struct mt65xx_u3phy *u3phy,
|
||||||
|
struct mt65xx_phy_instance *instance)
|
||||||
|
{
|
||||||
|
struct u3phy_banks *u3_banks = &instance->u3_banks;
|
||||||
|
u32 tmp;
|
||||||
|
|
||||||
|
/* gating PCIe Analog XTAL clock */
|
||||||
|
tmp = readl(u3_banks->spllc + U3P_SPLLC_XTALCTL3);
|
||||||
|
tmp |= XC3_RG_U3_XTAL_RX_PWD | XC3_RG_U3_FRC_XTAL_RX_PWD;
|
||||||
|
writel(tmp, u3_banks->spllc + U3P_SPLLC_XTALCTL3);
|
||||||
|
|
||||||
|
/* gating XSQ */
|
||||||
|
tmp = readl(u3_banks->phya + U3P_U3_PHYA_DA_REG0);
|
||||||
|
tmp &= ~P3A_RG_XTAL_EXT_EN_U3;
|
||||||
|
tmp |= P3A_RG_XTAL_EXT_EN_U3_VAL(2);
|
||||||
|
writel(tmp, u3_banks->phya + U3P_U3_PHYA_DA_REG0);
|
||||||
|
|
||||||
|
tmp = readl(u3_banks->phya + U3P_U3_PHYA_REG9);
|
||||||
|
tmp &= ~P3A_RG_RX_DAC_MUX;
|
||||||
|
tmp |= P3A_RG_RX_DAC_MUX_VAL(4);
|
||||||
|
writel(tmp, u3_banks->phya + U3P_U3_PHYA_REG9);
|
||||||
|
|
||||||
|
tmp = readl(u3_banks->phya + U3P_U3_PHYA_REG6);
|
||||||
|
tmp &= ~P3A_RG_TX_EIDLE_CM;
|
||||||
|
tmp |= P3A_RG_TX_EIDLE_CM_VAL(0xe);
|
||||||
|
writel(tmp, u3_banks->phya + U3P_U3_PHYA_REG6);
|
||||||
|
|
||||||
|
tmp = readl(u3_banks->phyd + U3P_U3_PHYD_CDR1);
|
||||||
|
tmp &= ~(P3D_RG_CDR_BIR_LTD0 | P3D_RG_CDR_BIR_LTD1);
|
||||||
|
tmp |= P3D_RG_CDR_BIR_LTD0_VAL(0xc) | P3D_RG_CDR_BIR_LTD1_VAL(0x3);
|
||||||
|
writel(tmp, u3_banks->phyd + U3P_U3_PHYD_CDR1);
|
||||||
|
|
||||||
|
tmp = readl(u3_banks->phyd + U3P_U3_PHYD_LFPS1);
|
||||||
|
tmp &= ~P3D_RG_FWAKE_TH;
|
||||||
|
tmp |= P3D_RG_FWAKE_TH_VAL(0x34);
|
||||||
|
writel(tmp, u3_banks->phyd + U3P_U3_PHYD_LFPS1);
|
||||||
|
|
||||||
|
tmp = readl(u3_banks->phyd + U3P_U3_PHYD_RXDET1);
|
||||||
|
tmp &= ~P3D_RG_RXDET_STB2_SET;
|
||||||
|
tmp |= P3D_RG_RXDET_STB2_SET_VAL(0x10);
|
||||||
|
writel(tmp, u3_banks->phyd + U3P_U3_PHYD_RXDET1);
|
||||||
|
|
||||||
|
tmp = readl(u3_banks->phyd + U3P_U3_PHYD_RXDET2);
|
||||||
|
tmp &= ~P3D_RG_RXDET_STB2_SET_P3;
|
||||||
|
tmp |= P3D_RG_RXDET_STB2_SET_P3_VAL(0x10);
|
||||||
|
writel(tmp, u3_banks->phyd + U3P_U3_PHYD_RXDET2);
|
||||||
|
|
||||||
|
dev_dbg(u3phy->dev, "%s(%d)\n", __func__, instance->index);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void phy_instance_init(struct mt65xx_u3phy *u3phy,
|
static void phy_instance_init(struct mt65xx_u3phy *u3phy,
|
||||||
struct mt65xx_phy_instance *instance)
|
struct mt65xx_phy_instance *instance)
|
||||||
{
|
{
|
||||||
void __iomem *port_base = instance->port_base;
|
struct u2phy_banks *u2_banks = &instance->u2_banks;
|
||||||
|
void __iomem *com = u2_banks->com;
|
||||||
u32 index = instance->index;
|
u32 index = instance->index;
|
||||||
u32 tmp;
|
u32 tmp;
|
||||||
|
|
||||||
/* switch to USB function. (system register, force ip into usb mode) */
|
/* switch to USB function. (system register, force ip into usb mode) */
|
||||||
tmp = readl(port_base + U3P_U2PHYDTM0);
|
tmp = readl(com + U3P_U2PHYDTM0);
|
||||||
tmp &= ~P2C_FORCE_UART_EN;
|
tmp &= ~P2C_FORCE_UART_EN;
|
||||||
tmp |= P2C_RG_XCVRSEL_VAL(1) | P2C_RG_DATAIN_VAL(0);
|
tmp |= P2C_RG_XCVRSEL_VAL(1) | P2C_RG_DATAIN_VAL(0);
|
||||||
writel(tmp, port_base + U3P_U2PHYDTM0);
|
writel(tmp, com + U3P_U2PHYDTM0);
|
||||||
|
|
||||||
tmp = readl(port_base + U3P_U2PHYDTM1);
|
tmp = readl(com + U3P_U2PHYDTM1);
|
||||||
tmp &= ~P2C_RG_UART_EN;
|
tmp &= ~P2C_RG_UART_EN;
|
||||||
writel(tmp, port_base + U3P_U2PHYDTM1);
|
writel(tmp, com + U3P_U2PHYDTM1);
|
||||||
|
|
||||||
|
tmp = readl(com + U3P_USBPHYACR0);
|
||||||
|
tmp |= PA0_RG_USB20_INTR_EN;
|
||||||
|
writel(tmp, com + U3P_USBPHYACR0);
|
||||||
|
|
||||||
|
/* disable switch 100uA current to SSUSB */
|
||||||
|
tmp = readl(com + U3P_USBPHYACR5);
|
||||||
|
tmp &= ~PA5_RG_U2_HS_100U_U3_EN;
|
||||||
|
writel(tmp, com + U3P_USBPHYACR5);
|
||||||
|
|
||||||
if (!index) {
|
if (!index) {
|
||||||
tmp = readl(port_base + U3P_U2PHYACR4);
|
tmp = readl(com + U3P_U2PHYACR4);
|
||||||
tmp &= ~P2C_U2_GPIO_CTR_MSK;
|
tmp &= ~P2C_U2_GPIO_CTR_MSK;
|
||||||
writel(tmp, port_base + U3P_U2PHYACR4);
|
writel(tmp, com + U3P_U2PHYACR4);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (u3phy->pdata->avoid_rx_sen_degradation) {
|
if (u3phy->pdata->avoid_rx_sen_degradation) {
|
||||||
if (!index) {
|
if (!index) {
|
||||||
tmp = readl(port_base + U3P_USBPHYACR2);
|
tmp = readl(com + U3P_USBPHYACR2);
|
||||||
tmp |= PA2_RG_SIF_U2PLL_FORCE_EN;
|
tmp |= PA2_RG_SIF_U2PLL_FORCE_EN;
|
||||||
writel(tmp, port_base + U3P_USBPHYACR2);
|
writel(tmp, com + U3P_USBPHYACR2);
|
||||||
|
|
||||||
tmp = readl(port_base + U3D_U2PHYDCR0);
|
tmp = readl(com + U3D_U2PHYDCR0);
|
||||||
tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
|
tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
|
||||||
writel(tmp, port_base + U3D_U2PHYDCR0);
|
writel(tmp, com + U3D_U2PHYDCR0);
|
||||||
} else {
|
} else {
|
||||||
tmp = readl(port_base + U3D_U2PHYDCR0);
|
tmp = readl(com + U3D_U2PHYDCR0);
|
||||||
tmp |= P2C_RG_SIF_U2PLL_FORCE_ON;
|
tmp |= P2C_RG_SIF_U2PLL_FORCE_ON;
|
||||||
writel(tmp, port_base + U3D_U2PHYDCR0);
|
writel(tmp, com + U3D_U2PHYDCR0);
|
||||||
|
|
||||||
tmp = readl(port_base + U3P_U2PHYDTM0);
|
tmp = readl(com + U3P_U2PHYDTM0);
|
||||||
tmp |= P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM;
|
tmp |= P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM;
|
||||||
writel(tmp, port_base + U3P_U2PHYDTM0);
|
writel(tmp, com + U3P_U2PHYDTM0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp = readl(port_base + U3P_USBPHYACR6);
|
tmp = readl(com + U3P_USBPHYACR6);
|
||||||
tmp &= ~PA6_RG_U2_BC11_SW_EN; /* DP/DM BC1.1 path Disable */
|
tmp &= ~PA6_RG_U2_BC11_SW_EN; /* DP/DM BC1.1 path Disable */
|
||||||
tmp &= ~PA6_RG_U2_SQTH;
|
tmp &= ~PA6_RG_U2_SQTH;
|
||||||
tmp |= PA6_RG_U2_SQTH_VAL(2);
|
tmp |= PA6_RG_U2_SQTH_VAL(2);
|
||||||
writel(tmp, port_base + U3P_USBPHYACR6);
|
writel(tmp, com + U3P_USBPHYACR6);
|
||||||
|
|
||||||
tmp = readl(port_base + U3P_U3PHYA_DA_REG0);
|
|
||||||
tmp &= ~P3A_RG_XTAL_EXT_EN_U3;
|
|
||||||
tmp |= P3A_RG_XTAL_EXT_EN_U3_VAL(2);
|
|
||||||
writel(tmp, port_base + U3P_U3PHYA_DA_REG0);
|
|
||||||
|
|
||||||
tmp = readl(port_base + U3P_U3_PHYA_REG9);
|
|
||||||
tmp &= ~P3A_RG_RX_DAC_MUX;
|
|
||||||
tmp |= P3A_RG_RX_DAC_MUX_VAL(4);
|
|
||||||
writel(tmp, port_base + U3P_U3_PHYA_REG9);
|
|
||||||
|
|
||||||
tmp = readl(port_base + U3P_U3_PHYA_REG6);
|
|
||||||
tmp &= ~P3A_RG_TX_EIDLE_CM;
|
|
||||||
tmp |= P3A_RG_TX_EIDLE_CM_VAL(0xe);
|
|
||||||
writel(tmp, port_base + U3P_U3_PHYA_REG6);
|
|
||||||
|
|
||||||
tmp = readl(port_base + U3P_PHYD_CDR1);
|
|
||||||
tmp &= ~(P3D_RG_CDR_BIR_LTD0 | P3D_RG_CDR_BIR_LTD1);
|
|
||||||
tmp |= P3D_RG_CDR_BIR_LTD0_VAL(0xc) | P3D_RG_CDR_BIR_LTD1_VAL(0x3);
|
|
||||||
writel(tmp, port_base + U3P_PHYD_CDR1);
|
|
||||||
|
|
||||||
dev_dbg(u3phy->dev, "%s(%d)\n", __func__, index);
|
dev_dbg(u3phy->dev, "%s(%d)\n", __func__, index);
|
||||||
}
|
}
|
||||||
@ -301,58 +387,35 @@ static void phy_instance_init(struct mt65xx_u3phy *u3phy,
|
|||||||
static void phy_instance_power_on(struct mt65xx_u3phy *u3phy,
|
static void phy_instance_power_on(struct mt65xx_u3phy *u3phy,
|
||||||
struct mt65xx_phy_instance *instance)
|
struct mt65xx_phy_instance *instance)
|
||||||
{
|
{
|
||||||
void __iomem *port_base = instance->port_base;
|
struct u2phy_banks *u2_banks = &instance->u2_banks;
|
||||||
|
void __iomem *com = u2_banks->com;
|
||||||
u32 index = instance->index;
|
u32 index = instance->index;
|
||||||
u32 tmp;
|
u32 tmp;
|
||||||
|
|
||||||
if (!index) {
|
|
||||||
/* Set RG_SSUSB_VUSB10_ON as 1 after VUSB10 ready */
|
|
||||||
tmp = readl(port_base + U3P_U3_PHYA_REG0);
|
|
||||||
tmp |= P3A_RG_U3_VUSB10_ON;
|
|
||||||
writel(tmp, port_base + U3P_U3_PHYA_REG0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* (force_suspendm=0) (let suspendm=1, enable usb 480MHz pll) */
|
/* (force_suspendm=0) (let suspendm=1, enable usb 480MHz pll) */
|
||||||
tmp = readl(port_base + U3P_U2PHYDTM0);
|
tmp = readl(com + U3P_U2PHYDTM0);
|
||||||
tmp &= ~(P2C_FORCE_SUSPENDM | P2C_RG_XCVRSEL);
|
tmp &= ~(P2C_FORCE_SUSPENDM | P2C_RG_XCVRSEL);
|
||||||
tmp &= ~(P2C_RG_DATAIN | P2C_DTM0_PART_MASK);
|
tmp &= ~(P2C_RG_DATAIN | P2C_DTM0_PART_MASK);
|
||||||
writel(tmp, port_base + U3P_U2PHYDTM0);
|
writel(tmp, com + U3P_U2PHYDTM0);
|
||||||
|
|
||||||
/* OTG Enable */
|
/* OTG Enable */
|
||||||
tmp = readl(port_base + U3P_USBPHYACR6);
|
tmp = readl(com + U3P_USBPHYACR6);
|
||||||
tmp |= PA6_RG_U2_OTG_VBUSCMP_EN;
|
tmp |= PA6_RG_U2_OTG_VBUSCMP_EN;
|
||||||
writel(tmp, port_base + U3P_USBPHYACR6);
|
writel(tmp, com + U3P_USBPHYACR6);
|
||||||
|
|
||||||
if (!index) {
|
tmp = readl(com + U3P_U2PHYDTM1);
|
||||||
tmp = readl(u3phy->sif_base + U3P_XTALCTL3);
|
|
||||||
tmp |= XC3_RG_U3_XTAL_RX_PWD | XC3_RG_U3_FRC_XTAL_RX_PWD;
|
|
||||||
writel(tmp, u3phy->sif_base + U3P_XTALCTL3);
|
|
||||||
|
|
||||||
/* switch 100uA current to SSUSB */
|
|
||||||
tmp = readl(port_base + U3P_USBPHYACR5);
|
|
||||||
tmp |= PA5_RG_U2_HS_100U_U3_EN;
|
|
||||||
writel(tmp, port_base + U3P_USBPHYACR5);
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp = readl(port_base + U3P_U2PHYDTM1);
|
|
||||||
tmp |= P2C_RG_VBUSVALID | P2C_RG_AVALID;
|
tmp |= P2C_RG_VBUSVALID | P2C_RG_AVALID;
|
||||||
tmp &= ~P2C_RG_SESSEND;
|
tmp &= ~P2C_RG_SESSEND;
|
||||||
writel(tmp, port_base + U3P_U2PHYDTM1);
|
writel(tmp, com + U3P_U2PHYDTM1);
|
||||||
|
|
||||||
/* USB 2.0 slew rate calibration */
|
|
||||||
tmp = readl(port_base + U3P_USBPHYACR5);
|
|
||||||
tmp &= ~PA5_RG_U2_HSTX_SRCTRL;
|
|
||||||
tmp |= PA5_RG_U2_HSTX_SRCTRL_VAL(4);
|
|
||||||
writel(tmp, port_base + U3P_USBPHYACR5);
|
|
||||||
|
|
||||||
if (u3phy->pdata->avoid_rx_sen_degradation && index) {
|
if (u3phy->pdata->avoid_rx_sen_degradation && index) {
|
||||||
tmp = readl(port_base + U3D_U2PHYDCR0);
|
tmp = readl(com + U3D_U2PHYDCR0);
|
||||||
tmp |= P2C_RG_SIF_U2PLL_FORCE_ON;
|
tmp |= P2C_RG_SIF_U2PLL_FORCE_ON;
|
||||||
writel(tmp, port_base + U3D_U2PHYDCR0);
|
writel(tmp, com + U3D_U2PHYDCR0);
|
||||||
|
|
||||||
tmp = readl(port_base + U3P_U2PHYDTM0);
|
tmp = readl(com + U3P_U2PHYDTM0);
|
||||||
tmp |= P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM;
|
tmp |= P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM;
|
||||||
writel(tmp, port_base + U3P_U2PHYDTM0);
|
writel(tmp, com + U3P_U2PHYDTM0);
|
||||||
}
|
}
|
||||||
dev_dbg(u3phy->dev, "%s(%d)\n", __func__, index);
|
dev_dbg(u3phy->dev, "%s(%d)\n", __func__, index);
|
||||||
}
|
}
|
||||||
@ -360,48 +423,36 @@ static void phy_instance_power_on(struct mt65xx_u3phy *u3phy,
|
|||||||
static void phy_instance_power_off(struct mt65xx_u3phy *u3phy,
|
static void phy_instance_power_off(struct mt65xx_u3phy *u3phy,
|
||||||
struct mt65xx_phy_instance *instance)
|
struct mt65xx_phy_instance *instance)
|
||||||
{
|
{
|
||||||
void __iomem *port_base = instance->port_base;
|
struct u2phy_banks *u2_banks = &instance->u2_banks;
|
||||||
|
void __iomem *com = u2_banks->com;
|
||||||
u32 index = instance->index;
|
u32 index = instance->index;
|
||||||
u32 tmp;
|
u32 tmp;
|
||||||
|
|
||||||
tmp = readl(port_base + U3P_U2PHYDTM0);
|
tmp = readl(com + U3P_U2PHYDTM0);
|
||||||
tmp &= ~(P2C_RG_XCVRSEL | P2C_RG_DATAIN);
|
tmp &= ~(P2C_RG_XCVRSEL | P2C_RG_DATAIN);
|
||||||
tmp |= P2C_FORCE_SUSPENDM;
|
tmp |= P2C_FORCE_SUSPENDM;
|
||||||
writel(tmp, port_base + U3P_U2PHYDTM0);
|
writel(tmp, com + U3P_U2PHYDTM0);
|
||||||
|
|
||||||
/* OTG Disable */
|
/* OTG Disable */
|
||||||
tmp = readl(port_base + U3P_USBPHYACR6);
|
tmp = readl(com + U3P_USBPHYACR6);
|
||||||
tmp &= ~PA6_RG_U2_OTG_VBUSCMP_EN;
|
tmp &= ~PA6_RG_U2_OTG_VBUSCMP_EN;
|
||||||
writel(tmp, port_base + U3P_USBPHYACR6);
|
writel(tmp, com + U3P_USBPHYACR6);
|
||||||
|
|
||||||
if (!index) {
|
|
||||||
/* switch 100uA current back to USB2.0 */
|
|
||||||
tmp = readl(port_base + U3P_USBPHYACR5);
|
|
||||||
tmp &= ~PA5_RG_U2_HS_100U_U3_EN;
|
|
||||||
writel(tmp, port_base + U3P_USBPHYACR5);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* let suspendm=0, set utmi into analog power down */
|
/* let suspendm=0, set utmi into analog power down */
|
||||||
tmp = readl(port_base + U3P_U2PHYDTM0);
|
tmp = readl(com + U3P_U2PHYDTM0);
|
||||||
tmp &= ~P2C_RG_SUSPENDM;
|
tmp &= ~P2C_RG_SUSPENDM;
|
||||||
writel(tmp, port_base + U3P_U2PHYDTM0);
|
writel(tmp, com + U3P_U2PHYDTM0);
|
||||||
udelay(1);
|
udelay(1);
|
||||||
|
|
||||||
tmp = readl(port_base + U3P_U2PHYDTM1);
|
tmp = readl(com + U3P_U2PHYDTM1);
|
||||||
tmp &= ~(P2C_RG_VBUSVALID | P2C_RG_AVALID);
|
tmp &= ~(P2C_RG_VBUSVALID | P2C_RG_AVALID);
|
||||||
tmp |= P2C_RG_SESSEND;
|
tmp |= P2C_RG_SESSEND;
|
||||||
writel(tmp, port_base + U3P_U2PHYDTM1);
|
writel(tmp, com + U3P_U2PHYDTM1);
|
||||||
|
|
||||||
if (!index) {
|
|
||||||
tmp = readl(port_base + U3P_U3_PHYA_REG0);
|
|
||||||
tmp &= ~P3A_RG_U3_VUSB10_ON;
|
|
||||||
writel(tmp, port_base + U3P_U3_PHYA_REG0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (u3phy->pdata->avoid_rx_sen_degradation && index) {
|
if (u3phy->pdata->avoid_rx_sen_degradation && index) {
|
||||||
tmp = readl(port_base + U3D_U2PHYDCR0);
|
tmp = readl(com + U3D_U2PHYDCR0);
|
||||||
tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
|
tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
|
||||||
writel(tmp, port_base + U3D_U2PHYDCR0);
|
writel(tmp, com + U3D_U2PHYDCR0);
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_dbg(u3phy->dev, "%s(%d)\n", __func__, index);
|
dev_dbg(u3phy->dev, "%s(%d)\n", __func__, index);
|
||||||
@ -410,18 +461,55 @@ static void phy_instance_power_off(struct mt65xx_u3phy *u3phy,
|
|||||||
static void phy_instance_exit(struct mt65xx_u3phy *u3phy,
|
static void phy_instance_exit(struct mt65xx_u3phy *u3phy,
|
||||||
struct mt65xx_phy_instance *instance)
|
struct mt65xx_phy_instance *instance)
|
||||||
{
|
{
|
||||||
void __iomem *port_base = instance->port_base;
|
struct u2phy_banks *u2_banks = &instance->u2_banks;
|
||||||
|
void __iomem *com = u2_banks->com;
|
||||||
u32 index = instance->index;
|
u32 index = instance->index;
|
||||||
u32 tmp;
|
u32 tmp;
|
||||||
|
|
||||||
if (u3phy->pdata->avoid_rx_sen_degradation && index) {
|
if (u3phy->pdata->avoid_rx_sen_degradation && index) {
|
||||||
tmp = readl(port_base + U3D_U2PHYDCR0);
|
tmp = readl(com + U3D_U2PHYDCR0);
|
||||||
tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
|
tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;
|
||||||
writel(tmp, port_base + U3D_U2PHYDCR0);
|
writel(tmp, com + U3D_U2PHYDCR0);
|
||||||
|
|
||||||
tmp = readl(port_base + U3P_U2PHYDTM0);
|
tmp = readl(com + U3P_U2PHYDTM0);
|
||||||
tmp &= ~P2C_FORCE_SUSPENDM;
|
tmp &= ~P2C_FORCE_SUSPENDM;
|
||||||
writel(tmp, port_base + U3P_U2PHYDTM0);
|
writel(tmp, com + U3P_U2PHYDTM0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void phy_v1_banks_init(struct mt65xx_u3phy *u3phy,
|
||||||
|
struct mt65xx_phy_instance *instance)
|
||||||
|
{
|
||||||
|
struct u2phy_banks *u2_banks = &instance->u2_banks;
|
||||||
|
struct u3phy_banks *u3_banks = &instance->u3_banks;
|
||||||
|
|
||||||
|
if (instance->type == PHY_TYPE_USB2) {
|
||||||
|
u2_banks->misc = NULL;
|
||||||
|
u2_banks->fmreg = u3phy->sif_base + SSUSB_SIFSLV_V1_U2FREQ;
|
||||||
|
u2_banks->com = instance->port_base + SSUSB_SIFSLV_V1_U2PHY_COM;
|
||||||
|
} else if (instance->type == PHY_TYPE_USB3) {
|
||||||
|
u3_banks->spllc = u3phy->sif_base + SSUSB_SIFSLV_V1_SPLLC;
|
||||||
|
u3_banks->chip = NULL;
|
||||||
|
u3_banks->phyd = instance->port_base + SSUSB_SIFSLV_V1_U3PHYD;
|
||||||
|
u3_banks->phya = instance->port_base + SSUSB_SIFSLV_V1_U3PHYA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void phy_v2_banks_init(struct mt65xx_u3phy *u3phy,
|
||||||
|
struct mt65xx_phy_instance *instance)
|
||||||
|
{
|
||||||
|
struct u2phy_banks *u2_banks = &instance->u2_banks;
|
||||||
|
struct u3phy_banks *u3_banks = &instance->u3_banks;
|
||||||
|
|
||||||
|
if (instance->type == PHY_TYPE_USB2) {
|
||||||
|
u2_banks->misc = instance->port_base + SSUSB_SIFSLV_V2_MISC;
|
||||||
|
u2_banks->fmreg = instance->port_base + SSUSB_SIFSLV_V2_U2FREQ;
|
||||||
|
u2_banks->com = instance->port_base + SSUSB_SIFSLV_V2_U2PHY_COM;
|
||||||
|
} else if (instance->type == PHY_TYPE_USB3) {
|
||||||
|
u3_banks->spllc = instance->port_base + SSUSB_SIFSLV_V2_SPLLC;
|
||||||
|
u3_banks->chip = instance->port_base + SSUSB_SIFSLV_V2_CHIP;
|
||||||
|
u3_banks->phyd = instance->port_base + SSUSB_SIFSLV_V2_U3PHYD;
|
||||||
|
u3_banks->phya = instance->port_base + SSUSB_SIFSLV_V2_U3PHYA;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -437,7 +525,17 @@ static int mt65xx_phy_init(struct phy *phy)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
phy_instance_init(u3phy, instance);
|
ret = clk_prepare_enable(instance->ref_clk);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(u3phy->dev, "failed to enable ref_clk\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instance->type == PHY_TYPE_USB2)
|
||||||
|
phy_instance_init(u3phy, instance);
|
||||||
|
else
|
||||||
|
u3_phy_instance_init(u3phy, instance);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -446,8 +544,10 @@ static int mt65xx_phy_power_on(struct phy *phy)
|
|||||||
struct mt65xx_phy_instance *instance = phy_get_drvdata(phy);
|
struct mt65xx_phy_instance *instance = phy_get_drvdata(phy);
|
||||||
struct mt65xx_u3phy *u3phy = dev_get_drvdata(phy->dev.parent);
|
struct mt65xx_u3phy *u3phy = dev_get_drvdata(phy->dev.parent);
|
||||||
|
|
||||||
phy_instance_power_on(u3phy, instance);
|
if (instance->type == PHY_TYPE_USB2) {
|
||||||
hs_slew_rate_calibrate(u3phy, instance);
|
phy_instance_power_on(u3phy, instance);
|
||||||
|
hs_slew_rate_calibrate(u3phy, instance);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -456,7 +556,9 @@ static int mt65xx_phy_power_off(struct phy *phy)
|
|||||||
struct mt65xx_phy_instance *instance = phy_get_drvdata(phy);
|
struct mt65xx_phy_instance *instance = phy_get_drvdata(phy);
|
||||||
struct mt65xx_u3phy *u3phy = dev_get_drvdata(phy->dev.parent);
|
struct mt65xx_u3phy *u3phy = dev_get_drvdata(phy->dev.parent);
|
||||||
|
|
||||||
phy_instance_power_off(u3phy, instance);
|
if (instance->type == PHY_TYPE_USB2)
|
||||||
|
phy_instance_power_off(u3phy, instance);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -465,7 +567,10 @@ static int mt65xx_phy_exit(struct phy *phy)
|
|||||||
struct mt65xx_phy_instance *instance = phy_get_drvdata(phy);
|
struct mt65xx_phy_instance *instance = phy_get_drvdata(phy);
|
||||||
struct mt65xx_u3phy *u3phy = dev_get_drvdata(phy->dev.parent);
|
struct mt65xx_u3phy *u3phy = dev_get_drvdata(phy->dev.parent);
|
||||||
|
|
||||||
phy_instance_exit(u3phy, instance);
|
if (instance->type == PHY_TYPE_USB2)
|
||||||
|
phy_instance_exit(u3phy, instance);
|
||||||
|
|
||||||
|
clk_disable_unprepare(instance->ref_clk);
|
||||||
clk_disable_unprepare(u3phy->u3phya_ref);
|
clk_disable_unprepare(u3phy->u3phya_ref);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -478,7 +583,6 @@ static struct phy *mt65xx_phy_xlate(struct device *dev,
|
|||||||
struct device_node *phy_np = args->np;
|
struct device_node *phy_np = args->np;
|
||||||
int index;
|
int index;
|
||||||
|
|
||||||
|
|
||||||
if (args->args_count != 1) {
|
if (args->args_count != 1) {
|
||||||
dev_err(dev, "invalid number of cells in 'phy' property\n");
|
dev_err(dev, "invalid number of cells in 'phy' property\n");
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
@ -496,13 +600,21 @@ static struct phy *mt65xx_phy_xlate(struct device *dev,
|
|||||||
}
|
}
|
||||||
|
|
||||||
instance->type = args->args[0];
|
instance->type = args->args[0];
|
||||||
|
|
||||||
if (!(instance->type == PHY_TYPE_USB2 ||
|
if (!(instance->type == PHY_TYPE_USB2 ||
|
||||||
instance->type == PHY_TYPE_USB3)) {
|
instance->type == PHY_TYPE_USB3)) {
|
||||||
dev_err(dev, "unsupported device type: %d\n", instance->type);
|
dev_err(dev, "unsupported device type: %d\n", instance->type);
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (u3phy->pdata->version == MT_PHY_V1) {
|
||||||
|
phy_v1_banks_init(u3phy, instance);
|
||||||
|
} else if (u3phy->pdata->version == MT_PHY_V2) {
|
||||||
|
phy_v2_banks_init(u3phy, instance);
|
||||||
|
} else {
|
||||||
|
dev_err(dev, "phy version is not supported\n");
|
||||||
|
return ERR_PTR(-EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
return instance->phy;
|
return instance->phy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -516,14 +628,22 @@ static const struct phy_ops mt65xx_u3phy_ops = {
|
|||||||
|
|
||||||
static const struct mt65xx_phy_pdata mt2701_pdata = {
|
static const struct mt65xx_phy_pdata mt2701_pdata = {
|
||||||
.avoid_rx_sen_degradation = false,
|
.avoid_rx_sen_degradation = false,
|
||||||
|
.version = MT_PHY_V1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct mt65xx_phy_pdata mt2712_pdata = {
|
||||||
|
.avoid_rx_sen_degradation = false,
|
||||||
|
.version = MT_PHY_V2,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct mt65xx_phy_pdata mt8173_pdata = {
|
static const struct mt65xx_phy_pdata mt8173_pdata = {
|
||||||
.avoid_rx_sen_degradation = true,
|
.avoid_rx_sen_degradation = true,
|
||||||
|
.version = MT_PHY_V1,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct of_device_id mt65xx_u3phy_id_table[] = {
|
static const struct of_device_id mt65xx_u3phy_id_table[] = {
|
||||||
{ .compatible = "mediatek,mt2701-u3phy", .data = &mt2701_pdata },
|
{ .compatible = "mediatek,mt2701-u3phy", .data = &mt2701_pdata },
|
||||||
|
{ .compatible = "mediatek,mt2712-u3phy", .data = &mt2712_pdata },
|
||||||
{ .compatible = "mediatek,mt8173-u3phy", .data = &mt8173_pdata },
|
{ .compatible = "mediatek,mt8173-u3phy", .data = &mt8173_pdata },
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
@ -559,17 +679,23 @@ static int mt65xx_u3phy_probe(struct platform_device *pdev)
|
|||||||
u3phy->dev = dev;
|
u3phy->dev = dev;
|
||||||
platform_set_drvdata(pdev, u3phy);
|
platform_set_drvdata(pdev, u3phy);
|
||||||
|
|
||||||
sif_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
if (u3phy->pdata->version == MT_PHY_V1) {
|
||||||
u3phy->sif_base = devm_ioremap_resource(dev, sif_res);
|
/* get banks shared by multiple phys */
|
||||||
if (IS_ERR(u3phy->sif_base)) {
|
sif_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
dev_err(dev, "failed to remap sif regs\n");
|
u3phy->sif_base = devm_ioremap_resource(dev, sif_res);
|
||||||
return PTR_ERR(u3phy->sif_base);
|
if (IS_ERR(u3phy->sif_base)) {
|
||||||
|
dev_err(dev, "failed to remap sif regs\n");
|
||||||
|
return PTR_ERR(u3phy->sif_base);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* it's deprecated, make it optional for backward compatibility */
|
||||||
u3phy->u3phya_ref = devm_clk_get(dev, "u3phya_ref");
|
u3phy->u3phya_ref = devm_clk_get(dev, "u3phya_ref");
|
||||||
if (IS_ERR(u3phy->u3phya_ref)) {
|
if (IS_ERR(u3phy->u3phya_ref)) {
|
||||||
dev_err(dev, "error to get u3phya_ref\n");
|
if (PTR_ERR(u3phy->u3phya_ref) == -EPROBE_DEFER)
|
||||||
return PTR_ERR(u3phy->u3phya_ref);
|
return -EPROBE_DEFER;
|
||||||
|
|
||||||
|
u3phy->u3phya_ref = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
port = 0;
|
port = 0;
|
||||||
@ -610,6 +736,17 @@ static int mt65xx_u3phy_probe(struct platform_device *pdev)
|
|||||||
instance->index = port;
|
instance->index = port;
|
||||||
phy_set_drvdata(phy, instance);
|
phy_set_drvdata(phy, instance);
|
||||||
port++;
|
port++;
|
||||||
|
|
||||||
|
/* if deprecated clock is provided, ignore instance's one */
|
||||||
|
if (u3phy->u3phya_ref)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
instance->ref_clk = devm_clk_get(&phy->dev, "ref");
|
||||||
|
if (IS_ERR(instance->ref_clk)) {
|
||||||
|
dev_err(dev, "failed to get ref_clk(id-%d)\n", port);
|
||||||
|
retval = PTR_ERR(instance->ref_clk);
|
||||||
|
goto put_child;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
provider = devm_of_phy_provider_register(dev, mt65xx_phy_xlate);
|
provider = devm_of_phy_provider_register(dev, mt65xx_phy_xlate);
|
||||||
|
1153
drivers/phy/phy-qcom-qmp.c
Normal file
1153
drivers/phy/phy-qcom-qmp.c
Normal file
File diff suppressed because it is too large
Load Diff
493
drivers/phy/phy-qcom-qusb2.c
Normal file
493
drivers/phy/phy-qcom-qusb2.c
Normal file
@ -0,0 +1,493 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017, The Linux Foundation. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 and
|
||||||
|
* only version 2 as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/clk.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/mfd/syscon.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/nvmem-consumer.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_device.h>
|
||||||
|
#include <linux/phy/phy.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
#include <linux/regulator/consumer.h>
|
||||||
|
#include <linux/reset.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
|
||||||
|
#define QUSB2PHY_PLL_TEST 0x04
|
||||||
|
#define CLK_REF_SEL BIT(7)
|
||||||
|
|
||||||
|
#define QUSB2PHY_PLL_TUNE 0x08
|
||||||
|
#define QUSB2PHY_PLL_USER_CTL1 0x0c
|
||||||
|
#define QUSB2PHY_PLL_USER_CTL2 0x10
|
||||||
|
#define QUSB2PHY_PLL_AUTOPGM_CTL1 0x1c
|
||||||
|
#define QUSB2PHY_PLL_PWR_CTRL 0x18
|
||||||
|
|
||||||
|
#define QUSB2PHY_PLL_STATUS 0x38
|
||||||
|
#define PLL_LOCKED BIT(5)
|
||||||
|
|
||||||
|
#define QUSB2PHY_PORT_TUNE1 0x80
|
||||||
|
#define QUSB2PHY_PORT_TUNE2 0x84
|
||||||
|
#define QUSB2PHY_PORT_TUNE3 0x88
|
||||||
|
#define QUSB2PHY_PORT_TUNE4 0x8c
|
||||||
|
#define QUSB2PHY_PORT_TUNE5 0x90
|
||||||
|
#define QUSB2PHY_PORT_TEST2 0x9c
|
||||||
|
|
||||||
|
#define QUSB2PHY_PORT_POWERDOWN 0xb4
|
||||||
|
#define CLAMP_N_EN BIT(5)
|
||||||
|
#define FREEZIO_N BIT(1)
|
||||||
|
#define POWER_DOWN BIT(0)
|
||||||
|
|
||||||
|
#define QUSB2PHY_REFCLK_ENABLE BIT(0)
|
||||||
|
|
||||||
|
#define PHY_CLK_SCHEME_SEL BIT(0)
|
||||||
|
|
||||||
|
struct qusb2_phy_init_tbl {
|
||||||
|
unsigned int offset;
|
||||||
|
unsigned int val;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define QUSB2_PHY_INIT_CFG(o, v) \
|
||||||
|
{ \
|
||||||
|
.offset = o, \
|
||||||
|
.val = v, \
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct qusb2_phy_init_tbl msm8996_init_tbl[] = {
|
||||||
|
QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE1, 0xf8),
|
||||||
|
QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE2, 0xb3),
|
||||||
|
QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE3, 0x83),
|
||||||
|
QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TUNE4, 0xc0),
|
||||||
|
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_TUNE, 0x30),
|
||||||
|
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL1, 0x79),
|
||||||
|
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_USER_CTL2, 0x21),
|
||||||
|
QUSB2_PHY_INIT_CFG(QUSB2PHY_PORT_TEST2, 0x14),
|
||||||
|
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_AUTOPGM_CTL1, 0x9f),
|
||||||
|
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_PWR_CTRL, 0x00),
|
||||||
|
};
|
||||||
|
|
||||||
|
struct qusb2_phy_cfg {
|
||||||
|
const struct qusb2_phy_init_tbl *tbl;
|
||||||
|
/* number of entries in the table */
|
||||||
|
unsigned int tbl_num;
|
||||||
|
/* offset to PHY_CLK_SCHEME register in TCSR map */
|
||||||
|
unsigned int clk_scheme_offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct qusb2_phy_cfg msm8996_phy_cfg = {
|
||||||
|
.tbl = msm8996_init_tbl,
|
||||||
|
.tbl_num = ARRAY_SIZE(msm8996_init_tbl),
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const qusb2_phy_vreg_names[] = {
|
||||||
|
"vdda-pll", "vdda-phy-dpdm",
|
||||||
|
};
|
||||||
|
|
||||||
|
#define QUSB2_NUM_VREGS ARRAY_SIZE(qusb2_phy_vreg_names)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct qusb2_phy - structure holding qusb2 phy attributes
|
||||||
|
*
|
||||||
|
* @phy: generic phy
|
||||||
|
* @base: iomapped memory space for qubs2 phy
|
||||||
|
*
|
||||||
|
* @cfg_ahb_clk: AHB2PHY interface clock
|
||||||
|
* @ref_clk: phy reference clock
|
||||||
|
* @iface_clk: phy interface clock
|
||||||
|
* @phy_reset: phy reset control
|
||||||
|
* @vregs: regulator supplies bulk data
|
||||||
|
*
|
||||||
|
* @tcsr: TCSR syscon register map
|
||||||
|
* @cell: nvmem cell containing phy tuning value
|
||||||
|
*
|
||||||
|
* @cfg: phy config data
|
||||||
|
* @has_se_clk_scheme: indicate if PHY has single-ended ref clock scheme
|
||||||
|
*/
|
||||||
|
struct qusb2_phy {
|
||||||
|
struct phy *phy;
|
||||||
|
void __iomem *base;
|
||||||
|
|
||||||
|
struct clk *cfg_ahb_clk;
|
||||||
|
struct clk *ref_clk;
|
||||||
|
struct clk *iface_clk;
|
||||||
|
struct reset_control *phy_reset;
|
||||||
|
struct regulator_bulk_data vregs[QUSB2_NUM_VREGS];
|
||||||
|
|
||||||
|
struct regmap *tcsr;
|
||||||
|
struct nvmem_cell *cell;
|
||||||
|
|
||||||
|
const struct qusb2_phy_cfg *cfg;
|
||||||
|
bool has_se_clk_scheme;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void qusb2_setbits(void __iomem *base, u32 offset, u32 val)
|
||||||
|
{
|
||||||
|
u32 reg;
|
||||||
|
|
||||||
|
reg = readl(base + offset);
|
||||||
|
reg |= val;
|
||||||
|
writel(reg, base + offset);
|
||||||
|
|
||||||
|
/* Ensure above write is completed */
|
||||||
|
readl(base + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void qusb2_clrbits(void __iomem *base, u32 offset, u32 val)
|
||||||
|
{
|
||||||
|
u32 reg;
|
||||||
|
|
||||||
|
reg = readl(base + offset);
|
||||||
|
reg &= ~val;
|
||||||
|
writel(reg, base + offset);
|
||||||
|
|
||||||
|
/* Ensure above write is completed */
|
||||||
|
readl(base + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void qcom_qusb2_phy_configure(void __iomem *base,
|
||||||
|
const struct qusb2_phy_init_tbl tbl[], int num)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < num; i++)
|
||||||
|
writel(tbl[i].val, base + tbl[i].offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fetches HS Tx tuning value from nvmem and sets the
|
||||||
|
* QUSB2PHY_PORT_TUNE2 register.
|
||||||
|
* For error case, skip setting the value and use the default value.
|
||||||
|
*/
|
||||||
|
static void qusb2_phy_set_tune2_param(struct qusb2_phy *qphy)
|
||||||
|
{
|
||||||
|
struct device *dev = &qphy->phy->dev;
|
||||||
|
u8 *val;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read efuse register having TUNE2 parameter's high nibble.
|
||||||
|
* If efuse register shows value as 0x0, or if we fail to find
|
||||||
|
* a valid efuse register settings, then use default value
|
||||||
|
* as 0xB for high nibble that we have already set while
|
||||||
|
* configuring phy.
|
||||||
|
*/
|
||||||
|
val = nvmem_cell_read(qphy->cell, NULL);
|
||||||
|
if (IS_ERR(val) || !val[0]) {
|
||||||
|
dev_dbg(dev, "failed to read a valid hs-tx trim value\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fused TUNE2 value is the higher nibble only */
|
||||||
|
qusb2_setbits(qphy->base, QUSB2PHY_PORT_TUNE2, val[0] << 0x4);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qusb2_phy_poweron(struct phy *phy)
|
||||||
|
{
|
||||||
|
struct qusb2_phy *qphy = phy_get_drvdata(phy);
|
||||||
|
int num = ARRAY_SIZE(qphy->vregs);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
dev_vdbg(&phy->dev, "%s(): Powering-on QUSB2 phy\n", __func__);
|
||||||
|
|
||||||
|
/* turn on regulator supplies */
|
||||||
|
ret = regulator_bulk_enable(num, qphy->vregs);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = clk_prepare_enable(qphy->iface_clk);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&phy->dev, "failed to enable iface_clk, %d\n", ret);
|
||||||
|
regulator_bulk_disable(num, qphy->vregs);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qusb2_phy_poweroff(struct phy *phy)
|
||||||
|
{
|
||||||
|
struct qusb2_phy *qphy = phy_get_drvdata(phy);
|
||||||
|
|
||||||
|
clk_disable_unprepare(qphy->iface_clk);
|
||||||
|
|
||||||
|
regulator_bulk_disable(ARRAY_SIZE(qphy->vregs), qphy->vregs);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qusb2_phy_init(struct phy *phy)
|
||||||
|
{
|
||||||
|
struct qusb2_phy *qphy = phy_get_drvdata(phy);
|
||||||
|
unsigned int val;
|
||||||
|
unsigned int clk_scheme;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
dev_vdbg(&phy->dev, "%s(): Initializing QUSB2 phy\n", __func__);
|
||||||
|
|
||||||
|
/* enable ahb interface clock to program phy */
|
||||||
|
ret = clk_prepare_enable(qphy->cfg_ahb_clk);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&phy->dev, "failed to enable cfg ahb clock, %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Perform phy reset */
|
||||||
|
ret = reset_control_assert(qphy->phy_reset);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&phy->dev, "failed to assert phy_reset, %d\n", ret);
|
||||||
|
goto disable_ahb_clk;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 100 us delay to keep PHY in reset mode */
|
||||||
|
usleep_range(100, 150);
|
||||||
|
|
||||||
|
ret = reset_control_deassert(qphy->phy_reset);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&phy->dev, "failed to de-assert phy_reset, %d\n", ret);
|
||||||
|
goto disable_ahb_clk;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disable the PHY */
|
||||||
|
qusb2_setbits(qphy->base, QUSB2PHY_PORT_POWERDOWN,
|
||||||
|
CLAMP_N_EN | FREEZIO_N | POWER_DOWN);
|
||||||
|
|
||||||
|
/* save reset value to override reference clock scheme later */
|
||||||
|
val = readl(qphy->base + QUSB2PHY_PLL_TEST);
|
||||||
|
|
||||||
|
qcom_qusb2_phy_configure(qphy->base, qphy->cfg->tbl,
|
||||||
|
qphy->cfg->tbl_num);
|
||||||
|
|
||||||
|
/* Set efuse value for tuning the PHY */
|
||||||
|
qusb2_phy_set_tune2_param(qphy);
|
||||||
|
|
||||||
|
/* Enable the PHY */
|
||||||
|
qusb2_clrbits(qphy->base, QUSB2PHY_PORT_POWERDOWN, POWER_DOWN);
|
||||||
|
|
||||||
|
/* Required to get phy pll lock successfully */
|
||||||
|
usleep_range(150, 160);
|
||||||
|
|
||||||
|
/* Default is single-ended clock on msm8996 */
|
||||||
|
qphy->has_se_clk_scheme = true;
|
||||||
|
/*
|
||||||
|
* read TCSR_PHY_CLK_SCHEME register to check if single-ended
|
||||||
|
* clock scheme is selected. If yes, then disable differential
|
||||||
|
* ref_clk and use single-ended clock, otherwise use differential
|
||||||
|
* ref_clk only.
|
||||||
|
*/
|
||||||
|
if (qphy->tcsr) {
|
||||||
|
ret = regmap_read(qphy->tcsr, qphy->cfg->clk_scheme_offset,
|
||||||
|
&clk_scheme);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&phy->dev, "failed to read clk scheme reg\n");
|
||||||
|
goto assert_phy_reset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* is it a differential clock scheme ? */
|
||||||
|
if (!(clk_scheme & PHY_CLK_SCHEME_SEL)) {
|
||||||
|
dev_vdbg(&phy->dev, "%s(): select differential clk\n",
|
||||||
|
__func__);
|
||||||
|
qphy->has_se_clk_scheme = false;
|
||||||
|
} else {
|
||||||
|
dev_vdbg(&phy->dev, "%s(): select single-ended clk\n",
|
||||||
|
__func__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!qphy->has_se_clk_scheme) {
|
||||||
|
val &= ~CLK_REF_SEL;
|
||||||
|
ret = clk_prepare_enable(qphy->ref_clk);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(&phy->dev, "failed to enable ref clk, %d\n",
|
||||||
|
ret);
|
||||||
|
goto assert_phy_reset;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val |= CLK_REF_SEL;
|
||||||
|
}
|
||||||
|
|
||||||
|
writel(val, qphy->base + QUSB2PHY_PLL_TEST);
|
||||||
|
|
||||||
|
/* ensure above write is through */
|
||||||
|
readl(qphy->base + QUSB2PHY_PLL_TEST);
|
||||||
|
|
||||||
|
/* Required to get phy pll lock successfully */
|
||||||
|
usleep_range(100, 110);
|
||||||
|
|
||||||
|
val = readb(qphy->base + QUSB2PHY_PLL_STATUS);
|
||||||
|
if (!(val & PLL_LOCKED)) {
|
||||||
|
dev_err(&phy->dev,
|
||||||
|
"QUSB2PHY pll lock failed: status reg = %x\n", val);
|
||||||
|
ret = -EBUSY;
|
||||||
|
goto disable_ref_clk;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
disable_ref_clk:
|
||||||
|
if (!qphy->has_se_clk_scheme)
|
||||||
|
clk_disable_unprepare(qphy->ref_clk);
|
||||||
|
assert_phy_reset:
|
||||||
|
reset_control_assert(qphy->phy_reset);
|
||||||
|
disable_ahb_clk:
|
||||||
|
clk_disable_unprepare(qphy->cfg_ahb_clk);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int qusb2_phy_exit(struct phy *phy)
|
||||||
|
{
|
||||||
|
struct qusb2_phy *qphy = phy_get_drvdata(phy);
|
||||||
|
|
||||||
|
/* Disable the PHY */
|
||||||
|
qusb2_setbits(qphy->base, QUSB2PHY_PORT_POWERDOWN,
|
||||||
|
CLAMP_N_EN | FREEZIO_N | POWER_DOWN);
|
||||||
|
|
||||||
|
if (!qphy->has_se_clk_scheme)
|
||||||
|
clk_disable_unprepare(qphy->ref_clk);
|
||||||
|
|
||||||
|
reset_control_assert(qphy->phy_reset);
|
||||||
|
|
||||||
|
clk_disable_unprepare(qphy->cfg_ahb_clk);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct phy_ops qusb2_phy_gen_ops = {
|
||||||
|
.init = qusb2_phy_init,
|
||||||
|
.exit = qusb2_phy_exit,
|
||||||
|
.power_on = qusb2_phy_poweron,
|
||||||
|
.power_off = qusb2_phy_poweroff,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct of_device_id qusb2_phy_of_match_table[] = {
|
||||||
|
{
|
||||||
|
.compatible = "qcom,msm8996-qusb2-phy",
|
||||||
|
.data = &msm8996_phy_cfg,
|
||||||
|
},
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, qusb2_phy_of_match_table);
|
||||||
|
|
||||||
|
static int qusb2_phy_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct qusb2_phy *qphy;
|
||||||
|
struct phy_provider *phy_provider;
|
||||||
|
struct phy *generic_phy;
|
||||||
|
struct resource *res;
|
||||||
|
int ret, i;
|
||||||
|
int num;
|
||||||
|
|
||||||
|
qphy = devm_kzalloc(dev, sizeof(*qphy), GFP_KERNEL);
|
||||||
|
if (!qphy)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
qphy->base = devm_ioremap_resource(dev, res);
|
||||||
|
if (IS_ERR(qphy->base))
|
||||||
|
return PTR_ERR(qphy->base);
|
||||||
|
|
||||||
|
qphy->cfg_ahb_clk = devm_clk_get(dev, "cfg_ahb");
|
||||||
|
if (IS_ERR(qphy->cfg_ahb_clk)) {
|
||||||
|
ret = PTR_ERR(qphy->cfg_ahb_clk);
|
||||||
|
if (ret != -EPROBE_DEFER)
|
||||||
|
dev_err(dev, "failed to get cfg ahb clk, %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
qphy->ref_clk = devm_clk_get(dev, "ref");
|
||||||
|
if (IS_ERR(qphy->ref_clk)) {
|
||||||
|
ret = PTR_ERR(qphy->ref_clk);
|
||||||
|
if (ret != -EPROBE_DEFER)
|
||||||
|
dev_err(dev, "failed to get ref clk, %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
qphy->iface_clk = devm_clk_get(dev, "iface");
|
||||||
|
if (IS_ERR(qphy->iface_clk)) {
|
||||||
|
ret = PTR_ERR(qphy->iface_clk);
|
||||||
|
if (ret == -EPROBE_DEFER)
|
||||||
|
return ret;
|
||||||
|
qphy->iface_clk = NULL;
|
||||||
|
dev_dbg(dev, "failed to get iface clk, %d\n", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
qphy->phy_reset = devm_reset_control_get_by_index(&pdev->dev, 0);
|
||||||
|
if (IS_ERR(qphy->phy_reset)) {
|
||||||
|
dev_err(dev, "failed to get phy core reset\n");
|
||||||
|
return PTR_ERR(qphy->phy_reset);
|
||||||
|
}
|
||||||
|
|
||||||
|
num = ARRAY_SIZE(qphy->vregs);
|
||||||
|
for (i = 0; i < num; i++)
|
||||||
|
qphy->vregs[i].supply = qusb2_phy_vreg_names[i];
|
||||||
|
|
||||||
|
ret = devm_regulator_bulk_get(dev, num, qphy->vregs);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "failed to get regulator supplies\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the specific init parameters of QMP phy */
|
||||||
|
qphy->cfg = of_device_get_match_data(dev);
|
||||||
|
|
||||||
|
qphy->tcsr = syscon_regmap_lookup_by_phandle(dev->of_node,
|
||||||
|
"qcom,tcsr-syscon");
|
||||||
|
if (IS_ERR(qphy->tcsr)) {
|
||||||
|
dev_dbg(dev, "failed to lookup TCSR regmap\n");
|
||||||
|
qphy->tcsr = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
qphy->cell = devm_nvmem_cell_get(dev, NULL);
|
||||||
|
if (IS_ERR(qphy->cell)) {
|
||||||
|
if (PTR_ERR(qphy->cell) == -EPROBE_DEFER)
|
||||||
|
return -EPROBE_DEFER;
|
||||||
|
qphy->cell = NULL;
|
||||||
|
dev_dbg(dev, "failed to lookup tune2 hstx trim value\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
generic_phy = devm_phy_create(dev, NULL, &qusb2_phy_gen_ops);
|
||||||
|
if (IS_ERR(generic_phy)) {
|
||||||
|
ret = PTR_ERR(generic_phy);
|
||||||
|
dev_err(dev, "failed to create phy, %d\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
qphy->phy = generic_phy;
|
||||||
|
|
||||||
|
dev_set_drvdata(dev, qphy);
|
||||||
|
phy_set_drvdata(generic_phy, qphy);
|
||||||
|
|
||||||
|
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||||
|
if (!IS_ERR(phy_provider))
|
||||||
|
dev_info(dev, "Registered Qcom-QUSB2 phy\n");
|
||||||
|
|
||||||
|
return PTR_ERR_OR_ZERO(phy_provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver qusb2_phy_driver = {
|
||||||
|
.probe = qusb2_phy_probe,
|
||||||
|
.driver = {
|
||||||
|
.name = "qcom-qusb2-phy",
|
||||||
|
.of_match_table = qusb2_phy_of_match_table,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module_platform_driver(qusb2_phy_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Vivek Gautam <vivek.gautam@codeaurora.org>");
|
||||||
|
MODULE_DESCRIPTION("Qualcomm QUSB2 PHY driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
@ -20,6 +20,7 @@
|
|||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
#include <linux/phy/phy.h>
|
#include <linux/phy/phy.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
|
|
||||||
@ -395,7 +396,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
|
|||||||
struct rcar_gen3_chan *channel;
|
struct rcar_gen3_chan *channel;
|
||||||
struct phy_provider *provider;
|
struct phy_provider *provider;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
int irq;
|
int irq, ret = 0;
|
||||||
|
|
||||||
if (!dev->of_node) {
|
if (!dev->of_node) {
|
||||||
dev_err(dev, "This driver needs device tree\n");
|
dev_err(dev, "This driver needs device tree\n");
|
||||||
@ -434,17 +435,24 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* devm_phy_create() will call pm_runtime_enable(dev); */
|
/*
|
||||||
|
* 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);
|
||||||
channel->phy = devm_phy_create(dev, NULL, &rcar_gen3_phy_usb2_ops);
|
channel->phy = devm_phy_create(dev, NULL, &rcar_gen3_phy_usb2_ops);
|
||||||
if (IS_ERR(channel->phy)) {
|
if (IS_ERR(channel->phy)) {
|
||||||
dev_err(dev, "Failed to create USB2 PHY\n");
|
dev_err(dev, "Failed to create USB2 PHY\n");
|
||||||
return PTR_ERR(channel->phy);
|
ret = PTR_ERR(channel->phy);
|
||||||
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
channel->vbus = devm_regulator_get_optional(dev, "vbus");
|
channel->vbus = devm_regulator_get_optional(dev, "vbus");
|
||||||
if (IS_ERR(channel->vbus)) {
|
if (IS_ERR(channel->vbus)) {
|
||||||
if (PTR_ERR(channel->vbus) == -EPROBE_DEFER)
|
if (PTR_ERR(channel->vbus) == -EPROBE_DEFER) {
|
||||||
return PTR_ERR(channel->vbus);
|
ret = PTR_ERR(channel->vbus);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
channel->vbus = NULL;
|
channel->vbus = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -454,15 +462,22 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev)
|
|||||||
provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||||
if (IS_ERR(provider)) {
|
if (IS_ERR(provider)) {
|
||||||
dev_err(dev, "Failed to register PHY provider\n");
|
dev_err(dev, "Failed to register PHY provider\n");
|
||||||
|
ret = PTR_ERR(provider);
|
||||||
|
goto error;
|
||||||
} else if (channel->has_otg) {
|
} else if (channel->has_otg) {
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = device_create_file(dev, &dev_attr_role);
|
ret = device_create_file(dev, &dev_attr_role);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return PTR_ERR_OR_ZERO(provider);
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
pm_runtime_disable(dev);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rcar_gen3_phy_usb2_remove(struct platform_device *pdev)
|
static int rcar_gen3_phy_usb2_remove(struct platform_device *pdev)
|
||||||
@ -472,6 +487,8 @@ static int rcar_gen3_phy_usb2_remove(struct platform_device *pdev)
|
|||||||
if (channel->has_otg)
|
if (channel->has_otg)
|
||||||
device_remove_file(&pdev->dev, &dev_attr_role);
|
device_remove_file(&pdev->dev, &dev_attr_role);
|
||||||
|
|
||||||
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -554,8 +554,7 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)
|
|||||||
case USB_CHG_STATE_DETECTED:
|
case USB_CHG_STATE_DETECTED:
|
||||||
switch (rphy->chg_type) {
|
switch (rphy->chg_type) {
|
||||||
case POWER_SUPPLY_TYPE_USB:
|
case POWER_SUPPLY_TYPE_USB:
|
||||||
dev_dbg(&rport->phy->dev,
|
dev_dbg(&rport->phy->dev, "sdp cable is connected\n");
|
||||||
"sdp cable is connecetd\n");
|
|
||||||
rockchip_usb2phy_power_on(rport->phy);
|
rockchip_usb2phy_power_on(rport->phy);
|
||||||
rport->state = OTG_STATE_B_PERIPHERAL;
|
rport->state = OTG_STATE_B_PERIPHERAL;
|
||||||
notify_charger = true;
|
notify_charger = true;
|
||||||
@ -563,16 +562,14 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)
|
|||||||
cable = EXTCON_CHG_USB_SDP;
|
cable = EXTCON_CHG_USB_SDP;
|
||||||
break;
|
break;
|
||||||
case POWER_SUPPLY_TYPE_USB_DCP:
|
case POWER_SUPPLY_TYPE_USB_DCP:
|
||||||
dev_dbg(&rport->phy->dev,
|
dev_dbg(&rport->phy->dev, "dcp cable is connected\n");
|
||||||
"dcp cable is connecetd\n");
|
|
||||||
rockchip_usb2phy_power_off(rport->phy);
|
rockchip_usb2phy_power_off(rport->phy);
|
||||||
notify_charger = true;
|
notify_charger = true;
|
||||||
sch_work = true;
|
sch_work = true;
|
||||||
cable = EXTCON_CHG_USB_DCP;
|
cable = EXTCON_CHG_USB_DCP;
|
||||||
break;
|
break;
|
||||||
case POWER_SUPPLY_TYPE_USB_CDP:
|
case POWER_SUPPLY_TYPE_USB_CDP:
|
||||||
dev_dbg(&rport->phy->dev,
|
dev_dbg(&rport->phy->dev, "cdp cable is connected\n");
|
||||||
"cdp cable is connecetd\n");
|
|
||||||
rockchip_usb2phy_power_on(rport->phy);
|
rockchip_usb2phy_power_on(rport->phy);
|
||||||
rport->state = OTG_STATE_B_PERIPHERAL;
|
rport->state = OTG_STATE_B_PERIPHERAL;
|
||||||
notify_charger = true;
|
notify_charger = true;
|
||||||
@ -1141,6 +1138,49 @@ disable_clks:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct rockchip_usb2phy_cfg rk3328_phy_cfgs[] = {
|
||||||
|
{
|
||||||
|
.reg = 0x100,
|
||||||
|
.num_ports = 2,
|
||||||
|
.clkout_ctl = { 0x108, 4, 4, 1, 0 },
|
||||||
|
.port_cfgs = {
|
||||||
|
[USB2PHY_PORT_OTG] = {
|
||||||
|
.phy_sus = { 0x0100, 15, 0, 0, 0x1d1 },
|
||||||
|
.bvalid_det_en = { 0x0110, 2, 2, 0, 1 },
|
||||||
|
.bvalid_det_st = { 0x0114, 2, 2, 0, 1 },
|
||||||
|
.bvalid_det_clr = { 0x0118, 2, 2, 0, 1 },
|
||||||
|
.ls_det_en = { 0x0110, 0, 0, 0, 1 },
|
||||||
|
.ls_det_st = { 0x0114, 0, 0, 0, 1 },
|
||||||
|
.ls_det_clr = { 0x0118, 0, 0, 0, 1 },
|
||||||
|
.utmi_avalid = { 0x0120, 10, 10, 0, 1 },
|
||||||
|
.utmi_bvalid = { 0x0120, 9, 9, 0, 1 },
|
||||||
|
.utmi_ls = { 0x0120, 5, 4, 0, 1 },
|
||||||
|
},
|
||||||
|
[USB2PHY_PORT_HOST] = {
|
||||||
|
.phy_sus = { 0x104, 15, 0, 0, 0x1d1 },
|
||||||
|
.ls_det_en = { 0x110, 1, 1, 0, 1 },
|
||||||
|
.ls_det_st = { 0x114, 1, 1, 0, 1 },
|
||||||
|
.ls_det_clr = { 0x118, 1, 1, 0, 1 },
|
||||||
|
.utmi_ls = { 0x120, 17, 16, 0, 1 },
|
||||||
|
.utmi_hstdet = { 0x120, 19, 19, 0, 1 }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.chg_det = {
|
||||||
|
.opmode = { 0x0100, 3, 0, 5, 1 },
|
||||||
|
.cp_det = { 0x0120, 24, 24, 0, 1 },
|
||||||
|
.dcp_det = { 0x0120, 23, 23, 0, 1 },
|
||||||
|
.dp_det = { 0x0120, 25, 25, 0, 1 },
|
||||||
|
.idm_sink_en = { 0x0108, 8, 8, 0, 1 },
|
||||||
|
.idp_sink_en = { 0x0108, 7, 7, 0, 1 },
|
||||||
|
.idp_src_en = { 0x0108, 9, 9, 0, 1 },
|
||||||
|
.rdm_pdwn_en = { 0x0108, 10, 10, 0, 1 },
|
||||||
|
.vdm_src_en = { 0x0108, 12, 12, 0, 1 },
|
||||||
|
.vdp_src_en = { 0x0108, 11, 11, 0, 1 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ /* sentinel */ }
|
||||||
|
};
|
||||||
|
|
||||||
static const struct rockchip_usb2phy_cfg rk3366_phy_cfgs[] = {
|
static const struct rockchip_usb2phy_cfg rk3366_phy_cfgs[] = {
|
||||||
{
|
{
|
||||||
.reg = 0x700,
|
.reg = 0x700,
|
||||||
@ -1223,6 +1263,7 @@ static const struct rockchip_usb2phy_cfg rk3399_phy_cfgs[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const struct of_device_id rockchip_usb2phy_dt_match[] = {
|
static const struct of_device_id rockchip_usb2phy_dt_match[] = {
|
||||||
|
{ .compatible = "rockchip,rk3328-usb2phy", .data = &rk3328_phy_cfgs },
|
||||||
{ .compatible = "rockchip,rk3366-usb2phy", .data = &rk3366_phy_cfgs },
|
{ .compatible = "rockchip,rk3366-usb2phy", .data = &rk3366_phy_cfgs },
|
||||||
{ .compatible = "rockchip,rk3399-usb2phy", .data = &rk3399_phy_cfgs },
|
{ .compatible = "rockchip,rk3399-usb2phy", .data = &rk3399_phy_cfgs },
|
||||||
{}
|
{}
|
||||||
|
@ -66,6 +66,7 @@ struct rockchip_usb_phy {
|
|||||||
struct phy *phy;
|
struct phy *phy;
|
||||||
bool uart_enabled;
|
bool uart_enabled;
|
||||||
struct reset_control *reset;
|
struct reset_control *reset;
|
||||||
|
struct regulator *vbus;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int rockchip_usb_phy_power(struct rockchip_usb_phy *phy,
|
static int rockchip_usb_phy_power(struct rockchip_usb_phy *phy,
|
||||||
@ -88,6 +89,9 @@ static void rockchip_usb_phy480m_disable(struct clk_hw *hw)
|
|||||||
struct rockchip_usb_phy,
|
struct rockchip_usb_phy,
|
||||||
clk480m_hw);
|
clk480m_hw);
|
||||||
|
|
||||||
|
if (phy->vbus)
|
||||||
|
regulator_disable(phy->vbus);
|
||||||
|
|
||||||
/* Power down usb phy analog blocks by set siddq 1 */
|
/* Power down usb phy analog blocks by set siddq 1 */
|
||||||
rockchip_usb_phy_power(phy, 1);
|
rockchip_usb_phy_power(phy, 1);
|
||||||
}
|
}
|
||||||
@ -143,6 +147,14 @@ static int rockchip_usb_phy_power_on(struct phy *_phy)
|
|||||||
if (phy->uart_enabled)
|
if (phy->uart_enabled)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
|
|
||||||
|
if (phy->vbus) {
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = regulator_enable(phy->vbus);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
return clk_prepare_enable(phy->clk480m);
|
return clk_prepare_enable(phy->clk480m);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,6 +280,13 @@ static int rockchip_usb_phy_init(struct rockchip_usb_phy_base *base,
|
|||||||
}
|
}
|
||||||
phy_set_drvdata(rk_phy->phy, rk_phy);
|
phy_set_drvdata(rk_phy->phy, rk_phy);
|
||||||
|
|
||||||
|
rk_phy->vbus = devm_regulator_get_optional(&rk_phy->phy->dev, "vbus");
|
||||||
|
if (IS_ERR(rk_phy->vbus)) {
|
||||||
|
if (PTR_ERR(rk_phy->vbus) == -EPROBE_DEFER)
|
||||||
|
return PTR_ERR(rk_phy->vbus);
|
||||||
|
rk_phy->vbus = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When acting as uart-pipe, just keep clock on otherwise
|
* When acting as uart-pipe, just keep clock on otherwise
|
||||||
* only power up usb phy when it use, so disable it when init
|
* only power up usb phy when it use, so disable it when init
|
||||||
|
@ -49,12 +49,14 @@
|
|||||||
#define REG_PHYBIST 0x08
|
#define REG_PHYBIST 0x08
|
||||||
#define REG_PHYTUNE 0x0c
|
#define REG_PHYTUNE 0x0c
|
||||||
#define REG_PHYCTL_A33 0x10
|
#define REG_PHYCTL_A33 0x10
|
||||||
#define REG_PHY_UNK_H3 0x20
|
#define REG_PHY_OTGCTL 0x20
|
||||||
|
|
||||||
#define REG_PMU_UNK1 0x10
|
#define REG_PMU_UNK1 0x10
|
||||||
|
|
||||||
#define PHYCTL_DATA BIT(7)
|
#define PHYCTL_DATA BIT(7)
|
||||||
|
|
||||||
|
#define OTGCTL_ROUTE_MUSB BIT(0)
|
||||||
|
|
||||||
#define SUNXI_AHB_ICHR8_EN BIT(10)
|
#define SUNXI_AHB_ICHR8_EN BIT(10)
|
||||||
#define SUNXI_AHB_INCR4_BURST_EN BIT(9)
|
#define SUNXI_AHB_INCR4_BURST_EN BIT(9)
|
||||||
#define SUNXI_AHB_INCRX_ALIGN_EN BIT(8)
|
#define SUNXI_AHB_INCRX_ALIGN_EN BIT(8)
|
||||||
@ -110,6 +112,7 @@ struct sun4i_usb_phy_cfg {
|
|||||||
u8 phyctl_offset;
|
u8 phyctl_offset;
|
||||||
bool dedicated_clocks;
|
bool dedicated_clocks;
|
||||||
bool enable_pmu_unk1;
|
bool enable_pmu_unk1;
|
||||||
|
bool phy0_dual_route;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sun4i_usb_phy_data {
|
struct sun4i_usb_phy_data {
|
||||||
@ -188,10 +191,8 @@ static void sun4i_usb_phy_write(struct sun4i_usb_phy *phy, u32 addr, u32 data,
|
|||||||
|
|
||||||
spin_lock_irqsave(&phy_data->reg_lock, flags);
|
spin_lock_irqsave(&phy_data->reg_lock, flags);
|
||||||
|
|
||||||
if (phy_data->cfg->type == sun8i_a33_phy ||
|
if (phy_data->cfg->phyctl_offset == REG_PHYCTL_A33) {
|
||||||
phy_data->cfg->type == sun50i_a64_phy ||
|
/* SoCs newer than A33 need us to set phyctl to 0 explicitly */
|
||||||
phy_data->cfg->type == sun8i_v3s_phy) {
|
|
||||||
/* A33 or A64 needs us to set phyctl to 0 explicitly */
|
|
||||||
writel(0, phyctl);
|
writel(0, phyctl);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -271,23 +272,16 @@ static int sun4i_usb_phy_init(struct phy *_phy)
|
|||||||
writel(val & ~2, phy->pmu + REG_PMU_UNK1);
|
writel(val & ~2, phy->pmu + REG_PMU_UNK1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data->cfg->type == sun8i_h3_phy) {
|
/* Enable USB 45 Ohm resistor calibration */
|
||||||
if (phy->index == 0) {
|
if (phy->index == 0)
|
||||||
val = readl(data->base + REG_PHY_UNK_H3);
|
sun4i_usb_phy_write(phy, PHY_RES45_CAL_EN, 0x01, 1);
|
||||||
writel(val & ~1, data->base + REG_PHY_UNK_H3);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* Enable USB 45 Ohm resistor calibration */
|
|
||||||
if (phy->index == 0)
|
|
||||||
sun4i_usb_phy_write(phy, PHY_RES45_CAL_EN, 0x01, 1);
|
|
||||||
|
|
||||||
/* Adjust PHY's magnitude and rate */
|
/* Adjust PHY's magnitude and rate */
|
||||||
sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE, 0x14, 5);
|
sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE, 0x14, 5);
|
||||||
|
|
||||||
/* Disconnect threshold adjustment */
|
/* Disconnect threshold adjustment */
|
||||||
sun4i_usb_phy_write(phy, PHY_DISCON_TH_SEL,
|
sun4i_usb_phy_write(phy, PHY_DISCON_TH_SEL,
|
||||||
data->cfg->disc_thresh, 2);
|
data->cfg->disc_thresh, 2);
|
||||||
}
|
|
||||||
|
|
||||||
sun4i_usb_phy_passby(phy, 1);
|
sun4i_usb_phy_passby(phy, 1);
|
||||||
|
|
||||||
@ -486,6 +480,21 @@ static const struct phy_ops sun4i_usb_phy_ops = {
|
|||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void sun4i_usb_phy0_reroute(struct sun4i_usb_phy_data *data, int id_det)
|
||||||
|
{
|
||||||
|
u32 regval;
|
||||||
|
|
||||||
|
regval = readl(data->base + REG_PHY_OTGCTL);
|
||||||
|
if (id_det == 0) {
|
||||||
|
/* Host mode. Route phy0 to EHCI/OHCI */
|
||||||
|
regval &= ~OTGCTL_ROUTE_MUSB;
|
||||||
|
} else {
|
||||||
|
/* Peripheral mode. Route phy0 to MUSB */
|
||||||
|
regval |= OTGCTL_ROUTE_MUSB;
|
||||||
|
}
|
||||||
|
writel(regval, data->base + REG_PHY_OTGCTL);
|
||||||
|
}
|
||||||
|
|
||||||
static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work)
|
static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct sun4i_usb_phy_data *data =
|
struct sun4i_usb_phy_data *data =
|
||||||
@ -546,6 +555,10 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work)
|
|||||||
sun4i_usb_phy0_set_vbus_detect(phy0, 1);
|
sun4i_usb_phy0_set_vbus_detect(phy0, 1);
|
||||||
mutex_unlock(&phy0->mutex);
|
mutex_unlock(&phy0->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Re-route PHY0 if necessary */
|
||||||
|
if (data->cfg->phy0_dual_route)
|
||||||
|
sun4i_usb_phy0_reroute(data, id_det);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vbus_notify)
|
if (vbus_notify)
|
||||||
@ -700,7 +713,7 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
|
|||||||
return PTR_ERR(phy->reset);
|
return PTR_ERR(phy->reset);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i) { /* No pmu for usbc0 */
|
if (i || data->cfg->phy0_dual_route) { /* No pmu for musb */
|
||||||
snprintf(name, sizeof(name), "pmu%d", i);
|
snprintf(name, sizeof(name), "pmu%d", i);
|
||||||
res = platform_get_resource_byname(pdev,
|
res = platform_get_resource_byname(pdev,
|
||||||
IORESOURCE_MEM, name);
|
IORESOURCE_MEM, name);
|
||||||
@ -823,8 +836,10 @@ static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = {
|
|||||||
.num_phys = 4,
|
.num_phys = 4,
|
||||||
.type = sun8i_h3_phy,
|
.type = sun8i_h3_phy,
|
||||||
.disc_thresh = 3,
|
.disc_thresh = 3,
|
||||||
|
.phyctl_offset = REG_PHYCTL_A33,
|
||||||
.dedicated_clocks = true,
|
.dedicated_clocks = true,
|
||||||
.enable_pmu_unk1 = true,
|
.enable_pmu_unk1 = true,
|
||||||
|
.phy0_dual_route = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct sun4i_usb_phy_cfg sun8i_v3s_cfg = {
|
static const struct sun4i_usb_phy_cfg sun8i_v3s_cfg = {
|
||||||
@ -843,6 +858,7 @@ static const struct sun4i_usb_phy_cfg sun50i_a64_cfg = {
|
|||||||
.phyctl_offset = REG_PHYCTL_A33,
|
.phyctl_offset = REG_PHYCTL_A33,
|
||||||
.dedicated_clocks = true,
|
.dedicated_clocks = true,
|
||||||
.enable_pmu_unk1 = true,
|
.enable_pmu_unk1 = true,
|
||||||
|
.phy0_dual_route = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct of_device_id sun4i_usb_phy_of_match[] = {
|
static const struct of_device_id sun4i_usb_phy_of_match[] = {
|
||||||
|
@ -104,4 +104,6 @@ source "drivers/staging/vc04_services/Kconfig"
|
|||||||
|
|
||||||
source "drivers/staging/bcm2835-audio/Kconfig"
|
source "drivers/staging/bcm2835-audio/Kconfig"
|
||||||
|
|
||||||
|
source "drivers/staging/typec/Kconfig"
|
||||||
|
|
||||||
endif # STAGING
|
endif # STAGING
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
# 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/
|
||||||
@ -41,4 +42,3 @@ obj-$(CONFIG_KS7010) += ks7010/
|
|||||||
obj-$(CONFIG_GREYBUS) += greybus/
|
obj-$(CONFIG_GREYBUS) += greybus/
|
||||||
obj-$(CONFIG_BCM2835_VCHIQ) += vc04_services/
|
obj-$(CONFIG_BCM2835_VCHIQ) += vc04_services/
|
||||||
obj-$(CONFIG_SND_BCM2835) += bcm2835-audio/
|
obj-$(CONFIG_SND_BCM2835) += bcm2835-audio/
|
||||||
|
|
||||||
|
24
drivers/staging/typec/Kconfig
Normal file
24
drivers/staging/typec/Kconfig
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
menu "USB Power Delivery and Type-C drivers"
|
||||||
|
|
||||||
|
config TYPEC_TCPM
|
||||||
|
tristate "USB Type-C Port Controller Manager"
|
||||||
|
depends on USB
|
||||||
|
select TYPEC
|
||||||
|
help
|
||||||
|
The Type-C Port Controller Manager provides a USB PD and USB Type-C
|
||||||
|
state machine for use with Type-C Port Controllers.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
source "drivers/staging/typec/fusb302/Kconfig"
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
endmenu
|
3
drivers/staging/typec/Makefile
Normal file
3
drivers/staging/typec/Makefile
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
obj-$(CONFIG_TYPEC_TCPM) += tcpm.o
|
||||||
|
obj-$(CONFIG_TYPEC_TCPCI) += tcpci.o
|
||||||
|
obj-y += fusb302/
|
15
drivers/staging/typec/TODO
Normal file
15
drivers/staging/typec/TODO
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
tcpm:
|
||||||
|
- Add documentation (at the very least for the API to low level drivers)
|
||||||
|
- Split PD code into separate file
|
||||||
|
- Check if it makes sense to use tracepoints instead of debugfs for debug logs
|
||||||
|
- Implement Alternate Mode handling
|
||||||
|
- Address "#if 0" code if not addressed with the above
|
||||||
|
- Validate all comments marked with "XXX"; either address or remove comments
|
||||||
|
- Add support for USB PD 3.0. While not mandatory, at least fast role swap
|
||||||
|
as well as authentication support would be very desirable.
|
||||||
|
|
||||||
|
tcpci:
|
||||||
|
- Test with real hardware
|
||||||
|
|
||||||
|
Please send patches to Guenter Roeck <linux@roeck-us.net> and copy
|
||||||
|
Heikki Krogerus <heikki.krogerus@linux.intel.com>.
|
7
drivers/staging/typec/fusb302/Kconfig
Normal file
7
drivers/staging/typec/fusb302/Kconfig
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
config TYPEC_FUSB302
|
||||||
|
tristate "Fairchild FUSB302 Type-C chip driver"
|
||||||
|
depends on I2C
|
||||||
|
help
|
||||||
|
The Fairchild FUSB302 Type-C chip driver that works with
|
||||||
|
Type-C Port Controller Manager to provide USB PD and USB
|
||||||
|
Type-C functionalities.
|
1
drivers/staging/typec/fusb302/Makefile
Normal file
1
drivers/staging/typec/fusb302/Makefile
Normal file
@ -0,0 +1 @@
|
|||||||
|
obj-$(CONFIG_TYPEC_FUSB302) += fusb302.o
|
6
drivers/staging/typec/fusb302/TODO
Normal file
6
drivers/staging/typec/fusb302/TODO
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
fusb302:
|
||||||
|
- Find a better logging scheme, at least not having the same debugging/logging
|
||||||
|
code replicated here and in tcpm
|
||||||
|
- Find a non-hacky way to coordinate between PM and I2C access
|
||||||
|
- Documentation? The FUSB302 datasheet provides information on the chip to help
|
||||||
|
understand the code. But it may still be helpful to have a documentation.
|
1815
drivers/staging/typec/fusb302/fusb302.c
Normal file
1815
drivers/staging/typec/fusb302/fusb302.c
Normal file
File diff suppressed because it is too large
Load Diff
186
drivers/staging/typec/fusb302/fusb302_reg.h
Normal file
186
drivers/staging/typec/fusb302/fusb302_reg.h
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2016-2017 Google, Inc
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* Fairchild FUSB302 Type-C Chip Driver
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FUSB302_REG_H
|
||||||
|
#define FUSB302_REG_H
|
||||||
|
|
||||||
|
#define FUSB_REG_DEVICE_ID 0x01
|
||||||
|
#define FUSB_REG_SWITCHES0 0x02
|
||||||
|
#define FUSB_REG_SWITCHES0_CC2_PU_EN BIT(7)
|
||||||
|
#define FUSB_REG_SWITCHES0_CC1_PU_EN BIT(6)
|
||||||
|
#define FUSB_REG_SWITCHES0_VCONN_CC2 BIT(5)
|
||||||
|
#define FUSB_REG_SWITCHES0_VCONN_CC1 BIT(4)
|
||||||
|
#define FUSB_REG_SWITCHES0_MEAS_CC2 BIT(3)
|
||||||
|
#define FUSB_REG_SWITCHES0_MEAS_CC1 BIT(2)
|
||||||
|
#define FUSB_REG_SWITCHES0_CC2_PD_EN BIT(1)
|
||||||
|
#define FUSB_REG_SWITCHES0_CC1_PD_EN BIT(0)
|
||||||
|
#define FUSB_REG_SWITCHES1 0x03
|
||||||
|
#define FUSB_REG_SWITCHES1_POWERROLE BIT(7)
|
||||||
|
#define FUSB_REG_SWITCHES1_SPECREV1 BIT(6)
|
||||||
|
#define FUSB_REG_SWITCHES1_SPECREV0 BIT(5)
|
||||||
|
#define FUSB_REG_SWITCHES1_DATAROLE BIT(4)
|
||||||
|
#define FUSB_REG_SWITCHES1_AUTO_GCRC BIT(2)
|
||||||
|
#define FUSB_REG_SWITCHES1_TXCC2_EN BIT(1)
|
||||||
|
#define FUSB_REG_SWITCHES1_TXCC1_EN BIT(0)
|
||||||
|
#define FUSB_REG_MEASURE 0x04
|
||||||
|
#define FUSB_REG_MEASURE_MDAC5 BIT(7)
|
||||||
|
#define FUSB_REG_MEASURE_MDAC4 BIT(6)
|
||||||
|
#define FUSB_REG_MEASURE_MDAC3 BIT(5)
|
||||||
|
#define FUSB_REG_MEASURE_MDAC2 BIT(4)
|
||||||
|
#define FUSB_REG_MEASURE_MDAC1 BIT(3)
|
||||||
|
#define FUSB_REG_MEASURE_MDAC0 BIT(2)
|
||||||
|
#define FUSB_REG_MEASURE_VBUS BIT(1)
|
||||||
|
#define FUSB_REG_MEASURE_XXXX5 BIT(0)
|
||||||
|
#define FUSB_REG_CONTROL0 0x06
|
||||||
|
#define FUSB_REG_CONTROL0_TX_FLUSH BIT(6)
|
||||||
|
#define FUSB_REG_CONTROL0_INT_MASK BIT(5)
|
||||||
|
#define FUSB_REG_CONTROL0_HOST_CUR_MASK (0xC)
|
||||||
|
#define FUSB_REG_CONTROL0_HOST_CUR_HIGH (0xC)
|
||||||
|
#define FUSB_REG_CONTROL0_HOST_CUR_MED (0x8)
|
||||||
|
#define FUSB_REG_CONTROL0_HOST_CUR_DEF (0x4)
|
||||||
|
#define FUSB_REG_CONTROL0_TX_START BIT(0)
|
||||||
|
#define FUSB_REG_CONTROL1 0x07
|
||||||
|
#define FUSB_REG_CONTROL1_ENSOP2DB BIT(6)
|
||||||
|
#define FUSB_REG_CONTROL1_ENSOP1DB BIT(5)
|
||||||
|
#define FUSB_REG_CONTROL1_BIST_MODE2 BIT(4)
|
||||||
|
#define FUSB_REG_CONTROL1_RX_FLUSH BIT(2)
|
||||||
|
#define FUSB_REG_CONTROL1_ENSOP2 BIT(1)
|
||||||
|
#define FUSB_REG_CONTROL1_ENSOP1 BIT(0)
|
||||||
|
#define FUSB_REG_CONTROL2 0x08
|
||||||
|
#define FUSB_REG_CONTROL2_MODE BIT(1)
|
||||||
|
#define FUSB_REG_CONTROL2_MODE_MASK (0x6)
|
||||||
|
#define FUSB_REG_CONTROL2_MODE_DFP (0x6)
|
||||||
|
#define FUSB_REG_CONTROL2_MODE_UFP (0x4)
|
||||||
|
#define FUSB_REG_CONTROL2_MODE_DRP (0x2)
|
||||||
|
#define FUSB_REG_CONTROL2_MODE_NONE (0x0)
|
||||||
|
#define FUSB_REG_CONTROL2_TOGGLE BIT(0)
|
||||||
|
#define FUSB_REG_CONTROL3 0x09
|
||||||
|
#define FUSB_REG_CONTROL3_SEND_HARDRESET BIT(6)
|
||||||
|
#define FUSB_REG_CONTROL3_BIST_TMODE BIT(5) /* 302B Only */
|
||||||
|
#define FUSB_REG_CONTROL3_AUTO_HARDRESET BIT(4)
|
||||||
|
#define FUSB_REG_CONTROL3_AUTO_SOFTRESET BIT(3)
|
||||||
|
#define FUSB_REG_CONTROL3_N_RETRIES BIT(1)
|
||||||
|
#define FUSB_REG_CONTROL3_N_RETRIES_MASK (0x6)
|
||||||
|
#define FUSB_REG_CONTROL3_N_RETRIES_3 (0x6)
|
||||||
|
#define FUSB_REG_CONTROL3_N_RETRIES_2 (0x4)
|
||||||
|
#define FUSB_REG_CONTROL3_N_RETRIES_1 (0x2)
|
||||||
|
#define FUSB_REG_CONTROL3_AUTO_RETRY BIT(0)
|
||||||
|
#define FUSB_REG_MASK 0x0A
|
||||||
|
#define FUSB_REG_MASK_VBUSOK BIT(7)
|
||||||
|
#define FUSB_REG_MASK_ACTIVITY BIT(6)
|
||||||
|
#define FUSB_REG_MASK_COMP_CHNG BIT(5)
|
||||||
|
#define FUSB_REG_MASK_CRC_CHK BIT(4)
|
||||||
|
#define FUSB_REG_MASK_ALERT BIT(3)
|
||||||
|
#define FUSB_REG_MASK_WAKE BIT(2)
|
||||||
|
#define FUSB_REG_MASK_COLLISION BIT(1)
|
||||||
|
#define FUSB_REG_MASK_BC_LVL BIT(0)
|
||||||
|
#define FUSB_REG_POWER 0x0B
|
||||||
|
#define FUSB_REG_POWER_PWR BIT(0)
|
||||||
|
#define FUSB_REG_POWER_PWR_LOW 0x1
|
||||||
|
#define FUSB_REG_POWER_PWR_MEDIUM 0x3
|
||||||
|
#define FUSB_REG_POWER_PWR_HIGH 0x7
|
||||||
|
#define FUSB_REG_POWER_PWR_ALL 0xF
|
||||||
|
#define FUSB_REG_RESET 0x0C
|
||||||
|
#define FUSB_REG_RESET_PD_RESET BIT(1)
|
||||||
|
#define FUSB_REG_RESET_SW_RESET BIT(0)
|
||||||
|
#define FUSB_REG_MASKA 0x0E
|
||||||
|
#define FUSB_REG_MASKA_OCP_TEMP BIT(7)
|
||||||
|
#define FUSB_REG_MASKA_TOGDONE BIT(6)
|
||||||
|
#define FUSB_REG_MASKA_SOFTFAIL BIT(5)
|
||||||
|
#define FUSB_REG_MASKA_RETRYFAIL BIT(4)
|
||||||
|
#define FUSB_REG_MASKA_HARDSENT BIT(3)
|
||||||
|
#define FUSB_REG_MASKA_TX_SUCCESS BIT(2)
|
||||||
|
#define FUSB_REG_MASKA_SOFTRESET BIT(1)
|
||||||
|
#define FUSB_REG_MASKA_HARDRESET BIT(0)
|
||||||
|
#define FUSB_REG_MASKB 0x0F
|
||||||
|
#define FUSB_REG_MASKB_GCRCSENT BIT(0)
|
||||||
|
#define FUSB_REG_STATUS0A 0x3C
|
||||||
|
#define FUSB_REG_STATUS0A_SOFTFAIL BIT(5)
|
||||||
|
#define FUSB_REG_STATUS0A_RETRYFAIL BIT(4)
|
||||||
|
#define FUSB_REG_STATUS0A_POWER BIT(2)
|
||||||
|
#define FUSB_REG_STATUS0A_RX_SOFT_RESET BIT(1)
|
||||||
|
#define FUSB_REG_STATUS0A_RX_HARD_RESET BIT(0)
|
||||||
|
#define FUSB_REG_STATUS1A 0x3D
|
||||||
|
#define FUSB_REG_STATUS1A_TOGSS BIT(3)
|
||||||
|
#define FUSB_REG_STATUS1A_TOGSS_RUNNING 0x0
|
||||||
|
#define FUSB_REG_STATUS1A_TOGSS_SRC1 0x1
|
||||||
|
#define FUSB_REG_STATUS1A_TOGSS_SRC2 0x2
|
||||||
|
#define FUSB_REG_STATUS1A_TOGSS_SNK1 0x5
|
||||||
|
#define FUSB_REG_STATUS1A_TOGSS_SNK2 0x6
|
||||||
|
#define FUSB_REG_STATUS1A_TOGSS_AA 0x7
|
||||||
|
#define FUSB_REG_STATUS1A_TOGSS_POS (3)
|
||||||
|
#define FUSB_REG_STATUS1A_TOGSS_MASK (0x7)
|
||||||
|
#define FUSB_REG_STATUS1A_RXSOP2DB BIT(2)
|
||||||
|
#define FUSB_REG_STATUS1A_RXSOP1DB BIT(1)
|
||||||
|
#define FUSB_REG_STATUS1A_RXSOP BIT(0)
|
||||||
|
#define FUSB_REG_INTERRUPTA 0x3E
|
||||||
|
#define FUSB_REG_INTERRUPTA_OCP_TEMP BIT(7)
|
||||||
|
#define FUSB_REG_INTERRUPTA_TOGDONE BIT(6)
|
||||||
|
#define FUSB_REG_INTERRUPTA_SOFTFAIL BIT(5)
|
||||||
|
#define FUSB_REG_INTERRUPTA_RETRYFAIL BIT(4)
|
||||||
|
#define FUSB_REG_INTERRUPTA_HARDSENT BIT(3)
|
||||||
|
#define FUSB_REG_INTERRUPTA_TX_SUCCESS BIT(2)
|
||||||
|
#define FUSB_REG_INTERRUPTA_SOFTRESET BIT(1)
|
||||||
|
#define FUSB_REG_INTERRUPTA_HARDRESET BIT(0)
|
||||||
|
#define FUSB_REG_INTERRUPTB 0x3F
|
||||||
|
#define FUSB_REG_INTERRUPTB_GCRCSENT BIT(0)
|
||||||
|
#define FUSB_REG_STATUS0 0x40
|
||||||
|
#define FUSB_REG_STATUS0_VBUSOK BIT(7)
|
||||||
|
#define FUSB_REG_STATUS0_ACTIVITY BIT(6)
|
||||||
|
#define FUSB_REG_STATUS0_COMP BIT(5)
|
||||||
|
#define FUSB_REG_STATUS0_CRC_CHK BIT(4)
|
||||||
|
#define FUSB_REG_STATUS0_ALERT BIT(3)
|
||||||
|
#define FUSB_REG_STATUS0_WAKE BIT(2)
|
||||||
|
#define FUSB_REG_STATUS0_BC_LVL_MASK 0x03
|
||||||
|
#define FUSB_REG_STATUS0_BC_LVL_0_200 0x0
|
||||||
|
#define FUSB_REG_STATUS0_BC_LVL_200_600 0x1
|
||||||
|
#define FUSB_REG_STATUS0_BC_LVL_600_1230 0x2
|
||||||
|
#define FUSB_REG_STATUS0_BC_LVL_1230_MAX 0x3
|
||||||
|
#define FUSB_REG_STATUS0_BC_LVL1 BIT(1)
|
||||||
|
#define FUSB_REG_STATUS0_BC_LVL0 BIT(0)
|
||||||
|
#define FUSB_REG_STATUS1 0x41
|
||||||
|
#define FUSB_REG_STATUS1_RXSOP2 BIT(7)
|
||||||
|
#define FUSB_REG_STATUS1_RXSOP1 BIT(6)
|
||||||
|
#define FUSB_REG_STATUS1_RX_EMPTY BIT(5)
|
||||||
|
#define FUSB_REG_STATUS1_RX_FULL BIT(4)
|
||||||
|
#define FUSB_REG_STATUS1_TX_EMPTY BIT(3)
|
||||||
|
#define FUSB_REG_STATUS1_TX_FULL BIT(2)
|
||||||
|
#define FUSB_REG_INTERRUPT 0x42
|
||||||
|
#define FUSB_REG_INTERRUPT_VBUSOK BIT(7)
|
||||||
|
#define FUSB_REG_INTERRUPT_ACTIVITY BIT(6)
|
||||||
|
#define FUSB_REG_INTERRUPT_COMP_CHNG BIT(5)
|
||||||
|
#define FUSB_REG_INTERRUPT_CRC_CHK BIT(4)
|
||||||
|
#define FUSB_REG_INTERRUPT_ALERT BIT(3)
|
||||||
|
#define FUSB_REG_INTERRUPT_WAKE BIT(2)
|
||||||
|
#define FUSB_REG_INTERRUPT_COLLISION BIT(1)
|
||||||
|
#define FUSB_REG_INTERRUPT_BC_LVL BIT(0)
|
||||||
|
#define FUSB_REG_FIFOS 0x43
|
||||||
|
|
||||||
|
/* Tokens defined for the FUSB302 TX FIFO */
|
||||||
|
enum fusb302_txfifo_tokens {
|
||||||
|
FUSB302_TKN_TXON = 0xA1,
|
||||||
|
FUSB302_TKN_SYNC1 = 0x12,
|
||||||
|
FUSB302_TKN_SYNC2 = 0x13,
|
||||||
|
FUSB302_TKN_SYNC3 = 0x1B,
|
||||||
|
FUSB302_TKN_RST1 = 0x15,
|
||||||
|
FUSB302_TKN_RST2 = 0x16,
|
||||||
|
FUSB302_TKN_PACKSYM = 0x80,
|
||||||
|
FUSB302_TKN_JAMCRC = 0xFF,
|
||||||
|
FUSB302_TKN_EOP = 0x14,
|
||||||
|
FUSB302_TKN_TXOFF = 0xFE,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
281
drivers/staging/typec/pd.h
Normal file
281
drivers/staging/typec/pd.h
Normal file
@ -0,0 +1,281 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015-2017 Google, Inc
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LINUX_USB_PD_H
|
||||||
|
#define __LINUX_USB_PD_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
#include <linux/usb/typec.h>
|
||||||
|
|
||||||
|
/* USB PD Messages */
|
||||||
|
enum pd_ctrl_msg_type {
|
||||||
|
/* 0 Reserved */
|
||||||
|
PD_CTRL_GOOD_CRC = 1,
|
||||||
|
PD_CTRL_GOTO_MIN = 2,
|
||||||
|
PD_CTRL_ACCEPT = 3,
|
||||||
|
PD_CTRL_REJECT = 4,
|
||||||
|
PD_CTRL_PING = 5,
|
||||||
|
PD_CTRL_PS_RDY = 6,
|
||||||
|
PD_CTRL_GET_SOURCE_CAP = 7,
|
||||||
|
PD_CTRL_GET_SINK_CAP = 8,
|
||||||
|
PD_CTRL_DR_SWAP = 9,
|
||||||
|
PD_CTRL_PR_SWAP = 10,
|
||||||
|
PD_CTRL_VCONN_SWAP = 11,
|
||||||
|
PD_CTRL_WAIT = 12,
|
||||||
|
PD_CTRL_SOFT_RESET = 13,
|
||||||
|
/* 14-15 Reserved */
|
||||||
|
};
|
||||||
|
|
||||||
|
enum pd_data_msg_type {
|
||||||
|
/* 0 Reserved */
|
||||||
|
PD_DATA_SOURCE_CAP = 1,
|
||||||
|
PD_DATA_REQUEST = 2,
|
||||||
|
PD_DATA_BIST = 3,
|
||||||
|
PD_DATA_SINK_CAP = 4,
|
||||||
|
/* 5-14 Reserved */
|
||||||
|
PD_DATA_VENDOR_DEF = 15,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PD_REV10 0x0
|
||||||
|
#define PD_REV20 0x1
|
||||||
|
|
||||||
|
#define PD_HEADER_CNT_SHIFT 12
|
||||||
|
#define PD_HEADER_CNT_MASK 0x7
|
||||||
|
#define PD_HEADER_ID_SHIFT 9
|
||||||
|
#define PD_HEADER_ID_MASK 0x7
|
||||||
|
#define PD_HEADER_PWR_ROLE BIT(8)
|
||||||
|
#define PD_HEADER_REV_SHIFT 6
|
||||||
|
#define PD_HEADER_REV_MASK 0x3
|
||||||
|
#define PD_HEADER_DATA_ROLE BIT(5)
|
||||||
|
#define PD_HEADER_TYPE_SHIFT 0
|
||||||
|
#define PD_HEADER_TYPE_MASK 0xf
|
||||||
|
|
||||||
|
#define PD_HEADER(type, pwr, data, id, cnt) \
|
||||||
|
((((type) & PD_HEADER_TYPE_MASK) << PD_HEADER_TYPE_SHIFT) | \
|
||||||
|
((pwr) == TYPEC_SOURCE ? PD_HEADER_PWR_ROLE : 0) | \
|
||||||
|
((data) == TYPEC_HOST ? PD_HEADER_DATA_ROLE : 0) | \
|
||||||
|
(PD_REV20 << PD_HEADER_REV_SHIFT) | \
|
||||||
|
(((id) & PD_HEADER_ID_MASK) << PD_HEADER_ID_SHIFT) | \
|
||||||
|
(((cnt) & PD_HEADER_CNT_MASK) << PD_HEADER_CNT_SHIFT))
|
||||||
|
|
||||||
|
#define PD_HEADER_LE(type, pwr, data, id, cnt) \
|
||||||
|
cpu_to_le16(PD_HEADER((type), (pwr), (data), (id), (cnt)))
|
||||||
|
|
||||||
|
static inline unsigned int pd_header_cnt(u16 header)
|
||||||
|
{
|
||||||
|
return (header >> PD_HEADER_CNT_SHIFT) & PD_HEADER_CNT_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned int pd_header_cnt_le(__le16 header)
|
||||||
|
{
|
||||||
|
return pd_header_cnt(le16_to_cpu(header));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned int pd_header_type(u16 header)
|
||||||
|
{
|
||||||
|
return (header >> PD_HEADER_TYPE_SHIFT) & PD_HEADER_TYPE_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned int pd_header_type_le(__le16 header)
|
||||||
|
{
|
||||||
|
return pd_header_type(le16_to_cpu(header));
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PD_MAX_PAYLOAD 7
|
||||||
|
|
||||||
|
struct pd_message {
|
||||||
|
__le16 header;
|
||||||
|
__le32 payload[PD_MAX_PAYLOAD];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
/* PDO: Power Data Object */
|
||||||
|
#define PDO_MAX_OBJECTS 7
|
||||||
|
|
||||||
|
enum pd_pdo_type {
|
||||||
|
PDO_TYPE_FIXED = 0,
|
||||||
|
PDO_TYPE_BATT = 1,
|
||||||
|
PDO_TYPE_VAR = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PDO_TYPE_SHIFT 30
|
||||||
|
#define PDO_TYPE_MASK 0x3
|
||||||
|
|
||||||
|
#define PDO_TYPE(t) ((t) << PDO_TYPE_SHIFT)
|
||||||
|
|
||||||
|
#define PDO_VOLT_MASK 0x3ff
|
||||||
|
#define PDO_CURR_MASK 0x3ff
|
||||||
|
#define PDO_PWR_MASK 0x3ff
|
||||||
|
|
||||||
|
#define PDO_FIXED_DUAL_ROLE BIT(29) /* Power role swap supported */
|
||||||
|
#define PDO_FIXED_SUSPEND BIT(28) /* USB Suspend supported (Source) */
|
||||||
|
#define PDO_FIXED_HIGHER_CAP BIT(28) /* Requires more than vSafe5V (Sink) */
|
||||||
|
#define PDO_FIXED_EXTPOWER BIT(27) /* Externally powered */
|
||||||
|
#define PDO_FIXED_USB_COMM BIT(26) /* USB communications capable */
|
||||||
|
#define PDO_FIXED_DATA_SWAP BIT(25) /* Data role swap supported */
|
||||||
|
#define PDO_FIXED_VOLT_SHIFT 10 /* 50mV units */
|
||||||
|
#define PDO_FIXED_CURR_SHIFT 0 /* 10mA units */
|
||||||
|
|
||||||
|
#define PDO_FIXED_VOLT(mv) ((((mv) / 50) & PDO_VOLT_MASK) << PDO_FIXED_VOLT_SHIFT)
|
||||||
|
#define PDO_FIXED_CURR(ma) ((((ma) / 10) & PDO_CURR_MASK) << PDO_FIXED_CURR_SHIFT)
|
||||||
|
|
||||||
|
#define PDO_FIXED(mv, ma, flags) \
|
||||||
|
(PDO_TYPE(PDO_TYPE_FIXED) | (flags) | \
|
||||||
|
PDO_FIXED_VOLT(mv) | PDO_FIXED_CURR(ma))
|
||||||
|
|
||||||
|
#define PDO_BATT_MAX_VOLT_SHIFT 20 /* 50mV units */
|
||||||
|
#define PDO_BATT_MIN_VOLT_SHIFT 10 /* 50mV units */
|
||||||
|
#define PDO_BATT_MAX_PWR_SHIFT 0 /* 250mW units */
|
||||||
|
|
||||||
|
#define PDO_BATT_MIN_VOLT(mv) ((((mv) / 50) & PDO_VOLT_MASK) << PDO_BATT_MIN_VOLT_SHIFT)
|
||||||
|
#define PDO_BATT_MAX_VOLT(mv) ((((mv) / 50) & PDO_VOLT_MASK) << PDO_BATT_MAX_VOLT_SHIFT)
|
||||||
|
#define PDO_BATT_MAX_POWER(mw) ((((mw) / 250) & PDO_PWR_MASK) << PDO_BATT_MAX_PWR_SHIFT)
|
||||||
|
|
||||||
|
#define PDO_BATT(min_mv, max_mv, max_mw) \
|
||||||
|
(PDO_TYPE(PDO_TYPE_BATT) | PDO_BATT_MIN_VOLT(min_mv) | \
|
||||||
|
PDO_BATT_MAX_VOLT(max_mv) | PDO_BATT_MAX_POWER(max_mw))
|
||||||
|
|
||||||
|
#define PDO_VAR_MAX_VOLT_SHIFT 20 /* 50mV units */
|
||||||
|
#define PDO_VAR_MIN_VOLT_SHIFT 10 /* 50mV units */
|
||||||
|
#define PDO_VAR_MAX_CURR_SHIFT 0 /* 10mA units */
|
||||||
|
|
||||||
|
#define PDO_VAR_MIN_VOLT(mv) ((((mv) / 50) & PDO_VOLT_MASK) << PDO_VAR_MIN_VOLT_SHIFT)
|
||||||
|
#define PDO_VAR_MAX_VOLT(mv) ((((mv) / 50) & PDO_VOLT_MASK) << PDO_VAR_MAX_VOLT_SHIFT)
|
||||||
|
#define PDO_VAR_MAX_CURR(ma) ((((ma) / 10) & PDO_CURR_MASK) << PDO_VAR_MAX_CURR_SHIFT)
|
||||||
|
|
||||||
|
#define PDO_VAR(min_mv, max_mv, max_ma) \
|
||||||
|
(PDO_TYPE(PDO_TYPE_VAR) | PDO_VAR_MIN_VOLT(min_mv) | \
|
||||||
|
PDO_VAR_MAX_VOLT(max_mv) | PDO_VAR_MAX_CURR(max_ma))
|
||||||
|
|
||||||
|
static inline enum pd_pdo_type pdo_type(u32 pdo)
|
||||||
|
{
|
||||||
|
return (pdo >> PDO_TYPE_SHIFT) & PDO_TYPE_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned int pdo_fixed_voltage(u32 pdo)
|
||||||
|
{
|
||||||
|
return ((pdo >> PDO_FIXED_VOLT_SHIFT) & PDO_VOLT_MASK) * 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned int pdo_min_voltage(u32 pdo)
|
||||||
|
{
|
||||||
|
return ((pdo >> PDO_VAR_MIN_VOLT_SHIFT) & PDO_VOLT_MASK) * 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned int pdo_max_voltage(u32 pdo)
|
||||||
|
{
|
||||||
|
return ((pdo >> PDO_VAR_MAX_VOLT_SHIFT) & PDO_VOLT_MASK) * 50;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned int pdo_max_current(u32 pdo)
|
||||||
|
{
|
||||||
|
return ((pdo >> PDO_VAR_MAX_CURR_SHIFT) & PDO_CURR_MASK) * 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned int pdo_max_power(u32 pdo)
|
||||||
|
{
|
||||||
|
return ((pdo >> PDO_BATT_MAX_PWR_SHIFT) & PDO_PWR_MASK) * 250;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* RDO: Request Data Object */
|
||||||
|
#define RDO_OBJ_POS_SHIFT 28
|
||||||
|
#define RDO_OBJ_POS_MASK 0x7
|
||||||
|
#define RDO_GIVE_BACK BIT(27) /* Supports reduced operating current */
|
||||||
|
#define RDO_CAP_MISMATCH BIT(26) /* Not satisfied by source caps */
|
||||||
|
#define RDO_USB_COMM BIT(25) /* USB communications capable */
|
||||||
|
#define RDO_NO_SUSPEND BIT(24) /* USB Suspend not supported */
|
||||||
|
|
||||||
|
#define RDO_PWR_MASK 0x3ff
|
||||||
|
#define RDO_CURR_MASK 0x3ff
|
||||||
|
|
||||||
|
#define RDO_FIXED_OP_CURR_SHIFT 10
|
||||||
|
#define RDO_FIXED_MAX_CURR_SHIFT 0
|
||||||
|
|
||||||
|
#define RDO_OBJ(idx) (((idx) & RDO_OBJ_POS_MASK) << RDO_OBJ_POS_SHIFT)
|
||||||
|
|
||||||
|
#define PDO_FIXED_OP_CURR(ma) ((((ma) / 10) & RDO_CURR_MASK) << RDO_FIXED_OP_CURR_SHIFT)
|
||||||
|
#define PDO_FIXED_MAX_CURR(ma) ((((ma) / 10) & RDO_CURR_MASK) << RDO_FIXED_MAX_CURR_SHIFT)
|
||||||
|
|
||||||
|
#define RDO_FIXED(idx, op_ma, max_ma, flags) \
|
||||||
|
(RDO_OBJ(idx) | (flags) | \
|
||||||
|
PDO_FIXED_OP_CURR(op_ma) | PDO_FIXED_MAX_CURR(max_ma))
|
||||||
|
|
||||||
|
#define RDO_BATT_OP_PWR_SHIFT 10 /* 250mW units */
|
||||||
|
#define RDO_BATT_MAX_PWR_SHIFT 0 /* 250mW units */
|
||||||
|
|
||||||
|
#define RDO_BATT_OP_PWR(mw) ((((mw) / 250) & RDO_PWR_MASK) << RDO_BATT_OP_PWR_SHIFT)
|
||||||
|
#define RDO_BATT_MAX_PWR(mw) ((((mw) / 250) & RDO_PWR_MASK) << RDO_BATT_MAX_PWR_SHIFT)
|
||||||
|
|
||||||
|
#define RDO_BATT(idx, op_mw, max_mw, flags) \
|
||||||
|
(RDO_OBJ(idx) | (flags) | \
|
||||||
|
RDO_BATT_OP_PWR(op_mw) | RDO_BATT_MAX_PWR(max_mw))
|
||||||
|
|
||||||
|
static inline unsigned int rdo_index(u32 rdo)
|
||||||
|
{
|
||||||
|
return (rdo >> RDO_OBJ_POS_SHIFT) & RDO_OBJ_POS_MASK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned int rdo_op_current(u32 rdo)
|
||||||
|
{
|
||||||
|
return ((rdo >> RDO_FIXED_OP_CURR_SHIFT) & RDO_CURR_MASK) * 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned int rdo_max_current(u32 rdo)
|
||||||
|
{
|
||||||
|
return ((rdo >> RDO_FIXED_MAX_CURR_SHIFT) &
|
||||||
|
RDO_CURR_MASK) * 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned int rdo_op_power(u32 rdo)
|
||||||
|
{
|
||||||
|
return ((rdo >> RDO_BATT_OP_PWR_SHIFT) & RDO_PWR_MASK) * 250;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned int rdo_max_power(u32 rdo)
|
||||||
|
{
|
||||||
|
return ((rdo >> RDO_BATT_MAX_PWR_SHIFT) & RDO_PWR_MASK) * 250;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* USB PD timers and counters */
|
||||||
|
#define PD_T_NO_RESPONSE 5000 /* 4.5 - 5.5 seconds */
|
||||||
|
#define PD_T_DB_DETECT 10000 /* 10 - 15 seconds */
|
||||||
|
#define PD_T_SEND_SOURCE_CAP 150 /* 100 - 200 ms */
|
||||||
|
#define PD_T_SENDER_RESPONSE 60 /* 24 - 30 ms, relaxed */
|
||||||
|
#define PD_T_SOURCE_ACTIVITY 45
|
||||||
|
#define PD_T_SINK_ACTIVITY 135
|
||||||
|
#define PD_T_SINK_WAIT_CAP 240
|
||||||
|
#define PD_T_PS_TRANSITION 500
|
||||||
|
#define PD_T_SRC_TRANSITION 35
|
||||||
|
#define PD_T_DRP_SNK 40
|
||||||
|
#define PD_T_DRP_SRC 30
|
||||||
|
#define PD_T_PS_SOURCE_OFF 920
|
||||||
|
#define PD_T_PS_SOURCE_ON 480
|
||||||
|
#define PD_T_PS_HARD_RESET 30
|
||||||
|
#define PD_T_SRC_RECOVER 760
|
||||||
|
#define PD_T_SRC_RECOVER_MAX 1000
|
||||||
|
#define PD_T_SRC_TURN_ON 275
|
||||||
|
#define PD_T_SAFE_0V 650
|
||||||
|
#define PD_T_VCONN_SOURCE_ON 100
|
||||||
|
#define PD_T_SINK_REQUEST 100 /* 100 ms minimum */
|
||||||
|
#define PD_T_ERROR_RECOVERY 100 /* minimum 25 is insufficient */
|
||||||
|
|
||||||
|
#define PD_T_DRP_TRY 100 /* 75 - 150 ms */
|
||||||
|
#define PD_T_DRP_TRYWAIT 600 /* 400 - 800 ms */
|
||||||
|
|
||||||
|
#define PD_T_CC_DEBOUNCE 200 /* 100 - 200 ms */
|
||||||
|
#define PD_T_PD_DEBOUNCE 20 /* 10 - 20 ms */
|
||||||
|
|
||||||
|
#define PD_N_CAPS_COUNT (PD_T_NO_RESPONSE / PD_T_SEND_SOURCE_CAP)
|
||||||
|
#define PD_N_HARD_RESET_COUNT 2
|
||||||
|
|
||||||
|
#endif /* __LINUX_USB_PD_H */
|
31
drivers/staging/typec/pd_bdo.h
Normal file
31
drivers/staging/typec/pd_bdo.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015-2017 Google, Inc
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LINUX_USB_PD_BDO_H
|
||||||
|
#define __LINUX_USB_PD_BDO_H
|
||||||
|
|
||||||
|
/* BDO : BIST Data Object */
|
||||||
|
#define BDO_MODE_RECV (0 << 28)
|
||||||
|
#define BDO_MODE_TRANSMIT (1 << 28)
|
||||||
|
#define BDO_MODE_COUNTERS (2 << 28)
|
||||||
|
#define BDO_MODE_CARRIER0 (3 << 28)
|
||||||
|
#define BDO_MODE_CARRIER1 (4 << 28)
|
||||||
|
#define BDO_MODE_CARRIER2 (5 << 28)
|
||||||
|
#define BDO_MODE_CARRIER3 (6 << 28)
|
||||||
|
#define BDO_MODE_EYE (7 << 28)
|
||||||
|
#define BDO_MODE_TESTDATA (8 << 28)
|
||||||
|
|
||||||
|
#define BDO_MODE_MASK(mode) ((mode) & 0xf0000000)
|
||||||
|
|
||||||
|
#endif
|
249
drivers/staging/typec/pd_vdo.h
Normal file
249
drivers/staging/typec/pd_vdo.h
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015-2017 Google, Inc
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LINUX_USB_PD_VDO_H
|
||||||
|
#define __LINUX_USB_PD_VDO_H
|
||||||
|
|
||||||
|
#include "pd.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* VDO : Vendor Defined Message Object
|
||||||
|
* VDM object is minimum of VDM header + 6 additional data objects.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* VDM header
|
||||||
|
* ----------
|
||||||
|
* <31:16> :: SVID
|
||||||
|
* <15> :: VDM type ( 1b == structured, 0b == unstructured )
|
||||||
|
* <14:13> :: Structured VDM version (can only be 00 == 1.0 currently)
|
||||||
|
* <12:11> :: reserved
|
||||||
|
* <10:8> :: object position (1-7 valid ... used for enter/exit mode only)
|
||||||
|
* <7:6> :: command type (SVDM only?)
|
||||||
|
* <5> :: reserved (SVDM), command type (UVDM)
|
||||||
|
* <4:0> :: command
|
||||||
|
*/
|
||||||
|
#define VDO_MAX_SIZE 7
|
||||||
|
#define VDO(vid, type, custom) \
|
||||||
|
(((vid) << 16) | \
|
||||||
|
((type) << 15) | \
|
||||||
|
((custom) & 0x7FFF))
|
||||||
|
|
||||||
|
#define VDO_SVDM_TYPE (1 << 15)
|
||||||
|
#define VDO_SVDM_VERS(x) ((x) << 13)
|
||||||
|
#define VDO_OPOS(x) ((x) << 8)
|
||||||
|
#define VDO_CMDT(x) ((x) << 6)
|
||||||
|
#define VDO_OPOS_MASK VDO_OPOS(0x7)
|
||||||
|
#define VDO_CMDT_MASK VDO_CMDT(0x3)
|
||||||
|
|
||||||
|
#define CMDT_INIT 0
|
||||||
|
#define CMDT_RSP_ACK 1
|
||||||
|
#define CMDT_RSP_NAK 2
|
||||||
|
#define CMDT_RSP_BUSY 3
|
||||||
|
|
||||||
|
/* reserved for SVDM ... for Google UVDM */
|
||||||
|
#define VDO_SRC_INITIATOR (0 << 5)
|
||||||
|
#define VDO_SRC_RESPONDER (1 << 5)
|
||||||
|
|
||||||
|
#define CMD_DISCOVER_IDENT 1
|
||||||
|
#define CMD_DISCOVER_SVID 2
|
||||||
|
#define CMD_DISCOVER_MODES 3
|
||||||
|
#define CMD_ENTER_MODE 4
|
||||||
|
#define CMD_EXIT_MODE 5
|
||||||
|
#define CMD_ATTENTION 6
|
||||||
|
|
||||||
|
#define VDO_CMD_VENDOR(x) (((10 + (x)) & 0x1f))
|
||||||
|
|
||||||
|
/* ChromeOS specific commands */
|
||||||
|
#define VDO_CMD_VERSION VDO_CMD_VENDOR(0)
|
||||||
|
#define VDO_CMD_SEND_INFO VDO_CMD_VENDOR(1)
|
||||||
|
#define VDO_CMD_READ_INFO VDO_CMD_VENDOR(2)
|
||||||
|
#define VDO_CMD_REBOOT VDO_CMD_VENDOR(5)
|
||||||
|
#define VDO_CMD_FLASH_ERASE VDO_CMD_VENDOR(6)
|
||||||
|
#define VDO_CMD_FLASH_WRITE VDO_CMD_VENDOR(7)
|
||||||
|
#define VDO_CMD_ERASE_SIG VDO_CMD_VENDOR(8)
|
||||||
|
#define VDO_CMD_PING_ENABLE VDO_CMD_VENDOR(10)
|
||||||
|
#define VDO_CMD_CURRENT VDO_CMD_VENDOR(11)
|
||||||
|
#define VDO_CMD_FLIP VDO_CMD_VENDOR(12)
|
||||||
|
#define VDO_CMD_GET_LOG VDO_CMD_VENDOR(13)
|
||||||
|
#define VDO_CMD_CCD_EN VDO_CMD_VENDOR(14)
|
||||||
|
|
||||||
|
#define PD_VDO_VID(vdo) ((vdo) >> 16)
|
||||||
|
#define PD_VDO_SVDM(vdo) (((vdo) >> 15) & 1)
|
||||||
|
#define PD_VDO_OPOS(vdo) (((vdo) >> 8) & 0x7)
|
||||||
|
#define PD_VDO_CMD(vdo) ((vdo) & 0x1f)
|
||||||
|
#define PD_VDO_CMDT(vdo) (((vdo) >> 6) & 0x3)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SVDM Identity request -> response
|
||||||
|
*
|
||||||
|
* Request is simply properly formatted SVDM header
|
||||||
|
*
|
||||||
|
* Response is 4 data objects:
|
||||||
|
* [0] :: SVDM header
|
||||||
|
* [1] :: Identitiy header
|
||||||
|
* [2] :: Cert Stat VDO
|
||||||
|
* [3] :: (Product | Cable) VDO
|
||||||
|
* [4] :: AMA VDO
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define VDO_INDEX_HDR 0
|
||||||
|
#define VDO_INDEX_IDH 1
|
||||||
|
#define VDO_INDEX_CSTAT 2
|
||||||
|
#define VDO_INDEX_CABLE 3
|
||||||
|
#define VDO_INDEX_PRODUCT 3
|
||||||
|
#define VDO_INDEX_AMA 4
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SVDM Identity Header
|
||||||
|
* --------------------
|
||||||
|
* <31> :: data capable as a USB host
|
||||||
|
* <30> :: data capable as a USB device
|
||||||
|
* <29:27> :: product type
|
||||||
|
* <26> :: modal operation supported (1b == yes)
|
||||||
|
* <25:16> :: Reserved, Shall be set to zero
|
||||||
|
* <15:0> :: USB-IF assigned VID for this cable vendor
|
||||||
|
*/
|
||||||
|
#define IDH_PTYPE_UNDEF 0
|
||||||
|
#define IDH_PTYPE_HUB 1
|
||||||
|
#define IDH_PTYPE_PERIPH 2
|
||||||
|
#define IDH_PTYPE_PCABLE 3
|
||||||
|
#define IDH_PTYPE_ACABLE 4
|
||||||
|
#define IDH_PTYPE_AMA 5
|
||||||
|
|
||||||
|
#define VDO_IDH(usbh, usbd, ptype, is_modal, vid) \
|
||||||
|
((usbh) << 31 | (usbd) << 30 | ((ptype) & 0x7) << 27 \
|
||||||
|
| (is_modal) << 26 | ((vid) & 0xffff))
|
||||||
|
|
||||||
|
#define PD_IDH_PTYPE(vdo) (((vdo) >> 27) & 0x7)
|
||||||
|
#define PD_IDH_VID(vdo) ((vdo) & 0xffff)
|
||||||
|
#define PD_IDH_MODAL_SUPP(vdo) ((vdo) & (1 << 26))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cert Stat VDO
|
||||||
|
* -------------
|
||||||
|
* <31:0> : USB-IF assigned XID for this cable
|
||||||
|
*/
|
||||||
|
#define PD_CSTAT_XID(vdo) (vdo)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Product VDO
|
||||||
|
* -----------
|
||||||
|
* <31:16> : USB Product ID
|
||||||
|
* <15:0> : USB bcdDevice
|
||||||
|
*/
|
||||||
|
#define VDO_PRODUCT(pid, bcd) (((pid) & 0xffff) << 16 | ((bcd) & 0xffff))
|
||||||
|
#define PD_PRODUCT_PID(vdo) (((vdo) >> 16) & 0xffff)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cable VDO
|
||||||
|
* ---------
|
||||||
|
* <31:28> :: Cable HW version
|
||||||
|
* <27:24> :: Cable FW version
|
||||||
|
* <23:20> :: Reserved, Shall be set to zero
|
||||||
|
* <19:18> :: type-C to Type-A/B/C (00b == A, 01 == B, 10 == C)
|
||||||
|
* <17> :: Type-C to Plug/Receptacle (0b == plug, 1b == receptacle)
|
||||||
|
* <16:13> :: cable latency (0001 == <10ns(~1m length))
|
||||||
|
* <12:11> :: cable termination type (11b == both ends active VCONN req)
|
||||||
|
* <10> :: SSTX1 Directionality support (0b == fixed, 1b == cfgable)
|
||||||
|
* <9> :: SSTX2 Directionality support
|
||||||
|
* <8> :: SSRX1 Directionality support
|
||||||
|
* <7> :: SSRX2 Directionality support
|
||||||
|
* <6:5> :: Vbus current handling capability
|
||||||
|
* <4> :: Vbus through cable (0b == no, 1b == yes)
|
||||||
|
* <3> :: SOP" controller present? (0b == no, 1b == yes)
|
||||||
|
* <2:0> :: USB SS Signaling support
|
||||||
|
*/
|
||||||
|
#define CABLE_ATYPE 0
|
||||||
|
#define CABLE_BTYPE 1
|
||||||
|
#define CABLE_CTYPE 2
|
||||||
|
#define CABLE_PLUG 0
|
||||||
|
#define CABLE_RECEPTACLE 1
|
||||||
|
#define CABLE_CURR_1A5 0
|
||||||
|
#define CABLE_CURR_3A 1
|
||||||
|
#define CABLE_CURR_5A 2
|
||||||
|
#define CABLE_USBSS_U2_ONLY 0
|
||||||
|
#define CABLE_USBSS_U31_GEN1 1
|
||||||
|
#define CABLE_USBSS_U31_GEN2 2
|
||||||
|
#define VDO_CABLE(hw, fw, cbl, gdr, lat, term, tx1d, tx2d, rx1d, rx2d, cur,\
|
||||||
|
vps, sopp, usbss) \
|
||||||
|
(((hw) & 0x7) << 28 | ((fw) & 0x7) << 24 | ((cbl) & 0x3) << 18 \
|
||||||
|
| (gdr) << 17 | ((lat) & 0x7) << 13 | ((term) & 0x3) << 11 \
|
||||||
|
| (tx1d) << 10 | (tx2d) << 9 | (rx1d) << 8 | (rx2d) << 7 \
|
||||||
|
| ((cur) & 0x3) << 5 | (vps) << 4 | (sopp) << 3 \
|
||||||
|
| ((usbss) & 0x7))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* AMA VDO
|
||||||
|
* ---------
|
||||||
|
* <31:28> :: Cable HW version
|
||||||
|
* <27:24> :: Cable FW version
|
||||||
|
* <23:12> :: Reserved, Shall be set to zero
|
||||||
|
* <11> :: SSTX1 Directionality support (0b == fixed, 1b == cfgable)
|
||||||
|
* <10> :: SSTX2 Directionality support
|
||||||
|
* <9> :: SSRX1 Directionality support
|
||||||
|
* <8> :: SSRX2 Directionality support
|
||||||
|
* <7:5> :: Vconn power
|
||||||
|
* <4> :: Vconn power required
|
||||||
|
* <3> :: Vbus power required
|
||||||
|
* <2:0> :: USB SS Signaling support
|
||||||
|
*/
|
||||||
|
#define VDO_AMA(hw, fw, tx1d, tx2d, rx1d, rx2d, vcpwr, vcr, vbr, usbss) \
|
||||||
|
(((hw) & 0x7) << 28 | ((fw) & 0x7) << 24 \
|
||||||
|
| (tx1d) << 11 | (tx2d) << 10 | (rx1d) << 9 | (rx2d) << 8 \
|
||||||
|
| ((vcpwr) & 0x7) << 5 | (vcr) << 4 | (vbr) << 3 \
|
||||||
|
| ((usbss) & 0x7))
|
||||||
|
|
||||||
|
#define PD_VDO_AMA_VCONN_REQ(vdo) (((vdo) >> 4) & 1)
|
||||||
|
#define PD_VDO_AMA_VBUS_REQ(vdo) (((vdo) >> 3) & 1)
|
||||||
|
|
||||||
|
#define AMA_VCONN_PWR_1W 0
|
||||||
|
#define AMA_VCONN_PWR_1W5 1
|
||||||
|
#define AMA_VCONN_PWR_2W 2
|
||||||
|
#define AMA_VCONN_PWR_3W 3
|
||||||
|
#define AMA_VCONN_PWR_4W 4
|
||||||
|
#define AMA_VCONN_PWR_5W 5
|
||||||
|
#define AMA_VCONN_PWR_6W 6
|
||||||
|
#define AMA_USBSS_U2_ONLY 0
|
||||||
|
#define AMA_USBSS_U31_GEN1 1
|
||||||
|
#define AMA_USBSS_U31_GEN2 2
|
||||||
|
#define AMA_USBSS_BBONLY 3
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SVDM Discover SVIDs request -> response
|
||||||
|
*
|
||||||
|
* Request is properly formatted VDM Header with discover SVIDs command.
|
||||||
|
* Response is a set of SVIDs of all all supported SVIDs with all zero's to
|
||||||
|
* mark the end of SVIDs. If more than 12 SVIDs are supported command SHOULD be
|
||||||
|
* repeated.
|
||||||
|
*/
|
||||||
|
#define VDO_SVID(svid0, svid1) (((svid0) & 0xffff) << 16 | ((svid1) & 0xffff))
|
||||||
|
#define PD_VDO_SVID_SVID0(vdo) ((vdo) >> 16)
|
||||||
|
#define PD_VDO_SVID_SVID1(vdo) ((vdo) & 0xffff)
|
||||||
|
|
||||||
|
/* USB-IF SIDs */
|
||||||
|
#define USB_SID_PD 0xff00 /* power delivery */
|
||||||
|
#define USB_SID_DISPLAYPORT 0xff01
|
||||||
|
#define USB_SID_MHL 0xff02 /* Mobile High-Definition Link */
|
||||||
|
|
||||||
|
/* VDM command timeouts (in ms) */
|
||||||
|
|
||||||
|
#define PD_T_VDM_UNSTRUCTURED 500
|
||||||
|
#define PD_T_VDM_BUSY 100
|
||||||
|
#define PD_T_VDM_WAIT_MODE_E 100
|
||||||
|
#define PD_T_VDM_SNDR_RSP 30
|
||||||
|
#define PD_T_VDM_E_MODE 25
|
||||||
|
#define PD_T_VDM_RCVR_RSP 15
|
||||||
|
|
||||||
|
#endif /* __LINUX_USB_PD_VDO_H */
|
526
drivers/staging/typec/tcpci.c
Normal file
526
drivers/staging/typec/tcpci.c
Normal file
@ -0,0 +1,526 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015-2017 Google, Inc
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* USB Type-C Port Controller Interface.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/i2c.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
#include <linux/usb/typec.h>
|
||||||
|
|
||||||
|
#include "pd.h"
|
||||||
|
#include "tcpci.h"
|
||||||
|
#include "tcpm.h"
|
||||||
|
|
||||||
|
#define PD_RETRY_COUNT 3
|
||||||
|
|
||||||
|
struct tcpci {
|
||||||
|
struct device *dev;
|
||||||
|
struct i2c_client *client;
|
||||||
|
|
||||||
|
struct tcpm_port *port;
|
||||||
|
|
||||||
|
struct regmap *regmap;
|
||||||
|
|
||||||
|
bool controls_vbus;
|
||||||
|
|
||||||
|
struct tcpc_dev tcpc;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline struct tcpci *tcpc_to_tcpci(struct tcpc_dev *tcpc)
|
||||||
|
{
|
||||||
|
return container_of(tcpc, struct tcpci, tcpc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tcpci_read16(struct tcpci *tcpci, unsigned int reg,
|
||||||
|
unsigned int *val)
|
||||||
|
{
|
||||||
|
return regmap_raw_read(tcpci->regmap, reg, val, sizeof(u16));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tcpci_write16(struct tcpci *tcpci, unsigned int reg, u16 val)
|
||||||
|
{
|
||||||
|
return regmap_raw_write(tcpci->regmap, reg, &val, sizeof(u16));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc)
|
||||||
|
{
|
||||||
|
struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
|
||||||
|
unsigned int reg;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
switch (cc) {
|
||||||
|
case TYPEC_CC_RA:
|
||||||
|
reg = (TCPC_ROLE_CTRL_CC_RA << TCPC_ROLE_CTRL_CC1_SHIFT) |
|
||||||
|
(TCPC_ROLE_CTRL_CC_RA << TCPC_ROLE_CTRL_CC2_SHIFT);
|
||||||
|
break;
|
||||||
|
case TYPEC_CC_RD:
|
||||||
|
reg = (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT) |
|
||||||
|
(TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT);
|
||||||
|
break;
|
||||||
|
case TYPEC_CC_RP_DEF:
|
||||||
|
reg = (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT) |
|
||||||
|
(TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT) |
|
||||||
|
(TCPC_ROLE_CTRL_RP_VAL_DEF <<
|
||||||
|
TCPC_ROLE_CTRL_RP_VAL_SHIFT);
|
||||||
|
break;
|
||||||
|
case TYPEC_CC_RP_1_5:
|
||||||
|
reg = (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT) |
|
||||||
|
(TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT) |
|
||||||
|
(TCPC_ROLE_CTRL_RP_VAL_1_5 <<
|
||||||
|
TCPC_ROLE_CTRL_RP_VAL_SHIFT);
|
||||||
|
break;
|
||||||
|
case TYPEC_CC_RP_3_0:
|
||||||
|
reg = (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT) |
|
||||||
|
(TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT) |
|
||||||
|
(TCPC_ROLE_CTRL_RP_VAL_3_0 <<
|
||||||
|
TCPC_ROLE_CTRL_RP_VAL_SHIFT);
|
||||||
|
break;
|
||||||
|
case TYPEC_CC_OPEN:
|
||||||
|
default:
|
||||||
|
reg = (TCPC_ROLE_CTRL_CC_OPEN << TCPC_ROLE_CTRL_CC1_SHIFT) |
|
||||||
|
(TCPC_ROLE_CTRL_CC_OPEN << TCPC_ROLE_CTRL_CC2_SHIFT);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc,
|
||||||
|
enum typec_cc_status cc)
|
||||||
|
{
|
||||||
|
struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
|
||||||
|
unsigned int reg = TCPC_ROLE_CTRL_DRP;
|
||||||
|
|
||||||
|
switch (cc) {
|
||||||
|
default:
|
||||||
|
case TYPEC_CC_RP_DEF:
|
||||||
|
reg |= (TCPC_ROLE_CTRL_RP_VAL_DEF <<
|
||||||
|
TCPC_ROLE_CTRL_RP_VAL_SHIFT);
|
||||||
|
break;
|
||||||
|
case TYPEC_CC_RP_1_5:
|
||||||
|
reg |= (TCPC_ROLE_CTRL_RP_VAL_1_5 <<
|
||||||
|
TCPC_ROLE_CTRL_RP_VAL_SHIFT);
|
||||||
|
break;
|
||||||
|
case TYPEC_CC_RP_3_0:
|
||||||
|
reg |= (TCPC_ROLE_CTRL_RP_VAL_3_0 <<
|
||||||
|
TCPC_ROLE_CTRL_RP_VAL_SHIFT);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return regmap_write(tcpci->regmap, TCPC_ROLE_CTRL, reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum typec_cc_status tcpci_to_typec_cc(unsigned int cc, bool sink)
|
||||||
|
{
|
||||||
|
switch (cc) {
|
||||||
|
case 0x1:
|
||||||
|
return sink ? TYPEC_CC_RP_DEF : TYPEC_CC_RA;
|
||||||
|
case 0x2:
|
||||||
|
return sink ? TYPEC_CC_RP_1_5 : TYPEC_CC_RD;
|
||||||
|
case 0x3:
|
||||||
|
if (sink)
|
||||||
|
return TYPEC_CC_RP_3_0;
|
||||||
|
case 0x0:
|
||||||
|
default:
|
||||||
|
return TYPEC_CC_OPEN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tcpci_get_cc(struct tcpc_dev *tcpc,
|
||||||
|
enum typec_cc_status *cc1, enum typec_cc_status *cc2)
|
||||||
|
{
|
||||||
|
struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
|
||||||
|
unsigned int reg;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = regmap_read(tcpci->regmap, TCPC_CC_STATUS, ®);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
*cc1 = tcpci_to_typec_cc((reg >> TCPC_CC_STATUS_CC1_SHIFT) &
|
||||||
|
TCPC_CC_STATUS_CC1_MASK,
|
||||||
|
reg & TCPC_CC_STATUS_TERM);
|
||||||
|
*cc2 = tcpci_to_typec_cc((reg >> TCPC_CC_STATUS_CC2_SHIFT) &
|
||||||
|
TCPC_CC_STATUS_CC2_MASK,
|
||||||
|
reg & TCPC_CC_STATUS_TERM);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tcpci_set_polarity(struct tcpc_dev *tcpc,
|
||||||
|
enum typec_cc_polarity polarity)
|
||||||
|
{
|
||||||
|
struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = regmap_write(tcpci->regmap, TCPC_TCPC_CTRL,
|
||||||
|
(polarity == TYPEC_POLARITY_CC2) ?
|
||||||
|
TCPC_TCPC_CTRL_ORIENTATION : 0);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tcpci_set_vconn(struct tcpc_dev *tcpc, bool enable)
|
||||||
|
{
|
||||||
|
struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = regmap_write(tcpci->regmap, TCPC_POWER_CTRL,
|
||||||
|
enable ? TCPC_POWER_CTRL_VCONN_ENABLE : 0);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tcpci_set_roles(struct tcpc_dev *tcpc, bool attached,
|
||||||
|
enum typec_role role, enum typec_data_role data)
|
||||||
|
{
|
||||||
|
struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
|
||||||
|
unsigned int reg;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
reg = PD_REV20 << TCPC_MSG_HDR_INFO_REV_SHIFT;
|
||||||
|
if (role == TYPEC_SOURCE)
|
||||||
|
reg |= TCPC_MSG_HDR_INFO_PWR_ROLE;
|
||||||
|
if (data == TYPEC_HOST)
|
||||||
|
reg |= TCPC_MSG_HDR_INFO_DATA_ROLE;
|
||||||
|
ret = regmap_write(tcpci->regmap, TCPC_MSG_HDR_INFO, reg);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tcpci_set_pd_rx(struct tcpc_dev *tcpc, bool enable)
|
||||||
|
{
|
||||||
|
struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
|
||||||
|
unsigned int reg = 0;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (enable)
|
||||||
|
reg = TCPC_RX_DETECT_SOP | TCPC_RX_DETECT_HARD_RESET;
|
||||||
|
ret = regmap_write(tcpci->regmap, TCPC_RX_DETECT, reg);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tcpci_get_vbus(struct tcpc_dev *tcpc)
|
||||||
|
{
|
||||||
|
struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
|
||||||
|
unsigned int reg;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = regmap_read(tcpci->regmap, TCPC_POWER_STATUS, ®);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return !!(reg & TCPC_POWER_STATUS_VBUS_PRES);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tcpci_set_vbus(struct tcpc_dev *tcpc, bool source, bool sink)
|
||||||
|
{
|
||||||
|
struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Disable both source and sink first before enabling anything */
|
||||||
|
|
||||||
|
if (!source) {
|
||||||
|
ret = regmap_write(tcpci->regmap, TCPC_COMMAND,
|
||||||
|
TCPC_CMD_DISABLE_SRC_VBUS);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sink) {
|
||||||
|
ret = regmap_write(tcpci->regmap, TCPC_COMMAND,
|
||||||
|
TCPC_CMD_DISABLE_SINK_VBUS);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source) {
|
||||||
|
ret = regmap_write(tcpci->regmap, TCPC_COMMAND,
|
||||||
|
TCPC_CMD_SRC_VBUS_DEFAULT);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sink) {
|
||||||
|
ret = regmap_write(tcpci->regmap, TCPC_COMMAND,
|
||||||
|
TCPC_CMD_SINK_VBUS);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tcpci_pd_transmit(struct tcpc_dev *tcpc,
|
||||||
|
enum tcpm_transmit_type type,
|
||||||
|
const struct pd_message *msg)
|
||||||
|
{
|
||||||
|
struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
|
||||||
|
unsigned int reg, cnt, header;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
cnt = msg ? pd_header_cnt(msg->header) * 4 : 0;
|
||||||
|
ret = regmap_write(tcpci->regmap, TCPC_TX_BYTE_CNT, cnt + 2);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
header = msg ? msg->header : 0;
|
||||||
|
ret = tcpci_write16(tcpci, TCPC_TX_HDR, header);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (cnt > 0) {
|
||||||
|
ret = regmap_raw_write(tcpci->regmap, TCPC_TX_DATA,
|
||||||
|
&msg->payload, cnt);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
reg = (PD_RETRY_COUNT << TCPC_TRANSMIT_RETRY_SHIFT) |
|
||||||
|
(type << TCPC_TRANSMIT_TYPE_SHIFT);
|
||||||
|
ret = regmap_write(tcpci->regmap, TCPC_TRANSMIT, reg);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tcpci_init(struct tcpc_dev *tcpc)
|
||||||
|
{
|
||||||
|
struct tcpci *tcpci = tcpc_to_tcpci(tcpc);
|
||||||
|
unsigned long timeout = jiffies + msecs_to_jiffies(2000); /* XXX */
|
||||||
|
unsigned int reg;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
while (time_before_eq(jiffies, timeout)) {
|
||||||
|
ret = regmap_read(tcpci->regmap, TCPC_POWER_STATUS, ®);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
if (!(reg & TCPC_POWER_STATUS_UNINIT))
|
||||||
|
break;
|
||||||
|
usleep_range(10000, 20000);
|
||||||
|
}
|
||||||
|
if (time_after(jiffies, timeout))
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
|
||||||
|
/* Clear all events */
|
||||||
|
ret = tcpci_write16(tcpci, TCPC_ALERT, 0xffff);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (tcpci->controls_vbus)
|
||||||
|
reg = TCPC_POWER_STATUS_VBUS_PRES;
|
||||||
|
else
|
||||||
|
reg = 0;
|
||||||
|
ret = regmap_write(tcpci->regmap, TCPC_POWER_STATUS_MASK, reg);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
reg = TCPC_ALERT_TX_SUCCESS | TCPC_ALERT_TX_FAILED |
|
||||||
|
TCPC_ALERT_TX_DISCARDED | TCPC_ALERT_RX_STATUS |
|
||||||
|
TCPC_ALERT_RX_HARD_RST | TCPC_ALERT_CC_STATUS;
|
||||||
|
if (tcpci->controls_vbus)
|
||||||
|
reg |= TCPC_ALERT_POWER_STATUS;
|
||||||
|
return tcpci_write16(tcpci, TCPC_ALERT_MASK, reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
static irqreturn_t tcpci_irq(int irq, void *dev_id)
|
||||||
|
{
|
||||||
|
struct tcpci *tcpci = dev_id;
|
||||||
|
unsigned int status, reg;
|
||||||
|
|
||||||
|
tcpci_read16(tcpci, TCPC_ALERT, &status);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear alert status for everything except RX_STATUS, which shouldn't
|
||||||
|
* be cleared until we have successfully retrieved message.
|
||||||
|
*/
|
||||||
|
if (status & ~TCPC_ALERT_RX_STATUS)
|
||||||
|
tcpci_write16(tcpci, TCPC_ALERT,
|
||||||
|
status & ~TCPC_ALERT_RX_STATUS);
|
||||||
|
|
||||||
|
if (status & TCPC_ALERT_CC_STATUS)
|
||||||
|
tcpm_cc_change(tcpci->port);
|
||||||
|
|
||||||
|
if (status & TCPC_ALERT_POWER_STATUS) {
|
||||||
|
regmap_read(tcpci->regmap, TCPC_POWER_STATUS_MASK, ®);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If power status mask has been reset, then the TCPC
|
||||||
|
* has reset.
|
||||||
|
*/
|
||||||
|
if (reg == 0xff)
|
||||||
|
tcpm_tcpc_reset(tcpci->port);
|
||||||
|
else
|
||||||
|
tcpm_vbus_change(tcpci->port);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status & TCPC_ALERT_RX_STATUS) {
|
||||||
|
struct pd_message msg;
|
||||||
|
unsigned int cnt;
|
||||||
|
|
||||||
|
regmap_read(tcpci->regmap, TCPC_RX_BYTE_CNT, &cnt);
|
||||||
|
|
||||||
|
tcpci_read16(tcpci, TCPC_RX_HDR, ®);
|
||||||
|
msg.header = reg;
|
||||||
|
|
||||||
|
if (WARN_ON(cnt > sizeof(msg.payload)))
|
||||||
|
cnt = sizeof(msg.payload);
|
||||||
|
|
||||||
|
if (cnt > 0)
|
||||||
|
regmap_raw_read(tcpci->regmap, TCPC_RX_DATA,
|
||||||
|
&msg.payload, cnt);
|
||||||
|
|
||||||
|
/* Read complete, clear RX status alert bit */
|
||||||
|
tcpci_write16(tcpci, TCPC_ALERT, TCPC_ALERT_RX_STATUS);
|
||||||
|
|
||||||
|
tcpm_pd_receive(tcpci->port, &msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status & TCPC_ALERT_RX_HARD_RST)
|
||||||
|
tcpm_pd_hard_reset(tcpci->port);
|
||||||
|
|
||||||
|
if (status & TCPC_ALERT_TX_SUCCESS)
|
||||||
|
tcpm_pd_transmit_complete(tcpci->port, TCPC_TX_SUCCESS);
|
||||||
|
else if (status & TCPC_ALERT_TX_DISCARDED)
|
||||||
|
tcpm_pd_transmit_complete(tcpci->port, TCPC_TX_DISCARDED);
|
||||||
|
else if (status & TCPC_ALERT_TX_FAILED)
|
||||||
|
tcpm_pd_transmit_complete(tcpci->port, TCPC_TX_FAILED);
|
||||||
|
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct regmap_config tcpci_regmap_config = {
|
||||||
|
.reg_bits = 8,
|
||||||
|
.val_bits = 8,
|
||||||
|
|
||||||
|
.max_register = 0x7F, /* 0x80 .. 0xFF are vendor defined */
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct tcpc_config tcpci_tcpc_config = {
|
||||||
|
.type = TYPEC_PORT_DFP,
|
||||||
|
.default_role = TYPEC_SINK,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int tcpci_parse_config(struct tcpci *tcpci)
|
||||||
|
{
|
||||||
|
tcpci->controls_vbus = true; /* XXX */
|
||||||
|
|
||||||
|
/* TODO: Populate struct tcpc_config from ACPI/device-tree */
|
||||||
|
tcpci->tcpc.config = &tcpci_tcpc_config;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tcpci_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *i2c_id)
|
||||||
|
{
|
||||||
|
struct tcpci *tcpci;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
tcpci = devm_kzalloc(&client->dev, sizeof(*tcpci), GFP_KERNEL);
|
||||||
|
if (!tcpci)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
tcpci->client = client;
|
||||||
|
tcpci->dev = &client->dev;
|
||||||
|
i2c_set_clientdata(client, tcpci);
|
||||||
|
tcpci->regmap = devm_regmap_init_i2c(client, &tcpci_regmap_config);
|
||||||
|
if (IS_ERR(tcpci->regmap))
|
||||||
|
return PTR_ERR(tcpci->regmap);
|
||||||
|
|
||||||
|
tcpci->tcpc.init = tcpci_init;
|
||||||
|
tcpci->tcpc.get_vbus = tcpci_get_vbus;
|
||||||
|
tcpci->tcpc.set_vbus = tcpci_set_vbus;
|
||||||
|
tcpci->tcpc.set_cc = tcpci_set_cc;
|
||||||
|
tcpci->tcpc.get_cc = tcpci_get_cc;
|
||||||
|
tcpci->tcpc.set_polarity = tcpci_set_polarity;
|
||||||
|
tcpci->tcpc.set_vconn = tcpci_set_vconn;
|
||||||
|
tcpci->tcpc.start_drp_toggling = tcpci_start_drp_toggling;
|
||||||
|
|
||||||
|
tcpci->tcpc.set_pd_rx = tcpci_set_pd_rx;
|
||||||
|
tcpci->tcpc.set_roles = tcpci_set_roles;
|
||||||
|
tcpci->tcpc.pd_transmit = tcpci_pd_transmit;
|
||||||
|
|
||||||
|
err = tcpci_parse_config(tcpci);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
/* Disable chip interrupts */
|
||||||
|
tcpci_write16(tcpci, TCPC_ALERT_MASK, 0);
|
||||||
|
|
||||||
|
err = devm_request_threaded_irq(tcpci->dev, client->irq, NULL,
|
||||||
|
tcpci_irq,
|
||||||
|
IRQF_ONESHOT | IRQF_TRIGGER_LOW,
|
||||||
|
dev_name(tcpci->dev), tcpci);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
tcpci->port = tcpm_register_port(tcpci->dev, &tcpci->tcpc);
|
||||||
|
return PTR_ERR_OR_ZERO(tcpci->port);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tcpci_remove(struct i2c_client *client)
|
||||||
|
{
|
||||||
|
struct tcpci *tcpci = i2c_get_clientdata(client);
|
||||||
|
|
||||||
|
tcpm_unregister_port(tcpci->port);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct i2c_device_id tcpci_id[] = {
|
||||||
|
{ "tcpci", 0 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, tcpci_id);
|
||||||
|
|
||||||
|
#ifdef CONFIG_OF
|
||||||
|
static const struct of_device_id tcpci_of_match[] = {
|
||||||
|
{ .compatible = "usb,tcpci", },
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, tcpci_of_match);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static struct i2c_driver tcpci_i2c_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "tcpci",
|
||||||
|
.of_match_table = of_match_ptr(tcpci_of_match),
|
||||||
|
},
|
||||||
|
.probe = tcpci_probe,
|
||||||
|
.remove = tcpci_remove,
|
||||||
|
.id_table = tcpci_id,
|
||||||
|
};
|
||||||
|
module_i2c_driver(tcpci_i2c_driver);
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("USB Type-C Port Controller Interface driver");
|
||||||
|
MODULE_LICENSE("GPL");
|
133
drivers/staging/typec/tcpci.h
Normal file
133
drivers/staging/typec/tcpci.h
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015-2017 Google, Inc
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* USB Type-C Port Controller Interface.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LINUX_USB_TCPCI_H
|
||||||
|
#define __LINUX_USB_TCPCI_H
|
||||||
|
|
||||||
|
#define TCPC_VENDOR_ID 0x0
|
||||||
|
#define TCPC_PRODUCT_ID 0x2
|
||||||
|
#define TCPC_BCD_DEV 0x4
|
||||||
|
#define TCPC_TC_REV 0x6
|
||||||
|
#define TCPC_PD_REV 0x8
|
||||||
|
#define TCPC_PD_INT_REV 0xa
|
||||||
|
|
||||||
|
#define TCPC_ALERT 0x10
|
||||||
|
#define TCPC_ALERT_VBUS_DISCNCT BIT(11)
|
||||||
|
#define TCPC_ALERT_RX_BUF_OVF BIT(10)
|
||||||
|
#define TCPC_ALERT_FAULT BIT(9)
|
||||||
|
#define TCPC_ALERT_V_ALARM_LO BIT(8)
|
||||||
|
#define TCPC_ALERT_V_ALARM_HI BIT(7)
|
||||||
|
#define TCPC_ALERT_TX_SUCCESS BIT(6)
|
||||||
|
#define TCPC_ALERT_TX_DISCARDED BIT(5)
|
||||||
|
#define TCPC_ALERT_TX_FAILED BIT(4)
|
||||||
|
#define TCPC_ALERT_RX_HARD_RST BIT(3)
|
||||||
|
#define TCPC_ALERT_RX_STATUS BIT(2)
|
||||||
|
#define TCPC_ALERT_POWER_STATUS BIT(1)
|
||||||
|
#define TCPC_ALERT_CC_STATUS BIT(0)
|
||||||
|
|
||||||
|
#define TCPC_ALERT_MASK 0x12
|
||||||
|
#define TCPC_POWER_STATUS_MASK 0x14
|
||||||
|
#define TCPC_FAULT_STATUS_MASK 0x15
|
||||||
|
#define TCPC_CONFIG_STD_OUTPUT 0x18
|
||||||
|
|
||||||
|
#define TCPC_TCPC_CTRL 0x19
|
||||||
|
#define TCPC_TCPC_CTRL_ORIENTATION BIT(0)
|
||||||
|
|
||||||
|
#define TCPC_ROLE_CTRL 0x1a
|
||||||
|
#define TCPC_ROLE_CTRL_DRP BIT(6)
|
||||||
|
#define TCPC_ROLE_CTRL_RP_VAL_SHIFT 4
|
||||||
|
#define TCPC_ROLE_CTRL_RP_VAL_MASK 0x3
|
||||||
|
#define TCPC_ROLE_CTRL_RP_VAL_DEF 0x0
|
||||||
|
#define TCPC_ROLE_CTRL_RP_VAL_1_5 0x1
|
||||||
|
#define TCPC_ROLE_CTRL_RP_VAL_3_0 0x2
|
||||||
|
#define TCPC_ROLE_CTRL_CC2_SHIFT 2
|
||||||
|
#define TCPC_ROLE_CTRL_CC2_MASK 0x3
|
||||||
|
#define TCPC_ROLE_CTRL_CC1_SHIFT 0
|
||||||
|
#define TCPC_ROLE_CTRL_CC1_MASK 0x3
|
||||||
|
#define TCPC_ROLE_CTRL_CC_RA 0x0
|
||||||
|
#define TCPC_ROLE_CTRL_CC_RP 0x1
|
||||||
|
#define TCPC_ROLE_CTRL_CC_RD 0x2
|
||||||
|
#define TCPC_ROLE_CTRL_CC_OPEN 0x3
|
||||||
|
|
||||||
|
#define TCPC_FAULT_CTRL 0x1b
|
||||||
|
|
||||||
|
#define TCPC_POWER_CTRL 0x1c
|
||||||
|
#define TCPC_POWER_CTRL_VCONN_ENABLE BIT(0)
|
||||||
|
|
||||||
|
#define TCPC_CC_STATUS 0x1d
|
||||||
|
#define TCPC_CC_STATUS_TERM BIT(4)
|
||||||
|
#define TCPC_CC_STATUS_CC2_SHIFT 2
|
||||||
|
#define TCPC_CC_STATUS_CC2_MASK 0x3
|
||||||
|
#define TCPC_CC_STATUS_CC1_SHIFT 0
|
||||||
|
#define TCPC_CC_STATUS_CC1_MASK 0x3
|
||||||
|
|
||||||
|
#define TCPC_POWER_STATUS 0x1e
|
||||||
|
#define TCPC_POWER_STATUS_UNINIT BIT(6)
|
||||||
|
#define TCPC_POWER_STATUS_VBUS_DET BIT(3)
|
||||||
|
#define TCPC_POWER_STATUS_VBUS_PRES BIT(2)
|
||||||
|
|
||||||
|
#define TCPC_FAULT_STATUS 0x1f
|
||||||
|
|
||||||
|
#define TCPC_COMMAND 0x23
|
||||||
|
#define TCPC_CMD_WAKE_I2C 0x11
|
||||||
|
#define TCPC_CMD_DISABLE_VBUS_DETECT 0x22
|
||||||
|
#define TCPC_CMD_ENABLE_VBUS_DETECT 0x33
|
||||||
|
#define TCPC_CMD_DISABLE_SINK_VBUS 0x44
|
||||||
|
#define TCPC_CMD_SINK_VBUS 0x55
|
||||||
|
#define TCPC_CMD_DISABLE_SRC_VBUS 0x66
|
||||||
|
#define TCPC_CMD_SRC_VBUS_DEFAULT 0x77
|
||||||
|
#define TCPC_CMD_SRC_VBUS_HIGH 0x88
|
||||||
|
#define TCPC_CMD_LOOK4CONNECTION 0x99
|
||||||
|
#define TCPC_CMD_RXONEMORE 0xAA
|
||||||
|
#define TCPC_CMD_I2C_IDLE 0xFF
|
||||||
|
|
||||||
|
#define TCPC_DEV_CAP_1 0x24
|
||||||
|
#define TCPC_DEV_CAP_2 0x26
|
||||||
|
#define TCPC_STD_INPUT_CAP 0x28
|
||||||
|
#define TCPC_STD_OUTPUT_CAP 0x29
|
||||||
|
|
||||||
|
#define TCPC_MSG_HDR_INFO 0x2e
|
||||||
|
#define TCPC_MSG_HDR_INFO_DATA_ROLE BIT(3)
|
||||||
|
#define TCPC_MSG_HDR_INFO_PWR_ROLE BIT(0)
|
||||||
|
#define TCPC_MSG_HDR_INFO_REV_SHIFT 1
|
||||||
|
#define TCPC_MSG_HDR_INFO_REV_MASK 0x3
|
||||||
|
|
||||||
|
#define TCPC_RX_DETECT 0x2f
|
||||||
|
#define TCPC_RX_DETECT_HARD_RESET BIT(5)
|
||||||
|
#define TCPC_RX_DETECT_SOP BIT(0)
|
||||||
|
|
||||||
|
#define TCPC_RX_BYTE_CNT 0x30
|
||||||
|
#define TCPC_RX_BUF_FRAME_TYPE 0x31
|
||||||
|
#define TCPC_RX_HDR 0x32
|
||||||
|
#define TCPC_RX_DATA 0x34 /* through 0x4f */
|
||||||
|
|
||||||
|
#define TCPC_TRANSMIT 0x50
|
||||||
|
#define TCPC_TRANSMIT_RETRY_SHIFT 4
|
||||||
|
#define TCPC_TRANSMIT_RETRY_MASK 0x3
|
||||||
|
#define TCPC_TRANSMIT_TYPE_SHIFT 0
|
||||||
|
#define TCPC_TRANSMIT_TYPE_MASK 0x7
|
||||||
|
|
||||||
|
#define TCPC_TX_BYTE_CNT 0x51
|
||||||
|
#define TCPC_TX_HDR 0x52
|
||||||
|
#define TCPC_TX_DATA 0x54 /* through 0x6f */
|
||||||
|
|
||||||
|
#define TCPC_VBUS_VOLTAGE 0x70
|
||||||
|
#define TCPC_VBUS_SINK_DISCONNECT_THRESH 0x72
|
||||||
|
#define TCPC_VBUS_STOP_DISCHARGE_THRESH 0x74
|
||||||
|
#define TCPC_VBUS_VOLTAGE_ALARM_HI_CFG 0x76
|
||||||
|
#define TCPC_VBUS_VOLTAGE_ALARM_LO_CFG 0x78
|
||||||
|
|
||||||
|
#endif /* __LINUX_USB_TCPCI_H */
|
3465
drivers/staging/typec/tcpm.c
Normal file
3465
drivers/staging/typec/tcpm.c
Normal file
File diff suppressed because it is too large
Load Diff
150
drivers/staging/typec/tcpm.h
Normal file
150
drivers/staging/typec/tcpm.h
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015-2017 Google, Inc
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LINUX_USB_TCPM_H
|
||||||
|
#define __LINUX_USB_TCPM_H
|
||||||
|
|
||||||
|
#include <linux/bitops.h>
|
||||||
|
#include <linux/usb/typec.h>
|
||||||
|
#include "pd.h"
|
||||||
|
|
||||||
|
enum typec_cc_status {
|
||||||
|
TYPEC_CC_OPEN,
|
||||||
|
TYPEC_CC_RA,
|
||||||
|
TYPEC_CC_RD,
|
||||||
|
TYPEC_CC_RP_DEF,
|
||||||
|
TYPEC_CC_RP_1_5,
|
||||||
|
TYPEC_CC_RP_3_0,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum typec_cc_polarity {
|
||||||
|
TYPEC_POLARITY_CC1,
|
||||||
|
TYPEC_POLARITY_CC2,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Time to wait for TCPC to complete transmit */
|
||||||
|
#define PD_T_TCPC_TX_TIMEOUT 100
|
||||||
|
|
||||||
|
enum tcpm_transmit_status {
|
||||||
|
TCPC_TX_SUCCESS = 0,
|
||||||
|
TCPC_TX_DISCARDED = 1,
|
||||||
|
TCPC_TX_FAILED = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum tcpm_transmit_type {
|
||||||
|
TCPC_TX_SOP = 0,
|
||||||
|
TCPC_TX_SOP_PRIME = 1,
|
||||||
|
TCPC_TX_SOP_PRIME_PRIME = 2,
|
||||||
|
TCPC_TX_SOP_DEBUG_PRIME = 3,
|
||||||
|
TCPC_TX_SOP_DEBUG_PRIME_PRIME = 4,
|
||||||
|
TCPC_TX_HARD_RESET = 5,
|
||||||
|
TCPC_TX_CABLE_RESET = 6,
|
||||||
|
TCPC_TX_BIST_MODE_2 = 7
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tcpc_config {
|
||||||
|
const u32 *src_pdo;
|
||||||
|
unsigned int nr_src_pdo;
|
||||||
|
|
||||||
|
const u32 *snk_pdo;
|
||||||
|
unsigned int nr_snk_pdo;
|
||||||
|
|
||||||
|
unsigned int max_snk_mv;
|
||||||
|
unsigned int max_snk_ma;
|
||||||
|
unsigned int max_snk_mw;
|
||||||
|
unsigned int operating_snk_mw;
|
||||||
|
|
||||||
|
enum typec_port_type type;
|
||||||
|
enum typec_role default_role;
|
||||||
|
bool try_role_hw; /* try.{src,snk} implemented in hardware */
|
||||||
|
|
||||||
|
struct typec_altmode_desc *alt_modes;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum tcpc_usb_switch {
|
||||||
|
TCPC_USB_SWITCH_CONNECT,
|
||||||
|
TCPC_USB_SWITCH_DISCONNECT,
|
||||||
|
TCPC_USB_SWITCH_RESTORE, /* TODO FIXME */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Mux state attributes */
|
||||||
|
#define TCPC_MUX_USB_ENABLED BIT(0) /* USB enabled */
|
||||||
|
#define TCPC_MUX_DP_ENABLED BIT(1) /* DP enabled */
|
||||||
|
#define TCPC_MUX_POLARITY_INVERTED BIT(2) /* Polarity inverted */
|
||||||
|
|
||||||
|
/* Mux modes, decoded to attributes */
|
||||||
|
enum tcpc_mux_mode {
|
||||||
|
TYPEC_MUX_NONE = 0, /* Open switch */
|
||||||
|
TYPEC_MUX_USB = TCPC_MUX_USB_ENABLED, /* USB only */
|
||||||
|
TYPEC_MUX_DP = TCPC_MUX_DP_ENABLED, /* DP only */
|
||||||
|
TYPEC_MUX_DOCK = TCPC_MUX_USB_ENABLED | /* Both USB and DP */
|
||||||
|
TCPC_MUX_DP_ENABLED,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tcpc_mux_dev {
|
||||||
|
int (*set)(struct tcpc_mux_dev *dev, enum tcpc_mux_mode mux_mode,
|
||||||
|
enum tcpc_usb_switch usb_config,
|
||||||
|
enum typec_cc_polarity polarity);
|
||||||
|
bool dfp_only;
|
||||||
|
void *priv_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tcpc_dev {
|
||||||
|
const struct tcpc_config *config;
|
||||||
|
|
||||||
|
int (*init)(struct tcpc_dev *dev);
|
||||||
|
int (*get_vbus)(struct tcpc_dev *dev);
|
||||||
|
int (*set_cc)(struct tcpc_dev *dev, enum typec_cc_status cc);
|
||||||
|
int (*get_cc)(struct tcpc_dev *dev, enum typec_cc_status *cc1,
|
||||||
|
enum typec_cc_status *cc2);
|
||||||
|
int (*set_polarity)(struct tcpc_dev *dev,
|
||||||
|
enum typec_cc_polarity polarity);
|
||||||
|
int (*set_vconn)(struct tcpc_dev *dev, bool on);
|
||||||
|
int (*set_vbus)(struct tcpc_dev *dev, bool on, bool charge);
|
||||||
|
int (*set_current_limit)(struct tcpc_dev *dev, u32 max_ma, u32 mv);
|
||||||
|
int (*set_pd_rx)(struct tcpc_dev *dev, bool on);
|
||||||
|
int (*set_roles)(struct tcpc_dev *dev, bool attached,
|
||||||
|
enum typec_role role, enum typec_data_role data);
|
||||||
|
int (*start_drp_toggling)(struct tcpc_dev *dev,
|
||||||
|
enum typec_cc_status cc);
|
||||||
|
int (*try_role)(struct tcpc_dev *dev, int role);
|
||||||
|
int (*pd_transmit)(struct tcpc_dev *dev, enum tcpm_transmit_type type,
|
||||||
|
const struct pd_message *msg);
|
||||||
|
struct tcpc_mux_dev *mux;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tcpm_port;
|
||||||
|
|
||||||
|
struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc);
|
||||||
|
void tcpm_unregister_port(struct tcpm_port *port);
|
||||||
|
|
||||||
|
void tcpm_update_source_capabilities(struct tcpm_port *port, const u32 *pdo,
|
||||||
|
unsigned int nr_pdo);
|
||||||
|
void tcpm_update_sink_capabilities(struct tcpm_port *port, const u32 *pdo,
|
||||||
|
unsigned int nr_pdo,
|
||||||
|
unsigned int max_snk_mv,
|
||||||
|
unsigned int max_snk_ma,
|
||||||
|
unsigned int max_snk_mw,
|
||||||
|
unsigned int operating_snk_mw);
|
||||||
|
|
||||||
|
void tcpm_vbus_change(struct tcpm_port *port);
|
||||||
|
void tcpm_cc_change(struct tcpm_port *port);
|
||||||
|
void tcpm_pd_receive(struct tcpm_port *port,
|
||||||
|
const struct pd_message *msg);
|
||||||
|
void tcpm_pd_transmit_complete(struct tcpm_port *port,
|
||||||
|
enum tcpm_transmit_status status);
|
||||||
|
void tcpm_pd_hard_reset(struct tcpm_port *port);
|
||||||
|
void tcpm_tcpc_reset(struct tcpm_port *port);
|
||||||
|
|
||||||
|
#endif /* __LINUX_USB_TCPM_H */
|
@ -35,7 +35,6 @@ config USB_COMMON
|
|||||||
config USB_ARCH_HAS_HCD
|
config USB_ARCH_HAS_HCD
|
||||||
def_bool y
|
def_bool y
|
||||||
|
|
||||||
# ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
|
|
||||||
config USB
|
config USB
|
||||||
tristate "Support for Host-side USB"
|
tristate "Support for Host-side USB"
|
||||||
depends on USB_ARCH_HAS_HCD
|
depends on USB_ARCH_HAS_HCD
|
||||||
@ -73,6 +72,17 @@ config USB
|
|||||||
To compile this driver as a module, choose M here: the
|
To compile this driver as a module, choose M here: the
|
||||||
module will be called usbcore.
|
module will be called usbcore.
|
||||||
|
|
||||||
|
config USB_PCI
|
||||||
|
bool "PCI based USB host interface"
|
||||||
|
depends on PCI
|
||||||
|
default y
|
||||||
|
---help---
|
||||||
|
A lot of embeded system SOC (e.g. freescale T2080) have both
|
||||||
|
PCI and USB modules. But USB module is controlled by registers
|
||||||
|
directly, it have no relationship with PCI module.
|
||||||
|
|
||||||
|
When say N here it will not build PCI related code in USB driver.
|
||||||
|
|
||||||
if USB
|
if USB
|
||||||
|
|
||||||
source "drivers/usb/core/Kconfig"
|
source "drivers/usb/core/Kconfig"
|
||||||
@ -152,6 +162,8 @@ source "drivers/usb/phy/Kconfig"
|
|||||||
|
|
||||||
source "drivers/usb/gadget/Kconfig"
|
source "drivers/usb/gadget/Kconfig"
|
||||||
|
|
||||||
|
source "drivers/usb/typec/Kconfig"
|
||||||
|
|
||||||
config USB_LED_TRIG
|
config USB_LED_TRIG
|
||||||
bool "USB LED Triggers"
|
bool "USB LED Triggers"
|
||||||
depends on LEDS_CLASS && LEDS_TRIGGERS
|
depends on LEDS_CLASS && LEDS_TRIGGERS
|
||||||
|
@ -14,7 +14,7 @@ obj-$(CONFIG_USB_ISP1760) += isp1760/
|
|||||||
obj-$(CONFIG_USB_MON) += mon/
|
obj-$(CONFIG_USB_MON) += mon/
|
||||||
obj-$(CONFIG_USB_MTU3) += mtu3/
|
obj-$(CONFIG_USB_MTU3) += mtu3/
|
||||||
|
|
||||||
obj-$(CONFIG_PCI) += host/
|
obj-$(CONFIG_USB_PCI) += host/
|
||||||
obj-$(CONFIG_USB_EHCI_HCD) += host/
|
obj-$(CONFIG_USB_EHCI_HCD) += host/
|
||||||
obj-$(CONFIG_USB_ISP116X_HCD) += host/
|
obj-$(CONFIG_USB_ISP116X_HCD) += host/
|
||||||
obj-$(CONFIG_USB_OHCI_HCD) += host/
|
obj-$(CONFIG_USB_OHCI_HCD) += host/
|
||||||
@ -62,3 +62,5 @@ obj-$(CONFIG_USB_GADGET) += gadget/
|
|||||||
obj-$(CONFIG_USB_COMMON) += common/
|
obj-$(CONFIG_USB_COMMON) += common/
|
||||||
|
|
||||||
obj-$(CONFIG_USBIP_CORE) += usbip/
|
obj-$(CONFIG_USBIP_CORE) += usbip/
|
||||||
|
|
||||||
|
obj-$(CONFIG_TYPEC) += typec/
|
||||||
|
@ -474,7 +474,7 @@ static ssize_t cxacru_sysfs_store_adsl_config(struct device *dev,
|
|||||||
ret = sscanf(buf + pos, "%x=%x%n", &index, &value, &tmp);
|
ret = sscanf(buf + pos, "%x=%x%n", &index, &value, &tmp);
|
||||||
if (ret < 2)
|
if (ret < 2)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (index < 0 || index > 0x7f)
|
if (index > 0x7f)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (tmp < 0 || tmp > len - pos)
|
if (tmp < 0 || tmp > len - pos)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -20,7 +20,7 @@ config USB_CHIPIDEA_OF
|
|||||||
|
|
||||||
config USB_CHIPIDEA_PCI
|
config USB_CHIPIDEA_PCI
|
||||||
tristate
|
tristate
|
||||||
depends on PCI
|
depends on USB_PCI
|
||||||
depends on NOP_USB_XCEIV
|
depends on NOP_USB_XCEIV
|
||||||
default USB_CHIPIDEA
|
default USB_CHIPIDEA
|
||||||
|
|
||||||
|
@ -177,6 +177,7 @@ struct hw_bank {
|
|||||||
* @td_pool: allocation pool for transfer descriptors
|
* @td_pool: allocation pool for transfer descriptors
|
||||||
* @gadget: device side representation for peripheral controller
|
* @gadget: device side representation for peripheral controller
|
||||||
* @driver: gadget driver
|
* @driver: gadget driver
|
||||||
|
* @resume_state: save the state of gadget suspend from
|
||||||
* @hw_ep_max: total number of endpoints supported by hardware
|
* @hw_ep_max: total number of endpoints supported by hardware
|
||||||
* @ci_hw_ep: array of endpoints
|
* @ci_hw_ep: array of endpoints
|
||||||
* @ep0_dir: ep0 direction
|
* @ep0_dir: ep0 direction
|
||||||
@ -227,6 +228,7 @@ struct ci_hdrc {
|
|||||||
|
|
||||||
struct usb_gadget gadget;
|
struct usb_gadget gadget;
|
||||||
struct usb_gadget_driver *driver;
|
struct usb_gadget_driver *driver;
|
||||||
|
enum usb_device_state resume_state;
|
||||||
unsigned hw_ep_max;
|
unsigned hw_ep_max;
|
||||||
struct ci_hw_ep ci_hw_ep[ENDPT_MAX];
|
struct ci_hw_ep ci_hw_ep[ENDPT_MAX];
|
||||||
u32 ep0_dir;
|
u32 ep0_dir;
|
||||||
|
@ -783,9 +783,6 @@ struct platform_device *ci_hdrc_add_device(struct device *dev,
|
|||||||
}
|
}
|
||||||
|
|
||||||
pdev->dev.parent = dev;
|
pdev->dev.parent = dev;
|
||||||
pdev->dev.dma_mask = dev->dma_mask;
|
|
||||||
pdev->dev.dma_parms = dev->dma_parms;
|
|
||||||
dma_set_coherent_mask(&pdev->dev, dev->coherent_dma_mask);
|
|
||||||
|
|
||||||
ret = platform_device_add_resources(pdev, res, nres);
|
ret = platform_device_add_resources(pdev, res, nres);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -841,6 +838,56 @@ static void ci_get_otg_capable(struct ci_hdrc *ci)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ssize_t ci_role_show(struct device *dev, struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct ci_hdrc *ci = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
return sprintf(buf, "%s\n", ci_role(ci)->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t ci_role_store(struct device *dev,
|
||||||
|
struct device_attribute *attr, const char *buf, size_t n)
|
||||||
|
{
|
||||||
|
struct ci_hdrc *ci = dev_get_drvdata(dev);
|
||||||
|
enum ci_role role;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!(ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET])) {
|
||||||
|
dev_warn(dev, "Current configuration is not dual-role, quit\n");
|
||||||
|
return -EPERM;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++)
|
||||||
|
if (!strncmp(buf, ci->roles[role]->name,
|
||||||
|
strlen(ci->roles[role]->name)))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (role == CI_ROLE_END || role == ci->role)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
pm_runtime_get_sync(dev);
|
||||||
|
disable_irq(ci->irq);
|
||||||
|
ci_role_stop(ci);
|
||||||
|
ret = ci_role_start(ci, role);
|
||||||
|
if (!ret && ci->role == CI_ROLE_GADGET)
|
||||||
|
ci_handle_vbus_change(ci);
|
||||||
|
enable_irq(ci->irq);
|
||||||
|
pm_runtime_put_sync(dev);
|
||||||
|
|
||||||
|
return (ret == 0) ? n : ret;
|
||||||
|
}
|
||||||
|
static DEVICE_ATTR(role, 0644, ci_role_show, ci_role_store);
|
||||||
|
|
||||||
|
static struct attribute *ci_attrs[] = {
|
||||||
|
&dev_attr_role.attr,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct attribute_group ci_attr_group = {
|
||||||
|
.attrs = ci_attrs,
|
||||||
|
};
|
||||||
|
|
||||||
static int ci_hdrc_probe(struct platform_device *pdev)
|
static int ci_hdrc_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
@ -1007,11 +1054,18 @@ static int ci_hdrc_probe(struct platform_device *pdev)
|
|||||||
ci_hdrc_otg_fsm_start(ci);
|
ci_hdrc_otg_fsm_start(ci);
|
||||||
|
|
||||||
device_set_wakeup_capable(&pdev->dev, true);
|
device_set_wakeup_capable(&pdev->dev, true);
|
||||||
|
|
||||||
ret = dbg_create_files(ci);
|
ret = dbg_create_files(ci);
|
||||||
if (!ret)
|
if (ret)
|
||||||
return 0;
|
goto stop;
|
||||||
|
|
||||||
|
ret = sysfs_create_group(&dev->kobj, &ci_attr_group);
|
||||||
|
if (ret)
|
||||||
|
goto remove_debug;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
remove_debug:
|
||||||
|
dbg_remove_files(ci);
|
||||||
stop:
|
stop:
|
||||||
ci_role_destroy(ci);
|
ci_role_destroy(ci);
|
||||||
deinit_phy:
|
deinit_phy:
|
||||||
@ -1033,6 +1087,7 @@ static int ci_hdrc_remove(struct platform_device *pdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
dbg_remove_files(ci);
|
dbg_remove_files(ci);
|
||||||
|
sysfs_remove_group(&ci->dev->kobj, &ci_attr_group);
|
||||||
ci_role_destroy(ci);
|
ci_role_destroy(ci);
|
||||||
ci_hdrc_enter_lpm(ci, true);
|
ci_hdrc_enter_lpm(ci, true);
|
||||||
ci_usb_phy_exit(ci);
|
ci_usb_phy_exit(ci);
|
||||||
|
@ -123,7 +123,8 @@ static int host_start(struct ci_hdrc *ci)
|
|||||||
if (usb_disabled())
|
if (usb_disabled())
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
hcd = usb_create_hcd(&ci_ehci_hc_driver, ci->dev, dev_name(ci->dev));
|
hcd = __usb_create_hcd(&ci_ehci_hc_driver, ci->dev->parent,
|
||||||
|
ci->dev, dev_name(ci->dev), NULL);
|
||||||
if (!hcd)
|
if (!hcd)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
@ -423,7 +423,8 @@ static int _hardware_enqueue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
|
|||||||
|
|
||||||
hwreq->req.status = -EALREADY;
|
hwreq->req.status = -EALREADY;
|
||||||
|
|
||||||
ret = usb_gadget_map_request(&ci->gadget, &hwreq->req, hwep->dir);
|
ret = usb_gadget_map_request_by_dev(ci->dev->parent,
|
||||||
|
&hwreq->req, hwep->dir);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -603,7 +604,8 @@ static int _hardware_dequeue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
|
|||||||
list_del_init(&node->td);
|
list_del_init(&node->td);
|
||||||
}
|
}
|
||||||
|
|
||||||
usb_gadget_unmap_request(&hwep->ci->gadget, &hwreq->req, hwep->dir);
|
usb_gadget_unmap_request_by_dev(hwep->ci->dev->parent,
|
||||||
|
&hwreq->req, hwep->dir);
|
||||||
|
|
||||||
hwreq->req.actual += actual;
|
hwreq->req.actual += actual;
|
||||||
|
|
||||||
@ -1845,27 +1847,32 @@ static irqreturn_t udc_irq(struct ci_hdrc *ci)
|
|||||||
if (USBi_PCI & intr) {
|
if (USBi_PCI & intr) {
|
||||||
ci->gadget.speed = hw_port_is_high_speed(ci) ?
|
ci->gadget.speed = hw_port_is_high_speed(ci) ?
|
||||||
USB_SPEED_HIGH : USB_SPEED_FULL;
|
USB_SPEED_HIGH : USB_SPEED_FULL;
|
||||||
if (ci->suspended && ci->driver->resume) {
|
if (ci->suspended) {
|
||||||
spin_unlock(&ci->lock);
|
if (ci->driver->resume) {
|
||||||
ci->driver->resume(&ci->gadget);
|
spin_unlock(&ci->lock);
|
||||||
spin_lock(&ci->lock);
|
ci->driver->resume(&ci->gadget);
|
||||||
|
spin_lock(&ci->lock);
|
||||||
|
}
|
||||||
ci->suspended = 0;
|
ci->suspended = 0;
|
||||||
|
usb_gadget_set_state(&ci->gadget,
|
||||||
|
ci->resume_state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (USBi_UI & intr)
|
if (USBi_UI & intr)
|
||||||
isr_tr_complete_handler(ci);
|
isr_tr_complete_handler(ci);
|
||||||
|
|
||||||
if (USBi_SLI & intr) {
|
if ((USBi_SLI & intr) && !(ci->suspended)) {
|
||||||
|
ci->suspended = 1;
|
||||||
|
ci->resume_state = ci->gadget.state;
|
||||||
if (ci->gadget.speed != USB_SPEED_UNKNOWN &&
|
if (ci->gadget.speed != USB_SPEED_UNKNOWN &&
|
||||||
ci->driver->suspend) {
|
ci->driver->suspend) {
|
||||||
ci->suspended = 1;
|
|
||||||
spin_unlock(&ci->lock);
|
spin_unlock(&ci->lock);
|
||||||
ci->driver->suspend(&ci->gadget);
|
ci->driver->suspend(&ci->gadget);
|
||||||
usb_gadget_set_state(&ci->gadget,
|
|
||||||
USB_STATE_SUSPENDED);
|
|
||||||
spin_lock(&ci->lock);
|
spin_lock(&ci->lock);
|
||||||
}
|
}
|
||||||
|
usb_gadget_set_state(&ci->gadget,
|
||||||
|
USB_STATE_SUSPENDED);
|
||||||
}
|
}
|
||||||
retval = IRQ_HANDLED;
|
retval = IRQ_HANDLED;
|
||||||
} else {
|
} else {
|
||||||
@ -1899,13 +1906,13 @@ static int udc_start(struct ci_hdrc *ci)
|
|||||||
INIT_LIST_HEAD(&ci->gadget.ep_list);
|
INIT_LIST_HEAD(&ci->gadget.ep_list);
|
||||||
|
|
||||||
/* alloc resources */
|
/* alloc resources */
|
||||||
ci->qh_pool = dma_pool_create("ci_hw_qh", dev,
|
ci->qh_pool = dma_pool_create("ci_hw_qh", dev->parent,
|
||||||
sizeof(struct ci_hw_qh),
|
sizeof(struct ci_hw_qh),
|
||||||
64, CI_HDRC_PAGE_SIZE);
|
64, CI_HDRC_PAGE_SIZE);
|
||||||
if (ci->qh_pool == NULL)
|
if (ci->qh_pool == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
ci->td_pool = dma_pool_create("ci_hw_td", dev,
|
ci->td_pool = dma_pool_create("ci_hw_td", dev->parent,
|
||||||
sizeof(struct ci_hw_td),
|
sizeof(struct ci_hw_td),
|
||||||
64, CI_HDRC_PAGE_SIZE);
|
64, CI_HDRC_PAGE_SIZE);
|
||||||
if (ci->td_pool == NULL) {
|
if (ci->td_pool == NULL) {
|
||||||
@ -1973,6 +1980,8 @@ static void udc_id_switch_for_host(struct ci_hdrc *ci)
|
|||||||
*/
|
*/
|
||||||
if (ci->is_otg)
|
if (ci->is_otg)
|
||||||
hw_write_otgsc(ci, OTGSC_BSVIE | OTGSC_BSVIS, OTGSC_BSVIS);
|
hw_write_otgsc(ci, OTGSC_BSVIE | OTGSC_BSVIS, OTGSC_BSVIS);
|
||||||
|
|
||||||
|
ci->vbus_active = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -12,7 +12,7 @@ config USB_ACM
|
|||||||
Please read <file:Documentation/usb/acm.txt> for details.
|
Please read <file:Documentation/usb/acm.txt> for details.
|
||||||
|
|
||||||
If your modem only reports "Cls=ff(vend.)" in the descriptors in
|
If your modem only reports "Cls=ff(vend.)" in the descriptors in
|
||||||
/proc/bus/usb/devices, then your modem will not work with this
|
/sys/kernel/debug/usb/devices, then your modem will not work with this
|
||||||
driver.
|
driver.
|
||||||
|
|
||||||
To compile this driver as a module, choose M here: the
|
To compile this driver as a module, choose M here: the
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/log2.h>
|
||||||
#include <linux/tty.h>
|
#include <linux/tty.h>
|
||||||
#include <linux/serial.h>
|
#include <linux/serial.h>
|
||||||
#include <linux/tty_driver.h>
|
#include <linux/tty_driver.h>
|
||||||
@ -283,39 +284,13 @@ static DEVICE_ATTR(iCountryCodeRelDate, S_IRUGO, show_country_rel_date, NULL);
|
|||||||
* Interrupt handlers for various ACM device responses
|
* Interrupt handlers for various ACM device responses
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* control interface reports status changes with "interrupt" transfers */
|
static void acm_process_notification(struct acm *acm, unsigned char *buf)
|
||||||
static void acm_ctrl_irq(struct urb *urb)
|
|
||||||
{
|
{
|
||||||
struct acm *acm = urb->context;
|
|
||||||
struct usb_cdc_notification *dr = urb->transfer_buffer;
|
|
||||||
unsigned char *data;
|
|
||||||
int newctrl;
|
int newctrl;
|
||||||
int difference;
|
int difference;
|
||||||
int retval;
|
struct usb_cdc_notification *dr = (struct usb_cdc_notification *)buf;
|
||||||
int status = urb->status;
|
unsigned char *data = buf + sizeof(struct usb_cdc_notification);
|
||||||
|
|
||||||
switch (status) {
|
|
||||||
case 0:
|
|
||||||
/* success */
|
|
||||||
break;
|
|
||||||
case -ECONNRESET:
|
|
||||||
case -ENOENT:
|
|
||||||
case -ESHUTDOWN:
|
|
||||||
/* this urb is terminated, clean up */
|
|
||||||
dev_dbg(&acm->control->dev,
|
|
||||||
"%s - urb shutting down with status: %d\n",
|
|
||||||
__func__, status);
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
dev_dbg(&acm->control->dev,
|
|
||||||
"%s - nonzero urb status received: %d\n",
|
|
||||||
__func__, status);
|
|
||||||
goto exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
usb_mark_last_busy(acm->dev);
|
|
||||||
|
|
||||||
data = (unsigned char *)(dr + 1);
|
|
||||||
switch (dr->bNotificationType) {
|
switch (dr->bNotificationType) {
|
||||||
case USB_CDC_NOTIFY_NETWORK_CONNECTION:
|
case USB_CDC_NOTIFY_NETWORK_CONNECTION:
|
||||||
dev_dbg(&acm->control->dev,
|
dev_dbg(&acm->control->dev,
|
||||||
@ -323,7 +298,15 @@ static void acm_ctrl_irq(struct urb *urb)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case USB_CDC_NOTIFY_SERIAL_STATE:
|
case USB_CDC_NOTIFY_SERIAL_STATE:
|
||||||
|
if (le16_to_cpu(dr->wLength) != 2) {
|
||||||
|
dev_dbg(&acm->control->dev,
|
||||||
|
"%s - malformed serial state\n", __func__);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
newctrl = get_unaligned_le16(data);
|
newctrl = get_unaligned_le16(data);
|
||||||
|
dev_dbg(&acm->control->dev,
|
||||||
|
"%s - serial state: 0x%x\n", __func__, newctrl);
|
||||||
|
|
||||||
if (!acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
|
if (!acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
|
||||||
dev_dbg(&acm->control->dev,
|
dev_dbg(&acm->control->dev,
|
||||||
@ -359,13 +342,86 @@ static void acm_ctrl_irq(struct urb *urb)
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
dev_dbg(&acm->control->dev,
|
dev_dbg(&acm->control->dev,
|
||||||
"%s - unknown notification %d received: index %d "
|
"%s - unknown notification %d received: index %d len %d\n",
|
||||||
"len %d data0 %d data1 %d\n",
|
|
||||||
__func__,
|
__func__,
|
||||||
dr->bNotificationType, dr->wIndex,
|
dr->bNotificationType, dr->wIndex, dr->wLength);
|
||||||
dr->wLength, data[0], data[1]);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* control interface reports status changes with "interrupt" transfers */
|
||||||
|
static void acm_ctrl_irq(struct urb *urb)
|
||||||
|
{
|
||||||
|
struct acm *acm = urb->context;
|
||||||
|
struct usb_cdc_notification *dr = urb->transfer_buffer;
|
||||||
|
unsigned int current_size = urb->actual_length;
|
||||||
|
unsigned int expected_size, copy_size, alloc_size;
|
||||||
|
int retval;
|
||||||
|
int status = urb->status;
|
||||||
|
|
||||||
|
switch (status) {
|
||||||
|
case 0:
|
||||||
|
/* success */
|
||||||
|
break;
|
||||||
|
case -ECONNRESET:
|
||||||
|
case -ENOENT:
|
||||||
|
case -ESHUTDOWN:
|
||||||
|
/* this urb is terminated, clean up */
|
||||||
|
acm->nb_index = 0;
|
||||||
|
dev_dbg(&acm->control->dev,
|
||||||
|
"%s - urb shutting down with status: %d\n",
|
||||||
|
__func__, status);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
dev_dbg(&acm->control->dev,
|
||||||
|
"%s - nonzero urb status received: %d\n",
|
||||||
|
__func__, status);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
usb_mark_last_busy(acm->dev);
|
||||||
|
|
||||||
|
if (acm->nb_index)
|
||||||
|
dr = (struct usb_cdc_notification *)acm->notification_buffer;
|
||||||
|
|
||||||
|
/* size = notification-header + (optional) data */
|
||||||
|
expected_size = sizeof(struct usb_cdc_notification) +
|
||||||
|
le16_to_cpu(dr->wLength);
|
||||||
|
|
||||||
|
if (current_size < expected_size) {
|
||||||
|
/* notification is transmitted fragmented, reassemble */
|
||||||
|
if (acm->nb_size < expected_size) {
|
||||||
|
if (acm->nb_size) {
|
||||||
|
kfree(acm->notification_buffer);
|
||||||
|
acm->nb_size = 0;
|
||||||
|
}
|
||||||
|
alloc_size = roundup_pow_of_two(expected_size);
|
||||||
|
/*
|
||||||
|
* kmalloc ensures a valid notification_buffer after a
|
||||||
|
* use of kfree in case the previous allocation was too
|
||||||
|
* small. Final freeing is done on disconnect.
|
||||||
|
*/
|
||||||
|
acm->notification_buffer =
|
||||||
|
kmalloc(alloc_size, GFP_ATOMIC);
|
||||||
|
if (!acm->notification_buffer)
|
||||||
|
goto exit;
|
||||||
|
acm->nb_size = alloc_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
copy_size = min(current_size,
|
||||||
|
expected_size - acm->nb_index);
|
||||||
|
|
||||||
|
memcpy(&acm->notification_buffer[acm->nb_index],
|
||||||
|
urb->transfer_buffer, copy_size);
|
||||||
|
acm->nb_index += copy_size;
|
||||||
|
current_size = acm->nb_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_size >= expected_size) {
|
||||||
|
/* notification complete */
|
||||||
|
acm_process_notification(acm, (unsigned char *)dr);
|
||||||
|
acm->nb_index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
retval = usb_submit_urb(urb, GFP_ATOMIC);
|
retval = usb_submit_urb(urb, GFP_ATOMIC);
|
||||||
if (retval && retval != -EPERM)
|
if (retval && retval != -EPERM)
|
||||||
@ -1174,6 +1230,7 @@ static int acm_probe(struct usb_interface *intf,
|
|||||||
int combined_interfaces = 0;
|
int combined_interfaces = 0;
|
||||||
struct device *tty_dev;
|
struct device *tty_dev;
|
||||||
int rv = -ENOMEM;
|
int rv = -ENOMEM;
|
||||||
|
int res;
|
||||||
|
|
||||||
/* normal quirks */
|
/* normal quirks */
|
||||||
quirks = (unsigned long)id->driver_info;
|
quirks = (unsigned long)id->driver_info;
|
||||||
@ -1274,23 +1331,12 @@ static int acm_probe(struct usb_interface *intf,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
look_for_collapsed_interface:
|
look_for_collapsed_interface:
|
||||||
for (i = 0; i < 3; i++) {
|
res = usb_find_common_endpoints(data_interface->cur_altsetting,
|
||||||
struct usb_endpoint_descriptor *ep;
|
&epread, &epwrite, &epctrl, NULL);
|
||||||
ep = &data_interface->cur_altsetting->endpoint[i].desc;
|
if (res)
|
||||||
|
return res;
|
||||||
|
|
||||||
if (usb_endpoint_is_int_in(ep))
|
goto made_compressed_probe;
|
||||||
epctrl = ep;
|
|
||||||
else if (usb_endpoint_is_bulk_out(ep))
|
|
||||||
epwrite = ep;
|
|
||||||
else if (usb_endpoint_is_bulk_in(ep))
|
|
||||||
epread = ep;
|
|
||||||
else
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
if (!epctrl || !epread || !epwrite)
|
|
||||||
return -ENODEV;
|
|
||||||
else
|
|
||||||
goto made_compressed_probe;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
skip_normal_probe:
|
skip_normal_probe:
|
||||||
@ -1488,6 +1534,9 @@ skip_countries:
|
|||||||
epctrl->bInterval ? epctrl->bInterval : 16);
|
epctrl->bInterval ? epctrl->bInterval : 16);
|
||||||
acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||||
acm->ctrlurb->transfer_dma = acm->ctrl_dma;
|
acm->ctrlurb->transfer_dma = acm->ctrl_dma;
|
||||||
|
acm->notification_buffer = NULL;
|
||||||
|
acm->nb_index = 0;
|
||||||
|
acm->nb_size = 0;
|
||||||
|
|
||||||
dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
|
dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
|
||||||
|
|
||||||
@ -1580,6 +1629,8 @@ static void acm_disconnect(struct usb_interface *intf)
|
|||||||
usb_free_coherent(acm->dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
|
usb_free_coherent(acm->dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
|
||||||
acm_read_buffers_free(acm);
|
acm_read_buffers_free(acm);
|
||||||
|
|
||||||
|
kfree(acm->notification_buffer);
|
||||||
|
|
||||||
if (!acm->combined_interfaces)
|
if (!acm->combined_interfaces)
|
||||||
usb_driver_release_interface(&acm_driver, intf == acm->control ?
|
usb_driver_release_interface(&acm_driver, intf == acm->control ?
|
||||||
acm->data : acm->control);
|
acm->data : acm->control);
|
||||||
|
@ -98,7 +98,9 @@ struct acm {
|
|||||||
struct acm_wb *putbuffer; /* for acm_tty_put_char() */
|
struct acm_wb *putbuffer; /* for acm_tty_put_char() */
|
||||||
int rx_buflimit;
|
int rx_buflimit;
|
||||||
spinlock_t read_lock;
|
spinlock_t read_lock;
|
||||||
int write_used; /* number of non-empty write buffers */
|
u8 *notification_buffer; /* to reassemble fragmented notifications */
|
||||||
|
unsigned int nb_index;
|
||||||
|
unsigned int nb_size;
|
||||||
int transmitting;
|
int transmitting;
|
||||||
spinlock_t write_lock;
|
spinlock_t write_lock;
|
||||||
struct mutex mutex;
|
struct mutex mutex;
|
||||||
|
@ -58,7 +58,6 @@ MODULE_DEVICE_TABLE (usb, wdm_ids);
|
|||||||
#define WDM_SUSPENDING 8
|
#define WDM_SUSPENDING 8
|
||||||
#define WDM_RESETTING 9
|
#define WDM_RESETTING 9
|
||||||
#define WDM_OVERFLOW 10
|
#define WDM_OVERFLOW 10
|
||||||
#define WDM_DRAIN_ON_OPEN 11
|
|
||||||
|
|
||||||
#define WDM_MAX 16
|
#define WDM_MAX 16
|
||||||
|
|
||||||
@ -182,7 +181,7 @@ static void wdm_in_callback(struct urb *urb)
|
|||||||
"nonzero urb status received: -ESHUTDOWN\n");
|
"nonzero urb status received: -ESHUTDOWN\n");
|
||||||
goto skip_error;
|
goto skip_error;
|
||||||
case -EPIPE:
|
case -EPIPE:
|
||||||
dev_dbg(&desc->intf->dev,
|
dev_err(&desc->intf->dev,
|
||||||
"nonzero urb status received: -EPIPE\n");
|
"nonzero urb status received: -EPIPE\n");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -210,25 +209,6 @@ static void wdm_in_callback(struct urb *urb)
|
|||||||
desc->reslength = length;
|
desc->reslength = length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Handling devices with the WDM_DRAIN_ON_OPEN flag set:
|
|
||||||
* If desc->resp_count is unset, then the urb was submitted
|
|
||||||
* without a prior notification. If the device returned any
|
|
||||||
* data, then this implies that it had messages queued without
|
|
||||||
* notifying us. Continue reading until that queue is flushed.
|
|
||||||
*/
|
|
||||||
if (!desc->resp_count) {
|
|
||||||
if (!length) {
|
|
||||||
/* do not propagate the expected -EPIPE */
|
|
||||||
desc->rerr = 0;
|
|
||||||
goto unlock;
|
|
||||||
}
|
|
||||||
dev_dbg(&desc->intf->dev, "got %d bytes without notification\n", length);
|
|
||||||
set_bit(WDM_RESPONDING, &desc->flags);
|
|
||||||
usb_submit_urb(desc->response, GFP_ATOMIC);
|
|
||||||
}
|
|
||||||
|
|
||||||
skip_error:
|
skip_error:
|
||||||
set_bit(WDM_READ, &desc->flags);
|
set_bit(WDM_READ, &desc->flags);
|
||||||
wake_up(&desc->wait);
|
wake_up(&desc->wait);
|
||||||
@ -243,7 +223,6 @@ skip_error:
|
|||||||
service_outstanding_interrupt(desc);
|
service_outstanding_interrupt(desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
unlock:
|
|
||||||
spin_unlock(&desc->iuspin);
|
spin_unlock(&desc->iuspin);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -686,17 +665,6 @@ static int wdm_open(struct inode *inode, struct file *file)
|
|||||||
dev_err(&desc->intf->dev,
|
dev_err(&desc->intf->dev,
|
||||||
"Error submitting int urb - %d\n", rv);
|
"Error submitting int urb - %d\n", rv);
|
||||||
rv = usb_translate_errors(rv);
|
rv = usb_translate_errors(rv);
|
||||||
} else if (test_bit(WDM_DRAIN_ON_OPEN, &desc->flags)) {
|
|
||||||
/*
|
|
||||||
* Some devices keep pending messages queued
|
|
||||||
* without resending notifications. We must
|
|
||||||
* flush the message queue before we can
|
|
||||||
* assume a one-to-one relationship between
|
|
||||||
* notifications and messages in the queue
|
|
||||||
*/
|
|
||||||
dev_dbg(&desc->intf->dev, "draining queued data\n");
|
|
||||||
set_bit(WDM_RESPONDING, &desc->flags);
|
|
||||||
rv = usb_submit_urb(desc->response, GFP_KERNEL);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rv = 0;
|
rv = 0;
|
||||||
@ -803,8 +771,7 @@ static void wdm_rxwork(struct work_struct *work)
|
|||||||
/* --- 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,
|
||||||
u16 bufsize, int (*manage_power)(struct usb_interface *, int),
|
u16 bufsize, int (*manage_power)(struct usb_interface *, int))
|
||||||
bool drain_on_open)
|
|
||||||
{
|
{
|
||||||
int rv = -ENOMEM;
|
int rv = -ENOMEM;
|
||||||
struct wdm_device *desc;
|
struct wdm_device *desc;
|
||||||
@ -891,68 +858,6 @@ static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor
|
|||||||
|
|
||||||
desc->manage_power = manage_power;
|
desc->manage_power = manage_power;
|
||||||
|
|
||||||
/*
|
|
||||||
* "drain_on_open" enables a hack to work around a firmware
|
|
||||||
* issue observed on network functions, in particular MBIM
|
|
||||||
* functions.
|
|
||||||
*
|
|
||||||
* Quoting section 7 of the CDC-WMC r1.1 specification:
|
|
||||||
*
|
|
||||||
* "The firmware shall interpret GetEncapsulatedResponse as a
|
|
||||||
* request to read response bytes. The firmware shall send
|
|
||||||
* the next wLength bytes from the response. The firmware
|
|
||||||
* shall allow the host to retrieve data using any number of
|
|
||||||
* GetEncapsulatedResponse requests. The firmware shall
|
|
||||||
* return a zero- length reply if there are no data bytes
|
|
||||||
* available.
|
|
||||||
*
|
|
||||||
* The firmware shall send ResponseAvailable notifications
|
|
||||||
* periodically, using any appropriate algorithm, to inform
|
|
||||||
* the host that there is data available in the reply
|
|
||||||
* buffer. The firmware is allowed to send ResponseAvailable
|
|
||||||
* notifications even if there is no data available, but
|
|
||||||
* this will obviously reduce overall performance."
|
|
||||||
*
|
|
||||||
* These requirements, although they make equally sense, are
|
|
||||||
* often not implemented by network functions. Some firmwares
|
|
||||||
* will queue data indefinitely, without ever resending a
|
|
||||||
* notification. The result is that the driver and firmware
|
|
||||||
* loses "syncronization" if the driver ever fails to respond
|
|
||||||
* to a single notification, something which easily can happen
|
|
||||||
* on release(). When this happens, the driver will appear to
|
|
||||||
* never receive notifications for the most current data. Each
|
|
||||||
* notification will only cause a single read, which returns
|
|
||||||
* the oldest data in the firmware's queue.
|
|
||||||
*
|
|
||||||
* The "drain_on_open" hack resolves the situation by draining
|
|
||||||
* data from the firmware until none is returned, without a
|
|
||||||
* prior notification.
|
|
||||||
*
|
|
||||||
* This will inevitably race with the firmware, risking that
|
|
||||||
* we read data from the device before handling the associated
|
|
||||||
* notification. To make things worse, some of the devices
|
|
||||||
* needing the hack do not implement the "return zero if no
|
|
||||||
* data is available" requirement either. Instead they return
|
|
||||||
* an error on the subsequent read in this case. This means
|
|
||||||
* that "winning" the race can cause an unexpected EIO to
|
|
||||||
* userspace.
|
|
||||||
*
|
|
||||||
* "winning" the race is more likely on resume() than on
|
|
||||||
* open(), and the unexpected error is more harmful in the
|
|
||||||
* middle of an open session. The hack is therefore only
|
|
||||||
* applied on open(), and not on resume() where it logically
|
|
||||||
* would be equally necessary. So we define open() as the only
|
|
||||||
* driver <-> device "syncronization point". Should we happen
|
|
||||||
* to lose a notification after open(), then syncronization
|
|
||||||
* will be lost until release()
|
|
||||||
*
|
|
||||||
* The hack should not be enabled for CDC WDM devices
|
|
||||||
* conforming to the CDC-WMC r1.1 specification. This is
|
|
||||||
* ensured by setting drain_on_open to false in wdm_probe().
|
|
||||||
*/
|
|
||||||
if (drain_on_open)
|
|
||||||
set_bit(WDM_DRAIN_ON_OPEN, &desc->flags);
|
|
||||||
|
|
||||||
spin_lock(&wdm_device_list_lock);
|
spin_lock(&wdm_device_list_lock);
|
||||||
list_add(&desc->device_list, &wdm_device_list);
|
list_add(&desc->device_list, &wdm_device_list);
|
||||||
spin_unlock(&wdm_device_list_lock);
|
spin_unlock(&wdm_device_list_lock);
|
||||||
@ -1006,7 +911,7 @@ static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
|||||||
goto err;
|
goto err;
|
||||||
ep = &iface->endpoint[0].desc;
|
ep = &iface->endpoint[0].desc;
|
||||||
|
|
||||||
rv = wdm_create(intf, ep, maxcom, &wdm_manage_power, false);
|
rv = wdm_create(intf, ep, maxcom, &wdm_manage_power);
|
||||||
|
|
||||||
err:
|
err:
|
||||||
return rv;
|
return rv;
|
||||||
@ -1038,7 +943,7 @@ struct usb_driver *usb_cdc_wdm_register(struct usb_interface *intf,
|
|||||||
{
|
{
|
||||||
int rv = -EINVAL;
|
int rv = -EINVAL;
|
||||||
|
|
||||||
rv = wdm_create(intf, ep, bufsize, manage_power, true);
|
rv = wdm_create(intf, ep, bufsize, manage_power);
|
||||||
if (rv < 0)
|
if (rv < 0)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
|
@ -294,7 +294,7 @@ static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, i
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* See the description for usblp_select_alts() below for the usage
|
* See the description for usblp_select_alts() below for the usage
|
||||||
* explanation. Look into your /proc/bus/usb/devices and dmesg in
|
* explanation. Look into your /sys/kernel/debug/usb/devices and dmesg in
|
||||||
* case of any trouble.
|
* case of any trouble.
|
||||||
*/
|
*/
|
||||||
static int proto_bias = -1;
|
static int proto_bias = -1;
|
||||||
@ -1239,8 +1239,9 @@ static int usblp_select_alts(struct usblp *usblp)
|
|||||||
{
|
{
|
||||||
struct usb_interface *if_alt;
|
struct usb_interface *if_alt;
|
||||||
struct usb_host_interface *ifd;
|
struct usb_host_interface *ifd;
|
||||||
struct usb_endpoint_descriptor *epd, *epwrite, *epread;
|
struct usb_endpoint_descriptor *epwrite, *epread;
|
||||||
int p, i, e;
|
int p, i;
|
||||||
|
int res;
|
||||||
|
|
||||||
if_alt = usblp->intf;
|
if_alt = usblp->intf;
|
||||||
|
|
||||||
@ -1260,31 +1261,21 @@ static int usblp_select_alts(struct usblp *usblp)
|
|||||||
ifd->desc.bInterfaceProtocol > USBLP_LAST_PROTOCOL)
|
ifd->desc.bInterfaceProtocol > USBLP_LAST_PROTOCOL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Look for bulk OUT and IN endpoints. */
|
/* Look for the expected bulk endpoints. */
|
||||||
epwrite = epread = NULL;
|
if (ifd->desc.bInterfaceProtocol > 1) {
|
||||||
for (e = 0; e < ifd->desc.bNumEndpoints; e++) {
|
res = usb_find_common_endpoints(ifd,
|
||||||
epd = &ifd->endpoint[e].desc;
|
&epread, &epwrite, NULL, NULL);
|
||||||
|
} else {
|
||||||
if (usb_endpoint_is_bulk_out(epd))
|
epread = NULL;
|
||||||
if (!epwrite)
|
res = usb_find_bulk_out_endpoint(ifd, &epwrite);
|
||||||
epwrite = epd;
|
|
||||||
|
|
||||||
if (usb_endpoint_is_bulk_in(epd))
|
|
||||||
if (!epread)
|
|
||||||
epread = epd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ignore buggy hardware without the right endpoints. */
|
/* Ignore buggy hardware without the right endpoints. */
|
||||||
if (!epwrite || (ifd->desc.bInterfaceProtocol > 1 && !epread))
|
if (res)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/*
|
/* Turn off reads for buggy bidirectional printers. */
|
||||||
* Turn off reads for USB_CLASS_PRINTER/1/1 (unidirectional)
|
if (usblp->quirks & USBLP_QUIRK_BIDIR) {
|
||||||
* interfaces and buggy bidirectional printers.
|
|
||||||
*/
|
|
||||||
if (ifd->desc.bInterfaceProtocol == 1) {
|
|
||||||
epread = NULL;
|
|
||||||
} else if (usblp->quirks & USBLP_QUIRK_BIDIR) {
|
|
||||||
printk(KERN_INFO "usblp%d: Disabling reads from "
|
printk(KERN_INFO "usblp%d: Disabling reads from "
|
||||||
"problematic bidirectional printer\n",
|
"problematic bidirectional printer\n",
|
||||||
usblp->minor);
|
usblp->minor);
|
||||||
|
@ -1375,7 +1375,7 @@ static int usbtmc_probe(struct usb_interface *intf,
|
|||||||
{
|
{
|
||||||
struct usbtmc_device_data *data;
|
struct usbtmc_device_data *data;
|
||||||
struct usb_host_interface *iface_desc;
|
struct usb_host_interface *iface_desc;
|
||||||
struct usb_endpoint_descriptor *endpoint;
|
struct usb_endpoint_descriptor *bulk_in, *bulk_out, *int_in;
|
||||||
int n;
|
int n;
|
||||||
int retcode;
|
int retcode;
|
||||||
|
|
||||||
@ -1421,49 +1421,29 @@ static int usbtmc_probe(struct usb_interface *intf,
|
|||||||
iface_desc = data->intf->cur_altsetting;
|
iface_desc = data->intf->cur_altsetting;
|
||||||
data->ifnum = iface_desc->desc.bInterfaceNumber;
|
data->ifnum = iface_desc->desc.bInterfaceNumber;
|
||||||
|
|
||||||
/* Find bulk in endpoint */
|
/* Find bulk endpoints */
|
||||||
for (n = 0; n < iface_desc->desc.bNumEndpoints; n++) {
|
retcode = usb_find_common_endpoints(iface_desc,
|
||||||
endpoint = &iface_desc->endpoint[n].desc;
|
&bulk_in, &bulk_out, NULL, NULL);
|
||||||
|
if (retcode) {
|
||||||
if (usb_endpoint_is_bulk_in(endpoint)) {
|
|
||||||
data->bulk_in = endpoint->bEndpointAddress;
|
|
||||||
dev_dbg(&intf->dev, "Found bulk in endpoint at %u\n",
|
|
||||||
data->bulk_in);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find bulk out endpoint */
|
|
||||||
for (n = 0; n < iface_desc->desc.bNumEndpoints; n++) {
|
|
||||||
endpoint = &iface_desc->endpoint[n].desc;
|
|
||||||
|
|
||||||
if (usb_endpoint_is_bulk_out(endpoint)) {
|
|
||||||
data->bulk_out = endpoint->bEndpointAddress;
|
|
||||||
dev_dbg(&intf->dev, "Found Bulk out endpoint at %u\n",
|
|
||||||
data->bulk_out);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!data->bulk_out || !data->bulk_in) {
|
|
||||||
dev_err(&intf->dev, "bulk endpoints not found\n");
|
dev_err(&intf->dev, "bulk endpoints not found\n");
|
||||||
retcode = -ENODEV;
|
|
||||||
goto err_put;
|
goto err_put;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find int endpoint */
|
data->bulk_in = bulk_in->bEndpointAddress;
|
||||||
for (n = 0; n < iface_desc->desc.bNumEndpoints; n++) {
|
dev_dbg(&intf->dev, "Found bulk in endpoint at %u\n", data->bulk_in);
|
||||||
endpoint = &iface_desc->endpoint[n].desc;
|
|
||||||
|
|
||||||
if (usb_endpoint_is_int_in(endpoint)) {
|
data->bulk_out = bulk_out->bEndpointAddress;
|
||||||
data->iin_ep_present = 1;
|
dev_dbg(&intf->dev, "Found Bulk out endpoint at %u\n", data->bulk_out);
|
||||||
data->iin_ep = endpoint->bEndpointAddress;
|
|
||||||
data->iin_wMaxPacketSize = usb_endpoint_maxp(endpoint);
|
/* Find int endpoint */
|
||||||
data->iin_interval = endpoint->bInterval;
|
retcode = usb_find_int_in_endpoint(iface_desc, &int_in);
|
||||||
dev_dbg(&intf->dev, "Found Int in endpoint at %u\n",
|
if (!retcode) {
|
||||||
|
data->iin_ep_present = 1;
|
||||||
|
data->iin_ep = int_in->bEndpointAddress;
|
||||||
|
data->iin_wMaxPacketSize = usb_endpoint_maxp(int_in);
|
||||||
|
data->iin_interval = int_in->bInterval;
|
||||||
|
dev_dbg(&intf->dev, "Found Int in endpoint at %u\n",
|
||||||
data->iin_ep);
|
data->iin_ep);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
retcode = get_capabilities(data);
|
retcode = get_capabilities(data);
|
||||||
|
@ -31,6 +31,13 @@
|
|||||||
#include <linux/usb/otg.h>
|
#include <linux/usb/otg.h>
|
||||||
#include <linux/usb/otg-fsm.h>
|
#include <linux/usb/otg-fsm.h>
|
||||||
|
|
||||||
|
#ifdef VERBOSE
|
||||||
|
#define VDBG(fmt, args...) pr_debug("[%s] " fmt, \
|
||||||
|
__func__, ## args)
|
||||||
|
#else
|
||||||
|
#define VDBG(stuff...) do {} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Change USB protocol when there is a protocol change */
|
/* Change USB protocol when there is a protocol change */
|
||||||
static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
|
static int otg_set_protocol(struct otg_fsm *fsm, int protocol)
|
||||||
{
|
{
|
||||||
|
@ -8,7 +8,7 @@ usbcore-y += devio.o notify.o generic.o quirks.o devices.o
|
|||||||
usbcore-y += port.o
|
usbcore-y += port.o
|
||||||
|
|
||||||
usbcore-$(CONFIG_OF) += of.o
|
usbcore-$(CONFIG_OF) += of.o
|
||||||
usbcore-$(CONFIG_PCI) += hcd-pci.o
|
usbcore-$(CONFIG_USB_PCI) += hcd-pci.o
|
||||||
usbcore-$(CONFIG_ACPI) += usb-acpi.o
|
usbcore-$(CONFIG_ACPI) += usb-acpi.o
|
||||||
|
|
||||||
obj-$(CONFIG_USB) += usbcore.o
|
obj-$(CONFIG_USB) += usbcore.o
|
||||||
|
@ -66,7 +66,7 @@ int hcd_buffer_create(struct usb_hcd *hcd)
|
|||||||
int i, size;
|
int i, size;
|
||||||
|
|
||||||
if (!IS_ENABLED(CONFIG_HAS_DMA) ||
|
if (!IS_ENABLED(CONFIG_HAS_DMA) ||
|
||||||
(!hcd->self.controller->dma_mask &&
|
(!is_device_dma_capable(hcd->self.sysdev) &&
|
||||||
!(hcd->driver->flags & HCD_LOCAL_MEM)))
|
!(hcd->driver->flags & HCD_LOCAL_MEM)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -75,7 +75,7 @@ int hcd_buffer_create(struct usb_hcd *hcd)
|
|||||||
if (!size)
|
if (!size)
|
||||||
continue;
|
continue;
|
||||||
snprintf(name, sizeof(name), "buffer-%d", size);
|
snprintf(name, sizeof(name), "buffer-%d", size);
|
||||||
hcd->pool[i] = dma_pool_create(name, hcd->self.controller,
|
hcd->pool[i] = dma_pool_create(name, hcd->self.sysdev,
|
||||||
size, size, 0);
|
size, size, 0);
|
||||||
if (!hcd->pool[i]) {
|
if (!hcd->pool[i]) {
|
||||||
hcd_buffer_destroy(hcd);
|
hcd_buffer_destroy(hcd);
|
||||||
@ -130,7 +130,7 @@ void *hcd_buffer_alloc(
|
|||||||
|
|
||||||
/* some USB hosts just use PIO */
|
/* some USB hosts just use PIO */
|
||||||
if (!IS_ENABLED(CONFIG_HAS_DMA) ||
|
if (!IS_ENABLED(CONFIG_HAS_DMA) ||
|
||||||
(!bus->controller->dma_mask &&
|
(!is_device_dma_capable(bus->sysdev) &&
|
||||||
!(hcd->driver->flags & HCD_LOCAL_MEM))) {
|
!(hcd->driver->flags & HCD_LOCAL_MEM))) {
|
||||||
*dma = ~(dma_addr_t) 0;
|
*dma = ~(dma_addr_t) 0;
|
||||||
return kmalloc(size, mem_flags);
|
return kmalloc(size, mem_flags);
|
||||||
@ -140,7 +140,7 @@ void *hcd_buffer_alloc(
|
|||||||
if (size <= pool_max[i])
|
if (size <= pool_max[i])
|
||||||
return dma_pool_alloc(hcd->pool[i], mem_flags, dma);
|
return dma_pool_alloc(hcd->pool[i], mem_flags, dma);
|
||||||
}
|
}
|
||||||
return dma_alloc_coherent(hcd->self.controller, size, dma, mem_flags);
|
return dma_alloc_coherent(hcd->self.sysdev, size, dma, mem_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hcd_buffer_free(
|
void hcd_buffer_free(
|
||||||
@ -157,7 +157,7 @@ void hcd_buffer_free(
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (!IS_ENABLED(CONFIG_HAS_DMA) ||
|
if (!IS_ENABLED(CONFIG_HAS_DMA) ||
|
||||||
(!bus->controller->dma_mask &&
|
(!is_device_dma_capable(bus->sysdev) &&
|
||||||
!(hcd->driver->flags & HCD_LOCAL_MEM))) {
|
!(hcd->driver->flags & HCD_LOCAL_MEM))) {
|
||||||
kfree(addr);
|
kfree(addr);
|
||||||
return;
|
return;
|
||||||
@ -169,5 +169,5 @@ void hcd_buffer_free(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dma_free_coherent(hcd->self.controller, size, addr, dma);
|
dma_free_coherent(hcd->self.sysdev, size, addr, dma);
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
* <mountpoint>/devices contains USB topology, device, config, class,
|
* <mountpoint>/devices contains USB topology, device, config, class,
|
||||||
* interface, & endpoint data.
|
* interface, & endpoint data.
|
||||||
*
|
*
|
||||||
* I considered using /proc/bus/usb/devices/device# for each device
|
* I considered using /dev/bus/usb/device# for each device
|
||||||
* as it is attached or detached, but I didn't like this for some
|
* as it is attached or detached, but I didn't like this for some
|
||||||
* reason -- maybe it's just too deep of a directory structure.
|
* reason -- maybe it's just too deep of a directory structure.
|
||||||
* I also don't like looking in multiple places to gather and view
|
* I also don't like looking in multiple places to gather and view
|
||||||
@ -40,7 +40,7 @@
|
|||||||
* Converted the whole proc stuff to real
|
* Converted the whole proc stuff to real
|
||||||
* read methods. Now not the whole device list needs to fit
|
* read methods. Now not the whole device list needs to fit
|
||||||
* into one page, only the device list for one bus.
|
* into one page, only the device list for one bus.
|
||||||
* Added a poll method to /proc/bus/usb/devices, to wake
|
* Added a poll method to /sys/kernel/debug/usb/devices, to wake
|
||||||
* up an eventual usbd
|
* up an eventual usbd
|
||||||
* 2000-01-04: Thomas Sailer <sailer@ife.ee.ethz.ch>
|
* 2000-01-04: Thomas Sailer <sailer@ife.ee.ethz.ch>
|
||||||
* Turned into its own filesystem
|
* Turned into its own filesystem
|
||||||
|
@ -1331,6 +1331,24 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
|
|||||||
*/
|
*/
|
||||||
if (udev->parent && !PMSG_IS_AUTO(msg))
|
if (udev->parent && !PMSG_IS_AUTO(msg))
|
||||||
status = 0;
|
status = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the device is inaccessible, don't try to resume
|
||||||
|
* suspended interfaces and just return the error.
|
||||||
|
*/
|
||||||
|
if (status && status != -EBUSY) {
|
||||||
|
int err;
|
||||||
|
u16 devstat;
|
||||||
|
|
||||||
|
err = usb_get_status(udev, USB_RECIP_DEVICE, 0,
|
||||||
|
&devstat);
|
||||||
|
if (err) {
|
||||||
|
dev_err(&udev->dev,
|
||||||
|
"Failed to suspend device, error %d\n",
|
||||||
|
status);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the suspend failed, resume interfaces that did get suspended */
|
/* If the suspend failed, resume interfaces that did get suspended */
|
||||||
@ -1763,6 +1781,9 @@ static int autosuspend_check(struct usb_device *udev)
|
|||||||
int w, i;
|
int w, i;
|
||||||
struct usb_interface *intf;
|
struct usb_interface *intf;
|
||||||
|
|
||||||
|
if (udev->state == USB_STATE_NOTATTACHED)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
/* Fail if autosuspend is disabled, or any interfaces are in use, or
|
/* Fail if autosuspend is disabled, or any interfaces are in use, or
|
||||||
* any interface drivers require remote wakeup but it isn't available.
|
* any interface drivers require remote wakeup but it isn't available.
|
||||||
*/
|
*/
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#define MAX_USB_MINORS 256
|
#define MAX_USB_MINORS 256
|
||||||
static const struct file_operations *usb_minors[MAX_USB_MINORS];
|
static const struct file_operations *usb_minors[MAX_USB_MINORS];
|
||||||
static DECLARE_RWSEM(minor_rwsem);
|
static DECLARE_RWSEM(minor_rwsem);
|
||||||
|
static DEFINE_MUTEX(init_usb_class_mutex);
|
||||||
|
|
||||||
static int usb_open(struct inode *inode, struct file *file)
|
static int usb_open(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
@ -111,8 +112,9 @@ static void release_usb_class(struct kref *kref)
|
|||||||
|
|
||||||
static void destroy_usb_class(void)
|
static void destroy_usb_class(void)
|
||||||
{
|
{
|
||||||
if (usb_class)
|
mutex_lock(&init_usb_class_mutex);
|
||||||
kref_put(&usb_class->kref, release_usb_class);
|
kref_put(&usb_class->kref, release_usb_class);
|
||||||
|
mutex_unlock(&init_usb_class_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
int usb_major_init(void)
|
int usb_major_init(void)
|
||||||
@ -173,7 +175,10 @@ int usb_register_dev(struct usb_interface *intf,
|
|||||||
if (intf->minor >= 0)
|
if (intf->minor >= 0)
|
||||||
return -EADDRINUSE;
|
return -EADDRINUSE;
|
||||||
|
|
||||||
|
mutex_lock(&init_usb_class_mutex);
|
||||||
retval = init_usb_class();
|
retval = init_usb_class();
|
||||||
|
mutex_unlock(&init_usb_class_mutex);
|
||||||
|
|
||||||
if (retval)
|
if (retval)
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
|
@ -1076,6 +1076,7 @@ static void usb_deregister_bus (struct usb_bus *bus)
|
|||||||
static int register_root_hub(struct usb_hcd *hcd)
|
static int register_root_hub(struct usb_hcd *hcd)
|
||||||
{
|
{
|
||||||
struct device *parent_dev = hcd->self.controller;
|
struct device *parent_dev = hcd->self.controller;
|
||||||
|
struct device *sysdev = hcd->self.sysdev;
|
||||||
struct usb_device *usb_dev = hcd->self.root_hub;
|
struct usb_device *usb_dev = hcd->self.root_hub;
|
||||||
const int devnum = 1;
|
const int devnum = 1;
|
||||||
int retval;
|
int retval;
|
||||||
@ -1122,7 +1123,7 @@ static int register_root_hub(struct usb_hcd *hcd)
|
|||||||
/* Did the HC die before the root hub was registered? */
|
/* Did the HC die before the root hub was registered? */
|
||||||
if (HCD_DEAD(hcd))
|
if (HCD_DEAD(hcd))
|
||||||
usb_hc_died (hcd); /* This time clean up */
|
usb_hc_died (hcd); /* This time clean up */
|
||||||
usb_dev->dev.of_node = parent_dev->of_node;
|
usb_dev->dev.of_node = sysdev->of_node;
|
||||||
}
|
}
|
||||||
mutex_unlock(&usb_bus_idr_lock);
|
mutex_unlock(&usb_bus_idr_lock);
|
||||||
|
|
||||||
@ -1435,7 +1436,7 @@ void usb_hcd_unmap_urb_setup_for_dma(struct usb_hcd *hcd, struct urb *urb)
|
|||||||
{
|
{
|
||||||
if (IS_ENABLED(CONFIG_HAS_DMA) &&
|
if (IS_ENABLED(CONFIG_HAS_DMA) &&
|
||||||
(urb->transfer_flags & URB_SETUP_MAP_SINGLE))
|
(urb->transfer_flags & URB_SETUP_MAP_SINGLE))
|
||||||
dma_unmap_single(hcd->self.controller,
|
dma_unmap_single(hcd->self.sysdev,
|
||||||
urb->setup_dma,
|
urb->setup_dma,
|
||||||
sizeof(struct usb_ctrlrequest),
|
sizeof(struct usb_ctrlrequest),
|
||||||
DMA_TO_DEVICE);
|
DMA_TO_DEVICE);
|
||||||
@ -1468,19 +1469,19 @@ void usb_hcd_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
|
|||||||
dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
|
dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
|
||||||
if (IS_ENABLED(CONFIG_HAS_DMA) &&
|
if (IS_ENABLED(CONFIG_HAS_DMA) &&
|
||||||
(urb->transfer_flags & URB_DMA_MAP_SG))
|
(urb->transfer_flags & URB_DMA_MAP_SG))
|
||||||
dma_unmap_sg(hcd->self.controller,
|
dma_unmap_sg(hcd->self.sysdev,
|
||||||
urb->sg,
|
urb->sg,
|
||||||
urb->num_sgs,
|
urb->num_sgs,
|
||||||
dir);
|
dir);
|
||||||
else if (IS_ENABLED(CONFIG_HAS_DMA) &&
|
else if (IS_ENABLED(CONFIG_HAS_DMA) &&
|
||||||
(urb->transfer_flags & URB_DMA_MAP_PAGE))
|
(urb->transfer_flags & URB_DMA_MAP_PAGE))
|
||||||
dma_unmap_page(hcd->self.controller,
|
dma_unmap_page(hcd->self.sysdev,
|
||||||
urb->transfer_dma,
|
urb->transfer_dma,
|
||||||
urb->transfer_buffer_length,
|
urb->transfer_buffer_length,
|
||||||
dir);
|
dir);
|
||||||
else if (IS_ENABLED(CONFIG_HAS_DMA) &&
|
else if (IS_ENABLED(CONFIG_HAS_DMA) &&
|
||||||
(urb->transfer_flags & URB_DMA_MAP_SINGLE))
|
(urb->transfer_flags & URB_DMA_MAP_SINGLE))
|
||||||
dma_unmap_single(hcd->self.controller,
|
dma_unmap_single(hcd->self.sysdev,
|
||||||
urb->transfer_dma,
|
urb->transfer_dma,
|
||||||
urb->transfer_buffer_length,
|
urb->transfer_buffer_length,
|
||||||
dir);
|
dir);
|
||||||
@ -1523,11 +1524,11 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
|
|||||||
return ret;
|
return ret;
|
||||||
if (IS_ENABLED(CONFIG_HAS_DMA) && hcd->self.uses_dma) {
|
if (IS_ENABLED(CONFIG_HAS_DMA) && hcd->self.uses_dma) {
|
||||||
urb->setup_dma = dma_map_single(
|
urb->setup_dma = dma_map_single(
|
||||||
hcd->self.controller,
|
hcd->self.sysdev,
|
||||||
urb->setup_packet,
|
urb->setup_packet,
|
||||||
sizeof(struct usb_ctrlrequest),
|
sizeof(struct usb_ctrlrequest),
|
||||||
DMA_TO_DEVICE);
|
DMA_TO_DEVICE);
|
||||||
if (dma_mapping_error(hcd->self.controller,
|
if (dma_mapping_error(hcd->self.sysdev,
|
||||||
urb->setup_dma))
|
urb->setup_dma))
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
urb->transfer_flags |= URB_SETUP_MAP_SINGLE;
|
urb->transfer_flags |= URB_SETUP_MAP_SINGLE;
|
||||||
@ -1558,7 +1559,7 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
|
|||||||
}
|
}
|
||||||
|
|
||||||
n = dma_map_sg(
|
n = dma_map_sg(
|
||||||
hcd->self.controller,
|
hcd->self.sysdev,
|
||||||
urb->sg,
|
urb->sg,
|
||||||
urb->num_sgs,
|
urb->num_sgs,
|
||||||
dir);
|
dir);
|
||||||
@ -1573,12 +1574,12 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
|
|||||||
} else if (urb->sg) {
|
} else if (urb->sg) {
|
||||||
struct scatterlist *sg = urb->sg;
|
struct scatterlist *sg = urb->sg;
|
||||||
urb->transfer_dma = dma_map_page(
|
urb->transfer_dma = dma_map_page(
|
||||||
hcd->self.controller,
|
hcd->self.sysdev,
|
||||||
sg_page(sg),
|
sg_page(sg),
|
||||||
sg->offset,
|
sg->offset,
|
||||||
urb->transfer_buffer_length,
|
urb->transfer_buffer_length,
|
||||||
dir);
|
dir);
|
||||||
if (dma_mapping_error(hcd->self.controller,
|
if (dma_mapping_error(hcd->self.sysdev,
|
||||||
urb->transfer_dma))
|
urb->transfer_dma))
|
||||||
ret = -EAGAIN;
|
ret = -EAGAIN;
|
||||||
else
|
else
|
||||||
@ -1588,11 +1589,11 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
|
|||||||
ret = -EAGAIN;
|
ret = -EAGAIN;
|
||||||
} else {
|
} else {
|
||||||
urb->transfer_dma = dma_map_single(
|
urb->transfer_dma = dma_map_single(
|
||||||
hcd->self.controller,
|
hcd->self.sysdev,
|
||||||
urb->transfer_buffer,
|
urb->transfer_buffer,
|
||||||
urb->transfer_buffer_length,
|
urb->transfer_buffer_length,
|
||||||
dir);
|
dir);
|
||||||
if (dma_mapping_error(hcd->self.controller,
|
if (dma_mapping_error(hcd->self.sysdev,
|
||||||
urb->transfer_dma))
|
urb->transfer_dma))
|
||||||
ret = -EAGAIN;
|
ret = -EAGAIN;
|
||||||
else
|
else
|
||||||
@ -2498,24 +2499,8 @@ static void init_giveback_urb_bh(struct giveback_urb_bh *bh)
|
|||||||
tasklet_init(&bh->bh, usb_giveback_urb_bh, (unsigned long)bh);
|
tasklet_init(&bh->bh, usb_giveback_urb_bh, (unsigned long)bh);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
struct usb_hcd *__usb_create_hcd(const struct hc_driver *driver,
|
||||||
* usb_create_shared_hcd - create and initialize an HCD structure
|
struct device *sysdev, struct device *dev, const char *bus_name,
|
||||||
* @driver: HC driver that will use this hcd
|
|
||||||
* @dev: device for this HC, stored in hcd->self.controller
|
|
||||||
* @bus_name: value to store in hcd->self.bus_name
|
|
||||||
* @primary_hcd: a pointer to the usb_hcd structure that is sharing the
|
|
||||||
* PCI device. Only allocate certain resources for the primary HCD
|
|
||||||
* Context: !in_interrupt()
|
|
||||||
*
|
|
||||||
* Allocate a struct usb_hcd, with extra space at the end for the
|
|
||||||
* HC driver's private data. Initialize the generic members of the
|
|
||||||
* hcd structure.
|
|
||||||
*
|
|
||||||
* Return: On success, a pointer to the created and initialized HCD structure.
|
|
||||||
* On failure (e.g. if memory is unavailable), %NULL.
|
|
||||||
*/
|
|
||||||
struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
|
|
||||||
struct device *dev, const char *bus_name,
|
|
||||||
struct usb_hcd *primary_hcd)
|
struct usb_hcd *primary_hcd)
|
||||||
{
|
{
|
||||||
struct usb_hcd *hcd;
|
struct usb_hcd *hcd;
|
||||||
@ -2556,8 +2541,9 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
|
|||||||
|
|
||||||
usb_bus_init(&hcd->self);
|
usb_bus_init(&hcd->self);
|
||||||
hcd->self.controller = dev;
|
hcd->self.controller = dev;
|
||||||
|
hcd->self.sysdev = sysdev;
|
||||||
hcd->self.bus_name = bus_name;
|
hcd->self.bus_name = bus_name;
|
||||||
hcd->self.uses_dma = (dev->dma_mask != NULL);
|
hcd->self.uses_dma = (sysdev->dma_mask != NULL);
|
||||||
|
|
||||||
init_timer(&hcd->rh_timer);
|
init_timer(&hcd->rh_timer);
|
||||||
hcd->rh_timer.function = rh_timer_func;
|
hcd->rh_timer.function = rh_timer_func;
|
||||||
@ -2572,6 +2558,30 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
|
|||||||
"USB Host Controller";
|
"USB Host Controller";
|
||||||
return hcd;
|
return hcd;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(__usb_create_hcd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* usb_create_shared_hcd - create and initialize an HCD structure
|
||||||
|
* @driver: HC driver that will use this hcd
|
||||||
|
* @dev: device for this HC, stored in hcd->self.controller
|
||||||
|
* @bus_name: value to store in hcd->self.bus_name
|
||||||
|
* @primary_hcd: a pointer to the usb_hcd structure that is sharing the
|
||||||
|
* PCI device. Only allocate certain resources for the primary HCD
|
||||||
|
* Context: !in_interrupt()
|
||||||
|
*
|
||||||
|
* Allocate a struct usb_hcd, with extra space at the end for the
|
||||||
|
* HC driver's private data. Initialize the generic members of the
|
||||||
|
* hcd structure.
|
||||||
|
*
|
||||||
|
* Return: On success, a pointer to the created and initialized HCD structure.
|
||||||
|
* On failure (e.g. if memory is unavailable), %NULL.
|
||||||
|
*/
|
||||||
|
struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
|
||||||
|
struct device *dev, const char *bus_name,
|
||||||
|
struct usb_hcd *primary_hcd)
|
||||||
|
{
|
||||||
|
return __usb_create_hcd(driver, dev, dev, bus_name, primary_hcd);
|
||||||
|
}
|
||||||
EXPORT_SYMBOL_GPL(usb_create_shared_hcd);
|
EXPORT_SYMBOL_GPL(usb_create_shared_hcd);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2591,7 +2601,7 @@ EXPORT_SYMBOL_GPL(usb_create_shared_hcd);
|
|||||||
struct usb_hcd *usb_create_hcd(const struct hc_driver *driver,
|
struct usb_hcd *usb_create_hcd(const struct hc_driver *driver,
|
||||||
struct device *dev, const char *bus_name)
|
struct device *dev, const char *bus_name)
|
||||||
{
|
{
|
||||||
return usb_create_shared_hcd(driver, dev, bus_name, NULL);
|
return __usb_create_hcd(driver, dev, dev, bus_name, NULL);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(usb_create_hcd);
|
EXPORT_SYMBOL_GPL(usb_create_hcd);
|
||||||
|
|
||||||
@ -2718,7 +2728,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
|||||||
struct usb_device *rhdev;
|
struct usb_device *rhdev;
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_USB_PHY) && !hcd->usb_phy) {
|
if (IS_ENABLED(CONFIG_USB_PHY) && !hcd->usb_phy) {
|
||||||
struct usb_phy *phy = usb_get_phy_dev(hcd->self.controller, 0);
|
struct usb_phy *phy = usb_get_phy_dev(hcd->self.sysdev, 0);
|
||||||
|
|
||||||
if (IS_ERR(phy)) {
|
if (IS_ERR(phy)) {
|
||||||
retval = PTR_ERR(phy);
|
retval = PTR_ERR(phy);
|
||||||
@ -2736,7 +2746,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_GENERIC_PHY) && !hcd->phy) {
|
if (IS_ENABLED(CONFIG_GENERIC_PHY) && !hcd->phy) {
|
||||||
struct phy *phy = phy_get(hcd->self.controller, "usb");
|
struct phy *phy = phy_get(hcd->self.sysdev, "usb");
|
||||||
|
|
||||||
if (IS_ERR(phy)) {
|
if (IS_ERR(phy)) {
|
||||||
retval = PTR_ERR(phy);
|
retval = PTR_ERR(phy);
|
||||||
@ -2784,7 +2794,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
|||||||
*/
|
*/
|
||||||
retval = hcd_buffer_create(hcd);
|
retval = hcd_buffer_create(hcd);
|
||||||
if (retval != 0) {
|
if (retval != 0) {
|
||||||
dev_dbg(hcd->self.controller, "pool alloc failed\n");
|
dev_dbg(hcd->self.sysdev, "pool alloc failed\n");
|
||||||
goto err_create_buf;
|
goto err_create_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2794,7 +2804,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
|||||||
|
|
||||||
rhdev = usb_alloc_dev(NULL, &hcd->self, 0);
|
rhdev = usb_alloc_dev(NULL, &hcd->self, 0);
|
||||||
if (rhdev == NULL) {
|
if (rhdev == NULL) {
|
||||||
dev_err(hcd->self.controller, "unable to allocate root hub\n");
|
dev_err(hcd->self.sysdev, "unable to allocate root hub\n");
|
||||||
retval = -ENOMEM;
|
retval = -ENOMEM;
|
||||||
goto err_allocate_root_hub;
|
goto err_allocate_root_hub;
|
||||||
}
|
}
|
||||||
|
@ -1066,6 +1066,9 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
|
|||||||
|
|
||||||
portstatus = portchange = 0;
|
portstatus = portchange = 0;
|
||||||
status = hub_port_status(hub, port1, &portstatus, &portchange);
|
status = hub_port_status(hub, port1, &portstatus, &portchange);
|
||||||
|
if (status)
|
||||||
|
goto abort;
|
||||||
|
|
||||||
if (udev || (portstatus & USB_PORT_STAT_CONNECTION))
|
if (udev || (portstatus & USB_PORT_STAT_CONNECTION))
|
||||||
dev_dbg(&port_dev->dev, "status %04x change %04x\n",
|
dev_dbg(&port_dev->dev, "status %04x change %04x\n",
|
||||||
portstatus, portchange);
|
portstatus, portchange);
|
||||||
@ -1198,7 +1201,7 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
|
|||||||
|
|
||||||
/* Scan all ports that need attention */
|
/* Scan all ports that need attention */
|
||||||
kick_hub_wq(hub);
|
kick_hub_wq(hub);
|
||||||
|
abort:
|
||||||
if (type == HUB_INIT2 || type == HUB_INIT3) {
|
if (type == HUB_INIT2 || type == HUB_INIT3) {
|
||||||
/* Allow autosuspend if it was suppressed */
|
/* Allow autosuspend if it was suppressed */
|
||||||
disconnected:
|
disconnected:
|
||||||
@ -2084,6 +2087,12 @@ void usb_disconnect(struct usb_device **pdev)
|
|||||||
dev_info(&udev->dev, "USB disconnect, device number %d\n",
|
dev_info(&udev->dev, "USB disconnect, device number %d\n",
|
||||||
udev->devnum);
|
udev->devnum);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ensure that the pm runtime code knows that the USB device
|
||||||
|
* is in the process of being disconnected.
|
||||||
|
*/
|
||||||
|
pm_runtime_barrier(&udev->dev);
|
||||||
|
|
||||||
usb_lock_device(udev);
|
usb_lock_device(udev);
|
||||||
|
|
||||||
hub_disconnect_children(udev);
|
hub_disconnect_children(udev);
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
|
#include <linux/of_platform.h>
|
||||||
#include <linux/usb/of.h>
|
#include <linux/usb/of.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -46,3 +47,25 @@ struct device_node *usb_of_get_child_node(struct device_node *parent,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(usb_of_get_child_node);
|
EXPORT_SYMBOL_GPL(usb_of_get_child_node);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* usb_of_get_companion_dev - Find the companion device
|
||||||
|
* @dev: the device pointer to find a companion
|
||||||
|
*
|
||||||
|
* Find the companion device from platform bus.
|
||||||
|
*
|
||||||
|
* Return: On success, a pointer to the companion device, %NULL on failure.
|
||||||
|
*/
|
||||||
|
struct device *usb_of_get_companion_dev(struct device *dev)
|
||||||
|
{
|
||||||
|
struct device_node *node;
|
||||||
|
struct platform_device *pdev = NULL;
|
||||||
|
|
||||||
|
node = of_parse_phandle(dev->of_node, "companion", 0);
|
||||||
|
if (node)
|
||||||
|
pdev = of_find_device_by_node(node);
|
||||||
|
|
||||||
|
of_node_put(node);
|
||||||
|
|
||||||
|
return pdev ? &pdev->dev : NULL;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(usb_of_get_companion_dev);
|
||||||
|
@ -74,6 +74,140 @@ MODULE_PARM_DESC(autosuspend, "default autosuspend delay");
|
|||||||
#define usb_autosuspend_delay 0
|
#define usb_autosuspend_delay 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static bool match_endpoint(struct usb_endpoint_descriptor *epd,
|
||||||
|
struct usb_endpoint_descriptor **bulk_in,
|
||||||
|
struct usb_endpoint_descriptor **bulk_out,
|
||||||
|
struct usb_endpoint_descriptor **int_in,
|
||||||
|
struct usb_endpoint_descriptor **int_out)
|
||||||
|
{
|
||||||
|
switch (usb_endpoint_type(epd)) {
|
||||||
|
case USB_ENDPOINT_XFER_BULK:
|
||||||
|
if (usb_endpoint_dir_in(epd)) {
|
||||||
|
if (bulk_in && !*bulk_in) {
|
||||||
|
*bulk_in = epd;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (bulk_out && !*bulk_out) {
|
||||||
|
*bulk_out = epd;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
case USB_ENDPOINT_XFER_INT:
|
||||||
|
if (usb_endpoint_dir_in(epd)) {
|
||||||
|
if (int_in && !*int_in) {
|
||||||
|
*int_in = epd;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (int_out && !*int_out) {
|
||||||
|
*int_out = epd;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (!bulk_in || *bulk_in) && (!bulk_out || *bulk_out) &&
|
||||||
|
(!int_in || *int_in) && (!int_out || *int_out);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* usb_find_common_endpoints() -- look up common endpoint descriptors
|
||||||
|
* @alt: alternate setting to search
|
||||||
|
* @bulk_in: pointer to descriptor pointer, or NULL
|
||||||
|
* @bulk_out: pointer to descriptor pointer, or NULL
|
||||||
|
* @int_in: pointer to descriptor pointer, or NULL
|
||||||
|
* @int_out: pointer to descriptor pointer, or NULL
|
||||||
|
*
|
||||||
|
* Search the alternate setting's endpoint descriptors for the first bulk-in,
|
||||||
|
* bulk-out, interrupt-in and interrupt-out endpoints and return them in the
|
||||||
|
* provided pointers (unless they are NULL).
|
||||||
|
*
|
||||||
|
* If a requested endpoint is not found, the corresponding pointer is set to
|
||||||
|
* NULL.
|
||||||
|
*
|
||||||
|
* Return: Zero if all requested descriptors were found, or -ENXIO otherwise.
|
||||||
|
*/
|
||||||
|
int usb_find_common_endpoints(struct usb_host_interface *alt,
|
||||||
|
struct usb_endpoint_descriptor **bulk_in,
|
||||||
|
struct usb_endpoint_descriptor **bulk_out,
|
||||||
|
struct usb_endpoint_descriptor **int_in,
|
||||||
|
struct usb_endpoint_descriptor **int_out)
|
||||||
|
{
|
||||||
|
struct usb_endpoint_descriptor *epd;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (bulk_in)
|
||||||
|
*bulk_in = NULL;
|
||||||
|
if (bulk_out)
|
||||||
|
*bulk_out = NULL;
|
||||||
|
if (int_in)
|
||||||
|
*int_in = NULL;
|
||||||
|
if (int_out)
|
||||||
|
*int_out = NULL;
|
||||||
|
|
||||||
|
for (i = 0; i < alt->desc.bNumEndpoints; ++i) {
|
||||||
|
epd = &alt->endpoint[i].desc;
|
||||||
|
|
||||||
|
if (match_endpoint(epd, bulk_in, bulk_out, int_in, int_out))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(usb_find_common_endpoints);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* usb_find_common_endpoints_reverse() -- look up common endpoint descriptors
|
||||||
|
* @alt: alternate setting to search
|
||||||
|
* @bulk_in: pointer to descriptor pointer, or NULL
|
||||||
|
* @bulk_out: pointer to descriptor pointer, or NULL
|
||||||
|
* @int_in: pointer to descriptor pointer, or NULL
|
||||||
|
* @int_out: pointer to descriptor pointer, or NULL
|
||||||
|
*
|
||||||
|
* Search the alternate setting's endpoint descriptors for the last bulk-in,
|
||||||
|
* bulk-out, interrupt-in and interrupt-out endpoints and return them in the
|
||||||
|
* provided pointers (unless they are NULL).
|
||||||
|
*
|
||||||
|
* If a requested endpoint is not found, the corresponding pointer is set to
|
||||||
|
* NULL.
|
||||||
|
*
|
||||||
|
* Return: Zero if all requested descriptors were found, or -ENXIO otherwise.
|
||||||
|
*/
|
||||||
|
int usb_find_common_endpoints_reverse(struct usb_host_interface *alt,
|
||||||
|
struct usb_endpoint_descriptor **bulk_in,
|
||||||
|
struct usb_endpoint_descriptor **bulk_out,
|
||||||
|
struct usb_endpoint_descriptor **int_in,
|
||||||
|
struct usb_endpoint_descriptor **int_out)
|
||||||
|
{
|
||||||
|
struct usb_endpoint_descriptor *epd;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (bulk_in)
|
||||||
|
*bulk_in = NULL;
|
||||||
|
if (bulk_out)
|
||||||
|
*bulk_out = NULL;
|
||||||
|
if (int_in)
|
||||||
|
*int_in = NULL;
|
||||||
|
if (int_out)
|
||||||
|
*int_out = NULL;
|
||||||
|
|
||||||
|
for (i = alt->desc.bNumEndpoints - 1; i >= 0; --i) {
|
||||||
|
epd = &alt->endpoint[i].desc;
|
||||||
|
|
||||||
|
if (match_endpoint(epd, bulk_in, bulk_out, int_in, int_out))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(usb_find_common_endpoints_reverse);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* usb_find_alt_setting() - Given a configuration, find the alternate setting
|
* usb_find_alt_setting() - Given a configuration, find the alternate setting
|
||||||
@ -453,9 +587,9 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
|
|||||||
* Note: calling dma_set_mask() on a USB device would set the
|
* Note: calling dma_set_mask() on a USB device would set the
|
||||||
* mask for the entire HCD, so don't do that.
|
* mask for the entire HCD, so don't do that.
|
||||||
*/
|
*/
|
||||||
dev->dev.dma_mask = bus->controller->dma_mask;
|
dev->dev.dma_mask = bus->sysdev->dma_mask;
|
||||||
dev->dev.dma_pfn_offset = bus->controller->dma_pfn_offset;
|
dev->dev.dma_pfn_offset = bus->sysdev->dma_pfn_offset;
|
||||||
set_dev_node(&dev->dev, dev_to_node(bus->controller));
|
set_dev_node(&dev->dev, dev_to_node(bus->sysdev));
|
||||||
dev->state = USB_STATE_ATTACHED;
|
dev->state = USB_STATE_ATTACHED;
|
||||||
dev->lpm_disable_count = 1;
|
dev->lpm_disable_count = 1;
|
||||||
atomic_set(&dev->urbnum, 0);
|
atomic_set(&dev->urbnum, 0);
|
||||||
@ -803,7 +937,7 @@ struct urb *usb_buffer_map(struct urb *urb)
|
|||||||
if (!urb
|
if (!urb
|
||||||
|| !urb->dev
|
|| !urb->dev
|
||||||
|| !(bus = urb->dev->bus)
|
|| !(bus = urb->dev->bus)
|
||||||
|| !(controller = bus->controller))
|
|| !(controller = bus->sysdev))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (controller->dma_mask) {
|
if (controller->dma_mask) {
|
||||||
@ -841,7 +975,7 @@ void usb_buffer_dmasync(struct urb *urb)
|
|||||||
|| !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
|
|| !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
|
||||||
|| !urb->dev
|
|| !urb->dev
|
||||||
|| !(bus = urb->dev->bus)
|
|| !(bus = urb->dev->bus)
|
||||||
|| !(controller = bus->controller))
|
|| !(controller = bus->sysdev))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (controller->dma_mask) {
|
if (controller->dma_mask) {
|
||||||
@ -875,7 +1009,7 @@ void usb_buffer_unmap(struct urb *urb)
|
|||||||
|| !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
|
|| !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
|
||||||
|| !urb->dev
|
|| !urb->dev
|
||||||
|| !(bus = urb->dev->bus)
|
|| !(bus = urb->dev->bus)
|
||||||
|| !(controller = bus->controller))
|
|| !(controller = bus->sysdev))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (controller->dma_mask) {
|
if (controller->dma_mask) {
|
||||||
@ -925,7 +1059,7 @@ int usb_buffer_map_sg(const struct usb_device *dev, int is_in,
|
|||||||
|
|
||||||
if (!dev
|
if (!dev
|
||||||
|| !(bus = dev->bus)
|
|| !(bus = dev->bus)
|
||||||
|| !(controller = bus->controller)
|
|| !(controller = bus->sysdev)
|
||||||
|| !controller->dma_mask)
|
|| !controller->dma_mask)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
@ -961,7 +1095,7 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in,
|
|||||||
|
|
||||||
if (!dev
|
if (!dev
|
||||||
|| !(bus = dev->bus)
|
|| !(bus = dev->bus)
|
||||||
|| !(controller = bus->controller)
|
|| !(controller = bus->sysdev)
|
||||||
|| !controller->dma_mask)
|
|| !controller->dma_mask)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -989,7 +1123,7 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in,
|
|||||||
|
|
||||||
if (!dev
|
if (!dev
|
||||||
|| !(bus = dev->bus)
|
|| !(bus = dev->bus)
|
||||||
|| !(controller = bus->controller)
|
|| !(controller = bus->sysdev)
|
||||||
|| !controller->dma_mask)
|
|| !controller->dma_mask)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ endchoice
|
|||||||
|
|
||||||
config USB_DWC2_PCI
|
config USB_DWC2_PCI
|
||||||
tristate "DWC2 PCI"
|
tristate "DWC2 PCI"
|
||||||
depends on PCI
|
depends on USB_PCI
|
||||||
depends on USB_GADGET || !USB_GADGET
|
depends on USB_GADGET || !USB_GADGET
|
||||||
default n
|
default n
|
||||||
select NOP_USB_XCEIV
|
select NOP_USB_XCEIV
|
||||||
|
@ -423,6 +423,10 @@ enum dwc2_ep0_state {
|
|||||||
* needed.
|
* needed.
|
||||||
* 0 - No (default)
|
* 0 - No (default)
|
||||||
* 1 - Yes
|
* 1 - Yes
|
||||||
|
* @activate_stm_fs_transceiver: Activate internal transceiver using GGPIO
|
||||||
|
* register.
|
||||||
|
* 0 - Deactivate the transceiver (default)
|
||||||
|
* 1 - Activate the transceiver
|
||||||
* @g_dma: Enables gadget dma usage (default: autodetect).
|
* @g_dma: Enables gadget dma usage (default: autodetect).
|
||||||
* @g_dma_desc: Enables gadget descriptor DMA (default: autodetect).
|
* @g_dma_desc: Enables gadget descriptor DMA (default: autodetect).
|
||||||
* @g_rx_fifo_size: The periodic rx fifo size for the device, in
|
* @g_rx_fifo_size: The periodic rx fifo size for the device, in
|
||||||
@ -477,6 +481,7 @@ struct dwc2_core_params {
|
|||||||
bool uframe_sched;
|
bool uframe_sched;
|
||||||
bool external_id_pin_ctl;
|
bool external_id_pin_ctl;
|
||||||
bool hibernation;
|
bool hibernation;
|
||||||
|
bool activate_stm_fs_transceiver;
|
||||||
u16 max_packet_count;
|
u16 max_packet_count;
|
||||||
u32 max_transfer_size;
|
u32 max_transfer_size;
|
||||||
u32 ahbcfg;
|
u32 ahbcfg;
|
||||||
|
@ -121,7 +121,7 @@ static void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg)
|
|||||||
|
|
||||||
static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
|
static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
|
||||||
{
|
{
|
||||||
u32 usbcfg, i2cctl;
|
u32 usbcfg, ggpio, i2cctl;
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -145,6 +145,19 @@ static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy)
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hsotg->params.activate_stm_fs_transceiver) {
|
||||||
|
ggpio = dwc2_readl(hsotg->regs + GGPIO);
|
||||||
|
if (!(ggpio & GGPIO_STM32_OTG_GCCFG_PWRDWN)) {
|
||||||
|
dev_dbg(hsotg->dev, "Activating transceiver\n");
|
||||||
|
/*
|
||||||
|
* STM32F4x9 uses the GGPIO register as general
|
||||||
|
* core configuration register.
|
||||||
|
*/
|
||||||
|
ggpio |= GGPIO_STM32_OTG_GCCFG_PWRDWN;
|
||||||
|
dwc2_writel(ggpio, hsotg->regs + GGPIO);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3264,6 +3277,7 @@ static void dwc2_conn_id_status_change(struct work_struct *work)
|
|||||||
dwc2_core_init(hsotg, false);
|
dwc2_core_init(hsotg, false);
|
||||||
dwc2_enable_global_interrupts(hsotg);
|
dwc2_enable_global_interrupts(hsotg);
|
||||||
spin_lock_irqsave(&hsotg->lock, flags);
|
spin_lock_irqsave(&hsotg->lock, flags);
|
||||||
|
dwc2_hsotg_disconnect(hsotg);
|
||||||
dwc2_hsotg_core_init_disconnected(hsotg, false);
|
dwc2_hsotg_core_init_disconnected(hsotg, false);
|
||||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||||
dwc2_hsotg_core_connect(hsotg);
|
dwc2_hsotg_core_connect(hsotg);
|
||||||
|
@ -225,6 +225,8 @@
|
|||||||
|
|
||||||
#define GPVNDCTL HSOTG_REG(0x0034)
|
#define GPVNDCTL HSOTG_REG(0x0034)
|
||||||
#define GGPIO HSOTG_REG(0x0038)
|
#define GGPIO HSOTG_REG(0x0038)
|
||||||
|
#define GGPIO_STM32_OTG_GCCFG_PWRDWN BIT(16)
|
||||||
|
|
||||||
#define GUID HSOTG_REG(0x003c)
|
#define GUID HSOTG_REG(0x003c)
|
||||||
#define GSNPSID HSOTG_REG(0x0040)
|
#define GSNPSID HSOTG_REG(0x0040)
|
||||||
#define GHWCFG1 HSOTG_REG(0x0044)
|
#define GHWCFG1 HSOTG_REG(0x0044)
|
||||||
|
@ -120,6 +120,22 @@ static void dwc2_set_amcc_params(struct dwc2_hsotg *hsotg)
|
|||||||
p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << GAHBCFG_HBSTLEN_SHIFT;
|
p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << GAHBCFG_HBSTLEN_SHIFT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dwc2_set_stm32f4x9_fsotg_params(struct dwc2_hsotg *hsotg)
|
||||||
|
{
|
||||||
|
struct dwc2_core_params *p = &hsotg->params;
|
||||||
|
|
||||||
|
p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE;
|
||||||
|
p->speed = DWC2_SPEED_PARAM_FULL;
|
||||||
|
p->host_rx_fifo_size = 128;
|
||||||
|
p->host_nperio_tx_fifo_size = 96;
|
||||||
|
p->host_perio_tx_fifo_size = 96;
|
||||||
|
p->max_packet_count = 256;
|
||||||
|
p->phy_type = DWC2_PHY_TYPE_PARAM_FS;
|
||||||
|
p->i2c_enable = false;
|
||||||
|
p->uframe_sched = false;
|
||||||
|
p->activate_stm_fs_transceiver = true;
|
||||||
|
}
|
||||||
|
|
||||||
const struct of_device_id dwc2_of_match_table[] = {
|
const struct of_device_id dwc2_of_match_table[] = {
|
||||||
{ .compatible = "brcm,bcm2835-usb", .data = dwc2_set_bcm_params },
|
{ .compatible = "brcm,bcm2835-usb", .data = dwc2_set_bcm_params },
|
||||||
{ .compatible = "hisilicon,hi6220-usb", .data = dwc2_set_his_params },
|
{ .compatible = "hisilicon,hi6220-usb", .data = dwc2_set_his_params },
|
||||||
@ -133,6 +149,9 @@ const struct of_device_id dwc2_of_match_table[] = {
|
|||||||
{ .compatible = "amlogic,meson-gxbb-usb",
|
{ .compatible = "amlogic,meson-gxbb-usb",
|
||||||
.data = dwc2_set_amlogic_params },
|
.data = dwc2_set_amlogic_params },
|
||||||
{ .compatible = "amcc,dwc-otg", .data = dwc2_set_amcc_params },
|
{ .compatible = "amcc,dwc-otg", .data = dwc2_set_amcc_params },
|
||||||
|
{ .compatible = "st,stm32f4x9-fsotg",
|
||||||
|
.data = dwc2_set_stm32f4x9_fsotg_params },
|
||||||
|
{ .compatible = "st,stm32f4x9-hsotg" },
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, dwc2_of_match_table);
|
MODULE_DEVICE_TABLE(of, dwc2_of_match_table);
|
||||||
|
@ -214,20 +214,11 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg)
|
|||||||
hsotg->reset = devm_reset_control_get_optional(hsotg->dev, "dwc2");
|
hsotg->reset = devm_reset_control_get_optional(hsotg->dev, "dwc2");
|
||||||
if (IS_ERR(hsotg->reset)) {
|
if (IS_ERR(hsotg->reset)) {
|
||||||
ret = PTR_ERR(hsotg->reset);
|
ret = PTR_ERR(hsotg->reset);
|
||||||
switch (ret) {
|
dev_err(hsotg->dev, "error getting reset control %d\n", ret);
|
||||||
case -ENOENT:
|
return ret;
|
||||||
case -ENOTSUPP:
|
|
||||||
hsotg->reset = NULL;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
dev_err(hsotg->dev, "error getting reset control %d\n",
|
|
||||||
ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hsotg->reset)
|
reset_control_deassert(hsotg->reset);
|
||||||
reset_control_deassert(hsotg->reset);
|
|
||||||
|
|
||||||
/* Set default UTMI width */
|
/* Set default UTMI width */
|
||||||
hsotg->phyif = GUSBCFG_PHYIF16;
|
hsotg->phyif = GUSBCFG_PHYIF16;
|
||||||
@ -326,8 +317,7 @@ static int dwc2_driver_remove(struct platform_device *dev)
|
|||||||
if (hsotg->ll_hw_enabled)
|
if (hsotg->ll_hw_enabled)
|
||||||
dwc2_lowlevel_hw_disable(hsotg);
|
dwc2_lowlevel_hw_disable(hsotg);
|
||||||
|
|
||||||
if (hsotg->reset)
|
reset_control_assert(hsotg->reset);
|
||||||
reset_control_assert(hsotg->reset);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,7 @@ config USB_DWC3_GADGET
|
|||||||
config USB_DWC3_DUAL_ROLE
|
config USB_DWC3_DUAL_ROLE
|
||||||
bool "Dual Role mode"
|
bool "Dual Role mode"
|
||||||
depends on ((USB=y || USB=USB_DWC3) && (USB_GADGET=y || USB_GADGET=USB_DWC3))
|
depends on ((USB=y || USB=USB_DWC3) && (USB_GADGET=y || USB_GADGET=USB_DWC3))
|
||||||
|
depends on (EXTCON=y || EXTCON=USB_DWC3)
|
||||||
help
|
help
|
||||||
This is the default mode of working of DWC3 controller where
|
This is the default mode of working of DWC3 controller where
|
||||||
both host and gadget features are enabled.
|
both host and gadget features are enabled.
|
||||||
@ -70,7 +71,7 @@ config USB_DWC3_EXYNOS
|
|||||||
|
|
||||||
config USB_DWC3_PCI
|
config USB_DWC3_PCI
|
||||||
tristate "PCIe-based Platforms"
|
tristate "PCIe-based Platforms"
|
||||||
depends on 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, please say
|
||||||
|
@ -17,6 +17,10 @@ ifneq ($(filter y,$(CONFIG_USB_DWC3_GADGET) $(CONFIG_USB_DWC3_DUAL_ROLE)),)
|
|||||||
dwc3-y += gadget.o ep0.o
|
dwc3-y += gadget.o ep0.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq ($(CONFIG_USB_DWC3_DUAL_ROLE),)
|
||||||
|
dwc3-y += drd.o
|
||||||
|
endif
|
||||||
|
|
||||||
ifneq ($(CONFIG_USB_DWC3_ULPI),)
|
ifneq ($(CONFIG_USB_DWC3_ULPI),)
|
||||||
dwc3-y += ulpi.o
|
dwc3-y += ulpi.o
|
||||||
endif
|
endif
|
||||||
|
@ -100,7 +100,10 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
|
static void dwc3_event_buffers_cleanup(struct dwc3 *dwc);
|
||||||
|
static int dwc3_event_buffers_setup(struct dwc3 *dwc);
|
||||||
|
|
||||||
|
static void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
|
||||||
{
|
{
|
||||||
u32 reg;
|
u32 reg;
|
||||||
|
|
||||||
@ -110,6 +113,69 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
|
|||||||
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
|
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void __dwc3_set_mode(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct dwc3 *dwc = work_to_dwc(work);
|
||||||
|
unsigned long flags;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!dwc->desired_dr_role)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (dwc->desired_dr_role == dwc->current_dr_role)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (dwc->dr_mode != USB_DR_MODE_OTG)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (dwc->current_dr_role) {
|
||||||
|
case DWC3_GCTL_PRTCAP_HOST:
|
||||||
|
dwc3_host_exit(dwc);
|
||||||
|
break;
|
||||||
|
case DWC3_GCTL_PRTCAP_DEVICE:
|
||||||
|
dwc3_gadget_exit(dwc);
|
||||||
|
dwc3_event_buffers_cleanup(dwc);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
spin_lock_irqsave(&dwc->lock, flags);
|
||||||
|
|
||||||
|
dwc3_set_prtcap(dwc, dwc->desired_dr_role);
|
||||||
|
|
||||||
|
dwc->current_dr_role = dwc->desired_dr_role;
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||||
|
|
||||||
|
switch (dwc->desired_dr_role) {
|
||||||
|
case DWC3_GCTL_PRTCAP_HOST:
|
||||||
|
ret = dwc3_host_init(dwc);
|
||||||
|
if (ret)
|
||||||
|
dev_err(dwc->dev, "failed to initialize host\n");
|
||||||
|
break;
|
||||||
|
case DWC3_GCTL_PRTCAP_DEVICE:
|
||||||
|
dwc3_event_buffers_setup(dwc);
|
||||||
|
ret = dwc3_gadget_init(dwc);
|
||||||
|
if (ret)
|
||||||
|
dev_err(dwc->dev, "failed to initialize peripheral\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&dwc->lock, flags);
|
||||||
|
dwc->desired_dr_role = mode;
|
||||||
|
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||||
|
|
||||||
|
queue_work(system_power_efficient_wq, &dwc->drd_work);
|
||||||
|
}
|
||||||
|
|
||||||
u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type)
|
u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type)
|
||||||
{
|
{
|
||||||
struct dwc3 *dwc = dep->dwc;
|
struct dwc3 *dwc = dep->dwc;
|
||||||
@ -397,8 +463,7 @@ static void dwc3_core_num_eps(struct dwc3 *dwc)
|
|||||||
{
|
{
|
||||||
struct dwc3_hwparams *parms = &dwc->hwparams;
|
struct dwc3_hwparams *parms = &dwc->hwparams;
|
||||||
|
|
||||||
dwc->num_in_eps = DWC3_NUM_IN_EPS(parms);
|
dwc->num_eps = DWC3_NUM_EPS(parms);
|
||||||
dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dwc3_cache_hwparams(struct dwc3 *dwc)
|
static void dwc3_cache_hwparams(struct dwc3 *dwc)
|
||||||
@ -431,6 +496,12 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
|
|||||||
|
|
||||||
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
|
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make sure UX_EXIT_PX is cleared as that causes issues with some
|
||||||
|
* PHYs. Also, this bit is not supposed to be used in normal operation.
|
||||||
|
*/
|
||||||
|
reg &= ~DWC3_GUSB3PIPECTL_UX_EXIT_PX;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Above 1.94a, it is recommended to set DWC3_GUSB3PIPECTL_SUSPHY
|
* Above 1.94a, it is recommended to set DWC3_GUSB3PIPECTL_SUSPHY
|
||||||
* to '0' during coreConsultant configuration. So default value
|
* to '0' during coreConsultant configuration. So default value
|
||||||
@ -714,21 +785,6 @@ static int dwc3_core_init(struct dwc3 *dwc)
|
|||||||
goto err4;
|
goto err4;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (dwc->dr_mode) {
|
|
||||||
case USB_DR_MODE_PERIPHERAL:
|
|
||||||
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
|
|
||||||
break;
|
|
||||||
case USB_DR_MODE_HOST:
|
|
||||||
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
|
|
||||||
break;
|
|
||||||
case USB_DR_MODE_OTG:
|
|
||||||
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
dev_warn(dwc->dev, "Unsupported mode %d\n", dwc->dr_mode);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ENDXFER polling is available on version 3.10a and later of
|
* ENDXFER polling is available on version 3.10a and later of
|
||||||
* the DWC_usb3 controller. It is NOT available in the
|
* the DWC_usb3 controller. It is NOT available in the
|
||||||
@ -846,6 +902,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
|
|||||||
|
|
||||||
switch (dwc->dr_mode) {
|
switch (dwc->dr_mode) {
|
||||||
case USB_DR_MODE_PERIPHERAL:
|
case USB_DR_MODE_PERIPHERAL:
|
||||||
|
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
|
||||||
ret = dwc3_gadget_init(dwc);
|
ret = dwc3_gadget_init(dwc);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (ret != -EPROBE_DEFER)
|
if (ret != -EPROBE_DEFER)
|
||||||
@ -854,6 +911,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case USB_DR_MODE_HOST:
|
case USB_DR_MODE_HOST:
|
||||||
|
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
|
||||||
ret = dwc3_host_init(dwc);
|
ret = dwc3_host_init(dwc);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (ret != -EPROBE_DEFER)
|
if (ret != -EPROBE_DEFER)
|
||||||
@ -862,17 +920,11 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case USB_DR_MODE_OTG:
|
case USB_DR_MODE_OTG:
|
||||||
ret = dwc3_host_init(dwc);
|
INIT_WORK(&dwc->drd_work, __dwc3_set_mode);
|
||||||
|
ret = dwc3_drd_init(dwc);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (ret != -EPROBE_DEFER)
|
if (ret != -EPROBE_DEFER)
|
||||||
dev_err(dev, "failed to initialize host\n");
|
dev_err(dev, "failed to initialize dual-role\n");
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = dwc3_gadget_init(dwc);
|
|
||||||
if (ret) {
|
|
||||||
if (ret != -EPROBE_DEFER)
|
|
||||||
dev_err(dev, "failed to initialize gadget\n");
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -894,8 +946,7 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc)
|
|||||||
dwc3_host_exit(dwc);
|
dwc3_host_exit(dwc);
|
||||||
break;
|
break;
|
||||||
case USB_DR_MODE_OTG:
|
case USB_DR_MODE_OTG:
|
||||||
dwc3_host_exit(dwc);
|
dwc3_drd_exit(dwc);
|
||||||
dwc3_gadget_exit(dwc);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* do nothing */
|
/* do nothing */
|
||||||
|
@ -23,10 +23,12 @@
|
|||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
|
#include <linux/bitops.h>
|
||||||
#include <linux/dma-mapping.h>
|
#include <linux/dma-mapping.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/debugfs.h>
|
#include <linux/debugfs.h>
|
||||||
#include <linux/wait.h>
|
#include <linux/wait.h>
|
||||||
|
#include <linux/workqueue.h>
|
||||||
|
|
||||||
#include <linux/usb/ch9.h>
|
#include <linux/usb/ch9.h>
|
||||||
#include <linux/usb/gadget.h>
|
#include <linux/usb/gadget.h>
|
||||||
@ -39,9 +41,8 @@
|
|||||||
|
|
||||||
/* Global constants */
|
/* Global constants */
|
||||||
#define DWC3_PULL_UP_TIMEOUT 500 /* ms */
|
#define DWC3_PULL_UP_TIMEOUT 500 /* ms */
|
||||||
#define DWC3_ZLP_BUF_SIZE 1024 /* size of a superspeed bulk */
|
|
||||||
#define DWC3_BOUNCE_SIZE 1024 /* size of a superspeed bulk */
|
#define DWC3_BOUNCE_SIZE 1024 /* size of a superspeed bulk */
|
||||||
#define DWC3_EP0_BOUNCE_SIZE 512
|
#define DWC3_EP0_SETUP_SIZE 512
|
||||||
#define DWC3_ENDPOINTS_NUM 32
|
#define DWC3_ENDPOINTS_NUM 32
|
||||||
#define DWC3_XHCI_RESOURCES_NUM 2
|
#define DWC3_XHCI_RESOURCES_NUM 2
|
||||||
|
|
||||||
@ -66,7 +67,7 @@
|
|||||||
#define DWC3_DEVICE_EVENT_OVERFLOW 11
|
#define DWC3_DEVICE_EVENT_OVERFLOW 11
|
||||||
|
|
||||||
#define DWC3_GEVNTCOUNT_MASK 0xfffc
|
#define DWC3_GEVNTCOUNT_MASK 0xfffc
|
||||||
#define DWC3_GEVNTCOUNT_EHB (1 << 31)
|
#define DWC3_GEVNTCOUNT_EHB BIT(31)
|
||||||
#define DWC3_GSNPSID_MASK 0xffff0000
|
#define DWC3_GSNPSID_MASK 0xffff0000
|
||||||
#define DWC3_GSNPSREV_MASK 0xffff
|
#define DWC3_GSNPSREV_MASK 0xffff
|
||||||
|
|
||||||
@ -116,20 +117,20 @@
|
|||||||
#define DWC3_VER_NUMBER 0xc1a0
|
#define DWC3_VER_NUMBER 0xc1a0
|
||||||
#define DWC3_VER_TYPE 0xc1a4
|
#define DWC3_VER_TYPE 0xc1a4
|
||||||
|
|
||||||
#define DWC3_GUSB2PHYCFG(n) (0xc200 + (n * 0x04))
|
#define DWC3_GUSB2PHYCFG(n) (0xc200 + ((n) * 0x04))
|
||||||
#define DWC3_GUSB2I2CCTL(n) (0xc240 + (n * 0x04))
|
#define DWC3_GUSB2I2CCTL(n) (0xc240 + ((n) * 0x04))
|
||||||
|
|
||||||
#define DWC3_GUSB2PHYACC(n) (0xc280 + (n * 0x04))
|
#define DWC3_GUSB2PHYACC(n) (0xc280 + ((n) * 0x04))
|
||||||
|
|
||||||
#define DWC3_GUSB3PIPECTL(n) (0xc2c0 + (n * 0x04))
|
#define DWC3_GUSB3PIPECTL(n) (0xc2c0 + ((n) * 0x04))
|
||||||
|
|
||||||
#define DWC3_GTXFIFOSIZ(n) (0xc300 + (n * 0x04))
|
#define DWC3_GTXFIFOSIZ(n) (0xc300 + ((n) * 0x04))
|
||||||
#define DWC3_GRXFIFOSIZ(n) (0xc380 + (n * 0x04))
|
#define DWC3_GRXFIFOSIZ(n) (0xc380 + ((n) * 0x04))
|
||||||
|
|
||||||
#define DWC3_GEVNTADRLO(n) (0xc400 + (n * 0x10))
|
#define DWC3_GEVNTADRLO(n) (0xc400 + ((n) * 0x10))
|
||||||
#define DWC3_GEVNTADRHI(n) (0xc404 + (n * 0x10))
|
#define DWC3_GEVNTADRHI(n) (0xc404 + ((n) * 0x10))
|
||||||
#define DWC3_GEVNTSIZ(n) (0xc408 + (n * 0x10))
|
#define DWC3_GEVNTSIZ(n) (0xc408 + ((n) * 0x10))
|
||||||
#define DWC3_GEVNTCOUNT(n) (0xc40c + (n * 0x10))
|
#define DWC3_GEVNTCOUNT(n) (0xc40c + ((n) * 0x10))
|
||||||
|
|
||||||
#define DWC3_GHWPARAMS8 0xc600
|
#define DWC3_GHWPARAMS8 0xc600
|
||||||
#define DWC3_GFLADJ 0xc630
|
#define DWC3_GFLADJ 0xc630
|
||||||
@ -143,13 +144,13 @@
|
|||||||
#define DWC3_DGCMD 0xc714
|
#define DWC3_DGCMD 0xc714
|
||||||
#define DWC3_DALEPENA 0xc720
|
#define DWC3_DALEPENA 0xc720
|
||||||
|
|
||||||
#define DWC3_DEP_BASE(n) (0xc800 + (n * 0x10))
|
#define DWC3_DEP_BASE(n) (0xc800 + ((n) * 0x10))
|
||||||
#define DWC3_DEPCMDPAR2 0x00
|
#define DWC3_DEPCMDPAR2 0x00
|
||||||
#define DWC3_DEPCMDPAR1 0x04
|
#define DWC3_DEPCMDPAR1 0x04
|
||||||
#define DWC3_DEPCMDPAR0 0x08
|
#define DWC3_DEPCMDPAR0 0x08
|
||||||
#define DWC3_DEPCMD 0x0c
|
#define DWC3_DEPCMD 0x0c
|
||||||
|
|
||||||
#define DWC3_DEV_IMOD(n) (0xca00 + (n * 0x4))
|
#define DWC3_DEV_IMOD(n) (0xca00 + ((n) * 0x4))
|
||||||
|
|
||||||
/* OTG Registers */
|
/* OTG Registers */
|
||||||
#define DWC3_OCFG 0xcc00
|
#define DWC3_OCFG 0xcc00
|
||||||
@ -176,11 +177,11 @@
|
|||||||
/* Global RX Threshold Configuration Register */
|
/* Global RX Threshold Configuration Register */
|
||||||
#define DWC3_GRXTHRCFG_MAXRXBURSTSIZE(n) (((n) & 0x1f) << 19)
|
#define DWC3_GRXTHRCFG_MAXRXBURSTSIZE(n) (((n) & 0x1f) << 19)
|
||||||
#define DWC3_GRXTHRCFG_RXPKTCNT(n) (((n) & 0xf) << 24)
|
#define DWC3_GRXTHRCFG_RXPKTCNT(n) (((n) & 0xf) << 24)
|
||||||
#define DWC3_GRXTHRCFG_PKTCNTSEL (1 << 29)
|
#define DWC3_GRXTHRCFG_PKTCNTSEL BIT(29)
|
||||||
|
|
||||||
/* Global Configuration Register */
|
/* Global Configuration Register */
|
||||||
#define DWC3_GCTL_PWRDNSCALE(n) ((n) << 19)
|
#define DWC3_GCTL_PWRDNSCALE(n) ((n) << 19)
|
||||||
#define DWC3_GCTL_U2RSTECN (1 << 16)
|
#define DWC3_GCTL_U2RSTECN BIT(16)
|
||||||
#define DWC3_GCTL_RAMCLKSEL(x) (((x) & DWC3_GCTL_CLK_MASK) << 6)
|
#define DWC3_GCTL_RAMCLKSEL(x) (((x) & DWC3_GCTL_CLK_MASK) << 6)
|
||||||
#define DWC3_GCTL_CLK_BUS (0)
|
#define DWC3_GCTL_CLK_BUS (0)
|
||||||
#define DWC3_GCTL_CLK_PIPE (1)
|
#define DWC3_GCTL_CLK_PIPE (1)
|
||||||
@ -193,24 +194,24 @@
|
|||||||
#define DWC3_GCTL_PRTCAP_DEVICE 2
|
#define DWC3_GCTL_PRTCAP_DEVICE 2
|
||||||
#define DWC3_GCTL_PRTCAP_OTG 3
|
#define DWC3_GCTL_PRTCAP_OTG 3
|
||||||
|
|
||||||
#define DWC3_GCTL_CORESOFTRESET (1 << 11)
|
#define DWC3_GCTL_CORESOFTRESET BIT(11)
|
||||||
#define DWC3_GCTL_SOFITPSYNC (1 << 10)
|
#define DWC3_GCTL_SOFITPSYNC BIT(10)
|
||||||
#define DWC3_GCTL_SCALEDOWN(n) ((n) << 4)
|
#define DWC3_GCTL_SCALEDOWN(n) ((n) << 4)
|
||||||
#define DWC3_GCTL_SCALEDOWN_MASK DWC3_GCTL_SCALEDOWN(3)
|
#define DWC3_GCTL_SCALEDOWN_MASK DWC3_GCTL_SCALEDOWN(3)
|
||||||
#define DWC3_GCTL_DISSCRAMBLE (1 << 3)
|
#define DWC3_GCTL_DISSCRAMBLE BIT(3)
|
||||||
#define DWC3_GCTL_U2EXIT_LFPS (1 << 2)
|
#define DWC3_GCTL_U2EXIT_LFPS BIT(2)
|
||||||
#define DWC3_GCTL_GBLHIBERNATIONEN (1 << 1)
|
#define DWC3_GCTL_GBLHIBERNATIONEN BIT(1)
|
||||||
#define DWC3_GCTL_DSBLCLKGTNG (1 << 0)
|
#define DWC3_GCTL_DSBLCLKGTNG BIT(0)
|
||||||
|
|
||||||
/* Global User Control 1 Register */
|
/* Global User Control 1 Register */
|
||||||
#define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW (1 << 24)
|
#define DWC3_GUCTL1_DEV_L1_EXIT_BY_HW BIT(24)
|
||||||
|
|
||||||
/* Global USB2 PHY Configuration Register */
|
/* Global USB2 PHY Configuration Register */
|
||||||
#define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31)
|
#define DWC3_GUSB2PHYCFG_PHYSOFTRST BIT(31)
|
||||||
#define DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS (1 << 30)
|
#define DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS BIT(30)
|
||||||
#define DWC3_GUSB2PHYCFG_SUSPHY (1 << 6)
|
#define DWC3_GUSB2PHYCFG_SUSPHY BIT(6)
|
||||||
#define DWC3_GUSB2PHYCFG_ULPI_UTMI (1 << 4)
|
#define DWC3_GUSB2PHYCFG_ULPI_UTMI BIT(4)
|
||||||
#define DWC3_GUSB2PHYCFG_ENBLSLPM (1 << 8)
|
#define DWC3_GUSB2PHYCFG_ENBLSLPM BIT(8)
|
||||||
#define DWC3_GUSB2PHYCFG_PHYIF(n) (n << 3)
|
#define DWC3_GUSB2PHYCFG_PHYIF(n) (n << 3)
|
||||||
#define DWC3_GUSB2PHYCFG_PHYIF_MASK DWC3_GUSB2PHYCFG_PHYIF(1)
|
#define DWC3_GUSB2PHYCFG_PHYIF_MASK DWC3_GUSB2PHYCFG_PHYIF(1)
|
||||||
#define DWC3_GUSB2PHYCFG_USBTRDTIM(n) (n << 10)
|
#define DWC3_GUSB2PHYCFG_USBTRDTIM(n) (n << 10)
|
||||||
@ -221,25 +222,26 @@
|
|||||||
#define UTMI_PHYIF_8_BIT 0
|
#define UTMI_PHYIF_8_BIT 0
|
||||||
|
|
||||||
/* Global USB2 PHY Vendor Control Register */
|
/* Global USB2 PHY Vendor Control Register */
|
||||||
#define DWC3_GUSB2PHYACC_NEWREGREQ (1 << 25)
|
#define DWC3_GUSB2PHYACC_NEWREGREQ BIT(25)
|
||||||
#define DWC3_GUSB2PHYACC_BUSY (1 << 23)
|
#define DWC3_GUSB2PHYACC_BUSY BIT(23)
|
||||||
#define DWC3_GUSB2PHYACC_WRITE (1 << 22)
|
#define DWC3_GUSB2PHYACC_WRITE BIT(22)
|
||||||
#define DWC3_GUSB2PHYACC_ADDR(n) (n << 16)
|
#define DWC3_GUSB2PHYACC_ADDR(n) (n << 16)
|
||||||
#define DWC3_GUSB2PHYACC_EXTEND_ADDR(n) (n << 8)
|
#define DWC3_GUSB2PHYACC_EXTEND_ADDR(n) (n << 8)
|
||||||
#define DWC3_GUSB2PHYACC_DATA(n) (n & 0xff)
|
#define DWC3_GUSB2PHYACC_DATA(n) (n & 0xff)
|
||||||
|
|
||||||
/* Global USB3 PIPE Control Register */
|
/* Global USB3 PIPE Control Register */
|
||||||
#define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
|
#define DWC3_GUSB3PIPECTL_PHYSOFTRST BIT(31)
|
||||||
#define DWC3_GUSB3PIPECTL_U2SSINP3OK (1 << 29)
|
#define DWC3_GUSB3PIPECTL_U2SSINP3OK BIT(29)
|
||||||
#define DWC3_GUSB3PIPECTL_DISRXDETINP3 (1 << 28)
|
#define DWC3_GUSB3PIPECTL_DISRXDETINP3 BIT(28)
|
||||||
#define DWC3_GUSB3PIPECTL_REQP1P2P3 (1 << 24)
|
#define DWC3_GUSB3PIPECTL_UX_EXIT_PX BIT(27)
|
||||||
|
#define DWC3_GUSB3PIPECTL_REQP1P2P3 BIT(24)
|
||||||
#define DWC3_GUSB3PIPECTL_DEP1P2P3(n) ((n) << 19)
|
#define DWC3_GUSB3PIPECTL_DEP1P2P3(n) ((n) << 19)
|
||||||
#define DWC3_GUSB3PIPECTL_DEP1P2P3_MASK DWC3_GUSB3PIPECTL_DEP1P2P3(7)
|
#define DWC3_GUSB3PIPECTL_DEP1P2P3_MASK DWC3_GUSB3PIPECTL_DEP1P2P3(7)
|
||||||
#define DWC3_GUSB3PIPECTL_DEP1P2P3_EN DWC3_GUSB3PIPECTL_DEP1P2P3(1)
|
#define DWC3_GUSB3PIPECTL_DEP1P2P3_EN DWC3_GUSB3PIPECTL_DEP1P2P3(1)
|
||||||
#define DWC3_GUSB3PIPECTL_DEPOCHANGE (1 << 18)
|
#define DWC3_GUSB3PIPECTL_DEPOCHANGE BIT(18)
|
||||||
#define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17)
|
#define DWC3_GUSB3PIPECTL_SUSPHY BIT(17)
|
||||||
#define DWC3_GUSB3PIPECTL_LFPSFILT (1 << 9)
|
#define DWC3_GUSB3PIPECTL_LFPSFILT BIT(9)
|
||||||
#define DWC3_GUSB3PIPECTL_RX_DETOPOLL (1 << 8)
|
#define DWC3_GUSB3PIPECTL_RX_DETOPOLL BIT(8)
|
||||||
#define DWC3_GUSB3PIPECTL_TX_DEEPH_MASK DWC3_GUSB3PIPECTL_TX_DEEPH(3)
|
#define DWC3_GUSB3PIPECTL_TX_DEEPH_MASK DWC3_GUSB3PIPECTL_TX_DEEPH(3)
|
||||||
#define DWC3_GUSB3PIPECTL_TX_DEEPH(n) ((n) << 1)
|
#define DWC3_GUSB3PIPECTL_TX_DEEPH(n) ((n) << 1)
|
||||||
|
|
||||||
@ -248,7 +250,7 @@
|
|||||||
#define DWC3_GTXFIFOSIZ_TXFSTADDR(n) ((n) & 0xffff0000)
|
#define DWC3_GTXFIFOSIZ_TXFSTADDR(n) ((n) & 0xffff0000)
|
||||||
|
|
||||||
/* Global Event Size Registers */
|
/* Global Event Size Registers */
|
||||||
#define DWC3_GEVNTSIZ_INTMASK (1 << 31)
|
#define DWC3_GEVNTSIZ_INTMASK BIT(31)
|
||||||
#define DWC3_GEVNTSIZ_SIZE(n) ((n) & 0xffff)
|
#define DWC3_GEVNTSIZ_SIZE(n) ((n) & 0xffff)
|
||||||
|
|
||||||
/* Global HWPARAMS0 Register */
|
/* Global HWPARAMS0 Register */
|
||||||
@ -289,18 +291,18 @@
|
|||||||
#define DWC3_MAX_HIBER_SCRATCHBUFS 15
|
#define DWC3_MAX_HIBER_SCRATCHBUFS 15
|
||||||
|
|
||||||
/* Global HWPARAMS6 Register */
|
/* Global HWPARAMS6 Register */
|
||||||
#define DWC3_GHWPARAMS6_EN_FPGA (1 << 7)
|
#define DWC3_GHWPARAMS6_EN_FPGA BIT(7)
|
||||||
|
|
||||||
/* Global HWPARAMS7 Register */
|
/* Global HWPARAMS7 Register */
|
||||||
#define DWC3_GHWPARAMS7_RAM1_DEPTH(n) ((n) & 0xffff)
|
#define DWC3_GHWPARAMS7_RAM1_DEPTH(n) ((n) & 0xffff)
|
||||||
#define DWC3_GHWPARAMS7_RAM2_DEPTH(n) (((n) >> 16) & 0xffff)
|
#define DWC3_GHWPARAMS7_RAM2_DEPTH(n) (((n) >> 16) & 0xffff)
|
||||||
|
|
||||||
/* Global Frame Length Adjustment Register */
|
/* Global Frame Length Adjustment Register */
|
||||||
#define DWC3_GFLADJ_30MHZ_SDBND_SEL (1 << 7)
|
#define DWC3_GFLADJ_30MHZ_SDBND_SEL BIT(7)
|
||||||
#define DWC3_GFLADJ_30MHZ_MASK 0x3f
|
#define DWC3_GFLADJ_30MHZ_MASK 0x3f
|
||||||
|
|
||||||
/* Global User Control Register 2 */
|
/* Global User Control Register 2 */
|
||||||
#define DWC3_GUCTL2_RST_ACTBITLATER (1 << 14)
|
#define DWC3_GUCTL2_RST_ACTBITLATER BIT(14)
|
||||||
|
|
||||||
/* Device Configuration Register */
|
/* Device Configuration Register */
|
||||||
#define DWC3_DCFG_DEVADDR(addr) ((addr) << 3)
|
#define DWC3_DCFG_DEVADDR(addr) ((addr) << 3)
|
||||||
@ -310,23 +312,23 @@
|
|||||||
#define DWC3_DCFG_SUPERSPEED_PLUS (5 << 0) /* DWC_usb31 only */
|
#define DWC3_DCFG_SUPERSPEED_PLUS (5 << 0) /* DWC_usb31 only */
|
||||||
#define DWC3_DCFG_SUPERSPEED (4 << 0)
|
#define DWC3_DCFG_SUPERSPEED (4 << 0)
|
||||||
#define DWC3_DCFG_HIGHSPEED (0 << 0)
|
#define DWC3_DCFG_HIGHSPEED (0 << 0)
|
||||||
#define DWC3_DCFG_FULLSPEED (1 << 0)
|
#define DWC3_DCFG_FULLSPEED BIT(0)
|
||||||
#define DWC3_DCFG_LOWSPEED (2 << 0)
|
#define DWC3_DCFG_LOWSPEED (2 << 0)
|
||||||
|
|
||||||
#define DWC3_DCFG_NUMP_SHIFT 17
|
#define DWC3_DCFG_NUMP_SHIFT 17
|
||||||
#define DWC3_DCFG_NUMP(n) (((n) >> DWC3_DCFG_NUMP_SHIFT) & 0x1f)
|
#define DWC3_DCFG_NUMP(n) (((n) >> DWC3_DCFG_NUMP_SHIFT) & 0x1f)
|
||||||
#define DWC3_DCFG_NUMP_MASK (0x1f << DWC3_DCFG_NUMP_SHIFT)
|
#define DWC3_DCFG_NUMP_MASK (0x1f << DWC3_DCFG_NUMP_SHIFT)
|
||||||
#define DWC3_DCFG_LPM_CAP (1 << 22)
|
#define DWC3_DCFG_LPM_CAP BIT(22)
|
||||||
|
|
||||||
/* Device Control Register */
|
/* Device Control Register */
|
||||||
#define DWC3_DCTL_RUN_STOP (1 << 31)
|
#define DWC3_DCTL_RUN_STOP BIT(31)
|
||||||
#define DWC3_DCTL_CSFTRST (1 << 30)
|
#define DWC3_DCTL_CSFTRST BIT(30)
|
||||||
#define DWC3_DCTL_LSFTRST (1 << 29)
|
#define DWC3_DCTL_LSFTRST BIT(29)
|
||||||
|
|
||||||
#define DWC3_DCTL_HIRD_THRES_MASK (0x1f << 24)
|
#define DWC3_DCTL_HIRD_THRES_MASK (0x1f << 24)
|
||||||
#define DWC3_DCTL_HIRD_THRES(n) ((n) << 24)
|
#define DWC3_DCTL_HIRD_THRES(n) ((n) << 24)
|
||||||
|
|
||||||
#define DWC3_DCTL_APPL1RES (1 << 23)
|
#define DWC3_DCTL_APPL1RES BIT(23)
|
||||||
|
|
||||||
/* These apply for core versions 1.87a and earlier */
|
/* These apply for core versions 1.87a and earlier */
|
||||||
#define DWC3_DCTL_TRGTULST_MASK (0x0f << 17)
|
#define DWC3_DCTL_TRGTULST_MASK (0x0f << 17)
|
||||||
@ -341,15 +343,15 @@
|
|||||||
#define DWC3_DCTL_LPM_ERRATA_MASK DWC3_DCTL_LPM_ERRATA(0xf)
|
#define DWC3_DCTL_LPM_ERRATA_MASK DWC3_DCTL_LPM_ERRATA(0xf)
|
||||||
#define DWC3_DCTL_LPM_ERRATA(n) ((n) << 20)
|
#define DWC3_DCTL_LPM_ERRATA(n) ((n) << 20)
|
||||||
|
|
||||||
#define DWC3_DCTL_KEEP_CONNECT (1 << 19)
|
#define DWC3_DCTL_KEEP_CONNECT BIT(19)
|
||||||
#define DWC3_DCTL_L1_HIBER_EN (1 << 18)
|
#define DWC3_DCTL_L1_HIBER_EN BIT(18)
|
||||||
#define DWC3_DCTL_CRS (1 << 17)
|
#define DWC3_DCTL_CRS BIT(17)
|
||||||
#define DWC3_DCTL_CSS (1 << 16)
|
#define DWC3_DCTL_CSS BIT(16)
|
||||||
|
|
||||||
#define DWC3_DCTL_INITU2ENA (1 << 12)
|
#define DWC3_DCTL_INITU2ENA BIT(12)
|
||||||
#define DWC3_DCTL_ACCEPTU2ENA (1 << 11)
|
#define DWC3_DCTL_ACCEPTU2ENA BIT(11)
|
||||||
#define DWC3_DCTL_INITU1ENA (1 << 10)
|
#define DWC3_DCTL_INITU1ENA BIT(10)
|
||||||
#define DWC3_DCTL_ACCEPTU1ENA (1 << 9)
|
#define DWC3_DCTL_ACCEPTU1ENA BIT(9)
|
||||||
#define DWC3_DCTL_TSTCTRL_MASK (0xf << 1)
|
#define DWC3_DCTL_TSTCTRL_MASK (0xf << 1)
|
||||||
|
|
||||||
#define DWC3_DCTL_ULSTCHNGREQ_MASK (0x0f << 5)
|
#define DWC3_DCTL_ULSTCHNGREQ_MASK (0x0f << 5)
|
||||||
@ -364,36 +366,36 @@
|
|||||||
#define DWC3_DCTL_ULSTCHNG_LOOPBACK (DWC3_DCTL_ULSTCHNGREQ(11))
|
#define DWC3_DCTL_ULSTCHNG_LOOPBACK (DWC3_DCTL_ULSTCHNGREQ(11))
|
||||||
|
|
||||||
/* Device Event Enable Register */
|
/* Device Event Enable Register */
|
||||||
#define DWC3_DEVTEN_VNDRDEVTSTRCVEDEN (1 << 12)
|
#define DWC3_DEVTEN_VNDRDEVTSTRCVEDEN BIT(12)
|
||||||
#define DWC3_DEVTEN_EVNTOVERFLOWEN (1 << 11)
|
#define DWC3_DEVTEN_EVNTOVERFLOWEN BIT(11)
|
||||||
#define DWC3_DEVTEN_CMDCMPLTEN (1 << 10)
|
#define DWC3_DEVTEN_CMDCMPLTEN BIT(10)
|
||||||
#define DWC3_DEVTEN_ERRTICERREN (1 << 9)
|
#define DWC3_DEVTEN_ERRTICERREN BIT(9)
|
||||||
#define DWC3_DEVTEN_SOFEN (1 << 7)
|
#define DWC3_DEVTEN_SOFEN BIT(7)
|
||||||
#define DWC3_DEVTEN_EOPFEN (1 << 6)
|
#define DWC3_DEVTEN_EOPFEN BIT(6)
|
||||||
#define DWC3_DEVTEN_HIBERNATIONREQEVTEN (1 << 5)
|
#define DWC3_DEVTEN_HIBERNATIONREQEVTEN BIT(5)
|
||||||
#define DWC3_DEVTEN_WKUPEVTEN (1 << 4)
|
#define DWC3_DEVTEN_WKUPEVTEN BIT(4)
|
||||||
#define DWC3_DEVTEN_ULSTCNGEN (1 << 3)
|
#define DWC3_DEVTEN_ULSTCNGEN BIT(3)
|
||||||
#define DWC3_DEVTEN_CONNECTDONEEN (1 << 2)
|
#define DWC3_DEVTEN_CONNECTDONEEN BIT(2)
|
||||||
#define DWC3_DEVTEN_USBRSTEN (1 << 1)
|
#define DWC3_DEVTEN_USBRSTEN BIT(1)
|
||||||
#define DWC3_DEVTEN_DISCONNEVTEN (1 << 0)
|
#define DWC3_DEVTEN_DISCONNEVTEN BIT(0)
|
||||||
|
|
||||||
/* Device Status Register */
|
/* Device Status Register */
|
||||||
#define DWC3_DSTS_DCNRD (1 << 29)
|
#define DWC3_DSTS_DCNRD BIT(29)
|
||||||
|
|
||||||
/* This applies for core versions 1.87a and earlier */
|
/* This applies for core versions 1.87a and earlier */
|
||||||
#define DWC3_DSTS_PWRUPREQ (1 << 24)
|
#define DWC3_DSTS_PWRUPREQ BIT(24)
|
||||||
|
|
||||||
/* These apply for core versions 1.94a and later */
|
/* These apply for core versions 1.94a and later */
|
||||||
#define DWC3_DSTS_RSS (1 << 25)
|
#define DWC3_DSTS_RSS BIT(25)
|
||||||
#define DWC3_DSTS_SSS (1 << 24)
|
#define DWC3_DSTS_SSS BIT(24)
|
||||||
|
|
||||||
#define DWC3_DSTS_COREIDLE (1 << 23)
|
#define DWC3_DSTS_COREIDLE BIT(23)
|
||||||
#define DWC3_DSTS_DEVCTRLHLT (1 << 22)
|
#define DWC3_DSTS_DEVCTRLHLT BIT(22)
|
||||||
|
|
||||||
#define DWC3_DSTS_USBLNKST_MASK (0x0f << 18)
|
#define DWC3_DSTS_USBLNKST_MASK (0x0f << 18)
|
||||||
#define DWC3_DSTS_USBLNKST(n) (((n) & DWC3_DSTS_USBLNKST_MASK) >> 18)
|
#define DWC3_DSTS_USBLNKST(n) (((n) & DWC3_DSTS_USBLNKST_MASK) >> 18)
|
||||||
|
|
||||||
#define DWC3_DSTS_RXFIFOEMPTY (1 << 17)
|
#define DWC3_DSTS_RXFIFOEMPTY BIT(17)
|
||||||
|
|
||||||
#define DWC3_DSTS_SOFFN_MASK (0x3fff << 3)
|
#define DWC3_DSTS_SOFFN_MASK (0x3fff << 3)
|
||||||
#define DWC3_DSTS_SOFFN(n) (((n) & DWC3_DSTS_SOFFN_MASK) >> 3)
|
#define DWC3_DSTS_SOFFN(n) (((n) & DWC3_DSTS_SOFFN_MASK) >> 3)
|
||||||
@ -403,7 +405,7 @@
|
|||||||
#define DWC3_DSTS_SUPERSPEED_PLUS (5 << 0) /* DWC_usb31 only */
|
#define DWC3_DSTS_SUPERSPEED_PLUS (5 << 0) /* DWC_usb31 only */
|
||||||
#define DWC3_DSTS_SUPERSPEED (4 << 0)
|
#define DWC3_DSTS_SUPERSPEED (4 << 0)
|
||||||
#define DWC3_DSTS_HIGHSPEED (0 << 0)
|
#define DWC3_DSTS_HIGHSPEED (0 << 0)
|
||||||
#define DWC3_DSTS_FULLSPEED (1 << 0)
|
#define DWC3_DSTS_FULLSPEED BIT(0)
|
||||||
#define DWC3_DSTS_LOWSPEED (2 << 0)
|
#define DWC3_DSTS_LOWSPEED (2 << 0)
|
||||||
|
|
||||||
/* Device Generic Command Register */
|
/* Device Generic Command Register */
|
||||||
@ -421,26 +423,26 @@
|
|||||||
#define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK 0x10
|
#define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK 0x10
|
||||||
|
|
||||||
#define DWC3_DGCMD_STATUS(n) (((n) >> 12) & 0x0F)
|
#define DWC3_DGCMD_STATUS(n) (((n) >> 12) & 0x0F)
|
||||||
#define DWC3_DGCMD_CMDACT (1 << 10)
|
#define DWC3_DGCMD_CMDACT BIT(10)
|
||||||
#define DWC3_DGCMD_CMDIOC (1 << 8)
|
#define DWC3_DGCMD_CMDIOC BIT(8)
|
||||||
|
|
||||||
/* Device Generic Command Parameter Register */
|
/* Device Generic Command Parameter Register */
|
||||||
#define DWC3_DGCMDPAR_FORCE_LINKPM_ACCEPT (1 << 0)
|
#define DWC3_DGCMDPAR_FORCE_LINKPM_ACCEPT BIT(0)
|
||||||
#define DWC3_DGCMDPAR_FIFO_NUM(n) ((n) << 0)
|
#define DWC3_DGCMDPAR_FIFO_NUM(n) ((n) << 0)
|
||||||
#define DWC3_DGCMDPAR_RX_FIFO (0 << 5)
|
#define DWC3_DGCMDPAR_RX_FIFO (0 << 5)
|
||||||
#define DWC3_DGCMDPAR_TX_FIFO (1 << 5)
|
#define DWC3_DGCMDPAR_TX_FIFO BIT(5)
|
||||||
#define DWC3_DGCMDPAR_LOOPBACK_DIS (0 << 0)
|
#define DWC3_DGCMDPAR_LOOPBACK_DIS (0 << 0)
|
||||||
#define DWC3_DGCMDPAR_LOOPBACK_ENA (1 << 0)
|
#define DWC3_DGCMDPAR_LOOPBACK_ENA BIT(0)
|
||||||
|
|
||||||
/* Device Endpoint Command Register */
|
/* Device Endpoint Command Register */
|
||||||
#define DWC3_DEPCMD_PARAM_SHIFT 16
|
#define DWC3_DEPCMD_PARAM_SHIFT 16
|
||||||
#define DWC3_DEPCMD_PARAM(x) ((x) << DWC3_DEPCMD_PARAM_SHIFT)
|
#define DWC3_DEPCMD_PARAM(x) ((x) << DWC3_DEPCMD_PARAM_SHIFT)
|
||||||
#define DWC3_DEPCMD_GET_RSC_IDX(x) (((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
|
#define DWC3_DEPCMD_GET_RSC_IDX(x) (((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
|
||||||
#define DWC3_DEPCMD_STATUS(x) (((x) >> 12) & 0x0F)
|
#define DWC3_DEPCMD_STATUS(x) (((x) >> 12) & 0x0F)
|
||||||
#define DWC3_DEPCMD_HIPRI_FORCERM (1 << 11)
|
#define DWC3_DEPCMD_HIPRI_FORCERM BIT(11)
|
||||||
#define DWC3_DEPCMD_CLEARPENDIN (1 << 11)
|
#define DWC3_DEPCMD_CLEARPENDIN BIT(11)
|
||||||
#define DWC3_DEPCMD_CMDACT (1 << 10)
|
#define DWC3_DEPCMD_CMDACT BIT(10)
|
||||||
#define DWC3_DEPCMD_CMDIOC (1 << 8)
|
#define DWC3_DEPCMD_CMDIOC BIT(8)
|
||||||
|
|
||||||
#define DWC3_DEPCMD_DEPSTARTCFG (0x09 << 0)
|
#define DWC3_DEPCMD_DEPSTARTCFG (0x09 << 0)
|
||||||
#define DWC3_DEPCMD_ENDTRANSFER (0x08 << 0)
|
#define DWC3_DEPCMD_ENDTRANSFER (0x08 << 0)
|
||||||
@ -458,7 +460,7 @@
|
|||||||
#define DWC3_DEPCMD_CMD(x) ((x) & 0xf)
|
#define DWC3_DEPCMD_CMD(x) ((x) & 0xf)
|
||||||
|
|
||||||
/* The EP number goes 0..31 so ep0 is always out and ep1 is always in */
|
/* The EP number goes 0..31 so ep0 is always out and ep1 is always in */
|
||||||
#define DWC3_DALEPENA_EP(n) (1 << n)
|
#define DWC3_DALEPENA_EP(n) BIT(n)
|
||||||
|
|
||||||
#define DWC3_DEPCMD_TYPE_CONTROL 0
|
#define DWC3_DEPCMD_TYPE_CONTROL 0
|
||||||
#define DWC3_DEPCMD_TYPE_ISOC 1
|
#define DWC3_DEPCMD_TYPE_ISOC 1
|
||||||
@ -500,8 +502,8 @@ struct dwc3_event_buffer {
|
|||||||
struct dwc3 *dwc;
|
struct dwc3 *dwc;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DWC3_EP_FLAG_STALLED (1 << 0)
|
#define DWC3_EP_FLAG_STALLED BIT(0)
|
||||||
#define DWC3_EP_FLAG_WEDGED (1 << 1)
|
#define DWC3_EP_FLAG_WEDGED BIT(1)
|
||||||
|
|
||||||
#define DWC3_EP_DIRECTION_TX true
|
#define DWC3_EP_DIRECTION_TX true
|
||||||
#define DWC3_EP_DIRECTION_RX false
|
#define DWC3_EP_DIRECTION_RX false
|
||||||
@ -550,17 +552,17 @@ struct dwc3_ep {
|
|||||||
|
|
||||||
u32 saved_state;
|
u32 saved_state;
|
||||||
unsigned flags;
|
unsigned flags;
|
||||||
#define DWC3_EP_ENABLED (1 << 0)
|
#define DWC3_EP_ENABLED BIT(0)
|
||||||
#define DWC3_EP_STALL (1 << 1)
|
#define DWC3_EP_STALL BIT(1)
|
||||||
#define DWC3_EP_WEDGE (1 << 2)
|
#define DWC3_EP_WEDGE BIT(2)
|
||||||
#define DWC3_EP_BUSY (1 << 4)
|
#define DWC3_EP_BUSY BIT(4)
|
||||||
#define DWC3_EP_PENDING_REQUEST (1 << 5)
|
#define DWC3_EP_PENDING_REQUEST BIT(5)
|
||||||
#define DWC3_EP_MISSED_ISOC (1 << 6)
|
#define DWC3_EP_MISSED_ISOC BIT(6)
|
||||||
#define DWC3_EP_END_TRANSFER_PENDING (1 << 7)
|
#define DWC3_EP_END_TRANSFER_PENDING BIT(7)
|
||||||
#define DWC3_EP_TRANSFER_STARTED (1 << 8)
|
#define DWC3_EP_TRANSFER_STARTED BIT(8)
|
||||||
|
|
||||||
/* This last one is specific to EP0 */
|
/* This last one is specific to EP0 */
|
||||||
#define DWC3_EP0_DIR_IN (1 << 31)
|
#define DWC3_EP0_DIR_IN BIT(31)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IMPORTANT: we *know* we have 256 TRBs in our @trb_pool, so we will
|
* IMPORTANT: we *know* we have 256 TRBs in our @trb_pool, so we will
|
||||||
@ -638,13 +640,13 @@ enum dwc3_link_state {
|
|||||||
#define DWC3_TRB_STS_XFER_IN_PROG 4
|
#define DWC3_TRB_STS_XFER_IN_PROG 4
|
||||||
|
|
||||||
/* TRB Control */
|
/* TRB Control */
|
||||||
#define DWC3_TRB_CTRL_HWO (1 << 0)
|
#define DWC3_TRB_CTRL_HWO BIT(0)
|
||||||
#define DWC3_TRB_CTRL_LST (1 << 1)
|
#define DWC3_TRB_CTRL_LST BIT(1)
|
||||||
#define DWC3_TRB_CTRL_CHN (1 << 2)
|
#define DWC3_TRB_CTRL_CHN BIT(2)
|
||||||
#define DWC3_TRB_CTRL_CSP (1 << 3)
|
#define DWC3_TRB_CTRL_CSP BIT(3)
|
||||||
#define DWC3_TRB_CTRL_TRBCTL(n) (((n) & 0x3f) << 4)
|
#define DWC3_TRB_CTRL_TRBCTL(n) (((n) & 0x3f) << 4)
|
||||||
#define DWC3_TRB_CTRL_ISP_IMI (1 << 10)
|
#define DWC3_TRB_CTRL_ISP_IMI BIT(10)
|
||||||
#define DWC3_TRB_CTRL_IOC (1 << 11)
|
#define DWC3_TRB_CTRL_IOC BIT(11)
|
||||||
#define DWC3_TRB_CTRL_SID_SOFN(n) (((n) & 0xffff) << 14)
|
#define DWC3_TRB_CTRL_SID_SOFN(n) (((n) & 0xffff) << 14)
|
||||||
|
|
||||||
#define DWC3_TRBCTL_TYPE(n) ((n) & (0x3f << 4))
|
#define DWC3_TRBCTL_TYPE(n) ((n) & (0x3f << 4))
|
||||||
@ -746,6 +748,7 @@ struct dwc3_request {
|
|||||||
unsigned direction:1;
|
unsigned direction:1;
|
||||||
unsigned mapped:1;
|
unsigned mapped:1;
|
||||||
unsigned started:1;
|
unsigned started:1;
|
||||||
|
unsigned zero:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -758,15 +761,11 @@ struct dwc3_scratchpad_array {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* struct dwc3 - representation of our controller
|
* struct dwc3 - representation of our controller
|
||||||
* @ctrl_req: usb control request which is used for ep0
|
* @drd_work - workqueue used for role swapping
|
||||||
* @ep0_trb: trb which is used for the ctrl_req
|
* @ep0_trb: trb which is used for the ctrl_req
|
||||||
* @ep0_bounce: bounce buffer for ep0
|
|
||||||
* @zlp_buf: used when request->zero is set
|
|
||||||
* @setup_buf: used while precessing STD USB requests
|
* @setup_buf: used while precessing STD USB requests
|
||||||
* @ctrl_req_addr: dma address of ctrl_req
|
|
||||||
* @ep0_trb: dma address of ep0_trb
|
* @ep0_trb: dma address of ep0_trb
|
||||||
* @ep0_usb_req: dummy req used while handling STD USB requests
|
* @ep0_usb_req: dummy req used while handling STD USB requests
|
||||||
* @ep0_bounce_addr: dma address of ep0_bounce
|
|
||||||
* @scratch_addr: dma address of scratchbuf
|
* @scratch_addr: dma address of scratchbuf
|
||||||
* @ep0_in_setup: one control transfer is completed and enter setup phase
|
* @ep0_in_setup: one control transfer is completed and enter setup phase
|
||||||
* @lock: for synchronizing
|
* @lock: for synchronizing
|
||||||
@ -784,6 +783,10 @@ struct dwc3_scratchpad_array {
|
|||||||
* @maximum_speed: maximum speed requested (mainly for testing purposes)
|
* @maximum_speed: maximum speed requested (mainly for testing purposes)
|
||||||
* @revision: revision register contents
|
* @revision: revision register contents
|
||||||
* @dr_mode: requested mode of operation
|
* @dr_mode: requested mode of operation
|
||||||
|
* @current_dr_role: current role of operation when in dual-role mode
|
||||||
|
* @desired_dr_role: desired role of operation when in dual-role mode
|
||||||
|
* @edev: extcon handle
|
||||||
|
* @edev_nb: extcon notifier
|
||||||
* @hsphy_mode: UTMI phy mode, one of following:
|
* @hsphy_mode: UTMI phy mode, one of following:
|
||||||
* - USBPHY_INTERFACE_MODE_UTMI
|
* - USBPHY_INTERFACE_MODE_UTMI
|
||||||
* - USBPHY_INTERFACE_MODE_UTMIW
|
* - USBPHY_INTERFACE_MODE_UTMIW
|
||||||
@ -799,8 +802,7 @@ struct dwc3_scratchpad_array {
|
|||||||
* @u2pel: parameter from Set SEL request.
|
* @u2pel: parameter from Set SEL request.
|
||||||
* @u1sel: parameter from Set SEL request.
|
* @u1sel: parameter from Set SEL request.
|
||||||
* @u1pel: parameter from Set SEL request.
|
* @u1pel: parameter from Set SEL request.
|
||||||
* @num_out_eps: number of out endpoints
|
* @num_eps: number of endpoints
|
||||||
* @num_in_eps: number of in endpoints
|
|
||||||
* @ep0_next_event: hold the next expected event
|
* @ep0_next_event: hold the next expected event
|
||||||
* @ep0state: state of endpoint zero
|
* @ep0state: state of endpoint zero
|
||||||
* @link_state: link state
|
* @link_state: link state
|
||||||
@ -858,17 +860,13 @@ struct dwc3_scratchpad_array {
|
|||||||
* increments or 0 to disable.
|
* increments or 0 to disable.
|
||||||
*/
|
*/
|
||||||
struct dwc3 {
|
struct dwc3 {
|
||||||
struct usb_ctrlrequest *ctrl_req;
|
struct work_struct drd_work;
|
||||||
struct dwc3_trb *ep0_trb;
|
struct dwc3_trb *ep0_trb;
|
||||||
void *bounce;
|
void *bounce;
|
||||||
void *ep0_bounce;
|
|
||||||
void *zlp_buf;
|
|
||||||
void *scratchbuf;
|
void *scratchbuf;
|
||||||
u8 *setup_buf;
|
u8 *setup_buf;
|
||||||
dma_addr_t ctrl_req_addr;
|
|
||||||
dma_addr_t ep0_trb_addr;
|
dma_addr_t ep0_trb_addr;
|
||||||
dma_addr_t bounce_addr;
|
dma_addr_t bounce_addr;
|
||||||
dma_addr_t ep0_bounce_addr;
|
|
||||||
dma_addr_t scratch_addr;
|
dma_addr_t scratch_addr;
|
||||||
struct dwc3_request ep0_usb_req;
|
struct dwc3_request ep0_usb_req;
|
||||||
struct completion ep0_in_setup;
|
struct completion ep0_in_setup;
|
||||||
@ -900,6 +898,10 @@ struct dwc3 {
|
|||||||
size_t regs_size;
|
size_t regs_size;
|
||||||
|
|
||||||
enum usb_dr_mode dr_mode;
|
enum usb_dr_mode dr_mode;
|
||||||
|
u32 current_dr_role;
|
||||||
|
u32 desired_dr_role;
|
||||||
|
struct extcon_dev *edev;
|
||||||
|
struct notifier_block edev_nb;
|
||||||
enum usb_phy_interface hsphy_mode;
|
enum usb_phy_interface hsphy_mode;
|
||||||
|
|
||||||
u32 fladj;
|
u32 fladj;
|
||||||
@ -960,8 +962,7 @@ struct dwc3 {
|
|||||||
|
|
||||||
u8 speed;
|
u8 speed;
|
||||||
|
|
||||||
u8 num_out_eps;
|
u8 num_eps;
|
||||||
u8 num_in_eps;
|
|
||||||
|
|
||||||
struct dwc3_hwparams hwparams;
|
struct dwc3_hwparams hwparams;
|
||||||
struct dentry *root;
|
struct dentry *root;
|
||||||
@ -1010,7 +1011,7 @@ struct dwc3 {
|
|||||||
u16 imod_interval;
|
u16 imod_interval;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
#define work_to_dwc(w) (container_of((w), struct dwc3, drd_work))
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
@ -1054,13 +1055,13 @@ struct dwc3_event_depevt {
|
|||||||
u32 status:4;
|
u32 status:4;
|
||||||
|
|
||||||
/* Within XferNotReady */
|
/* Within XferNotReady */
|
||||||
#define DEPEVT_STATUS_TRANSFER_ACTIVE (1 << 3)
|
#define DEPEVT_STATUS_TRANSFER_ACTIVE BIT(3)
|
||||||
|
|
||||||
/* Within XferComplete */
|
/* Within XferComplete */
|
||||||
#define DEPEVT_STATUS_BUSERR (1 << 0)
|
#define DEPEVT_STATUS_BUSERR BIT(0)
|
||||||
#define DEPEVT_STATUS_SHORT (1 << 1)
|
#define DEPEVT_STATUS_SHORT BIT(1)
|
||||||
#define DEPEVT_STATUS_IOC (1 << 2)
|
#define DEPEVT_STATUS_IOC BIT(2)
|
||||||
#define DEPEVT_STATUS_LST (1 << 3)
|
#define DEPEVT_STATUS_LST BIT(3)
|
||||||
|
|
||||||
/* Stream event only */
|
/* Stream event only */
|
||||||
#define DEPEVT_STREAMEVT_FOUND 1
|
#define DEPEVT_STREAMEVT_FOUND 1
|
||||||
@ -1221,6 +1222,16 @@ static inline int dwc3_send_gadget_generic_command(struct dwc3 *dwc,
|
|||||||
{ return 0; }
|
{ return 0; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
|
||||||
|
int dwc3_drd_init(struct dwc3 *dwc);
|
||||||
|
void dwc3_drd_exit(struct dwc3 *dwc);
|
||||||
|
#else
|
||||||
|
static inline int dwc3_drd_init(struct dwc3 *dwc)
|
||||||
|
{ return 0; }
|
||||||
|
static inline void dwc3_drd_exit(struct dwc3 *dwc)
|
||||||
|
{ }
|
||||||
|
#endif
|
||||||
|
|
||||||
/* power management interface */
|
/* power management interface */
|
||||||
#if !IS_ENABLED(CONFIG_USB_DWC3_HOST)
|
#if !IS_ENABLED(CONFIG_USB_DWC3_HOST)
|
||||||
int dwc3_gadget_suspend(struct dwc3 *dwc);
|
int dwc3_gadget_suspend(struct dwc3 *dwc);
|
||||||
|
@ -124,6 +124,34 @@ dwc3_gadget_link_string(enum dwc3_link_state link_state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dwc3_trb_type_string - returns TRB type as a string
|
||||||
|
* @type: the type of the TRB
|
||||||
|
*/
|
||||||
|
static inline const char *dwc3_trb_type_string(unsigned int type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case DWC3_TRBCTL_NORMAL:
|
||||||
|
return "normal";
|
||||||
|
case DWC3_TRBCTL_CONTROL_SETUP:
|
||||||
|
return "setup";
|
||||||
|
case DWC3_TRBCTL_CONTROL_STATUS2:
|
||||||
|
return "status2";
|
||||||
|
case DWC3_TRBCTL_CONTROL_STATUS3:
|
||||||
|
return "status3";
|
||||||
|
case DWC3_TRBCTL_CONTROL_DATA:
|
||||||
|
return "data";
|
||||||
|
case DWC3_TRBCTL_ISOCHRONOUS_FIRST:
|
||||||
|
return "isoc-first";
|
||||||
|
case DWC3_TRBCTL_ISOCHRONOUS:
|
||||||
|
return "isoc";
|
||||||
|
case DWC3_TRBCTL_LINK_TRB:
|
||||||
|
return "link";
|
||||||
|
default:
|
||||||
|
return "UNKNOWN";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static inline const char *dwc3_ep0_state_string(enum dwc3_ep0_state state)
|
static inline const char *dwc3_ep0_state_string(enum dwc3_ep0_state state)
|
||||||
{
|
{
|
||||||
switch (state) {
|
switch (state) {
|
||||||
|
@ -300,7 +300,7 @@ static int dwc3_mode_show(struct seq_file *s, void *unused)
|
|||||||
seq_printf(s, "device\n");
|
seq_printf(s, "device\n");
|
||||||
break;
|
break;
|
||||||
case DWC3_GCTL_PRTCAP_OTG:
|
case DWC3_GCTL_PRTCAP_OTG:
|
||||||
seq_printf(s, "OTG\n");
|
seq_printf(s, "otg\n");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
seq_printf(s, "UNKNOWN %08x\n", DWC3_GCTL_PRTCAP(reg));
|
seq_printf(s, "UNKNOWN %08x\n", DWC3_GCTL_PRTCAP(reg));
|
||||||
@ -319,7 +319,6 @@ static ssize_t dwc3_mode_write(struct file *file,
|
|||||||
{
|
{
|
||||||
struct seq_file *s = file->private_data;
|
struct seq_file *s = file->private_data;
|
||||||
struct dwc3 *dwc = s->private;
|
struct dwc3 *dwc = s->private;
|
||||||
unsigned long flags;
|
|
||||||
u32 mode = 0;
|
u32 mode = 0;
|
||||||
char buf[32];
|
char buf[32];
|
||||||
|
|
||||||
@ -327,19 +326,16 @@ static ssize_t dwc3_mode_write(struct file *file,
|
|||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
if (!strncmp(buf, "host", 4))
|
if (!strncmp(buf, "host", 4))
|
||||||
mode |= DWC3_GCTL_PRTCAP_HOST;
|
mode = DWC3_GCTL_PRTCAP_HOST;
|
||||||
|
|
||||||
if (!strncmp(buf, "device", 6))
|
if (!strncmp(buf, "device", 6))
|
||||||
mode |= DWC3_GCTL_PRTCAP_DEVICE;
|
mode = DWC3_GCTL_PRTCAP_DEVICE;
|
||||||
|
|
||||||
if (!strncmp(buf, "otg", 3))
|
if (!strncmp(buf, "otg", 3))
|
||||||
mode |= DWC3_GCTL_PRTCAP_OTG;
|
mode = DWC3_GCTL_PRTCAP_OTG;
|
||||||
|
|
||||||
|
dwc3_set_mode(dwc, mode);
|
||||||
|
|
||||||
if (mode) {
|
|
||||||
spin_lock_irqsave(&dwc->lock, flags);
|
|
||||||
dwc3_set_mode(dwc, mode);
|
|
||||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
|
||||||
}
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -446,52 +442,7 @@ static int dwc3_link_state_show(struct seq_file *s, void *unused)
|
|||||||
state = DWC3_DSTS_USBLNKST(reg);
|
state = DWC3_DSTS_USBLNKST(reg);
|
||||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||||
|
|
||||||
switch (state) {
|
seq_printf(s, "%s\n", dwc3_gadget_link_string(state));
|
||||||
case DWC3_LINK_STATE_U0:
|
|
||||||
seq_printf(s, "U0\n");
|
|
||||||
break;
|
|
||||||
case DWC3_LINK_STATE_U1:
|
|
||||||
seq_printf(s, "U1\n");
|
|
||||||
break;
|
|
||||||
case DWC3_LINK_STATE_U2:
|
|
||||||
seq_printf(s, "U2\n");
|
|
||||||
break;
|
|
||||||
case DWC3_LINK_STATE_U3:
|
|
||||||
seq_printf(s, "U3\n");
|
|
||||||
break;
|
|
||||||
case DWC3_LINK_STATE_SS_DIS:
|
|
||||||
seq_printf(s, "SS.Disabled\n");
|
|
||||||
break;
|
|
||||||
case DWC3_LINK_STATE_RX_DET:
|
|
||||||
seq_printf(s, "Rx.Detect\n");
|
|
||||||
break;
|
|
||||||
case DWC3_LINK_STATE_SS_INACT:
|
|
||||||
seq_printf(s, "SS.Inactive\n");
|
|
||||||
break;
|
|
||||||
case DWC3_LINK_STATE_POLL:
|
|
||||||
seq_printf(s, "Poll\n");
|
|
||||||
break;
|
|
||||||
case DWC3_LINK_STATE_RECOV:
|
|
||||||
seq_printf(s, "Recovery\n");
|
|
||||||
break;
|
|
||||||
case DWC3_LINK_STATE_HRESET:
|
|
||||||
seq_printf(s, "HRESET\n");
|
|
||||||
break;
|
|
||||||
case DWC3_LINK_STATE_CMPLY:
|
|
||||||
seq_printf(s, "Compliance\n");
|
|
||||||
break;
|
|
||||||
case DWC3_LINK_STATE_LPBK:
|
|
||||||
seq_printf(s, "Loopback\n");
|
|
||||||
break;
|
|
||||||
case DWC3_LINK_STATE_RESET:
|
|
||||||
seq_printf(s, "Reset\n");
|
|
||||||
break;
|
|
||||||
case DWC3_LINK_STATE_RESUME:
|
|
||||||
seq_printf(s, "Resume\n");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
seq_printf(s, "UNKNOWN %d\n", state);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -689,30 +640,6 @@ out:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline const char *dwc3_trb_type_string(struct dwc3_trb *trb)
|
|
||||||
{
|
|
||||||
switch (DWC3_TRBCTL_TYPE(trb->ctrl)) {
|
|
||||||
case DWC3_TRBCTL_NORMAL:
|
|
||||||
return "normal";
|
|
||||||
case DWC3_TRBCTL_CONTROL_SETUP:
|
|
||||||
return "control-setup";
|
|
||||||
case DWC3_TRBCTL_CONTROL_STATUS2:
|
|
||||||
return "control-status2";
|
|
||||||
case DWC3_TRBCTL_CONTROL_STATUS3:
|
|
||||||
return "control-status3";
|
|
||||||
case DWC3_TRBCTL_CONTROL_DATA:
|
|
||||||
return "control-data";
|
|
||||||
case DWC3_TRBCTL_ISOCHRONOUS_FIRST:
|
|
||||||
return "isoc-first";
|
|
||||||
case DWC3_TRBCTL_ISOCHRONOUS:
|
|
||||||
return "isoc";
|
|
||||||
case DWC3_TRBCTL_LINK_TRB:
|
|
||||||
return "link";
|
|
||||||
default:
|
|
||||||
return "UNKNOWN";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dwc3_ep_trb_ring_show(struct seq_file *s, void *unused)
|
static int dwc3_ep_trb_ring_show(struct seq_file *s, void *unused)
|
||||||
{
|
{
|
||||||
struct dwc3_ep *dep = s->private;
|
struct dwc3_ep *dep = s->private;
|
||||||
@ -733,10 +660,11 @@ static int dwc3_ep_trb_ring_show(struct seq_file *s, void *unused)
|
|||||||
|
|
||||||
for (i = 0; i < DWC3_TRB_NUM; i++) {
|
for (i = 0; i < DWC3_TRB_NUM; i++) {
|
||||||
struct dwc3_trb *trb = &dep->trb_pool[i];
|
struct dwc3_trb *trb = &dep->trb_pool[i];
|
||||||
|
unsigned int type = DWC3_TRBCTL_TYPE(trb->ctrl);
|
||||||
|
|
||||||
seq_printf(s, "%08x%08x,%d,%s,%d,%d,%d,%d,%d,%d\n",
|
seq_printf(s, "%08x%08x,%d,%s,%d,%d,%d,%d,%d,%d\n",
|
||||||
trb->bph, trb->bpl, trb->size,
|
trb->bph, trb->bpl, trb->size,
|
||||||
dwc3_trb_type_string(trb),
|
dwc3_trb_type_string(type),
|
||||||
!!(trb->ctrl & DWC3_TRB_CTRL_IOC),
|
!!(trb->ctrl & DWC3_TRB_CTRL_IOC),
|
||||||
!!(trb->ctrl & DWC3_TRB_CTRL_ISP_IMI),
|
!!(trb->ctrl & DWC3_TRB_CTRL_ISP_IMI),
|
||||||
!!(trb->ctrl & DWC3_TRB_CTRL_CSP),
|
!!(trb->ctrl & DWC3_TRB_CTRL_CSP),
|
||||||
@ -822,19 +750,8 @@ static void dwc3_debugfs_create_endpoint_dirs(struct dwc3 *dwc,
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < dwc->num_in_eps; i++) {
|
for (i = 0; i < dwc->num_eps; i++) {
|
||||||
u8 epnum = (i << 1) | 1;
|
struct dwc3_ep *dep = dwc->eps[i];
|
||||||
struct dwc3_ep *dep = dwc->eps[epnum];
|
|
||||||
|
|
||||||
if (!dep)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
dwc3_debugfs_create_endpoint_dir(dep, parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < dwc->num_out_eps; i++) {
|
|
||||||
u8 epnum = (i << 1);
|
|
||||||
struct dwc3_ep *dep = dwc->eps[epnum];
|
|
||||||
|
|
||||||
if (!dep)
|
if (!dep)
|
||||||
continue;
|
continue;
|
||||||
|
85
drivers/usb/dwc3/drd.c
Normal file
85
drivers/usb/dwc3/drd.c
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
/**
|
||||||
|
* drd.c - DesignWare USB3 DRD Controller Dual-role support
|
||||||
|
*
|
||||||
|
* Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com
|
||||||
|
*
|
||||||
|
* Authors: Roger Quadros <rogerq@ti.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 of
|
||||||
|
* the License as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/extcon.h>
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
#include "core.h"
|
||||||
|
#include "gadget.h"
|
||||||
|
|
||||||
|
static void dwc3_drd_update(struct dwc3 *dwc)
|
||||||
|
{
|
||||||
|
int id;
|
||||||
|
|
||||||
|
id = extcon_get_state(dwc->edev, EXTCON_USB_HOST);
|
||||||
|
if (id < 0)
|
||||||
|
id = 0;
|
||||||
|
|
||||||
|
dwc3_set_mode(dwc, id ?
|
||||||
|
DWC3_GCTL_PRTCAP_HOST :
|
||||||
|
DWC3_GCTL_PRTCAP_DEVICE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dwc3_drd_notifier(struct notifier_block *nb,
|
||||||
|
unsigned long event, void *ptr)
|
||||||
|
{
|
||||||
|
struct dwc3 *dwc = container_of(nb, struct dwc3, edev_nb);
|
||||||
|
|
||||||
|
dwc3_set_mode(dwc, event ?
|
||||||
|
DWC3_GCTL_PRTCAP_HOST :
|
||||||
|
DWC3_GCTL_PRTCAP_DEVICE);
|
||||||
|
|
||||||
|
return NOTIFY_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dwc3_drd_init(struct dwc3 *dwc)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (dwc->dev->of_node) {
|
||||||
|
if (of_property_read_bool(dwc->dev->of_node, "extcon"))
|
||||||
|
dwc->edev = extcon_get_edev_by_phandle(dwc->dev, 0);
|
||||||
|
|
||||||
|
if (IS_ERR(dwc->edev))
|
||||||
|
return PTR_ERR(dwc->edev);
|
||||||
|
|
||||||
|
dwc->edev_nb.notifier_call = dwc3_drd_notifier;
|
||||||
|
ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST,
|
||||||
|
&dwc->edev_nb);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(dwc->dev, "couldn't register cable notifier\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dwc3_drd_update(dwc);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dwc3_drd_exit(struct dwc3 *dwc)
|
||||||
|
{
|
||||||
|
extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST,
|
||||||
|
&dwc->edev_nb);
|
||||||
|
|
||||||
|
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
|
||||||
|
flush_work(&dwc->drd_work);
|
||||||
|
dwc3_gadget_exit(dwc);
|
||||||
|
}
|
@ -147,53 +147,53 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
|
|||||||
exynos->vdd33 = devm_regulator_get(dev, "vdd33");
|
exynos->vdd33 = devm_regulator_get(dev, "vdd33");
|
||||||
if (IS_ERR(exynos->vdd33)) {
|
if (IS_ERR(exynos->vdd33)) {
|
||||||
ret = PTR_ERR(exynos->vdd33);
|
ret = PTR_ERR(exynos->vdd33);
|
||||||
goto err2;
|
goto vdd33_err;
|
||||||
}
|
}
|
||||||
ret = regulator_enable(exynos->vdd33);
|
ret = regulator_enable(exynos->vdd33);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "Failed to enable VDD33 supply\n");
|
dev_err(dev, "Failed to enable VDD33 supply\n");
|
||||||
goto err2;
|
goto vdd33_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
exynos->vdd10 = devm_regulator_get(dev, "vdd10");
|
exynos->vdd10 = devm_regulator_get(dev, "vdd10");
|
||||||
if (IS_ERR(exynos->vdd10)) {
|
if (IS_ERR(exynos->vdd10)) {
|
||||||
ret = PTR_ERR(exynos->vdd10);
|
ret = PTR_ERR(exynos->vdd10);
|
||||||
goto err3;
|
goto vdd10_err;
|
||||||
}
|
}
|
||||||
ret = regulator_enable(exynos->vdd10);
|
ret = regulator_enable(exynos->vdd10);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "Failed to enable VDD10 supply\n");
|
dev_err(dev, "Failed to enable VDD10 supply\n");
|
||||||
goto err3;
|
goto vdd10_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = dwc3_exynos_register_phys(exynos);
|
ret = dwc3_exynos_register_phys(exynos);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "couldn't register PHYs\n");
|
dev_err(dev, "couldn't register PHYs\n");
|
||||||
goto err4;
|
goto phys_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node) {
|
if (node) {
|
||||||
ret = of_platform_populate(node, NULL, NULL, dev);
|
ret = of_platform_populate(node, NULL, NULL, dev);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dev, "failed to add dwc3 core\n");
|
dev_err(dev, "failed to add dwc3 core\n");
|
||||||
goto err5;
|
goto populate_err;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
dev_err(dev, "no device node, failed to add dwc3 core\n");
|
dev_err(dev, "no device node, failed to add dwc3 core\n");
|
||||||
ret = -ENODEV;
|
ret = -ENODEV;
|
||||||
goto err5;
|
goto populate_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err5:
|
populate_err:
|
||||||
platform_device_unregister(exynos->usb2_phy);
|
platform_device_unregister(exynos->usb2_phy);
|
||||||
platform_device_unregister(exynos->usb3_phy);
|
platform_device_unregister(exynos->usb3_phy);
|
||||||
err4:
|
phys_err:
|
||||||
regulator_disable(exynos->vdd10);
|
regulator_disable(exynos->vdd10);
|
||||||
err3:
|
vdd10_err:
|
||||||
regulator_disable(exynos->vdd33);
|
regulator_disable(exynos->vdd33);
|
||||||
err2:
|
vdd33_err:
|
||||||
clk_disable_unprepare(exynos->axius_clk);
|
clk_disable_unprepare(exynos->axius_clk);
|
||||||
axius_clk_err:
|
axius_clk_err:
|
||||||
clk_disable_unprepare(exynos->susp_clk);
|
clk_disable_unprepare(exynos->susp_clk);
|
||||||
|
@ -79,40 +79,40 @@
|
|||||||
#define USBOTGSS_DEBUG_OFFSET 0x0600
|
#define USBOTGSS_DEBUG_OFFSET 0x0600
|
||||||
|
|
||||||
/* SYSCONFIG REGISTER */
|
/* SYSCONFIG REGISTER */
|
||||||
#define USBOTGSS_SYSCONFIG_DMADISABLE (1 << 16)
|
#define USBOTGSS_SYSCONFIG_DMADISABLE BIT(16)
|
||||||
|
|
||||||
/* IRQ_EOI REGISTER */
|
/* IRQ_EOI REGISTER */
|
||||||
#define USBOTGSS_IRQ_EOI_LINE_NUMBER (1 << 0)
|
#define USBOTGSS_IRQ_EOI_LINE_NUMBER BIT(0)
|
||||||
|
|
||||||
/* IRQS0 BITS */
|
/* IRQS0 BITS */
|
||||||
#define USBOTGSS_IRQO_COREIRQ_ST (1 << 0)
|
#define USBOTGSS_IRQO_COREIRQ_ST BIT(0)
|
||||||
|
|
||||||
/* IRQMISC BITS */
|
/* IRQMISC BITS */
|
||||||
#define USBOTGSS_IRQMISC_DMADISABLECLR (1 << 17)
|
#define USBOTGSS_IRQMISC_DMADISABLECLR BIT(17)
|
||||||
#define USBOTGSS_IRQMISC_OEVT (1 << 16)
|
#define USBOTGSS_IRQMISC_OEVT BIT(16)
|
||||||
#define USBOTGSS_IRQMISC_DRVVBUS_RISE (1 << 13)
|
#define USBOTGSS_IRQMISC_DRVVBUS_RISE BIT(13)
|
||||||
#define USBOTGSS_IRQMISC_CHRGVBUS_RISE (1 << 12)
|
#define USBOTGSS_IRQMISC_CHRGVBUS_RISE BIT(12)
|
||||||
#define USBOTGSS_IRQMISC_DISCHRGVBUS_RISE (1 << 11)
|
#define USBOTGSS_IRQMISC_DISCHRGVBUS_RISE BIT(11)
|
||||||
#define USBOTGSS_IRQMISC_IDPULLUP_RISE (1 << 8)
|
#define USBOTGSS_IRQMISC_IDPULLUP_RISE BIT(8)
|
||||||
#define USBOTGSS_IRQMISC_DRVVBUS_FALL (1 << 5)
|
#define USBOTGSS_IRQMISC_DRVVBUS_FALL BIT(5)
|
||||||
#define USBOTGSS_IRQMISC_CHRGVBUS_FALL (1 << 4)
|
#define USBOTGSS_IRQMISC_CHRGVBUS_FALL BIT(4)
|
||||||
#define USBOTGSS_IRQMISC_DISCHRGVBUS_FALL (1 << 3)
|
#define USBOTGSS_IRQMISC_DISCHRGVBUS_FALL BIT(3)
|
||||||
#define USBOTGSS_IRQMISC_IDPULLUP_FALL (1 << 0)
|
#define USBOTGSS_IRQMISC_IDPULLUP_FALL BIT(0)
|
||||||
|
|
||||||
/* UTMI_OTG_STATUS REGISTER */
|
/* UTMI_OTG_STATUS REGISTER */
|
||||||
#define USBOTGSS_UTMI_OTG_STATUS_DRVVBUS (1 << 5)
|
#define USBOTGSS_UTMI_OTG_STATUS_DRVVBUS BIT(5)
|
||||||
#define USBOTGSS_UTMI_OTG_STATUS_CHRGVBUS (1 << 4)
|
#define USBOTGSS_UTMI_OTG_STATUS_CHRGVBUS BIT(4)
|
||||||
#define USBOTGSS_UTMI_OTG_STATUS_DISCHRGVBUS (1 << 3)
|
#define USBOTGSS_UTMI_OTG_STATUS_DISCHRGVBUS BIT(3)
|
||||||
#define USBOTGSS_UTMI_OTG_STATUS_IDPULLUP (1 << 0)
|
#define USBOTGSS_UTMI_OTG_STATUS_IDPULLUP BIT(0)
|
||||||
|
|
||||||
/* UTMI_OTG_CTRL REGISTER */
|
/* UTMI_OTG_CTRL REGISTER */
|
||||||
#define USBOTGSS_UTMI_OTG_CTRL_SW_MODE (1 << 31)
|
#define USBOTGSS_UTMI_OTG_CTRL_SW_MODE BIT(31)
|
||||||
#define USBOTGSS_UTMI_OTG_CTRL_POWERPRESENT (1 << 9)
|
#define USBOTGSS_UTMI_OTG_CTRL_POWERPRESENT BIT(9)
|
||||||
#define USBOTGSS_UTMI_OTG_CTRL_TXBITSTUFFENABLE (1 << 8)
|
#define USBOTGSS_UTMI_OTG_CTRL_TXBITSTUFFENABLE BIT(8)
|
||||||
#define USBOTGSS_UTMI_OTG_CTRL_IDDIG (1 << 4)
|
#define USBOTGSS_UTMI_OTG_CTRL_IDDIG BIT(4)
|
||||||
#define USBOTGSS_UTMI_OTG_CTRL_SESSEND (1 << 3)
|
#define USBOTGSS_UTMI_OTG_CTRL_SESSEND BIT(3)
|
||||||
#define USBOTGSS_UTMI_OTG_CTRL_SESSVALID (1 << 2)
|
#define USBOTGSS_UTMI_OTG_CTRL_SESSVALID BIT(2)
|
||||||
#define USBOTGSS_UTMI_OTG_CTRL_VBUSVALID (1 << 1)
|
#define USBOTGSS_UTMI_OTG_CTRL_VBUSVALID BIT(1)
|
||||||
|
|
||||||
struct dwc3_omap {
|
struct dwc3_omap {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
@ -39,14 +39,13 @@ static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep);
|
|||||||
static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
||||||
struct dwc3_ep *dep, struct dwc3_request *req);
|
struct dwc3_ep *dep, struct dwc3_request *req);
|
||||||
|
|
||||||
static void dwc3_ep0_prepare_one_trb(struct dwc3 *dwc, u8 epnum,
|
static void dwc3_ep0_prepare_one_trb(struct dwc3_ep *dep,
|
||||||
dma_addr_t buf_dma, u32 len, u32 type, bool chain)
|
dma_addr_t buf_dma, u32 len, u32 type, bool chain)
|
||||||
{
|
{
|
||||||
struct dwc3_trb *trb;
|
struct dwc3_trb *trb;
|
||||||
struct dwc3_ep *dep;
|
struct dwc3 *dwc;
|
||||||
|
|
||||||
dep = dwc->eps[epnum];
|
|
||||||
|
|
||||||
|
dwc = dep->dwc;
|
||||||
trb = &dwc->ep0_trb[dep->trb_enqueue];
|
trb = &dwc->ep0_trb[dep->trb_enqueue];
|
||||||
|
|
||||||
if (chain)
|
if (chain)
|
||||||
@ -69,16 +68,17 @@ static void dwc3_ep0_prepare_one_trb(struct dwc3 *dwc, u8 epnum,
|
|||||||
trace_dwc3_prepare_trb(dep, trb);
|
trace_dwc3_prepare_trb(dep, trb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum)
|
static int dwc3_ep0_start_trans(struct dwc3_ep *dep)
|
||||||
{
|
{
|
||||||
struct dwc3_gadget_ep_cmd_params params;
|
struct dwc3_gadget_ep_cmd_params params;
|
||||||
struct dwc3_ep *dep;
|
struct dwc3 *dwc;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
dep = dwc->eps[epnum];
|
|
||||||
if (dep->flags & DWC3_EP_BUSY)
|
if (dep->flags & DWC3_EP_BUSY)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
dwc = dep->dwc;
|
||||||
|
|
||||||
memset(¶ms, 0, sizeof(params));
|
memset(¶ms, 0, sizeof(params));
|
||||||
params.param0 = upper_32_bits(dwc->ep0_trb_addr);
|
params.param0 = upper_32_bits(dwc->ep0_trb_addr);
|
||||||
params.param1 = lower_32_bits(dwc->ep0_trb_addr);
|
params.param1 = lower_32_bits(dwc->ep0_trb_addr);
|
||||||
@ -279,13 +279,15 @@ int dwc3_gadget_ep0_set_halt(struct usb_ep *ep, int value)
|
|||||||
|
|
||||||
void dwc3_ep0_out_start(struct dwc3 *dwc)
|
void dwc3_ep0_out_start(struct dwc3 *dwc)
|
||||||
{
|
{
|
||||||
|
struct dwc3_ep *dep;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
complete(&dwc->ep0_in_setup);
|
complete(&dwc->ep0_in_setup);
|
||||||
|
|
||||||
dwc3_ep0_prepare_one_trb(dwc, 0, dwc->ctrl_req_addr, 8,
|
dep = dwc->eps[0];
|
||||||
|
dwc3_ep0_prepare_one_trb(dep, dwc->ep0_trb_addr, 8,
|
||||||
DWC3_TRBCTL_CONTROL_SETUP, false);
|
DWC3_TRBCTL_CONTROL_SETUP, false);
|
||||||
ret = dwc3_ep0_start_trans(dwc, 0);
|
ret = dwc3_ep0_start_trans(dep);
|
||||||
WARN_ON(ret < 0);
|
WARN_ON(ret < 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -794,7 +796,7 @@ static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
|
|||||||
static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
|
static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
|
||||||
const struct dwc3_event_depevt *event)
|
const struct dwc3_event_depevt *event)
|
||||||
{
|
{
|
||||||
struct usb_ctrlrequest *ctrl = dwc->ctrl_req;
|
struct usb_ctrlrequest *ctrl = (void *) dwc->ep0_trb;
|
||||||
int ret = -EINVAL;
|
int ret = -EINVAL;
|
||||||
u32 len;
|
u32 len;
|
||||||
|
|
||||||
@ -834,7 +836,6 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
|
|||||||
struct usb_request *ur;
|
struct usb_request *ur;
|
||||||
struct dwc3_trb *trb;
|
struct dwc3_trb *trb;
|
||||||
struct dwc3_ep *ep0;
|
struct dwc3_ep *ep0;
|
||||||
unsigned transfer_size = 0;
|
|
||||||
unsigned maxp;
|
unsigned maxp;
|
||||||
unsigned remaining_ur_length;
|
unsigned remaining_ur_length;
|
||||||
void *buf;
|
void *buf;
|
||||||
@ -847,9 +848,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
|
|||||||
ep0 = dwc->eps[0];
|
ep0 = dwc->eps[0];
|
||||||
|
|
||||||
dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS;
|
dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS;
|
||||||
|
|
||||||
trb = dwc->ep0_trb;
|
trb = dwc->ep0_trb;
|
||||||
|
|
||||||
trace_dwc3_complete_trb(ep0, trb);
|
trace_dwc3_complete_trb(ep0, trb);
|
||||||
|
|
||||||
r = next_request(&ep0->pending_list);
|
r = next_request(&ep0->pending_list);
|
||||||
@ -870,58 +869,23 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
|
|||||||
remaining_ur_length = ur->length;
|
remaining_ur_length = ur->length;
|
||||||
|
|
||||||
length = trb->size & DWC3_TRB_SIZE_MASK;
|
length = trb->size & DWC3_TRB_SIZE_MASK;
|
||||||
|
|
||||||
maxp = ep0->endpoint.maxpacket;
|
maxp = ep0->endpoint.maxpacket;
|
||||||
|
transferred = ur->length - length;
|
||||||
if (dwc->ep0_bounced) {
|
|
||||||
/*
|
|
||||||
* Handle the first TRB before handling the bounce buffer if
|
|
||||||
* the request length is greater than the bounce buffer size
|
|
||||||
*/
|
|
||||||
if (ur->length > DWC3_EP0_BOUNCE_SIZE) {
|
|
||||||
transfer_size = ALIGN(ur->length - maxp, maxp);
|
|
||||||
transferred = transfer_size - length;
|
|
||||||
buf = (u8 *)buf + transferred;
|
|
||||||
ur->actual += transferred;
|
|
||||||
remaining_ur_length -= transferred;
|
|
||||||
|
|
||||||
trb++;
|
|
||||||
length = trb->size & DWC3_TRB_SIZE_MASK;
|
|
||||||
|
|
||||||
ep0->trb_enqueue = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
transfer_size = roundup((ur->length - transfer_size),
|
|
||||||
maxp);
|
|
||||||
|
|
||||||
transferred = min_t(u32, remaining_ur_length,
|
|
||||||
transfer_size - length);
|
|
||||||
memcpy(buf, dwc->ep0_bounce, transferred);
|
|
||||||
} else {
|
|
||||||
transferred = ur->length - length;
|
|
||||||
}
|
|
||||||
|
|
||||||
ur->actual += transferred;
|
ur->actual += transferred;
|
||||||
|
|
||||||
if ((epnum & 1) && ur->actual < ur->length) {
|
if ((IS_ALIGNED(ur->length, ep0->endpoint.maxpacket) &&
|
||||||
/* for some reason we did not get everything out */
|
ur->length && ur->zero) || dwc->ep0_bounced) {
|
||||||
|
trb++;
|
||||||
dwc3_ep0_stall_and_restart(dwc);
|
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
|
||||||
} else {
|
trace_dwc3_complete_trb(ep0, trb);
|
||||||
dwc3_gadget_giveback(ep0, r, 0);
|
ep0->trb_enqueue = 0;
|
||||||
|
dwc->ep0_bounced = false;
|
||||||
if (IS_ALIGNED(ur->length, ep0->endpoint.maxpacket) &&
|
|
||||||
ur->length && ur->zero) {
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
dwc->ep0_next_event = DWC3_EP0_COMPLETE;
|
|
||||||
|
|
||||||
dwc3_ep0_prepare_one_trb(dwc, epnum, dwc->ctrl_req_addr,
|
|
||||||
0, DWC3_TRBCTL_CONTROL_DATA, false);
|
|
||||||
ret = dwc3_ep0_start_trans(dwc, epnum);
|
|
||||||
WARN_ON(ret < 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((epnum & 1) && ur->actual < ur->length)
|
||||||
|
dwc3_ep0_stall_and_restart(dwc);
|
||||||
|
else
|
||||||
|
dwc3_gadget_giveback(ep0, r, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dwc3_ep0_complete_status(struct dwc3 *dwc,
|
static void dwc3_ep0_complete_status(struct dwc3 *dwc,
|
||||||
@ -997,14 +961,13 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
|||||||
req->direction = !!dep->number;
|
req->direction = !!dep->number;
|
||||||
|
|
||||||
if (req->request.length == 0) {
|
if (req->request.length == 0) {
|
||||||
dwc3_ep0_prepare_one_trb(dwc, dep->number,
|
dwc3_ep0_prepare_one_trb(dep, dwc->ep0_trb_addr, 0,
|
||||||
dwc->ctrl_req_addr, 0,
|
|
||||||
DWC3_TRBCTL_CONTROL_DATA, false);
|
DWC3_TRBCTL_CONTROL_DATA, false);
|
||||||
ret = dwc3_ep0_start_trans(dwc, dep->number);
|
ret = dwc3_ep0_start_trans(dep);
|
||||||
} else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket)
|
} else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket)
|
||||||
&& (dep->number == 0)) {
|
&& (dep->number == 0)) {
|
||||||
u32 transfer_size = 0;
|
|
||||||
u32 maxpacket;
|
u32 maxpacket;
|
||||||
|
u32 rem;
|
||||||
|
|
||||||
ret = usb_gadget_map_request_by_dev(dwc->sysdev,
|
ret = usb_gadget_map_request_by_dev(dwc->sysdev,
|
||||||
&req->request, dep->number);
|
&req->request, dep->number);
|
||||||
@ -1012,36 +975,55 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
maxpacket = dep->endpoint.maxpacket;
|
maxpacket = dep->endpoint.maxpacket;
|
||||||
|
rem = req->request.length % maxpacket;
|
||||||
if (req->request.length > DWC3_EP0_BOUNCE_SIZE) {
|
|
||||||
transfer_size = ALIGN(req->request.length - maxpacket,
|
|
||||||
maxpacket);
|
|
||||||
dwc3_ep0_prepare_one_trb(dwc, dep->number,
|
|
||||||
req->request.dma,
|
|
||||||
transfer_size,
|
|
||||||
DWC3_TRBCTL_CONTROL_DATA,
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
|
|
||||||
transfer_size = roundup((req->request.length - transfer_size),
|
|
||||||
maxpacket);
|
|
||||||
|
|
||||||
dwc->ep0_bounced = true;
|
dwc->ep0_bounced = true;
|
||||||
|
|
||||||
dwc3_ep0_prepare_one_trb(dwc, dep->number,
|
/* prepare normal TRB */
|
||||||
dwc->ep0_bounce_addr, transfer_size,
|
dwc3_ep0_prepare_one_trb(dep, req->request.dma,
|
||||||
DWC3_TRBCTL_CONTROL_DATA, false);
|
req->request.length,
|
||||||
ret = dwc3_ep0_start_trans(dwc, dep->number);
|
DWC3_TRBCTL_CONTROL_DATA,
|
||||||
|
true);
|
||||||
|
|
||||||
|
/* Now prepare one extra TRB to align transfer size */
|
||||||
|
dwc3_ep0_prepare_one_trb(dep, dwc->bounce_addr,
|
||||||
|
maxpacket - rem,
|
||||||
|
DWC3_TRBCTL_CONTROL_DATA,
|
||||||
|
false);
|
||||||
|
ret = dwc3_ep0_start_trans(dep);
|
||||||
|
} else if (IS_ALIGNED(req->request.length, dep->endpoint.maxpacket) &&
|
||||||
|
req->request.length && req->request.zero) {
|
||||||
|
u32 maxpacket;
|
||||||
|
u32 rem;
|
||||||
|
|
||||||
|
ret = usb_gadget_map_request_by_dev(dwc->sysdev,
|
||||||
|
&req->request, dep->number);
|
||||||
|
if (ret)
|
||||||
|
return;
|
||||||
|
|
||||||
|
maxpacket = dep->endpoint.maxpacket;
|
||||||
|
rem = req->request.length % maxpacket;
|
||||||
|
|
||||||
|
/* prepare normal TRB */
|
||||||
|
dwc3_ep0_prepare_one_trb(dep, req->request.dma,
|
||||||
|
req->request.length,
|
||||||
|
DWC3_TRBCTL_CONTROL_DATA,
|
||||||
|
true);
|
||||||
|
|
||||||
|
/* Now prepare one extra TRB to align transfer size */
|
||||||
|
dwc3_ep0_prepare_one_trb(dep, dwc->bounce_addr,
|
||||||
|
0, DWC3_TRBCTL_CONTROL_DATA,
|
||||||
|
false);
|
||||||
|
ret = dwc3_ep0_start_trans(dep);
|
||||||
} else {
|
} else {
|
||||||
ret = usb_gadget_map_request_by_dev(dwc->sysdev,
|
ret = usb_gadget_map_request_by_dev(dwc->sysdev,
|
||||||
&req->request, dep->number);
|
&req->request, dep->number);
|
||||||
if (ret)
|
if (ret)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
dwc3_ep0_prepare_one_trb(dwc, dep->number, req->request.dma,
|
dwc3_ep0_prepare_one_trb(dep, req->request.dma,
|
||||||
req->request.length, DWC3_TRBCTL_CONTROL_DATA,
|
req->request.length, DWC3_TRBCTL_CONTROL_DATA,
|
||||||
false);
|
false);
|
||||||
ret = dwc3_ep0_start_trans(dwc, dep->number);
|
ret = dwc3_ep0_start_trans(dep);
|
||||||
}
|
}
|
||||||
|
|
||||||
WARN_ON(ret < 0);
|
WARN_ON(ret < 0);
|
||||||
@ -1055,9 +1037,8 @@ static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)
|
|||||||
type = dwc->three_stage_setup ? DWC3_TRBCTL_CONTROL_STATUS3
|
type = dwc->three_stage_setup ? DWC3_TRBCTL_CONTROL_STATUS3
|
||||||
: DWC3_TRBCTL_CONTROL_STATUS2;
|
: DWC3_TRBCTL_CONTROL_STATUS2;
|
||||||
|
|
||||||
dwc3_ep0_prepare_one_trb(dwc, dep->number,
|
dwc3_ep0_prepare_one_trb(dep, dwc->ep0_trb_addr, 0, type, false);
|
||||||
dwc->ctrl_req_addr, 0, type, false);
|
return dwc3_ep0_start_trans(dep);
|
||||||
return dwc3_ep0_start_trans(dwc, dep->number);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep)
|
static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep)
|
||||||
|
@ -171,7 +171,6 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
|
|||||||
int status)
|
int status)
|
||||||
{
|
{
|
||||||
struct dwc3 *dwc = dep->dwc;
|
struct dwc3 *dwc = dep->dwc;
|
||||||
unsigned int unmap_after_complete = false;
|
|
||||||
|
|
||||||
req->started = false;
|
req->started = false;
|
||||||
list_del(&req->list);
|
list_del(&req->list);
|
||||||
@ -181,19 +180,8 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
|
|||||||
if (req->request.status == -EINPROGRESS)
|
if (req->request.status == -EINPROGRESS)
|
||||||
req->request.status = status;
|
req->request.status = status;
|
||||||
|
|
||||||
/*
|
usb_gadget_unmap_request_by_dev(dwc->sysdev,
|
||||||
* NOTICE we don't want to unmap before calling ->complete() if we're
|
&req->request, req->direction);
|
||||||
* dealing with a bounced ep0 request. If we unmap it here, we would end
|
|
||||||
* up overwritting the contents of req->buf and this could confuse the
|
|
||||||
* gadget driver.
|
|
||||||
*/
|
|
||||||
if (dwc->ep0_bounced && dep->number <= 1) {
|
|
||||||
dwc->ep0_bounced = false;
|
|
||||||
unmap_after_complete = true;
|
|
||||||
} else {
|
|
||||||
usb_gadget_unmap_request_by_dev(dwc->sysdev,
|
|
||||||
&req->request, req->direction);
|
|
||||||
}
|
|
||||||
|
|
||||||
trace_dwc3_gadget_giveback(req);
|
trace_dwc3_gadget_giveback(req);
|
||||||
|
|
||||||
@ -201,10 +189,6 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
|
|||||||
usb_gadget_giveback_request(&dep->endpoint, &req->request);
|
usb_gadget_giveback_request(&dep->endpoint, &req->request);
|
||||||
spin_lock(&dwc->lock);
|
spin_lock(&dwc->lock);
|
||||||
|
|
||||||
if (unmap_after_complete)
|
|
||||||
usb_gadget_unmap_request_by_dev(dwc->sysdev,
|
|
||||||
&req->request, req->direction);
|
|
||||||
|
|
||||||
if (dep->number > 1)
|
if (dep->number > 1)
|
||||||
pm_runtime_put(dwc->dev);
|
pm_runtime_put(dwc->dev);
|
||||||
}
|
}
|
||||||
@ -1060,6 +1044,22 @@ static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep,
|
|||||||
false, 0, req->request.stream_id,
|
false, 0, req->request.stream_id,
|
||||||
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 &&
|
||||||
|
(IS_ALIGNED(req->request.length,dep->endpoint.maxpacket))) {
|
||||||
|
struct dwc3 *dwc = dep->dwc;
|
||||||
|
struct dwc3_trb *trb;
|
||||||
|
|
||||||
|
req->zero = true;
|
||||||
|
|
||||||
|
/* prepare normal TRB */
|
||||||
|
dwc3_prepare_one_trb(dep, req, true, 0);
|
||||||
|
|
||||||
|
/* Now prepare one extra TRB to handle ZLP */
|
||||||
|
trb = &dep->trb_pool[dep->trb_enqueue];
|
||||||
|
__dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, 0,
|
||||||
|
false, 0, req->request.stream_id,
|
||||||
|
req->request.short_not_ok,
|
||||||
|
req->request.no_interrupt);
|
||||||
} else {
|
} else {
|
||||||
dwc3_prepare_one_trb(dep, req, false, 0);
|
dwc3_prepare_one_trb(dep, req, false, 0);
|
||||||
}
|
}
|
||||||
@ -1184,8 +1184,11 @@ static void __dwc3_gadget_start_isoc(struct dwc3 *dwc,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 4 micro frames in the future */
|
/*
|
||||||
uf = cur_uf + dep->interval * 4;
|
* Schedule the first trb for one interval in the future or at
|
||||||
|
* least 4 microframes.
|
||||||
|
*/
|
||||||
|
uf = cur_uf + max_t(u32, 4, dep->interval);
|
||||||
|
|
||||||
__dwc3_gadget_kick_transfer(dep, uf);
|
__dwc3_gadget_kick_transfer(dep, uf);
|
||||||
}
|
}
|
||||||
@ -1272,31 +1275,6 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __dwc3_gadget_ep_zlp_complete(struct usb_ep *ep,
|
|
||||||
struct usb_request *request)
|
|
||||||
{
|
|
||||||
dwc3_gadget_ep_free_request(ep, request);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __dwc3_gadget_ep_queue_zlp(struct dwc3 *dwc, struct dwc3_ep *dep)
|
|
||||||
{
|
|
||||||
struct dwc3_request *req;
|
|
||||||
struct usb_request *request;
|
|
||||||
struct usb_ep *ep = &dep->endpoint;
|
|
||||||
|
|
||||||
request = dwc3_gadget_ep_alloc_request(ep, GFP_ATOMIC);
|
|
||||||
if (!request)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
request->length = 0;
|
|
||||||
request->buf = dwc->zlp_buf;
|
|
||||||
request->complete = __dwc3_gadget_ep_zlp_complete;
|
|
||||||
|
|
||||||
req = to_dwc3_request(request);
|
|
||||||
|
|
||||||
return __dwc3_gadget_ep_queue(dep, req);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
|
static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
|
||||||
gfp_t gfp_flags)
|
gfp_t gfp_flags)
|
||||||
{
|
{
|
||||||
@ -1310,17 +1288,6 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
|
|||||||
|
|
||||||
spin_lock_irqsave(&dwc->lock, flags);
|
spin_lock_irqsave(&dwc->lock, flags);
|
||||||
ret = __dwc3_gadget_ep_queue(dep, req);
|
ret = __dwc3_gadget_ep_queue(dep, req);
|
||||||
|
|
||||||
/*
|
|
||||||
* Okay, here's the thing, if gadget driver has requested for a ZLP by
|
|
||||||
* setting request->zero, instead of doing magic, we will just queue an
|
|
||||||
* extra usb_request ourselves so that it gets handled the same way as
|
|
||||||
* any other request.
|
|
||||||
*/
|
|
||||||
if (ret == 0 && request->zero && request->length &&
|
|
||||||
(request->length % ep->maxpacket == 0))
|
|
||||||
ret = __dwc3_gadget_ep_queue_zlp(dwc, dep);
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -1400,7 +1367,7 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
|
|||||||
dwc3_ep_inc_deq(dep);
|
dwc3_ep_inc_deq(dep);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r->unaligned) {
|
if (r->unaligned || r->zero) {
|
||||||
trb = r->trb + r->num_pending_sgs + 1;
|
trb = r->trb + r->num_pending_sgs + 1;
|
||||||
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
|
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
|
||||||
dwc3_ep_inc_deq(dep);
|
dwc3_ep_inc_deq(dep);
|
||||||
@ -1411,7 +1378,7 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
|
|||||||
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
|
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
|
||||||
dwc3_ep_inc_deq(dep);
|
dwc3_ep_inc_deq(dep);
|
||||||
|
|
||||||
if (r->unaligned) {
|
if (r->unaligned || r->zero) {
|
||||||
trb = r->trb + 1;
|
trb = r->trb + 1;
|
||||||
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
|
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
|
||||||
dwc3_ep_inc_deq(dep);
|
dwc3_ep_inc_deq(dep);
|
||||||
@ -2006,14 +1973,15 @@ static const struct usb_gadget_ops dwc3_gadget_ops = {
|
|||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
|
static int dwc3_gadget_init_endpoints(struct dwc3 *dwc, u8 num)
|
||||||
u8 num, u32 direction)
|
|
||||||
{
|
{
|
||||||
struct dwc3_ep *dep;
|
struct dwc3_ep *dep;
|
||||||
u8 i;
|
u8 epnum;
|
||||||
|
|
||||||
for (i = 0; i < num; i++) {
|
INIT_LIST_HEAD(&dwc->gadget.ep_list);
|
||||||
u8 epnum = (i << 1) | (direction ? 1 : 0);
|
|
||||||
|
for (epnum = 0; epnum < num; epnum++) {
|
||||||
|
bool direction = epnum & 1;
|
||||||
|
|
||||||
dep = kzalloc(sizeof(*dep), GFP_KERNEL);
|
dep = kzalloc(sizeof(*dep), GFP_KERNEL);
|
||||||
if (!dep)
|
if (!dep)
|
||||||
@ -2021,12 +1989,12 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
|
|||||||
|
|
||||||
dep->dwc = dwc;
|
dep->dwc = dwc;
|
||||||
dep->number = epnum;
|
dep->number = epnum;
|
||||||
dep->direction = !!direction;
|
dep->direction = direction;
|
||||||
dep->regs = dwc->regs + DWC3_DEP_BASE(epnum);
|
dep->regs = dwc->regs + DWC3_DEP_BASE(epnum);
|
||||||
dwc->eps[epnum] = dep;
|
dwc->eps[epnum] = dep;
|
||||||
|
|
||||||
snprintf(dep->name, sizeof(dep->name), "ep%d%s", epnum >> 1,
|
snprintf(dep->name, sizeof(dep->name), "ep%d%s", epnum >> 1,
|
||||||
(epnum & 1) ? "in" : "out");
|
direction ? "in" : "out");
|
||||||
|
|
||||||
dep->endpoint.name = dep->name;
|
dep->endpoint.name = dep->name;
|
||||||
|
|
||||||
@ -2053,7 +2021,7 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
|
|||||||
/* MDWIDTH is represented in bits, we need it in bytes */
|
/* MDWIDTH is represented in bits, we need it in bytes */
|
||||||
mdwidth /= 8;
|
mdwidth /= 8;
|
||||||
|
|
||||||
size = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(i));
|
size = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(epnum >> 1));
|
||||||
size = DWC3_GTXFIFOSIZ_TXFDEF(size);
|
size = DWC3_GTXFIFOSIZ_TXFDEF(size);
|
||||||
|
|
||||||
/* FIFO Depth is in MDWDITH bytes. Multiply */
|
/* FIFO Depth is in MDWDITH bytes. Multiply */
|
||||||
@ -2103,7 +2071,7 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
|
|||||||
dep->endpoint.caps.type_int = true;
|
dep->endpoint.caps.type_int = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
dep->endpoint.caps.dir_in = !!direction;
|
dep->endpoint.caps.dir_in = direction;
|
||||||
dep->endpoint.caps.dir_out = !direction;
|
dep->endpoint.caps.dir_out = !direction;
|
||||||
|
|
||||||
INIT_LIST_HEAD(&dep->pending_list);
|
INIT_LIST_HEAD(&dep->pending_list);
|
||||||
@ -2113,27 +2081,6 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dwc3_gadget_init_endpoints(struct dwc3 *dwc)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
INIT_LIST_HEAD(&dwc->gadget.ep_list);
|
|
||||||
|
|
||||||
ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_out_eps, 0);
|
|
||||||
if (ret < 0) {
|
|
||||||
dev_err(dwc->dev, "failed to initialize OUT endpoints\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_in_eps, 1);
|
|
||||||
if (ret < 0) {
|
|
||||||
dev_err(dwc->dev, "failed to initialize IN endpoints\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
|
static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
|
||||||
{
|
{
|
||||||
struct dwc3_ep *dep;
|
struct dwc3_ep *dep;
|
||||||
@ -2197,7 +2144,7 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep,
|
|||||||
* with one TRB pending in the ring. We need to manually clear HWO bit
|
* with one TRB pending in the ring. We need to manually clear HWO bit
|
||||||
* from that TRB.
|
* from that TRB.
|
||||||
*/
|
*/
|
||||||
if (req->unaligned && (trb->ctrl & DWC3_TRB_CTRL_HWO)) {
|
if ((req->zero || req->unaligned) && (trb->ctrl & DWC3_TRB_CTRL_HWO)) {
|
||||||
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
|
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -2291,11 +2238,12 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
|
|||||||
event, status, chain);
|
event, status, chain);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req->unaligned) {
|
if (req->unaligned || req->zero) {
|
||||||
trb = &dep->trb_pool[dep->trb_dequeue];
|
trb = &dep->trb_pool[dep->trb_dequeue];
|
||||||
ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb,
|
ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb,
|
||||||
event, status, false);
|
event, status, false);
|
||||||
req->unaligned = false;
|
req->unaligned = false;
|
||||||
|
req->zero = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
req->request.actual = length - req->remaining;
|
req->request.actual = length - req->remaining;
|
||||||
@ -3161,49 +3109,26 @@ int dwc3_gadget_init(struct dwc3 *dwc)
|
|||||||
|
|
||||||
dwc->irq_gadget = irq;
|
dwc->irq_gadget = irq;
|
||||||
|
|
||||||
dwc->ctrl_req = dma_alloc_coherent(dwc->sysdev, sizeof(*dwc->ctrl_req),
|
|
||||||
&dwc->ctrl_req_addr, GFP_KERNEL);
|
|
||||||
if (!dwc->ctrl_req) {
|
|
||||||
dev_err(dwc->dev, "failed to allocate ctrl request\n");
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto err0;
|
|
||||||
}
|
|
||||||
|
|
||||||
dwc->ep0_trb = dma_alloc_coherent(dwc->sysdev,
|
dwc->ep0_trb = dma_alloc_coherent(dwc->sysdev,
|
||||||
sizeof(*dwc->ep0_trb) * 2,
|
sizeof(*dwc->ep0_trb) * 2,
|
||||||
&dwc->ep0_trb_addr, GFP_KERNEL);
|
&dwc->ep0_trb_addr, GFP_KERNEL);
|
||||||
if (!dwc->ep0_trb) {
|
if (!dwc->ep0_trb) {
|
||||||
dev_err(dwc->dev, "failed to allocate ep0 trb\n");
|
dev_err(dwc->dev, "failed to allocate ep0 trb\n");
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto err1;
|
goto err0;
|
||||||
}
|
}
|
||||||
|
|
||||||
dwc->setup_buf = kzalloc(DWC3_EP0_BOUNCE_SIZE, GFP_KERNEL);
|
dwc->setup_buf = kzalloc(DWC3_EP0_SETUP_SIZE, GFP_KERNEL);
|
||||||
if (!dwc->setup_buf) {
|
if (!dwc->setup_buf) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto err2;
|
goto err1;
|
||||||
}
|
|
||||||
|
|
||||||
dwc->ep0_bounce = dma_alloc_coherent(dwc->sysdev,
|
|
||||||
DWC3_EP0_BOUNCE_SIZE, &dwc->ep0_bounce_addr,
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (!dwc->ep0_bounce) {
|
|
||||||
dev_err(dwc->dev, "failed to allocate ep0 bounce buffer\n");
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto err3;
|
|
||||||
}
|
|
||||||
|
|
||||||
dwc->zlp_buf = kzalloc(DWC3_ZLP_BUF_SIZE, GFP_KERNEL);
|
|
||||||
if (!dwc->zlp_buf) {
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto err4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dwc->bounce = dma_alloc_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE,
|
dwc->bounce = dma_alloc_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE,
|
||||||
&dwc->bounce_addr, GFP_KERNEL);
|
&dwc->bounce_addr, GFP_KERNEL);
|
||||||
if (!dwc->bounce) {
|
if (!dwc->bounce) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto err5;
|
goto err2;
|
||||||
}
|
}
|
||||||
|
|
||||||
init_completion(&dwc->ep0_in_setup);
|
init_completion(&dwc->ep0_in_setup);
|
||||||
@ -3241,39 +3166,31 @@ int dwc3_gadget_init(struct dwc3 *dwc)
|
|||||||
* sure we're starting from a well known location.
|
* sure we're starting from a well known location.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ret = dwc3_gadget_init_endpoints(dwc);
|
ret = dwc3_gadget_init_endpoints(dwc, dwc->num_eps);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err6;
|
goto err3;
|
||||||
|
|
||||||
ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget);
|
ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
dev_err(dwc->dev, "failed to register udc\n");
|
dev_err(dwc->dev, "failed to register udc\n");
|
||||||
goto err6;
|
goto err4;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
err6:
|
|
||||||
dma_free_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce,
|
|
||||||
dwc->bounce_addr);
|
|
||||||
|
|
||||||
err5:
|
|
||||||
kfree(dwc->zlp_buf);
|
|
||||||
|
|
||||||
err4:
|
err4:
|
||||||
dwc3_gadget_free_endpoints(dwc);
|
dwc3_gadget_free_endpoints(dwc);
|
||||||
dma_free_coherent(dwc->sysdev, DWC3_EP0_BOUNCE_SIZE,
|
|
||||||
dwc->ep0_bounce, dwc->ep0_bounce_addr);
|
|
||||||
|
|
||||||
err3:
|
err3:
|
||||||
kfree(dwc->setup_buf);
|
dma_free_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce,
|
||||||
|
dwc->bounce_addr);
|
||||||
|
|
||||||
err2:
|
err2:
|
||||||
dma_free_coherent(dwc->sysdev, sizeof(*dwc->ep0_trb) * 2,
|
kfree(dwc->setup_buf);
|
||||||
dwc->ep0_trb, dwc->ep0_trb_addr);
|
|
||||||
|
|
||||||
err1:
|
err1:
|
||||||
dma_free_coherent(dwc->sysdev, sizeof(*dwc->ctrl_req),
|
dma_free_coherent(dwc->sysdev, sizeof(*dwc->ep0_trb) * 2,
|
||||||
dwc->ctrl_req, dwc->ctrl_req_addr);
|
dwc->ep0_trb, dwc->ep0_trb_addr);
|
||||||
|
|
||||||
err0:
|
err0:
|
||||||
return ret;
|
return ret;
|
||||||
@ -3284,22 +3201,12 @@ err0:
|
|||||||
void dwc3_gadget_exit(struct dwc3 *dwc)
|
void dwc3_gadget_exit(struct dwc3 *dwc)
|
||||||
{
|
{
|
||||||
usb_del_gadget_udc(&dwc->gadget);
|
usb_del_gadget_udc(&dwc->gadget);
|
||||||
|
|
||||||
dwc3_gadget_free_endpoints(dwc);
|
dwc3_gadget_free_endpoints(dwc);
|
||||||
|
|
||||||
dma_free_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce,
|
dma_free_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce,
|
||||||
dwc->bounce_addr);
|
dwc->bounce_addr);
|
||||||
dma_free_coherent(dwc->sysdev, DWC3_EP0_BOUNCE_SIZE,
|
|
||||||
dwc->ep0_bounce, dwc->ep0_bounce_addr);
|
|
||||||
|
|
||||||
kfree(dwc->setup_buf);
|
kfree(dwc->setup_buf);
|
||||||
kfree(dwc->zlp_buf);
|
|
||||||
|
|
||||||
dma_free_coherent(dwc->sysdev, sizeof(*dwc->ep0_trb) * 2,
|
dma_free_coherent(dwc->sysdev, sizeof(*dwc->ep0_trb) * 2,
|
||||||
dwc->ep0_trb, dwc->ep0_trb_addr);
|
dwc->ep0_trb, dwc->ep0_trb_addr);
|
||||||
|
|
||||||
dma_free_coherent(dwc->sysdev, sizeof(*dwc->ctrl_req),
|
|
||||||
dwc->ctrl_req, dwc->ctrl_req_addr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int dwc3_gadget_suspend(struct dwc3 *dwc)
|
int dwc3_gadget_suspend(struct dwc3 *dwc)
|
||||||
|
@ -29,16 +29,16 @@ struct dwc3;
|
|||||||
|
|
||||||
/* DEPCFG parameter 1 */
|
/* DEPCFG parameter 1 */
|
||||||
#define DWC3_DEPCFG_INT_NUM(n) (((n) & 0x1f) << 0)
|
#define DWC3_DEPCFG_INT_NUM(n) (((n) & 0x1f) << 0)
|
||||||
#define DWC3_DEPCFG_XFER_COMPLETE_EN (1 << 8)
|
#define DWC3_DEPCFG_XFER_COMPLETE_EN BIT(8)
|
||||||
#define DWC3_DEPCFG_XFER_IN_PROGRESS_EN (1 << 9)
|
#define DWC3_DEPCFG_XFER_IN_PROGRESS_EN BIT(9)
|
||||||
#define DWC3_DEPCFG_XFER_NOT_READY_EN (1 << 10)
|
#define DWC3_DEPCFG_XFER_NOT_READY_EN BIT(10)
|
||||||
#define DWC3_DEPCFG_FIFO_ERROR_EN (1 << 11)
|
#define DWC3_DEPCFG_FIFO_ERROR_EN BIT(11)
|
||||||
#define DWC3_DEPCFG_STREAM_EVENT_EN (1 << 13)
|
#define DWC3_DEPCFG_STREAM_EVENT_EN BIT(12)
|
||||||
#define DWC3_DEPCFG_BINTERVAL_M1(n) (((n) & 0xff) << 16)
|
#define DWC3_DEPCFG_BINTERVAL_M1(n) (((n) & 0xff) << 16)
|
||||||
#define DWC3_DEPCFG_STREAM_CAPABLE (1 << 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)
|
||||||
#define DWC3_DEPCFG_BULK_BASED (1 << 30)
|
#define DWC3_DEPCFG_BULK_BASED BIT(30)
|
||||||
#define DWC3_DEPCFG_FIFO_BASED (1 << 31)
|
#define DWC3_DEPCFG_FIFO_BASED BIT(31)
|
||||||
|
|
||||||
/* DEPCFG parameter 0 */
|
/* DEPCFG parameter 0 */
|
||||||
#define DWC3_DEPCFG_EP_TYPE(n) (((n) & 0x3) << 1)
|
#define DWC3_DEPCFG_EP_TYPE(n) (((n) & 0x3) << 1)
|
||||||
@ -47,10 +47,10 @@ struct dwc3;
|
|||||||
#define DWC3_DEPCFG_BURST_SIZE(n) (((n) & 0xf) << 22)
|
#define DWC3_DEPCFG_BURST_SIZE(n) (((n) & 0xf) << 22)
|
||||||
#define DWC3_DEPCFG_DATA_SEQ_NUM(n) ((n) << 26)
|
#define DWC3_DEPCFG_DATA_SEQ_NUM(n) ((n) << 26)
|
||||||
/* This applies for core versions earlier than 1.94a */
|
/* This applies for core versions earlier than 1.94a */
|
||||||
#define DWC3_DEPCFG_IGN_SEQ_NUM (1 << 31)
|
#define DWC3_DEPCFG_IGN_SEQ_NUM BIT(31)
|
||||||
/* These apply for core versions 1.94a and later */
|
/* These apply for core versions 1.94a and later */
|
||||||
#define DWC3_DEPCFG_ACTION_INIT (0 << 30)
|
#define DWC3_DEPCFG_ACTION_INIT (0 << 30)
|
||||||
#define DWC3_DEPCFG_ACTION_RESTORE (1 << 30)
|
#define DWC3_DEPCFG_ACTION_RESTORE BIT(30)
|
||||||
#define DWC3_DEPCFG_ACTION_MODIFY (2 << 30)
|
#define DWC3_DEPCFG_ACTION_MODIFY (2 << 30)
|
||||||
|
|
||||||
/* DEPXFERCFG parameter 0 */
|
/* DEPXFERCFG parameter 0 */
|
||||||
|
@ -27,31 +27,6 @@
|
|||||||
#include "core.h"
|
#include "core.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
DECLARE_EVENT_CLASS(dwc3_log_msg,
|
|
||||||
TP_PROTO(struct va_format *vaf),
|
|
||||||
TP_ARGS(vaf),
|
|
||||||
TP_STRUCT__entry(__dynamic_array(char, msg, DWC3_MSG_MAX)),
|
|
||||||
TP_fast_assign(
|
|
||||||
vsnprintf(__get_str(msg), DWC3_MSG_MAX, vaf->fmt, *vaf->va);
|
|
||||||
),
|
|
||||||
TP_printk("%s", __get_str(msg))
|
|
||||||
);
|
|
||||||
|
|
||||||
DEFINE_EVENT(dwc3_log_msg, dwc3_gadget,
|
|
||||||
TP_PROTO(struct va_format *vaf),
|
|
||||||
TP_ARGS(vaf)
|
|
||||||
);
|
|
||||||
|
|
||||||
DEFINE_EVENT(dwc3_log_msg, dwc3_core,
|
|
||||||
TP_PROTO(struct va_format *vaf),
|
|
||||||
TP_ARGS(vaf)
|
|
||||||
);
|
|
||||||
|
|
||||||
DEFINE_EVENT(dwc3_log_msg, dwc3_ep0,
|
|
||||||
TP_PROTO(struct va_format *vaf),
|
|
||||||
TP_ARGS(vaf)
|
|
||||||
);
|
|
||||||
|
|
||||||
DECLARE_EVENT_CLASS(dwc3_log_io,
|
DECLARE_EVENT_CLASS(dwc3_log_io,
|
||||||
TP_PROTO(void *base, u32 offset, u32 value),
|
TP_PROTO(void *base, u32 offset, u32 value),
|
||||||
TP_ARGS(base, offset, value),
|
TP_ARGS(base, offset, value),
|
||||||
@ -198,7 +173,7 @@ DECLARE_EVENT_CLASS(dwc3_log_generic_cmd,
|
|||||||
__entry->param = param;
|
__entry->param = param;
|
||||||
__entry->status = status;
|
__entry->status = status;
|
||||||
),
|
),
|
||||||
TP_printk("cmd '%s' [%d] param %08x --> status: %s",
|
TP_printk("cmd '%s' [%x] param %08x --> status: %s",
|
||||||
dwc3_gadget_generic_cmd_string(__entry->cmd),
|
dwc3_gadget_generic_cmd_string(__entry->cmd),
|
||||||
__entry->cmd, __entry->param,
|
__entry->cmd, __entry->param,
|
||||||
dwc3_gadget_generic_cmd_status_string(__entry->status)
|
dwc3_gadget_generic_cmd_status_string(__entry->status)
|
||||||
@ -298,36 +273,7 @@ DECLARE_EVENT_CLASS(dwc3_log_trb,
|
|||||||
__entry->ctrl & DWC3_TRB_CTRL_CSP ? 'S' : 's',
|
__entry->ctrl & DWC3_TRB_CTRL_CSP ? 'S' : 's',
|
||||||
__entry->ctrl & DWC3_TRB_CTRL_ISP_IMI ? 'S' : 's',
|
__entry->ctrl & DWC3_TRB_CTRL_ISP_IMI ? 'S' : 's',
|
||||||
__entry->ctrl & DWC3_TRB_CTRL_IOC ? 'C' : 'c',
|
__entry->ctrl & DWC3_TRB_CTRL_IOC ? 'C' : 'c',
|
||||||
({char *s;
|
dwc3_trb_type_string(DWC3_TRBCTL_TYPE(__entry->ctrl))
|
||||||
switch (__entry->ctrl & 0x3f0) {
|
|
||||||
case DWC3_TRBCTL_NORMAL:
|
|
||||||
s = "normal";
|
|
||||||
break;
|
|
||||||
case DWC3_TRBCTL_CONTROL_SETUP:
|
|
||||||
s = "setup";
|
|
||||||
break;
|
|
||||||
case DWC3_TRBCTL_CONTROL_STATUS2:
|
|
||||||
s = "status2";
|
|
||||||
break;
|
|
||||||
case DWC3_TRBCTL_CONTROL_STATUS3:
|
|
||||||
s = "status3";
|
|
||||||
break;
|
|
||||||
case DWC3_TRBCTL_CONTROL_DATA:
|
|
||||||
s = "data";
|
|
||||||
break;
|
|
||||||
case DWC3_TRBCTL_ISOCHRONOUS_FIRST:
|
|
||||||
s = "isoc-first";
|
|
||||||
break;
|
|
||||||
case DWC3_TRBCTL_ISOCHRONOUS:
|
|
||||||
s = "isoc";
|
|
||||||
break;
|
|
||||||
case DWC3_TRBCTL_LINK_TRB:
|
|
||||||
s = "link";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
s = "UNKNOWN";
|
|
||||||
break;
|
|
||||||
} s; })
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -212,7 +212,7 @@ config USB_F_TCM
|
|||||||
# this first set of drivers all depend on bulk-capable hardware.
|
# this first set of drivers all depend on bulk-capable hardware.
|
||||||
|
|
||||||
config USB_CONFIGFS
|
config USB_CONFIGFS
|
||||||
tristate "USB functions configurable through configfs"
|
tristate "USB Gadget functions configurable through configfs"
|
||||||
select USB_LIBCOMPOSITE
|
select USB_LIBCOMPOSITE
|
||||||
help
|
help
|
||||||
A Linux USB "gadget" can be set up through configfs.
|
A Linux USB "gadget" can be set up through configfs.
|
||||||
@ -458,8 +458,9 @@ config USB_CONFIGFS_F_TCM
|
|||||||
UAS utilizes the USB 3.0 feature called streams support.
|
UAS utilizes the USB 3.0 feature called streams support.
|
||||||
|
|
||||||
choice
|
choice
|
||||||
tristate "USB Gadget Drivers"
|
tristate "USB Gadget precomposed configurations"
|
||||||
default USB_ETH
|
default USB_ETH
|
||||||
|
optional
|
||||||
help
|
help
|
||||||
A Linux "Gadget Driver" talks to the USB Peripheral Controller
|
A Linux "Gadget Driver" talks to the USB Peripheral Controller
|
||||||
driver through the abstract "gadget" API. Some other operating
|
driver through the abstract "gadget" API. Some other operating
|
||||||
@ -476,6 +477,12 @@ choice
|
|||||||
not be able work with that controller, or might need to implement
|
not be able work with that controller, or might need to implement
|
||||||
a less common variant of a device class protocol.
|
a less common variant of a device class protocol.
|
||||||
|
|
||||||
|
The available choices each represent a single precomposed USB
|
||||||
|
gadget configuration. In the device model, each option contains
|
||||||
|
both the device instantiation as a child for a USB gadget
|
||||||
|
controller, and the relevant drivers for each function declared
|
||||||
|
by the device.
|
||||||
|
|
||||||
source "drivers/usb/gadget/legacy/Kconfig"
|
source "drivers/usb/gadget/legacy/Kconfig"
|
||||||
|
|
||||||
endchoice
|
endchoice
|
||||||
|
@ -246,7 +246,6 @@ EXPORT_SYMBOL_GPL(ffs_lock);
|
|||||||
|
|
||||||
static struct ffs_dev *_ffs_find_dev(const char *name);
|
static struct ffs_dev *_ffs_find_dev(const char *name);
|
||||||
static struct ffs_dev *_ffs_alloc_dev(void);
|
static struct ffs_dev *_ffs_alloc_dev(void);
|
||||||
static int _ffs_name_dev(struct ffs_dev *dev, const char *name);
|
|
||||||
static void _ffs_free_dev(struct ffs_dev *dev);
|
static void _ffs_free_dev(struct ffs_dev *dev);
|
||||||
static void *ffs_acquire_dev(const char *dev_name);
|
static void *ffs_acquire_dev(const char *dev_name);
|
||||||
static void ffs_release_dev(struct ffs_data *ffs_data);
|
static void ffs_release_dev(struct ffs_data *ffs_data);
|
||||||
@ -1571,14 +1570,14 @@ static void ffs_data_get(struct ffs_data *ffs)
|
|||||||
{
|
{
|
||||||
ENTER();
|
ENTER();
|
||||||
|
|
||||||
atomic_inc(&ffs->ref);
|
refcount_inc(&ffs->ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ffs_data_opened(struct ffs_data *ffs)
|
static void ffs_data_opened(struct ffs_data *ffs)
|
||||||
{
|
{
|
||||||
ENTER();
|
ENTER();
|
||||||
|
|
||||||
atomic_inc(&ffs->ref);
|
refcount_inc(&ffs->ref);
|
||||||
if (atomic_add_return(1, &ffs->opened) == 1 &&
|
if (atomic_add_return(1, &ffs->opened) == 1 &&
|
||||||
ffs->state == FFS_DEACTIVATED) {
|
ffs->state == FFS_DEACTIVATED) {
|
||||||
ffs->state = FFS_CLOSING;
|
ffs->state = FFS_CLOSING;
|
||||||
@ -1590,7 +1589,7 @@ static void ffs_data_put(struct ffs_data *ffs)
|
|||||||
{
|
{
|
||||||
ENTER();
|
ENTER();
|
||||||
|
|
||||||
if (unlikely(atomic_dec_and_test(&ffs->ref))) {
|
if (unlikely(refcount_dec_and_test(&ffs->ref))) {
|
||||||
pr_info("%s(): freeing\n", __func__);
|
pr_info("%s(): freeing\n", __func__);
|
||||||
ffs_data_clear(ffs);
|
ffs_data_clear(ffs);
|
||||||
BUG_ON(waitqueue_active(&ffs->ev.waitq) ||
|
BUG_ON(waitqueue_active(&ffs->ev.waitq) ||
|
||||||
@ -1635,7 +1634,7 @@ static struct ffs_data *ffs_data_new(void)
|
|||||||
|
|
||||||
ENTER();
|
ENTER();
|
||||||
|
|
||||||
atomic_set(&ffs->ref, 1);
|
refcount_set(&ffs->ref, 1);
|
||||||
atomic_set(&ffs->opened, 0);
|
atomic_set(&ffs->opened, 0);
|
||||||
ffs->state = FFS_READ_DESCRIPTORS;
|
ffs->state = FFS_READ_DESCRIPTORS;
|
||||||
mutex_init(&ffs->mutex);
|
mutex_init(&ffs->mutex);
|
||||||
@ -3302,9 +3301,10 @@ static struct ffs_dev *_ffs_do_find_dev(const char *name)
|
|||||||
{
|
{
|
||||||
struct ffs_dev *dev;
|
struct ffs_dev *dev;
|
||||||
|
|
||||||
|
if (!name)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
list_for_each_entry(dev, &ffs_devices, entry) {
|
list_for_each_entry(dev, &ffs_devices, entry) {
|
||||||
if (!dev->name || !name)
|
|
||||||
continue;
|
|
||||||
if (strcmp(dev->name, name) == 0)
|
if (strcmp(dev->name, name) == 0)
|
||||||
return dev;
|
return dev;
|
||||||
}
|
}
|
||||||
@ -3380,42 +3380,11 @@ static void ffs_free_inst(struct usb_function_instance *f)
|
|||||||
kfree(opts);
|
kfree(opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MAX_INST_NAME_LEN 40
|
|
||||||
|
|
||||||
static int ffs_set_inst_name(struct usb_function_instance *fi, const char *name)
|
static int ffs_set_inst_name(struct usb_function_instance *fi, const char *name)
|
||||||
{
|
{
|
||||||
struct f_fs_opts *opts;
|
if (strlen(name) >= FIELD_SIZEOF(struct ffs_dev, name))
|
||||||
char *ptr;
|
|
||||||
const char *tmp;
|
|
||||||
int name_len, ret;
|
|
||||||
|
|
||||||
name_len = strlen(name) + 1;
|
|
||||||
if (name_len > MAX_INST_NAME_LEN)
|
|
||||||
return -ENAMETOOLONG;
|
return -ENAMETOOLONG;
|
||||||
|
return ffs_name_dev(to_f_fs_opts(fi)->dev, name);
|
||||||
ptr = kstrndup(name, name_len, GFP_KERNEL);
|
|
||||||
if (!ptr)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
opts = to_f_fs_opts(fi);
|
|
||||||
tmp = NULL;
|
|
||||||
|
|
||||||
ffs_dev_lock();
|
|
||||||
|
|
||||||
tmp = opts->dev->name_allocated ? opts->dev->name : NULL;
|
|
||||||
ret = _ffs_name_dev(opts->dev, ptr);
|
|
||||||
if (ret) {
|
|
||||||
kfree(ptr);
|
|
||||||
ffs_dev_unlock();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
opts->dev->name_allocated = true;
|
|
||||||
|
|
||||||
ffs_dev_unlock();
|
|
||||||
|
|
||||||
kfree(tmp);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct usb_function_instance *ffs_alloc_inst(void)
|
static struct usb_function_instance *ffs_alloc_inst(void)
|
||||||
@ -3545,32 +3514,19 @@ static struct ffs_dev *_ffs_alloc_dev(void)
|
|||||||
return dev;
|
return dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* ffs_lock must be taken by the caller of this function
|
|
||||||
* The caller is responsible for "name" being available whenever f_fs needs it
|
|
||||||
*/
|
|
||||||
static int _ffs_name_dev(struct ffs_dev *dev, const char *name)
|
|
||||||
{
|
|
||||||
struct ffs_dev *existing;
|
|
||||||
|
|
||||||
existing = _ffs_do_find_dev(name);
|
|
||||||
if (existing)
|
|
||||||
return -EBUSY;
|
|
||||||
|
|
||||||
dev->name = name;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The caller is responsible for "name" being available whenever f_fs needs it
|
|
||||||
*/
|
|
||||||
int ffs_name_dev(struct ffs_dev *dev, const char *name)
|
int ffs_name_dev(struct ffs_dev *dev, const char *name)
|
||||||
{
|
{
|
||||||
int ret;
|
struct ffs_dev *existing;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
ffs_dev_lock();
|
ffs_dev_lock();
|
||||||
ret = _ffs_name_dev(dev, name);
|
|
||||||
|
existing = _ffs_do_find_dev(name);
|
||||||
|
if (!existing)
|
||||||
|
strlcpy(dev->name, name, ARRAY_SIZE(dev->name));
|
||||||
|
else if (existing != dev)
|
||||||
|
ret = -EBUSY;
|
||||||
|
|
||||||
ffs_dev_unlock();
|
ffs_dev_unlock();
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -3600,8 +3556,6 @@ EXPORT_SYMBOL_GPL(ffs_single_dev);
|
|||||||
static void _ffs_free_dev(struct ffs_dev *dev)
|
static void _ffs_free_dev(struct ffs_dev *dev)
|
||||||
{
|
{
|
||||||
list_del(&dev->entry);
|
list_del(&dev->entry);
|
||||||
if (dev->name_allocated)
|
|
||||||
kfree(dev->name);
|
|
||||||
|
|
||||||
/* Clear the private_data pointer to stop incorrect dev access */
|
/* Clear the private_data pointer to stop incorrect dev access */
|
||||||
if (dev->ffs_data)
|
if (dev->ffs_data)
|
||||||
|
@ -178,6 +178,7 @@ static void rx_complete(struct usb_ep *ep, struct usb_request *req);
|
|||||||
static int
|
static int
|
||||||
rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
|
rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
|
||||||
{
|
{
|
||||||
|
struct usb_gadget *g = dev->gadget;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
int retval = -ENOMEM;
|
int retval = -ENOMEM;
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
@ -209,8 +210,11 @@ rx_submit(struct eth_dev *dev, struct usb_request *req, gfp_t gfp_flags)
|
|||||||
*/
|
*/
|
||||||
size += sizeof(struct ethhdr) + dev->net->mtu + RX_EXTRA;
|
size += sizeof(struct ethhdr) + dev->net->mtu + RX_EXTRA;
|
||||||
size += dev->port_usb->header_len;
|
size += dev->port_usb->header_len;
|
||||||
size += out->maxpacket - 1;
|
|
||||||
size -= size % out->maxpacket;
|
if (g->quirk_ep_out_aligned_size) {
|
||||||
|
size += out->maxpacket - 1;
|
||||||
|
size -= size % out->maxpacket;
|
||||||
|
}
|
||||||
|
|
||||||
if (dev->port_usb->is_fixed)
|
if (dev->port_usb->is_fixed)
|
||||||
size = max_t(size_t, size, dev->port_usb->fixed_out_len);
|
size = max_t(size_t, size, dev->port_usb->fixed_out_len);
|
||||||
@ -401,13 +405,12 @@ done:
|
|||||||
static void rx_fill(struct eth_dev *dev, gfp_t gfp_flags)
|
static void rx_fill(struct eth_dev *dev, gfp_t gfp_flags)
|
||||||
{
|
{
|
||||||
struct usb_request *req;
|
struct usb_request *req;
|
||||||
|
struct usb_request *tmp;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
/* fill unused rxq slots with some skb */
|
/* fill unused rxq slots with some skb */
|
||||||
spin_lock_irqsave(&dev->req_lock, flags);
|
spin_lock_irqsave(&dev->req_lock, flags);
|
||||||
while (!list_empty(&dev->rx_reqs)) {
|
list_for_each_entry_safe(req, tmp, &dev->rx_reqs, list) {
|
||||||
req = container_of(dev->rx_reqs.next,
|
|
||||||
struct usb_request, list);
|
|
||||||
list_del_init(&req->list);
|
list_del_init(&req->list);
|
||||||
spin_unlock_irqrestore(&dev->req_lock, flags);
|
spin_unlock_irqrestore(&dev->req_lock, flags);
|
||||||
|
|
||||||
@ -527,7 +530,7 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
|
|||||||
return NETDEV_TX_BUSY;
|
return NETDEV_TX_BUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
req = container_of(dev->tx_reqs.next, struct usb_request, list);
|
req = list_first_entry(&dev->tx_reqs, struct usb_request, list);
|
||||||
list_del(&req->list);
|
list_del(&req->list);
|
||||||
|
|
||||||
/* temporarily stop TX queue when the freelist empties */
|
/* temporarily stop TX queue when the freelist empties */
|
||||||
@ -1122,6 +1125,7 @@ void gether_disconnect(struct gether *link)
|
|||||||
{
|
{
|
||||||
struct eth_dev *dev = link->ioport;
|
struct eth_dev *dev = link->ioport;
|
||||||
struct usb_request *req;
|
struct usb_request *req;
|
||||||
|
struct usb_request *tmp;
|
||||||
|
|
||||||
WARN_ON(!dev);
|
WARN_ON(!dev);
|
||||||
if (!dev)
|
if (!dev)
|
||||||
@ -1138,9 +1142,7 @@ void gether_disconnect(struct gether *link)
|
|||||||
*/
|
*/
|
||||||
usb_ep_disable(link->in_ep);
|
usb_ep_disable(link->in_ep);
|
||||||
spin_lock(&dev->req_lock);
|
spin_lock(&dev->req_lock);
|
||||||
while (!list_empty(&dev->tx_reqs)) {
|
list_for_each_entry_safe(req, tmp, &dev->tx_reqs, list) {
|
||||||
req = container_of(dev->tx_reqs.next,
|
|
||||||
struct usb_request, list);
|
|
||||||
list_del(&req->list);
|
list_del(&req->list);
|
||||||
|
|
||||||
spin_unlock(&dev->req_lock);
|
spin_unlock(&dev->req_lock);
|
||||||
@ -1152,9 +1154,7 @@ void gether_disconnect(struct gether *link)
|
|||||||
|
|
||||||
usb_ep_disable(link->out_ep);
|
usb_ep_disable(link->out_ep);
|
||||||
spin_lock(&dev->req_lock);
|
spin_lock(&dev->req_lock);
|
||||||
while (!list_empty(&dev->rx_reqs)) {
|
list_for_each_entry_safe(req, tmp, &dev->rx_reqs, list) {
|
||||||
req = container_of(dev->rx_reqs.next,
|
|
||||||
struct usb_request, list);
|
|
||||||
list_del(&req->list);
|
list_del(&req->list);
|
||||||
|
|
||||||
spin_unlock(&dev->req_lock);
|
spin_unlock(&dev->req_lock);
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
|
#include <linux/refcount.h>
|
||||||
|
|
||||||
#ifdef VERBOSE_DEBUG
|
#ifdef VERBOSE_DEBUG
|
||||||
#ifndef pr_vdebug
|
#ifndef pr_vdebug
|
||||||
@ -39,15 +40,16 @@
|
|||||||
struct f_fs_opts;
|
struct f_fs_opts;
|
||||||
|
|
||||||
struct ffs_dev {
|
struct ffs_dev {
|
||||||
const char *name;
|
|
||||||
bool name_allocated;
|
|
||||||
bool mounted;
|
|
||||||
bool desc_ready;
|
|
||||||
bool single;
|
|
||||||
struct ffs_data *ffs_data;
|
struct ffs_data *ffs_data;
|
||||||
struct f_fs_opts *opts;
|
struct f_fs_opts *opts;
|
||||||
struct list_head entry;
|
struct list_head entry;
|
||||||
|
|
||||||
|
char name[41];
|
||||||
|
|
||||||
|
bool mounted;
|
||||||
|
bool desc_ready;
|
||||||
|
bool single;
|
||||||
|
|
||||||
int (*ffs_ready_callback)(struct ffs_data *ffs);
|
int (*ffs_ready_callback)(struct ffs_data *ffs);
|
||||||
void (*ffs_closed_callback)(struct ffs_data *ffs);
|
void (*ffs_closed_callback)(struct ffs_data *ffs);
|
||||||
void *(*ffs_acquire_dev_callback)(struct ffs_dev *dev);
|
void *(*ffs_acquire_dev_callback)(struct ffs_dev *dev);
|
||||||
@ -177,7 +179,7 @@ struct ffs_data {
|
|||||||
struct completion ep0req_completion; /* P: mutex */
|
struct completion ep0req_completion; /* P: mutex */
|
||||||
|
|
||||||
/* reference counter */
|
/* reference counter */
|
||||||
atomic_t ref;
|
refcount_t ref;
|
||||||
/* how many files are opened (EP0 and others) */
|
/* how many files are opened (EP0 and others) */
|
||||||
atomic_t opened;
|
atomic_t opened;
|
||||||
|
|
||||||
|
@ -2125,7 +2125,7 @@ static struct configfs_item_operations uvc_item_ops = {
|
|||||||
.release = uvc_attr_release,
|
.release = uvc_attr_release,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define UVCG_OPTS_ATTR(cname, conv, str2u, uxx, vnoc, limit) \
|
#define UVCG_OPTS_ATTR(cname, aname, conv, str2u, uxx, vnoc, limit) \
|
||||||
static ssize_t f_uvc_opts_##cname##_show( \
|
static ssize_t f_uvc_opts_##cname##_show( \
|
||||||
struct config_item *item, char *page) \
|
struct config_item *item, char *page) \
|
||||||
{ \
|
{ \
|
||||||
@ -2168,16 +2168,16 @@ end: \
|
|||||||
return ret; \
|
return ret; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
UVC_ATTR(f_uvc_opts_, cname, aname)
|
UVC_ATTR(f_uvc_opts_, cname, cname)
|
||||||
|
|
||||||
#define identity_conv(x) (x)
|
#define identity_conv(x) (x)
|
||||||
|
|
||||||
UVCG_OPTS_ATTR(streaming_interval, identity_conv, kstrtou8, u8, identity_conv,
|
UVCG_OPTS_ATTR(streaming_interval, streaming_interval, identity_conv,
|
||||||
16);
|
kstrtou8, u8, identity_conv, 16);
|
||||||
UVCG_OPTS_ATTR(streaming_maxpacket, le16_to_cpu, kstrtou16, u16, le16_to_cpu,
|
UVCG_OPTS_ATTR(streaming_maxpacket, streaming_maxpacket, le16_to_cpu,
|
||||||
3072);
|
kstrtou16, u16, le16_to_cpu, 3072);
|
||||||
UVCG_OPTS_ATTR(streaming_maxburst, identity_conv, kstrtou8, u8, identity_conv,
|
UVCG_OPTS_ATTR(streaming_maxburst, streaming_maxburst, identity_conv,
|
||||||
15);
|
kstrtou8, u8, identity_conv, 15);
|
||||||
|
|
||||||
#undef identity_conv
|
#undef identity_conv
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include <linux/mmu_context.h>
|
#include <linux/mmu_context.h>
|
||||||
#include <linux/aio.h>
|
#include <linux/aio.h>
|
||||||
#include <linux/uio.h>
|
#include <linux/uio.h>
|
||||||
|
#include <linux/refcount.h>
|
||||||
|
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/moduleparam.h>
|
#include <linux/moduleparam.h>
|
||||||
@ -114,7 +115,7 @@ enum ep0_state {
|
|||||||
|
|
||||||
struct dev_data {
|
struct dev_data {
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
atomic_t count;
|
refcount_t count;
|
||||||
enum ep0_state state; /* P: lock */
|
enum ep0_state state; /* P: lock */
|
||||||
struct usb_gadgetfs_event event [N_EVENT];
|
struct usb_gadgetfs_event event [N_EVENT];
|
||||||
unsigned ev_next;
|
unsigned ev_next;
|
||||||
@ -150,12 +151,12 @@ struct dev_data {
|
|||||||
|
|
||||||
static inline void get_dev (struct dev_data *data)
|
static inline void get_dev (struct dev_data *data)
|
||||||
{
|
{
|
||||||
atomic_inc (&data->count);
|
refcount_inc (&data->count);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void put_dev (struct dev_data *data)
|
static void put_dev (struct dev_data *data)
|
||||||
{
|
{
|
||||||
if (likely (!atomic_dec_and_test (&data->count)))
|
if (likely (!refcount_dec_and_test (&data->count)))
|
||||||
return;
|
return;
|
||||||
/* needs no more cleanup */
|
/* needs no more cleanup */
|
||||||
BUG_ON (waitqueue_active (&data->wait));
|
BUG_ON (waitqueue_active (&data->wait));
|
||||||
@ -170,7 +171,7 @@ static struct dev_data *dev_new (void)
|
|||||||
if (!dev)
|
if (!dev)
|
||||||
return NULL;
|
return NULL;
|
||||||
dev->state = STATE_DEV_DISABLED;
|
dev->state = STATE_DEV_DISABLED;
|
||||||
atomic_set (&dev->count, 1);
|
refcount_set (&dev->count, 1);
|
||||||
spin_lock_init (&dev->lock);
|
spin_lock_init (&dev->lock);
|
||||||
INIT_LIST_HEAD (&dev->epfiles);
|
INIT_LIST_HEAD (&dev->epfiles);
|
||||||
init_waitqueue_head (&dev->wait);
|
init_waitqueue_head (&dev->wait);
|
||||||
@ -190,7 +191,7 @@ enum ep_state {
|
|||||||
struct ep_data {
|
struct ep_data {
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
enum ep_state state;
|
enum ep_state state;
|
||||||
atomic_t count;
|
refcount_t count;
|
||||||
struct dev_data *dev;
|
struct dev_data *dev;
|
||||||
/* must hold dev->lock before accessing ep or req */
|
/* must hold dev->lock before accessing ep or req */
|
||||||
struct usb_ep *ep;
|
struct usb_ep *ep;
|
||||||
@ -205,12 +206,12 @@ struct ep_data {
|
|||||||
|
|
||||||
static inline void get_ep (struct ep_data *data)
|
static inline void get_ep (struct ep_data *data)
|
||||||
{
|
{
|
||||||
atomic_inc (&data->count);
|
refcount_inc (&data->count);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void put_ep (struct ep_data *data)
|
static void put_ep (struct ep_data *data)
|
||||||
{
|
{
|
||||||
if (likely (!atomic_dec_and_test (&data->count)))
|
if (likely (!refcount_dec_and_test (&data->count)))
|
||||||
return;
|
return;
|
||||||
put_dev (data->dev);
|
put_dev (data->dev);
|
||||||
/* needs no more cleanup */
|
/* needs no more cleanup */
|
||||||
@ -1561,7 +1562,7 @@ static int activate_ep_files (struct dev_data *dev)
|
|||||||
init_waitqueue_head (&data->wait);
|
init_waitqueue_head (&data->wait);
|
||||||
|
|
||||||
strncpy (data->name, ep->name, sizeof (data->name) - 1);
|
strncpy (data->name, ep->name, sizeof (data->name) - 1);
|
||||||
atomic_set (&data->count, 1);
|
refcount_set (&data->count, 1);
|
||||||
data->dev = dev;
|
data->dev = dev;
|
||||||
get_dev (dev);
|
get_dev (dev);
|
||||||
|
|
||||||
|
@ -62,8 +62,9 @@ config USB_ATMEL_USBA
|
|||||||
|
|
||||||
The fifo_mode parameter is used to select endpoint allocation mode.
|
The fifo_mode parameter is used to select endpoint allocation mode.
|
||||||
fifo_mode = 0 is used to let the driver autoconfigure the endpoints.
|
fifo_mode = 0 is used to let the driver autoconfigure the endpoints.
|
||||||
In this case 2 banks are allocated for isochronous endpoints and
|
In this case, for ep1 2 banks are allocated if it works in isochronous
|
||||||
only one bank is allocated for the rest of the endpoints.
|
mode and only 1 bank otherwise. For the rest of the endpoints
|
||||||
|
only 1 bank is allocated.
|
||||||
|
|
||||||
fifo_mode = 1 is a generic maximum fifo size (1024 bytes) configuration
|
fifo_mode = 1 is a generic maximum fifo size (1024 bytes) configuration
|
||||||
allowing the usage of ep1 - ep6
|
allowing the usage of ep1 - ep6
|
||||||
@ -191,6 +192,7 @@ config USB_RENESAS_USBHS_UDC
|
|||||||
config USB_RENESAS_USB3
|
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
|
||||||
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.
|
||||||
@ -253,6 +255,20 @@ config USB_MV_U3D
|
|||||||
MARVELL PXA2128 Processor series include a super speed USB3.0 device
|
MARVELL PXA2128 Processor series include a super speed USB3.0 device
|
||||||
controller, which support super speed USB peripheral.
|
controller, which support super speed USB peripheral.
|
||||||
|
|
||||||
|
config USB_SNP_CORE
|
||||||
|
depends on USB_AMD5536UDC
|
||||||
|
tristate
|
||||||
|
help
|
||||||
|
This enables core driver support for Synopsys USB 2.0 Device
|
||||||
|
controller.
|
||||||
|
|
||||||
|
This will be enabled when PCI or Platform driver for this UDC is
|
||||||
|
selected. Currently, this will be enabled by USB_SNP_UDC_PLAT or
|
||||||
|
USB_AMD5536UDC options.
|
||||||
|
|
||||||
|
This IP is different to the High Speed OTG IP that can be enabled
|
||||||
|
by selecting USB_DWC2 or USB_DWC3 options.
|
||||||
|
|
||||||
#
|
#
|
||||||
# Controllers available in both integrated and discrete versions
|
# Controllers available in both integrated and discrete versions
|
||||||
#
|
#
|
||||||
@ -277,7 +293,8 @@ source "drivers/usb/gadget/udc/bdc/Kconfig"
|
|||||||
|
|
||||||
config USB_AMD5536UDC
|
config USB_AMD5536UDC
|
||||||
tristate "AMD5536 UDC"
|
tristate "AMD5536 UDC"
|
||||||
depends on PCI
|
depends on USB_PCI
|
||||||
|
select USB_SNP_CORE
|
||||||
help
|
help
|
||||||
The AMD5536 UDC is part of the AMD Geode CS5536, an x86 southbridge.
|
The AMD5536 UDC is part of the AMD Geode CS5536, an x86 southbridge.
|
||||||
It is a USB Highspeed DMA capable USB device controller. Beside ep0
|
It is a USB Highspeed DMA capable USB device controller. Beside ep0
|
||||||
@ -285,6 +302,9 @@ config USB_AMD5536UDC
|
|||||||
The UDC port supports OTG operation, and may be used as a host port
|
The UDC port supports OTG operation, and may be used as a host port
|
||||||
if it's not being used to implement peripheral or OTG roles.
|
if it's not being used to implement peripheral or OTG roles.
|
||||||
|
|
||||||
|
This UDC is based on Synopsys USB device controller IP and selects
|
||||||
|
CONFIG_USB_SNP_CORE option to build the core driver.
|
||||||
|
|
||||||
Say "y" to link the driver statically, or "m" to build a
|
Say "y" to link the driver statically, or "m" to build a
|
||||||
dynamically linked module called "amd5536udc" and force all
|
dynamically linked module called "amd5536udc" and force all
|
||||||
gadget drivers to also be dynamically linked.
|
gadget drivers to also be dynamically linked.
|
||||||
@ -327,7 +347,7 @@ config USB_NET2272_DMA
|
|||||||
|
|
||||||
config USB_NET2280
|
config USB_NET2280
|
||||||
tristate "NetChip NET228x / PLX USB3x8x"
|
tristate "NetChip NET228x / PLX USB3x8x"
|
||||||
depends on PCI
|
depends on USB_PCI
|
||||||
help
|
help
|
||||||
NetChip 2280 / 2282 is a PCI based USB peripheral controller which
|
NetChip 2280 / 2282 is a PCI based USB peripheral controller which
|
||||||
supports both full and high speed USB 2.0 data transfers.
|
supports both full and high speed USB 2.0 data transfers.
|
||||||
@ -352,7 +372,7 @@ config USB_NET2280
|
|||||||
|
|
||||||
config USB_GOKU
|
config USB_GOKU
|
||||||
tristate "Toshiba TC86C001 'Goku-S'"
|
tristate "Toshiba TC86C001 'Goku-S'"
|
||||||
depends on PCI
|
depends on USB_PCI
|
||||||
help
|
help
|
||||||
The Toshiba TC86C001 is a PCI device which includes controllers
|
The Toshiba TC86C001 is a PCI device which includes controllers
|
||||||
for full speed USB devices, IDE, I2C, SIO, plus a USB host (OHCI).
|
for full speed USB devices, IDE, I2C, SIO, plus a USB host (OHCI).
|
||||||
@ -366,7 +386,7 @@ config USB_GOKU
|
|||||||
|
|
||||||
config USB_EG20T
|
config USB_EG20T
|
||||||
tristate "Intel QUARK X1000/EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7831) UDC"
|
tristate "Intel QUARK X1000/EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7831) UDC"
|
||||||
depends on PCI
|
depends on USB_PCI
|
||||||
help
|
help
|
||||||
This is a USB device driver for EG20T PCH.
|
This is a USB device driver for EG20T PCH.
|
||||||
EG20T PCH is the platform controller hub that is used in Intel's
|
EG20T PCH is the platform controller hub that is used in Intel's
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user