mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-24 04:34:08 +08:00
USB/PHY patches for 5.1-rc1
Here is the big USB/PHY driver pull request for 5.1-rc1. The usual set of gadget driver updates, phy driver updates (you will have a merge issue with Kconfig and Makefile), xhci updates, and typec additions. Also included in here are a lot of small cleanups and fixes and driver updates where needed. 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----- iG0EABECAC0WIQT0tgzFv3jCIUoxPcsxR9QN2y37KQUCXH+hsw8cZ3JlZ0Brcm9h aC5jb20ACgkQMUfUDdst+ynfNwCgqKKg+MxJ9pFjrwfWYOrbk+BBe2UAn2Elp4ia 8FTdneQfN2J8Hhc6KGXE =Kx9I -----END PGP SIGNATURE----- Merge tag 'usb-5.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB/PHY updates from Greg KH: "Here is the big USB/PHY driver pull request for 5.1-rc1. The usual set of gadget driver updates, phy driver updates, xhci updates, and typec additions. Also included in here are a lot of small cleanups and fixes and driver updates where needed. All of these have been in linux-next for a while with no reported issues" * tag 'usb-5.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (167 commits) wusb: Remove unnecessary static function ckhdid_printf usb: core: make default autosuspend delay configurable usb: core: Fix typo in description of "authorized_default" usb: chipidea: Refactor USB PHY selection and keep a single PHY usb: chipidea: Grab the (legacy) USB PHY by phandle first usb: chipidea: imx: set power polarity dt-bindings: usb: ci-hdrc-usb2: add property power-active-high usb: chipidea: imx: remove unused header files usb: chipidea: tegra: Fix missed ci_hdrc_remove_device() usb: core: add option of only authorizing internal devices usb: typec: tps6598x: handle block writes separately with plain-I2C adapters usb: xhci: Fix for Enabling USB ROLE SWITCH QUIRK on INTEL_SUNRISEPOINT_LP_XHCI usb: xhci: fix build warning - missing prototype usb: xhci: dbc: Fixing typo error. usb: xhci: remove unused member 'parent' in xhci_regset struct xhci: tegra: Prevent error pointer dereference USB: serial: option: add Telit ME910 ECM composition usb: core: Replace hardcoded check with inline function from usb.h usb: core: skip interfaces disabled in devicetree usb: typec: mux: remove redundant check on variable match ...
This commit is contained in:
commit
f90d64483e
@ -186,7 +186,7 @@ Contact: Lan Tianyu <tianyu.lan@intel.com>
|
||||
Description:
|
||||
Some platforms provide usb port connect types through ACPI.
|
||||
This attribute is to expose these information to user space.
|
||||
The file will read "hotplug", "wired" and "not used" if the
|
||||
The file will read "hotplug", "hardwired" and "not used" if the
|
||||
information is available, and "unknown" otherwise.
|
||||
|
||||
What: /sys/bus/usb/devices/.../(hub interface)/portX/location
|
||||
|
@ -4718,7 +4718,8 @@
|
||||
usbcore.authorized_default=
|
||||
[USB] Default USB device authorization:
|
||||
(default -1 = authorized except for wireless USB,
|
||||
0 = not authorized, 1 = authorized)
|
||||
0 = not authorized, 1 = authorized, 2 = authorized
|
||||
if device connected to internal port)
|
||||
|
||||
usbcore.autosuspend=
|
||||
[USB] The autosuspend time delay (in seconds) used
|
||||
|
@ -147,6 +147,7 @@ required properties:
|
||||
- compatible: Should be "atmel,<chip>-sfr", "syscon" or
|
||||
"atmel,<chip>-sfrbu", "syscon"
|
||||
<chip> can be "sama5d3", "sama5d4" or "sama5d2".
|
||||
It also can be "microchip,sam9x60-sfr", "syscon".
|
||||
- reg: Should contain registers location and length
|
||||
|
||||
sfr@f0038000 {
|
||||
|
@ -31,28 +31,7 @@ Required subnodes:
|
||||
- one subnode per DSI device connected on the DSI bus. Each DSI device should
|
||||
contain a reg property encoding its virtual channel.
|
||||
|
||||
Cadence DPHY
|
||||
============
|
||||
|
||||
Cadence DPHY block.
|
||||
|
||||
Required properties:
|
||||
- compatible: should be set to "cdns,dphy".
|
||||
- reg: physical base address and length of the DPHY registers.
|
||||
- clocks: DPHY reference clocks.
|
||||
- clock-names: must contain "psm" and "pll_ref".
|
||||
- #phy-cells: must be set to 0.
|
||||
|
||||
|
||||
Example:
|
||||
dphy0: dphy@fd0e0000{
|
||||
compatible = "cdns,dphy";
|
||||
reg = <0x0 0xfd0e0000 0x0 0x1000>;
|
||||
clocks = <&psm_clk>, <&pll_ref_clk>;
|
||||
clock-names = "psm", "pll_ref";
|
||||
#phy-cells = <0>;
|
||||
};
|
||||
|
||||
dsi0: dsi@fd0c0000 {
|
||||
compatible = "cdns,dsi";
|
||||
reg = <0x0 0xfd0c0000 0x0 0x1000>;
|
||||
|
20
Documentation/devicetree/bindings/phy/cdns,dphy.txt
Normal file
20
Documentation/devicetree/bindings/phy/cdns,dphy.txt
Normal file
@ -0,0 +1,20 @@
|
||||
Cadence DPHY
|
||||
============
|
||||
|
||||
Cadence DPHY block.
|
||||
|
||||
Required properties:
|
||||
- compatible: should be set to "cdns,dphy".
|
||||
- reg: physical base address and length of the DPHY registers.
|
||||
- clocks: DPHY reference clocks.
|
||||
- clock-names: must contain "psm" and "pll_ref".
|
||||
- #phy-cells: must be set to 0.
|
||||
|
||||
Example:
|
||||
dphy0: dphy@fd0e0000{
|
||||
compatible = "cdns,dphy";
|
||||
reg = <0x0 0xfd0e0000 0x0 0x1000>;
|
||||
clocks = <&psm_clk>, <&pll_ref_clk>;
|
||||
clock-names = "psm", "pll_ref";
|
||||
#phy-cells = <0>;
|
||||
};
|
@ -1,16 +1,27 @@
|
||||
mvebu comphy driver
|
||||
-------------------
|
||||
MVEBU comphy drivers
|
||||
--------------------
|
||||
|
||||
A comphy controller can be found on Marvell Armada 7k/8k on the CP110. It
|
||||
provides a number of shared PHYs used by various interfaces (network, sata,
|
||||
usb, PCIe...).
|
||||
COMPHY controllers can be found on the following Marvell MVEBU SoCs:
|
||||
* Armada 7k/8k (on the CP110)
|
||||
* Armada 3700
|
||||
It provides a number of shared PHYs used by various interfaces (network, SATA,
|
||||
USB, PCIe...).
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: should be "marvell,comphy-cp110"
|
||||
- reg: should contain the comphy register location and length.
|
||||
- marvell,system-controller: should contain a phandle to the
|
||||
system controller node.
|
||||
- compatible: should be one of:
|
||||
* "marvell,comphy-cp110" for Armada 7k/8k
|
||||
* "marvell,comphy-a3700" for Armada 3700
|
||||
- reg: should contain the COMPHY register(s) location(s) and length(s).
|
||||
* 1 entry for Armada 7k/8k
|
||||
* 4 entries for Armada 3700 along with the corresponding reg-names
|
||||
properties, memory areas are:
|
||||
* Generic COMPHY registers
|
||||
* Lane 1 (PCIe/GbE)
|
||||
* Lane 0 (USB3/GbE)
|
||||
* Lane 2 (SATA/USB3)
|
||||
- marvell,system-controller: should contain a phandle to the system
|
||||
controller node (only for Armada 7k/8k)
|
||||
- #address-cells: should be 1.
|
||||
- #size-cells: should be 0.
|
||||
|
||||
@ -18,11 +29,11 @@ A sub-node is required for each comphy lane provided by the comphy.
|
||||
|
||||
Required properties (child nodes):
|
||||
|
||||
- reg: comphy lane number.
|
||||
- #phy-cells : from the generic phy bindings, must be 1. Defines the
|
||||
- reg: COMPHY lane number.
|
||||
- #phy-cells : from the generic PHY bindings, must be 1. Defines the
|
||||
input port to use for a given comphy lane.
|
||||
|
||||
Example:
|
||||
Examples:
|
||||
|
||||
cpm_comphy: phy@120000 {
|
||||
compatible = "marvell,comphy-cp110";
|
||||
@ -41,3 +52,33 @@ Example:
|
||||
#phy-cells = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
comphy: phy@18300 {
|
||||
compatible = "marvell,comphy-a3700";
|
||||
reg = <0x18300 0x300>,
|
||||
<0x1F000 0x400>,
|
||||
<0x5C000 0x400>,
|
||||
<0xe0178 0x8>;
|
||||
reg-names = "comphy",
|
||||
"lane1_pcie_gbe",
|
||||
"lane0_usb3_gbe",
|
||||
"lane2_sata_usb3";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
|
||||
comphy0: phy@0 {
|
||||
reg = <0>;
|
||||
#phy-cells = <1>;
|
||||
};
|
||||
|
||||
comphy1: phy@1 {
|
||||
reg = <1>;
|
||||
#phy-cells = <1>;
|
||||
};
|
||||
|
||||
comphy2: phy@2 {
|
||||
reg = <2>;
|
||||
#phy-cells = <1>;
|
||||
};
|
||||
};
|
||||
|
38
Documentation/devicetree/bindings/phy/phy-mvebu-utmi.txt
Normal file
38
Documentation/devicetree/bindings/phy/phy-mvebu-utmi.txt
Normal file
@ -0,0 +1,38 @@
|
||||
MVEBU A3700 UTMI PHY
|
||||
--------------------
|
||||
|
||||
USB2 UTMI+ PHY controllers can be found on the following Marvell MVEBU SoCs:
|
||||
* Armada 3700
|
||||
|
||||
On Armada 3700, there are two USB controllers, one is compatible with the USB2
|
||||
and USB3 specifications and supports OTG. The other one is USB2 compliant and
|
||||
only supports host mode. Both of these controllers come with a slightly
|
||||
different UTMI PHY.
|
||||
|
||||
Required Properties:
|
||||
|
||||
- compatible: Should be one of:
|
||||
* "marvell,a3700-utmi-host-phy" for the PHY connected to
|
||||
the USB2 host-only controller.
|
||||
* "marvell,a3700-utmi-otg-phy" for the PHY connected to
|
||||
the USB3 and USB2 OTG capable controller.
|
||||
- reg: PHY IP register range.
|
||||
- marvell,usb-misc-reg: handle on the "USB miscellaneous registers" shared
|
||||
region covering registers related to both the host
|
||||
controller and the PHY.
|
||||
- #phy-cells: Standard property (Documentation: phy-bindings.txt) Should be 0.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
usb2_utmi_host_phy: phy@5f000 {
|
||||
compatible = "marvell,armada-3700-utmi-host-phy";
|
||||
reg = <0x5f000 0x800>;
|
||||
marvell,usb-misc-reg = <&usb2_syscon>;
|
||||
#phy-cells = <0>;
|
||||
};
|
||||
|
||||
usb2_syscon: system-controller@5f800 {
|
||||
compatible = "marvell,armada-3700-usb2-host-misc", "syscon";
|
||||
reg = <0x5f800 0x800>;
|
||||
};
|
@ -23,6 +23,8 @@ Optional properties:
|
||||
register files". When set driver will request its
|
||||
phandle as one companion-grf for some special SoCs
|
||||
(e.g RV1108).
|
||||
- extcon : phandle to the extcon device providing the cable state for
|
||||
the otg phy.
|
||||
|
||||
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,
|
||||
|
@ -9,6 +9,8 @@ Required properties:
|
||||
"qcom,ipq8074-qmp-pcie-phy" for PCIe phy on IPQ8074
|
||||
"qcom,msm8996-qmp-pcie-phy" for 14nm PCIe phy on msm8996,
|
||||
"qcom,msm8996-qmp-usb3-phy" for 14nm USB3 phy on msm8996,
|
||||
"qcom,msm8998-qmp-usb3-phy" for USB3 QMP V3 phy on msm8998,
|
||||
"qcom,msm8998-qmp-ufs-phy" for UFS QMP phy on msm8998,
|
||||
"qcom,sdm845-qmp-usb3-phy" for USB3 QMP V3 phy on sdm845,
|
||||
"qcom,sdm845-qmp-usb3-uni-phy" for USB3 QMP V3 UNI phy on sdm845,
|
||||
"qcom,sdm845-qmp-ufs-phy" for UFS QMP phy on sdm845.
|
||||
@ -42,6 +44,10 @@ Required properties:
|
||||
"aux", "cfg_ahb", "ref".
|
||||
For "qcom,msm8996-qmp-usb3-phy" must contain:
|
||||
"aux", "cfg_ahb", "ref".
|
||||
For "qcom,msm8998-qmp-usb3-phy" must contain:
|
||||
"aux", "cfg_ahb", "ref".
|
||||
For "qcom,msm8998-qmp-ufs-phy" must contain:
|
||||
"ref", "ref_aux".
|
||||
For "qcom,sdm845-qmp-usb3-phy" must contain:
|
||||
"aux", "cfg_ahb", "ref", "com_aux".
|
||||
For "qcom,sdm845-qmp-usb3-uni-phy" must contain:
|
||||
@ -61,6 +67,9 @@ Required properties:
|
||||
"phy", "common", "cfg".
|
||||
For "qcom,msm8996-qmp-usb3-phy" must contain
|
||||
"phy", "common".
|
||||
For "qcom,msm8998-qmp-usb3-phy" must contain
|
||||
"phy", "common".
|
||||
For "qcom,msm8998-qmp-ufs-phy": no resets are listed.
|
||||
For "qcom,sdm845-qmp-usb3-phy" must contain:
|
||||
"phy", "common".
|
||||
For "qcom,sdm845-qmp-usb3-uni-phy" must contain:
|
||||
|
@ -6,6 +6,7 @@ QUSB2 controller supports LS/FS/HS usb connectivity on Qualcomm chipsets.
|
||||
Required properties:
|
||||
- compatible: compatible list, contains
|
||||
"qcom,msm8996-qusb2-phy" for 14nm PHY on msm8996,
|
||||
"qcom,msm8998-qusb2-phy" for 10nm PHY on msm8998,
|
||||
"qcom,sdm845-qusb2-phy" for 10nm PHY on sdm845.
|
||||
|
||||
- reg: offset and length of the PHY register set.
|
||||
|
@ -5,6 +5,8 @@ This file provides information on what the device node for the R-Car generation
|
||||
|
||||
Required properties:
|
||||
- compatible: "renesas,usb2-phy-r8a774a1" if the device is a part of an R8A774A1
|
||||
SoC.
|
||||
"renesas,usb2-phy-r8a774c0" if the device is a part of an R8A774C0
|
||||
SoC.
|
||||
"renesas,usb2-phy-r8a7795" if the device is a part of an R8A7795
|
||||
SoC.
|
||||
|
@ -35,6 +35,7 @@ Required properties:
|
||||
DRA7x
|
||||
Should be "ti,dra7x-usb2-phy2" for the 2nd instance of USB2 PHY
|
||||
in DRA7x
|
||||
Should be "ti,am654-usb2" for the USB2 PHYs on AM654.
|
||||
- reg : Address and length of the register set for the device.
|
||||
- #phy-cells: determine the number of cells that should be given in the
|
||||
phandle while referencing this phy.
|
||||
|
@ -93,6 +93,7 @@ i.mx specific properties
|
||||
- over-current-active-low: over current signal polarity is active low.
|
||||
- over-current-active-high: over current signal polarity is active high.
|
||||
It's recommended to specify the over current polarity.
|
||||
- power-active-high: power signal polarity is active high
|
||||
- external-vbus-divider: enables off-chip resistor divider for Vbus
|
||||
|
||||
Example:
|
||||
|
@ -0,0 +1,24 @@
|
||||
Ingenic JZ4740 MUSB driver
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: Must be "ingenic,jz4740-musb"
|
||||
- reg: Address range of the UDC register set
|
||||
- interrupts: IRQ number related to the UDC hardware
|
||||
- interrupt-names: must be "mc"
|
||||
- clocks: phandle to the "udc" clock
|
||||
- clock-names: must be "udc"
|
||||
|
||||
Example:
|
||||
|
||||
udc: usb@13040000 {
|
||||
compatible = "ingenic,jz4740-musb";
|
||||
reg = <0x13040000 0x10000>;
|
||||
|
||||
interrupt-parent = <&intc>;
|
||||
interrupts = <24>;
|
||||
interrupt-names = "mc";
|
||||
|
||||
clocks = <&cgu JZ4740_CLK_UDC>;
|
||||
clock-names = "udc";
|
||||
};
|
@ -3,7 +3,9 @@ TI Keystone Soc USB Controller
|
||||
DWC3 GLUE
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "ti,keystone-dwc3".
|
||||
- compatible: should be
|
||||
"ti,keystone-dwc3" for Keystone 2 SoCs
|
||||
"ti,am654-dwc3" for AM654 SoC
|
||||
- #address-cells, #size-cells : should be '1' if the device has sub-nodes
|
||||
with 'reg' property.
|
||||
- reg : Address and length of the register set for the USB subsystem on
|
||||
@ -21,7 +23,7 @@ SoCs only:
|
||||
- clock-names: Must be "usb".
|
||||
|
||||
|
||||
The following are mandatory properties for Keystone 2 66AK2G SoCs only:
|
||||
The following are mandatory properties for 66AK2G and AM654:
|
||||
|
||||
- power-domains: Should contain a phandle to a PM domain provider node
|
||||
and an args specifier containing the USB device id
|
||||
|
@ -4,6 +4,7 @@ Required properties:
|
||||
- compatible: Compatible list, contains
|
||||
"qcom,dwc3"
|
||||
"qcom,msm8996-dwc3" for msm8996 SOC.
|
||||
"qcom,msm8998-dwc3" for msm8998 SOC.
|
||||
"qcom,sdm845-dwc3" for sdm845 SOC.
|
||||
- reg: Offset and length of register set for QSCRATCH wrapper
|
||||
- power-domains: specifies a phandle to PM domain provider node
|
||||
|
@ -3,6 +3,7 @@ Renesas Electronics USB3.0 Peripheral driver
|
||||
Required properties:
|
||||
- compatible: Must contain one of the following:
|
||||
- "renesas,r8a774a1-usb3-peri"
|
||||
- "renesas,r8a774c0-usb3-peri"
|
||||
- "renesas,r8a7795-usb3-peri"
|
||||
- "renesas,r8a7796-usb3-peri"
|
||||
- "renesas,r8a77965-usb3-peri"
|
||||
|
@ -7,6 +7,7 @@ Required properties:
|
||||
- "renesas,usbhs-r8a7744" for r8a7744 (RZ/G1N) compatible device
|
||||
- "renesas,usbhs-r8a7745" for r8a7745 (RZ/G1E) compatible device
|
||||
- "renesas,usbhs-r8a774a1" for r8a774a1 (RZ/G2M) compatible device
|
||||
- "renesas,usbhs-r8a774c0" for r8a774c0 (RZ/G2E) compatible device
|
||||
- "renesas,usbhs-r8a7790" for r8a7790 (R-Car H2) compatible device
|
||||
- "renesas,usbhs-r8a7791" for r8a7791 (R-Car M2-W) compatible device
|
||||
- "renesas,usbhs-r8a7792" for r8a7792 (R-Car V2H) compatible device
|
||||
|
@ -64,6 +64,8 @@ Optional properties :
|
||||
- power-on-time-ms : Specifies the time it takes from the time the host
|
||||
initiates the power-on sequence to a port until the port has adequate
|
||||
power. The value is given in ms in a 0 - 510 range (default is 100ms).
|
||||
- swap-dx-lanes : Specifies the ports which will swap the differential-pair
|
||||
(D+/D-), default is not-swapped.
|
||||
|
||||
Examples:
|
||||
usb2512b@2c {
|
||||
@ -81,4 +83,6 @@ Examples:
|
||||
manufacturer = "Foo";
|
||||
product = "Foo-Bar";
|
||||
serial = "1234567890A";
|
||||
/* correct misplaced usb connectors on port 1,2 */
|
||||
swap-dx-lanes = <1 2>;
|
||||
};
|
||||
|
@ -34,7 +34,9 @@ $ echo 1 > /sys/bus/usb/devices/usbX/authorized_default
|
||||
By default, Wired USB devices are authorized by default to
|
||||
connect. Wireless USB hosts deauthorize by default all new connected
|
||||
devices (this is so because we need to do an authentication phase
|
||||
before authorizing).
|
||||
before authorizing). Writing "2" to the authorized_default attribute
|
||||
causes kernel to only authorize by default devices connected to internal
|
||||
USB ports.
|
||||
|
||||
|
||||
Example system lockdown (lame)
|
||||
|
@ -9178,6 +9178,14 @@ F: drivers/gpu/drm/armada/
|
||||
F: include/uapi/drm/armada_drm.h
|
||||
F: Documentation/devicetree/bindings/display/armada/
|
||||
|
||||
MARVELL ARMADA 3700 PHY DRIVERS
|
||||
M: Miquel Raynal <miquel.raynal@bootlin.com>
|
||||
S: Maintained
|
||||
F: drivers/phy/marvell/phy-mvebu-a3700-comphy.c
|
||||
F: drivers/phy/marvell/phy-mvebu-a3700-utmi.c
|
||||
F: Documentation/devicetree/bindings/phy/phy-mvebu-comphy.txt
|
||||
F: Documentation/devicetree/bindings/phy/phy-mvebu-utmi.txt
|
||||
|
||||
MARVELL CRYPTO DRIVER
|
||||
M: Boris Brezillon <bbrezillon@kernel.org>
|
||||
M: Arnaud Ebalard <arno@natisbad.org>
|
||||
|
@ -7,10 +7,37 @@
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/property.h>
|
||||
|
||||
static DEFINE_MUTEX(devcon_lock);
|
||||
static LIST_HEAD(devcon_list);
|
||||
|
||||
typedef void *(*devcon_match_fn_t)(struct device_connection *con, int ep,
|
||||
void *data);
|
||||
|
||||
static void *
|
||||
fwnode_graph_devcon_match(struct fwnode_handle *fwnode, const char *con_id,
|
||||
void *data, devcon_match_fn_t match)
|
||||
{
|
||||
struct device_connection con = { .id = con_id };
|
||||
struct fwnode_handle *ep;
|
||||
void *ret;
|
||||
|
||||
fwnode_graph_for_each_endpoint(fwnode, ep) {
|
||||
con.fwnode = fwnode_graph_get_remote_port_parent(ep);
|
||||
if (!fwnode_device_is_available(con.fwnode))
|
||||
continue;
|
||||
|
||||
ret = match(&con, -1, data);
|
||||
fwnode_handle_put(con.fwnode);
|
||||
if (ret) {
|
||||
fwnode_handle_put(ep);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* device_connection_find_match - Find physical connection to a device
|
||||
* @dev: Device with the connection
|
||||
@ -23,10 +50,9 @@ static LIST_HEAD(devcon_list);
|
||||
* caller is expecting to be returned.
|
||||
*/
|
||||
void *device_connection_find_match(struct device *dev, const char *con_id,
|
||||
void *data,
|
||||
void *(*match)(struct device_connection *con,
|
||||
int ep, void *data))
|
||||
void *data, devcon_match_fn_t match)
|
||||
{
|
||||
struct fwnode_handle *fwnode = dev_fwnode(dev);
|
||||
const char *devname = dev_name(dev);
|
||||
struct device_connection *con;
|
||||
void *ret = NULL;
|
||||
@ -35,6 +61,12 @@ void *device_connection_find_match(struct device *dev, const char *con_id,
|
||||
if (!match)
|
||||
return NULL;
|
||||
|
||||
if (fwnode) {
|
||||
ret = fwnode_graph_devcon_match(fwnode, con_id, data, match);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
mutex_lock(&devcon_lock);
|
||||
|
||||
list_for_each_entry(con, &devcon_list, list) {
|
||||
@ -75,12 +107,36 @@ static struct bus_type *generic_match_buses[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static int device_fwnode_match(struct device *dev, void *fwnode)
|
||||
{
|
||||
return dev_fwnode(dev) == fwnode;
|
||||
}
|
||||
|
||||
static void *device_connection_fwnode_match(struct device_connection *con)
|
||||
{
|
||||
struct bus_type *bus;
|
||||
struct device *dev;
|
||||
|
||||
for (bus = generic_match_buses[0]; bus; bus++) {
|
||||
dev = bus_find_device(bus, NULL, (void *)con->fwnode,
|
||||
device_fwnode_match);
|
||||
if (dev && !strncmp(dev_name(dev), con->id, strlen(con->id)))
|
||||
return dev;
|
||||
|
||||
put_device(dev);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* This tries to find the device from the most common bus types by name. */
|
||||
static void *generic_match(struct device_connection *con, int ep, void *data)
|
||||
{
|
||||
struct bus_type *bus;
|
||||
struct device *dev;
|
||||
|
||||
if (con->fwnode)
|
||||
return device_connection_fwnode_match(con);
|
||||
|
||||
for (bus = generic_match_buses[0]; bus; bus++) {
|
||||
dev = bus_find_device_by_name(bus, NULL, con->endpoint[ep]);
|
||||
if (dev)
|
||||
|
@ -78,8 +78,8 @@ struct sr_pcie_phy_core {
|
||||
static const u8 pipemux_table[] = {
|
||||
/* PIPEMUX = 0, EP 1x16 */
|
||||
0x00,
|
||||
/* PIPEMUX = 1, EP 2x8 */
|
||||
0x00,
|
||||
/* PIPEMUX = 1, EP 1x8 + RC 1x8, core 7 */
|
||||
0x80,
|
||||
/* PIPEMUX = 2, EP 4x4 */
|
||||
0x00,
|
||||
/* PIPEMUX = 3, RC 2x8, cores 0, 7 */
|
||||
|
@ -1,6 +1,7 @@
|
||||
#
|
||||
# Phy drivers for Cadence PHYs
|
||||
#
|
||||
|
||||
config PHY_CADENCE_DP
|
||||
tristate "Cadence MHDP DisplayPort PHY driver"
|
||||
depends on OF
|
||||
@ -9,9 +10,19 @@ config PHY_CADENCE_DP
|
||||
help
|
||||
Support for Cadence MHDP DisplayPort PHY.
|
||||
|
||||
config PHY_CADENCE_DPHY
|
||||
tristate "Cadence D-PHY Support"
|
||||
depends on HAS_IOMEM && OF
|
||||
select GENERIC_PHY
|
||||
select GENERIC_PHY_MIPI_DPHY
|
||||
help
|
||||
Choose this option if you have a Cadence D-PHY in your
|
||||
system. If M is selected, the module will be called
|
||||
cdns-dphy.
|
||||
|
||||
config PHY_CADENCE_SIERRA
|
||||
tristate "Cadence Sierra PHY Driver"
|
||||
depends on OF && HAS_IOMEM && RESET_CONTROLLER
|
||||
select GENERIC_PHY
|
||||
help
|
||||
Enable this to support the Cadence Sierra PHY driver
|
||||
Enable this to support the Cadence Sierra PHY driver
|
||||
|
@ -1,2 +1,3 @@
|
||||
obj-$(CONFIG_PHY_CADENCE_DP) += phy-cadence-dp.o
|
||||
obj-$(CONFIG_PHY_CADENCE_DPHY) += cdns-dphy.o
|
||||
obj-$(CONFIG_PHY_CADENCE_SIERRA) += phy-cadence-sierra.o
|
||||
|
391
drivers/phy/cadence/cdns-dphy.c
Normal file
391
drivers/phy/cadence/cdns-dphy.c
Normal file
@ -0,0 +1,391 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright: 2017-2018 Cadence Design Systems, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/phy/phy-mipi-dphy.h>
|
||||
|
||||
#define REG_WAKEUP_TIME_NS 800
|
||||
#define DPHY_PLL_RATE_HZ 108000000
|
||||
|
||||
/* DPHY registers */
|
||||
#define DPHY_PMA_CMN(reg) (reg)
|
||||
#define DPHY_PMA_LCLK(reg) (0x100 + (reg))
|
||||
#define DPHY_PMA_LDATA(lane, reg) (0x200 + ((lane) * 0x100) + (reg))
|
||||
#define DPHY_PMA_RCLK(reg) (0x600 + (reg))
|
||||
#define DPHY_PMA_RDATA(lane, reg) (0x700 + ((lane) * 0x100) + (reg))
|
||||
#define DPHY_PCS(reg) (0xb00 + (reg))
|
||||
|
||||
#define DPHY_CMN_SSM DPHY_PMA_CMN(0x20)
|
||||
#define DPHY_CMN_SSM_EN BIT(0)
|
||||
#define DPHY_CMN_TX_MODE_EN BIT(9)
|
||||
|
||||
#define DPHY_CMN_PWM DPHY_PMA_CMN(0x40)
|
||||
#define DPHY_CMN_PWM_DIV(x) ((x) << 20)
|
||||
#define DPHY_CMN_PWM_LOW(x) ((x) << 10)
|
||||
#define DPHY_CMN_PWM_HIGH(x) (x)
|
||||
|
||||
#define DPHY_CMN_FBDIV DPHY_PMA_CMN(0x4c)
|
||||
#define DPHY_CMN_FBDIV_VAL(low, high) (((high) << 11) | ((low) << 22))
|
||||
#define DPHY_CMN_FBDIV_FROM_REG (BIT(10) | BIT(21))
|
||||
|
||||
#define DPHY_CMN_OPIPDIV DPHY_PMA_CMN(0x50)
|
||||
#define DPHY_CMN_IPDIV_FROM_REG BIT(0)
|
||||
#define DPHY_CMN_IPDIV(x) ((x) << 1)
|
||||
#define DPHY_CMN_OPDIV_FROM_REG BIT(6)
|
||||
#define DPHY_CMN_OPDIV(x) ((x) << 7)
|
||||
|
||||
#define DPHY_PSM_CFG DPHY_PCS(0x4)
|
||||
#define DPHY_PSM_CFG_FROM_REG BIT(0)
|
||||
#define DPHY_PSM_CLK_DIV(x) ((x) << 1)
|
||||
|
||||
#define DSI_HBP_FRAME_OVERHEAD 12
|
||||
#define DSI_HSA_FRAME_OVERHEAD 14
|
||||
#define DSI_HFP_FRAME_OVERHEAD 6
|
||||
#define DSI_HSS_VSS_VSE_FRAME_OVERHEAD 4
|
||||
#define DSI_BLANKING_FRAME_OVERHEAD 6
|
||||
#define DSI_NULL_FRAME_OVERHEAD 6
|
||||
#define DSI_EOT_PKT_SIZE 4
|
||||
|
||||
struct cdns_dphy_cfg {
|
||||
u8 pll_ipdiv;
|
||||
u8 pll_opdiv;
|
||||
u16 pll_fbdiv;
|
||||
unsigned int nlanes;
|
||||
};
|
||||
|
||||
enum cdns_dphy_clk_lane_cfg {
|
||||
DPHY_CLK_CFG_LEFT_DRIVES_ALL = 0,
|
||||
DPHY_CLK_CFG_LEFT_DRIVES_RIGHT = 1,
|
||||
DPHY_CLK_CFG_LEFT_DRIVES_LEFT = 2,
|
||||
DPHY_CLK_CFG_RIGHT_DRIVES_ALL = 3,
|
||||
};
|
||||
|
||||
struct cdns_dphy;
|
||||
struct cdns_dphy_ops {
|
||||
int (*probe)(struct cdns_dphy *dphy);
|
||||
void (*remove)(struct cdns_dphy *dphy);
|
||||
void (*set_psm_div)(struct cdns_dphy *dphy, u8 div);
|
||||
void (*set_clk_lane_cfg)(struct cdns_dphy *dphy,
|
||||
enum cdns_dphy_clk_lane_cfg cfg);
|
||||
void (*set_pll_cfg)(struct cdns_dphy *dphy,
|
||||
const struct cdns_dphy_cfg *cfg);
|
||||
unsigned long (*get_wakeup_time_ns)(struct cdns_dphy *dphy);
|
||||
};
|
||||
|
||||
struct cdns_dphy {
|
||||
struct cdns_dphy_cfg cfg;
|
||||
void __iomem *regs;
|
||||
struct clk *psm_clk;
|
||||
struct clk *pll_ref_clk;
|
||||
const struct cdns_dphy_ops *ops;
|
||||
struct phy *phy;
|
||||
};
|
||||
|
||||
static int cdns_dsi_get_dphy_pll_cfg(struct cdns_dphy *dphy,
|
||||
struct cdns_dphy_cfg *cfg,
|
||||
struct phy_configure_opts_mipi_dphy *opts,
|
||||
unsigned int *dsi_hfp_ext)
|
||||
{
|
||||
unsigned long pll_ref_hz = clk_get_rate(dphy->pll_ref_clk);
|
||||
u64 dlane_bps;
|
||||
|
||||
memset(cfg, 0, sizeof(*cfg));
|
||||
|
||||
if (pll_ref_hz < 9600000 || pll_ref_hz >= 150000000)
|
||||
return -EINVAL;
|
||||
else if (pll_ref_hz < 19200000)
|
||||
cfg->pll_ipdiv = 1;
|
||||
else if (pll_ref_hz < 38400000)
|
||||
cfg->pll_ipdiv = 2;
|
||||
else if (pll_ref_hz < 76800000)
|
||||
cfg->pll_ipdiv = 4;
|
||||
else
|
||||
cfg->pll_ipdiv = 8;
|
||||
|
||||
dlane_bps = opts->hs_clk_rate;
|
||||
|
||||
if (dlane_bps > 2500000000UL || dlane_bps < 160000000UL)
|
||||
return -EINVAL;
|
||||
else if (dlane_bps >= 1250000000)
|
||||
cfg->pll_opdiv = 1;
|
||||
else if (dlane_bps >= 630000000)
|
||||
cfg->pll_opdiv = 2;
|
||||
else if (dlane_bps >= 320000000)
|
||||
cfg->pll_opdiv = 4;
|
||||
else if (dlane_bps >= 160000000)
|
||||
cfg->pll_opdiv = 8;
|
||||
|
||||
cfg->pll_fbdiv = DIV_ROUND_UP_ULL(dlane_bps * 2 * cfg->pll_opdiv *
|
||||
cfg->pll_ipdiv,
|
||||
pll_ref_hz);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdns_dphy_setup_psm(struct cdns_dphy *dphy)
|
||||
{
|
||||
unsigned long psm_clk_hz = clk_get_rate(dphy->psm_clk);
|
||||
unsigned long psm_div;
|
||||
|
||||
if (!psm_clk_hz || psm_clk_hz > 100000000)
|
||||
return -EINVAL;
|
||||
|
||||
psm_div = DIV_ROUND_CLOSEST(psm_clk_hz, 1000000);
|
||||
if (dphy->ops->set_psm_div)
|
||||
dphy->ops->set_psm_div(dphy, psm_div);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cdns_dphy_set_clk_lane_cfg(struct cdns_dphy *dphy,
|
||||
enum cdns_dphy_clk_lane_cfg cfg)
|
||||
{
|
||||
if (dphy->ops->set_clk_lane_cfg)
|
||||
dphy->ops->set_clk_lane_cfg(dphy, cfg);
|
||||
}
|
||||
|
||||
static void cdns_dphy_set_pll_cfg(struct cdns_dphy *dphy,
|
||||
const struct cdns_dphy_cfg *cfg)
|
||||
{
|
||||
if (dphy->ops->set_pll_cfg)
|
||||
dphy->ops->set_pll_cfg(dphy, cfg);
|
||||
}
|
||||
|
||||
static unsigned long cdns_dphy_get_wakeup_time_ns(struct cdns_dphy *dphy)
|
||||
{
|
||||
return dphy->ops->get_wakeup_time_ns(dphy);
|
||||
}
|
||||
|
||||
static unsigned long cdns_dphy_ref_get_wakeup_time_ns(struct cdns_dphy *dphy)
|
||||
{
|
||||
/* Default wakeup time is 800 ns (in a simulated environment). */
|
||||
return 800;
|
||||
}
|
||||
|
||||
static void cdns_dphy_ref_set_pll_cfg(struct cdns_dphy *dphy,
|
||||
const struct cdns_dphy_cfg *cfg)
|
||||
{
|
||||
u32 fbdiv_low, fbdiv_high;
|
||||
|
||||
fbdiv_low = (cfg->pll_fbdiv / 4) - 2;
|
||||
fbdiv_high = cfg->pll_fbdiv - fbdiv_low - 2;
|
||||
|
||||
writel(DPHY_CMN_IPDIV_FROM_REG | DPHY_CMN_OPDIV_FROM_REG |
|
||||
DPHY_CMN_IPDIV(cfg->pll_ipdiv) |
|
||||
DPHY_CMN_OPDIV(cfg->pll_opdiv),
|
||||
dphy->regs + DPHY_CMN_OPIPDIV);
|
||||
writel(DPHY_CMN_FBDIV_FROM_REG |
|
||||
DPHY_CMN_FBDIV_VAL(fbdiv_low, fbdiv_high),
|
||||
dphy->regs + DPHY_CMN_FBDIV);
|
||||
writel(DPHY_CMN_PWM_HIGH(6) | DPHY_CMN_PWM_LOW(0x101) |
|
||||
DPHY_CMN_PWM_DIV(0x8),
|
||||
dphy->regs + DPHY_CMN_PWM);
|
||||
}
|
||||
|
||||
static void cdns_dphy_ref_set_psm_div(struct cdns_dphy *dphy, u8 div)
|
||||
{
|
||||
writel(DPHY_PSM_CFG_FROM_REG | DPHY_PSM_CLK_DIV(div),
|
||||
dphy->regs + DPHY_PSM_CFG);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the reference implementation of DPHY hooks. Specific integration of
|
||||
* this IP may have to re-implement some of them depending on how they decided
|
||||
* to wire things in the SoC.
|
||||
*/
|
||||
static const struct cdns_dphy_ops ref_dphy_ops = {
|
||||
.get_wakeup_time_ns = cdns_dphy_ref_get_wakeup_time_ns,
|
||||
.set_pll_cfg = cdns_dphy_ref_set_pll_cfg,
|
||||
.set_psm_div = cdns_dphy_ref_set_psm_div,
|
||||
};
|
||||
|
||||
static int cdns_dphy_config_from_opts(struct phy *phy,
|
||||
struct phy_configure_opts_mipi_dphy *opts,
|
||||
struct cdns_dphy_cfg *cfg)
|
||||
{
|
||||
struct cdns_dphy *dphy = phy_get_drvdata(phy);
|
||||
unsigned int dsi_hfp_ext = 0;
|
||||
int ret;
|
||||
|
||||
ret = phy_mipi_dphy_config_validate(opts);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = cdns_dsi_get_dphy_pll_cfg(dphy, cfg,
|
||||
opts, &dsi_hfp_ext);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
opts->wakeup = cdns_dphy_get_wakeup_time_ns(dphy) / 1000;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdns_dphy_validate(struct phy *phy, enum phy_mode mode, int submode,
|
||||
union phy_configure_opts *opts)
|
||||
{
|
||||
struct cdns_dphy_cfg cfg = { 0 };
|
||||
|
||||
if (mode != PHY_MODE_MIPI_DPHY)
|
||||
return -EINVAL;
|
||||
|
||||
return cdns_dphy_config_from_opts(phy, &opts->mipi_dphy, &cfg);
|
||||
}
|
||||
|
||||
static int cdns_dphy_configure(struct phy *phy, union phy_configure_opts *opts)
|
||||
{
|
||||
struct cdns_dphy *dphy = phy_get_drvdata(phy);
|
||||
struct cdns_dphy_cfg cfg = { 0 };
|
||||
int ret;
|
||||
|
||||
ret = cdns_dphy_config_from_opts(phy, &opts->mipi_dphy, &cfg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Configure the internal PSM clk divider so that the DPHY has a
|
||||
* 1MHz clk (or something close).
|
||||
*/
|
||||
ret = cdns_dphy_setup_psm(dphy);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Configure attach clk lanes to data lanes: the DPHY has 2 clk lanes
|
||||
* and 8 data lanes, each clk lane can be attache different set of
|
||||
* data lanes. The 2 groups are named 'left' and 'right', so here we
|
||||
* just say that we want the 'left' clk lane to drive the 'left' data
|
||||
* lanes.
|
||||
*/
|
||||
cdns_dphy_set_clk_lane_cfg(dphy, DPHY_CLK_CFG_LEFT_DRIVES_LEFT);
|
||||
|
||||
/*
|
||||
* Configure the DPHY PLL that will be used to generate the TX byte
|
||||
* clk.
|
||||
*/
|
||||
cdns_dphy_set_pll_cfg(dphy, &cfg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdns_dphy_power_on(struct phy *phy)
|
||||
{
|
||||
struct cdns_dphy *dphy = phy_get_drvdata(phy);
|
||||
|
||||
clk_prepare_enable(dphy->psm_clk);
|
||||
clk_prepare_enable(dphy->pll_ref_clk);
|
||||
|
||||
/* Start TX state machine. */
|
||||
writel(DPHY_CMN_SSM_EN | DPHY_CMN_TX_MODE_EN,
|
||||
dphy->regs + DPHY_CMN_SSM);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdns_dphy_power_off(struct phy *phy)
|
||||
{
|
||||
struct cdns_dphy *dphy = phy_get_drvdata(phy);
|
||||
|
||||
clk_disable_unprepare(dphy->pll_ref_clk);
|
||||
clk_disable_unprepare(dphy->psm_clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct phy_ops cdns_dphy_ops = {
|
||||
.configure = cdns_dphy_configure,
|
||||
.validate = cdns_dphy_validate,
|
||||
.power_on = cdns_dphy_power_on,
|
||||
.power_off = cdns_dphy_power_off,
|
||||
};
|
||||
|
||||
static int cdns_dphy_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct phy_provider *phy_provider;
|
||||
struct cdns_dphy *dphy;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL);
|
||||
if (!dphy)
|
||||
return -ENOMEM;
|
||||
dev_set_drvdata(&pdev->dev, dphy);
|
||||
|
||||
dphy->ops = of_device_get_match_data(&pdev->dev);
|
||||
if (!dphy->ops)
|
||||
return -EINVAL;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
dphy->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(dphy->regs))
|
||||
return PTR_ERR(dphy->regs);
|
||||
|
||||
dphy->psm_clk = devm_clk_get(&pdev->dev, "psm");
|
||||
if (IS_ERR(dphy->psm_clk))
|
||||
return PTR_ERR(dphy->psm_clk);
|
||||
|
||||
dphy->pll_ref_clk = devm_clk_get(&pdev->dev, "pll_ref");
|
||||
if (IS_ERR(dphy->pll_ref_clk))
|
||||
return PTR_ERR(dphy->pll_ref_clk);
|
||||
|
||||
if (dphy->ops->probe) {
|
||||
ret = dphy->ops->probe(dphy);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
dphy->phy = devm_phy_create(&pdev->dev, NULL, &cdns_dphy_ops);
|
||||
if (IS_ERR(dphy->phy)) {
|
||||
dev_err(&pdev->dev, "failed to create PHY\n");
|
||||
if (dphy->ops->remove)
|
||||
dphy->ops->remove(dphy);
|
||||
return PTR_ERR(dphy->phy);
|
||||
}
|
||||
|
||||
phy_set_drvdata(dphy->phy, dphy);
|
||||
phy_provider = devm_of_phy_provider_register(&pdev->dev,
|
||||
of_phy_simple_xlate);
|
||||
|
||||
return PTR_ERR_OR_ZERO(phy_provider);
|
||||
}
|
||||
|
||||
static int cdns_dphy_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct cdns_dphy *dphy = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
if (dphy->ops->remove)
|
||||
dphy->ops->remove(dphy);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id cdns_dphy_of_match[] = {
|
||||
{ .compatible = "cdns,dphy", .data = &ref_dphy_ops },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cdns_dphy_of_match);
|
||||
|
||||
static struct platform_driver cdns_dphy_platform_driver = {
|
||||
.probe = cdns_dphy_probe,
|
||||
.remove = cdns_dphy_remove,
|
||||
.driver = {
|
||||
.name = "cdns-mipi-dphy",
|
||||
.of_match_table = cdns_dphy_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(cdns_dphy_platform_driver);
|
||||
|
||||
MODULE_AUTHOR("Maxime Ripard <maxime.ripard@bootlin.com>");
|
||||
MODULE_DESCRIPTION("Cadence MIPI D-PHY Driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -2,4 +2,4 @@ config PHY_FSL_IMX8MQ_USB
|
||||
tristate "Freescale i.MX8M USB3 PHY"
|
||||
depends on OF && HAS_IOMEM
|
||||
select GENERIC_PHY
|
||||
default SOC_IMX8MQ
|
||||
default ARCH_MXC && ARM64
|
||||
|
@ -21,6 +21,27 @@ config PHY_BERLIN_USB
|
||||
help
|
||||
Enable this to support the USB PHY on Marvell Berlin SoCs.
|
||||
|
||||
config PHY_MVEBU_A3700_COMPHY
|
||||
tristate "Marvell A3700 comphy driver"
|
||||
depends on ARCH_MVEBU || COMPILE_TEST
|
||||
depends on OF
|
||||
depends on HAVE_ARM_SMCCC
|
||||
default y
|
||||
select GENERIC_PHY
|
||||
help
|
||||
This driver allows to control the comphy, a hardware block providing
|
||||
shared serdes PHYs on Marvell Armada 3700. Its serdes lanes can be
|
||||
used by various controllers: Ethernet, SATA, USB3, PCIe.
|
||||
|
||||
config PHY_MVEBU_A3700_UTMI
|
||||
tristate "Marvell A3700 UTMI driver"
|
||||
depends on ARCH_MVEBU || COMPILE_TEST
|
||||
depends on OF
|
||||
default y
|
||||
select GENERIC_PHY
|
||||
help
|
||||
Enable this to support Marvell A3700 UTMI PHY driver.
|
||||
|
||||
config PHY_MVEBU_A38X_COMPHY
|
||||
tristate "Marvell Armada 38x comphy driver"
|
||||
depends on ARCH_MVEBU || COMPILE_TEST
|
||||
|
@ -2,6 +2,8 @@
|
||||
obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY) += phy-armada375-usb2.o
|
||||
obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.o
|
||||
obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.o
|
||||
obj-$(CONFIG_PHY_MVEBU_A3700_COMPHY) += phy-mvebu-a3700-comphy.o
|
||||
obj-$(CONFIG_PHY_MVEBU_A3700_UTMI) += phy-mvebu-a3700-utmi.o
|
||||
obj-$(CONFIG_PHY_MVEBU_A38X_COMPHY) += phy-armada38x-comphy.o
|
||||
obj-$(CONFIG_PHY_MVEBU_CP110_COMPHY) += phy-mvebu-cp110-comphy.o
|
||||
obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* USB cluster support for Armada 375 platform.
|
||||
*
|
||||
@ -5,10 +6,6 @@
|
||||
*
|
||||
* Gregory CLEMENT <gregory.clement@free-electrons.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2 or later. This program is licensed "as is"
|
||||
* without any warranty of any kind, whether express or implied.
|
||||
*
|
||||
* Armada 375 comes with an USB2 host and device controller and an
|
||||
* USB3 controller. The USB cluster control register allows to manage
|
||||
* common features of both USB controllers.
|
||||
@ -18,7 +15,6 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
@ -142,7 +138,6 @@ static const struct of_device_id of_usb_cluster_table[] = {
|
||||
{ .compatible = "marvell,armada-375-usb-cluster", },
|
||||
{ /* end of list */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, of_usb_cluster_table);
|
||||
|
||||
static struct platform_driver armada375_usb_phy_driver = {
|
||||
.probe = armada375_usb_phy_probe,
|
||||
@ -151,8 +146,4 @@ static struct platform_driver armada375_usb_phy_driver = {
|
||||
.name = "armada-375-usb-cluster",
|
||||
}
|
||||
};
|
||||
module_platform_driver(armada375_usb_phy_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Armada 375 USB cluster driver");
|
||||
MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
builtin_platform_driver(armada375_usb_phy_driver);
|
||||
|
318
drivers/phy/marvell/phy-mvebu-a3700-comphy.c
Normal file
318
drivers/phy/marvell/phy-mvebu-a3700-comphy.c
Normal file
@ -0,0 +1,318 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2018 Marvell
|
||||
*
|
||||
* Authors:
|
||||
* Evan Wang <xswang@marvell.com>
|
||||
* Miquèl Raynal <miquel.raynal@bootlin.com>
|
||||
*
|
||||
* Structure inspired from phy-mvebu-cp110-comphy.c written by Antoine Tenart.
|
||||
* SMC call initial support done by Grzegorz Jaszczyk.
|
||||
*/
|
||||
|
||||
#include <linux/arm-smccc.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define MVEBU_A3700_COMPHY_LANES 3
|
||||
#define MVEBU_A3700_COMPHY_PORTS 2
|
||||
|
||||
/* COMPHY Fast SMC function identifiers */
|
||||
#define COMPHY_SIP_POWER_ON 0x82000001
|
||||
#define COMPHY_SIP_POWER_OFF 0x82000002
|
||||
#define COMPHY_SIP_PLL_LOCK 0x82000003
|
||||
|
||||
#define COMPHY_FW_MODE_SATA 0x1
|
||||
#define COMPHY_FW_MODE_SGMII 0x2
|
||||
#define COMPHY_FW_MODE_HS_SGMII 0x3
|
||||
#define COMPHY_FW_MODE_USB3H 0x4
|
||||
#define COMPHY_FW_MODE_USB3D 0x5
|
||||
#define COMPHY_FW_MODE_PCIE 0x6
|
||||
#define COMPHY_FW_MODE_RXAUI 0x7
|
||||
#define COMPHY_FW_MODE_XFI 0x8
|
||||
#define COMPHY_FW_MODE_SFI 0x9
|
||||
#define COMPHY_FW_MODE_USB3 0xa
|
||||
|
||||
#define COMPHY_FW_SPEED_1_25G 0 /* SGMII 1G */
|
||||
#define COMPHY_FW_SPEED_2_5G 1
|
||||
#define COMPHY_FW_SPEED_3_125G 2 /* SGMII 2.5G */
|
||||
#define COMPHY_FW_SPEED_5G 3
|
||||
#define COMPHY_FW_SPEED_5_15625G 4 /* XFI 5G */
|
||||
#define COMPHY_FW_SPEED_6G 5
|
||||
#define COMPHY_FW_SPEED_10_3125G 6 /* XFI 10G */
|
||||
#define COMPHY_FW_SPEED_MAX 0x3F
|
||||
|
||||
#define COMPHY_FW_MODE(mode) ((mode) << 12)
|
||||
#define COMPHY_FW_NET(mode, idx, speed) (COMPHY_FW_MODE(mode) | \
|
||||
((idx) << 8) | \
|
||||
((speed) << 2))
|
||||
#define COMPHY_FW_PCIE(mode, idx, speed, width) (COMPHY_FW_NET(mode, idx, speed) | \
|
||||
((width) << 18))
|
||||
|
||||
struct mvebu_a3700_comphy_conf {
|
||||
unsigned int lane;
|
||||
enum phy_mode mode;
|
||||
int submode;
|
||||
unsigned int port;
|
||||
u32 fw_mode;
|
||||
};
|
||||
|
||||
#define MVEBU_A3700_COMPHY_CONF(_lane, _mode, _smode, _port, _fw) \
|
||||
{ \
|
||||
.lane = _lane, \
|
||||
.mode = _mode, \
|
||||
.submode = _smode, \
|
||||
.port = _port, \
|
||||
.fw_mode = _fw, \
|
||||
}
|
||||
|
||||
#define MVEBU_A3700_COMPHY_CONF_GEN(_lane, _mode, _port, _fw) \
|
||||
MVEBU_A3700_COMPHY_CONF(_lane, _mode, PHY_INTERFACE_MODE_NA, _port, _fw)
|
||||
|
||||
#define MVEBU_A3700_COMPHY_CONF_ETH(_lane, _smode, _port, _fw) \
|
||||
MVEBU_A3700_COMPHY_CONF(_lane, PHY_MODE_ETHERNET, _smode, _port, _fw)
|
||||
|
||||
static const struct mvebu_a3700_comphy_conf mvebu_a3700_comphy_modes[] = {
|
||||
/* lane 0 */
|
||||
MVEBU_A3700_COMPHY_CONF_GEN(0, PHY_MODE_USB_HOST_SS, 0,
|
||||
COMPHY_FW_MODE_USB3H),
|
||||
MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_SGMII, 1,
|
||||
COMPHY_FW_MODE_SGMII),
|
||||
MVEBU_A3700_COMPHY_CONF_ETH(0, PHY_INTERFACE_MODE_2500BASEX, 1,
|
||||
COMPHY_FW_MODE_HS_SGMII),
|
||||
/* lane 1 */
|
||||
MVEBU_A3700_COMPHY_CONF_GEN(1, PHY_MODE_PCIE, 0,
|
||||
COMPHY_FW_MODE_PCIE),
|
||||
MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_SGMII, 0,
|
||||
COMPHY_FW_MODE_SGMII),
|
||||
MVEBU_A3700_COMPHY_CONF_ETH(1, PHY_INTERFACE_MODE_2500BASEX, 0,
|
||||
COMPHY_FW_MODE_HS_SGMII),
|
||||
/* lane 2 */
|
||||
MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_SATA, 0,
|
||||
COMPHY_FW_MODE_SATA),
|
||||
MVEBU_A3700_COMPHY_CONF_GEN(2, PHY_MODE_USB_HOST_SS, 0,
|
||||
COMPHY_FW_MODE_USB3H),
|
||||
};
|
||||
|
||||
struct mvebu_a3700_comphy_lane {
|
||||
struct device *dev;
|
||||
unsigned int id;
|
||||
enum phy_mode mode;
|
||||
int submode;
|
||||
int port;
|
||||
};
|
||||
|
||||
static int mvebu_a3700_comphy_smc(unsigned long function, unsigned long lane,
|
||||
unsigned long mode)
|
||||
{
|
||||
struct arm_smccc_res res;
|
||||
|
||||
arm_smccc_smc(function, lane, mode, 0, 0, 0, 0, 0, &res);
|
||||
|
||||
return res.a0;
|
||||
}
|
||||
|
||||
static int mvebu_a3700_comphy_get_fw_mode(int lane, int port,
|
||||
enum phy_mode mode,
|
||||
int submode)
|
||||
{
|
||||
int i, n = ARRAY_SIZE(mvebu_a3700_comphy_modes);
|
||||
|
||||
/* Unused PHY mux value is 0x0 */
|
||||
if (mode == PHY_MODE_INVALID)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if (mvebu_a3700_comphy_modes[i].lane == lane &&
|
||||
mvebu_a3700_comphy_modes[i].port == port &&
|
||||
mvebu_a3700_comphy_modes[i].mode == mode &&
|
||||
mvebu_a3700_comphy_modes[i].submode == submode)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == n)
|
||||
return -EINVAL;
|
||||
|
||||
return mvebu_a3700_comphy_modes[i].fw_mode;
|
||||
}
|
||||
|
||||
static int mvebu_a3700_comphy_set_mode(struct phy *phy, enum phy_mode mode,
|
||||
int submode)
|
||||
{
|
||||
struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy);
|
||||
int fw_mode;
|
||||
|
||||
if (submode == PHY_INTERFACE_MODE_1000BASEX)
|
||||
submode = PHY_INTERFACE_MODE_SGMII;
|
||||
|
||||
fw_mode = mvebu_a3700_comphy_get_fw_mode(lane->id, lane->port, mode,
|
||||
submode);
|
||||
if (fw_mode < 0) {
|
||||
dev_err(lane->dev, "invalid COMPHY mode\n");
|
||||
return fw_mode;
|
||||
}
|
||||
|
||||
/* Just remember the mode, ->power_on() will do the real setup */
|
||||
lane->mode = mode;
|
||||
lane->submode = submode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mvebu_a3700_comphy_power_on(struct phy *phy)
|
||||
{
|
||||
struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy);
|
||||
u32 fw_param;
|
||||
int fw_mode;
|
||||
|
||||
fw_mode = mvebu_a3700_comphy_get_fw_mode(lane->id, lane->port,
|
||||
lane->mode, lane->submode);
|
||||
if (fw_mode < 0) {
|
||||
dev_err(lane->dev, "invalid COMPHY mode\n");
|
||||
return fw_mode;
|
||||
}
|
||||
|
||||
switch (lane->mode) {
|
||||
case PHY_MODE_USB_HOST_SS:
|
||||
dev_dbg(lane->dev, "set lane %d to USB3 host mode\n", lane->id);
|
||||
fw_param = COMPHY_FW_MODE(fw_mode);
|
||||
break;
|
||||
case PHY_MODE_SATA:
|
||||
dev_dbg(lane->dev, "set lane %d to SATA mode\n", lane->id);
|
||||
fw_param = COMPHY_FW_MODE(fw_mode);
|
||||
break;
|
||||
case PHY_MODE_ETHERNET:
|
||||
switch (lane->submode) {
|
||||
case PHY_INTERFACE_MODE_SGMII:
|
||||
dev_dbg(lane->dev, "set lane %d to SGMII mode\n",
|
||||
lane->id);
|
||||
fw_param = COMPHY_FW_NET(fw_mode, lane->port,
|
||||
COMPHY_FW_SPEED_1_25G);
|
||||
break;
|
||||
case PHY_INTERFACE_MODE_2500BASEX:
|
||||
dev_dbg(lane->dev, "set lane %d to HS SGMII mode\n",
|
||||
lane->id);
|
||||
fw_param = COMPHY_FW_NET(fw_mode, lane->port,
|
||||
COMPHY_FW_SPEED_3_125G);
|
||||
break;
|
||||
default:
|
||||
dev_err(lane->dev, "unsupported PHY submode (%d)\n",
|
||||
lane->submode);
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
break;
|
||||
case PHY_MODE_PCIE:
|
||||
dev_dbg(lane->dev, "set lane %d to PCIe mode\n", lane->id);
|
||||
fw_param = COMPHY_FW_PCIE(fw_mode, lane->port,
|
||||
COMPHY_FW_SPEED_5G,
|
||||
phy->attrs.bus_width);
|
||||
break;
|
||||
default:
|
||||
dev_err(lane->dev, "unsupported PHY mode (%d)\n", lane->mode);
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
return mvebu_a3700_comphy_smc(COMPHY_SIP_POWER_ON, lane->id, fw_param);
|
||||
}
|
||||
|
||||
static int mvebu_a3700_comphy_power_off(struct phy *phy)
|
||||
{
|
||||
struct mvebu_a3700_comphy_lane *lane = phy_get_drvdata(phy);
|
||||
|
||||
return mvebu_a3700_comphy_smc(COMPHY_SIP_POWER_OFF, lane->id, 0);
|
||||
}
|
||||
|
||||
static const struct phy_ops mvebu_a3700_comphy_ops = {
|
||||
.power_on = mvebu_a3700_comphy_power_on,
|
||||
.power_off = mvebu_a3700_comphy_power_off,
|
||||
.set_mode = mvebu_a3700_comphy_set_mode,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static struct phy *mvebu_a3700_comphy_xlate(struct device *dev,
|
||||
struct of_phandle_args *args)
|
||||
{
|
||||
struct mvebu_a3700_comphy_lane *lane;
|
||||
struct phy *phy;
|
||||
|
||||
if (WARN_ON(args->args[0] >= MVEBU_A3700_COMPHY_PORTS))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
phy = of_phy_simple_xlate(dev, args);
|
||||
if (IS_ERR(phy))
|
||||
return phy;
|
||||
|
||||
lane = phy_get_drvdata(phy);
|
||||
lane->port = args->args[0];
|
||||
|
||||
return phy;
|
||||
}
|
||||
|
||||
static int mvebu_a3700_comphy_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct phy_provider *provider;
|
||||
struct device_node *child;
|
||||
|
||||
for_each_available_child_of_node(pdev->dev.of_node, child) {
|
||||
struct mvebu_a3700_comphy_lane *lane;
|
||||
struct phy *phy;
|
||||
int ret;
|
||||
u32 lane_id;
|
||||
|
||||
ret = of_property_read_u32(child, "reg", &lane_id);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "missing 'reg' property (%d)\n",
|
||||
ret);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (lane_id >= MVEBU_A3700_COMPHY_LANES) {
|
||||
dev_err(&pdev->dev, "invalid 'reg' property\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
lane = devm_kzalloc(&pdev->dev, sizeof(*lane), GFP_KERNEL);
|
||||
if (!lane)
|
||||
return -ENOMEM;
|
||||
|
||||
phy = devm_phy_create(&pdev->dev, child,
|
||||
&mvebu_a3700_comphy_ops);
|
||||
if (IS_ERR(phy))
|
||||
return PTR_ERR(phy);
|
||||
|
||||
lane->dev = &pdev->dev;
|
||||
lane->mode = PHY_MODE_INVALID;
|
||||
lane->submode = PHY_INTERFACE_MODE_NA;
|
||||
lane->id = lane_id;
|
||||
lane->port = -1;
|
||||
phy_set_drvdata(phy, lane);
|
||||
}
|
||||
|
||||
provider = devm_of_phy_provider_register(&pdev->dev,
|
||||
mvebu_a3700_comphy_xlate);
|
||||
return PTR_ERR_OR_ZERO(provider);
|
||||
}
|
||||
|
||||
static const struct of_device_id mvebu_a3700_comphy_of_match_table[] = {
|
||||
{ .compatible = "marvell,comphy-a3700" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mvebu_a3700_comphy_of_match_table);
|
||||
|
||||
static struct platform_driver mvebu_a3700_comphy_driver = {
|
||||
.probe = mvebu_a3700_comphy_probe,
|
||||
.driver = {
|
||||
.name = "mvebu-a3700-comphy",
|
||||
.of_match_table = mvebu_a3700_comphy_of_match_table,
|
||||
},
|
||||
};
|
||||
module_platform_driver(mvebu_a3700_comphy_driver);
|
||||
|
||||
MODULE_AUTHOR("Miquèl Raynal <miquel.raynal@bootlin.com>");
|
||||
MODULE_DESCRIPTION("Common PHY driver for A3700");
|
||||
MODULE_LICENSE("GPL v2");
|
278
drivers/phy/marvell/phy-mvebu-a3700-utmi.c
Normal file
278
drivers/phy/marvell/phy-mvebu-a3700-utmi.c
Normal file
@ -0,0 +1,278 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2018 Marvell
|
||||
*
|
||||
* Authors:
|
||||
* Igal Liberman <igall@marvell.com>
|
||||
* Miquèl Raynal <miquel.raynal@bootlin.com>
|
||||
*
|
||||
* Marvell A3700 UTMI PHY driver
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
/* Armada 3700 UTMI PHY registers */
|
||||
#define USB2_PHY_PLL_CTRL_REG0 0x0
|
||||
#define PLL_REF_DIV_OFF 0
|
||||
#define PLL_REF_DIV_MASK GENMASK(6, 0)
|
||||
#define PLL_REF_DIV_5 5
|
||||
#define PLL_FB_DIV_OFF 16
|
||||
#define PLL_FB_DIV_MASK GENMASK(24, 16)
|
||||
#define PLL_FB_DIV_96 96
|
||||
#define PLL_SEL_LPFR_OFF 28
|
||||
#define PLL_SEL_LPFR_MASK GENMASK(29, 28)
|
||||
#define PLL_READY BIT(31)
|
||||
#define USB2_PHY_CAL_CTRL 0x8
|
||||
#define PHY_PLLCAL_DONE BIT(31)
|
||||
#define PHY_IMPCAL_DONE BIT(23)
|
||||
#define USB2_RX_CHAN_CTRL1 0x18
|
||||
#define USB2PHY_SQCAL_DONE BIT(31)
|
||||
#define USB2_PHY_OTG_CTRL 0x34
|
||||
#define PHY_PU_OTG BIT(4)
|
||||
#define USB2_PHY_CHRGR_DETECT 0x38
|
||||
#define PHY_CDP_EN BIT(2)
|
||||
#define PHY_DCP_EN BIT(3)
|
||||
#define PHY_PD_EN BIT(4)
|
||||
#define PHY_PU_CHRG_DTC BIT(5)
|
||||
#define PHY_CDP_DM_AUTO BIT(7)
|
||||
#define PHY_ENSWITCH_DP BIT(12)
|
||||
#define PHY_ENSWITCH_DM BIT(13)
|
||||
|
||||
/* Armada 3700 USB miscellaneous registers */
|
||||
#define USB2_PHY_CTRL(usb32) (usb32 ? 0x20 : 0x4)
|
||||
#define RB_USB2PHY_PU BIT(0)
|
||||
#define USB2_DP_PULLDN_DEV_MODE BIT(5)
|
||||
#define USB2_DM_PULLDN_DEV_MODE BIT(6)
|
||||
#define RB_USB2PHY_SUSPM(usb32) (usb32 ? BIT(14) : BIT(7))
|
||||
|
||||
#define PLL_LOCK_DELAY_US 10000
|
||||
#define PLL_LOCK_TIMEOUT_US 1000000
|
||||
|
||||
/**
|
||||
* struct mvebu_a3700_utmi_caps - PHY capabilities
|
||||
*
|
||||
* @usb32: Flag indicating which PHY is in use (impacts the register map):
|
||||
* - The UTMI PHY wired to the USB3/USB2 controller (otg)
|
||||
* - The UTMI PHY wired to the USB2 controller (host only)
|
||||
* @ops: PHY operations
|
||||
*/
|
||||
struct mvebu_a3700_utmi_caps {
|
||||
int usb32;
|
||||
const struct phy_ops *ops;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mvebu_a3700_utmi - PHY driver data
|
||||
*
|
||||
* @regs: PHY registers
|
||||
* @usb_mis: Regmap with USB miscellaneous registers including PHY ones
|
||||
* @caps: PHY capabilities
|
||||
* @phy: PHY handle
|
||||
*/
|
||||
struct mvebu_a3700_utmi {
|
||||
void __iomem *regs;
|
||||
struct regmap *usb_misc;
|
||||
const struct mvebu_a3700_utmi_caps *caps;
|
||||
struct phy *phy;
|
||||
};
|
||||
|
||||
static int mvebu_a3700_utmi_phy_power_on(struct phy *phy)
|
||||
{
|
||||
struct mvebu_a3700_utmi *utmi = phy_get_drvdata(phy);
|
||||
struct device *dev = &phy->dev;
|
||||
int usb32 = utmi->caps->usb32;
|
||||
int ret = 0;
|
||||
u32 reg;
|
||||
|
||||
/*
|
||||
* Setup PLL. 40MHz clock used to be the default, being 25MHz now.
|
||||
* See "PLL Settings for Typical REFCLK" table.
|
||||
*/
|
||||
reg = readl(utmi->regs + USB2_PHY_PLL_CTRL_REG0);
|
||||
reg &= ~(PLL_REF_DIV_MASK | PLL_FB_DIV_MASK | PLL_SEL_LPFR_MASK);
|
||||
reg |= (PLL_REF_DIV_5 << PLL_REF_DIV_OFF) |
|
||||
(PLL_FB_DIV_96 << PLL_FB_DIV_OFF);
|
||||
writel(reg, utmi->regs + USB2_PHY_PLL_CTRL_REG0);
|
||||
|
||||
/* Enable PHY pull up and disable USB2 suspend */
|
||||
regmap_update_bits(utmi->usb_misc, USB2_PHY_CTRL(usb32),
|
||||
RB_USB2PHY_SUSPM(usb32) | RB_USB2PHY_PU,
|
||||
RB_USB2PHY_SUSPM(usb32) | RB_USB2PHY_PU);
|
||||
|
||||
if (usb32) {
|
||||
/* Power up OTG module */
|
||||
reg = readl(utmi->regs + USB2_PHY_OTG_CTRL);
|
||||
reg |= PHY_PU_OTG;
|
||||
writel(reg, utmi->regs + USB2_PHY_OTG_CTRL);
|
||||
|
||||
/* Disable PHY charger detection */
|
||||
reg = readl(utmi->regs + USB2_PHY_CHRGR_DETECT);
|
||||
reg &= ~(PHY_CDP_EN | PHY_DCP_EN | PHY_PD_EN | PHY_PU_CHRG_DTC |
|
||||
PHY_CDP_DM_AUTO | PHY_ENSWITCH_DP | PHY_ENSWITCH_DM);
|
||||
writel(reg, utmi->regs + USB2_PHY_CHRGR_DETECT);
|
||||
|
||||
/* Disable PHY DP/DM pull-down (used for device mode) */
|
||||
regmap_update_bits(utmi->usb_misc, USB2_PHY_CTRL(usb32),
|
||||
USB2_DP_PULLDN_DEV_MODE |
|
||||
USB2_DM_PULLDN_DEV_MODE, 0);
|
||||
}
|
||||
|
||||
/* Wait for PLL calibration */
|
||||
ret = readl_poll_timeout(utmi->regs + USB2_PHY_CAL_CTRL, reg,
|
||||
reg & PHY_PLLCAL_DONE,
|
||||
PLL_LOCK_DELAY_US, PLL_LOCK_TIMEOUT_US);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to end USB2 PLL calibration\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Wait for impedance calibration */
|
||||
ret = readl_poll_timeout(utmi->regs + USB2_PHY_CAL_CTRL, reg,
|
||||
reg & PHY_IMPCAL_DONE,
|
||||
PLL_LOCK_DELAY_US, PLL_LOCK_TIMEOUT_US);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to end USB2 impedance calibration\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Wait for squelch calibration */
|
||||
ret = readl_poll_timeout(utmi->regs + USB2_RX_CHAN_CTRL1, reg,
|
||||
reg & USB2PHY_SQCAL_DONE,
|
||||
PLL_LOCK_DELAY_US, PLL_LOCK_TIMEOUT_US);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to end USB2 unknown calibration\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Wait for PLL to be locked */
|
||||
ret = readl_poll_timeout(utmi->regs + USB2_PHY_PLL_CTRL_REG0, reg,
|
||||
reg & PLL_READY,
|
||||
PLL_LOCK_DELAY_US, PLL_LOCK_TIMEOUT_US);
|
||||
if (ret)
|
||||
dev_err(dev, "Failed to lock USB2 PLL\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mvebu_a3700_utmi_phy_power_off(struct phy *phy)
|
||||
{
|
||||
struct mvebu_a3700_utmi *utmi = phy_get_drvdata(phy);
|
||||
int usb32 = utmi->caps->usb32;
|
||||
u32 reg;
|
||||
|
||||
/* Disable PHY pull-up and enable USB2 suspend */
|
||||
reg = readl(utmi->regs + USB2_PHY_CTRL(usb32));
|
||||
reg &= ~(RB_USB2PHY_PU | RB_USB2PHY_SUSPM(usb32));
|
||||
writel(reg, utmi->regs + USB2_PHY_CTRL(usb32));
|
||||
|
||||
/* Power down OTG module */
|
||||
if (usb32) {
|
||||
reg = readl(utmi->regs + USB2_PHY_OTG_CTRL);
|
||||
reg &= ~PHY_PU_OTG;
|
||||
writel(reg, utmi->regs + USB2_PHY_OTG_CTRL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct phy_ops mvebu_a3700_utmi_phy_ops = {
|
||||
.power_on = mvebu_a3700_utmi_phy_power_on,
|
||||
.power_off = mvebu_a3700_utmi_phy_power_off,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct mvebu_a3700_utmi_caps mvebu_a3700_utmi_otg_phy_caps = {
|
||||
.usb32 = true,
|
||||
.ops = &mvebu_a3700_utmi_phy_ops,
|
||||
};
|
||||
|
||||
static const struct mvebu_a3700_utmi_caps mvebu_a3700_utmi_host_phy_caps = {
|
||||
.usb32 = false,
|
||||
.ops = &mvebu_a3700_utmi_phy_ops,
|
||||
};
|
||||
|
||||
static const struct of_device_id mvebu_a3700_utmi_of_match[] = {
|
||||
{
|
||||
.compatible = "marvell,a3700-utmi-otg-phy",
|
||||
.data = &mvebu_a3700_utmi_otg_phy_caps,
|
||||
},
|
||||
{
|
||||
.compatible = "marvell,a3700-utmi-host-phy",
|
||||
.data = &mvebu_a3700_utmi_host_phy_caps,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mvebu_a3700_utmi_of_match);
|
||||
|
||||
static int mvebu_a3700_utmi_phy_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct mvebu_a3700_utmi *utmi;
|
||||
struct phy_provider *provider;
|
||||
struct resource *res;
|
||||
|
||||
utmi = devm_kzalloc(dev, sizeof(*utmi), GFP_KERNEL);
|
||||
if (!utmi)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Get UTMI memory region */
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(dev, "Missing UTMI PHY memory resource\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
utmi->regs = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(utmi->regs))
|
||||
return PTR_ERR(utmi->regs);
|
||||
|
||||
/* Get miscellaneous Host/PHY region */
|
||||
utmi->usb_misc = syscon_regmap_lookup_by_phandle(dev->of_node,
|
||||
"marvell,usb-misc-reg");
|
||||
if (IS_ERR(utmi->usb_misc)) {
|
||||
dev_err(dev,
|
||||
"Missing USB misc purpose system controller\n");
|
||||
return PTR_ERR(utmi->usb_misc);
|
||||
}
|
||||
|
||||
/* Retrieve PHY capabilities */
|
||||
utmi->caps = of_device_get_match_data(dev);
|
||||
|
||||
/* Instantiate the PHY */
|
||||
utmi->phy = devm_phy_create(dev, NULL, utmi->caps->ops);
|
||||
if (IS_ERR(utmi->phy)) {
|
||||
dev_err(dev, "Failed to create the UTMI PHY\n");
|
||||
return PTR_ERR(utmi->phy);
|
||||
}
|
||||
|
||||
phy_set_drvdata(utmi->phy, utmi);
|
||||
|
||||
/* Ensure the PHY is powered off */
|
||||
utmi->caps->ops->power_off(utmi->phy);
|
||||
|
||||
provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||
|
||||
return PTR_ERR_OR_ZERO(provider);
|
||||
}
|
||||
|
||||
static struct platform_driver mvebu_a3700_utmi_driver = {
|
||||
.probe = mvebu_a3700_utmi_phy_probe,
|
||||
.driver = {
|
||||
.name = "mvebu-a3700-utmi-phy",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = mvebu_a3700_utmi_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(mvebu_a3700_utmi_driver);
|
||||
|
||||
MODULE_AUTHOR("Igal Liberman <igall@marvell.com>");
|
||||
MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com>");
|
||||
MODULE_DESCRIPTION("Marvell EBU A3700 UTMI PHY driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -580,8 +580,6 @@ static struct phy *mvebu_comphy_xlate(struct device *dev,
|
||||
return phy;
|
||||
|
||||
lane = phy_get_drvdata(phy);
|
||||
if (lane->port >= 0)
|
||||
return ERR_PTR(-EBUSY);
|
||||
lane->port = args->args[0];
|
||||
|
||||
return phy;
|
||||
|
@ -10,7 +10,7 @@
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/io.h>
|
||||
@ -122,7 +122,6 @@ static const struct of_device_id phy_mvebu_sata_of_match[] = {
|
||||
{ .compatible = "marvell,mvebu-sata-phy" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, phy_mvebu_sata_of_match);
|
||||
|
||||
static struct platform_driver phy_mvebu_sata_driver = {
|
||||
.probe = phy_mvebu_sata_probe,
|
||||
@ -131,8 +130,4 @@ static struct platform_driver phy_mvebu_sata_driver = {
|
||||
.of_match_table = phy_mvebu_sata_of_match,
|
||||
}
|
||||
};
|
||||
module_platform_driver(phy_mvebu_sata_driver);
|
||||
|
||||
MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>");
|
||||
MODULE_DESCRIPTION("Marvell MVEBU SATA PHY driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
builtin_platform_driver(phy_mvebu_sata_driver);
|
||||
|
@ -65,12 +65,12 @@ int phy_mipi_dphy_get_default_config(unsigned long pixel_clock,
|
||||
*/
|
||||
cfg->hs_trail = max(4 * 8 * ui, 60000 + 4 * 4 * ui);
|
||||
|
||||
cfg->init = 100000000;
|
||||
cfg->init = 100;
|
||||
cfg->lpx = 60000;
|
||||
cfg->ta_get = 5 * cfg->lpx;
|
||||
cfg->ta_go = 4 * cfg->lpx;
|
||||
cfg->ta_sure = 2 * cfg->lpx;
|
||||
cfg->wakeup = 1000000000;
|
||||
cfg->wakeup = 1000;
|
||||
|
||||
cfg->hs_clk_rate = hs_clk_rate;
|
||||
cfg->lanes = lanes;
|
||||
@ -143,7 +143,7 @@ int phy_mipi_dphy_config_validate(struct phy_configure_opts_mipi_dphy *cfg)
|
||||
if (cfg->hs_trail < max(8 * ui, 60000 + 4 * ui))
|
||||
return -EINVAL;
|
||||
|
||||
if (cfg->init < 100000000)
|
||||
if (cfg->init < 100)
|
||||
return -EINVAL;
|
||||
|
||||
if (cfg->lpx < 50000)
|
||||
@ -158,7 +158,7 @@ int phy_mipi_dphy_config_validate(struct phy_configure_opts_mipi_dphy *cfg)
|
||||
if (cfg->ta_sure < cfg->lpx || cfg->ta_sure > (2 * cfg->lpx))
|
||||
return -EINVAL;
|
||||
|
||||
if (cfg->wakeup < 1000000000)
|
||||
if (cfg->wakeup < 1000)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
|
@ -1112,14 +1112,4 @@ static int __init phy_core_init(void)
|
||||
|
||||
return 0;
|
||||
}
|
||||
module_init(phy_core_init);
|
||||
|
||||
static void __exit phy_core_exit(void)
|
||||
{
|
||||
class_destroy(phy_class);
|
||||
}
|
||||
module_exit(phy_core_exit);
|
||||
|
||||
MODULE_DESCRIPTION("Generic PHY Framework");
|
||||
MODULE_AUTHOR("Kishon Vijay Abraham I <kishon@ti.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
device_initcall(phy_core_init);
|
||||
|
@ -687,6 +687,116 @@ static const struct qmp_phy_init_tbl sdm845_ufsphy_pcs_tbl[] = {
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_MULTI_LANE_CTRL1, 0x02),
|
||||
};
|
||||
|
||||
static const struct qmp_phy_init_tbl msm8998_usb3_serdes_tbl[] = {
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x04),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0x14),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x06),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_RESETSM_CNTRL2, 0x08),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_CONFIG, 0x06),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SVS_MODE_CLK_SEL, 0x01),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_HSCLK_SEL, 0x80),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_DEC_START_MODE0, 0x82),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START1_MODE0, 0xab),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START2_MODE0, 0xea),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START3_MODE0, 0x02),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CP_CTRL_MODE0, 0x06),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_RCTRL_MODE0, 0x16),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_CCTRL_MODE0, 0x36),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0, 0x3f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE2_MODE0, 0x01),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE1_MODE0, 0xc9),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORECLK_DIV_MODE0, 0x0a),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP3_MODE0, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE0, 0x34),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE0, 0x15),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_EN, 0x04),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORE_CLK_EN, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_CFG, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_BG_TIMER, 0x0a),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x07),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_INITVAL, 0x80),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_MODE, 0x01),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_EN_CENTER, 0x01),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER1, 0x31),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER2, 0x01),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER1, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER2, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE1, 0x85),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE2, 0x07),
|
||||
};
|
||||
|
||||
static const struct qmp_phy_init_tbl msm8998_usb3_tx_tbl[] = {
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_TX_HIGHZ_DRVR_EN, 0x10),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_TX_RCV_DETECT_LVL_2, 0x12),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_TX_LANE_MODE_1, 0x16),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x00),
|
||||
};
|
||||
|
||||
static const struct qmp_phy_init_tbl msm8998_usb3_rx_tbl[] = {
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0f),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x4e),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x18),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x07),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x43),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x1c),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x75),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_HIGH, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x80),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FO_GAIN, 0x0a),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_GAIN, 0x06),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_ENABLES, 0x00),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_RX_VGA_CAL_CNTRL2, 0x03),
|
||||
QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_MODE_00, 0x05),
|
||||
};
|
||||
|
||||
static const struct qmp_phy_init_tbl msm8998_usb3_pcs_tbl[] = {
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL2, 0x83),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_L, 0x09),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNT_VAL_H_TOL, 0xa2),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_MAN_CODE, 0x40),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_FLL_CNTRL1, 0x02),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG1, 0xd1),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG2, 0x1f),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_LOCK_DETECT_CONFIG3, 0x47),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_POWER_STATE_CONFIG2, 0x1b),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V0, 0x9f),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V1, 0x9f),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V2, 0xb7),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V3, 0x4e),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_V4, 0x65),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXMGN_LS, 0x6b),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V0, 0x15),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V0, 0x0d),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TX_LARGE_AMP_DRV_LVL, 0x15),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V1, 0x0d),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V2, 0x15),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V2, 0x0d),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V3, 0x15),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V3, 0x0d),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_V4, 0x15),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V4, 0x0d),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M6DB_LS, 0x15),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_LS, 0x0d),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RATE_SLEW_CNTRL, 0x02),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK, 0x04),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TSYNC_RSYNC_TIME, 0x44),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_L, 0xe7),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_P1U2_H, 0x03),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_L, 0x40),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RCVR_DTCT_DLY_U3_H, 0x00),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0x8a),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_WAIT_TIME, 0x75),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_LFPS_TX_ECSTART_EQTLOCK, 0x86),
|
||||
QMP_PHY_INIT_CFG(QPHY_V3_PCS_RXEQTRAINING_RUN_TIME, 0x13),
|
||||
};
|
||||
|
||||
|
||||
/* struct qmp_phy_cfg - per-PHY initialization config */
|
||||
struct qmp_phy_cfg {
|
||||
/* phy-type - PCIE/UFS/USB */
|
||||
@ -1036,6 +1146,33 @@ static const struct qmp_phy_cfg sdm845_ufsphy_cfg = {
|
||||
.no_pcs_sw_reset = true,
|
||||
};
|
||||
|
||||
static const struct qmp_phy_cfg msm8998_usb3phy_cfg = {
|
||||
.type = PHY_TYPE_USB3,
|
||||
.nlanes = 1,
|
||||
|
||||
.serdes_tbl = msm8998_usb3_serdes_tbl,
|
||||
.serdes_tbl_num = ARRAY_SIZE(msm8998_usb3_serdes_tbl),
|
||||
.tx_tbl = msm8998_usb3_tx_tbl,
|
||||
.tx_tbl_num = ARRAY_SIZE(msm8998_usb3_tx_tbl),
|
||||
.rx_tbl = msm8998_usb3_rx_tbl,
|
||||
.rx_tbl_num = ARRAY_SIZE(msm8998_usb3_rx_tbl),
|
||||
.pcs_tbl = msm8998_usb3_pcs_tbl,
|
||||
.pcs_tbl_num = ARRAY_SIZE(msm8998_usb3_pcs_tbl),
|
||||
.clk_list = msm8996_phy_clk_l,
|
||||
.num_clks = ARRAY_SIZE(msm8996_phy_clk_l),
|
||||
.reset_list = msm8996_usb3phy_reset_l,
|
||||
.num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
|
||||
.vreg_list = qmp_phy_vreg_l,
|
||||
.num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
|
||||
.regs = qmp_v3_usb3phy_regs_layout,
|
||||
|
||||
.start_ctrl = SERDES_START | PCS_START,
|
||||
.pwrdn_ctrl = SW_PWRDN,
|
||||
.mask_pcs_ready = PHYSTATUS,
|
||||
|
||||
.is_dual_lane_phy = true,
|
||||
};
|
||||
|
||||
static void qcom_qmp_phy_configure(void __iomem *base,
|
||||
const unsigned int *regs,
|
||||
const struct qmp_phy_init_tbl tbl[],
|
||||
@ -1735,6 +1872,9 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = {
|
||||
}, {
|
||||
.compatible = "qcom,msm8996-qmp-usb3-phy",
|
||||
.data = &msm8996_usb3phy_cfg,
|
||||
}, {
|
||||
.compatible = "qcom,msm8998-qmp-ufs-phy",
|
||||
.data = &sdm845_ufsphy_cfg,
|
||||
}, {
|
||||
.compatible = "qcom,ipq8074-qmp-pcie-phy",
|
||||
.data = &ipq8074_pciephy_cfg,
|
||||
@ -1747,6 +1887,9 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = {
|
||||
}, {
|
||||
.compatible = "qcom,sdm845-qmp-ufs-phy",
|
||||
.data = &sdm845_ufsphy_cfg,
|
||||
}, {
|
||||
.compatible = "qcom,msm8998-qmp-usb3-phy",
|
||||
.data = &msm8998_usb3phy_cfg,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
@ -174,6 +174,7 @@
|
||||
#define QSERDES_V3_COM_DIV_FRAC_START1_MODE1 0x0c4
|
||||
#define QSERDES_V3_COM_DIV_FRAC_START2_MODE1 0x0c8
|
||||
#define QSERDES_V3_COM_DIV_FRAC_START3_MODE1 0x0cc
|
||||
#define QSERDES_V3_COM_INTEGLOOP_INITVAL 0x0d0
|
||||
#define QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0 0x0d8
|
||||
#define QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0 0x0dc
|
||||
#define QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE1 0x0e0
|
||||
@ -201,6 +202,7 @@
|
||||
#define QSERDES_V3_COM_DEBUG_BUS2 0x170
|
||||
#define QSERDES_V3_COM_DEBUG_BUS3 0x174
|
||||
#define QSERDES_V3_COM_DEBUG_BUS_SEL 0x178
|
||||
#define QSERDES_V3_COM_CMN_MODE 0x184
|
||||
|
||||
/* Only for QMP V3 PHY - TX registers */
|
||||
#define QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX 0x044
|
||||
@ -211,6 +213,7 @@
|
||||
#define QSERDES_V3_TX_RCV_DETECT_LVL_2 0x0a4
|
||||
|
||||
/* Only for QMP V3 PHY - RX registers */
|
||||
#define QSERDES_V3_RX_UCDR_FO_GAIN 0x008
|
||||
#define QSERDES_V3_RX_UCDR_SO_GAIN_HALF 0x00c
|
||||
#define QSERDES_V3_RX_UCDR_SO_GAIN 0x014
|
||||
#define QSERDES_V3_RX_UCDR_SVS_SO_GAIN_HALF 0x024
|
||||
@ -219,6 +222,7 @@
|
||||
#define QSERDES_V3_RX_UCDR_FASTLOCK_FO_GAIN 0x030
|
||||
#define QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE 0x034
|
||||
#define QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW 0x03c
|
||||
#define QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_HIGH 0x040
|
||||
#define QSERDES_V3_RX_UCDR_PI_CONTROLS 0x044
|
||||
#define QSERDES_V3_RX_RX_TERM_BW 0x07c
|
||||
#define QSERDES_V3_RX_VGA_CAL_CNTRL1 0x0bc
|
||||
|
@ -152,6 +152,31 @@ static const struct qusb2_phy_init_tbl msm8996_init_tbl[] = {
|
||||
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_PWR_CTRL, 0x00),
|
||||
};
|
||||
|
||||
static const unsigned int msm8998_regs_layout[] = {
|
||||
[QUSB2PHY_PLL_CORE_INPUT_OVERRIDE] = 0xa8,
|
||||
[QUSB2PHY_PLL_STATUS] = 0x1a0,
|
||||
[QUSB2PHY_PORT_TUNE1] = 0x23c,
|
||||
[QUSB2PHY_PORT_TUNE2] = 0x240,
|
||||
[QUSB2PHY_PORT_TUNE3] = 0x244,
|
||||
[QUSB2PHY_PORT_TUNE4] = 0x248,
|
||||
[QUSB2PHY_PORT_TEST1] = 0x24c,
|
||||
[QUSB2PHY_PORT_TEST2] = 0x250,
|
||||
[QUSB2PHY_PORT_POWERDOWN] = 0x210,
|
||||
[QUSB2PHY_INTR_CTRL] = 0x22c,
|
||||
};
|
||||
|
||||
static const struct qusb2_phy_init_tbl msm8998_init_tbl[] = {
|
||||
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_ANALOG_CONTROLS_TWO, 0x13),
|
||||
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CLOCK_INVERTERS, 0x7c),
|
||||
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_CMODE, 0x80),
|
||||
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_LOCK_DELAY, 0x0a),
|
||||
|
||||
QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE1, 0xa5),
|
||||
QUSB2_PHY_INIT_CFG_L(QUSB2PHY_PORT_TUNE2, 0x09),
|
||||
|
||||
QUSB2_PHY_INIT_CFG(QUSB2PHY_PLL_DIGITAL_TIMERS_TWO, 0x19),
|
||||
};
|
||||
|
||||
static const unsigned int sdm845_regs_layout[] = {
|
||||
[QUSB2PHY_PLL_CORE_INPUT_OVERRIDE] = 0xa8,
|
||||
[QUSB2PHY_PLL_STATUS] = 0x1a0,
|
||||
@ -221,6 +246,18 @@ static const struct qusb2_phy_cfg msm8996_phy_cfg = {
|
||||
.autoresume_en = BIT(3),
|
||||
};
|
||||
|
||||
static const struct qusb2_phy_cfg msm8998_phy_cfg = {
|
||||
.tbl = msm8998_init_tbl,
|
||||
.tbl_num = ARRAY_SIZE(msm8998_init_tbl),
|
||||
.regs = msm8998_regs_layout,
|
||||
|
||||
.disable_ctrl = POWER_DOWN,
|
||||
.mask_core_ready = CORE_READY_STATUS,
|
||||
.has_pll_override = true,
|
||||
.autoresume_en = BIT(0),
|
||||
.update_tune1_with_efuse = true,
|
||||
};
|
||||
|
||||
static const struct qusb2_phy_cfg sdm845_phy_cfg = {
|
||||
.tbl = sdm845_init_tbl,
|
||||
.tbl_num = ARRAY_SIZE(sdm845_init_tbl),
|
||||
@ -733,6 +770,9 @@ static const struct of_device_id qusb2_phy_of_match_table[] = {
|
||||
{
|
||||
.compatible = "qcom,msm8996-qusb2-phy",
|
||||
.data = &msm8996_phy_cfg,
|
||||
}, {
|
||||
.compatible = "qcom,msm8998-qusb2-phy",
|
||||
.data = &msm8998_phy_cfg,
|
||||
}, {
|
||||
.compatible = "qcom,sdm845-qusb2-phy",
|
||||
.data = &sdm845_phy_cfg,
|
||||
|
@ -23,24 +23,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#define readl_poll_timeout(addr, val, cond, sleep_us, timeout_us) \
|
||||
({ \
|
||||
ktime_t timeout = ktime_add_us(ktime_get(), timeout_us); \
|
||||
might_sleep_if(timeout_us); \
|
||||
for (;;) { \
|
||||
(val) = readl(addr); \
|
||||
if (cond) \
|
||||
break; \
|
||||
if (timeout_us && ktime_compare(ktime_get(), timeout) > 0) { \
|
||||
(val) = readl(addr); \
|
||||
break; \
|
||||
} \
|
||||
if (sleep_us) \
|
||||
usleep_range(DIV_ROUND_UP(sleep_us, 4), sleep_us); \
|
||||
} \
|
||||
(cond) ? 0 : -ETIMEDOUT; \
|
||||
})
|
||||
#include <linux/iopoll.h>
|
||||
|
||||
#define UFS_QCOM_PHY_CAL_ENTRY(reg, val) \
|
||||
{ \
|
||||
|
@ -55,16 +55,16 @@ enum rockchip_usb2phy_host_state {
|
||||
};
|
||||
|
||||
/**
|
||||
* Different states involved in USB charger detection.
|
||||
* USB_CHG_STATE_UNDEFINED USB charger is not connected or detection
|
||||
* enum usb_chg_state - Different states involved in USB charger detection.
|
||||
* @USB_CHG_STATE_UNDEFINED: USB charger is not connected or detection
|
||||
* process is not yet started.
|
||||
* USB_CHG_STATE_WAIT_FOR_DCD Waiting for Data pins contact.
|
||||
* USB_CHG_STATE_DCD_DONE Data pin contact is detected.
|
||||
* USB_CHG_STATE_PRIMARY_DONE Primary detection is completed (Detects
|
||||
* @USB_CHG_STATE_WAIT_FOR_DCD: Waiting for Data pins contact.
|
||||
* @USB_CHG_STATE_DCD_DONE: Data pin contact is detected.
|
||||
* @USB_CHG_STATE_PRIMARY_DONE: Primary detection is completed (Detects
|
||||
* between SDP and DCP/CDP).
|
||||
* USB_CHG_STATE_SECONDARY_DONE Secondary detection is completed (Detects
|
||||
* between DCP and CDP).
|
||||
* USB_CHG_STATE_DETECTED USB charger type is determined.
|
||||
* @USB_CHG_STATE_SECONDARY_DONE: Secondary detection is completed (Detects
|
||||
* between DCP and CDP).
|
||||
* @USB_CHG_STATE_DETECTED: USB charger type is determined.
|
||||
*/
|
||||
enum usb_chg_state {
|
||||
USB_CHG_STATE_UNDEFINED = 0,
|
||||
@ -94,7 +94,7 @@ struct usb2phy_reg {
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rockchip_chg_det_reg: usb charger detect registers
|
||||
* struct rockchip_chg_det_reg - usb charger detect registers
|
||||
* @cp_det: charging port detected successfully.
|
||||
* @dcp_det: dedicated charging port detected successfully.
|
||||
* @dp_det: assert data pin connect successfully.
|
||||
@ -120,7 +120,7 @@ struct rockchip_chg_det_reg {
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rockchip_usb2phy_port_cfg: usb-phy port configuration.
|
||||
* struct rockchip_usb2phy_port_cfg - usb-phy port configuration.
|
||||
* @phy_sus: phy suspend register.
|
||||
* @bvalid_det_en: vbus valid rise detection enable register.
|
||||
* @bvalid_det_st: vbus valid rise detection status register.
|
||||
@ -148,10 +148,11 @@ struct rockchip_usb2phy_port_cfg {
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rockchip_usb2phy_cfg: usb-phy configuration.
|
||||
* struct rockchip_usb2phy_cfg - usb-phy configuration.
|
||||
* @reg: the address offset of grf for usb-phy config.
|
||||
* @num_ports: specify how many ports that the phy has.
|
||||
* @clkout_ctl: keep on/turn off output clk of phy.
|
||||
* @port_cfgs: usb-phy port configurations.
|
||||
* @chg_det: charger detection registers.
|
||||
*/
|
||||
struct rockchip_usb2phy_cfg {
|
||||
@ -163,12 +164,10 @@ struct rockchip_usb2phy_cfg {
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rockchip_usb2phy_port: usb-phy port data.
|
||||
* struct rockchip_usb2phy_port - usb-phy port data.
|
||||
* @phy: generic phy.
|
||||
* @port_id: flag for otg port or host port.
|
||||
* @suspended: phy suspended flag.
|
||||
* @utmi_avalid: utmi avalid status usage flag.
|
||||
* true - use avalid to get vbus status
|
||||
* flase - use bvalid to get vbus status
|
||||
* @vbus_attached: otg device vbus status.
|
||||
* @bvalid_irq: IRQ number assigned for vbus valid rise detection.
|
||||
* @ls_irq: IRQ number assigned for linestate detection.
|
||||
@ -178,7 +177,7 @@ struct rockchip_usb2phy_cfg {
|
||||
* @chg_work: charge detect work.
|
||||
* @otg_sm_work: OTG state machine work.
|
||||
* @sm_work: HOST state machine work.
|
||||
* @phy_cfg: port register configuration, assigned by driver data.
|
||||
* @port_cfg: port register configuration, assigned by driver data.
|
||||
* @event_nb: hold event notification callback.
|
||||
* @state: define OTG enumeration states before device reset.
|
||||
* @mode: the dr_mode of the controller.
|
||||
@ -187,7 +186,6 @@ struct rockchip_usb2phy_port {
|
||||
struct phy *phy;
|
||||
unsigned int port_id;
|
||||
bool suspended;
|
||||
bool utmi_avalid;
|
||||
bool vbus_attached;
|
||||
int bvalid_irq;
|
||||
int ls_irq;
|
||||
@ -203,12 +201,13 @@ struct rockchip_usb2phy_port {
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rockchip_usb2phy: usb2.0 phy driver data.
|
||||
* struct rockchip_usb2phy - usb2.0 phy driver data.
|
||||
* @dev: pointer to device.
|
||||
* @grf: General Register Files regmap.
|
||||
* @usbgrf: USB General Register Files regmap.
|
||||
* @clk: clock struct of phy input clk.
|
||||
* @clk480m: clock struct of phy output clk.
|
||||
* @clk_hw: clock struct of phy output clk management.
|
||||
* @clk480m_hw: clock struct of phy output clk management.
|
||||
* @chg_state: states involved in USB charger detection.
|
||||
* @chg_type: USB charger types.
|
||||
* @dcd_retries: The retry count used to track Data contact
|
||||
@ -542,12 +541,8 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)
|
||||
unsigned long delay;
|
||||
bool vbus_attach, sch_work, notify_charger;
|
||||
|
||||
if (rport->utmi_avalid)
|
||||
vbus_attach = property_enabled(rphy->grf,
|
||||
&rport->port_cfg->utmi_avalid);
|
||||
else
|
||||
vbus_attach = property_enabled(rphy->grf,
|
||||
&rport->port_cfg->utmi_bvalid);
|
||||
vbus_attach = property_enabled(rphy->grf,
|
||||
&rport->port_cfg->utmi_bvalid);
|
||||
|
||||
sch_work = false;
|
||||
notify_charger = false;
|
||||
@ -1021,9 +1016,6 @@ static int rockchip_usb2phy_otg_port_init(struct rockchip_usb2phy *rphy,
|
||||
INIT_DELAYED_WORK(&rport->chg_work, rockchip_chg_detect_work);
|
||||
INIT_DELAYED_WORK(&rport->otg_sm_work, rockchip_usb2phy_otg_sm_work);
|
||||
|
||||
rport->utmi_avalid =
|
||||
of_property_read_bool(child_np, "rockchip,utmi-avalid");
|
||||
|
||||
/*
|
||||
* Some SoCs use one interrupt with otg-id/otg-bvalid/linestate
|
||||
* interrupts muxed together, so probe the otg-mux interrupt first,
|
||||
|
@ -33,12 +33,11 @@ config OMAP_CONTROL_PHY
|
||||
|
||||
config OMAP_USB2
|
||||
tristate "OMAP USB2 PHY Driver"
|
||||
depends on ARCH_OMAP2PLUS
|
||||
depends on ARCH_OMAP2PLUS || ARCH_K3
|
||||
depends on USB_SUPPORT
|
||||
select GENERIC_PHY
|
||||
select USB_PHY
|
||||
select OMAP_CONTROL_PHY
|
||||
depends on OMAP_OCP2SCP
|
||||
select OMAP_CONTROL_PHY if ARCH_OMAP2PLUS
|
||||
help
|
||||
Enable this to support the transceiver that is part of SOC. This
|
||||
driver takes care of all the PHY functionality apart from comparator.
|
||||
@ -50,7 +49,6 @@ config TI_PIPE3
|
||||
depends on ARCH_OMAP2PLUS || COMPILE_TEST
|
||||
select GENERIC_PHY
|
||||
select OMAP_CONTROL_PHY
|
||||
depends on OMAP_OCP2SCP
|
||||
help
|
||||
Enable this to support the PIPE3 PHY that is part of TI SOCs. This
|
||||
driver takes care of all the PHY functionality apart from comparator.
|
||||
|
@ -36,6 +36,10 @@
|
||||
#define USB2PHY_DISCON_BYP_LATCH (1 << 31)
|
||||
#define USB2PHY_ANA_CONFIG1 0x4c
|
||||
|
||||
#define AM654_USB2_OTG_PD BIT(8)
|
||||
#define AM654_USB2_VBUS_DET_EN BIT(5)
|
||||
#define AM654_USB2_VBUSVALID_DET_EN BIT(4)
|
||||
|
||||
/**
|
||||
* omap_usb2_set_comparator - links the comparator present in the sytem with
|
||||
* this phy
|
||||
@ -135,9 +139,9 @@ static int omap_usb_power_on(struct phy *x)
|
||||
|
||||
static int omap_usb2_disable_clocks(struct omap_usb *phy)
|
||||
{
|
||||
clk_disable(phy->wkupclk);
|
||||
clk_disable_unprepare(phy->wkupclk);
|
||||
if (!IS_ERR(phy->optclk))
|
||||
clk_disable(phy->optclk);
|
||||
clk_disable_unprepare(phy->optclk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -146,14 +150,14 @@ static int omap_usb2_enable_clocks(struct omap_usb *phy)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = clk_enable(phy->wkupclk);
|
||||
ret = clk_prepare_enable(phy->wkupclk);
|
||||
if (ret < 0) {
|
||||
dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret);
|
||||
goto err0;
|
||||
}
|
||||
|
||||
if (!IS_ERR(phy->optclk)) {
|
||||
ret = clk_enable(phy->optclk);
|
||||
ret = clk_prepare_enable(phy->optclk);
|
||||
if (ret < 0) {
|
||||
dev_err(phy->dev, "Failed to enable optclk %d\n", ret);
|
||||
goto err1;
|
||||
@ -245,6 +249,15 @@ static const struct usb_phy_data am437x_usb2_data = {
|
||||
.power_off = AM437X_USB2_PHY_PD | AM437X_USB2_OTG_PD,
|
||||
};
|
||||
|
||||
static const struct usb_phy_data am654_usb2_data = {
|
||||
.label = "am654_usb2",
|
||||
.flags = OMAP_USB2_CALIBRATE_FALSE_DISCONNECT,
|
||||
.mask = AM654_USB2_OTG_PD | AM654_USB2_VBUS_DET_EN |
|
||||
AM654_USB2_VBUSVALID_DET_EN,
|
||||
.power_on = AM654_USB2_VBUS_DET_EN | AM654_USB2_VBUSVALID_DET_EN,
|
||||
.power_off = AM654_USB2_OTG_PD,
|
||||
};
|
||||
|
||||
static const struct of_device_id omap_usb2_id_table[] = {
|
||||
{
|
||||
.compatible = "ti,omap-usb2",
|
||||
@ -266,6 +279,10 @@ static const struct of_device_id omap_usb2_id_table[] = {
|
||||
.compatible = "ti,am437x-usb2",
|
||||
.data = &am437x_usb2_data,
|
||||
},
|
||||
{
|
||||
.compatible = "ti,am654-usb2",
|
||||
.data = &am654_usb2_data,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, omap_usb2_id_table);
|
||||
@ -346,13 +363,52 @@ static int omap_usb2_probe(struct platform_device *pdev)
|
||||
}
|
||||
}
|
||||
|
||||
otg->set_host = omap_usb_set_host;
|
||||
otg->set_peripheral = omap_usb_set_peripheral;
|
||||
|
||||
phy->wkupclk = devm_clk_get(phy->dev, "wkupclk");
|
||||
if (IS_ERR(phy->wkupclk)) {
|
||||
if (PTR_ERR(phy->wkupclk) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
dev_warn(&pdev->dev, "unable to get wkupclk %ld, trying old name\n",
|
||||
PTR_ERR(phy->wkupclk));
|
||||
phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k");
|
||||
|
||||
if (IS_ERR(phy->wkupclk)) {
|
||||
if (PTR_ERR(phy->wkupclk) != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n");
|
||||
return PTR_ERR(phy->wkupclk);
|
||||
} else {
|
||||
dev_warn(&pdev->dev,
|
||||
"found usb_phy_cm_clk32k, please fix DTS\n");
|
||||
}
|
||||
}
|
||||
|
||||
phy->optclk = devm_clk_get(phy->dev, "refclk");
|
||||
if (IS_ERR(phy->optclk)) {
|
||||
if (PTR_ERR(phy->optclk) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
dev_dbg(&pdev->dev, "unable to get refclk, trying old name\n");
|
||||
phy->optclk = devm_clk_get(phy->dev, "usb_otg_ss_refclk960m");
|
||||
|
||||
if (IS_ERR(phy->optclk)) {
|
||||
if (PTR_ERR(phy->optclk) != -EPROBE_DEFER) {
|
||||
dev_dbg(&pdev->dev,
|
||||
"unable to get usb_otg_ss_refclk960m\n");
|
||||
}
|
||||
} else {
|
||||
dev_warn(&pdev->dev,
|
||||
"found usb_otg_ss_refclk960m, please fix DTS\n");
|
||||
}
|
||||
}
|
||||
|
||||
otg->set_host = omap_usb_set_host;
|
||||
otg->set_peripheral = omap_usb_set_peripheral;
|
||||
if (phy_data->flags & OMAP_USB2_HAS_SET_VBUS)
|
||||
otg->set_vbus = omap_usb_set_vbus;
|
||||
otg->set_vbus = omap_usb_set_vbus;
|
||||
if (phy_data->flags & OMAP_USB2_HAS_START_SRP)
|
||||
otg->start_srp = omap_usb_start_srp;
|
||||
otg->usb_phy = &phy->phy;
|
||||
otg->start_srp = omap_usb_start_srp;
|
||||
otg->usb_phy = &phy->phy;
|
||||
|
||||
platform_set_drvdata(pdev, phy);
|
||||
pm_runtime_enable(phy->dev);
|
||||
@ -367,42 +423,12 @@ static int omap_usb2_probe(struct platform_device *pdev)
|
||||
omap_usb_power_off(generic_phy);
|
||||
|
||||
phy_provider = devm_of_phy_provider_register(phy->dev,
|
||||
of_phy_simple_xlate);
|
||||
of_phy_simple_xlate);
|
||||
if (IS_ERR(phy_provider)) {
|
||||
pm_runtime_disable(phy->dev);
|
||||
return PTR_ERR(phy_provider);
|
||||
}
|
||||
|
||||
phy->wkupclk = devm_clk_get(phy->dev, "wkupclk");
|
||||
if (IS_ERR(phy->wkupclk)) {
|
||||
dev_warn(&pdev->dev, "unable to get wkupclk, trying old name\n");
|
||||
phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k");
|
||||
if (IS_ERR(phy->wkupclk)) {
|
||||
dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n");
|
||||
pm_runtime_disable(phy->dev);
|
||||
return PTR_ERR(phy->wkupclk);
|
||||
} else {
|
||||
dev_warn(&pdev->dev,
|
||||
"found usb_phy_cm_clk32k, please fix DTS\n");
|
||||
}
|
||||
}
|
||||
clk_prepare(phy->wkupclk);
|
||||
|
||||
phy->optclk = devm_clk_get(phy->dev, "refclk");
|
||||
if (IS_ERR(phy->optclk)) {
|
||||
dev_dbg(&pdev->dev, "unable to get refclk, trying old name\n");
|
||||
phy->optclk = devm_clk_get(phy->dev, "usb_otg_ss_refclk960m");
|
||||
if (IS_ERR(phy->optclk)) {
|
||||
dev_dbg(&pdev->dev,
|
||||
"unable to get usb_otg_ss_refclk960m\n");
|
||||
} else {
|
||||
dev_warn(&pdev->dev,
|
||||
"found usb_otg_ss_refclk960m, please fix DTS\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (!IS_ERR(phy->optclk))
|
||||
clk_prepare(phy->optclk);
|
||||
|
||||
usb_add_phy_dev(&phy->phy);
|
||||
|
||||
@ -413,9 +439,6 @@ static int omap_usb2_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_usb *phy = platform_get_drvdata(pdev);
|
||||
|
||||
clk_unprepare(phy->wkupclk);
|
||||
if (!IS_ERR(phy->optclk))
|
||||
clk_unprepare(phy->optclk);
|
||||
usb_remove_phy(&phy->phy);
|
||||
pm_runtime_disable(phy->dev);
|
||||
|
||||
|
@ -32,7 +32,7 @@ struct cht_int33fe_data {
|
||||
struct i2c_client *fusb302;
|
||||
struct i2c_client *pi3usb30532;
|
||||
/* Contain a list-head must be per device */
|
||||
struct device_connection connections[5];
|
||||
struct device_connection connections[4];
|
||||
};
|
||||
|
||||
/*
|
||||
@ -174,16 +174,13 @@ static int cht_int33fe_probe(struct platform_device *pdev)
|
||||
|
||||
data->connections[0].endpoint[0] = "port0";
|
||||
data->connections[0].endpoint[1] = "i2c-pi3usb30532";
|
||||
data->connections[0].id = "typec-switch";
|
||||
data->connections[0].id = "orientation-switch";
|
||||
data->connections[1].endpoint[0] = "port0";
|
||||
data->connections[1].endpoint[1] = "i2c-pi3usb30532";
|
||||
data->connections[1].id = "typec-mux";
|
||||
data->connections[2].endpoint[0] = "port0";
|
||||
data->connections[2].endpoint[1] = "i2c-pi3usb30532";
|
||||
data->connections[2].id = "idff01m01";
|
||||
data->connections[3].endpoint[0] = "i2c-fusb302";
|
||||
data->connections[3].endpoint[1] = "intel_xhci_usb_sw-role-switch";
|
||||
data->connections[3].id = "usb-role-switch";
|
||||
data->connections[1].id = "mode-switch";
|
||||
data->connections[2].endpoint[0] = "i2c-fusb302";
|
||||
data->connections[2].endpoint[1] = "intel_xhci_usb_sw-role-switch";
|
||||
data->connections[2].id = "usb-role-switch";
|
||||
|
||||
device_connections_add(data->connections);
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# USB device configuration
|
||||
#
|
||||
|
@ -1,54 +0,0 @@
|
||||
To understand all the Linux-USB framework, you'll use these resources:
|
||||
|
||||
* This source code. This is necessarily an evolving work, and
|
||||
includes kerneldoc that should help you get a current overview.
|
||||
("make pdfdocs", and then look at "usb.pdf" for host side and
|
||||
"gadget.pdf" for peripheral side.) Also, Documentation/usb has
|
||||
more information.
|
||||
|
||||
* The USB 2.0 specification (from www.usb.org), with supplements
|
||||
such as those for USB OTG and the various device classes.
|
||||
The USB specification has a good overview chapter, and USB
|
||||
peripherals conform to the widely known "Chapter 9".
|
||||
|
||||
* Chip specifications for USB controllers. Examples include
|
||||
host controllers (on PCs, servers, and more); peripheral
|
||||
controllers (in devices with Linux firmware, like printers or
|
||||
cell phones); and hard-wired peripherals like Ethernet adapters.
|
||||
|
||||
* Specifications for other protocols implemented by USB peripheral
|
||||
functions. Some are vendor-specific; others are vendor-neutral
|
||||
but just standardized outside of the www.usb.org team.
|
||||
|
||||
Here is a list of what each subdirectory here is, and what is contained in
|
||||
them.
|
||||
|
||||
core/ - This is for the core USB host code, including the
|
||||
usbfs files and the hub class driver ("hub_wq").
|
||||
|
||||
host/ - This is for USB host controller drivers. This
|
||||
includes UHCI, OHCI, EHCI, and others that might
|
||||
be used with more specialized "embedded" systems.
|
||||
|
||||
gadget/ - This is for USB peripheral controller drivers and
|
||||
the various gadget drivers which talk to them.
|
||||
|
||||
|
||||
Individual USB driver directories. A new driver should be added to the
|
||||
first subdirectory in the list below that it fits into.
|
||||
|
||||
image/ - This is for still image drivers, like scanners or
|
||||
digital cameras.
|
||||
../input/ - This is for any driver that uses the input subsystem,
|
||||
like keyboard, mice, touchscreens, tablets, etc.
|
||||
../media/ - This is for multimedia drivers, like video cameras,
|
||||
radios, and any other drivers that talk to the v4l
|
||||
subsystem.
|
||||
../net/ - This is for network drivers.
|
||||
serial/ - This is for USB to serial drivers.
|
||||
storage/ - This is for USB mass-storage drivers.
|
||||
class/ - This is for all USB device drivers that do not fit
|
||||
into any of the above categories, and work for a range
|
||||
of USB Class specified devices.
|
||||
misc/ - This is for all USB device drivers that do not fit
|
||||
into any of the above categories.
|
@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# USB/ATM DSL configuration
|
||||
#
|
||||
|
@ -1,3 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
config USB_CHIPIDEA
|
||||
tristate "ChipIdea Highspeed Dual Role Controller"
|
||||
depends on ((USB_EHCI_HCD && USB_GADGET) || (USB_EHCI_HCD && !USB_GADGET) || (!USB_EHCI_HCD && USB_GADGET)) && HAS_DMA
|
||||
|
@ -7,10 +7,8 @@
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/usb/chipidea.h>
|
||||
#include <linux/usb/of.h>
|
||||
#include <linux/clk.h>
|
||||
@ -152,8 +150,8 @@ static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev)
|
||||
dev_warn(dev, "No over current polarity defined\n");
|
||||
}
|
||||
|
||||
if (of_find_property(np, "external-vbus-divider", NULL))
|
||||
data->evdo = 1;
|
||||
data->pwr_pol = of_property_read_bool(np, "power-active-high");
|
||||
data->evdo = of_property_read_bool(np, "external-vbus-divider");
|
||||
|
||||
if (of_usb_get_phy_mode(np) == USBPHY_INTERFACE_MODE_ULPI)
|
||||
data->ulpi = 1;
|
||||
|
@ -18,6 +18,7 @@ struct imx_usbmisc_data {
|
||||
/* true if dt specifies polarity */
|
||||
unsigned int oc_pol_configured:1;
|
||||
|
||||
unsigned int pwr_pol:1; /* power polarity */
|
||||
unsigned int evdo:1; /* set external vbus divider option */
|
||||
unsigned int ulpi:1; /* connected to an ULPI phy */
|
||||
unsigned int hsic:1; /* HSIC controlller */
|
||||
|
@ -130,6 +130,7 @@ static int tegra_udc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct tegra_udc *udc = platform_get_drvdata(pdev);
|
||||
|
||||
ci_hdrc_remove_device(udc->dev);
|
||||
usb_phy_set_suspend(udc->phy, 1);
|
||||
clk_disable_unprepare(udc->clk);
|
||||
|
||||
|
@ -954,25 +954,47 @@ static int ci_hdrc_probe(struct platform_device *pdev)
|
||||
} else if (ci->platdata->usb_phy) {
|
||||
ci->usb_phy = ci->platdata->usb_phy;
|
||||
} else {
|
||||
/* Look for a generic PHY first */
|
||||
ci->phy = devm_phy_get(dev->parent, "usb-phy");
|
||||
ci->usb_phy = devm_usb_get_phy(dev->parent, USB_PHY_TYPE_USB2);
|
||||
|
||||
/* if both generic PHY and USB PHY layers aren't enabled */
|
||||
if (PTR_ERR(ci->phy) == -ENOSYS &&
|
||||
PTR_ERR(ci->usb_phy) == -ENXIO) {
|
||||
if (PTR_ERR(ci->phy) == -EPROBE_DEFER) {
|
||||
ret = -EPROBE_DEFER;
|
||||
goto ulpi_exit;
|
||||
} else if (IS_ERR(ci->phy)) {
|
||||
ci->phy = NULL;
|
||||
}
|
||||
|
||||
/* Look for a legacy USB PHY from device-tree next */
|
||||
if (!ci->phy) {
|
||||
ci->usb_phy = devm_usb_get_phy_by_phandle(dev->parent,
|
||||
"phys", 0);
|
||||
|
||||
if (PTR_ERR(ci->usb_phy) == -EPROBE_DEFER) {
|
||||
ret = -EPROBE_DEFER;
|
||||
goto ulpi_exit;
|
||||
} else if (IS_ERR(ci->usb_phy)) {
|
||||
ci->usb_phy = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Look for any registered legacy USB PHY as last resort */
|
||||
if (!ci->phy && !ci->usb_phy) {
|
||||
ci->usb_phy = devm_usb_get_phy(dev->parent,
|
||||
USB_PHY_TYPE_USB2);
|
||||
|
||||
if (PTR_ERR(ci->usb_phy) == -EPROBE_DEFER) {
|
||||
ret = -EPROBE_DEFER;
|
||||
goto ulpi_exit;
|
||||
} else if (IS_ERR(ci->usb_phy)) {
|
||||
ci->usb_phy = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* No USB PHY was found in the end */
|
||||
if (!ci->phy && !ci->usb_phy) {
|
||||
ret = -ENXIO;
|
||||
goto ulpi_exit;
|
||||
}
|
||||
|
||||
if (IS_ERR(ci->phy) && IS_ERR(ci->usb_phy)) {
|
||||
ret = -EPROBE_DEFER;
|
||||
goto ulpi_exit;
|
||||
}
|
||||
|
||||
if (IS_ERR(ci->phy))
|
||||
ci->phy = NULL;
|
||||
else if (IS_ERR(ci->usb_phy))
|
||||
ci->usb_phy = NULL;
|
||||
}
|
||||
|
||||
ret = ci_usb_phy_init(ci);
|
||||
|
@ -63,6 +63,7 @@
|
||||
#define MX6_BM_NON_BURST_SETTING BIT(1)
|
||||
#define MX6_BM_OVER_CUR_DIS BIT(7)
|
||||
#define MX6_BM_OVER_CUR_POLARITY BIT(8)
|
||||
#define MX6_BM_PWR_POLARITY BIT(9)
|
||||
#define MX6_BM_WAKEUP_ENABLE BIT(10)
|
||||
#define MX6_BM_UTMI_ON_CLOCK BIT(13)
|
||||
#define MX6_BM_ID_WAKEUP BIT(16)
|
||||
@ -383,6 +384,9 @@ static int usbmisc_imx6q_init(struct imx_usbmisc_data *data)
|
||||
else if (data->oc_pol_configured)
|
||||
reg &= ~MX6_BM_OVER_CUR_POLARITY;
|
||||
}
|
||||
/* If the polarity is not set keep it as setup by the bootlader */
|
||||
if (data->pwr_pol == 1)
|
||||
reg |= MX6_BM_PWR_POLARITY;
|
||||
writel(reg, usbmisc->base + data->index * 4);
|
||||
|
||||
/* SoC non-burst setting */
|
||||
@ -585,6 +589,9 @@ static int usbmisc_imx7d_init(struct imx_usbmisc_data *data)
|
||||
else if (data->oc_pol_configured)
|
||||
reg &= ~MX6_BM_OVER_CUR_POLARITY;
|
||||
}
|
||||
/* If the polarity is not set keep it as setup by the bootlader */
|
||||
if (data->pwr_pol == 1)
|
||||
reg |= MX6_BM_PWR_POLARITY;
|
||||
writel(reg, usbmisc->base);
|
||||
|
||||
reg = readl(usbmisc->base + MX7D_USBNC_USB_CTRL2);
|
||||
|
@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# USB Class driver configuration
|
||||
#
|
||||
|
@ -1099,7 +1099,7 @@ static int wdm_post_reset(struct usb_interface *intf)
|
||||
rv = recover_from_urb_loss(desc);
|
||||
mutex_unlock(&desc->wlock);
|
||||
mutex_unlock(&desc->rlock);
|
||||
return 0;
|
||||
return rv;
|
||||
}
|
||||
|
||||
static struct usb_driver wdm_driver = {
|
||||
|
@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# USB Core configuration
|
||||
#
|
||||
@ -90,3 +91,15 @@ config USB_LEDS_TRIGGER_USBPORT
|
||||
This driver allows LEDs to be controlled by USB events. Enabling this
|
||||
trigger allows specifying list of USB ports that should turn on LED
|
||||
when some USB device gets connected.
|
||||
|
||||
config USB_AUTOSUSPEND_DELAY
|
||||
int "Default autosuspend delay"
|
||||
depends on USB
|
||||
default 2
|
||||
help
|
||||
The default autosuspend delay in seconds. Can be overridden
|
||||
with the usbcore.autosuspend command line or module parameter.
|
||||
|
||||
The default value Linux has always had is 2 seconds. Change
|
||||
this value if you want a different delay and cannot modify
|
||||
the command line or module parameter.
|
||||
|
@ -552,7 +552,7 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
|
||||
unsigned char *buffer2;
|
||||
int size2;
|
||||
struct usb_descriptor_header *header;
|
||||
int len, retval;
|
||||
int retval;
|
||||
u8 inums[USB_MAXINTERFACES], nalts[USB_MAXINTERFACES];
|
||||
unsigned iad_num = 0;
|
||||
|
||||
@ -707,8 +707,8 @@ static int usb_parse_configuration(struct usb_device *dev, int cfgidx,
|
||||
nalts[i] = j = USB_MAXALTSETTING;
|
||||
}
|
||||
|
||||
len = sizeof(*intfc) + sizeof(struct usb_host_interface) * j;
|
||||
config->intf_cache[i] = intfc = kzalloc(len, GFP_KERNEL);
|
||||
intfc = kzalloc(struct_size(intfc, altsetting, j), GFP_KERNEL);
|
||||
config->intf_cache[i] = intfc;
|
||||
if (!intfc)
|
||||
return -ENOMEM;
|
||||
kref_init(&intfc->ref);
|
||||
@ -800,13 +800,11 @@ int usb_get_configuration(struct usb_device *dev)
|
||||
{
|
||||
struct device *ddev = &dev->dev;
|
||||
int ncfg = dev->descriptor.bNumConfigurations;
|
||||
int result = 0;
|
||||
int result = -ENOMEM;
|
||||
unsigned int cfgno, length;
|
||||
unsigned char *bigbuffer;
|
||||
struct usb_config_descriptor *desc;
|
||||
|
||||
cfgno = 0;
|
||||
result = -ENOMEM;
|
||||
if (ncfg > USB_MAXCONFIG) {
|
||||
dev_warn(ddev, "too many configurations: %d, "
|
||||
"using maximum allowed: %d\n", ncfg, USB_MAXCONFIG);
|
||||
@ -832,8 +830,7 @@ int usb_get_configuration(struct usb_device *dev)
|
||||
if (!desc)
|
||||
goto err2;
|
||||
|
||||
result = 0;
|
||||
for (; cfgno < ncfg; cfgno++) {
|
||||
for (cfgno = 0; cfgno < ncfg; cfgno++) {
|
||||
/* We grab just the first descriptor so we know how long
|
||||
* the whole configuration is */
|
||||
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
|
||||
@ -889,7 +886,6 @@ int usb_get_configuration(struct usb_device *dev)
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
result = 0;
|
||||
|
||||
err:
|
||||
kfree(desc);
|
||||
|
@ -604,7 +604,7 @@ static void async_completed(struct urb *urb)
|
||||
snoop(&urb->dev->dev, "urb complete\n");
|
||||
snoop_urb(urb->dev, as->userurb, urb->pipe, urb->actual_length,
|
||||
as->status, COMPLETE, NULL, 0);
|
||||
if ((urb->transfer_flags & URB_DIR_MASK) == URB_DIR_IN)
|
||||
if (usb_urb_dir_in(urb))
|
||||
snoop_urb_data(urb, urb->actual_length);
|
||||
|
||||
if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET &&
|
||||
@ -1564,12 +1564,10 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
|
||||
}
|
||||
for (totlen = u = 0; u < number_of_packets; u++) {
|
||||
/*
|
||||
* arbitrary limit need for USB 3.0
|
||||
* bMaxBurst (0~15 allowed, 1~16 packets)
|
||||
* bmAttributes (bit 1:0, mult 0~2, 1~3 packets)
|
||||
* sizemax: 1024 * 16 * 3 = 49152
|
||||
* arbitrary limit need for USB 3.1 Gen2
|
||||
* sizemax: 96 DPs at SSP, 96 * 1024 = 98304
|
||||
*/
|
||||
if (isopkt[u].length > 49152) {
|
||||
if (isopkt[u].length > 98304) {
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
@ -1896,14 +1896,11 @@ int usb_runtime_idle(struct device *dev)
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)
|
||||
static int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)
|
||||
{
|
||||
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
|
||||
int ret = -EPERM;
|
||||
|
||||
if (enable && !udev->usb2_hw_lpm_allowed)
|
||||
return 0;
|
||||
|
||||
if (hcd->driver->set_usb2_hw_lpm) {
|
||||
ret = hcd->driver->set_usb2_hw_lpm(hcd, udev, enable);
|
||||
if (!ret)
|
||||
@ -1913,6 +1910,24 @@ int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int usb_enable_usb2_hardware_lpm(struct usb_device *udev)
|
||||
{
|
||||
if (!udev->usb2_hw_lpm_capable ||
|
||||
!udev->usb2_hw_lpm_allowed ||
|
||||
udev->usb2_hw_lpm_enabled)
|
||||
return 0;
|
||||
|
||||
return usb_set_usb2_hardware_lpm(udev, 1);
|
||||
}
|
||||
|
||||
int usb_disable_usb2_hardware_lpm(struct usb_device *udev)
|
||||
{
|
||||
if (!udev->usb2_hw_lpm_enabled)
|
||||
return 0;
|
||||
|
||||
return usb_set_usb2_hardware_lpm(udev, 0);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
struct bus_type usb_bus_type = {
|
||||
|
@ -118,6 +118,31 @@ int usb_choose_configuration(struct usb_device *udev)
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Select first configuration as default for audio so that
|
||||
* devices that don't comply with UAC3 protocol are supported.
|
||||
* But, still iterate through other configurations and
|
||||
* select UAC3 compliant config if present.
|
||||
*/
|
||||
if (desc && is_audio(desc)) {
|
||||
/* Always prefer the first found UAC3 config */
|
||||
if (is_uac3_config(desc)) {
|
||||
best = c;
|
||||
break;
|
||||
}
|
||||
|
||||
/* If there is no UAC3 config, prefer the first config */
|
||||
else if (i == 0)
|
||||
best = c;
|
||||
|
||||
/* Unconditional continue, because the rest of the code
|
||||
* in the loop is irrelevant for audio devices, and
|
||||
* because it can reassign best, which for audio devices
|
||||
* we don't want.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
/* When the first config's first interface is one of Microsoft's
|
||||
* pet nonstandard Ethernet-over-USB protocols, ignore it unless
|
||||
* this kernel has enabled the necessary host side driver.
|
||||
@ -132,25 +157,6 @@ int usb_choose_configuration(struct usb_device *udev)
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Select first configuration as default for audio so that
|
||||
* devices that don't comply with UAC3 protocol are supported.
|
||||
* But, still iterate through other configurations and
|
||||
* select UAC3 compliant config if present.
|
||||
*/
|
||||
if (i == 0 && num_configs > 1 && desc && is_audio(desc)) {
|
||||
best = c;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i > 0 && desc && is_audio(desc)) {
|
||||
if (is_uac3_config(desc)) {
|
||||
best = c;
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* From the remaining configs, choose the first one whose
|
||||
* first interface is for a non-vendor-specific class.
|
||||
* Reason: Linux is more likely to have a class driver
|
||||
|
@ -373,13 +373,19 @@ static const u8 ss_rh_config_descriptor[] = {
|
||||
* -1 is authorized for all devices except wireless (old behaviour)
|
||||
* 0 is unauthorized for all devices
|
||||
* 1 is authorized for all devices
|
||||
* 2 is authorized for internal devices
|
||||
*/
|
||||
static int authorized_default = -1;
|
||||
#define USB_AUTHORIZE_WIRED -1
|
||||
#define USB_AUTHORIZE_NONE 0
|
||||
#define USB_AUTHORIZE_ALL 1
|
||||
#define USB_AUTHORIZE_INTERNAL 2
|
||||
|
||||
static int authorized_default = USB_AUTHORIZE_WIRED;
|
||||
module_param(authorized_default, int, S_IRUGO|S_IWUSR);
|
||||
MODULE_PARM_DESC(authorized_default,
|
||||
"Default USB device authorization: 0 is not authorized, 1 is "
|
||||
"authorized, -1 is authorized except for wireless USB (default, "
|
||||
"old behaviour");
|
||||
"authorized, 2 is authorized for internal devices, -1 is "
|
||||
"authorized except for wireless USB (default, old behaviour)");
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
@ -884,7 +890,7 @@ static ssize_t authorized_default_show(struct device *dev,
|
||||
struct usb_hcd *hcd;
|
||||
|
||||
hcd = bus_to_hcd(usb_bus);
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", !!HCD_DEV_AUTHORIZED(hcd));
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", hcd->dev_policy);
|
||||
}
|
||||
|
||||
static ssize_t authorized_default_store(struct device *dev,
|
||||
@ -900,11 +906,8 @@ static ssize_t authorized_default_store(struct device *dev,
|
||||
hcd = bus_to_hcd(usb_bus);
|
||||
result = sscanf(buf, "%u\n", &val);
|
||||
if (result == 1) {
|
||||
if (val)
|
||||
set_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags);
|
||||
else
|
||||
clear_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags);
|
||||
|
||||
hcd->dev_policy = val <= USB_DEVICE_AUTHORIZE_INTERNAL ?
|
||||
val : USB_DEVICE_AUTHORIZE_ALL;
|
||||
result = size;
|
||||
} else {
|
||||
result = -EINVAL;
|
||||
@ -2736,6 +2739,11 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = usb_phy_roothub_set_mode(hcd->phy_roothub,
|
||||
PHY_MODE_USB_HOST_SS);
|
||||
if (retval)
|
||||
goto err_usb_phy_roothub_power_on;
|
||||
|
||||
retval = usb_phy_roothub_power_on(hcd->phy_roothub);
|
||||
if (retval)
|
||||
goto err_usb_phy_roothub_power_on;
|
||||
@ -2743,18 +2751,26 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
||||
|
||||
dev_info(hcd->self.controller, "%s\n", hcd->product_desc);
|
||||
|
||||
/* Keep old behaviour if authorized_default is not in [0, 1]. */
|
||||
if (authorized_default < 0 || authorized_default > 1) {
|
||||
if (hcd->wireless)
|
||||
clear_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags);
|
||||
else
|
||||
set_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags);
|
||||
} else {
|
||||
if (authorized_default)
|
||||
set_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags);
|
||||
else
|
||||
clear_bit(HCD_FLAG_DEV_AUTHORIZED, &hcd->flags);
|
||||
switch (authorized_default) {
|
||||
case USB_AUTHORIZE_NONE:
|
||||
hcd->dev_policy = USB_DEVICE_AUTHORIZE_NONE;
|
||||
break;
|
||||
|
||||
case USB_AUTHORIZE_ALL:
|
||||
hcd->dev_policy = USB_DEVICE_AUTHORIZE_ALL;
|
||||
break;
|
||||
|
||||
case USB_AUTHORIZE_INTERNAL:
|
||||
hcd->dev_policy = USB_DEVICE_AUTHORIZE_INTERNAL;
|
||||
break;
|
||||
|
||||
case USB_AUTHORIZE_WIRED:
|
||||
default:
|
||||
hcd->dev_policy = hcd->wireless ?
|
||||
USB_DEVICE_AUTHORIZE_NONE : USB_DEVICE_AUTHORIZE_ALL;
|
||||
break;
|
||||
}
|
||||
|
||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
|
||||
/* per default all interfaces are authorized */
|
||||
|
@ -108,6 +108,8 @@ EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem);
|
||||
static void hub_release(struct kref *kref);
|
||||
static int usb_reset_and_verify_device(struct usb_device *udev);
|
||||
static int hub_port_disable(struct usb_hub *hub, int port1, int set_state);
|
||||
static bool hub_port_warm_reset_required(struct usb_hub *hub, int port1,
|
||||
u16 portstatus);
|
||||
|
||||
static inline char *portspeed(struct usb_hub *hub, int portstatus)
|
||||
{
|
||||
@ -607,6 +609,36 @@ static int hub_port_status(struct usb_hub *hub, int port1,
|
||||
status, change, NULL);
|
||||
}
|
||||
|
||||
static void hub_resubmit_irq_urb(struct usb_hub *hub)
|
||||
{
|
||||
unsigned long flags;
|
||||
int status;
|
||||
|
||||
spin_lock_irqsave(&hub->irq_urb_lock, flags);
|
||||
|
||||
if (hub->quiescing) {
|
||||
spin_unlock_irqrestore(&hub->irq_urb_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
status = usb_submit_urb(hub->urb, GFP_ATOMIC);
|
||||
if (status && status != -ENODEV && status != -EPERM &&
|
||||
status != -ESHUTDOWN) {
|
||||
dev_err(hub->intfdev, "resubmit --> %d\n", status);
|
||||
mod_timer(&hub->irq_urb_retry, jiffies + HZ);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&hub->irq_urb_lock, flags);
|
||||
}
|
||||
|
||||
static void hub_retry_irq_urb(struct timer_list *t)
|
||||
{
|
||||
struct usb_hub *hub = from_timer(hub, t, irq_urb_retry);
|
||||
|
||||
hub_resubmit_irq_urb(hub);
|
||||
}
|
||||
|
||||
|
||||
static void kick_hub_wq(struct usb_hub *hub)
|
||||
{
|
||||
struct usb_interface *intf;
|
||||
@ -709,12 +741,7 @@ static void hub_irq(struct urb *urb)
|
||||
kick_hub_wq(hub);
|
||||
|
||||
resubmit:
|
||||
if (hub->quiescing)
|
||||
return;
|
||||
|
||||
status = usb_submit_urb(hub->urb, GFP_ATOMIC);
|
||||
if (status != 0 && status != -ENODEV && status != -EPERM)
|
||||
dev_err(hub->intfdev, "resubmit --> %d\n", status);
|
||||
hub_resubmit_irq_urb(hub);
|
||||
}
|
||||
|
||||
/* USB 2.0 spec Section 11.24.2.3 */
|
||||
@ -1112,6 +1139,11 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
|
||||
USB_PORT_FEAT_ENABLE);
|
||||
}
|
||||
|
||||
/* Make sure a warm-reset request is handled by port_event */
|
||||
if (type == HUB_RESUME &&
|
||||
hub_port_warm_reset_required(hub, port1, portstatus))
|
||||
set_bit(port1, hub->event_bits);
|
||||
|
||||
/*
|
||||
* Add debounce if USB3 link is in polling/link training state.
|
||||
* Link will automatically transition to Enabled state after
|
||||
@ -1264,10 +1296,13 @@ enum hub_quiescing_type {
|
||||
static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type)
|
||||
{
|
||||
struct usb_device *hdev = hub->hdev;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
/* hub_wq and related activity won't re-trigger */
|
||||
spin_lock_irqsave(&hub->irq_urb_lock, flags);
|
||||
hub->quiescing = 1;
|
||||
spin_unlock_irqrestore(&hub->irq_urb_lock, flags);
|
||||
|
||||
if (type != HUB_SUSPEND) {
|
||||
/* Disconnect all the children */
|
||||
@ -1278,6 +1313,7 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type)
|
||||
}
|
||||
|
||||
/* Stop hub_wq and related activity */
|
||||
del_timer_sync(&hub->irq_urb_retry);
|
||||
usb_kill_urb(hub->urb);
|
||||
if (hub->has_indicators)
|
||||
cancel_delayed_work_sync(&hub->leds);
|
||||
@ -1810,6 +1846,8 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
INIT_DELAYED_WORK(&hub->leds, led_work);
|
||||
INIT_DELAYED_WORK(&hub->init_work, NULL);
|
||||
INIT_WORK(&hub->events, hub_event);
|
||||
spin_lock_init(&hub->irq_urb_lock);
|
||||
timer_setup(&hub->irq_urb_retry, hub_retry_irq_urb, 0);
|
||||
usb_get_intf(intf);
|
||||
usb_get_dev(hdev);
|
||||
|
||||
@ -3220,8 +3258,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
|
||||
}
|
||||
|
||||
/* disable USB2 hardware LPM */
|
||||
if (udev->usb2_hw_lpm_enabled == 1)
|
||||
usb_set_usb2_hardware_lpm(udev, 0);
|
||||
usb_disable_usb2_hardware_lpm(udev);
|
||||
|
||||
if (usb_disable_ltm(udev)) {
|
||||
dev_err(&udev->dev, "Failed to disable LTM before suspend\n");
|
||||
@ -3259,8 +3296,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
|
||||
usb_enable_ltm(udev);
|
||||
err_ltm:
|
||||
/* Try to enable USB2 hardware LPM again */
|
||||
if (udev->usb2_hw_lpm_capable == 1)
|
||||
usb_set_usb2_hardware_lpm(udev, 1);
|
||||
usb_enable_usb2_hardware_lpm(udev);
|
||||
|
||||
if (udev->do_remote_wakeup)
|
||||
(void) usb_disable_remote_wakeup(udev);
|
||||
@ -3543,8 +3579,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
|
||||
hub_port_logical_disconnect(hub, port1);
|
||||
} else {
|
||||
/* Try to enable USB2 hardware LPM */
|
||||
if (udev->usb2_hw_lpm_capable == 1)
|
||||
usb_set_usb2_hardware_lpm(udev, 1);
|
||||
usb_enable_usb2_hardware_lpm(udev);
|
||||
|
||||
/* Try to enable USB3 LTM */
|
||||
usb_enable_ltm(udev);
|
||||
@ -4435,7 +4470,7 @@ static void hub_set_initial_usb2_lpm_policy(struct usb_device *udev)
|
||||
if ((udev->bos->ext_cap->bmAttributes & cpu_to_le32(USB_BESL_SUPPORT)) ||
|
||||
connect_type == USB_PORT_CONNECT_TYPE_HARD_WIRED) {
|
||||
udev->usb2_hw_lpm_allowed = 1;
|
||||
usb_set_usb2_hardware_lpm(udev, 1);
|
||||
usb_enable_usb2_hardware_lpm(udev);
|
||||
}
|
||||
}
|
||||
|
||||
@ -5649,8 +5684,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
|
||||
/* Disable USB2 hardware LPM.
|
||||
* It will be re-enabled by the enumeration process.
|
||||
*/
|
||||
if (udev->usb2_hw_lpm_enabled == 1)
|
||||
usb_set_usb2_hardware_lpm(udev, 0);
|
||||
usb_disable_usb2_hardware_lpm(udev);
|
||||
|
||||
/* Disable LPM while we reset the device and reinstall the alt settings.
|
||||
* Device-initiated LPM, and system exit latency settings are cleared
|
||||
@ -5753,7 +5787,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
|
||||
|
||||
done:
|
||||
/* Now that the alt settings are re-installed, enable LTM and LPM. */
|
||||
usb_set_usb2_hardware_lpm(udev, 1);
|
||||
usb_enable_usb2_hardware_lpm(udev);
|
||||
usb_unlocked_enable_lpm(udev);
|
||||
usb_enable_ltm(udev);
|
||||
usb_release_bos_descriptor(udev);
|
||||
|
@ -69,6 +69,8 @@ struct usb_hub {
|
||||
struct delayed_work leds;
|
||||
struct delayed_work init_work;
|
||||
struct work_struct events;
|
||||
spinlock_t irq_urb_lock;
|
||||
struct timer_list irq_urb_retry;
|
||||
struct usb_port **ports;
|
||||
};
|
||||
|
||||
|
@ -1243,8 +1243,7 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
|
||||
dev->actconfig->interface[i] = NULL;
|
||||
}
|
||||
|
||||
if (dev->usb2_hw_lpm_enabled == 1)
|
||||
usb_set_usb2_hardware_lpm(dev, 0);
|
||||
usb_disable_usb2_hardware_lpm(dev);
|
||||
usb_unlocked_disable_lpm(dev);
|
||||
usb_disable_ltm(dev);
|
||||
|
||||
@ -2007,6 +2006,13 @@ free_interfaces:
|
||||
for (i = 0; i < nintf; ++i) {
|
||||
struct usb_interface *intf = cp->interface[i];
|
||||
|
||||
if (intf->dev.of_node &&
|
||||
!of_device_is_available(intf->dev.of_node)) {
|
||||
dev_info(&dev->dev, "skipping disabled interface %d\n",
|
||||
intf->cur_altsetting->desc.bInterfaceNumber);
|
||||
continue;
|
||||
}
|
||||
|
||||
dev_dbg(&dev->dev,
|
||||
"adding %s (config #%d, interface %d)\n",
|
||||
dev_name(&intf->dev), configuration,
|
||||
|
@ -123,6 +123,34 @@ int usb_phy_roothub_exit(struct usb_phy_roothub *phy_roothub)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_phy_roothub_exit);
|
||||
|
||||
int usb_phy_roothub_set_mode(struct usb_phy_roothub *phy_roothub,
|
||||
enum phy_mode mode)
|
||||
{
|
||||
struct usb_phy_roothub *roothub_entry;
|
||||
struct list_head *head;
|
||||
int err;
|
||||
|
||||
if (!phy_roothub)
|
||||
return 0;
|
||||
|
||||
head = &phy_roothub->list;
|
||||
|
||||
list_for_each_entry(roothub_entry, head, list) {
|
||||
err = phy_set_mode(roothub_entry->phy, mode);
|
||||
if (err)
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
list_for_each_entry_continue_reverse(roothub_entry, head, list)
|
||||
phy_power_off(roothub_entry->phy);
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_phy_roothub_set_mode);
|
||||
|
||||
int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub)
|
||||
{
|
||||
struct usb_phy_roothub *roothub_entry;
|
||||
|
@ -16,6 +16,8 @@ struct usb_phy_roothub *usb_phy_roothub_alloc(struct device *dev);
|
||||
int usb_phy_roothub_init(struct usb_phy_roothub *phy_roothub);
|
||||
int usb_phy_roothub_exit(struct usb_phy_roothub *phy_roothub);
|
||||
|
||||
int usb_phy_roothub_set_mode(struct usb_phy_roothub *phy_roothub,
|
||||
enum phy_mode mode);
|
||||
int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub);
|
||||
void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub);
|
||||
|
||||
|
@ -528,7 +528,10 @@ static ssize_t usb2_hardware_lpm_store(struct device *dev,
|
||||
|
||||
if (!ret) {
|
||||
udev->usb2_hw_lpm_allowed = value;
|
||||
ret = usb_set_usb2_hardware_lpm(udev, value);
|
||||
if (value)
|
||||
ret = usb_enable_usb2_hardware_lpm(udev);
|
||||
else
|
||||
ret = usb_disable_usb2_hardware_lpm(udev);
|
||||
}
|
||||
|
||||
usb_unlock_device(udev);
|
||||
|
@ -70,9 +70,8 @@ struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)
|
||||
{
|
||||
struct urb *urb;
|
||||
|
||||
urb = kmalloc(sizeof(struct urb) +
|
||||
iso_packets * sizeof(struct usb_iso_packet_descriptor),
|
||||
mem_flags);
|
||||
urb = kmalloc(struct_size(urb, iso_frame_desc, iso_packets),
|
||||
mem_flags);
|
||||
if (!urb)
|
||||
return NULL;
|
||||
usb_init_urb(urb);
|
||||
|
@ -46,8 +46,7 @@
|
||||
#include <linux/mm.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include "usb.h"
|
||||
|
||||
#include "hub.h"
|
||||
|
||||
const char *usbcore_name = "usbcore";
|
||||
|
||||
@ -65,8 +64,8 @@ int usb_disabled(void)
|
||||
EXPORT_SYMBOL_GPL(usb_disabled);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int usb_autosuspend_delay = 2; /* Default delay value,
|
||||
* in seconds */
|
||||
/* Default delay value, in seconds */
|
||||
static int usb_autosuspend_delay = CONFIG_USB_AUTOSUSPEND_DELAY;
|
||||
module_param_named(autosuspend, usb_autosuspend_delay, int, 0644);
|
||||
MODULE_PARM_DESC(autosuspend, "default autosuspend delay");
|
||||
|
||||
@ -536,6 +535,27 @@ static unsigned usb_bus_is_wusb(struct usb_bus *bus)
|
||||
return hcd->wireless;
|
||||
}
|
||||
|
||||
static bool usb_dev_authorized(struct usb_device *dev, struct usb_hcd *hcd)
|
||||
{
|
||||
struct usb_hub *hub;
|
||||
|
||||
if (!dev->parent)
|
||||
return true; /* Root hub always ok [and always wired] */
|
||||
|
||||
switch (hcd->dev_policy) {
|
||||
case USB_DEVICE_AUTHORIZE_NONE:
|
||||
default:
|
||||
return false;
|
||||
|
||||
case USB_DEVICE_AUTHORIZE_ALL:
|
||||
return true;
|
||||
|
||||
case USB_DEVICE_AUTHORIZE_INTERNAL:
|
||||
hub = usb_hub_to_struct_hub(dev->parent);
|
||||
return hub->ports[dev->portnum - 1]->connect_type ==
|
||||
USB_PORT_CONNECT_TYPE_HARD_WIRED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_alloc_dev - usb device constructor (usbcore-internal)
|
||||
@ -663,12 +683,11 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
|
||||
dev->connect_time = jiffies;
|
||||
dev->active_duration = -jiffies;
|
||||
#endif
|
||||
if (root_hub) /* Root hub always ok [and always wired] */
|
||||
dev->authorized = 1;
|
||||
else {
|
||||
dev->authorized = !!HCD_DEV_AUTHORIZED(usb_hcd);
|
||||
|
||||
dev->authorized = usb_dev_authorized(dev, usb_hcd);
|
||||
if (!root_hub)
|
||||
dev->wusb = usb_bus_is_wusb(bus) ? 1 : 0;
|
||||
}
|
||||
|
||||
return dev;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_alloc_dev);
|
||||
|
@ -92,7 +92,8 @@ extern int usb_remote_wakeup(struct usb_device *dev);
|
||||
extern int usb_runtime_suspend(struct device *dev);
|
||||
extern int usb_runtime_resume(struct device *dev);
|
||||
extern int usb_runtime_idle(struct device *dev);
|
||||
extern int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable);
|
||||
extern int usb_enable_usb2_hardware_lpm(struct usb_device *udev);
|
||||
extern int usb_disable_usb2_hardware_lpm(struct usb_device *udev);
|
||||
|
||||
#else
|
||||
|
||||
@ -112,7 +113,12 @@ static inline int usb_autoresume_device(struct usb_device *udev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)
|
||||
static inline int usb_enable_usb2_hardware_lpm(struct usb_device *udev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int usb_disable_usb2_hardware_lpm(struct usb_device *udev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
config USB_DWC2
|
||||
tristate "DesignWare USB2 DRD Core Support"
|
||||
depends on HAS_DMA
|
||||
|
@ -768,22 +768,13 @@ static u32 dwc2_gadget_get_desc_params(struct dwc2_hsotg_ep *hs_ep, u32 *mask)
|
||||
return desc_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* dwc2_gadget_config_nonisoc_xfer_ddma - prepare non ISOC DMA desc chain.
|
||||
* @hs_ep: The endpoint
|
||||
* @dma_buff: DMA address to use
|
||||
* @len: Length of the transfer
|
||||
*
|
||||
* This function will iterate over descriptor chain and fill its entries
|
||||
* with corresponding information based on transfer data.
|
||||
*/
|
||||
static void dwc2_gadget_config_nonisoc_xfer_ddma(struct dwc2_hsotg_ep *hs_ep,
|
||||
static void dwc2_gadget_fill_nonisoc_xfer_ddma_one(struct dwc2_hsotg_ep *hs_ep,
|
||||
struct dwc2_dma_desc **desc,
|
||||
dma_addr_t dma_buff,
|
||||
unsigned int len)
|
||||
unsigned int len,
|
||||
bool true_last)
|
||||
{
|
||||
struct dwc2_hsotg *hsotg = hs_ep->parent;
|
||||
int dir_in = hs_ep->dir_in;
|
||||
struct dwc2_dma_desc *desc = hs_ep->desc_list;
|
||||
u32 mps = hs_ep->ep.maxpacket;
|
||||
u32 maxsize = 0;
|
||||
u32 offset = 0;
|
||||
@ -798,41 +789,79 @@ static void dwc2_gadget_config_nonisoc_xfer_ddma(struct dwc2_hsotg_ep *hs_ep,
|
||||
hs_ep->desc_count = 1;
|
||||
|
||||
for (i = 0; i < hs_ep->desc_count; ++i) {
|
||||
desc->status = 0;
|
||||
desc->status |= (DEV_DMA_BUFF_STS_HBUSY
|
||||
(*desc)->status = 0;
|
||||
(*desc)->status |= (DEV_DMA_BUFF_STS_HBUSY
|
||||
<< DEV_DMA_BUFF_STS_SHIFT);
|
||||
|
||||
if (len > maxsize) {
|
||||
if (!hs_ep->index && !dir_in)
|
||||
desc->status |= (DEV_DMA_L | DEV_DMA_IOC);
|
||||
(*desc)->status |= (DEV_DMA_L | DEV_DMA_IOC);
|
||||
|
||||
desc->status |= (maxsize <<
|
||||
DEV_DMA_NBYTES_SHIFT & mask);
|
||||
desc->buf = dma_buff + offset;
|
||||
(*desc)->status |=
|
||||
maxsize << DEV_DMA_NBYTES_SHIFT & mask;
|
||||
(*desc)->buf = dma_buff + offset;
|
||||
|
||||
len -= maxsize;
|
||||
offset += maxsize;
|
||||
} else {
|
||||
desc->status |= (DEV_DMA_L | DEV_DMA_IOC);
|
||||
if (true_last)
|
||||
(*desc)->status |= (DEV_DMA_L | DEV_DMA_IOC);
|
||||
|
||||
if (dir_in)
|
||||
desc->status |= (len % mps) ? DEV_DMA_SHORT :
|
||||
((hs_ep->send_zlp) ? DEV_DMA_SHORT : 0);
|
||||
if (len > maxsize)
|
||||
dev_err(hsotg->dev, "wrong len %d\n", len);
|
||||
(*desc)->status |= (len % mps) ? DEV_DMA_SHORT :
|
||||
((hs_ep->send_zlp && true_last) ?
|
||||
DEV_DMA_SHORT : 0);
|
||||
|
||||
desc->status |=
|
||||
(*desc)->status |=
|
||||
len << DEV_DMA_NBYTES_SHIFT & mask;
|
||||
desc->buf = dma_buff + offset;
|
||||
(*desc)->buf = dma_buff + offset;
|
||||
}
|
||||
|
||||
desc->status &= ~DEV_DMA_BUFF_STS_MASK;
|
||||
desc->status |= (DEV_DMA_BUFF_STS_HREADY
|
||||
(*desc)->status &= ~DEV_DMA_BUFF_STS_MASK;
|
||||
(*desc)->status |= (DEV_DMA_BUFF_STS_HREADY
|
||||
<< DEV_DMA_BUFF_STS_SHIFT);
|
||||
desc++;
|
||||
(*desc)++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* dwc2_gadget_config_nonisoc_xfer_ddma - prepare non ISOC DMA desc chain.
|
||||
* @hs_ep: The endpoint
|
||||
* @ureq: Request to transfer
|
||||
* @offset: offset in bytes
|
||||
* @len: Length of the transfer
|
||||
*
|
||||
* This function will iterate over descriptor chain and fill its entries
|
||||
* with corresponding information based on transfer data.
|
||||
*/
|
||||
static void dwc2_gadget_config_nonisoc_xfer_ddma(struct dwc2_hsotg_ep *hs_ep,
|
||||
struct usb_request *ureq,
|
||||
unsigned int offset,
|
||||
unsigned int len)
|
||||
{
|
||||
struct dwc2_dma_desc *desc = hs_ep->desc_list;
|
||||
struct scatterlist *sg;
|
||||
int i;
|
||||
u8 desc_count = 0;
|
||||
|
||||
/* non-DMA sg buffer */
|
||||
if (!ureq->num_sgs) {
|
||||
dwc2_gadget_fill_nonisoc_xfer_ddma_one(hs_ep, &desc,
|
||||
ureq->dma + offset, len, true);
|
||||
return;
|
||||
}
|
||||
|
||||
/* DMA sg buffer */
|
||||
for_each_sg(ureq->sg, sg, ureq->num_sgs, i) {
|
||||
dwc2_gadget_fill_nonisoc_xfer_ddma_one(hs_ep, &desc,
|
||||
sg_dma_address(sg) + sg->offset, sg_dma_len(sg),
|
||||
sg_is_last(sg));
|
||||
desc_count += hs_ep->desc_count;
|
||||
}
|
||||
|
||||
hs_ep->desc_count = desc_count;
|
||||
}
|
||||
|
||||
/*
|
||||
* dwc2_gadget_fill_isoc_desc - fills next isochronous descriptor in chain.
|
||||
* @hs_ep: The isochronous endpoint.
|
||||
@ -944,7 +973,13 @@ static void dwc2_gadget_start_isoc_ddma(struct dwc2_hsotg_ep *hs_ep)
|
||||
|
||||
hs_ep->next_desc = 0;
|
||||
list_for_each_entry_safe(hs_req, treq, &hs_ep->queue, queue) {
|
||||
ret = dwc2_gadget_fill_isoc_desc(hs_ep, hs_req->req.dma,
|
||||
dma_addr_t dma_addr = hs_req->req.dma;
|
||||
|
||||
if (hs_req->req.num_sgs) {
|
||||
WARN_ON(hs_req->req.num_sgs > 1);
|
||||
dma_addr = sg_dma_address(hs_req->req.sg);
|
||||
}
|
||||
ret = dwc2_gadget_fill_isoc_desc(hs_ep, dma_addr,
|
||||
hs_req->req.length);
|
||||
if (ret)
|
||||
break;
|
||||
@ -1100,7 +1135,7 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg,
|
||||
offset = ureq->actual;
|
||||
|
||||
/* Fill DDMA chain entries */
|
||||
dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, ureq->dma + offset,
|
||||
dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, ureq, offset,
|
||||
length);
|
||||
|
||||
/* write descriptor chain address to control register */
|
||||
@ -1399,7 +1434,13 @@ static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req,
|
||||
*/
|
||||
if (using_desc_dma(hs) && hs_ep->isochronous) {
|
||||
if (hs_ep->target_frame != TARGET_FRAME_INITIAL) {
|
||||
dwc2_gadget_fill_isoc_desc(hs_ep, hs_req->req.dma,
|
||||
dma_addr_t dma_addr = hs_req->req.dma;
|
||||
|
||||
if (hs_req->req.num_sgs) {
|
||||
WARN_ON(hs_req->req.num_sgs > 1);
|
||||
dma_addr = sg_dma_address(hs_req->req.sg);
|
||||
}
|
||||
dwc2_gadget_fill_isoc_desc(hs_ep, dma_addr,
|
||||
hs_req->req.length);
|
||||
}
|
||||
return 0;
|
||||
@ -1987,13 +2028,12 @@ static void dwc2_hsotg_program_zlp(struct dwc2_hsotg *hsotg,
|
||||
dev_dbg(hsotg->dev, "Receiving zero-length packet on ep%d\n",
|
||||
index);
|
||||
if (using_desc_dma(hsotg)) {
|
||||
/* Not specific buffer needed for ep0 ZLP */
|
||||
dma_addr_t dma = hs_ep->desc_list_dma;
|
||||
|
||||
if (!index)
|
||||
dwc2_gadget_set_ep0_desc_chain(hsotg, hs_ep);
|
||||
|
||||
dwc2_gadget_config_nonisoc_xfer_ddma(hs_ep, dma, 0);
|
||||
/* Not specific buffer needed for ep0 ZLP */
|
||||
dwc2_gadget_fill_nonisoc_xfer_ddma_one(hs_ep, &hs_ep->desc_list,
|
||||
hs_ep->desc_list_dma, 0, true);
|
||||
} else {
|
||||
dwc2_writel(hsotg, DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) |
|
||||
DXEPTSIZ_XFERSIZE(0),
|
||||
@ -4005,6 +4045,7 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep,
|
||||
ret = -ENOMEM;
|
||||
goto error1;
|
||||
}
|
||||
epctrl &= ~(DXEPCTL_TXFNUM_LIMIT << DXEPCTL_TXFNUM_SHIFT);
|
||||
hsotg->fifo_map |= 1 << fifo_index;
|
||||
epctrl |= DXEPCTL_TXFNUM(fifo_index);
|
||||
hs_ep->fifo_index = fifo_index;
|
||||
@ -4385,6 +4426,7 @@ static int dwc2_hsotg_udc_start(struct usb_gadget *gadget,
|
||||
hsotg->enabled = 0;
|
||||
spin_unlock_irqrestore(&hsotg->lock, flags);
|
||||
|
||||
gadget->sg_supported = using_desc_dma(hsotg);
|
||||
dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name);
|
||||
|
||||
return 0;
|
||||
|
@ -3981,10 +3981,8 @@ static struct dwc2_hcd_urb *dwc2_hcd_urb_alloc(struct dwc2_hsotg *hsotg,
|
||||
gfp_t mem_flags)
|
||||
{
|
||||
struct dwc2_hcd_urb *urb;
|
||||
u32 size = sizeof(*urb) + iso_desc_count *
|
||||
sizeof(struct dwc2_hcd_iso_packet_desc);
|
||||
|
||||
urb = kzalloc(size, mem_flags);
|
||||
urb = kzalloc(struct_size(urb, iso_descs, iso_desc_count), mem_flags);
|
||||
if (urb)
|
||||
urb->packet_count = iso_desc_count;
|
||||
return urb;
|
||||
|
@ -1,3 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
config USB_DWC3
|
||||
tristate "DesignWare USB3 DRD Core Support"
|
||||
depends on (USB || USB_GADGET) && HAS_DMA
|
||||
@ -86,11 +88,11 @@ config USB_DWC3_HAPS
|
||||
platform, please say 'Y' or 'M' here.
|
||||
|
||||
config USB_DWC3_KEYSTONE
|
||||
tristate "Texas Instruments Keystone2 Platforms"
|
||||
depends on ARCH_KEYSTONE || COMPILE_TEST
|
||||
tristate "Texas Instruments Keystone2/AM654 Platforms"
|
||||
depends on ARCH_KEYSTONE || ARCH_K3 || COMPILE_TEST
|
||||
default USB_DWC3
|
||||
help
|
||||
Support of USB2/3 functionality in TI Keystone2 platforms.
|
||||
Support of USB2/3 functionality in TI Keystone2 and AM654 platforms.
|
||||
Say 'Y' or 'M' here if you have one such device
|
||||
|
||||
config USB_DWC3_OF_SIMPLE
|
||||
|
@ -692,7 +692,6 @@ struct dwc3_ep {
|
||||
#define DWC3_EP_WEDGE BIT(2)
|
||||
#define DWC3_EP_TRANSFER_STARTED BIT(3)
|
||||
#define DWC3_EP_PENDING_REQUEST BIT(5)
|
||||
#define DWC3_EP_END_TRANSFER_PENDING BIT(7)
|
||||
|
||||
/* This last one is specific to EP0 */
|
||||
#define DWC3_EP0_DIR_IN BIT(31)
|
||||
@ -863,6 +862,7 @@ struct dwc3_hwparams {
|
||||
* @num_pending_sgs: counter to pending sgs
|
||||
* @num_queued_sgs: counter to the number of sgs which already got queued
|
||||
* @remaining: amount of data remaining
|
||||
* @status: internal dwc3 request status tracking
|
||||
* @epnum: endpoint number to which this request refers
|
||||
* @trb: pointer to struct dwc3_trb
|
||||
* @trb_dma: DMA address of @trb
|
||||
@ -871,7 +871,6 @@ struct dwc3_hwparams {
|
||||
* or unaligned OUT)
|
||||
* @direction: IN or OUT direction flag
|
||||
* @mapped: true when request has been dma-mapped
|
||||
* @started: request is started
|
||||
*/
|
||||
struct dwc3_request {
|
||||
struct usb_request request;
|
||||
@ -883,6 +882,14 @@ struct dwc3_request {
|
||||
unsigned num_pending_sgs;
|
||||
unsigned int num_queued_sgs;
|
||||
unsigned remaining;
|
||||
|
||||
unsigned int status;
|
||||
#define DWC3_REQUEST_STATUS_QUEUED 0
|
||||
#define DWC3_REQUEST_STATUS_STARTED 1
|
||||
#define DWC3_REQUEST_STATUS_CANCELLED 2
|
||||
#define DWC3_REQUEST_STATUS_COMPLETED 3
|
||||
#define DWC3_REQUEST_STATUS_UNKNOWN -1
|
||||
|
||||
u8 epnum;
|
||||
struct dwc3_trb *trb;
|
||||
dma_addr_t trb_dma;
|
||||
@ -892,7 +899,6 @@ struct dwc3_request {
|
||||
unsigned needs_extra_trb:1;
|
||||
unsigned direction:1;
|
||||
unsigned mapped:1;
|
||||
unsigned started:1;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -193,65 +193,69 @@ static inline const char *dwc3_ep0_state_string(enum dwc3_ep0_state state)
|
||||
* dwc3_gadget_event_string - returns event name
|
||||
* @event: the event code
|
||||
*/
|
||||
static inline const char *
|
||||
dwc3_gadget_event_string(char *str, const struct dwc3_event_devt *event)
|
||||
static inline const char *dwc3_gadget_event_string(char *str, size_t size,
|
||||
const struct dwc3_event_devt *event)
|
||||
{
|
||||
enum dwc3_link_state state = event->event_info & DWC3_LINK_STATE_MASK;
|
||||
|
||||
switch (event->type) {
|
||||
case DWC3_DEVICE_EVENT_DISCONNECT:
|
||||
sprintf(str, "Disconnect: [%s]",
|
||||
snprintf(str, size, "Disconnect: [%s]",
|
||||
dwc3_gadget_link_string(state));
|
||||
break;
|
||||
case DWC3_DEVICE_EVENT_RESET:
|
||||
sprintf(str, "Reset [%s]", dwc3_gadget_link_string(state));
|
||||
snprintf(str, size, "Reset [%s]",
|
||||
dwc3_gadget_link_string(state));
|
||||
break;
|
||||
case DWC3_DEVICE_EVENT_CONNECT_DONE:
|
||||
sprintf(str, "Connection Done [%s]",
|
||||
snprintf(str, size, "Connection Done [%s]",
|
||||
dwc3_gadget_link_string(state));
|
||||
break;
|
||||
case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
|
||||
sprintf(str, "Link Change [%s]",
|
||||
snprintf(str, size, "Link Change [%s]",
|
||||
dwc3_gadget_link_string(state));
|
||||
break;
|
||||
case DWC3_DEVICE_EVENT_WAKEUP:
|
||||
sprintf(str, "WakeUp [%s]", dwc3_gadget_link_string(state));
|
||||
snprintf(str, size, "WakeUp [%s]",
|
||||
dwc3_gadget_link_string(state));
|
||||
break;
|
||||
case DWC3_DEVICE_EVENT_EOPF:
|
||||
sprintf(str, "End-Of-Frame [%s]",
|
||||
snprintf(str, size, "End-Of-Frame [%s]",
|
||||
dwc3_gadget_link_string(state));
|
||||
break;
|
||||
case DWC3_DEVICE_EVENT_SOF:
|
||||
sprintf(str, "Start-Of-Frame [%s]",
|
||||
snprintf(str, size, "Start-Of-Frame [%s]",
|
||||
dwc3_gadget_link_string(state));
|
||||
break;
|
||||
case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
|
||||
sprintf(str, "Erratic Error [%s]",
|
||||
snprintf(str, size, "Erratic Error [%s]",
|
||||
dwc3_gadget_link_string(state));
|
||||
break;
|
||||
case DWC3_DEVICE_EVENT_CMD_CMPL:
|
||||
sprintf(str, "Command Complete [%s]",
|
||||
snprintf(str, size, "Command Complete [%s]",
|
||||
dwc3_gadget_link_string(state));
|
||||
break;
|
||||
case DWC3_DEVICE_EVENT_OVERFLOW:
|
||||
sprintf(str, "Overflow [%s]", dwc3_gadget_link_string(state));
|
||||
snprintf(str, size, "Overflow [%s]",
|
||||
dwc3_gadget_link_string(state));
|
||||
break;
|
||||
default:
|
||||
sprintf(str, "UNKNOWN");
|
||||
snprintf(str, size, "UNKNOWN");
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static inline void dwc3_decode_get_status(__u8 t, __u16 i, __u16 l, char *str)
|
||||
static inline void dwc3_decode_get_status(__u8 t, __u16 i, __u16 l, char *str,
|
||||
size_t size)
|
||||
{
|
||||
switch (t & USB_RECIP_MASK) {
|
||||
case USB_RECIP_INTERFACE:
|
||||
sprintf(str, "Get Interface Status(Intf = %d, Length = %d)",
|
||||
i, l);
|
||||
snprintf(str, size, "Get Interface Status(Intf = %d, Length = %d)",
|
||||
i, l);
|
||||
break;
|
||||
case USB_RECIP_ENDPOINT:
|
||||
sprintf(str, "Get Endpoint Status(ep%d%s)",
|
||||
snprintf(str, size, "Get Endpoint Status(ep%d%s)",
|
||||
i & ~USB_DIR_IN,
|
||||
i & USB_DIR_IN ? "in" : "out");
|
||||
break;
|
||||
@ -259,11 +263,11 @@ static inline void dwc3_decode_get_status(__u8 t, __u16 i, __u16 l, char *str)
|
||||
}
|
||||
|
||||
static inline void dwc3_decode_set_clear_feature(__u8 t, __u8 b, __u16 v,
|
||||
__u16 i, char *str)
|
||||
__u16 i, char *str, size_t size)
|
||||
{
|
||||
switch (t & USB_RECIP_MASK) {
|
||||
case USB_RECIP_DEVICE:
|
||||
sprintf(str, "%s Device Feature(%s%s)",
|
||||
snprintf(str, size, "%s Device Feature(%s%s)",
|
||||
b == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set",
|
||||
({char *s;
|
||||
switch (v) {
|
||||
@ -311,13 +315,13 @@ static inline void dwc3_decode_set_clear_feature(__u8 t, __u8 b, __u16 v,
|
||||
} s; }) : "");
|
||||
break;
|
||||
case USB_RECIP_INTERFACE:
|
||||
sprintf(str, "%s Interface Feature(%s)",
|
||||
snprintf(str, size, "%s Interface Feature(%s)",
|
||||
b == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set",
|
||||
v == USB_INTRF_FUNC_SUSPEND ?
|
||||
"Function Suspend" : "UNKNOWN");
|
||||
break;
|
||||
case USB_RECIP_ENDPOINT:
|
||||
sprintf(str, "%s Endpoint Feature(%s ep%d%s)",
|
||||
snprintf(str, size, "%s Endpoint Feature(%s ep%d%s)",
|
||||
b == USB_REQ_CLEAR_FEATURE ? "Clear" : "Set",
|
||||
v == USB_ENDPOINT_HALT ? "Halt" : "UNKNOWN",
|
||||
i & ~USB_DIR_IN,
|
||||
@ -326,15 +330,15 @@ static inline void dwc3_decode_set_clear_feature(__u8 t, __u8 b, __u16 v,
|
||||
}
|
||||
}
|
||||
|
||||
static inline void dwc3_decode_set_address(__u16 v, char *str)
|
||||
static inline void dwc3_decode_set_address(__u16 v, char *str, size_t size)
|
||||
{
|
||||
sprintf(str, "Set Address(Addr = %02x)", v);
|
||||
snprintf(str, size, "Set Address(Addr = %02x)", v);
|
||||
}
|
||||
|
||||
static inline void dwc3_decode_get_set_descriptor(__u8 t, __u8 b, __u16 v,
|
||||
__u16 i, __u16 l, char *str)
|
||||
__u16 i, __u16 l, char *str, size_t size)
|
||||
{
|
||||
sprintf(str, "%s %s Descriptor(Index = %d, Length = %d)",
|
||||
snprintf(str, size, "%s %s Descriptor(Index = %d, Length = %d)",
|
||||
b == USB_REQ_GET_DESCRIPTOR ? "Get" : "Set",
|
||||
({ char *s;
|
||||
switch (v >> 8) {
|
||||
@ -393,87 +397,92 @@ static inline void dwc3_decode_get_set_descriptor(__u8 t, __u8 b, __u16 v,
|
||||
}
|
||||
|
||||
|
||||
static inline void dwc3_decode_get_configuration(__u16 l, char *str)
|
||||
static inline void dwc3_decode_get_configuration(__u16 l, char *str,
|
||||
size_t size)
|
||||
{
|
||||
sprintf(str, "Get Configuration(Length = %d)", l);
|
||||
snprintf(str, size, "Get Configuration(Length = %d)", l);
|
||||
}
|
||||
|
||||
static inline void dwc3_decode_set_configuration(__u8 v, char *str)
|
||||
static inline void dwc3_decode_set_configuration(__u8 v, char *str, size_t size)
|
||||
{
|
||||
sprintf(str, "Set Configuration(Config = %d)", v);
|
||||
snprintf(str, size, "Set Configuration(Config = %d)", v);
|
||||
}
|
||||
|
||||
static inline void dwc3_decode_get_intf(__u16 i, __u16 l, char *str)
|
||||
static inline void dwc3_decode_get_intf(__u16 i, __u16 l, char *str,
|
||||
size_t size)
|
||||
{
|
||||
sprintf(str, "Get Interface(Intf = %d, Length = %d)", i, l);
|
||||
snprintf(str, size, "Get Interface(Intf = %d, Length = %d)", i, l);
|
||||
}
|
||||
|
||||
static inline void dwc3_decode_set_intf(__u8 v, __u16 i, char *str)
|
||||
static inline void dwc3_decode_set_intf(__u8 v, __u16 i, char *str, size_t size)
|
||||
{
|
||||
sprintf(str, "Set Interface(Intf = %d, Alt.Setting = %d)", i, v);
|
||||
snprintf(str, size, "Set Interface(Intf = %d, Alt.Setting = %d)", i, v);
|
||||
}
|
||||
|
||||
static inline void dwc3_decode_synch_frame(__u16 i, __u16 l, char *str)
|
||||
static inline void dwc3_decode_synch_frame(__u16 i, __u16 l, char *str,
|
||||
size_t size)
|
||||
{
|
||||
sprintf(str, "Synch Frame(Endpoint = %d, Length = %d)", i, l);
|
||||
snprintf(str, size, "Synch Frame(Endpoint = %d, Length = %d)", i, l);
|
||||
}
|
||||
|
||||
static inline void dwc3_decode_set_sel(__u16 l, char *str)
|
||||
static inline void dwc3_decode_set_sel(__u16 l, char *str, size_t size)
|
||||
{
|
||||
sprintf(str, "Set SEL(Length = %d)", l);
|
||||
snprintf(str, size, "Set SEL(Length = %d)", l);
|
||||
}
|
||||
|
||||
static inline void dwc3_decode_set_isoch_delay(__u8 v, char *str)
|
||||
static inline void dwc3_decode_set_isoch_delay(__u8 v, char *str, size_t size)
|
||||
{
|
||||
sprintf(str, "Set Isochronous Delay(Delay = %d ns)", v);
|
||||
snprintf(str, size, "Set Isochronous Delay(Delay = %d ns)", v);
|
||||
}
|
||||
|
||||
/**
|
||||
* dwc3_decode_ctrl - returns a string represetion of ctrl request
|
||||
*/
|
||||
static inline const char *dwc3_decode_ctrl(char *str, __u8 bRequestType,
|
||||
__u8 bRequest, __u16 wValue, __u16 wIndex, __u16 wLength)
|
||||
static inline const char *dwc3_decode_ctrl(char *str, size_t size,
|
||||
__u8 bRequestType, __u8 bRequest, __u16 wValue, __u16 wIndex,
|
||||
__u16 wLength)
|
||||
{
|
||||
switch (bRequest) {
|
||||
case USB_REQ_GET_STATUS:
|
||||
dwc3_decode_get_status(bRequestType, wIndex, wLength, str);
|
||||
dwc3_decode_get_status(bRequestType, wIndex, wLength, str,
|
||||
size);
|
||||
break;
|
||||
case USB_REQ_CLEAR_FEATURE:
|
||||
case USB_REQ_SET_FEATURE:
|
||||
dwc3_decode_set_clear_feature(bRequestType, bRequest, wValue,
|
||||
wIndex, str);
|
||||
wIndex, str, size);
|
||||
break;
|
||||
case USB_REQ_SET_ADDRESS:
|
||||
dwc3_decode_set_address(wValue, str);
|
||||
dwc3_decode_set_address(wValue, str, size);
|
||||
break;
|
||||
case USB_REQ_GET_DESCRIPTOR:
|
||||
case USB_REQ_SET_DESCRIPTOR:
|
||||
dwc3_decode_get_set_descriptor(bRequestType, bRequest, wValue,
|
||||
wIndex, wLength, str);
|
||||
wIndex, wLength, str, size);
|
||||
break;
|
||||
case USB_REQ_GET_CONFIGURATION:
|
||||
dwc3_decode_get_configuration(wLength, str);
|
||||
dwc3_decode_get_configuration(wLength, str, size);
|
||||
break;
|
||||
case USB_REQ_SET_CONFIGURATION:
|
||||
dwc3_decode_set_configuration(wValue, str);
|
||||
dwc3_decode_set_configuration(wValue, str, size);
|
||||
break;
|
||||
case USB_REQ_GET_INTERFACE:
|
||||
dwc3_decode_get_intf(wIndex, wLength, str);
|
||||
dwc3_decode_get_intf(wIndex, wLength, str, size);
|
||||
break;
|
||||
case USB_REQ_SET_INTERFACE:
|
||||
dwc3_decode_set_intf(wValue, wIndex, str);
|
||||
dwc3_decode_set_intf(wValue, wIndex, str, size);
|
||||
break;
|
||||
case USB_REQ_SYNCH_FRAME:
|
||||
dwc3_decode_synch_frame(wIndex, wLength, str);
|
||||
dwc3_decode_synch_frame(wIndex, wLength, str, size);
|
||||
break;
|
||||
case USB_REQ_SET_SEL:
|
||||
dwc3_decode_set_sel(wLength, str);
|
||||
dwc3_decode_set_sel(wLength, str, size);
|
||||
break;
|
||||
case USB_REQ_SET_ISOCH_DELAY:
|
||||
dwc3_decode_set_isoch_delay(wValue, str);
|
||||
dwc3_decode_set_isoch_delay(wValue, str, size);
|
||||
break;
|
||||
default:
|
||||
sprintf(str, "%02x %02x %02x %02x %02x %02x %02x %02x",
|
||||
snprintf(str, size, "%02x %02x %02x %02x %02x %02x %02x %02x",
|
||||
bRequestType, bRequest,
|
||||
cpu_to_le16(wValue) & 0xff,
|
||||
cpu_to_le16(wValue) >> 8,
|
||||
@ -490,16 +499,15 @@ static inline const char *dwc3_decode_ctrl(char *str, __u8 bRequestType,
|
||||
* dwc3_ep_event_string - returns event name
|
||||
* @event: then event code
|
||||
*/
|
||||
static inline const char *
|
||||
dwc3_ep_event_string(char *str, const struct dwc3_event_depevt *event,
|
||||
u32 ep0state)
|
||||
static inline const char *dwc3_ep_event_string(char *str, size_t size,
|
||||
const struct dwc3_event_depevt *event, u32 ep0state)
|
||||
{
|
||||
u8 epnum = event->endpoint_number;
|
||||
size_t len;
|
||||
int status;
|
||||
int ret;
|
||||
|
||||
ret = sprintf(str, "ep%d%s: ", epnum >> 1,
|
||||
ret = snprintf(str, size, "ep%d%s: ", epnum >> 1,
|
||||
(epnum & 1) ? "in" : "out");
|
||||
if (ret < 0)
|
||||
return "UNKNOWN";
|
||||
@ -509,7 +517,7 @@ dwc3_ep_event_string(char *str, const struct dwc3_event_depevt *event,
|
||||
switch (event->endpoint_event) {
|
||||
case DWC3_DEPEVT_XFERCOMPLETE:
|
||||
len = strlen(str);
|
||||
sprintf(str + len, "Transfer Complete (%c%c%c)",
|
||||
snprintf(str + len, size - len, "Transfer Complete (%c%c%c)",
|
||||
status & DEPEVT_STATUS_SHORT ? 'S' : 's',
|
||||
status & DEPEVT_STATUS_IOC ? 'I' : 'i',
|
||||
status & DEPEVT_STATUS_LST ? 'L' : 'l');
|
||||
@ -517,12 +525,13 @@ dwc3_ep_event_string(char *str, const struct dwc3_event_depevt *event,
|
||||
len = strlen(str);
|
||||
|
||||
if (epnum <= 1)
|
||||
sprintf(str + len, " [%s]", dwc3_ep0_state_string(ep0state));
|
||||
snprintf(str + len, size - len, " [%s]",
|
||||
dwc3_ep0_state_string(ep0state));
|
||||
break;
|
||||
case DWC3_DEPEVT_XFERINPROGRESS:
|
||||
len = strlen(str);
|
||||
|
||||
sprintf(str + len, "Transfer In Progress [%d] (%c%c%c)",
|
||||
snprintf(str + len, size - len, "Transfer In Progress [%d] (%c%c%c)",
|
||||
event->parameters,
|
||||
status & DEPEVT_STATUS_SHORT ? 'S' : 's',
|
||||
status & DEPEVT_STATUS_IOC ? 'I' : 'i',
|
||||
@ -531,47 +540,51 @@ dwc3_ep_event_string(char *str, const struct dwc3_event_depevt *event,
|
||||
case DWC3_DEPEVT_XFERNOTREADY:
|
||||
len = strlen(str);
|
||||
|
||||
sprintf(str + len, "Transfer Not Ready [%d]%s",
|
||||
snprintf(str + len, size - len, "Transfer Not Ready [%d]%s",
|
||||
event->parameters,
|
||||
status & DEPEVT_STATUS_TRANSFER_ACTIVE ?
|
||||
" (Active)" : " (Not Active)");
|
||||
|
||||
len = strlen(str);
|
||||
|
||||
/* Control Endpoints */
|
||||
if (epnum <= 1) {
|
||||
int phase = DEPEVT_STATUS_CONTROL_PHASE(event->status);
|
||||
|
||||
switch (phase) {
|
||||
case DEPEVT_STATUS_CONTROL_DATA:
|
||||
strcat(str, " [Data Phase]");
|
||||
snprintf(str + ret, size - ret,
|
||||
" [Data Phase]");
|
||||
break;
|
||||
case DEPEVT_STATUS_CONTROL_STATUS:
|
||||
strcat(str, " [Status Phase]");
|
||||
snprintf(str + ret, size - ret,
|
||||
" [Status Phase]");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DWC3_DEPEVT_RXTXFIFOEVT:
|
||||
strcat(str, "FIFO");
|
||||
snprintf(str + ret, size - ret, "FIFO");
|
||||
break;
|
||||
case DWC3_DEPEVT_STREAMEVT:
|
||||
status = event->status;
|
||||
|
||||
switch (status) {
|
||||
case DEPEVT_STREAMEVT_FOUND:
|
||||
sprintf(str + ret, " Stream %d Found",
|
||||
snprintf(str + ret, size - ret, " Stream %d Found",
|
||||
event->parameters);
|
||||
break;
|
||||
case DEPEVT_STREAMEVT_NOTFOUND:
|
||||
default:
|
||||
strcat(str, " Stream Not Found");
|
||||
snprintf(str + ret, size - ret, " Stream Not Found");
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case DWC3_DEPEVT_EPCMDCMPLT:
|
||||
strcat(str, "Endpoint Command Complete");
|
||||
snprintf(str + ret, size - ret, "Endpoint Command Complete");
|
||||
break;
|
||||
default:
|
||||
sprintf(str, "UNKNOWN");
|
||||
snprintf(str, size, "UNKNOWN");
|
||||
}
|
||||
|
||||
return str;
|
||||
@ -611,14 +624,15 @@ static inline const char *dwc3_gadget_event_type_string(u8 event)
|
||||
}
|
||||
}
|
||||
|
||||
static inline const char *dwc3_decode_event(char *str, u32 event, u32 ep0state)
|
||||
static inline const char *dwc3_decode_event(char *str, size_t size, u32 event,
|
||||
u32 ep0state)
|
||||
{
|
||||
const union dwc3_event evt = (union dwc3_event) event;
|
||||
|
||||
if (evt.type.is_devspec)
|
||||
return dwc3_gadget_event_string(str, &evt.devt);
|
||||
return dwc3_gadget_event_string(str, size, &evt.devt);
|
||||
else
|
||||
return dwc3_ep_event_string(str, &evt.depevt, ep0state);
|
||||
return dwc3_ep_event_string(str, size, &evt.depevt, ep0state);
|
||||
}
|
||||
|
||||
static inline const char *dwc3_ep_cmd_status_string(int status)
|
||||
|
@ -457,8 +457,13 @@ static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc)
|
||||
* This device property is for kernel internal use only and
|
||||
* is expected to be set by the glue code.
|
||||
*/
|
||||
if (device_property_read_string(dev, "linux,extcon-name", &name) == 0)
|
||||
return extcon_get_extcon_dev(name);
|
||||
if (device_property_read_string(dev, "linux,extcon-name", &name) == 0) {
|
||||
edev = extcon_get_extcon_dev(name);
|
||||
if (!edev)
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
return edev;
|
||||
}
|
||||
|
||||
np_phy = of_parse_phandle(dev->of_node, "phys", 0);
|
||||
np_conn = of_graph_get_remote_node(np_phy, -1, -1);
|
||||
|
@ -106,6 +106,15 @@ static const struct pci_device_id dwc3_haps_id_table[] = {
|
||||
{
|
||||
PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
|
||||
PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),
|
||||
/*
|
||||
* i.MX6QP and i.MX7D platform use a PCIe controller with the
|
||||
* same VID and PID as this USB controller. The system may
|
||||
* incorrectly match this driver to that PCIe controller. To
|
||||
* workaround this, specifically use class type USB to prevent
|
||||
* incorrect driver matching.
|
||||
*/
|
||||
.class = (PCI_CLASS_SERIAL_USB << 8),
|
||||
.class_mask = 0xffff00,
|
||||
},
|
||||
{
|
||||
PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
|
||||
|
@ -106,6 +106,10 @@ static int kdwc3_probe(struct platform_device *pdev)
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
/* IRQ processing not required currently for AM65 */
|
||||
if (of_device_is_compatible(node, "ti,am654-dwc3"))
|
||||
goto skip_irq;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&pdev->dev, "missing irq\n");
|
||||
@ -123,6 +127,7 @@ static int kdwc3_probe(struct platform_device *pdev)
|
||||
|
||||
kdwc3_enable_irqs(kdwc);
|
||||
|
||||
skip_irq:
|
||||
error = of_platform_populate(node, NULL, NULL, dev);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "failed to create dwc3 core\n");
|
||||
@ -152,8 +157,11 @@ static int kdwc3_remove_core(struct device *dev, void *c)
|
||||
static int kdwc3_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct dwc3_keystone *kdwc = platform_get_drvdata(pdev);
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
|
||||
if (!of_device_is_compatible(node, "ti,am654-dwc3"))
|
||||
kdwc3_disable_irqs(kdwc);
|
||||
|
||||
kdwc3_disable_irqs(kdwc);
|
||||
device_for_each_child(&pdev->dev, NULL, kdwc3_remove_core);
|
||||
pm_runtime_put_sync(kdwc->dev);
|
||||
pm_runtime_disable(kdwc->dev);
|
||||
@ -165,6 +173,7 @@ static int kdwc3_remove(struct platform_device *pdev)
|
||||
|
||||
static const struct of_device_id kdwc3_of_match[] = {
|
||||
{ .compatible = "ti,keystone-dwc3", },
|
||||
{ .compatible = "ti,am654-dwc3" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, kdwc3_of_match);
|
||||
|
@ -595,6 +595,7 @@ static const struct dev_pm_ops dwc3_qcom_dev_pm_ops = {
|
||||
static const struct of_device_id dwc3_qcom_of_match[] = {
|
||||
{ .compatible = "qcom,dwc3" },
|
||||
{ .compatible = "qcom,msm8996-dwc3" },
|
||||
{ .compatible = "qcom,msm8998-dwc3" },
|
||||
{ .compatible = "qcom,sdm845-dwc3" },
|
||||
{ }
|
||||
};
|
||||
|
@ -174,7 +174,6 @@ static void dwc3_gadget_del_and_unmap_request(struct dwc3_ep *dep,
|
||||
{
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
|
||||
req->started = false;
|
||||
list_del(&req->list);
|
||||
req->remaining = 0;
|
||||
req->needs_extra_trb = false;
|
||||
@ -209,6 +208,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
|
||||
dwc3_gadget_del_and_unmap_request(dep, req, status);
|
||||
req->status = DWC3_REQUEST_STATUS_COMPLETED;
|
||||
|
||||
spin_unlock(&dwc->lock);
|
||||
usb_gadget_giveback_request(&dep->endpoint, &req->request);
|
||||
@ -384,19 +384,9 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned cmd,
|
||||
|
||||
trace_dwc3_gadget_ep_cmd(dep, cmd, params, cmd_status);
|
||||
|
||||
if (ret == 0) {
|
||||
switch (DWC3_DEPCMD_CMD(cmd)) {
|
||||
case DWC3_DEPCMD_STARTTRANSFER:
|
||||
dep->flags |= DWC3_EP_TRANSFER_STARTED;
|
||||
dwc3_gadget_ep_get_transfer_index(dep);
|
||||
break;
|
||||
case DWC3_DEPCMD_ENDTRANSFER:
|
||||
dep->flags &= ~DWC3_EP_TRANSFER_STARTED;
|
||||
break;
|
||||
default:
|
||||
/* nothing */
|
||||
break;
|
||||
}
|
||||
if (ret == 0 && DWC3_DEPCMD_CMD(cmd) == DWC3_DEPCMD_STARTTRANSFER) {
|
||||
dep->flags |= DWC3_EP_TRANSFER_STARTED;
|
||||
dwc3_gadget_ep_get_transfer_index(dep);
|
||||
}
|
||||
|
||||
if (saved_config) {
|
||||
@ -642,7 +632,6 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, unsigned int action)
|
||||
|
||||
dep->type = usb_endpoint_type(desc);
|
||||
dep->flags |= DWC3_EP_ENABLED;
|
||||
dep->flags &= ~DWC3_EP_END_TRANSFER_PENDING;
|
||||
|
||||
reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
|
||||
reg |= DWC3_DALEPENA_EP(dep->number);
|
||||
@ -698,12 +687,13 @@ out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force);
|
||||
static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force,
|
||||
bool interrupt);
|
||||
static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
|
||||
{
|
||||
struct dwc3_request *req;
|
||||
|
||||
dwc3_stop_active_transfer(dep, true);
|
||||
dwc3_stop_active_transfer(dep, true, false);
|
||||
|
||||
/* - giveback all requests to gadget driver */
|
||||
while (!list_empty(&dep->started_list)) {
|
||||
@ -748,7 +738,7 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
|
||||
|
||||
dep->stream_capable = false;
|
||||
dep->type = 0;
|
||||
dep->flags &= DWC3_EP_END_TRANSFER_PENDING;
|
||||
dep->flags = 0;
|
||||
|
||||
/* Clear out the ep descriptors for non-ep0 */
|
||||
if (dep->number > 1) {
|
||||
@ -847,6 +837,7 @@ static struct usb_request *dwc3_gadget_ep_alloc_request(struct usb_ep *ep,
|
||||
req->direction = dep->direction;
|
||||
req->epnum = dep->number;
|
||||
req->dep = dep;
|
||||
req->status = DWC3_REQUEST_STATUS_UNKNOWN;
|
||||
|
||||
trace_dwc3_alloc_request(req);
|
||||
|
||||
@ -1360,7 +1351,7 @@ static int dwc3_gadget_start_isoc_quirk(struct dwc3_ep *dep)
|
||||
* to wait for the next XferNotReady to test the command again
|
||||
*/
|
||||
if (cmd_status == 0) {
|
||||
dwc3_stop_active_transfer(dep, true);
|
||||
dwc3_stop_active_transfer(dep, true, true);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -1435,6 +1426,11 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
||||
&req->request, req->dep->name))
|
||||
return -EINVAL;
|
||||
|
||||
if (WARN(req->status < DWC3_REQUEST_STATUS_COMPLETED,
|
||||
"%s: request %pK already in flight\n",
|
||||
dep->name, &req->request))
|
||||
return -EINVAL;
|
||||
|
||||
pm_runtime_get(dwc->dev);
|
||||
|
||||
req->request.actual = 0;
|
||||
@ -1443,6 +1439,7 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
|
||||
trace_dwc3_ep_queue(req);
|
||||
|
||||
list_add_tail(&req->list, &dep->pending_list);
|
||||
req->status = DWC3_REQUEST_STATUS_QUEUED;
|
||||
|
||||
/*
|
||||
* NOTICE: Isochronous endpoints should NEVER be prestarted. We must
|
||||
@ -1506,6 +1503,8 @@ static void dwc3_gadget_ep_skip_trbs(struct dwc3_ep *dep, struct dwc3_request *r
|
||||
trb->ctrl &= ~DWC3_TRB_CTRL_HWO;
|
||||
dwc3_ep_inc_deq(dep);
|
||||
}
|
||||
|
||||
req->num_trbs = 0;
|
||||
}
|
||||
|
||||
static void dwc3_gadget_ep_cleanup_cancelled_requests(struct dwc3_ep *dep)
|
||||
@ -1547,13 +1546,16 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
|
||||
}
|
||||
if (r == req) {
|
||||
/* wait until it is processed */
|
||||
dwc3_stop_active_transfer(dep, true);
|
||||
dwc3_stop_active_transfer(dep, true, true);
|
||||
|
||||
if (!r->trb)
|
||||
goto out0;
|
||||
|
||||
dwc3_gadget_move_cancelled_request(req);
|
||||
goto out0;
|
||||
if (dep->flags & DWC3_EP_TRANSFER_STARTED)
|
||||
goto out0;
|
||||
else
|
||||
goto out1;
|
||||
}
|
||||
dev_err(dwc->dev, "request %pK was not queued to %s\n",
|
||||
request, ep->name);
|
||||
@ -1561,6 +1563,7 @@ static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
|
||||
goto out0;
|
||||
}
|
||||
|
||||
out1:
|
||||
dwc3_gadget_giveback(dep, req, -ECONNRESET);
|
||||
|
||||
out0:
|
||||
@ -2500,7 +2503,7 @@ static void dwc3_gadget_endpoint_transfer_in_progress(struct dwc3_ep *dep,
|
||||
dwc3_gadget_ep_cleanup_completed_requests(dep, event, status);
|
||||
|
||||
if (stop) {
|
||||
dwc3_stop_active_transfer(dep, true);
|
||||
dwc3_stop_active_transfer(dep, true, true);
|
||||
dep->flags = DWC3_EP_ENABLED;
|
||||
}
|
||||
|
||||
@ -2547,7 +2550,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
|
||||
dep = dwc->eps[epnum];
|
||||
|
||||
if (!(dep->flags & DWC3_EP_ENABLED)) {
|
||||
if (!(dep->flags & DWC3_EP_END_TRANSFER_PENDING))
|
||||
if (!(dep->flags & DWC3_EP_TRANSFER_STARTED))
|
||||
return;
|
||||
|
||||
/* Handle only EPCMDCMPLT when EP disabled */
|
||||
@ -2571,7 +2574,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
|
||||
cmd = DEPEVT_PARAMETER_CMD(event->parameters);
|
||||
|
||||
if (cmd == DWC3_DEPCMD_ENDTRANSFER) {
|
||||
dep->flags &= ~DWC3_EP_END_TRANSFER_PENDING;
|
||||
dep->flags &= ~DWC3_EP_TRANSFER_STARTED;
|
||||
dwc3_gadget_ep_cleanup_cancelled_requests(dep);
|
||||
}
|
||||
break;
|
||||
@ -2621,15 +2624,15 @@ static void dwc3_reset_gadget(struct dwc3 *dwc)
|
||||
}
|
||||
}
|
||||
|
||||
static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force)
|
||||
static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force,
|
||||
bool interrupt)
|
||||
{
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
struct dwc3_gadget_ep_cmd_params params;
|
||||
u32 cmd;
|
||||
int ret;
|
||||
|
||||
if ((dep->flags & DWC3_EP_END_TRANSFER_PENDING) ||
|
||||
!dep->resource_index)
|
||||
if (!(dep->flags & DWC3_EP_TRANSFER_STARTED))
|
||||
return;
|
||||
|
||||
/*
|
||||
@ -2665,17 +2668,15 @@ static void dwc3_stop_active_transfer(struct dwc3_ep *dep, bool force)
|
||||
|
||||
cmd = DWC3_DEPCMD_ENDTRANSFER;
|
||||
cmd |= force ? DWC3_DEPCMD_HIPRI_FORCERM : 0;
|
||||
cmd |= DWC3_DEPCMD_CMDIOC;
|
||||
cmd |= interrupt ? DWC3_DEPCMD_CMDIOC : 0;
|
||||
cmd |= DWC3_DEPCMD_PARAM(dep->resource_index);
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
ret = dwc3_send_gadget_ep_cmd(dep, cmd, ¶ms);
|
||||
WARN_ON_ONCE(ret);
|
||||
dep->resource_index = 0;
|
||||
|
||||
if (dwc3_is_usb31(dwc) || dwc->revision < DWC3_REVISION_310A) {
|
||||
dep->flags |= DWC3_EP_END_TRANSFER_PENDING;
|
||||
if (dwc3_is_usb31(dwc) || dwc->revision < DWC3_REVISION_310A)
|
||||
udelay(100);
|
||||
}
|
||||
}
|
||||
|
||||
static void dwc3_clear_stall_all_ep(struct dwc3 *dwc)
|
||||
@ -3339,6 +3340,8 @@ int dwc3_gadget_init(struct dwc3 *dwc)
|
||||
goto err4;
|
||||
}
|
||||
|
||||
dwc3_gadget_set_speed(&dwc->gadget, dwc->maximum_speed);
|
||||
|
||||
return 0;
|
||||
|
||||
err4:
|
||||
|
@ -75,7 +75,7 @@ static inline void dwc3_gadget_move_started_request(struct dwc3_request *req)
|
||||
{
|
||||
struct dwc3_ep *dep = req->dep;
|
||||
|
||||
req->started = true;
|
||||
req->status = DWC3_REQUEST_STATUS_STARTED;
|
||||
list_move_tail(&req->list, &dep->started_list);
|
||||
}
|
||||
|
||||
@ -90,7 +90,7 @@ static inline void dwc3_gadget_move_cancelled_request(struct dwc3_request *req)
|
||||
{
|
||||
struct dwc3_ep *dep = req->dep;
|
||||
|
||||
req->started = false;
|
||||
req->status = DWC3_REQUEST_STATUS_CANCELLED;
|
||||
list_move_tail(&req->list, &dep->cancelled_list);
|
||||
}
|
||||
|
||||
|
@ -59,8 +59,8 @@ DECLARE_EVENT_CLASS(dwc3_log_event,
|
||||
__entry->ep0state = dwc->ep0state;
|
||||
),
|
||||
TP_printk("event (%08x): %s", __entry->event,
|
||||
dwc3_decode_event(__get_str(str), __entry->event,
|
||||
__entry->ep0state))
|
||||
dwc3_decode_event(__get_str(str), DWC3_MSG_MAX,
|
||||
__entry->event, __entry->ep0state))
|
||||
);
|
||||
|
||||
DEFINE_EVENT(dwc3_log_event, dwc3_event,
|
||||
@ -86,7 +86,8 @@ DECLARE_EVENT_CLASS(dwc3_log_ctrl,
|
||||
__entry->wIndex = le16_to_cpu(ctrl->wIndex);
|
||||
__entry->wLength = le16_to_cpu(ctrl->wLength);
|
||||
),
|
||||
TP_printk("%s", dwc3_decode_ctrl(__get_str(str), __entry->bRequestType,
|
||||
TP_printk("%s", dwc3_decode_ctrl(__get_str(str), DWC3_MSG_MAX,
|
||||
__entry->bRequestType,
|
||||
__entry->bRequest, __entry->wValue,
|
||||
__entry->wIndex, __entry->wLength)
|
||||
)
|
||||
@ -305,7 +306,7 @@ DECLARE_EVENT_CLASS(dwc3_log_ep,
|
||||
__entry->trb_enqueue = dep->trb_enqueue;
|
||||
__entry->trb_dequeue = dep->trb_dequeue;
|
||||
),
|
||||
TP_printk("%s: mps %d/%d streams %d burst %d ring %d/%d flags %c:%c%c%c%c:%c:%c",
|
||||
TP_printk("%s: mps %d/%d streams %d burst %d ring %d/%d flags %c:%c%c%c%c:%c",
|
||||
__get_str(name), __entry->maxpacket,
|
||||
__entry->maxpacket_limit, __entry->max_streams,
|
||||
__entry->maxburst, __entry->trb_enqueue,
|
||||
@ -315,7 +316,6 @@ DECLARE_EVENT_CLASS(dwc3_log_ep,
|
||||
__entry->flags & DWC3_EP_WEDGE ? 'W' : 'w',
|
||||
__entry->flags & DWC3_EP_TRANSFER_STARTED ? 'B' : 'b',
|
||||
__entry->flags & DWC3_EP_PENDING_REQUEST ? 'P' : 'p',
|
||||
__entry->flags & DWC3_EP_END_TRANSFER_PENDING ? 'E' : 'e',
|
||||
__entry->direction ? '<' : '>'
|
||||
)
|
||||
);
|
||||
|
@ -1,3 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# USB Gadget support on a system involves
|
||||
# (a) a peripheral controller, and
|
||||
|
@ -67,9 +67,6 @@ struct usb_ep *usb_ep_autoconfig_ss(
|
||||
)
|
||||
{
|
||||
struct usb_ep *ep;
|
||||
u8 type;
|
||||
|
||||
type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
|
||||
|
||||
if (gadget->ops->match_ep) {
|
||||
ep = gadget->ops->match_ep(gadget, desc, ep_comp);
|
||||
@ -109,16 +106,6 @@ found_ep:
|
||||
desc->bEndpointAddress |= gadget->out_epnum;
|
||||
}
|
||||
|
||||
/* report (variable) full speed bulk maxpacket */
|
||||
if ((type == USB_ENDPOINT_XFER_BULK) && !ep_comp) {
|
||||
int size = ep->maxpacket_limit;
|
||||
|
||||
/* min() doesn't work on bitfields with gcc-3.5 */
|
||||
if (size > 64)
|
||||
size = 64;
|
||||
desc->wMaxPacketSize = cpu_to_le16(size);
|
||||
}
|
||||
|
||||
ep->address = desc->bEndpointAddress;
|
||||
ep->desc = NULL;
|
||||
ep->comp_desc = NULL;
|
||||
@ -152,9 +139,10 @@ EXPORT_SYMBOL_GPL(usb_ep_autoconfig_ss);
|
||||
*
|
||||
* On success, this returns an claimed usb_ep, and modifies the endpoint
|
||||
* descriptor bEndpointAddress. For bulk endpoints, the wMaxPacket value
|
||||
* is initialized as if the endpoint were used at full speed. To prevent
|
||||
* the endpoint from being returned by a later autoconfig call, claims it
|
||||
* by assigning ep->claimed to true.
|
||||
* is initialized as if the endpoint were used at full speed. Because of
|
||||
* that the users must consider adjusting the autoconfigured descriptor.
|
||||
* To prevent the endpoint from being returned by a later autoconfig call,
|
||||
* claims it by assigning ep->claimed to true.
|
||||
*
|
||||
* On failure, this returns a null endpoint descriptor.
|
||||
*/
|
||||
@ -163,7 +151,26 @@ struct usb_ep *usb_ep_autoconfig(
|
||||
struct usb_endpoint_descriptor *desc
|
||||
)
|
||||
{
|
||||
return usb_ep_autoconfig_ss(gadget, desc, NULL);
|
||||
struct usb_ep *ep;
|
||||
u8 type;
|
||||
|
||||
ep = usb_ep_autoconfig_ss(gadget, desc, NULL);
|
||||
if (!ep)
|
||||
return NULL;
|
||||
|
||||
type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
|
||||
|
||||
/* report (variable) full speed bulk maxpacket */
|
||||
if (type == USB_ENDPOINT_XFER_BULK) {
|
||||
int size = ep->maxpacket_limit;
|
||||
|
||||
/* min() doesn't work on bitfields with gcc-3.5 */
|
||||
if (size > 64)
|
||||
size = 64;
|
||||
desc->wMaxPacketSize = cpu_to_le16(size);
|
||||
}
|
||||
|
||||
return ep;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_ep_autoconfig);
|
||||
|
||||
|
@ -1082,6 +1082,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
|
||||
* condition with req->complete callback.
|
||||
*/
|
||||
usb_ep_dequeue(ep->ep, req);
|
||||
wait_for_completion(&done);
|
||||
interrupted = ep->status < 0;
|
||||
}
|
||||
|
||||
@ -2843,12 +2844,18 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
|
||||
struct usb_request *req;
|
||||
struct usb_ep *ep;
|
||||
u8 bEndpointAddress;
|
||||
u16 wMaxPacketSize;
|
||||
|
||||
/*
|
||||
* We back up bEndpointAddress because autoconfig overwrites
|
||||
* it with physical endpoint address.
|
||||
*/
|
||||
bEndpointAddress = ds->bEndpointAddress;
|
||||
/*
|
||||
* We back up wMaxPacketSize because autoconfig treats
|
||||
* endpoint descriptors as if they were full speed.
|
||||
*/
|
||||
wMaxPacketSize = ds->wMaxPacketSize;
|
||||
pr_vdebug("autoconfig\n");
|
||||
ep = usb_ep_autoconfig(func->gadget, ds);
|
||||
if (unlikely(!ep))
|
||||
@ -2869,6 +2876,11 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
|
||||
*/
|
||||
if (func->ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR)
|
||||
ds->bEndpointAddress = bEndpointAddress;
|
||||
/*
|
||||
* Restore wMaxPacketSize which was potentially
|
||||
* overwritten by autoconfig.
|
||||
*/
|
||||
ds->wMaxPacketSize = wMaxPacketSize;
|
||||
}
|
||||
ffs_dump_mem(": Rewritten ep desc", ds, ds->bLength);
|
||||
|
||||
|
@ -459,10 +459,10 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
||||
} else if (intf == uac1->as_in_intf) {
|
||||
uac1->as_in_alt = alt;
|
||||
|
||||
if (alt)
|
||||
ret = u_audio_start_playback(&uac1->g_audio);
|
||||
else
|
||||
u_audio_stop_playback(&uac1->g_audio);
|
||||
if (alt)
|
||||
ret = u_audio_start_playback(&uac1->g_audio);
|
||||
else
|
||||
u_audio_stop_playback(&uac1->g_audio);
|
||||
} else {
|
||||
dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
|
||||
return -EINVAL;
|
||||
@ -568,6 +568,7 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
goto fail;
|
||||
as_out_interface_alt_0_desc.bInterfaceNumber = status;
|
||||
as_out_interface_alt_1_desc.bInterfaceNumber = status;
|
||||
ac_header_desc.baInterfaceNr[0] = status;
|
||||
uac1->as_out_intf = status;
|
||||
uac1->as_out_alt = 0;
|
||||
|
||||
@ -576,6 +577,7 @@ static int f_audio_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
goto fail;
|
||||
as_in_interface_alt_0_desc.bInterfaceNumber = status;
|
||||
as_in_interface_alt_1_desc.bInterfaceNumber = status;
|
||||
ac_header_desc.baInterfaceNr[1] = status;
|
||||
uac1->as_in_intf = status;
|
||||
uac1->as_in_alt = 0;
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
|
||||
* Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef U_ECM_H
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
|
||||
* Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef U_EEM_H
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
|
||||
* Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef __U_ETHER_CONFIGFS_H
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
|
||||
* Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef U_FFS_H
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
|
||||
* Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef U_GETHER_H
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
|
||||
* Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef U_HID_H
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
|
||||
* Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef U_MIDI_H
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
|
||||
* Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef U_NCM_H
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Copyright (c) 2015 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
|
||||
* Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef U_PRINTER_H
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Copyright (c) 2013 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
|
||||
* Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef U_RNDIS_H
|
||||
|
@ -16,7 +16,6 @@
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/tty.h>
|
||||
@ -26,6 +25,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/kfifo.h>
|
||||
|
||||
#include "u_serial.h"
|
||||
@ -110,7 +110,7 @@ struct gs_port {
|
||||
int read_allocated;
|
||||
struct list_head read_queue;
|
||||
unsigned n_read;
|
||||
struct tasklet_struct push;
|
||||
struct delayed_work push;
|
||||
|
||||
struct list_head write_pool;
|
||||
int write_started;
|
||||
@ -352,9 +352,10 @@ __acquires(&port->port_lock)
|
||||
* So QUEUE_SIZE packets plus however many the FIFO holds (usually two)
|
||||
* can be buffered before the TTY layer's buffers (currently 64 KB).
|
||||
*/
|
||||
static void gs_rx_push(unsigned long _port)
|
||||
static void gs_rx_push(struct work_struct *work)
|
||||
{
|
||||
struct gs_port *port = (void *)_port;
|
||||
struct delayed_work *w = to_delayed_work(work);
|
||||
struct gs_port *port = container_of(w, struct gs_port, push);
|
||||
struct tty_struct *tty;
|
||||
struct list_head *queue = &port->read_queue;
|
||||
bool disconnect = false;
|
||||
@ -429,21 +430,13 @@ static void gs_rx_push(unsigned long _port)
|
||||
|
||||
/* We want our data queue to become empty ASAP, keeping data
|
||||
* in the tty and ldisc (not here). If we couldn't push any
|
||||
* this time around, there may be trouble unless there's an
|
||||
* implicit tty_unthrottle() call on its way...
|
||||
* this time around, RX may be starved, so wait until next jiffy.
|
||||
*
|
||||
* REVISIT we should probably add a timer to keep the tasklet
|
||||
* from starving ... but it's not clear that case ever happens.
|
||||
* We may leave non-empty queue only when there is a tty, and
|
||||
* either it is throttled or there is no more room in flip buffer.
|
||||
*/
|
||||
if (!list_empty(queue) && tty) {
|
||||
if (!tty_throttled(tty)) {
|
||||
if (do_push)
|
||||
tasklet_schedule(&port->push);
|
||||
else
|
||||
pr_warn("ttyGS%d: RX not scheduled?\n",
|
||||
port->port_num);
|
||||
}
|
||||
}
|
||||
if (!list_empty(queue) && !tty_throttled(tty))
|
||||
schedule_delayed_work(&port->push, 1);
|
||||
|
||||
/* If we're still connected, refill the USB RX queue. */
|
||||
if (!disconnect && port->port_usb)
|
||||
@ -459,7 +452,7 @@ static void gs_read_complete(struct usb_ep *ep, struct usb_request *req)
|
||||
/* Queue all received data until the tty layer is ready for it. */
|
||||
spin_lock(&port->port_lock);
|
||||
list_add_tail(&req->list, &port->read_queue);
|
||||
tasklet_schedule(&port->push);
|
||||
schedule_delayed_work(&port->push, 0);
|
||||
spin_unlock(&port->port_lock);
|
||||
}
|
||||
|
||||
@ -854,8 +847,8 @@ static void gs_unthrottle(struct tty_struct *tty)
|
||||
* rts/cts, or other handshaking with the host, but if the
|
||||
* read queue backs up enough we'll be NAKing OUT packets.
|
||||
*/
|
||||
tasklet_schedule(&port->push);
|
||||
pr_vdebug("ttyGS%d: unthrottle\n", port->port_num);
|
||||
schedule_delayed_work(&port->push, 0);
|
||||
}
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
}
|
||||
@ -1159,7 +1152,7 @@ gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding)
|
||||
init_waitqueue_head(&port->drain_wait);
|
||||
init_waitqueue_head(&port->close_wait);
|
||||
|
||||
tasklet_init(&port->push, gs_rx_push, (unsigned long) port);
|
||||
INIT_DELAYED_WORK(&port->push, gs_rx_push);
|
||||
|
||||
INIT_LIST_HEAD(&port->read_pool);
|
||||
INIT_LIST_HEAD(&port->read_queue);
|
||||
@ -1186,7 +1179,7 @@ static int gs_closed(struct gs_port *port)
|
||||
|
||||
static void gserial_free_port(struct gs_port *port)
|
||||
{
|
||||
tasklet_kill(&port->push);
|
||||
cancel_delayed_work_sync(&port->push);
|
||||
/* wait for old opens to finish */
|
||||
wait_event(port->close_wait, gs_closed(port));
|
||||
WARN_ON(port->port_usb != NULL);
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
|
||||
* Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef U_UAC2_H
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Copyright (c) 2013-2014 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
|
||||
* Author: Andrzej Pietrasiewicz <andrzejtp2010@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef U_UVC_H
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user