mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-28 14:44:10 +08:00
USB patches for 4.3-rc1
Here's the big USB and PHY patchset for 4.3-rc1. As usual, the majority of the changes are in the USB gadget portion of the tree, lots of little changes all over the place for bugs and new hardware. Other than that, the normal mix of new hardware support and bugfixes. All have been in linux-next with no reported issues. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iEYEABECAAYFAlXWJacACgkQMUfUDdst+ymGCwCePl4ANthHngvzF6VNth0Osrdk T2EAoNiOxTymRKPLiZ9Vs4Qznqq8CH2X =g8e1 -----END PGP SIGNATURE----- Merge tag 'usb-4.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb Pull USB updates from Greg KH: "Here's the big USB and PHY patchset for 4.3-rc1. As usual, the majority of the changes are in the USB gadget portion of the tree, lots of little changes all over the place for bugs and new hardware. Other than that, the normal mix of new hardware support and bugfixes. All have been in linux-next with no reported issues" * tag 'usb-4.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (261 commits) USB: qcserial: add HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module USB: ftdi_sio: Added custom PID for CustomWare products USB: usb_wwan: silence read errors on disconnect USB: option: silence interrupt errors USB: symbolserial: Correct transferred data size USB: symbolserial: Use usb_get_serial_port_data usb: misc: usbtest: format max packet size for iso transfer usb: host: ehci-sys: delete useless bus_to_hcd conversion Revert "usb: interface authorization: Declare authorized attribute" Revert "usb: interface authorization: Introduces the default interface authorization" Revert "usb: interface authorization: Control interface probing and claiming" Revert "usb: interface authorization: Introduces the USB interface authorization" Revert "usb: interface authorization: SysFS part of USB interface authorization" Revert "usb: interface authorization: Documentation part" Revert "usb: interface authorization: Use a flag for the default device authorization" usb: core: hub: Removed some warnings generated by checkpatch.pl USB: host: ohci-at91: merge loops in ohci_hcd_at91_drv_probe USB: host: ohci-at91: merge ohci_at91_of_init in ohci_hcd_at91_drv_probe USB: host: ohci-at91: depend on OF USB: host: ohci-at91: move at91_usbh_data definition in c file ...
This commit is contained in:
commit
4ff12049d6
@ -5,4 +5,4 @@ Description:
|
||||
The attributes:
|
||||
|
||||
qlen - depth of loopback queue
|
||||
bulk_buflen - buffer length
|
||||
buflen - buffer length
|
||||
|
@ -9,4 +9,4 @@ Description:
|
||||
isoc_maxpacket - 0 - 1023 (fs), 0 - 1024 (hs/ss)
|
||||
isoc_mult - 0..2 (hs/ss only)
|
||||
isoc_maxburst - 0..15 (ss only)
|
||||
qlen - buffer length
|
||||
buflen - buffer length
|
||||
|
@ -114,6 +114,20 @@ Description:
|
||||
enabled for the device. Developer can write y/Y/1 or n/N/0 to
|
||||
the file to enable/disable the feature.
|
||||
|
||||
What: /sys/bus/usb/devices/.../power/usb3_hardware_lpm
|
||||
Date: June 2015
|
||||
Contact: Kevin Strasser <kevin.strasser@linux.intel.com>
|
||||
Description:
|
||||
If CONFIG_PM is set and a USB 3.0 lpm-capable device is plugged
|
||||
in to a xHCI host which supports link PM, it will check if U1
|
||||
and U2 exit latencies have been set in the BOS descriptor; if
|
||||
the check is is passed and the host supports USB3 hardware LPM,
|
||||
USB3 hardware LPM will be enabled for the device and the USB
|
||||
device directory will contain a file named
|
||||
power/usb3_hardware_lpm. The file holds a string value (enable
|
||||
or disable) indicating whether or not USB3 hardware LPM is
|
||||
enabled for the device.
|
||||
|
||||
What: /sys/bus/usb/devices/.../removable
|
||||
Date: February 2012
|
||||
Contact: Matthew Garrett <mjg@redhat.com>
|
||||
|
@ -0,0 +1,26 @@
|
||||
NXP LPC18xx/43xx internal USB OTG PHY binding
|
||||
---------------------------------------------
|
||||
|
||||
This file contains documentation for the internal USB OTG PHY found
|
||||
in NXP LPC18xx and LPC43xx SoCs.
|
||||
|
||||
Required properties:
|
||||
- compatible : must be "nxp,lpc1850-usb-otg-phy"
|
||||
- clocks : must be exactly one entry
|
||||
See: Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
- #phy-cells : must be 0 for this phy
|
||||
See: Documentation/devicetree/bindings/phy/phy-bindings.txt
|
||||
|
||||
The phy node must be a child of the creg syscon node.
|
||||
|
||||
Example:
|
||||
creg: syscon@40043000 {
|
||||
compatible = "nxp,lpc1850-creg", "syscon", "simple-mfd";
|
||||
reg = <0x40043000 0x1000>;
|
||||
|
||||
usb0_otg_phy: phy@004 {
|
||||
compatible = "nxp,lpc1850-usb-otg-phy";
|
||||
clocks = <&ccu1 CLK_USB0>;
|
||||
#phy-cells = <0>;
|
||||
};
|
||||
};
|
@ -7,6 +7,8 @@ Required properties:
|
||||
* allwinner,sun5i-a13-usb-phy
|
||||
* allwinner,sun6i-a31-usb-phy
|
||||
* allwinner,sun7i-a20-usb-phy
|
||||
* allwinner,sun8i-a23-usb-phy
|
||||
* allwinner,sun8i-a33-usb-phy
|
||||
- reg : a list of offset + length pairs
|
||||
- reg-names :
|
||||
* "phy_ctrl"
|
||||
@ -17,12 +19,21 @@ Required properties:
|
||||
- clock-names :
|
||||
* "usb_phy" for sun4i, sun5i or sun7i
|
||||
* "usb0_phy", "usb1_phy" and "usb2_phy" for sun6i
|
||||
* "usb0_phy", "usb1_phy" for sun8i
|
||||
- resets : a list of phandle + reset specifier pairs
|
||||
- reset-names :
|
||||
* "usb0_reset"
|
||||
* "usb1_reset"
|
||||
* "usb2_reset" for sun4i, sun6i or sun7i
|
||||
|
||||
Optional properties:
|
||||
- usb0_id_det-gpios : gpio phandle for reading the otg id pin value
|
||||
- usb0_vbus_det-gpios : gpio phandle for detecting the presence of usb0 vbus
|
||||
- usb0_vbus_power-supply: power-supply phandle for usb0 vbus presence detect
|
||||
- usb0_vbus-supply : regulator phandle for controller usb0 vbus
|
||||
- usb1_vbus-supply : regulator phandle for controller usb1 vbus
|
||||
- usb2_vbus-supply : regulator phandle for controller usb2 vbus
|
||||
|
||||
Example:
|
||||
usbphy: phy@0x01c13400 {
|
||||
#phy-cells = <1>;
|
||||
@ -32,6 +43,13 @@ Example:
|
||||
reg-names = "phy_ctrl", "pmu1", "pmu2";
|
||||
clocks = <&usb_clk 8>;
|
||||
clock-names = "usb_phy";
|
||||
resets = <&usb_clk 1>, <&usb_clk 2>;
|
||||
reset-names = "usb1_reset", "usb2_reset";
|
||||
resets = <&usb_clk 0>, <&usb_clk 1>, <&usb_clk 2>;
|
||||
reset-names = "usb0_reset", "usb1_reset", "usb2_reset";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&usb0_id_detect_pin>, <&usb0_vbus_detect_pin>;
|
||||
usb0_id_det-gpios = <&pio 7 19 GPIO_ACTIVE_HIGH>; /* PH19 */
|
||||
usb0_vbus_det-gpios = <&pio 7 22 GPIO_ACTIVE_HIGH>; /* PH22 */
|
||||
usb0_vbus-supply = <®_usb0_vbus>;
|
||||
usb1_vbus-supply = <®_usb1_vbus>;
|
||||
usb2_vbus-supply = <®_usb2_vbus>;
|
||||
};
|
||||
|
@ -0,0 +1,29 @@
|
||||
Allwinner sun4i A10 musb DRC/OTG controller
|
||||
-------------------------------------------
|
||||
|
||||
Required properties:
|
||||
- compatible : "allwinner,sun4i-a10-musb", "allwinner,sun6i-a31-musb"
|
||||
or "allwinner,sun8i-a33-musb"
|
||||
- reg : mmio address range of the musb controller
|
||||
- clocks : clock specifier for the musb controller ahb gate clock
|
||||
- reset : reset specifier for the ahb reset (A31 and newer only)
|
||||
- interrupts : interrupt to which the musb controller is connected
|
||||
- interrupt-names : must be "mc"
|
||||
- phys : phy specifier for the otg phy
|
||||
- phy-names : must be "usb"
|
||||
- dr_mode : Dual-Role mode must be "host" or "otg"
|
||||
- extcon : extcon specifier for the otg phy
|
||||
|
||||
Example:
|
||||
|
||||
usb_otg: usb@01c13000 {
|
||||
compatible = "allwinner,sun4i-a10-musb";
|
||||
reg = <0x01c13000 0x0400>;
|
||||
clocks = <&ahb_gates 0>;
|
||||
interrupts = <38>;
|
||||
interrupt-names = "mc";
|
||||
phys = <&usbphy 0>;
|
||||
phy-names = "usb";
|
||||
extcon = <&usbphy 0>;
|
||||
status = "disabled";
|
||||
};
|
@ -30,6 +30,21 @@ Optional properties:
|
||||
argument that indicate usb controller index
|
||||
- disable-over-current: (FSL only) disable over current detect
|
||||
- external-vbus-divider: (FSL only) enables off-chip resistor divider for Vbus
|
||||
- itc-setting: interrupt threshold control register control, the setting
|
||||
should be aligned with ITC bits at register USBCMD.
|
||||
- ahb-burst-config: it is vendor dependent, the required value should be
|
||||
aligned with AHBBRST at SBUSCFG, the range is from 0x0 to 0x7. This
|
||||
property is used to change AHB burst configuration, check the chipidea
|
||||
spec for meaning of each value. If this property is not existed, it
|
||||
will use the reset value.
|
||||
- tx-burst-size-dword: it is vendor dependent, the tx burst size in dword
|
||||
(4 bytes), This register represents the maximum length of a the burst
|
||||
in 32-bit words while moving data from system memory to the USB
|
||||
bus, changing this value takes effect only the SBUSCFG.AHBBRST is 0.
|
||||
- rx-burst-size-dword: it is vendor dependent, the rx burst size in dword
|
||||
(4 bytes), This register represents the maximum length of a the burst
|
||||
in 32-bit words while moving data from the USB bus to system memory,
|
||||
changing this value takes effect only the SBUSCFG.AHBBRST is 0.
|
||||
|
||||
Example:
|
||||
|
||||
@ -41,4 +56,9 @@ Example:
|
||||
phys = <&usb_phy0>;
|
||||
phy-names = "usb-phy";
|
||||
vbus-supply = <®_usb0_vbus>;
|
||||
gadget-itc-setting = <0x4>; /* 4 micro-frames */
|
||||
/* Incremental burst of unspecified length */
|
||||
ahb-burst-config = <0x0>;
|
||||
tx-burst-size-dword = <0x10>; /* 64 bytes */
|
||||
rx-burst-size-dword = <0x10>;
|
||||
};
|
||||
|
@ -11,6 +11,19 @@ Optional properties:
|
||||
"peripheral" and "otg". In case this attribute isn't
|
||||
passed via DT, USB DRD controllers should default to
|
||||
OTG.
|
||||
- otg-rev: tells usb driver the release number of the OTG and EH supplement
|
||||
with which the device and its descriptors are compliant,
|
||||
in binary-coded decimal (i.e. 2.0 is 0200H). This
|
||||
property is used if any real OTG features(HNP/SRP/ADP)
|
||||
is enabled, if ADP is required, otg-rev should be
|
||||
0x0200 or above.
|
||||
- hnp-disable: tells OTG controllers we want to disable OTG HNP, normally HNP
|
||||
is the basic function of real OTG except you want it
|
||||
to be a srp-capable only B device.
|
||||
- srp-disable: tells OTG controllers we want to disable OTG SRP, SRP is
|
||||
optional for OTG device.
|
||||
- adp-disable: tells OTG controllers we want to disable OTG ADP, ADP is
|
||||
optional for OTG device.
|
||||
|
||||
This is an attribute to a USB controller such as:
|
||||
|
||||
@ -21,4 +34,6 @@ dwc3@4a030000 {
|
||||
usb-phy = <&usb2_phy>, <&usb3,phy>;
|
||||
maximum-speed = "super-speed";
|
||||
dr_mode = "otg";
|
||||
otg-rev = <0x0200>;
|
||||
adp-disable;
|
||||
};
|
||||
|
@ -52,6 +52,10 @@ Required properties:
|
||||
Optional properties:
|
||||
- dr_mode: One of "host", "peripheral" or "otg". Defaults to "otg"
|
||||
|
||||
- switch-gpio: A phandle + gpio-specifier pair. Some boards are using Dual
|
||||
SPDT USB Switch, witch is cotrolled by GPIO to de/multiplex
|
||||
D+/D- USB lines between connectors.
|
||||
|
||||
- qcom,phy-init-sequence: PHY configuration sequence values. This is related to Device
|
||||
Mode Eye Diagram test. Start address at which these values will be
|
||||
written is ULPI_EXT_VENDOR_SPECIFIC. Value of -1 is reserved as
|
||||
|
76
Documentation/devicetree/bindings/usb/qcom,usb-8x16-phy.txt
Normal file
76
Documentation/devicetree/bindings/usb/qcom,usb-8x16-phy.txt
Normal file
@ -0,0 +1,76 @@
|
||||
Qualcomm's APQ8016/MSM8916 USB transceiver controller
|
||||
|
||||
- compatible:
|
||||
Usage: required
|
||||
Value type: <string>
|
||||
Definition: Should contain "qcom,usb-8x16-phy".
|
||||
|
||||
- reg:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: USB PHY base address and length of the register map
|
||||
|
||||
- clocks:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: See clock-bindings.txt section "consumers". List of
|
||||
two clock specifiers for interface and core controller
|
||||
clocks.
|
||||
|
||||
- clock-names:
|
||||
Usage: required
|
||||
Value type: <string>
|
||||
Definition: Must contain "iface" and "core" strings.
|
||||
|
||||
- vddcx-supply:
|
||||
Usage: required
|
||||
Value type: <phandle>
|
||||
Definition: phandle to the regulator VDCCX supply node.
|
||||
|
||||
- v1p8-supply:
|
||||
Usage: required
|
||||
Value type: <phandle>
|
||||
Definition: phandle to the regulator 1.8V supply node.
|
||||
|
||||
- v3p3-supply:
|
||||
Usage: required
|
||||
Value type: <phandle>
|
||||
Definition: phandle to the regulator 3.3V supply node.
|
||||
|
||||
- resets:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: See reset.txt section "consumers". PHY reset specifier.
|
||||
|
||||
- reset-names:
|
||||
Usage: required
|
||||
Value type: <string>
|
||||
Definition: Must contain "phy" string.
|
||||
|
||||
- switch-gpio:
|
||||
Usage: optional
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: Some boards are using Dual SPDT USB Switch, witch is
|
||||
controlled by GPIO to de/multiplex D+/D- USB lines
|
||||
between connectors.
|
||||
|
||||
Example:
|
||||
usb_phy: phy@78d9000 {
|
||||
compatible = "qcom,usb-8x16-phy";
|
||||
reg = <0x78d9000 0x400>;
|
||||
|
||||
vddcx-supply = <&pm8916_s1_corner>;
|
||||
v1p8-supply = <&pm8916_l7>;
|
||||
v3p3-supply = <&pm8916_l13>;
|
||||
|
||||
clocks = <&gcc GCC_USB_HS_AHB_CLK>,
|
||||
<&gcc GCC_USB_HS_SYSTEM_CLK>;
|
||||
clock-names = "iface", "core";
|
||||
|
||||
resets = <&gcc GCC_USB2A_PHY_BCR>;
|
||||
reset-names = "phy";
|
||||
|
||||
// D+/D- lines: 1 - Routed to HUB, 0 - Device connector
|
||||
switch-gpio = <&pm8916_gpios 4 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
|
@ -237,9 +237,7 @@ Testing the LOOPBACK function
|
||||
-----------------------------
|
||||
|
||||
device: run the gadget
|
||||
host: test-usb
|
||||
|
||||
http://www.linux-usb.org/usbtest/testusb.c
|
||||
host: test-usb (tools/usb/testusb.c)
|
||||
|
||||
8. MASS STORAGE function
|
||||
========================
|
||||
@ -586,9 +584,8 @@ Testing the SOURCESINK function
|
||||
-------------------------------
|
||||
|
||||
device: run the gadget
|
||||
host: test-usb
|
||||
host: test-usb (tools/usb/testusb.c)
|
||||
|
||||
http://www.linux-usb.org/usbtest/testusb.c
|
||||
|
||||
16. UAC1 function
|
||||
=================
|
||||
|
@ -521,10 +521,10 @@ enabling hardware LPM, the host can automatically put the device into
|
||||
lower power state(L1 for usb2.0 devices, or U1/U2 for usb3.0 devices),
|
||||
which state device can enter and resume very quickly.
|
||||
|
||||
The user interface for controlling USB2 hardware LPM is located in the
|
||||
The user interface for controlling hardware LPM is located in the
|
||||
power/ subdirectory of each USB device's sysfs directory, that is, in
|
||||
/sys/bus/usb/devices/.../power/ where "..." is the device's ID. The
|
||||
relevant attribute files is usb2_hardware_lpm.
|
||||
relevant attribute files are usb2_hardware_lpm and usb3_hardware_lpm.
|
||||
|
||||
power/usb2_hardware_lpm
|
||||
|
||||
@ -537,6 +537,17 @@ relevant attribute files is usb2_hardware_lpm.
|
||||
can write y/Y/1 or n/N/0 to the file to enable/disable
|
||||
USB2 hardware LPM manually. This is for test purpose mainly.
|
||||
|
||||
power/usb3_hardware_lpm
|
||||
|
||||
When a USB 3.0 lpm-capable device is plugged in to a
|
||||
xHCI host which supports link PM, it will check if U1
|
||||
and U2 exit latencies have been set in the BOS
|
||||
descriptor; if the check is is passed and the host
|
||||
supports USB3 hardware LPM, USB3 hardware LPM will be
|
||||
enabled for the device and this file will be created.
|
||||
The file holds a string value (enable or disable)
|
||||
indicating whether or not USB3 hardware LPM is
|
||||
enabled for the device.
|
||||
|
||||
USB Port Power Control
|
||||
----------------------
|
||||
|
@ -54,6 +54,17 @@ config PHY_EXYNOS_MIPI_VIDEO
|
||||
Support for MIPI CSI-2 and MIPI DSI DPHY found on Samsung S5P
|
||||
and EXYNOS SoCs.
|
||||
|
||||
config PHY_LPC18XX_USB_OTG
|
||||
tristate "NXP LPC18xx/43xx SoC USB OTG PHY driver"
|
||||
depends on OF && (ARCH_LPC18XX || COMPILE_TEST)
|
||||
depends on MFD_SYSCON
|
||||
select GENERIC_PHY
|
||||
help
|
||||
Enable this to support NXP LPC18xx/43xx internal USB OTG PHY.
|
||||
|
||||
This driver is need for USB0 support on LPC18xx/43xx and takes
|
||||
care of enabling and clock setup.
|
||||
|
||||
config PHY_PXA_28NM_HSIC
|
||||
tristate "Marvell USB HSIC 28nm PHY Driver"
|
||||
depends on HAS_IOMEM
|
||||
@ -199,6 +210,8 @@ config PHY_SUN4I_USB
|
||||
tristate "Allwinner sunxi SoC USB PHY driver"
|
||||
depends on ARCH_SUNXI && HAS_IOMEM && OF
|
||||
depends on RESET_CONTROLLER
|
||||
depends on EXTCON
|
||||
depends on POWER_SUPPLY
|
||||
select GENERIC_PHY
|
||||
help
|
||||
Enable this to support the transceiver that is part of Allwinner
|
||||
|
@ -10,6 +10,7 @@ obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY) += phy-armada375-usb2.o
|
||||
obj-$(CONFIG_BCM_KONA_USB2_PHY) += phy-bcm-kona-usb2.o
|
||||
obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o
|
||||
obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o
|
||||
obj-$(CONFIG_PHY_LPC18XX_USB_OTG) += phy-lpc18xx-usb-otg.o
|
||||
obj-$(CONFIG_PHY_PXA_28NM_USB2) += phy-pxa-28nm-usb2.o
|
||||
obj-$(CONFIG_PHY_PXA_28NM_HSIC) += phy-pxa-28nm-hsic.o
|
||||
obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o
|
||||
|
@ -51,7 +51,7 @@ static int armada375_usb_phy_init(struct phy *phy)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phy_ops armada375_usb_phy_ops = {
|
||||
static const struct phy_ops armada375_usb_phy_ops = {
|
||||
.init = armada375_usb_phy_init,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
@ -149,7 +149,6 @@ static struct platform_driver armada375_usb_phy_driver = {
|
||||
.driver = {
|
||||
.of_match_table = of_usb_cluster_table,
|
||||
.name = "armada-375-usb-cluster",
|
||||
.owner = THIS_MODULE,
|
||||
}
|
||||
};
|
||||
module_platform_driver(armada375_usb_phy_driver);
|
||||
|
@ -91,7 +91,7 @@ static int bcm_kona_usb_phy_power_off(struct phy *gphy)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phy_ops ops = {
|
||||
static const struct phy_ops ops = {
|
||||
.init = bcm_kona_usb_phy_init,
|
||||
.power_on = bcm_kona_usb_phy_power_on,
|
||||
.power_off = bcm_kona_usb_phy_power_off,
|
||||
|
@ -176,7 +176,7 @@ static struct phy *phy_berlin_sata_phy_xlate(struct device *dev,
|
||||
return priv->phys[i]->phy;
|
||||
}
|
||||
|
||||
static struct phy_ops phy_berlin_sata_ops = {
|
||||
static const struct phy_ops phy_berlin_sata_ops = {
|
||||
.power_on = phy_berlin_sata_power_on,
|
||||
.power_off = phy_berlin_sata_power_off,
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -147,12 +147,12 @@ static int phy_berlin_usb_power_on(struct phy *phy)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phy_ops phy_berlin_usb_ops = {
|
||||
static const struct phy_ops phy_berlin_usb_ops = {
|
||||
.power_on = phy_berlin_usb_power_on,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct of_device_id phy_berlin_sata_of_match[] = {
|
||||
static const struct of_device_id phy_berlin_usb_of_match[] = {
|
||||
{
|
||||
.compatible = "marvell,berlin2-usb-phy",
|
||||
.data = &phy_berlin_pll_dividers[0],
|
||||
@ -163,12 +163,12 @@ static const struct of_device_id phy_berlin_sata_of_match[] = {
|
||||
},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, phy_berlin_sata_of_match);
|
||||
MODULE_DEVICE_TABLE(of, phy_berlin_usb_of_match);
|
||||
|
||||
static int phy_berlin_usb_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *match =
|
||||
of_match_device(phy_berlin_sata_of_match, &pdev->dev);
|
||||
of_match_device(phy_berlin_usb_of_match, &pdev->dev);
|
||||
struct phy_berlin_usb_priv *priv;
|
||||
struct resource *res;
|
||||
struct phy *phy;
|
||||
@ -207,9 +207,8 @@ static struct platform_driver phy_berlin_usb_driver = {
|
||||
.probe = phy_berlin_usb_probe,
|
||||
.driver = {
|
||||
.name = "phy-berlin-usb",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = phy_berlin_sata_of_match,
|
||||
},
|
||||
.of_match_table = phy_berlin_usb_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(phy_berlin_usb_driver);
|
||||
|
||||
|
@ -122,7 +122,7 @@ static int brcm_sata_phy_init(struct phy *phy)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phy_ops phy_ops_28nm = {
|
||||
static const struct phy_ops phy_ops_28nm = {
|
||||
.init = brcm_sata_phy_init,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
@ -113,7 +113,7 @@ static int dm816x_usb_phy_init(struct phy *x)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phy_ops ops = {
|
||||
static const struct phy_ops ops = {
|
||||
.init = dm816x_usb_phy_init,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
@ -48,7 +48,7 @@ static int exynos_dp_video_phy_power_off(struct phy *phy)
|
||||
EXYNOS5_PHY_ENABLE, 0);
|
||||
}
|
||||
|
||||
static struct phy_ops exynos_dp_video_phy_ops = {
|
||||
static const struct phy_ops exynos_dp_video_phy_ops = {
|
||||
.power_on = exynos_dp_video_phy_power_on,
|
||||
.power_off = exynos_dp_video_phy_power_off,
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -124,7 +124,7 @@ static struct phy *exynos_mipi_video_phy_xlate(struct device *dev,
|
||||
return state->phys[args->args[0]].phy;
|
||||
}
|
||||
|
||||
static struct phy_ops exynos_mipi_video_phy_ops = {
|
||||
static const struct phy_ops exynos_mipi_video_phy_ops = {
|
||||
.power_on = exynos_mipi_video_phy_power_on,
|
||||
.power_off = exynos_mipi_video_phy_power_off,
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -537,7 +537,7 @@ static struct phy *exynos5_usbdrd_phy_xlate(struct device *dev,
|
||||
return phy_drd->phys[args->args[0]].phy;
|
||||
}
|
||||
|
||||
static struct phy_ops exynos5_usbdrd_phy_ops = {
|
||||
static const struct phy_ops exynos5_usbdrd_phy_ops = {
|
||||
.init = exynos5_usbdrd_phy_init,
|
||||
.exit = exynos5_usbdrd_phy_exit,
|
||||
.power_on = exynos5_usbdrd_phy_power_on,
|
||||
|
@ -154,7 +154,7 @@ static int exynos_sata_phy_init(struct phy *phy)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct phy_ops exynos_sata_phy_ops = {
|
||||
static const struct phy_ops exynos_sata_phy_ops = {
|
||||
.init = exynos_sata_phy_init,
|
||||
.power_on = exynos_sata_phy_power_on,
|
||||
.power_off = exynos_sata_phy_power_off,
|
||||
|
@ -129,7 +129,7 @@ static int hix5hd2_sata_phy_init(struct phy *phy)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phy_ops hix5hd2_sata_phy_ops = {
|
||||
static const struct phy_ops hix5hd2_sata_phy_ops = {
|
||||
.init = hix5hd2_sata_phy_init,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
143
drivers/phy/phy-lpc18xx-usb-otg.c
Normal file
143
drivers/phy/phy-lpc18xx-usb-otg.c
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* PHY driver for NXP LPC18xx/43xx internal USB OTG PHY
|
||||
*
|
||||
* Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
/* USB OTG PHY register offset and bit in CREG */
|
||||
#define LPC18XX_CREG_CREG0 0x004
|
||||
#define LPC18XX_CREG_CREG0_USB0PHY BIT(5)
|
||||
|
||||
struct lpc18xx_usb_otg_phy {
|
||||
struct phy *phy;
|
||||
struct clk *clk;
|
||||
struct regmap *reg;
|
||||
};
|
||||
|
||||
static int lpc18xx_usb_otg_phy_init(struct phy *phy)
|
||||
{
|
||||
struct lpc18xx_usb_otg_phy *lpc = phy_get_drvdata(phy);
|
||||
int ret;
|
||||
|
||||
/* The PHY must be clocked at 480 MHz */
|
||||
ret = clk_set_rate(lpc->clk, 480000000);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return clk_prepare(lpc->clk);
|
||||
}
|
||||
|
||||
static int lpc18xx_usb_otg_phy_exit(struct phy *phy)
|
||||
{
|
||||
struct lpc18xx_usb_otg_phy *lpc = phy_get_drvdata(phy);
|
||||
|
||||
clk_unprepare(lpc->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lpc18xx_usb_otg_phy_power_on(struct phy *phy)
|
||||
{
|
||||
struct lpc18xx_usb_otg_phy *lpc = phy_get_drvdata(phy);
|
||||
int ret;
|
||||
|
||||
ret = clk_enable(lpc->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* The bit in CREG is cleared to enable the PHY */
|
||||
return regmap_update_bits(lpc->reg, LPC18XX_CREG_CREG0,
|
||||
LPC18XX_CREG_CREG0_USB0PHY, 0);
|
||||
}
|
||||
|
||||
static int lpc18xx_usb_otg_phy_power_off(struct phy *phy)
|
||||
{
|
||||
struct lpc18xx_usb_otg_phy *lpc = phy_get_drvdata(phy);
|
||||
int ret;
|
||||
|
||||
ret = regmap_update_bits(lpc->reg, LPC18XX_CREG_CREG0,
|
||||
LPC18XX_CREG_CREG0_USB0PHY,
|
||||
LPC18XX_CREG_CREG0_USB0PHY);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
clk_disable(lpc->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct phy_ops lpc18xx_usb_otg_phy_ops = {
|
||||
.init = lpc18xx_usb_otg_phy_init,
|
||||
.exit = lpc18xx_usb_otg_phy_exit,
|
||||
.power_on = lpc18xx_usb_otg_phy_power_on,
|
||||
.power_off = lpc18xx_usb_otg_phy_power_off,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int lpc18xx_usb_otg_phy_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct phy_provider *phy_provider;
|
||||
struct lpc18xx_usb_otg_phy *lpc;
|
||||
|
||||
lpc = devm_kzalloc(&pdev->dev, sizeof(*lpc), GFP_KERNEL);
|
||||
if (!lpc)
|
||||
return -ENOMEM;
|
||||
|
||||
lpc->reg = syscon_node_to_regmap(pdev->dev.of_node->parent);
|
||||
if (IS_ERR(lpc->reg)) {
|
||||
dev_err(&pdev->dev, "failed to get syscon\n");
|
||||
return PTR_ERR(lpc->reg);
|
||||
}
|
||||
|
||||
lpc->clk = devm_clk_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(lpc->clk)) {
|
||||
dev_err(&pdev->dev, "failed to get clock\n");
|
||||
return PTR_ERR(lpc->clk);
|
||||
}
|
||||
|
||||
lpc->phy = devm_phy_create(&pdev->dev, NULL, &lpc18xx_usb_otg_phy_ops);
|
||||
if (IS_ERR(lpc->phy)) {
|
||||
dev_err(&pdev->dev, "failed to create PHY\n");
|
||||
return PTR_ERR(lpc->phy);
|
||||
}
|
||||
|
||||
phy_set_drvdata(lpc->phy, lpc);
|
||||
|
||||
phy_provider = devm_of_phy_provider_register(&pdev->dev,
|
||||
of_phy_simple_xlate);
|
||||
|
||||
return PTR_ERR_OR_ZERO(phy_provider);
|
||||
}
|
||||
|
||||
static const struct of_device_id lpc18xx_usb_otg_phy_match[] = {
|
||||
{ .compatible = "nxp,lpc1850-usb-otg-phy" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, lpc18xx_usb_otg_phy_match);
|
||||
|
||||
static struct platform_driver lpc18xx_usb_otg_phy_driver = {
|
||||
.probe = lpc18xx_usb_otg_phy_probe,
|
||||
.driver = {
|
||||
.name = "lpc18xx-usb-otg-phy",
|
||||
.of_match_table = lpc18xx_usb_otg_phy_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(lpc18xx_usb_otg_phy_driver);
|
||||
|
||||
MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
|
||||
MODULE_DESCRIPTION("NXP LPC18xx/43xx USB OTG PHY driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -1132,7 +1132,7 @@ static struct phy *miphy28lp_xlate(struct device *dev,
|
||||
return miphy_phy->phy;
|
||||
}
|
||||
|
||||
static struct phy_ops miphy28lp_ops = {
|
||||
static const struct phy_ops miphy28lp_ops = {
|
||||
.init = miphy28lp_init,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
@ -1268,7 +1268,6 @@ static struct platform_driver miphy28lp_driver = {
|
||||
.probe = miphy28lp_probe,
|
||||
.driver = {
|
||||
.name = "miphy28lp-phy",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = miphy28lp_of_match,
|
||||
}
|
||||
};
|
||||
|
@ -510,7 +510,7 @@ static struct phy *miphy365x_xlate(struct device *dev,
|
||||
return miphy_phy->phy;
|
||||
}
|
||||
|
||||
static struct phy_ops miphy365x_ops = {
|
||||
static const struct phy_ops miphy365x_ops = {
|
||||
.init = miphy365x_init,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
@ -75,7 +75,7 @@ static int phy_mvebu_sata_power_off(struct phy *phy)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phy_ops phy_mvebu_sata_ops = {
|
||||
static const struct phy_ops phy_mvebu_sata_ops = {
|
||||
.power_on = phy_mvebu_sata_power_on,
|
||||
.power_off = phy_mvebu_sata_power_off,
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -137,7 +137,7 @@ static int omap_usb_init(struct phy *x)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phy_ops ops = {
|
||||
static const struct phy_ops ops = {
|
||||
.init = omap_usb_init,
|
||||
.power_on = omap_usb_power_on,
|
||||
.power_off = omap_usb_power_off,
|
||||
|
@ -204,7 +204,7 @@ static int qcom_apq8064_sata_phy_exit(struct phy *generic_phy)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phy_ops qcom_apq8064_sata_phy_ops = {
|
||||
static const struct phy_ops qcom_apq8064_sata_phy_ops = {
|
||||
.init = qcom_apq8064_sata_phy_init,
|
||||
.exit = qcom_apq8064_sata_phy_exit,
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -126,7 +126,7 @@ static int qcom_ipq806x_sata_phy_exit(struct phy *generic_phy)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phy_ops qcom_ipq806x_sata_phy_ops = {
|
||||
static const struct phy_ops qcom_ipq806x_sata_phy_ops = {
|
||||
.init = qcom_ipq806x_sata_phy_init,
|
||||
.exit = qcom_ipq806x_sata_phy_exit,
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -150,7 +150,7 @@ int ufs_qcom_phy_remove(struct phy *generic_phy,
|
||||
struct ufs_qcom_phy *ufs_qcom_phy);
|
||||
struct phy *ufs_qcom_phy_generic_probe(struct platform_device *pdev,
|
||||
struct ufs_qcom_phy *common_cfg,
|
||||
struct phy_ops *ufs_qcom_phy_gen_ops,
|
||||
const struct phy_ops *ufs_qcom_phy_gen_ops,
|
||||
struct ufs_qcom_phy_specific_ops *phy_spec_ops);
|
||||
int ufs_qcom_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
|
||||
struct ufs_qcom_phy_calibration *tbl_A, int tbl_size_A,
|
||||
|
@ -115,7 +115,7 @@ static int ufs_qcom_phy_qmp_14nm_is_pcs_ready(struct ufs_qcom_phy *phy_common)
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct phy_ops ufs_qcom_phy_qmp_14nm_phy_ops = {
|
||||
static const struct phy_ops ufs_qcom_phy_qmp_14nm_phy_ops = {
|
||||
.init = ufs_qcom_phy_qmp_14nm_init,
|
||||
.exit = ufs_qcom_phy_exit,
|
||||
.power_on = ufs_qcom_phy_power_on,
|
||||
@ -191,7 +191,6 @@ static struct platform_driver ufs_qcom_phy_qmp_14nm_driver = {
|
||||
.driver = {
|
||||
.of_match_table = ufs_qcom_phy_qmp_14nm_of_match,
|
||||
.name = "ufs_qcom_phy_qmp_14nm",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -171,7 +171,7 @@ static int ufs_qcom_phy_qmp_20nm_is_pcs_ready(struct ufs_qcom_phy *phy_common)
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct phy_ops ufs_qcom_phy_qmp_20nm_phy_ops = {
|
||||
static const struct phy_ops ufs_qcom_phy_qmp_20nm_phy_ops = {
|
||||
.init = ufs_qcom_phy_qmp_20nm_init,
|
||||
.exit = ufs_qcom_phy_exit,
|
||||
.power_on = ufs_qcom_phy_power_on,
|
||||
@ -247,7 +247,6 @@ static struct platform_driver ufs_qcom_phy_qmp_20nm_driver = {
|
||||
.driver = {
|
||||
.of_match_table = ufs_qcom_phy_qmp_20nm_of_match,
|
||||
.name = "ufs_qcom_phy_qmp_20nm",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -77,7 +77,7 @@ EXPORT_SYMBOL_GPL(ufs_qcom_phy_calibrate);
|
||||
|
||||
struct phy *ufs_qcom_phy_generic_probe(struct platform_device *pdev,
|
||||
struct ufs_qcom_phy *common_cfg,
|
||||
struct phy_ops *ufs_qcom_phy_gen_ops,
|
||||
const struct phy_ops *ufs_qcom_phy_gen_ops,
|
||||
struct ufs_qcom_phy_specific_ops *phy_spec_ops)
|
||||
{
|
||||
int err;
|
||||
|
@ -184,7 +184,7 @@ static int rcar_gen2_phy_power_off(struct phy *p)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phy_ops rcar_gen2_phy_ops = {
|
||||
static const struct phy_ops rcar_gen2_phy_ops = {
|
||||
.init = rcar_gen2_phy_init,
|
||||
.exit = rcar_gen2_phy_exit,
|
||||
.power_on = rcar_gen2_phy_power_on,
|
||||
|
@ -84,7 +84,7 @@ static int rockchip_usb_phy_power_on(struct phy *_phy)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phy_ops ops = {
|
||||
static const struct phy_ops ops = {
|
||||
.power_on = rockchip_usb_phy_power_on,
|
||||
.power_off = rockchip_usb_phy_power_off,
|
||||
.owner = THIS_MODULE,
|
||||
@ -146,7 +146,6 @@ static struct platform_driver rockchip_usb_driver = {
|
||||
.probe = rockchip_usb_phy_probe,
|
||||
.driver = {
|
||||
.name = "rockchip-usb-phy",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = rockchip_usb_phy_dt_ids,
|
||||
},
|
||||
};
|
||||
|
@ -71,7 +71,7 @@ static int samsung_usb2_phy_power_off(struct phy *phy)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phy_ops samsung_usb2_phy_ops = {
|
||||
static const struct phy_ops samsung_usb2_phy_ops = {
|
||||
.power_on = samsung_usb2_phy_power_on,
|
||||
.power_off = samsung_usb2_phy_power_off,
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -179,7 +179,7 @@ static const struct of_device_id spear1310_miphy_of_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, spear1310_miphy_of_match);
|
||||
|
||||
static struct phy_ops spear1310_miphy_ops = {
|
||||
static const struct phy_ops spear1310_miphy_ops = {
|
||||
.init = spear1310_miphy_init,
|
||||
.exit = spear1310_miphy_exit,
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -189,7 +189,7 @@ static const struct of_device_id spear1340_miphy_of_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, spear1340_miphy_of_match);
|
||||
|
||||
static struct phy_ops spear1340_miphy_ops = {
|
||||
static const struct phy_ops spear1340_miphy_ops = {
|
||||
.init = spear1340_miphy_init,
|
||||
.exit = spear1340_miphy_exit,
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -112,7 +112,7 @@ static int stih41x_usb_phy_power_off(struct phy *phy)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phy_ops stih41x_usb_phy_ops = {
|
||||
static const struct phy_ops stih41x_usb_phy_ops = {
|
||||
.init = stih41x_usb_phy_init,
|
||||
.power_on = stih41x_usb_phy_power_on,
|
||||
.power_off = stih41x_usb_phy_power_off,
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Allwinner sun4i USB phy driver
|
||||
*
|
||||
* Copyright (C) 2014 Hans de Goede <hdegoede@redhat.com>
|
||||
* Copyright (C) 2014-2015 Hans de Goede <hdegoede@redhat.com>
|
||||
*
|
||||
* Based on code from
|
||||
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
|
||||
@ -22,23 +22,30 @@
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/extcon.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/phy/phy-sun4i-usb.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#define REG_ISCR 0x00
|
||||
#define REG_PHYCTL 0x04
|
||||
#define REG_PHYCTL_A10 0x04
|
||||
#define REG_PHYBIST 0x08
|
||||
#define REG_PHYTUNE 0x0c
|
||||
#define REG_PHYCTL_A33 0x10
|
||||
|
||||
#define PHYCTL_DATA BIT(7)
|
||||
|
||||
@ -47,6 +54,17 @@
|
||||
#define SUNXI_AHB_INCRX_ALIGN_EN BIT(8)
|
||||
#define SUNXI_ULPI_BYPASS_EN BIT(0)
|
||||
|
||||
/* ISCR, Interface Status and Control bits */
|
||||
#define ISCR_ID_PULLUP_EN (1 << 17)
|
||||
#define ISCR_DPDM_PULLUP_EN (1 << 16)
|
||||
/* sunxi has the phy id/vbus pins not connected, so we use the force bits */
|
||||
#define ISCR_FORCE_ID_MASK (3 << 14)
|
||||
#define ISCR_FORCE_ID_LOW (2 << 14)
|
||||
#define ISCR_FORCE_ID_HIGH (3 << 14)
|
||||
#define ISCR_FORCE_VBUS_MASK (3 << 12)
|
||||
#define ISCR_FORCE_VBUS_LOW (2 << 12)
|
||||
#define ISCR_FORCE_VBUS_HIGH (3 << 12)
|
||||
|
||||
/* Common Control Bits for Both PHYs */
|
||||
#define PHY_PLL_BW 0x03
|
||||
#define PHY_RES45_CAL_EN 0x0c
|
||||
@ -63,60 +81,124 @@
|
||||
|
||||
#define MAX_PHYS 3
|
||||
|
||||
/*
|
||||
* Note do not raise the debounce time, we must report Vusb high within 100ms
|
||||
* otherwise we get Vbus errors
|
||||
*/
|
||||
#define DEBOUNCE_TIME msecs_to_jiffies(50)
|
||||
#define POLL_TIME msecs_to_jiffies(250)
|
||||
|
||||
struct sun4i_usb_phy_data {
|
||||
void __iomem *base;
|
||||
struct mutex mutex;
|
||||
int num_phys;
|
||||
u32 disc_thresh;
|
||||
bool has_a33_phyctl;
|
||||
struct sun4i_usb_phy {
|
||||
struct phy *phy;
|
||||
void __iomem *pmu;
|
||||
struct regulator *vbus;
|
||||
struct reset_control *reset;
|
||||
struct clk *clk;
|
||||
bool regulator_on;
|
||||
int index;
|
||||
} phys[MAX_PHYS];
|
||||
/* phy0 / otg related variables */
|
||||
struct extcon_dev *extcon;
|
||||
bool phy0_init;
|
||||
bool phy0_poll;
|
||||
struct gpio_desc *id_det_gpio;
|
||||
struct gpio_desc *vbus_det_gpio;
|
||||
struct power_supply *vbus_power_supply;
|
||||
struct notifier_block vbus_power_nb;
|
||||
bool vbus_power_nb_registered;
|
||||
int id_det_irq;
|
||||
int vbus_det_irq;
|
||||
int id_det;
|
||||
int vbus_det;
|
||||
struct delayed_work detect;
|
||||
};
|
||||
|
||||
#define to_sun4i_usb_phy_data(phy) \
|
||||
container_of((phy), struct sun4i_usb_phy_data, phys[(phy)->index])
|
||||
|
||||
static void sun4i_usb_phy0_update_iscr(struct phy *_phy, u32 clr, u32 set)
|
||||
{
|
||||
struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
|
||||
struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy);
|
||||
u32 iscr;
|
||||
|
||||
iscr = readl(data->base + REG_ISCR);
|
||||
iscr &= ~clr;
|
||||
iscr |= set;
|
||||
writel(iscr, data->base + REG_ISCR);
|
||||
}
|
||||
|
||||
static void sun4i_usb_phy0_set_id_detect(struct phy *phy, u32 val)
|
||||
{
|
||||
if (val)
|
||||
val = ISCR_FORCE_ID_HIGH;
|
||||
else
|
||||
val = ISCR_FORCE_ID_LOW;
|
||||
|
||||
sun4i_usb_phy0_update_iscr(phy, ISCR_FORCE_ID_MASK, val);
|
||||
}
|
||||
|
||||
static void sun4i_usb_phy0_set_vbus_detect(struct phy *phy, u32 val)
|
||||
{
|
||||
if (val)
|
||||
val = ISCR_FORCE_VBUS_HIGH;
|
||||
else
|
||||
val = ISCR_FORCE_VBUS_LOW;
|
||||
|
||||
sun4i_usb_phy0_update_iscr(phy, ISCR_FORCE_VBUS_MASK, val);
|
||||
}
|
||||
|
||||
static void sun4i_usb_phy_write(struct sun4i_usb_phy *phy, u32 addr, u32 data,
|
||||
int len)
|
||||
{
|
||||
struct sun4i_usb_phy_data *phy_data = to_sun4i_usb_phy_data(phy);
|
||||
u32 temp, usbc_bit = BIT(phy->index * 2);
|
||||
void *phyctl;
|
||||
int i;
|
||||
|
||||
mutex_lock(&phy_data->mutex);
|
||||
|
||||
if (phy_data->has_a33_phyctl) {
|
||||
phyctl = phy_data->base + REG_PHYCTL_A33;
|
||||
/* A33 needs us to set phyctl to 0 explicitly */
|
||||
writel(0, phyctl);
|
||||
} else {
|
||||
phyctl = phy_data->base + REG_PHYCTL_A10;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
temp = readl(phy_data->base + REG_PHYCTL);
|
||||
temp = readl(phyctl);
|
||||
|
||||
/* clear the address portion */
|
||||
temp &= ~(0xff << 8);
|
||||
|
||||
/* set the address */
|
||||
temp |= ((addr + i) << 8);
|
||||
writel(temp, phy_data->base + REG_PHYCTL);
|
||||
writel(temp, phyctl);
|
||||
|
||||
/* set the data bit and clear usbc bit*/
|
||||
temp = readb(phy_data->base + REG_PHYCTL);
|
||||
temp = readb(phyctl);
|
||||
if (data & 0x1)
|
||||
temp |= PHYCTL_DATA;
|
||||
else
|
||||
temp &= ~PHYCTL_DATA;
|
||||
temp &= ~usbc_bit;
|
||||
writeb(temp, phy_data->base + REG_PHYCTL);
|
||||
writeb(temp, phyctl);
|
||||
|
||||
/* pulse usbc_bit */
|
||||
temp = readb(phy_data->base + REG_PHYCTL);
|
||||
temp = readb(phyctl);
|
||||
temp |= usbc_bit;
|
||||
writeb(temp, phy_data->base + REG_PHYCTL);
|
||||
writeb(temp, phyctl);
|
||||
|
||||
temp = readb(phy_data->base + REG_PHYCTL);
|
||||
temp = readb(phyctl);
|
||||
temp &= ~usbc_bit;
|
||||
writeb(temp, phy_data->base + REG_PHYCTL);
|
||||
writeb(temp, phyctl);
|
||||
|
||||
data >>= 1;
|
||||
}
|
||||
@ -171,12 +253,39 @@ static int sun4i_usb_phy_init(struct phy *_phy)
|
||||
|
||||
sun4i_usb_phy_passby(phy, 1);
|
||||
|
||||
if (phy->index == 0) {
|
||||
data->phy0_init = true;
|
||||
|
||||
/* Enable pull-ups */
|
||||
sun4i_usb_phy0_update_iscr(_phy, 0, ISCR_DPDM_PULLUP_EN);
|
||||
sun4i_usb_phy0_update_iscr(_phy, 0, ISCR_ID_PULLUP_EN);
|
||||
|
||||
if (data->id_det_gpio) {
|
||||
/* OTG mode, force ISCR and cable state updates */
|
||||
data->id_det = -1;
|
||||
data->vbus_det = -1;
|
||||
queue_delayed_work(system_wq, &data->detect, 0);
|
||||
} else {
|
||||
/* Host only mode */
|
||||
sun4i_usb_phy0_set_id_detect(_phy, 0);
|
||||
sun4i_usb_phy0_set_vbus_detect(_phy, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sun4i_usb_phy_exit(struct phy *_phy)
|
||||
{
|
||||
struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
|
||||
struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy);
|
||||
|
||||
if (phy->index == 0) {
|
||||
/* Disable pull-ups */
|
||||
sun4i_usb_phy0_update_iscr(_phy, ISCR_DPDM_PULLUP_EN, 0);
|
||||
sun4i_usb_phy0_update_iscr(_phy, ISCR_ID_PULLUP_EN, 0);
|
||||
data->phy0_init = false;
|
||||
}
|
||||
|
||||
sun4i_usb_phy_passby(phy, 0);
|
||||
reset_control_assert(phy->reset);
|
||||
@ -185,23 +294,74 @@ static int sun4i_usb_phy_exit(struct phy *_phy)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sun4i_usb_phy0_get_vbus_det(struct sun4i_usb_phy_data *data)
|
||||
{
|
||||
if (data->vbus_det_gpio)
|
||||
return gpiod_get_value_cansleep(data->vbus_det_gpio);
|
||||
|
||||
if (data->vbus_power_supply) {
|
||||
union power_supply_propval val;
|
||||
int r;
|
||||
|
||||
r = power_supply_get_property(data->vbus_power_supply,
|
||||
POWER_SUPPLY_PROP_PRESENT, &val);
|
||||
if (r == 0)
|
||||
return val.intval;
|
||||
}
|
||||
|
||||
/* Fallback: report vbus as high */
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool sun4i_usb_phy0_have_vbus_det(struct sun4i_usb_phy_data *data)
|
||||
{
|
||||
return data->vbus_det_gpio || data->vbus_power_supply;
|
||||
}
|
||||
|
||||
static int sun4i_usb_phy_power_on(struct phy *_phy)
|
||||
{
|
||||
struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
|
||||
int ret = 0;
|
||||
struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy);
|
||||
int ret;
|
||||
|
||||
if (phy->vbus)
|
||||
ret = regulator_enable(phy->vbus);
|
||||
if (!phy->vbus || phy->regulator_on)
|
||||
return 0;
|
||||
|
||||
return ret;
|
||||
/* For phy0 only turn on Vbus if we don't have an ext. Vbus */
|
||||
if (phy->index == 0 && sun4i_usb_phy0_have_vbus_det(data) &&
|
||||
data->vbus_det)
|
||||
return 0;
|
||||
|
||||
ret = regulator_enable(phy->vbus);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
phy->regulator_on = true;
|
||||
|
||||
/* We must report Vbus high within OTG_TIME_A_WAIT_VRISE msec. */
|
||||
if (phy->index == 0 && data->vbus_det_gpio && data->phy0_poll)
|
||||
mod_delayed_work(system_wq, &data->detect, DEBOUNCE_TIME);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sun4i_usb_phy_power_off(struct phy *_phy)
|
||||
{
|
||||
struct sun4i_usb_phy *phy = phy_get_drvdata(_phy);
|
||||
struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy);
|
||||
|
||||
if (phy->vbus)
|
||||
regulator_disable(phy->vbus);
|
||||
if (!phy->vbus || !phy->regulator_on)
|
||||
return 0;
|
||||
|
||||
regulator_disable(phy->vbus);
|
||||
phy->regulator_on = false;
|
||||
|
||||
/*
|
||||
* phy0 vbus typically slowly discharges, sometimes this causes the
|
||||
* Vbus gpio to not trigger an edge irq on Vbus off, so force a rescan.
|
||||
*/
|
||||
if (phy->index == 0 && data->vbus_det_gpio && !data->phy0_poll)
|
||||
mod_delayed_work(system_wq, &data->detect, POLL_TIME);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -214,7 +374,7 @@ void sun4i_usb_phy_set_squelch_detect(struct phy *_phy, bool enabled)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sun4i_usb_phy_set_squelch_detect);
|
||||
|
||||
static struct phy_ops sun4i_usb_phy_ops = {
|
||||
static const struct phy_ops sun4i_usb_phy_ops = {
|
||||
.init = sun4i_usb_phy_init,
|
||||
.exit = sun4i_usb_phy_exit,
|
||||
.power_on = sun4i_usb_phy_power_on,
|
||||
@ -222,6 +382,95 @@ static struct phy_ops sun4i_usb_phy_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work)
|
||||
{
|
||||
struct sun4i_usb_phy_data *data =
|
||||
container_of(work, struct sun4i_usb_phy_data, detect.work);
|
||||
struct phy *phy0 = data->phys[0].phy;
|
||||
int id_det, vbus_det, id_notify = 0, vbus_notify = 0;
|
||||
|
||||
id_det = gpiod_get_value_cansleep(data->id_det_gpio);
|
||||
vbus_det = sun4i_usb_phy0_get_vbus_det(data);
|
||||
|
||||
mutex_lock(&phy0->mutex);
|
||||
|
||||
if (!data->phy0_init) {
|
||||
mutex_unlock(&phy0->mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (id_det != data->id_det) {
|
||||
/*
|
||||
* When a host cable (id == 0) gets plugged in on systems
|
||||
* without vbus detection report vbus low for long enough for
|
||||
* the musb-ip to end the current device session.
|
||||
*/
|
||||
if (!sun4i_usb_phy0_have_vbus_det(data) && id_det == 0) {
|
||||
sun4i_usb_phy0_set_vbus_detect(phy0, 0);
|
||||
msleep(200);
|
||||
sun4i_usb_phy0_set_vbus_detect(phy0, 1);
|
||||
}
|
||||
sun4i_usb_phy0_set_id_detect(phy0, id_det);
|
||||
data->id_det = id_det;
|
||||
id_notify = 1;
|
||||
}
|
||||
|
||||
if (vbus_det != data->vbus_det) {
|
||||
sun4i_usb_phy0_set_vbus_detect(phy0, vbus_det);
|
||||
data->vbus_det = vbus_det;
|
||||
vbus_notify = 1;
|
||||
}
|
||||
|
||||
mutex_unlock(&phy0->mutex);
|
||||
|
||||
if (id_notify) {
|
||||
extcon_set_cable_state_(data->extcon, EXTCON_USB_HOST,
|
||||
!id_det);
|
||||
/*
|
||||
* When a host cable gets unplugged (id == 1) on systems
|
||||
* without vbus detection report vbus low for long enough to
|
||||
* the musb-ip to end the current host session.
|
||||
*/
|
||||
if (!sun4i_usb_phy0_have_vbus_det(data) && id_det == 1) {
|
||||
mutex_lock(&phy0->mutex);
|
||||
sun4i_usb_phy0_set_vbus_detect(phy0, 0);
|
||||
msleep(1000);
|
||||
sun4i_usb_phy0_set_vbus_detect(phy0, 1);
|
||||
mutex_unlock(&phy0->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
if (vbus_notify)
|
||||
extcon_set_cable_state_(data->extcon, EXTCON_USB, vbus_det);
|
||||
|
||||
if (data->phy0_poll)
|
||||
queue_delayed_work(system_wq, &data->detect, POLL_TIME);
|
||||
}
|
||||
|
||||
static irqreturn_t sun4i_usb_phy0_id_vbus_det_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct sun4i_usb_phy_data *data = dev_id;
|
||||
|
||||
/* vbus or id changed, let the pins settle and then scan them */
|
||||
mod_delayed_work(system_wq, &data->detect, DEBOUNCE_TIME);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int sun4i_usb_phy0_vbus_notify(struct notifier_block *nb,
|
||||
unsigned long val, void *v)
|
||||
{
|
||||
struct sun4i_usb_phy_data *data =
|
||||
container_of(nb, struct sun4i_usb_phy_data, vbus_power_nb);
|
||||
struct power_supply *psy = v;
|
||||
|
||||
/* Properties on the vbus_power_supply changed, scan vbus_det */
|
||||
if (val == PSY_EVENT_PROP_CHANGED && psy == data->vbus_power_supply)
|
||||
mod_delayed_work(system_wq, &data->detect, DEBOUNCE_TIME);
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static struct phy *sun4i_usb_phy_xlate(struct device *dev,
|
||||
struct of_phandle_args *args)
|
||||
{
|
||||
@ -233,6 +482,29 @@ static struct phy *sun4i_usb_phy_xlate(struct device *dev,
|
||||
return data->phys[args->args[0]].phy;
|
||||
}
|
||||
|
||||
static int sun4i_usb_phy_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct sun4i_usb_phy_data *data = dev_get_drvdata(dev);
|
||||
|
||||
if (data->vbus_power_nb_registered)
|
||||
power_supply_unreg_notifier(&data->vbus_power_nb);
|
||||
if (data->id_det_irq >= 0)
|
||||
devm_free_irq(dev, data->id_det_irq, data);
|
||||
if (data->vbus_det_irq >= 0)
|
||||
devm_free_irq(dev, data->vbus_det_irq, data);
|
||||
|
||||
cancel_delayed_work_sync(&data->detect);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const unsigned int sun4i_usb_phy0_cable[] = {
|
||||
EXTCON_USB,
|
||||
EXTCON_USB_HOST,
|
||||
EXTCON_NONE,
|
||||
};
|
||||
|
||||
static int sun4i_usb_phy_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sun4i_usb_phy_data *data;
|
||||
@ -241,35 +513,87 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
|
||||
struct phy_provider *phy_provider;
|
||||
bool dedicated_clocks;
|
||||
struct resource *res;
|
||||
int i;
|
||||
int i, ret;
|
||||
|
||||
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&data->mutex);
|
||||
INIT_DELAYED_WORK(&data->detect, sun4i_usb_phy0_id_vbus_det_scan);
|
||||
dev_set_drvdata(dev, data);
|
||||
|
||||
if (of_device_is_compatible(np, "allwinner,sun5i-a13-usb-phy"))
|
||||
if (of_device_is_compatible(np, "allwinner,sun5i-a13-usb-phy") ||
|
||||
of_device_is_compatible(np, "allwinner,sun8i-a23-usb-phy") ||
|
||||
of_device_is_compatible(np, "allwinner,sun8i-a33-usb-phy"))
|
||||
data->num_phys = 2;
|
||||
else
|
||||
data->num_phys = 3;
|
||||
|
||||
if (of_device_is_compatible(np, "allwinner,sun4i-a10-usb-phy") ||
|
||||
of_device_is_compatible(np, "allwinner,sun6i-a31-usb-phy"))
|
||||
data->disc_thresh = 3;
|
||||
else
|
||||
if (of_device_is_compatible(np, "allwinner,sun5i-a13-usb-phy") ||
|
||||
of_device_is_compatible(np, "allwinner,sun7i-a20-usb-phy"))
|
||||
data->disc_thresh = 2;
|
||||
else
|
||||
data->disc_thresh = 3;
|
||||
|
||||
if (of_device_is_compatible(np, "allwinner,sun6i-a31-usb-phy"))
|
||||
if (of_device_is_compatible(np, "allwinner,sun6i-a31-usb-phy") ||
|
||||
of_device_is_compatible(np, "allwinner,sun8i-a23-usb-phy") ||
|
||||
of_device_is_compatible(np, "allwinner,sun8i-a33-usb-phy"))
|
||||
dedicated_clocks = true;
|
||||
else
|
||||
dedicated_clocks = false;
|
||||
|
||||
if (of_device_is_compatible(np, "allwinner,sun8i-a33-usb-phy"))
|
||||
data->has_a33_phyctl = true;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_ctrl");
|
||||
data->base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(data->base))
|
||||
return PTR_ERR(data->base);
|
||||
|
||||
data->id_det_gpio = devm_gpiod_get(dev, "usb0_id_det", GPIOD_IN);
|
||||
if (IS_ERR(data->id_det_gpio)) {
|
||||
if (PTR_ERR(data->id_det_gpio) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
data->id_det_gpio = NULL;
|
||||
}
|
||||
|
||||
data->vbus_det_gpio = devm_gpiod_get(dev, "usb0_vbus_det", GPIOD_IN);
|
||||
if (IS_ERR(data->vbus_det_gpio)) {
|
||||
if (PTR_ERR(data->vbus_det_gpio) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
data->vbus_det_gpio = NULL;
|
||||
}
|
||||
|
||||
if (of_find_property(np, "usb0_vbus_power-supply", NULL)) {
|
||||
data->vbus_power_supply = devm_power_supply_get_by_phandle(dev,
|
||||
"usb0_vbus_power-supply");
|
||||
if (IS_ERR(data->vbus_power_supply))
|
||||
return PTR_ERR(data->vbus_power_supply);
|
||||
|
||||
if (!data->vbus_power_supply)
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
/* vbus_det without id_det makes no sense, and is not supported */
|
||||
if (sun4i_usb_phy0_have_vbus_det(data) && !data->id_det_gpio) {
|
||||
dev_err(dev, "usb0_id_det missing or invalid\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (data->id_det_gpio) {
|
||||
data->extcon = devm_extcon_dev_allocate(dev,
|
||||
sun4i_usb_phy0_cable);
|
||||
if (IS_ERR(data->extcon))
|
||||
return PTR_ERR(data->extcon);
|
||||
|
||||
ret = devm_extcon_dev_register(dev, data->extcon);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to register extcon: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < data->num_phys; i++) {
|
||||
struct sun4i_usb_phy *phy = data->phys + i;
|
||||
char name[16];
|
||||
@ -319,10 +643,54 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)
|
||||
phy_set_drvdata(phy->phy, &data->phys[i]);
|
||||
}
|
||||
|
||||
dev_set_drvdata(dev, data);
|
||||
phy_provider = devm_of_phy_provider_register(dev, sun4i_usb_phy_xlate);
|
||||
data->id_det_irq = gpiod_to_irq(data->id_det_gpio);
|
||||
data->vbus_det_irq = gpiod_to_irq(data->vbus_det_gpio);
|
||||
if ((data->id_det_gpio && data->id_det_irq < 0) ||
|
||||
(data->vbus_det_gpio && data->vbus_det_irq < 0))
|
||||
data->phy0_poll = true;
|
||||
|
||||
return PTR_ERR_OR_ZERO(phy_provider);
|
||||
if (data->id_det_irq >= 0) {
|
||||
ret = devm_request_irq(dev, data->id_det_irq,
|
||||
sun4i_usb_phy0_id_vbus_det_irq,
|
||||
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
|
||||
"usb0-id-det", data);
|
||||
if (ret) {
|
||||
dev_err(dev, "Err requesting id-det-irq: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (data->vbus_det_irq >= 0) {
|
||||
ret = devm_request_irq(dev, data->vbus_det_irq,
|
||||
sun4i_usb_phy0_id_vbus_det_irq,
|
||||
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
|
||||
"usb0-vbus-det", data);
|
||||
if (ret) {
|
||||
dev_err(dev, "Err requesting vbus-det-irq: %d\n", ret);
|
||||
data->vbus_det_irq = -1;
|
||||
sun4i_usb_phy_remove(pdev); /* Stop detect work */
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (data->vbus_power_supply) {
|
||||
data->vbus_power_nb.notifier_call = sun4i_usb_phy0_vbus_notify;
|
||||
data->vbus_power_nb.priority = 0;
|
||||
ret = power_supply_reg_notifier(&data->vbus_power_nb);
|
||||
if (ret) {
|
||||
sun4i_usb_phy_remove(pdev); /* Stop detect work */
|
||||
return ret;
|
||||
}
|
||||
data->vbus_power_nb_registered = true;
|
||||
}
|
||||
|
||||
phy_provider = devm_of_phy_provider_register(dev, sun4i_usb_phy_xlate);
|
||||
if (IS_ERR(phy_provider)) {
|
||||
sun4i_usb_phy_remove(pdev); /* Stop detect work */
|
||||
return PTR_ERR(phy_provider);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id sun4i_usb_phy_of_match[] = {
|
||||
@ -330,12 +698,15 @@ static const struct of_device_id sun4i_usb_phy_of_match[] = {
|
||||
{ .compatible = "allwinner,sun5i-a13-usb-phy" },
|
||||
{ .compatible = "allwinner,sun6i-a31-usb-phy" },
|
||||
{ .compatible = "allwinner,sun7i-a20-usb-phy" },
|
||||
{ .compatible = "allwinner,sun8i-a23-usb-phy" },
|
||||
{ .compatible = "allwinner,sun8i-a33-usb-phy" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sun4i_usb_phy_of_match);
|
||||
|
||||
static struct platform_driver sun4i_usb_phy_driver = {
|
||||
.probe = sun4i_usb_phy_probe,
|
||||
.remove = sun4i_usb_phy_remove,
|
||||
.driver = {
|
||||
.of_match_table = sun4i_usb_phy_of_match,
|
||||
.name = "sun4i-usb-phy",
|
||||
|
@ -114,7 +114,7 @@ static int sun9i_usb_phy_exit(struct phy *_phy)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phy_ops sun9i_usb_phy_ops = {
|
||||
static const struct phy_ops sun9i_usb_phy_ops = {
|
||||
.init = sun9i_usb_phy_init,
|
||||
.exit = sun9i_usb_phy_exit,
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -298,7 +298,7 @@ static int ti_pipe3_exit(struct phy *x)
|
||||
|
||||
return 0;
|
||||
}
|
||||
static struct phy_ops ops = {
|
||||
static const struct phy_ops ops = {
|
||||
.init = ti_pipe3_init,
|
||||
.exit = ti_pipe3_exit,
|
||||
.power_on = ti_pipe3_power_on,
|
||||
|
@ -53,7 +53,7 @@ static int tusb1210_power_off(struct phy *phy)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct phy_ops phy_ops = {
|
||||
static const struct phy_ops phy_ops = {
|
||||
.power_on = tusb1210_power_on,
|
||||
.power_off = tusb1210_power_off,
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -5,7 +5,7 @@
|
||||
* and it's controller, which is always the parent.
|
||||
*/
|
||||
static inline struct phy
|
||||
*ulpi_phy_create(struct ulpi *ulpi, struct phy_ops *ops)
|
||||
*ulpi_phy_create(struct ulpi *ulpi, const struct phy_ops *ops)
|
||||
{
|
||||
struct phy *phy;
|
||||
int ret;
|
||||
|
@ -3153,36 +3153,46 @@ static const struct usb_gadget_ops nbu2ss_gadget_ops = {
|
||||
.ioctl = nbu2ss_gad_ioctl,
|
||||
};
|
||||
|
||||
static const char g_ep0_name[] = "ep0";
|
||||
static const char g_ep1_name[] = "ep1-bulk";
|
||||
static const char g_ep2_name[] = "ep2-bulk";
|
||||
static const char g_ep3_name[] = "ep3in-int";
|
||||
static const char g_ep4_name[] = "ep4-iso";
|
||||
static const char g_ep5_name[] = "ep5-iso";
|
||||
static const char g_ep6_name[] = "ep6-bulk";
|
||||
static const char g_ep7_name[] = "ep7-bulk";
|
||||
static const char g_ep8_name[] = "ep8in-int";
|
||||
static const char g_ep9_name[] = "ep9-iso";
|
||||
static const char g_epa_name[] = "epa-iso";
|
||||
static const char g_epb_name[] = "epb-bulk";
|
||||
static const char g_epc_name[] = "epc-nulk";
|
||||
static const char g_epd_name[] = "epdin-int";
|
||||
static const struct {
|
||||
const char *name;
|
||||
const struct usb_ep_caps caps;
|
||||
} ep_info[NUM_ENDPOINTS] = {
|
||||
#define EP_INFO(_name, _caps) \
|
||||
{ \
|
||||
.name = _name, \
|
||||
.caps = _caps, \
|
||||
}
|
||||
|
||||
static const char *gp_ep_name[NUM_ENDPOINTS] = {
|
||||
g_ep0_name,
|
||||
g_ep1_name,
|
||||
g_ep2_name,
|
||||
g_ep3_name,
|
||||
g_ep4_name,
|
||||
g_ep5_name,
|
||||
g_ep6_name,
|
||||
g_ep7_name,
|
||||
g_ep8_name,
|
||||
g_ep9_name,
|
||||
g_epa_name,
|
||||
g_epb_name,
|
||||
g_epc_name,
|
||||
g_epd_name,
|
||||
EP_INFO("ep0",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_CONTROL, USB_EP_CAPS_DIR_ALL)),
|
||||
EP_INFO("ep1-bulk",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_ALL)),
|
||||
EP_INFO("ep2-bulk",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_ALL)),
|
||||
EP_INFO("ep3in-int",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)),
|
||||
EP_INFO("ep4-iso",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_ALL)),
|
||||
EP_INFO("ep5-iso",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_ALL)),
|
||||
EP_INFO("ep6-bulk",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_ALL)),
|
||||
EP_INFO("ep7-bulk",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_ALL)),
|
||||
EP_INFO("ep8in-int",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)),
|
||||
EP_INFO("ep9-iso",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_ALL)),
|
||||
EP_INFO("epa-iso",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_ISO, USB_EP_CAPS_DIR_ALL)),
|
||||
EP_INFO("epb-bulk",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_ALL)),
|
||||
EP_INFO("epc-bulk",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_BULK, USB_EP_CAPS_DIR_ALL)),
|
||||
EP_INFO("epdin-int",
|
||||
USB_EP_CAPS(USB_EP_CAPS_TYPE_INT, USB_EP_CAPS_DIR_IN)),
|
||||
|
||||
#undef EP_INFO
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
@ -3200,10 +3210,12 @@ static void __init nbu2ss_drv_ep_init(struct nbu2ss_udc *udc)
|
||||
ep->desc = NULL;
|
||||
|
||||
ep->ep.driver_data = NULL;
|
||||
ep->ep.name = gp_ep_name[i];
|
||||
ep->ep.name = ep_info[i].name;
|
||||
ep->ep.caps = ep_info[i].caps;
|
||||
ep->ep.ops = &nbu2ss_ep_ops;
|
||||
|
||||
ep->ep.maxpacket = (i == 0 ? EP0_PACKETSIZE : EP_PACKETSIZE);
|
||||
usb_ep_set_maxpacket_limit(&ep->ep,
|
||||
i == 0 ? EP0_PACKETSIZE : EP_PACKETSIZE);
|
||||
|
||||
list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
|
||||
INIT_LIST_HEAD(&ep->queue);
|
||||
|
@ -270,6 +270,7 @@ static ssize_t cxacru_sysfs_showattr_dB(s16 value, char *buf)
|
||||
static ssize_t cxacru_sysfs_showattr_bool(u32 value, char *buf)
|
||||
{
|
||||
static char *str[] = { "no", "yes" };
|
||||
|
||||
if (unlikely(value >= ARRAY_SIZE(str)))
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", value);
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", str[value]);
|
||||
@ -278,6 +279,7 @@ static ssize_t cxacru_sysfs_showattr_bool(u32 value, char *buf)
|
||||
static ssize_t cxacru_sysfs_showattr_LINK(u32 value, char *buf)
|
||||
{
|
||||
static char *str[] = { NULL, "not connected", "connected", "lost" };
|
||||
|
||||
if (unlikely(value >= ARRAY_SIZE(str) || str[value] == NULL))
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", value);
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", str[value]);
|
||||
@ -702,6 +704,7 @@ static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_requ
|
||||
len = ret / 4;
|
||||
for (offb = 0; offb < len; ) {
|
||||
int l = le32_to_cpu(buf[offb++]);
|
||||
|
||||
if (l < 0 || l > stride || l > (len - offb) / 2) {
|
||||
if (printk_ratelimit())
|
||||
usb_err(instance->usbatm, "invalid data length from cm %#x: %d\n",
|
||||
@ -732,6 +735,7 @@ cleanup:
|
||||
static int cxacru_card_status(struct cxacru_data *instance)
|
||||
{
|
||||
int ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_STATUS, NULL, 0, NULL, 0);
|
||||
|
||||
if (ret < 0) { /* firmware not loaded */
|
||||
usb_dbg(instance->usbatm, "cxacru_adsl_start: CARD_GET_STATUS returned %d\n", ret);
|
||||
return ret;
|
||||
@ -945,6 +949,7 @@ static int cxacru_fw(struct usb_device *usb_dev, enum cxacru_fw_request fw,
|
||||
offb = offd = 0;
|
||||
do {
|
||||
int l = min_t(int, stride, size - offd);
|
||||
|
||||
buf[offb++] = fw;
|
||||
buf[offb++] = l;
|
||||
buf[offb++] = code1;
|
||||
@ -1091,8 +1096,8 @@ static int cxacru_heavy_init(struct usbatm_data *usbatm_instance,
|
||||
{
|
||||
const struct firmware *fw, *bp;
|
||||
struct cxacru_data *instance = usbatm_instance->driver_data;
|
||||
|
||||
int ret = cxacru_find_firmware(instance, "fw", &fw);
|
||||
|
||||
if (ret) {
|
||||
usb_warn(usbatm_instance, "firmware (cxacru-fw.bin) unavailable (system misconfigured?)\n");
|
||||
return ret;
|
||||
|
@ -25,6 +25,9 @@
|
||||
#define VERSION (0xF << 25)
|
||||
#define CIVERSION (0x7 << 29)
|
||||
|
||||
/* SBUSCFG */
|
||||
#define AHBBRST_MASK 0x7
|
||||
|
||||
/* HCCPARAMS */
|
||||
#define HCCPARAMS_LEN BIT(17)
|
||||
|
||||
@ -53,6 +56,15 @@
|
||||
#define DEVICEADDR_USBADRA BIT(24)
|
||||
#define DEVICEADDR_USBADR (0x7FUL << 25)
|
||||
|
||||
/* TTCTRL */
|
||||
#define TTCTRL_TTHA_MASK (0x7fUL << 24)
|
||||
/* Set non-zero value for internal TT Hub address representation */
|
||||
#define TTCTRL_TTHA (0x7fUL << 24)
|
||||
|
||||
/* BURSTSIZE */
|
||||
#define RX_BURST_MASK 0xff
|
||||
#define TX_BURST_MASK 0xff00
|
||||
|
||||
/* PORTSC */
|
||||
#define PORTSC_CCS BIT(0)
|
||||
#define PORTSC_CSC BIT(1)
|
||||
|
@ -50,6 +50,8 @@ enum ci_hw_regs {
|
||||
OP_USBINTR,
|
||||
OP_DEVICEADDR,
|
||||
OP_ENDPTLISTADDR,
|
||||
OP_TTCTRL,
|
||||
OP_BURSTSIZE,
|
||||
OP_PORTSC,
|
||||
OP_DEVLC,
|
||||
OP_OTGSC,
|
||||
@ -406,8 +408,11 @@ static inline u32 hw_test_and_write(struct ci_hdrc *ci, enum ci_hw_regs reg,
|
||||
static inline bool ci_otg_is_fsm_mode(struct ci_hdrc *ci)
|
||||
{
|
||||
#ifdef CONFIG_USB_OTG_FSM
|
||||
struct usb_otg_caps *otg_caps = &ci->platdata->ci_otg_caps;
|
||||
|
||||
return ci->is_otg && ci->roles[CI_ROLE_HOST] &&
|
||||
ci->roles[CI_ROLE_GADGET];
|
||||
ci->roles[CI_ROLE_GADGET] && (otg_caps->srp_support ||
|
||||
otg_caps->hnp_support || otg_caps->adp_support);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
@ -426,4 +431,6 @@ u8 hw_port_test_get(struct ci_hdrc *ci);
|
||||
int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask,
|
||||
u32 value, unsigned int timeout_ms);
|
||||
|
||||
void ci_platform_configure(struct ci_hdrc *ci);
|
||||
|
||||
#endif /* __DRIVERS_USB_CHIPIDEA_CI_H */
|
||||
|
@ -29,26 +29,31 @@ struct ci_hdrc_imx_platform_flag {
|
||||
};
|
||||
|
||||
static const struct ci_hdrc_imx_platform_flag imx27_usb_data = {
|
||||
CI_HDRC_DISABLE_STREAMING,
|
||||
};
|
||||
|
||||
static const struct ci_hdrc_imx_platform_flag imx28_usb_data = {
|
||||
.flags = CI_HDRC_IMX28_WRITE_FIX |
|
||||
CI_HDRC_TURN_VBUS_EARLY_ON,
|
||||
CI_HDRC_TURN_VBUS_EARLY_ON |
|
||||
CI_HDRC_DISABLE_STREAMING,
|
||||
};
|
||||
|
||||
static const struct ci_hdrc_imx_platform_flag imx6q_usb_data = {
|
||||
.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
|
||||
CI_HDRC_TURN_VBUS_EARLY_ON,
|
||||
CI_HDRC_TURN_VBUS_EARLY_ON |
|
||||
CI_HDRC_DISABLE_STREAMING,
|
||||
};
|
||||
|
||||
static const struct ci_hdrc_imx_platform_flag imx6sl_usb_data = {
|
||||
.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
|
||||
CI_HDRC_TURN_VBUS_EARLY_ON,
|
||||
CI_HDRC_TURN_VBUS_EARLY_ON |
|
||||
CI_HDRC_DISABLE_HOST_STREAMING,
|
||||
};
|
||||
|
||||
static const struct ci_hdrc_imx_platform_flag imx6sx_usb_data = {
|
||||
.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
|
||||
CI_HDRC_TURN_VBUS_EARLY_ON,
|
||||
CI_HDRC_TURN_VBUS_EARLY_ON |
|
||||
CI_HDRC_DISABLE_HOST_STREAMING,
|
||||
};
|
||||
|
||||
static const struct of_device_id ci_hdrc_imx_dt_ids[] = {
|
||||
@ -104,7 +109,7 @@ static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev)
|
||||
misc_pdev = of_find_device_by_node(args.np);
|
||||
of_node_put(args.np);
|
||||
|
||||
if (!misc_pdev)
|
||||
if (!misc_pdev || !platform_get_drvdata(misc_pdev))
|
||||
return ERR_PTR(-EPROBE_DEFER);
|
||||
|
||||
data->dev = &misc_pdev->dev;
|
||||
@ -126,7 +131,7 @@ static int ci_hdrc_imx_probe(struct platform_device *pdev)
|
||||
struct ci_hdrc_platform_data pdata = {
|
||||
.name = dev_name(&pdev->dev),
|
||||
.capoffset = DEF_CAPOFFSET,
|
||||
.flags = CI_HDRC_DISABLE_STREAMING,
|
||||
.flags = CI_HDRC_SET_NON_ZERO_TTHA,
|
||||
};
|
||||
int ret;
|
||||
const struct of_device_id *of_id =
|
||||
|
@ -64,6 +64,7 @@
|
||||
#include <linux/of.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/usb/ehci_def.h>
|
||||
|
||||
#include "ci.h"
|
||||
#include "udc.h"
|
||||
@ -84,6 +85,8 @@ static const u8 ci_regs_nolpm[] = {
|
||||
[OP_USBINTR] = 0x08U,
|
||||
[OP_DEVICEADDR] = 0x14U,
|
||||
[OP_ENDPTLISTADDR] = 0x18U,
|
||||
[OP_TTCTRL] = 0x1CU,
|
||||
[OP_BURSTSIZE] = 0x20U,
|
||||
[OP_PORTSC] = 0x44U,
|
||||
[OP_DEVLC] = 0x84U,
|
||||
[OP_OTGSC] = 0x64U,
|
||||
@ -106,6 +109,8 @@ static const u8 ci_regs_lpm[] = {
|
||||
[OP_USBINTR] = 0x08U,
|
||||
[OP_DEVICEADDR] = 0x14U,
|
||||
[OP_ENDPTLISTADDR] = 0x18U,
|
||||
[OP_TTCTRL] = 0x1CU,
|
||||
[OP_BURSTSIZE] = 0x20U,
|
||||
[OP_PORTSC] = 0x44U,
|
||||
[OP_DEVLC] = 0x84U,
|
||||
[OP_OTGSC] = 0xC4U,
|
||||
@ -118,7 +123,7 @@ static const u8 ci_regs_lpm[] = {
|
||||
[OP_ENDPTCTRL] = 0xECU,
|
||||
};
|
||||
|
||||
static int hw_alloc_regmap(struct ci_hdrc *ci, bool is_lpm)
|
||||
static void hw_alloc_regmap(struct ci_hdrc *ci, bool is_lpm)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -134,7 +139,6 @@ static int hw_alloc_regmap(struct ci_hdrc *ci, bool is_lpm)
|
||||
? ci_regs_lpm[OP_ENDPTCTRL]
|
||||
: ci_regs_nolpm[OP_ENDPTCTRL]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static enum ci_revision ci_get_revision(struct ci_hdrc *ci)
|
||||
@ -403,6 +407,55 @@ static int ci_usb_phy_init(struct ci_hdrc *ci)
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ci_platform_configure: do controller configure
|
||||
* @ci: the controller
|
||||
*
|
||||
*/
|
||||
void ci_platform_configure(struct ci_hdrc *ci)
|
||||
{
|
||||
bool is_device_mode, is_host_mode;
|
||||
|
||||
is_device_mode = hw_read(ci, OP_USBMODE, USBMODE_CM) == USBMODE_CM_DC;
|
||||
is_host_mode = hw_read(ci, OP_USBMODE, USBMODE_CM) == USBMODE_CM_HC;
|
||||
|
||||
if (is_device_mode &&
|
||||
(ci->platdata->flags & CI_HDRC_DISABLE_DEVICE_STREAMING))
|
||||
hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);
|
||||
|
||||
if (is_host_mode &&
|
||||
(ci->platdata->flags & CI_HDRC_DISABLE_HOST_STREAMING))
|
||||
hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);
|
||||
|
||||
if (ci->platdata->flags & CI_HDRC_FORCE_FULLSPEED) {
|
||||
if (ci->hw_bank.lpm)
|
||||
hw_write(ci, OP_DEVLC, DEVLC_PFSC, DEVLC_PFSC);
|
||||
else
|
||||
hw_write(ci, OP_PORTSC, PORTSC_PFSC, PORTSC_PFSC);
|
||||
}
|
||||
|
||||
if (ci->platdata->flags & CI_HDRC_SET_NON_ZERO_TTHA)
|
||||
hw_write(ci, OP_TTCTRL, TTCTRL_TTHA_MASK, TTCTRL_TTHA);
|
||||
|
||||
hw_write(ci, OP_USBCMD, 0xff0000, ci->platdata->itc_setting << 16);
|
||||
|
||||
if (ci->platdata->flags & CI_HDRC_OVERRIDE_AHB_BURST)
|
||||
hw_write_id_reg(ci, ID_SBUSCFG, AHBBRST_MASK,
|
||||
ci->platdata->ahb_burst_config);
|
||||
|
||||
/* override burst size, take effect only when ahb_burst_config is 0 */
|
||||
if (!hw_read_id_reg(ci, ID_SBUSCFG, AHBBRST_MASK)) {
|
||||
if (ci->platdata->flags & CI_HDRC_OVERRIDE_TX_BURST)
|
||||
hw_write(ci, OP_BURSTSIZE, TX_BURST_MASK,
|
||||
ci->platdata->tx_burst_size << __ffs(TX_BURST_MASK));
|
||||
|
||||
if (ci->platdata->flags & CI_HDRC_OVERRIDE_RX_BURST)
|
||||
hw_write(ci, OP_BURSTSIZE, RX_BURST_MASK,
|
||||
ci->platdata->rx_burst_size);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* hw_controller_reset: do controller reset
|
||||
* @ci: the controller
|
||||
@ -447,16 +500,6 @@ int hw_device_reset(struct ci_hdrc *ci)
|
||||
ci->platdata->notify_event(ci,
|
||||
CI_HDRC_CONTROLLER_RESET_EVENT);
|
||||
|
||||
if (ci->platdata->flags & CI_HDRC_DISABLE_STREAMING)
|
||||
hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);
|
||||
|
||||
if (ci->platdata->flags & CI_HDRC_FORCE_FULLSPEED) {
|
||||
if (ci->hw_bank.lpm)
|
||||
hw_write(ci, OP_DEVLC, DEVLC_PFSC, DEVLC_PFSC);
|
||||
else
|
||||
hw_write(ci, OP_PORTSC, PORTSC_PFSC, PORTSC_PFSC);
|
||||
}
|
||||
|
||||
/* USBMODE should be configured step by step */
|
||||
hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE);
|
||||
hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_DC);
|
||||
@ -469,6 +512,8 @@ int hw_device_reset(struct ci_hdrc *ci)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ci_platform_configure(ci);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -560,6 +605,8 @@ static irqreturn_t ci_irq(int irq, void *data)
|
||||
static int ci_get_platdata(struct device *dev,
|
||||
struct ci_hdrc_platform_data *platdata)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!platdata->phy_mode)
|
||||
platdata->phy_mode = of_usb_get_phy_mode(dev->of_node);
|
||||
|
||||
@ -588,9 +635,66 @@ static int ci_get_platdata(struct device *dev,
|
||||
of_usb_host_tpl_support(dev->of_node);
|
||||
}
|
||||
|
||||
if (platdata->dr_mode == USB_DR_MODE_OTG) {
|
||||
/* We can support HNP and SRP of OTG 2.0 */
|
||||
platdata->ci_otg_caps.otg_rev = 0x0200;
|
||||
platdata->ci_otg_caps.hnp_support = true;
|
||||
platdata->ci_otg_caps.srp_support = true;
|
||||
|
||||
/* Update otg capabilities by DT properties */
|
||||
ret = of_usb_update_otg_caps(dev->of_node,
|
||||
&platdata->ci_otg_caps);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (of_usb_get_maximum_speed(dev->of_node) == USB_SPEED_FULL)
|
||||
platdata->flags |= CI_HDRC_FORCE_FULLSPEED;
|
||||
|
||||
platdata->itc_setting = 1;
|
||||
if (of_find_property(dev->of_node, "itc-setting", NULL)) {
|
||||
ret = of_property_read_u32(dev->of_node, "itc-setting",
|
||||
&platdata->itc_setting);
|
||||
if (ret) {
|
||||
dev_err(dev,
|
||||
"failed to get itc-setting\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (of_find_property(dev->of_node, "ahb-burst-config", NULL)) {
|
||||
ret = of_property_read_u32(dev->of_node, "ahb-burst-config",
|
||||
&platdata->ahb_burst_config);
|
||||
if (ret) {
|
||||
dev_err(dev,
|
||||
"failed to get ahb-burst-config\n");
|
||||
return ret;
|
||||
}
|
||||
platdata->flags |= CI_HDRC_OVERRIDE_AHB_BURST;
|
||||
}
|
||||
|
||||
if (of_find_property(dev->of_node, "tx-burst-size-dword", NULL)) {
|
||||
ret = of_property_read_u32(dev->of_node, "tx-burst-size-dword",
|
||||
&platdata->tx_burst_size);
|
||||
if (ret) {
|
||||
dev_err(dev,
|
||||
"failed to get tx-burst-size-dword\n");
|
||||
return ret;
|
||||
}
|
||||
platdata->flags |= CI_HDRC_OVERRIDE_TX_BURST;
|
||||
}
|
||||
|
||||
if (of_find_property(dev->of_node, "rx-burst-size-dword", NULL)) {
|
||||
ret = of_property_read_u32(dev->of_node, "rx-burst-size-dword",
|
||||
&platdata->rx_burst_size);
|
||||
if (ret) {
|
||||
dev_err(dev,
|
||||
"failed to get rx-burst-size-dword\n");
|
||||
return ret;
|
||||
}
|
||||
platdata->flags |= CI_HDRC_OVERRIDE_RX_BURST;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <linux/usb/phy.h>
|
||||
#include <linux/usb/otg.h>
|
||||
#include <linux/usb/otg-fsm.h>
|
||||
#include <linux/usb/chipidea.h>
|
||||
|
||||
#include "ci.h"
|
||||
#include "udc.h"
|
||||
@ -66,9 +67,11 @@ static int ci_port_test_show(struct seq_file *s, void *data)
|
||||
unsigned long flags;
|
||||
unsigned mode;
|
||||
|
||||
pm_runtime_get_sync(ci->dev);
|
||||
spin_lock_irqsave(&ci->lock, flags);
|
||||
mode = hw_port_test_get(ci);
|
||||
spin_unlock_irqrestore(&ci->lock, flags);
|
||||
pm_runtime_put_sync(ci->dev);
|
||||
|
||||
seq_printf(s, "mode = %u\n", mode);
|
||||
|
||||
@ -98,9 +101,11 @@ static ssize_t ci_port_test_write(struct file *file, const char __user *ubuf,
|
||||
if (sscanf(buf, "%u", &mode) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
pm_runtime_get_sync(ci->dev);
|
||||
spin_lock_irqsave(&ci->lock, flags);
|
||||
ret = hw_port_test_set(ci, mode);
|
||||
spin_unlock_irqrestore(&ci->lock, flags);
|
||||
pm_runtime_put_sync(ci->dev);
|
||||
|
||||
return ret ? ret : count;
|
||||
}
|
||||
@ -316,8 +321,10 @@ static ssize_t ci_role_write(struct file *file, const char __user *ubuf,
|
||||
if (role == CI_ROLE_END || role == ci->role)
|
||||
return -EINVAL;
|
||||
|
||||
pm_runtime_get_sync(ci->dev);
|
||||
ci_role_stop(ci);
|
||||
ret = ci_role_start(ci, role);
|
||||
pm_runtime_put_sync(ci->dev);
|
||||
|
||||
return ret ? ret : count;
|
||||
}
|
||||
|
@ -37,15 +37,14 @@ static int (*orig_bus_suspend)(struct usb_hcd *hcd);
|
||||
|
||||
struct ehci_ci_priv {
|
||||
struct regulator *reg_vbus;
|
||||
struct ci_hdrc *ci;
|
||||
};
|
||||
|
||||
static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
struct ehci_ci_priv *priv = (struct ehci_ci_priv *)ehci->priv;
|
||||
struct ci_hdrc *ci = priv->ci;
|
||||
struct device *dev = hcd->self.controller;
|
||||
struct ci_hdrc *ci = dev_get_drvdata(dev);
|
||||
int ret = 0;
|
||||
int port = HCS_N_PORTS(ehci->hcs_params);
|
||||
|
||||
@ -78,9 +77,25 @@ static int ehci_ci_portpower(struct usb_hcd *hcd, int portnum, bool enable)
|
||||
return 0;
|
||||
};
|
||||
|
||||
static int ehci_ci_reset(struct usb_hcd *hcd)
|
||||
{
|
||||
struct device *dev = hcd->self.controller;
|
||||
struct ci_hdrc *ci = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = ehci_setup(hcd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ci_platform_configure(ci);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct ehci_driver_overrides ehci_ci_overrides = {
|
||||
.extra_priv_size = sizeof(struct ehci_ci_priv),
|
||||
.port_power = ehci_ci_portpower,
|
||||
.reset = ehci_ci_reset,
|
||||
};
|
||||
|
||||
static irqreturn_t host_irq(struct ci_hdrc *ci)
|
||||
@ -123,7 +138,6 @@ static int host_start(struct ci_hdrc *ci)
|
||||
|
||||
priv = (struct ehci_ci_priv *)ehci->priv;
|
||||
priv->reg_vbus = NULL;
|
||||
priv->ci = ci;
|
||||
|
||||
if (ci->platdata->reg_vbus && !ci_otg_is_fsm_mode(ci)) {
|
||||
if (ci->platdata->flags & CI_HDRC_TURN_VBUS_EARLY_ON) {
|
||||
@ -153,12 +167,6 @@ static int host_start(struct ci_hdrc *ci)
|
||||
}
|
||||
}
|
||||
|
||||
if (ci->platdata->flags & CI_HDRC_DISABLE_STREAMING)
|
||||
hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS);
|
||||
|
||||
if (ci->platdata->flags & CI_HDRC_FORCE_FULLSPEED)
|
||||
hw_write(ci, OP_PORTSC, PORTSC_PFSC, PORTSC_PFSC);
|
||||
|
||||
return ret;
|
||||
|
||||
disable_reg:
|
||||
|
@ -525,7 +525,6 @@ static int ci_otg_start_host(struct otg_fsm *fsm, int on)
|
||||
ci_role_start(ci, CI_ROLE_HOST);
|
||||
} else {
|
||||
ci_role_stop(ci);
|
||||
hw_device_reset(ci);
|
||||
ci_role_start(ci, CI_ROLE_GADGET);
|
||||
}
|
||||
return 0;
|
||||
|
@ -445,7 +445,7 @@ static int _hardware_enqueue(struct ci_hw_ep *hwep, struct ci_hw_req *hwreq)
|
||||
rest -= count;
|
||||
}
|
||||
|
||||
if (hwreq->req.zero && hwreq->req.length
|
||||
if (hwreq->req.zero && hwreq->req.length && hwep->dir == TX
|
||||
&& (hwreq->req.length % hwep->ep.maxpacket == 0))
|
||||
add_td_to_list(hwep, hwreq, 0);
|
||||
|
||||
@ -1090,6 +1090,13 @@ __acquires(ci->lock)
|
||||
if (ci_otg_is_fsm_mode(ci))
|
||||
err = otg_a_alt_hnp_support(ci);
|
||||
break;
|
||||
case USB_DEVICE_A_HNP_SUPPORT:
|
||||
if (ci_otg_is_fsm_mode(ci)) {
|
||||
ci->gadget.a_hnp_support = 1;
|
||||
err = isr_setup_status_phase(
|
||||
ci);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto delegate;
|
||||
}
|
||||
@ -1624,6 +1631,20 @@ static int init_eps(struct ci_hdrc *ci)
|
||||
|
||||
hwep->ep.name = hwep->name;
|
||||
hwep->ep.ops = &usb_ep_ops;
|
||||
|
||||
if (i == 0) {
|
||||
hwep->ep.caps.type_control = true;
|
||||
} else {
|
||||
hwep->ep.caps.type_iso = true;
|
||||
hwep->ep.caps.type_bulk = true;
|
||||
hwep->ep.caps.type_int = true;
|
||||
}
|
||||
|
||||
if (j == TX)
|
||||
hwep->ep.caps.dir_in = true;
|
||||
else
|
||||
hwep->ep.caps.dir_out = true;
|
||||
|
||||
/*
|
||||
* for ep0: maxP defined in desc, for other
|
||||
* eps, maxP is set by epautoconfig() called
|
||||
@ -1827,6 +1848,7 @@ static irqreturn_t udc_irq(struct ci_hdrc *ci)
|
||||
static int udc_start(struct ci_hdrc *ci)
|
||||
{
|
||||
struct device *dev = ci->dev;
|
||||
struct usb_otg_caps *otg_caps = &ci->platdata->ci_otg_caps;
|
||||
int retval = 0;
|
||||
|
||||
spin_lock_init(&ci->lock);
|
||||
@ -1834,8 +1856,12 @@ static int udc_start(struct ci_hdrc *ci)
|
||||
ci->gadget.ops = &usb_gadget_ops;
|
||||
ci->gadget.speed = USB_SPEED_UNKNOWN;
|
||||
ci->gadget.max_speed = USB_SPEED_HIGH;
|
||||
ci->gadget.is_otg = ci->is_otg ? 1 : 0;
|
||||
ci->gadget.name = ci->platdata->name;
|
||||
ci->gadget.otg_caps = otg_caps;
|
||||
|
||||
if (ci->is_otg && (otg_caps->hnp_support || otg_caps->srp_support ||
|
||||
otg_caps->adp_support))
|
||||
ci->gadget.is_otg = 1;
|
||||
|
||||
INIT_LIST_HEAD(&ci->gadget.ep_list);
|
||||
|
||||
|
@ -54,6 +54,7 @@
|
||||
#define MX53_USB_PHYCTRL1_PLLDIV_MASK 0x3
|
||||
#define MX53_USB_PLL_DIV_24_MHZ 0x01
|
||||
|
||||
#define MX6_BM_NON_BURST_SETTING BIT(1)
|
||||
#define MX6_BM_OVER_CUR_DIS BIT(7)
|
||||
#define MX6_BM_WAKEUP_ENABLE BIT(10)
|
||||
#define MX6_BM_ID_WAKEUP BIT(16)
|
||||
@ -255,14 +256,21 @@ static int usbmisc_imx6q_init(struct imx_usbmisc_data *data)
|
||||
if (data->index > 3)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&usbmisc->lock, flags);
|
||||
|
||||
if (data->disable_oc) {
|
||||
spin_lock_irqsave(&usbmisc->lock, flags);
|
||||
reg = readl(usbmisc->base + data->index * 4);
|
||||
writel(reg | MX6_BM_OVER_CUR_DIS,
|
||||
usbmisc->base + data->index * 4);
|
||||
spin_unlock_irqrestore(&usbmisc->lock, flags);
|
||||
}
|
||||
|
||||
/* SoC non-burst setting */
|
||||
reg = readl(usbmisc->base + data->index * 4);
|
||||
writel(reg | MX6_BM_NON_BURST_SETTING,
|
||||
usbmisc->base + data->index * 4);
|
||||
|
||||
spin_unlock_irqrestore(&usbmisc->lock, flags);
|
||||
|
||||
usbmisc_imx6q_set_wakeup(data, false);
|
||||
|
||||
return 0;
|
||||
|
@ -57,6 +57,7 @@
|
||||
#include <linux/mutex.h>
|
||||
#undef DEBUG
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/ratelimit.h>
|
||||
|
||||
/*
|
||||
@ -79,12 +80,20 @@
|
||||
#define IOCNR_SOFT_RESET 7
|
||||
/* Get device_id string: */
|
||||
#define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len)
|
||||
/* The following ioctls were added for http://hpoj.sourceforge.net: */
|
||||
/* Get two-int array:
|
||||
* [0]=current protocol (1=7/1/1, 2=7/1/2, 3=7/1/3),
|
||||
* [1]=supported protocol mask (mask&(1<<n)!=0 means 7/1/n supported): */
|
||||
/* The following ioctls were added for http://hpoj.sourceforge.net:
|
||||
* Get two-int array:
|
||||
* [0]=current protocol
|
||||
* (1=USB_CLASS_PRINTER/1/1, 2=USB_CLASS_PRINTER/1/2,
|
||||
* 3=USB_CLASS_PRINTER/1/3),
|
||||
* [1]=supported protocol mask (mask&(1<<n)!=0 means
|
||||
* USB_CLASS_PRINTER/1/n supported):
|
||||
*/
|
||||
#define LPIOC_GET_PROTOCOLS(len) _IOC(_IOC_READ, 'P', IOCNR_GET_PROTOCOLS, len)
|
||||
/* Set protocol (arg: 1=7/1/1, 2=7/1/2, 3=7/1/3): */
|
||||
/*
|
||||
* Set protocol
|
||||
* (arg: 1=USB_CLASS_PRINTER/1/1, 2=USB_CLASS_PRINTER/1/2,
|
||||
* 3=USB_CLASS_PRINTER/1/3):
|
||||
*/
|
||||
#define LPIOC_SET_PROTOCOL _IOC(_IOC_WRITE, 'P', IOCNR_SET_PROTOCOL, 0)
|
||||
/* Set channel number (HP Vendor-specific command): */
|
||||
#define LPIOC_HP_SET_CHANNEL _IOC(_IOC_WRITE, 'P', IOCNR_HP_SET_CHANNEL, 0)
|
||||
@ -146,8 +155,10 @@ struct usblp {
|
||||
int readcount; /* Counter for reads */
|
||||
int ifnum; /* Interface number */
|
||||
struct usb_interface *intf; /* The interface */
|
||||
/* Alternate-setting numbers and endpoints for each protocol
|
||||
* (7/1/{index=1,2,3}) that the device supports: */
|
||||
/*
|
||||
* Alternate-setting numbers and endpoints for each protocol
|
||||
* (USB_CLASS_PRINTER/1/{index=1,2,3}) that the device supports:
|
||||
*/
|
||||
struct {
|
||||
int alt_setting;
|
||||
struct usb_endpoint_descriptor *epwrite;
|
||||
@ -1206,19 +1217,23 @@ abort_ret:
|
||||
* but our requirements are too intricate for simple match to handle.
|
||||
*
|
||||
* The "proto_bias" option may be used to specify the preferred protocol
|
||||
* for all USB printers (1=7/1/1, 2=7/1/2, 3=7/1/3). If the device
|
||||
* supports the preferred protocol, then we bind to it.
|
||||
* for all USB printers (1=USB_CLASS_PRINTER/1/1, 2=USB_CLASS_PRINTER/1/2,
|
||||
* 3=USB_CLASS_PRINTER/1/3). If the device supports the preferred protocol,
|
||||
* then we bind to it.
|
||||
*
|
||||
* The best interface for us is 7/1/2, because it is compatible
|
||||
* with a stream of characters. If we find it, we bind to it.
|
||||
* The best interface for us is USB_CLASS_PRINTER/1/2, because it
|
||||
* is compatible with a stream of characters. If we find it, we bind to it.
|
||||
*
|
||||
* Note that the people from hpoj.sourceforge.net need to be able to
|
||||
* bind to 7/1/3 (MLC/1284.4), so we provide them ioctls for this purpose.
|
||||
* bind to USB_CLASS_PRINTER/1/3 (MLC/1284.4), so we provide them ioctls
|
||||
* for this purpose.
|
||||
*
|
||||
* Failing 7/1/2, we look for 7/1/3, even though it's probably not
|
||||
* stream-compatible, because this matches the behaviour of the old code.
|
||||
* Failing USB_CLASS_PRINTER/1/2, we look for USB_CLASS_PRINTER/1/3,
|
||||
* even though it's probably not stream-compatible, because this matches
|
||||
* the behaviour of the old code.
|
||||
*
|
||||
* If nothing else, we bind to 7/1/1 - the unidirectional interface.
|
||||
* If nothing else, we bind to USB_CLASS_PRINTER/1/1
|
||||
* - the unidirectional interface.
|
||||
*/
|
||||
static int usblp_select_alts(struct usblp *usblp)
|
||||
{
|
||||
@ -1236,7 +1251,8 @@ static int usblp_select_alts(struct usblp *usblp)
|
||||
for (i = 0; i < if_alt->num_altsetting; i++) {
|
||||
ifd = &if_alt->altsetting[i];
|
||||
|
||||
if (ifd->desc.bInterfaceClass != 7 || ifd->desc.bInterfaceSubClass != 1)
|
||||
if (ifd->desc.bInterfaceClass != USB_CLASS_PRINTER ||
|
||||
ifd->desc.bInterfaceSubClass != 1)
|
||||
if (!(usblp->quirks & USBLP_QUIRK_BAD_CLASS))
|
||||
continue;
|
||||
|
||||
@ -1262,8 +1278,10 @@ static int usblp_select_alts(struct usblp *usblp)
|
||||
if (!epwrite || (ifd->desc.bInterfaceProtocol > 1 && !epread))
|
||||
continue;
|
||||
|
||||
/* Turn off reads for 7/1/1 (unidirectional) interfaces
|
||||
* and buggy bidirectional printers. */
|
||||
/*
|
||||
* Turn off reads for USB_CLASS_PRINTER/1/1 (unidirectional)
|
||||
* interfaces and buggy bidirectional printers.
|
||||
*/
|
||||
if (ifd->desc.bInterfaceProtocol == 1) {
|
||||
epread = NULL;
|
||||
} else if (usblp->quirks & USBLP_QUIRK_BIDIR) {
|
||||
@ -1406,12 +1424,12 @@ static int usblp_resume(struct usb_interface *intf)
|
||||
}
|
||||
|
||||
static const struct usb_device_id usblp_ids[] = {
|
||||
{ USB_DEVICE_INFO(7, 1, 1) },
|
||||
{ USB_DEVICE_INFO(7, 1, 2) },
|
||||
{ USB_DEVICE_INFO(7, 1, 3) },
|
||||
{ USB_INTERFACE_INFO(7, 1, 1) },
|
||||
{ USB_INTERFACE_INFO(7, 1, 2) },
|
||||
{ USB_INTERFACE_INFO(7, 1, 3) },
|
||||
{ USB_DEVICE_INFO(USB_CLASS_PRINTER, 1, 1) },
|
||||
{ USB_DEVICE_INFO(USB_CLASS_PRINTER, 1, 2) },
|
||||
{ USB_DEVICE_INFO(USB_CLASS_PRINTER, 1, 3) },
|
||||
{ USB_INTERFACE_INFO(USB_CLASS_PRINTER, 1, 1) },
|
||||
{ USB_INTERFACE_INFO(USB_CLASS_PRINTER, 1, 2) },
|
||||
{ USB_INTERFACE_INFO(USB_CLASS_PRINTER, 1, 3) },
|
||||
{ USB_DEVICE(0x04b8, 0x0202) }, /* Seiko Epson Receipt Printer M129C */
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
|
@ -154,6 +154,62 @@ bool of_usb_host_tpl_support(struct device_node *np)
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_usb_host_tpl_support);
|
||||
|
||||
/**
|
||||
* of_usb_update_otg_caps - to update usb otg capabilities according to
|
||||
* the passed properties in DT.
|
||||
* @np: Pointer to the given device_node
|
||||
* @otg_caps: Pointer to the target usb_otg_caps to be set
|
||||
*
|
||||
* The function updates the otg capabilities
|
||||
*/
|
||||
int of_usb_update_otg_caps(struct device_node *np,
|
||||
struct usb_otg_caps *otg_caps)
|
||||
{
|
||||
u32 otg_rev;
|
||||
|
||||
if (!otg_caps)
|
||||
return -EINVAL;
|
||||
|
||||
if (!of_property_read_u32(np, "otg-rev", &otg_rev)) {
|
||||
switch (otg_rev) {
|
||||
case 0x0100:
|
||||
case 0x0120:
|
||||
case 0x0130:
|
||||
case 0x0200:
|
||||
/* Choose the lesser one if it's already been set */
|
||||
if (otg_caps->otg_rev)
|
||||
otg_caps->otg_rev = min_t(u16, otg_rev,
|
||||
otg_caps->otg_rev);
|
||||
else
|
||||
otg_caps->otg_rev = otg_rev;
|
||||
break;
|
||||
default:
|
||||
pr_err("%s: unsupported otg-rev: 0x%x\n",
|
||||
np->full_name, otg_rev);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* otg-rev is mandatory for otg properties, if not passed
|
||||
* we set it to be 0 and assume it's a legacy otg device.
|
||||
* Non-dt platform can set it afterwards.
|
||||
*/
|
||||
otg_caps->otg_rev = 0;
|
||||
}
|
||||
|
||||
if (of_find_property(np, "hnp-disable", NULL))
|
||||
otg_caps->hnp_support = false;
|
||||
if (of_find_property(np, "srp-disable", NULL))
|
||||
otg_caps->srp_support = false;
|
||||
if (of_find_property(np, "adp-disable", NULL) ||
|
||||
(otg_caps->otg_rev < 0x0200))
|
||||
otg_caps->adp_support = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_usb_update_otg_caps);
|
||||
|
||||
#endif
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -103,7 +103,7 @@ MODULE_PARM_DESC(usbfs_snoop, "true to log all usbfs traffic");
|
||||
#define snoop(dev, format, arg...) \
|
||||
do { \
|
||||
if (usbfs_snoop) \
|
||||
dev_info(dev , format , ## arg); \
|
||||
dev_info(dev, format, ## arg); \
|
||||
} while (0)
|
||||
|
||||
enum snoop_when {
|
||||
@ -1082,7 +1082,8 @@ static int proc_bulk(struct usb_dev_state *ps, void __user *arg)
|
||||
ret = usbfs_increase_memory_usage(len1 + sizeof(struct urb));
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!(tbuf = kmalloc(len1, GFP_KERNEL))) {
|
||||
tbuf = kmalloc(len1, GFP_KERNEL);
|
||||
if (!tbuf) {
|
||||
ret = -ENOMEM;
|
||||
goto done;
|
||||
}
|
||||
@ -1224,7 +1225,8 @@ static int proc_setintf(struct usb_dev_state *ps, void __user *arg)
|
||||
|
||||
if (copy_from_user(&setintf, arg, sizeof(setintf)))
|
||||
return -EFAULT;
|
||||
if ((ret = checkintf(ps, setintf.interface)))
|
||||
ret = checkintf(ps, setintf.interface);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
destroy_async_on_interface(ps, setintf.interface);
|
||||
@ -1319,7 +1321,7 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
|
||||
is_in = (uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0;
|
||||
|
||||
u = 0;
|
||||
switch(uurb->type) {
|
||||
switch (uurb->type) {
|
||||
case USBDEVFS_URB_TYPE_CONTROL:
|
||||
if (!usb_endpoint_xfer_control(&ep->desc))
|
||||
return -EINVAL;
|
||||
@ -1393,7 +1395,8 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb
|
||||
number_of_packets = uurb->number_of_packets;
|
||||
isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) *
|
||||
number_of_packets;
|
||||
if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))
|
||||
isopkt = kmalloc(isofrmlen, GFP_KERNEL);
|
||||
if (!isopkt)
|
||||
return -ENOMEM;
|
||||
if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) {
|
||||
ret = -EFAULT;
|
||||
@ -1904,7 +1907,8 @@ static int proc_releaseinterface(struct usb_dev_state *ps, void __user *arg)
|
||||
|
||||
if (get_user(ifnum, (unsigned int __user *)arg))
|
||||
return -EFAULT;
|
||||
if ((ret = releaseintf(ps, ifnum)) < 0)
|
||||
ret = releaseintf(ps, ifnum);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
destroy_async_on_interface (ps, ifnum);
|
||||
return 0;
|
||||
@ -1919,7 +1923,8 @@ static int proc_ioctl(struct usb_dev_state *ps, struct usbdevfs_ioctl *ctl)
|
||||
struct usb_driver *driver = NULL;
|
||||
|
||||
/* alloc buffer */
|
||||
if ((size = _IOC_SIZE(ctl->ioctl_code)) > 0) {
|
||||
size = _IOC_SIZE(ctl->ioctl_code);
|
||||
if (size > 0) {
|
||||
buf = kmalloc(size, GFP_KERNEL);
|
||||
if (buf == NULL)
|
||||
return -ENOMEM;
|
||||
|
@ -160,6 +160,7 @@ static ssize_t remove_id_store(struct device_driver *driver, const char *buf,
|
||||
spin_lock(&usb_driver->dynids.lock);
|
||||
list_for_each_entry_safe(dynid, n, &usb_driver->dynids.list, node) {
|
||||
struct usb_device_id *id = &dynid->id;
|
||||
|
||||
if ((id->idVendor == idVendor) &&
|
||||
(id->idProduct == idProduct)) {
|
||||
list_del(&dynid->node);
|
||||
|
@ -51,7 +51,7 @@ static ssize_t wMaxPacketSize_show(struct device *dev,
|
||||
{
|
||||
struct ep_device *ep = to_ep_device(dev);
|
||||
return sprintf(buf, "%04x\n",
|
||||
usb_endpoint_maxp(ep->desc) & 0x07ff);
|
||||
usb_endpoint_maxp(ep->desc) & 0x07ff);
|
||||
}
|
||||
static DEVICE_ATTR_RO(wMaxPacketSize);
|
||||
|
||||
|
@ -2686,12 +2686,14 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
||||
* bottom up so that hcds can customize the root hubs before hub_wq
|
||||
* starts talking to them. (Note, bus id is assigned early too.)
|
||||
*/
|
||||
if ((retval = hcd_buffer_create(hcd)) != 0) {
|
||||
retval = hcd_buffer_create(hcd);
|
||||
if (retval != 0) {
|
||||
dev_dbg(hcd->self.controller, "pool alloc failed\n");
|
||||
goto err_create_buf;
|
||||
}
|
||||
|
||||
if ((retval = usb_register_bus(&hcd->self)) < 0)
|
||||
retval = usb_register_bus(&hcd->self);
|
||||
if (retval < 0)
|
||||
goto err_register_bus;
|
||||
|
||||
rhdev = usb_alloc_dev(NULL, &hcd->self, 0);
|
||||
@ -2737,9 +2739,13 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
||||
/* "reset" is misnamed; its role is now one-time init. the controller
|
||||
* should already have been reset (and boot firmware kicked off etc).
|
||||
*/
|
||||
if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) {
|
||||
dev_err(hcd->self.controller, "can't setup: %d\n", retval);
|
||||
goto err_hcd_driver_setup;
|
||||
if (hcd->driver->reset) {
|
||||
retval = hcd->driver->reset(hcd);
|
||||
if (retval < 0) {
|
||||
dev_err(hcd->self.controller, "can't setup: %d\n",
|
||||
retval);
|
||||
goto err_hcd_driver_setup;
|
||||
}
|
||||
}
|
||||
hcd->rh_pollable = 1;
|
||||
|
||||
@ -2769,7 +2775,8 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
||||
}
|
||||
|
||||
/* starting here, usbcore will pay attention to this root hub */
|
||||
if ((retval = register_root_hub(hcd)) != 0)
|
||||
retval = register_root_hub(hcd);
|
||||
if (retval != 0)
|
||||
goto err_register_root_hub;
|
||||
|
||||
retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group);
|
||||
|
@ -50,8 +50,8 @@ DEFINE_MUTEX(usb_port_peer_mutex);
|
||||
|
||||
/* cycle leds on hubs that aren't blinking for attention */
|
||||
static bool blinkenlights = 0;
|
||||
module_param (blinkenlights, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC (blinkenlights, "true to cycle leds on hubs");
|
||||
module_param(blinkenlights, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(blinkenlights, "true to cycle leds on hubs");
|
||||
|
||||
/*
|
||||
* Device SATA8000 FW1.0 from DATAST0R Technology Corp requires about
|
||||
@ -439,7 +439,7 @@ static void set_port_led(struct usb_hub *hub, int port1, int selector)
|
||||
|
||||
#define LED_CYCLE_PERIOD ((2*HZ)/3)
|
||||
|
||||
static void led_work (struct work_struct *work)
|
||||
static void led_work(struct work_struct *work)
|
||||
{
|
||||
struct usb_hub *hub =
|
||||
container_of(work, struct usb_hub, leds.work);
|
||||
@ -646,7 +646,7 @@ static void hub_irq(struct urb *urb)
|
||||
|
||||
default: /* presumably an error */
|
||||
/* Cause a hub reset after 10 consecutive errors */
|
||||
dev_dbg (hub->intfdev, "transfer --> %d\n", status);
|
||||
dev_dbg(hub->intfdev, "transfer --> %d\n", status);
|
||||
if ((++hub->nerrors < 10) || hub->error)
|
||||
goto resubmit;
|
||||
hub->error = status;
|
||||
@ -671,14 +671,14 @@ resubmit:
|
||||
if (hub->quiescing)
|
||||
return;
|
||||
|
||||
if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0
|
||||
&& status != -ENODEV && status != -EPERM)
|
||||
dev_err (hub->intfdev, "resubmit --> %d\n", status);
|
||||
status = usb_submit_urb(hub->urb, GFP_ATOMIC);
|
||||
if (status != 0 && status != -ENODEV && status != -EPERM)
|
||||
dev_err(hub->intfdev, "resubmit --> %d\n", status);
|
||||
}
|
||||
|
||||
/* USB 2.0 spec Section 11.24.2.3 */
|
||||
static inline int
|
||||
hub_clear_tt_buffer (struct usb_device *hdev, u16 devinfo, u16 tt)
|
||||
hub_clear_tt_buffer(struct usb_device *hdev, u16 devinfo, u16 tt)
|
||||
{
|
||||
/* Need to clear both directions for control ep */
|
||||
if (((devinfo >> 11) & USB_ENDPOINT_XFERTYPE_MASK) ==
|
||||
@ -706,7 +706,7 @@ static void hub_tt_work(struct work_struct *work)
|
||||
container_of(work, struct usb_hub, tt.clear_work);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave (&hub->tt.lock, flags);
|
||||
spin_lock_irqsave(&hub->tt.lock, flags);
|
||||
while (!list_empty(&hub->tt.clear_list)) {
|
||||
struct list_head *next;
|
||||
struct usb_tt_clear *clear;
|
||||
@ -715,14 +715,14 @@ static void hub_tt_work(struct work_struct *work)
|
||||
int status;
|
||||
|
||||
next = hub->tt.clear_list.next;
|
||||
clear = list_entry (next, struct usb_tt_clear, clear_list);
|
||||
list_del (&clear->clear_list);
|
||||
clear = list_entry(next, struct usb_tt_clear, clear_list);
|
||||
list_del(&clear->clear_list);
|
||||
|
||||
/* drop lock so HCD can concurrently report other TT errors */
|
||||
spin_unlock_irqrestore (&hub->tt.lock, flags);
|
||||
status = hub_clear_tt_buffer (hdev, clear->devinfo, clear->tt);
|
||||
spin_unlock_irqrestore(&hub->tt.lock, flags);
|
||||
status = hub_clear_tt_buffer(hdev, clear->devinfo, clear->tt);
|
||||
if (status && status != -ENODEV)
|
||||
dev_err (&hdev->dev,
|
||||
dev_err(&hdev->dev,
|
||||
"clear tt %d (%04x) error %d\n",
|
||||
clear->tt, clear->devinfo, status);
|
||||
|
||||
@ -734,7 +734,7 @@ static void hub_tt_work(struct work_struct *work)
|
||||
kfree(clear);
|
||||
spin_lock_irqsave(&hub->tt.lock, flags);
|
||||
}
|
||||
spin_unlock_irqrestore (&hub->tt.lock, flags);
|
||||
spin_unlock_irqrestore(&hub->tt.lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -797,7 +797,7 @@ int usb_hub_clear_tt_buffer(struct urb *urb)
|
||||
*/
|
||||
clear = kmalloc(sizeof *clear, GFP_ATOMIC);
|
||||
if (clear == NULL) {
|
||||
dev_err (&udev->dev, "can't save CLEAR_TT_BUFFER state\n");
|
||||
dev_err(&udev->dev, "can't save CLEAR_TT_BUFFER state\n");
|
||||
/* FIXME recover somehow ... RESET_TT? */
|
||||
return -ENOMEM;
|
||||
}
|
||||
@ -806,10 +806,10 @@ int usb_hub_clear_tt_buffer(struct urb *urb)
|
||||
clear->tt = tt->multi ? udev->ttport : 1;
|
||||
clear->devinfo = usb_pipeendpoint (pipe);
|
||||
clear->devinfo |= udev->devnum << 4;
|
||||
clear->devinfo |= usb_pipecontrol (pipe)
|
||||
clear->devinfo |= usb_pipecontrol(pipe)
|
||||
? (USB_ENDPOINT_XFER_CONTROL << 11)
|
||||
: (USB_ENDPOINT_XFER_BULK << 11);
|
||||
if (usb_pipein (pipe))
|
||||
if (usb_pipein(pipe))
|
||||
clear->devinfo |= 1 << 15;
|
||||
|
||||
/* info for completion callback */
|
||||
@ -817,10 +817,10 @@ int usb_hub_clear_tt_buffer(struct urb *urb)
|
||||
clear->ep = urb->ep;
|
||||
|
||||
/* tell keventd to clear state for this TT */
|
||||
spin_lock_irqsave (&tt->lock, flags);
|
||||
list_add_tail (&clear->clear_list, &tt->clear_list);
|
||||
spin_lock_irqsave(&tt->lock, flags);
|
||||
list_add_tail(&clear->clear_list, &tt->clear_list);
|
||||
schedule_work(&tt->clear_work);
|
||||
spin_unlock_irqrestore (&tt->lock, flags);
|
||||
spin_unlock_irqrestore(&tt->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_hub_clear_tt_buffer);
|
||||
@ -1442,8 +1442,8 @@ static int hub_configure(struct usb_hub *hub,
|
||||
break;
|
||||
}
|
||||
|
||||
spin_lock_init (&hub->tt.lock);
|
||||
INIT_LIST_HEAD (&hub->tt.clear_list);
|
||||
spin_lock_init(&hub->tt.lock);
|
||||
INIT_LIST_HEAD(&hub->tt.clear_list);
|
||||
INIT_WORK(&hub->tt.clear_work, hub_tt_work);
|
||||
switch (hdev->descriptor.bDeviceProtocol) {
|
||||
case USB_HUB_PR_FS:
|
||||
@ -1632,7 +1632,7 @@ static int hub_configure(struct usb_hub *hub,
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
dev_err (hub_dev, "config failed, %s (err %d)\n",
|
||||
dev_err(hub_dev, "config failed, %s (err %d)\n",
|
||||
message, ret);
|
||||
/* hub_disconnect() frees urb and descriptor */
|
||||
return ret;
|
||||
@ -1775,7 +1775,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
if ((desc->desc.bInterfaceSubClass != 0) &&
|
||||
(desc->desc.bInterfaceSubClass != 1)) {
|
||||
descriptor_error:
|
||||
dev_err (&intf->dev, "bad descriptor, ignoring hub\n");
|
||||
dev_err(&intf->dev, "bad descriptor, ignoring hub\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -1790,11 +1790,11 @@ descriptor_error:
|
||||
goto descriptor_error;
|
||||
|
||||
/* We found a hub */
|
||||
dev_info (&intf->dev, "USB hub found\n");
|
||||
dev_info(&intf->dev, "USB hub found\n");
|
||||
|
||||
hub = kzalloc(sizeof(*hub), GFP_KERNEL);
|
||||
if (!hub) {
|
||||
dev_dbg (&intf->dev, "couldn't kmalloc hub struct\n");
|
||||
dev_dbg(&intf->dev, "couldn't kmalloc hub struct\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@ -1807,7 +1807,7 @@ descriptor_error:
|
||||
usb_get_intf(intf);
|
||||
usb_get_dev(hdev);
|
||||
|
||||
usb_set_intfdata (intf, hub);
|
||||
usb_set_intfdata(intf, hub);
|
||||
intf->needs_remote_wakeup = 1;
|
||||
pm_suspend_ignore_children(&intf->dev, true);
|
||||
|
||||
@ -1820,14 +1820,14 @@ descriptor_error:
|
||||
if (hub_configure(hub, endpoint) >= 0)
|
||||
return 0;
|
||||
|
||||
hub_disconnect (intf);
|
||||
hub_disconnect(intf);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int
|
||||
hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
|
||||
{
|
||||
struct usb_device *hdev = interface_to_usbdev (intf);
|
||||
struct usb_device *hdev = interface_to_usbdev(intf);
|
||||
struct usb_hub *hub = usb_hub_to_struct_hub(hdev);
|
||||
|
||||
/* assert ifno == 0 (part of hub spec) */
|
||||
@ -2143,7 +2143,7 @@ void usb_disconnect(struct usb_device **pdev)
|
||||
* cleaning up all state associated with the current configuration
|
||||
* so that the hardware is now fully quiesced.
|
||||
*/
|
||||
dev_dbg (&udev->dev, "unregistering device\n");
|
||||
dev_dbg(&udev->dev, "unregistering device\n");
|
||||
usb_disable_device(udev, 0);
|
||||
usb_hcd_synchronize_unlinks(udev);
|
||||
|
||||
@ -2242,7 +2242,7 @@ static int usb_enumerate_device_otg(struct usb_device *udev)
|
||||
struct usb_bus *bus = udev->bus;
|
||||
|
||||
/* descriptor may appear anywhere in config */
|
||||
if (__usb_get_extra_descriptor (udev->rawdescriptors[0],
|
||||
if (__usb_get_extra_descriptor(udev->rawdescriptors[0],
|
||||
le16_to_cpu(udev->config[0].desc.wTotalLength),
|
||||
USB_DT_OTG, (void **) &desc) == 0) {
|
||||
if (desc->bmAttributes & USB_OTG_HNP) {
|
||||
@ -3526,7 +3526,7 @@ static int check_ports_changed(struct usb_hub *hub)
|
||||
|
||||
static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
|
||||
{
|
||||
struct usb_hub *hub = usb_get_intfdata (intf);
|
||||
struct usb_hub *hub = usb_get_intfdata(intf);
|
||||
struct usb_device *hdev = hub->hdev;
|
||||
unsigned port1;
|
||||
int status;
|
||||
@ -3950,6 +3950,8 @@ int usb_disable_lpm(struct usb_device *udev)
|
||||
if (usb_disable_link_state(hcd, udev, USB3_LPM_U2))
|
||||
goto enable_lpm;
|
||||
|
||||
udev->usb3_lpm_enabled = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
enable_lpm:
|
||||
@ -4007,6 +4009,8 @@ void usb_enable_lpm(struct usb_device *udev)
|
||||
|
||||
usb_enable_link_state(hcd, udev, USB3_LPM_U1);
|
||||
usb_enable_link_state(hcd, udev, USB3_LPM_U2);
|
||||
|
||||
udev->usb3_lpm_enabled = 1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_enable_lpm);
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
* YOU _SHOULD_ CHANGE THIS LIST TO MATCH YOUR PRODUCT AND ITS TESTING!
|
||||
*/
|
||||
|
||||
static struct usb_device_id whitelist_table [] = {
|
||||
static struct usb_device_id whitelist_table[] = {
|
||||
|
||||
/* hubs are optional in OTG, but very handy ... */
|
||||
{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 0), },
|
||||
|
@ -531,6 +531,25 @@ static ssize_t usb2_lpm_besl_store(struct device *dev,
|
||||
}
|
||||
static DEVICE_ATTR_RW(usb2_lpm_besl);
|
||||
|
||||
static ssize_t usb3_hardware_lpm_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct usb_device *udev = to_usb_device(dev);
|
||||
const char *p;
|
||||
|
||||
usb_lock_device(udev);
|
||||
|
||||
if (udev->usb3_lpm_enabled)
|
||||
p = "enabled";
|
||||
else
|
||||
p = "disabled";
|
||||
|
||||
usb_unlock_device(udev);
|
||||
|
||||
return sprintf(buf, "%s\n", p);
|
||||
}
|
||||
static DEVICE_ATTR_RO(usb3_hardware_lpm);
|
||||
|
||||
static struct attribute *usb2_hardware_lpm_attr[] = {
|
||||
&dev_attr_usb2_hardware_lpm.attr,
|
||||
&dev_attr_usb2_lpm_l1_timeout.attr,
|
||||
@ -542,6 +561,15 @@ static struct attribute_group usb2_hardware_lpm_attr_group = {
|
||||
.attrs = usb2_hardware_lpm_attr,
|
||||
};
|
||||
|
||||
static struct attribute *usb3_hardware_lpm_attr[] = {
|
||||
&dev_attr_usb3_hardware_lpm.attr,
|
||||
NULL,
|
||||
};
|
||||
static struct attribute_group usb3_hardware_lpm_attr_group = {
|
||||
.name = power_group_name,
|
||||
.attrs = usb3_hardware_lpm_attr,
|
||||
};
|
||||
|
||||
static struct attribute *power_attrs[] = {
|
||||
&dev_attr_autosuspend.attr,
|
||||
&dev_attr_level.attr,
|
||||
@ -564,6 +592,9 @@ static int add_power_attributes(struct device *dev)
|
||||
if (udev->usb2_hw_lpm_capable == 1)
|
||||
rc = sysfs_merge_group(&dev->kobj,
|
||||
&usb2_hardware_lpm_attr_group);
|
||||
if (udev->lpm_capable == 1)
|
||||
rc = sysfs_merge_group(&dev->kobj,
|
||||
&usb3_hardware_lpm_attr_group);
|
||||
}
|
||||
|
||||
return rc;
|
||||
|
@ -2880,7 +2880,7 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value)
|
||||
epctl = readl(hs->regs + epreg);
|
||||
|
||||
if (value) {
|
||||
epctl |= DXEPCTL_STALL + DXEPCTL_SNAK;
|
||||
epctl |= DXEPCTL_STALL | DXEPCTL_SNAK;
|
||||
if (epctl & DXEPCTL_EPENA)
|
||||
epctl |= DXEPCTL_EPDIS;
|
||||
} else {
|
||||
@ -3289,6 +3289,19 @@ static void s3c_hsotg_initep(struct dwc2_hsotg *hsotg,
|
||||
usb_ep_set_maxpacket_limit(&hs_ep->ep, epnum ? 1024 : EP0_MPS_LIMIT);
|
||||
hs_ep->ep.ops = &s3c_hsotg_ep_ops;
|
||||
|
||||
if (epnum == 0) {
|
||||
hs_ep->ep.caps.type_control = true;
|
||||
} else {
|
||||
hs_ep->ep.caps.type_iso = true;
|
||||
hs_ep->ep.caps.type_bulk = true;
|
||||
hs_ep->ep.caps.type_int = true;
|
||||
}
|
||||
|
||||
if (dir_in)
|
||||
hs_ep->ep.caps.dir_in = true;
|
||||
else
|
||||
hs_ep->ep.caps.dir_out = true;
|
||||
|
||||
/*
|
||||
* if we're using dma, we need to set the next-endpoint pointer
|
||||
* to be something valid.
|
||||
|
@ -104,11 +104,4 @@ config USB_DWC3_QCOM
|
||||
Recent Qualcomm SoCs ship with one DesignWare Core USB3 IP inside,
|
||||
say 'Y' or 'M' if you have one such device.
|
||||
|
||||
comment "Debugging features"
|
||||
|
||||
config USB_DWC3_DEBUG
|
||||
bool "Enable Debugging Messages"
|
||||
help
|
||||
Say Y here to enable debugging messages on DWC3 Driver.
|
||||
|
||||
endif
|
||||
|
@ -1,8 +1,6 @@
|
||||
# define_trace.h needs to know how to find our header
|
||||
CFLAGS_trace.o := -I$(src)
|
||||
|
||||
ccflags-$(CONFIG_USB_DWC3_DEBUG) := -DDEBUG
|
||||
|
||||
obj-$(CONFIG_USB_DWC3) += dwc3.o
|
||||
|
||||
dwc3-y := core.o debug.o trace.o
|
||||
|
@ -455,8 +455,6 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
|
||||
reg |= DWC3_GUSB2PHYCFG_ULPI_UTMI;
|
||||
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
|
||||
} else {
|
||||
dev_warn(dwc->dev, "HSPHY Interface not defined\n");
|
||||
|
||||
/* Relying on default value. */
|
||||
if (!(reg & DWC3_GUSB2PHYCFG_ULPI_UTMI))
|
||||
break;
|
||||
|
@ -145,7 +145,7 @@ static int dwc3_exynos_probe(struct platform_device *pdev)
|
||||
|
||||
exynos->susp_clk = devm_clk_get(dev, "usbdrd30_susp_clk");
|
||||
if (IS_ERR(exynos->susp_clk)) {
|
||||
dev_dbg(dev, "no suspend clk specified\n");
|
||||
dev_info(dev, "no suspend clk specified\n");
|
||||
exynos->susp_clk = NULL;
|
||||
}
|
||||
clk_prepare_enable(exynos->susp_clk);
|
||||
|
@ -115,7 +115,7 @@ static int kdwc3_probe(struct platform_device *pdev)
|
||||
|
||||
error = clk_prepare_enable(kdwc->clk);
|
||||
if (error < 0) {
|
||||
dev_dbg(kdwc->dev, "unable to enable usb clock, err %d\n",
|
||||
dev_err(kdwc->dev, "unable to enable usb clock, error %d\n",
|
||||
error);
|
||||
return error;
|
||||
}
|
||||
|
@ -128,8 +128,7 @@ struct dwc3_omap {
|
||||
|
||||
u32 dma_status:1;
|
||||
|
||||
struct extcon_specific_cable_nb extcon_vbus_dev;
|
||||
struct extcon_specific_cable_nb extcon_id_dev;
|
||||
struct extcon_dev *edev;
|
||||
struct notifier_block vbus_nb;
|
||||
struct notifier_block id_nb;
|
||||
|
||||
@ -225,12 +224,10 @@ static void dwc3_omap_set_mailbox(struct dwc3_omap *omap,
|
||||
|
||||
switch (status) {
|
||||
case OMAP_DWC3_ID_GROUND:
|
||||
dev_dbg(omap->dev, "ID GND\n");
|
||||
|
||||
if (omap->vbus_reg) {
|
||||
ret = regulator_enable(omap->vbus_reg);
|
||||
if (ret) {
|
||||
dev_dbg(omap->dev, "regulator enable failed\n");
|
||||
dev_err(omap->dev, "regulator enable failed\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -245,8 +242,6 @@ static void dwc3_omap_set_mailbox(struct dwc3_omap *omap,
|
||||
break;
|
||||
|
||||
case OMAP_DWC3_VBUS_VALID:
|
||||
dev_dbg(omap->dev, "VBUS Connect\n");
|
||||
|
||||
val = dwc3_omap_read_utmi_ctrl(omap);
|
||||
val &= ~USBOTGSS_UTMI_OTG_CTRL_SESSEND;
|
||||
val |= USBOTGSS_UTMI_OTG_CTRL_IDDIG
|
||||
@ -261,8 +256,6 @@ static void dwc3_omap_set_mailbox(struct dwc3_omap *omap,
|
||||
regulator_disable(omap->vbus_reg);
|
||||
|
||||
case OMAP_DWC3_VBUS_OFF:
|
||||
dev_dbg(omap->dev, "VBUS Disconnect\n");
|
||||
|
||||
val = dwc3_omap_read_utmi_ctrl(omap);
|
||||
val &= ~(USBOTGSS_UTMI_OTG_CTRL_SESSVALID
|
||||
| USBOTGSS_UTMI_OTG_CTRL_VBUSVALID
|
||||
@ -273,7 +266,7 @@ static void dwc3_omap_set_mailbox(struct dwc3_omap *omap,
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_dbg(omap->dev, "invalid state\n");
|
||||
dev_WARN(omap->dev, "invalid state\n");
|
||||
}
|
||||
}
|
||||
|
||||
@ -284,37 +277,8 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
|
||||
|
||||
reg = dwc3_omap_read_irqmisc_status(omap);
|
||||
|
||||
if (reg & USBOTGSS_IRQMISC_DMADISABLECLR) {
|
||||
dev_dbg(omap->dev, "DMA Disable was Cleared\n");
|
||||
if (reg & USBOTGSS_IRQMISC_DMADISABLECLR)
|
||||
omap->dma_status = false;
|
||||
}
|
||||
|
||||
if (reg & USBOTGSS_IRQMISC_OEVT)
|
||||
dev_dbg(omap->dev, "OTG Event\n");
|
||||
|
||||
if (reg & USBOTGSS_IRQMISC_DRVVBUS_RISE)
|
||||
dev_dbg(omap->dev, "DRVVBUS Rise\n");
|
||||
|
||||
if (reg & USBOTGSS_IRQMISC_CHRGVBUS_RISE)
|
||||
dev_dbg(omap->dev, "CHRGVBUS Rise\n");
|
||||
|
||||
if (reg & USBOTGSS_IRQMISC_DISCHRGVBUS_RISE)
|
||||
dev_dbg(omap->dev, "DISCHRGVBUS Rise\n");
|
||||
|
||||
if (reg & USBOTGSS_IRQMISC_IDPULLUP_RISE)
|
||||
dev_dbg(omap->dev, "IDPULLUP Rise\n");
|
||||
|
||||
if (reg & USBOTGSS_IRQMISC_DRVVBUS_FALL)
|
||||
dev_dbg(omap->dev, "DRVVBUS Fall\n");
|
||||
|
||||
if (reg & USBOTGSS_IRQMISC_CHRGVBUS_FALL)
|
||||
dev_dbg(omap->dev, "CHRGVBUS Fall\n");
|
||||
|
||||
if (reg & USBOTGSS_IRQMISC_DISCHRGVBUS_FALL)
|
||||
dev_dbg(omap->dev, "DISCHRGVBUS Fall\n");
|
||||
|
||||
if (reg & USBOTGSS_IRQMISC_IDPULLUP_FALL)
|
||||
dev_dbg(omap->dev, "IDPULLUP Fall\n");
|
||||
|
||||
dwc3_omap_write_irqmisc_status(omap, reg);
|
||||
|
||||
@ -434,7 +398,7 @@ static void dwc3_omap_set_utmi_mode(struct dwc3_omap *omap)
|
||||
reg &= ~USBOTGSS_UTMI_OTG_CTRL_SW_MODE;
|
||||
break;
|
||||
default:
|
||||
dev_dbg(omap->dev, "UNKNOWN utmi mode %d\n", utmi_mode);
|
||||
dev_WARN(omap->dev, "UNKNOWN utmi mode %d\n", utmi_mode);
|
||||
}
|
||||
|
||||
dwc3_omap_write_utmi_ctrl(omap, reg);
|
||||
@ -454,23 +418,23 @@ static int dwc3_omap_extcon_register(struct dwc3_omap *omap)
|
||||
}
|
||||
|
||||
omap->vbus_nb.notifier_call = dwc3_omap_vbus_notifier;
|
||||
ret = extcon_register_interest(&omap->extcon_vbus_dev,
|
||||
edev->name, "USB",
|
||||
&omap->vbus_nb);
|
||||
ret = extcon_register_notifier(edev, EXTCON_USB,
|
||||
&omap->vbus_nb);
|
||||
if (ret < 0)
|
||||
dev_vdbg(omap->dev, "failed to register notifier for USB\n");
|
||||
|
||||
omap->id_nb.notifier_call = dwc3_omap_id_notifier;
|
||||
ret = extcon_register_interest(&omap->extcon_id_dev,
|
||||
edev->name, "USB-HOST",
|
||||
&omap->id_nb);
|
||||
ret = extcon_register_notifier(edev, EXTCON_USB_HOST,
|
||||
&omap->id_nb);
|
||||
if (ret < 0)
|
||||
dev_vdbg(omap->dev, "failed to register notifier for USB-HOST\n");
|
||||
|
||||
if (extcon_get_cable_state(edev, "USB") == true)
|
||||
if (extcon_get_cable_state_(edev, EXTCON_USB) == true)
|
||||
dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID);
|
||||
if (extcon_get_cable_state(edev, "USB-HOST") == true)
|
||||
if (extcon_get_cable_state_(edev, EXTCON_USB_HOST) == true)
|
||||
dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND);
|
||||
|
||||
omap->edev = edev;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -565,11 +529,8 @@ static int dwc3_omap_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
err3:
|
||||
if (omap->extcon_vbus_dev.edev)
|
||||
extcon_unregister_interest(&omap->extcon_vbus_dev);
|
||||
if (omap->extcon_id_dev.edev)
|
||||
extcon_unregister_interest(&omap->extcon_id_dev);
|
||||
|
||||
extcon_unregister_notifier(omap->edev, EXTCON_USB, &omap->vbus_nb);
|
||||
extcon_unregister_notifier(omap->edev, EXTCON_USB_HOST, &omap->id_nb);
|
||||
err2:
|
||||
dwc3_omap_disable_irqs(omap);
|
||||
|
||||
@ -586,10 +547,8 @@ static int dwc3_omap_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct dwc3_omap *omap = platform_get_drvdata(pdev);
|
||||
|
||||
if (omap->extcon_vbus_dev.edev)
|
||||
extcon_unregister_interest(&omap->extcon_vbus_dev);
|
||||
if (omap->extcon_id_dev.edev)
|
||||
extcon_unregister_interest(&omap->extcon_id_dev);
|
||||
extcon_unregister_notifier(omap->edev, EXTCON_USB, &omap->vbus_nb);
|
||||
extcon_unregister_notifier(omap->edev, EXTCON_USB_HOST, &omap->id_nb);
|
||||
dwc3_omap_disable_irqs(omap);
|
||||
of_platform_depopulate(omap->dev);
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
|
@ -83,17 +83,23 @@ static int dwc3_pci_quirks(struct pci_dev *pdev)
|
||||
acpi_dev_add_driver_gpios(ACPI_COMPANION(&pdev->dev),
|
||||
acpi_dwc3_byt_gpios);
|
||||
|
||||
/* These GPIOs will turn on the USB2 PHY */
|
||||
gpio = gpiod_get(&pdev->dev, "cs");
|
||||
if (!IS_ERR(gpio)) {
|
||||
gpiod_direction_output(gpio, 0);
|
||||
gpiod_set_value_cansleep(gpio, 1);
|
||||
gpiod_put(gpio);
|
||||
}
|
||||
/*
|
||||
* These GPIOs will turn on the USB2 PHY. Note that we have to
|
||||
* put the gpio descriptors again here because the phy driver
|
||||
* might want to grab them, too.
|
||||
*/
|
||||
gpio = gpiod_get_optional(&pdev->dev, "cs", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(gpio))
|
||||
return PTR_ERR(gpio);
|
||||
|
||||
gpio = gpiod_get(&pdev->dev, "reset");
|
||||
if (!IS_ERR(gpio)) {
|
||||
gpiod_direction_output(gpio, 0);
|
||||
gpiod_set_value_cansleep(gpio, 1);
|
||||
gpiod_put(gpio);
|
||||
|
||||
gpio = gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(gpio))
|
||||
return PTR_ERR(gpio);
|
||||
|
||||
if (gpio) {
|
||||
gpiod_set_value_cansleep(gpio, 1);
|
||||
gpiod_put(gpio);
|
||||
usleep_range(10000, 11000);
|
||||
|
@ -48,13 +48,13 @@ static int dwc3_qcom_probe(struct platform_device *pdev)
|
||||
|
||||
qdwc->iface_clk = devm_clk_get(qdwc->dev, "iface");
|
||||
if (IS_ERR(qdwc->iface_clk)) {
|
||||
dev_dbg(qdwc->dev, "failed to get optional iface clock\n");
|
||||
dev_info(qdwc->dev, "failed to get optional iface clock\n");
|
||||
qdwc->iface_clk = NULL;
|
||||
}
|
||||
|
||||
qdwc->sleep_clk = devm_clk_get(qdwc->dev, "sleep");
|
||||
if (IS_ERR(qdwc->sleep_clk)) {
|
||||
dev_dbg(qdwc->dev, "failed to get optional sleep clock\n");
|
||||
dev_info(qdwc->dev, "failed to get optional sleep clock\n");
|
||||
qdwc->sleep_clk = NULL;
|
||||
}
|
||||
|
||||
|
@ -135,8 +135,6 @@ static int st_dwc3_drd_init(struct st_dwc3 *dwc3_data)
|
||||
| USB3_SEL_FORCE_DMPULLDOWN2 | USB3_FORCE_DMPULLDOWN2);
|
||||
|
||||
val |= USB3_DEVICE_NOT_HOST;
|
||||
|
||||
dev_dbg(dwc3_data->dev, "Configuring as Device\n");
|
||||
break;
|
||||
|
||||
case USB_DR_MODE_HOST:
|
||||
@ -154,8 +152,6 @@ static int st_dwc3_drd_init(struct st_dwc3 *dwc3_data)
|
||||
*/
|
||||
|
||||
val |= USB3_DELAY_VBUSVALID;
|
||||
|
||||
dev_dbg(dwc3_data->dev, "Configuring as Host\n");
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -56,7 +56,7 @@ static const char *dwc3_ep0_state_string(enum dwc3_ep0_state state)
|
||||
}
|
||||
|
||||
static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
|
||||
u32 len, u32 type)
|
||||
u32 len, u32 type, bool chain)
|
||||
{
|
||||
struct dwc3_gadget_ep_cmd_params params;
|
||||
struct dwc3_trb *trb;
|
||||
@ -70,7 +70,10 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
|
||||
return 0;
|
||||
}
|
||||
|
||||
trb = dwc->ep0_trb;
|
||||
trb = &dwc->ep0_trb[dep->free_slot];
|
||||
|
||||
if (chain)
|
||||
dep->free_slot++;
|
||||
|
||||
trb->bpl = lower_32_bits(buf_dma);
|
||||
trb->bph = upper_32_bits(buf_dma);
|
||||
@ -78,10 +81,17 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
|
||||
trb->ctrl = type;
|
||||
|
||||
trb->ctrl |= (DWC3_TRB_CTRL_HWO
|
||||
| DWC3_TRB_CTRL_LST
|
||||
| DWC3_TRB_CTRL_IOC
|
||||
| DWC3_TRB_CTRL_ISP_IMI);
|
||||
|
||||
if (chain)
|
||||
trb->ctrl |= DWC3_TRB_CTRL_CHN;
|
||||
else
|
||||
trb->ctrl |= (DWC3_TRB_CTRL_IOC
|
||||
| DWC3_TRB_CTRL_LST);
|
||||
|
||||
if (chain)
|
||||
return 0;
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
params.param0 = upper_32_bits(dwc->ep0_trb_addr);
|
||||
params.param1 = lower_32_bits(dwc->ep0_trb_addr);
|
||||
@ -302,7 +312,7 @@ void dwc3_ep0_out_start(struct dwc3 *dwc)
|
||||
int ret;
|
||||
|
||||
ret = dwc3_ep0_start_trans(dwc, 0, dwc->ctrl_req_addr, 8,
|
||||
DWC3_TRBCTL_CONTROL_SETUP);
|
||||
DWC3_TRBCTL_CONTROL_SETUP, false);
|
||||
WARN_ON(ret < 0);
|
||||
}
|
||||
|
||||
@ -783,7 +793,11 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
|
||||
struct usb_request *ur;
|
||||
struct dwc3_trb *trb;
|
||||
struct dwc3_ep *ep0;
|
||||
u32 transferred;
|
||||
unsigned transfer_size = 0;
|
||||
unsigned maxp;
|
||||
unsigned remaining_ur_length;
|
||||
void *buf;
|
||||
u32 transferred = 0;
|
||||
u32 status;
|
||||
u32 length;
|
||||
u8 epnum;
|
||||
@ -812,17 +826,37 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
|
||||
}
|
||||
|
||||
ur = &r->request;
|
||||
buf = ur->buf;
|
||||
remaining_ur_length = ur->length;
|
||||
|
||||
length = trb->size & DWC3_TRB_SIZE_MASK;
|
||||
|
||||
if (dwc->ep0_bounced) {
|
||||
unsigned transfer_size = ur->length;
|
||||
unsigned maxp = ep0->endpoint.maxpacket;
|
||||
maxp = ep0->endpoint.maxpacket;
|
||||
|
||||
transfer_size += (maxp - (transfer_size % maxp));
|
||||
transferred = min_t(u32, ur->length,
|
||||
transfer_size - length);
|
||||
memcpy(ur->buf, dwc->ep0_bounce, transferred);
|
||||
if (dwc->ep0_bounced) {
|
||||
/*
|
||||
* Handle the first TRB before handling the bounce buffer if
|
||||
* the request length is greater than the bounce buffer size
|
||||
*/
|
||||
if (ur->length > DWC3_EP0_BOUNCE_SIZE) {
|
||||
transfer_size = ALIGN(ur->length - maxp, maxp);
|
||||
transferred = transfer_size - length;
|
||||
buf = (u8 *)buf + transferred;
|
||||
ur->actual += transferred;
|
||||
remaining_ur_length -= transferred;
|
||||
|
||||
trb++;
|
||||
length = trb->size & DWC3_TRB_SIZE_MASK;
|
||||
|
||||
ep0->free_slot = 0;
|
||||
}
|
||||
|
||||
transfer_size = roundup((ur->length - transfer_size),
|
||||
maxp);
|
||||
|
||||
transferred = min_t(u32, remaining_ur_length,
|
||||
transfer_size - length);
|
||||
memcpy(buf, dwc->ep0_bounce, transferred);
|
||||
} else {
|
||||
transferred = ur->length - length;
|
||||
}
|
||||
@ -844,7 +878,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
|
||||
|
||||
ret = dwc3_ep0_start_trans(dwc, epnum,
|
||||
dwc->ctrl_req_addr, 0,
|
||||
DWC3_TRBCTL_CONTROL_DATA);
|
||||
DWC3_TRBCTL_CONTROL_DATA, false);
|
||||
WARN_ON(ret < 0);
|
||||
}
|
||||
}
|
||||
@ -928,10 +962,10 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
||||
if (req->request.length == 0) {
|
||||
ret = dwc3_ep0_start_trans(dwc, dep->number,
|
||||
dwc->ctrl_req_addr, 0,
|
||||
DWC3_TRBCTL_CONTROL_DATA);
|
||||
DWC3_TRBCTL_CONTROL_DATA, false);
|
||||
} else if (!IS_ALIGNED(req->request.length, dep->endpoint.maxpacket)
|
||||
&& (dep->number == 0)) {
|
||||
u32 transfer_size;
|
||||
u32 transfer_size = 0;
|
||||
u32 maxpacket;
|
||||
|
||||
ret = usb_gadget_map_request(&dwc->gadget, &req->request,
|
||||
@ -941,21 +975,26 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
||||
return;
|
||||
}
|
||||
|
||||
WARN_ON(req->request.length > DWC3_EP0_BOUNCE_SIZE);
|
||||
|
||||
maxpacket = dep->endpoint.maxpacket;
|
||||
transfer_size = roundup(req->request.length, maxpacket);
|
||||
|
||||
if (req->request.length > DWC3_EP0_BOUNCE_SIZE) {
|
||||
transfer_size = ALIGN(req->request.length - maxpacket,
|
||||
maxpacket);
|
||||
ret = dwc3_ep0_start_trans(dwc, dep->number,
|
||||
req->request.dma,
|
||||
transfer_size,
|
||||
DWC3_TRBCTL_CONTROL_DATA,
|
||||
true);
|
||||
}
|
||||
|
||||
transfer_size = roundup((req->request.length - transfer_size),
|
||||
maxpacket);
|
||||
|
||||
dwc->ep0_bounced = true;
|
||||
|
||||
/*
|
||||
* REVISIT in case request length is bigger than
|
||||
* DWC3_EP0_BOUNCE_SIZE we will need two chained
|
||||
* TRBs to handle the transfer.
|
||||
*/
|
||||
ret = dwc3_ep0_start_trans(dwc, dep->number,
|
||||
dwc->ep0_bounce_addr, transfer_size,
|
||||
DWC3_TRBCTL_CONTROL_DATA);
|
||||
DWC3_TRBCTL_CONTROL_DATA, false);
|
||||
} else {
|
||||
ret = usb_gadget_map_request(&dwc->gadget, &req->request,
|
||||
dep->number);
|
||||
@ -965,7 +1004,8 @@ static void __dwc3_ep0_do_control_data(struct dwc3 *dwc,
|
||||
}
|
||||
|
||||
ret = dwc3_ep0_start_trans(dwc, dep->number, req->request.dma,
|
||||
req->request.length, DWC3_TRBCTL_CONTROL_DATA);
|
||||
req->request.length, DWC3_TRBCTL_CONTROL_DATA,
|
||||
false);
|
||||
}
|
||||
|
||||
WARN_ON(ret < 0);
|
||||
@ -980,7 +1020,7 @@ static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)
|
||||
: DWC3_TRBCTL_CONTROL_STATUS2;
|
||||
|
||||
return dwc3_ep0_start_trans(dwc, dep->number,
|
||||
dwc->ctrl_req_addr, 0, type);
|
||||
dwc->ctrl_req_addr, 0, type, false);
|
||||
}
|
||||
|
||||
static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep)
|
||||
|
@ -547,6 +547,23 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
|
||||
trb_link->ctrl |= DWC3_TRB_CTRL_HWO;
|
||||
}
|
||||
|
||||
switch (usb_endpoint_type(desc)) {
|
||||
case USB_ENDPOINT_XFER_CONTROL:
|
||||
strlcat(dep->name, "-control", sizeof(dep->name));
|
||||
break;
|
||||
case USB_ENDPOINT_XFER_ISOC:
|
||||
strlcat(dep->name, "-isoc", sizeof(dep->name));
|
||||
break;
|
||||
case USB_ENDPOINT_XFER_BULK:
|
||||
strlcat(dep->name, "-bulk", sizeof(dep->name));
|
||||
break;
|
||||
case USB_ENDPOINT_XFER_INT:
|
||||
strlcat(dep->name, "-int", sizeof(dep->name));
|
||||
break;
|
||||
default:
|
||||
dev_err(dwc->dev, "invalid endpoint transfer type\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -586,6 +603,8 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
|
||||
struct dwc3 *dwc = dep->dwc;
|
||||
u32 reg;
|
||||
|
||||
dwc3_trace(trace_dwc3_gadget, "Disabling %s", dep->name);
|
||||
|
||||
dwc3_remove_requests(dwc, dep);
|
||||
|
||||
/* make sure HW endpoint isn't stalled */
|
||||
@ -602,6 +621,10 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
|
||||
dep->type = 0;
|
||||
dep->flags = 0;
|
||||
|
||||
snprintf(dep->name, sizeof(dep->name), "ep%d%s",
|
||||
dep->number >> 1,
|
||||
(dep->number & 1) ? "in" : "out");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -647,23 +670,6 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep,
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (usb_endpoint_type(desc)) {
|
||||
case USB_ENDPOINT_XFER_CONTROL:
|
||||
strlcat(dep->name, "-control", sizeof(dep->name));
|
||||
break;
|
||||
case USB_ENDPOINT_XFER_ISOC:
|
||||
strlcat(dep->name, "-isoc", sizeof(dep->name));
|
||||
break;
|
||||
case USB_ENDPOINT_XFER_BULK:
|
||||
strlcat(dep->name, "-bulk", sizeof(dep->name));
|
||||
break;
|
||||
case USB_ENDPOINT_XFER_INT:
|
||||
strlcat(dep->name, "-int", sizeof(dep->name));
|
||||
break;
|
||||
default:
|
||||
dev_err(dwc->dev, "invalid endpoint transfer type\n");
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc, false, false);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
@ -692,10 +698,6 @@ static int dwc3_gadget_ep_disable(struct usb_ep *ep)
|
||||
return 0;
|
||||
}
|
||||
|
||||
snprintf(dep->name, sizeof(dep->name), "ep%d%s",
|
||||
dep->number >> 1,
|
||||
(dep->number & 1) ? "in" : "out");
|
||||
|
||||
spin_lock_irqsave(&dwc->lock, flags);
|
||||
ret = __dwc3_gadget_ep_disable(dep);
|
||||
spin_unlock_irqrestore(&dwc->lock, flags);
|
||||
@ -1713,6 +1715,17 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (epnum == 0 || epnum == 1) {
|
||||
dep->endpoint.caps.type_control = true;
|
||||
} else {
|
||||
dep->endpoint.caps.type_iso = true;
|
||||
dep->endpoint.caps.type_bulk = true;
|
||||
dep->endpoint.caps.type_int = true;
|
||||
}
|
||||
|
||||
dep->endpoint.caps.dir_in = !!direction;
|
||||
dep->endpoint.caps.dir_out = !direction;
|
||||
|
||||
INIT_LIST_HEAD(&dep->request_list);
|
||||
INIT_LIST_HEAD(&dep->req_queued);
|
||||
}
|
||||
@ -2685,7 +2698,7 @@ int dwc3_gadget_init(struct dwc3 *dwc)
|
||||
goto err0;
|
||||
}
|
||||
|
||||
dwc->ep0_trb = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
|
||||
dwc->ep0_trb = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ep0_trb) * 2,
|
||||
&dwc->ep0_trb_addr, GFP_KERNEL);
|
||||
if (!dwc->ep0_trb) {
|
||||
dev_err(dwc->dev, "failed to allocate ep0 trb\n");
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <linux/utsname.h>
|
||||
|
||||
#include <linux/usb/composite.h>
|
||||
#include <linux/usb/otg.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "u_os_desc.h"
|
||||
@ -209,6 +210,12 @@ int usb_add_function(struct usb_configuration *config,
|
||||
function->config = config;
|
||||
list_add_tail(&function->list, &config->functions);
|
||||
|
||||
if (function->bind_deactivated) {
|
||||
value = usb_function_deactivate(function);
|
||||
if (value)
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* REVISIT *require* function->bind? */
|
||||
if (function->bind) {
|
||||
value = function->bind(config, function);
|
||||
@ -279,7 +286,7 @@ int usb_function_deactivate(struct usb_function *function)
|
||||
spin_lock_irqsave(&cdev->lock, flags);
|
||||
|
||||
if (cdev->deactivations == 0)
|
||||
status = usb_gadget_disconnect(cdev->gadget);
|
||||
status = usb_gadget_deactivate(cdev->gadget);
|
||||
if (status == 0)
|
||||
cdev->deactivations++;
|
||||
|
||||
@ -311,7 +318,7 @@ int usb_function_activate(struct usb_function *function)
|
||||
else {
|
||||
cdev->deactivations--;
|
||||
if (cdev->deactivations == 0)
|
||||
status = usb_gadget_connect(cdev->gadget);
|
||||
status = usb_gadget_activate(cdev->gadget);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&cdev->lock, flags);
|
||||
@ -896,7 +903,7 @@ void usb_remove_config(struct usb_composite_dev *cdev,
|
||||
|
||||
/* We support strings in multiple languages ... string descriptor zero
|
||||
* says which languages are supported. The typical case will be that
|
||||
* only one language (probably English) is used, with I18N handled on
|
||||
* only one language (probably English) is used, with i18n handled on
|
||||
* the host side.
|
||||
*/
|
||||
|
||||
@ -949,7 +956,7 @@ static int get_string(struct usb_composite_dev *cdev,
|
||||
struct usb_function *f;
|
||||
int len;
|
||||
|
||||
/* Yes, not only is USB's I18N support probably more than most
|
||||
/* Yes, not only is USB's i18n support probably more than most
|
||||
* folk will ever care about ... also, it's all supported here.
|
||||
* (Except for UTF8 support for Unicode's "Astral Planes".)
|
||||
*/
|
||||
@ -1534,6 +1541,32 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
||||
value = min(w_length, (u16) value);
|
||||
}
|
||||
break;
|
||||
case USB_DT_OTG:
|
||||
if (gadget_is_otg(gadget)) {
|
||||
struct usb_configuration *config;
|
||||
int otg_desc_len = 0;
|
||||
|
||||
if (cdev->config)
|
||||
config = cdev->config;
|
||||
else
|
||||
config = list_first_entry(
|
||||
&cdev->configs,
|
||||
struct usb_configuration, list);
|
||||
if (!config)
|
||||
goto done;
|
||||
|
||||
if (gadget->otg_caps &&
|
||||
(gadget->otg_caps->otg_rev >= 0x0200))
|
||||
otg_desc_len += sizeof(
|
||||
struct usb_otg20_descriptor);
|
||||
else
|
||||
otg_desc_len += sizeof(
|
||||
struct usb_otg_descriptor);
|
||||
|
||||
value = min_t(int, w_length, otg_desc_len);
|
||||
memcpy(req->buf, config->descriptors[0], value);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
#include <linux/usb/composite.h>
|
||||
#include <linux/usb/otg.h>
|
||||
|
||||
/**
|
||||
* usb_descriptor_fillbuf - fill buffer with descriptors
|
||||
@ -195,3 +196,58 @@ void usb_free_all_descriptors(struct usb_function *f)
|
||||
usb_free_descriptors(f->ss_descriptors);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_free_all_descriptors);
|
||||
|
||||
struct usb_descriptor_header *usb_otg_descriptor_alloc(
|
||||
struct usb_gadget *gadget)
|
||||
{
|
||||
struct usb_descriptor_header *otg_desc;
|
||||
unsigned length = 0;
|
||||
|
||||
if (gadget->otg_caps && (gadget->otg_caps->otg_rev >= 0x0200))
|
||||
length = sizeof(struct usb_otg20_descriptor);
|
||||
else
|
||||
length = sizeof(struct usb_otg_descriptor);
|
||||
|
||||
otg_desc = kzalloc(length, GFP_KERNEL);
|
||||
return otg_desc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_otg_descriptor_alloc);
|
||||
|
||||
int usb_otg_descriptor_init(struct usb_gadget *gadget,
|
||||
struct usb_descriptor_header *otg_desc)
|
||||
{
|
||||
struct usb_otg_descriptor *otg1x_desc;
|
||||
struct usb_otg20_descriptor *otg20_desc;
|
||||
struct usb_otg_caps *otg_caps = gadget->otg_caps;
|
||||
u8 otg_attributes = 0;
|
||||
|
||||
if (!otg_desc)
|
||||
return -EINVAL;
|
||||
|
||||
if (otg_caps && otg_caps->otg_rev) {
|
||||
if (otg_caps->hnp_support)
|
||||
otg_attributes |= USB_OTG_HNP;
|
||||
if (otg_caps->srp_support)
|
||||
otg_attributes |= USB_OTG_SRP;
|
||||
if (otg_caps->adp_support && (otg_caps->otg_rev >= 0x0200))
|
||||
otg_attributes |= USB_OTG_ADP;
|
||||
} else {
|
||||
otg_attributes = USB_OTG_SRP | USB_OTG_HNP;
|
||||
}
|
||||
|
||||
if (otg_caps && (otg_caps->otg_rev >= 0x0200)) {
|
||||
otg20_desc = (struct usb_otg20_descriptor *)otg_desc;
|
||||
otg20_desc->bLength = sizeof(struct usb_otg20_descriptor);
|
||||
otg20_desc->bDescriptorType = USB_DT_OTG;
|
||||
otg20_desc->bmAttributes = otg_attributes;
|
||||
otg20_desc->bcdOTG = cpu_to_le16(otg_caps->otg_rev);
|
||||
} else {
|
||||
otg1x_desc = (struct usb_otg_descriptor *)otg_desc;
|
||||
otg1x_desc->bLength = sizeof(struct usb_otg_descriptor);
|
||||
otg1x_desc->bDescriptorType = USB_DT_OTG;
|
||||
otg1x_desc->bmAttributes = otg_attributes;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_otg_descriptor_init);
|
||||
|
@ -41,6 +41,8 @@ int check_user_usb_string(const char *name,
|
||||
#define MAX_NAME_LEN 40
|
||||
#define MAX_USB_STRING_LANGS 2
|
||||
|
||||
static const struct usb_descriptor_header *otg_desc[2];
|
||||
|
||||
struct gadget_info {
|
||||
struct config_group group;
|
||||
struct config_group functions_group;
|
||||
@ -55,9 +57,6 @@ struct gadget_info {
|
||||
struct list_head available_func;
|
||||
|
||||
const char *udc_name;
|
||||
#ifdef CONFIG_USB_OTG
|
||||
struct usb_otg_descriptor otg;
|
||||
#endif
|
||||
struct usb_composite_driver composite;
|
||||
struct usb_composite_dev cdev;
|
||||
bool use_os_desc;
|
||||
@ -1376,6 +1375,19 @@ static int configfs_composite_bind(struct usb_gadget *gadget,
|
||||
memcpy(cdev->qw_sign, gi->qw_sign, OS_STRING_QW_SIGN_LEN);
|
||||
}
|
||||
|
||||
if (gadget_is_otg(gadget) && !otg_desc[0]) {
|
||||
struct usb_descriptor_header *usb_desc;
|
||||
|
||||
usb_desc = usb_otg_descriptor_alloc(gadget);
|
||||
if (!usb_desc) {
|
||||
ret = -ENOMEM;
|
||||
goto err_comp_cleanup;
|
||||
}
|
||||
usb_otg_descriptor_init(gadget, usb_desc);
|
||||
otg_desc[0] = usb_desc;
|
||||
otg_desc[1] = NULL;
|
||||
}
|
||||
|
||||
/* Go through all configs, attach all functions */
|
||||
list_for_each_entry(c, &gi->cdev.configs, list) {
|
||||
struct config_usb_cfg *cfg;
|
||||
@ -1383,6 +1395,9 @@ static int configfs_composite_bind(struct usb_gadget *gadget,
|
||||
struct usb_function *tmp;
|
||||
struct gadget_config_name *cn;
|
||||
|
||||
if (gadget_is_otg(gadget))
|
||||
c->descriptors = otg_desc;
|
||||
|
||||
cfg = container_of(c, struct config_usb_cfg, c);
|
||||
if (!list_empty(&cfg->string_list)) {
|
||||
i = 0;
|
||||
@ -1437,6 +1452,8 @@ static void configfs_composite_unbind(struct usb_gadget *gadget)
|
||||
cdev = get_gadget_data(gadget);
|
||||
gi = container_of(cdev, struct gadget_info, cdev);
|
||||
|
||||
kfree(otg_desc[0]);
|
||||
otg_desc[0] = NULL;
|
||||
purge_configs_funcs(gi);
|
||||
composite_dev_cleanup(cdev);
|
||||
usb_ep_autoconfig_reset(cdev->gadget);
|
||||
@ -1510,12 +1527,6 @@ static struct config_group *gadgets_make(
|
||||
if (!gi->composite.gadget_driver.function)
|
||||
goto err;
|
||||
|
||||
#ifdef CONFIG_USB_OTG
|
||||
gi->otg.bLength = sizeof(struct usb_otg_descriptor);
|
||||
gi->otg.bDescriptorType = USB_DT_OTG;
|
||||
gi->otg.bmAttributes = USB_OTG_SRP | USB_OTG_HNP;
|
||||
#endif
|
||||
|
||||
config_group_init_type_name(&gi->group, name,
|
||||
&gadget_root_type);
|
||||
return &gi->group;
|
||||
|
@ -20,186 +20,6 @@
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
|
||||
#include "gadget_chips.h"
|
||||
|
||||
/*
|
||||
* This should work with endpoints from controller drivers sharing the
|
||||
* same endpoint naming convention. By example:
|
||||
*
|
||||
* - ep1, ep2, ... address is fixed, not direction or type
|
||||
* - ep1in, ep2out, ... address and direction are fixed, not type
|
||||
* - ep1-bulk, ep2-bulk, ... address and type are fixed, not direction
|
||||
* - ep1in-bulk, ep2out-iso, ... all three are fixed
|
||||
* - ep-* ... no functionality restrictions
|
||||
*
|
||||
* Type suffixes are "-bulk", "-iso", or "-int". Numbers are decimal.
|
||||
* Less common restrictions are implied by gadget_is_*().
|
||||
*
|
||||
* NOTE: each endpoint is unidirectional, as specified by its USB
|
||||
* descriptor; and isn't specific to a configuration or altsetting.
|
||||
*/
|
||||
static int
|
||||
ep_matches (
|
||||
struct usb_gadget *gadget,
|
||||
struct usb_ep *ep,
|
||||
struct usb_endpoint_descriptor *desc,
|
||||
struct usb_ss_ep_comp_descriptor *ep_comp
|
||||
)
|
||||
{
|
||||
u8 type;
|
||||
const char *tmp;
|
||||
u16 max;
|
||||
|
||||
int num_req_streams = 0;
|
||||
|
||||
/* endpoint already claimed? */
|
||||
if (NULL != ep->driver_data)
|
||||
return 0;
|
||||
|
||||
/* only support ep0 for portable CONTROL traffic */
|
||||
type = usb_endpoint_type(desc);
|
||||
if (USB_ENDPOINT_XFER_CONTROL == type)
|
||||
return 0;
|
||||
|
||||
/* some other naming convention */
|
||||
if ('e' != ep->name[0])
|
||||
return 0;
|
||||
|
||||
/* type-restriction: "-iso", "-bulk", or "-int".
|
||||
* direction-restriction: "in", "out".
|
||||
*/
|
||||
if ('-' != ep->name[2]) {
|
||||
tmp = strrchr (ep->name, '-');
|
||||
if (tmp) {
|
||||
switch (type) {
|
||||
case USB_ENDPOINT_XFER_INT:
|
||||
/* bulk endpoints handle interrupt transfers,
|
||||
* except the toggle-quirky iso-synch kind
|
||||
*/
|
||||
if ('s' == tmp[2]) // == "-iso"
|
||||
return 0;
|
||||
/* for now, avoid PXA "interrupt-in";
|
||||
* it's documented as never using DATA1.
|
||||
*/
|
||||
if (gadget_is_pxa (gadget)
|
||||
&& 'i' == tmp [1])
|
||||
return 0;
|
||||
break;
|
||||
case USB_ENDPOINT_XFER_BULK:
|
||||
if ('b' != tmp[1]) // != "-bulk"
|
||||
return 0;
|
||||
break;
|
||||
case USB_ENDPOINT_XFER_ISOC:
|
||||
if ('s' != tmp[2]) // != "-iso"
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
tmp = ep->name + strlen (ep->name);
|
||||
}
|
||||
|
||||
/* direction-restriction: "..in-..", "out-.." */
|
||||
tmp--;
|
||||
if (!isdigit (*tmp)) {
|
||||
if (desc->bEndpointAddress & USB_DIR_IN) {
|
||||
if ('n' != *tmp)
|
||||
return 0;
|
||||
} else {
|
||||
if ('t' != *tmp)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the number of required streams from the EP companion
|
||||
* descriptor and see if the EP matches it
|
||||
*/
|
||||
if (usb_endpoint_xfer_bulk(desc)) {
|
||||
if (ep_comp && gadget->max_speed >= USB_SPEED_SUPER) {
|
||||
num_req_streams = ep_comp->bmAttributes & 0x1f;
|
||||
if (num_req_streams > ep->max_streams)
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* If the protocol driver hasn't yet decided on wMaxPacketSize
|
||||
* and wants to know the maximum possible, provide the info.
|
||||
*/
|
||||
if (desc->wMaxPacketSize == 0)
|
||||
desc->wMaxPacketSize = cpu_to_le16(ep->maxpacket_limit);
|
||||
|
||||
/* endpoint maxpacket size is an input parameter, except for bulk
|
||||
* where it's an output parameter representing the full speed limit.
|
||||
* the usb spec fixes high speed bulk maxpacket at 512 bytes.
|
||||
*/
|
||||
max = 0x7ff & usb_endpoint_maxp(desc);
|
||||
switch (type) {
|
||||
case USB_ENDPOINT_XFER_INT:
|
||||
/* INT: limit 64 bytes full speed, 1024 high/super speed */
|
||||
if (!gadget_is_dualspeed(gadget) && max > 64)
|
||||
return 0;
|
||||
/* FALLTHROUGH */
|
||||
|
||||
case USB_ENDPOINT_XFER_ISOC:
|
||||
/* ISO: limit 1023 bytes full speed, 1024 high/super speed */
|
||||
if (ep->maxpacket_limit < max)
|
||||
return 0;
|
||||
if (!gadget_is_dualspeed(gadget) && max > 1023)
|
||||
return 0;
|
||||
|
||||
/* BOTH: "high bandwidth" works only at high speed */
|
||||
if ((desc->wMaxPacketSize & cpu_to_le16(3<<11))) {
|
||||
if (!gadget_is_dualspeed(gadget))
|
||||
return 0;
|
||||
/* configure your hardware with enough buffering!! */
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* MATCH!! */
|
||||
|
||||
/* report address */
|
||||
desc->bEndpointAddress &= USB_DIR_IN;
|
||||
if (isdigit (ep->name [2])) {
|
||||
u8 num = simple_strtoul (&ep->name [2], NULL, 10);
|
||||
desc->bEndpointAddress |= num;
|
||||
} else if (desc->bEndpointAddress & USB_DIR_IN) {
|
||||
if (++gadget->in_epnum > 15)
|
||||
return 0;
|
||||
desc->bEndpointAddress = USB_DIR_IN | gadget->in_epnum;
|
||||
} else {
|
||||
if (++gadget->out_epnum > 15)
|
||||
return 0;
|
||||
desc->bEndpointAddress |= gadget->out_epnum;
|
||||
}
|
||||
|
||||
/* report (variable) full speed bulk maxpacket */
|
||||
if ((USB_ENDPOINT_XFER_BULK == type) && !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;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct usb_ep *
|
||||
find_ep (struct usb_gadget *gadget, const char *name)
|
||||
{
|
||||
struct usb_ep *ep;
|
||||
|
||||
list_for_each_entry (ep, &gadget->ep_list, ep_list) {
|
||||
if (0 == strcmp (ep->name, name))
|
||||
return ep;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_ep_autoconfig_ss() - choose an endpoint matching the ep
|
||||
* descriptor and ep companion descriptor
|
||||
@ -240,7 +60,7 @@ find_ep (struct usb_gadget *gadget, const char *name)
|
||||
* updated with the assigned number of streams if it is
|
||||
* different from the original value. To prevent the endpoint
|
||||
* from being returned by a later autoconfig call, claim it by
|
||||
* assigning ep->driver_data to some non-null value.
|
||||
* assigning ep->claimed to true.
|
||||
*
|
||||
* On failure, this returns a null endpoint descriptor.
|
||||
*/
|
||||
@ -255,74 +75,58 @@ struct usb_ep *usb_ep_autoconfig_ss(
|
||||
|
||||
type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
|
||||
|
||||
/* First, apply chip-specific "best usage" knowledge.
|
||||
* This might make a good usb_gadget_ops hook ...
|
||||
*/
|
||||
if (gadget_is_net2280(gadget)) {
|
||||
char name[8];
|
||||
|
||||
if (type == USB_ENDPOINT_XFER_INT) {
|
||||
/* ep-e, ep-f are PIO with only 64 byte fifos */
|
||||
ep = find_ep(gadget, "ep-e");
|
||||
if (ep && ep_matches(gadget, ep, desc, ep_comp))
|
||||
goto found_ep;
|
||||
ep = find_ep(gadget, "ep-f");
|
||||
if (ep && ep_matches(gadget, ep, desc, ep_comp))
|
||||
goto found_ep;
|
||||
}
|
||||
|
||||
/* USB3380: use same address for usb and hardware endpoints */
|
||||
snprintf(name, sizeof(name), "ep%d%s", usb_endpoint_num(desc),
|
||||
usb_endpoint_dir_in(desc) ? "in" : "out");
|
||||
ep = find_ep(gadget, name);
|
||||
if (ep && ep_matches(gadget, ep, desc, ep_comp))
|
||||
if (gadget->ops->match_ep) {
|
||||
ep = gadget->ops->match_ep(gadget, desc, ep_comp);
|
||||
if (ep)
|
||||
goto found_ep;
|
||||
} else if (gadget_is_goku (gadget)) {
|
||||
if (USB_ENDPOINT_XFER_INT == type) {
|
||||
/* single buffering is enough */
|
||||
ep = find_ep(gadget, "ep3-bulk");
|
||||
if (ep && ep_matches(gadget, ep, desc, ep_comp))
|
||||
goto found_ep;
|
||||
} else if (USB_ENDPOINT_XFER_BULK == type
|
||||
&& (USB_DIR_IN & desc->bEndpointAddress)) {
|
||||
/* DMA may be available */
|
||||
ep = find_ep(gadget, "ep2-bulk");
|
||||
if (ep && ep_matches(gadget, ep, desc,
|
||||
ep_comp))
|
||||
goto found_ep;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BLACKFIN
|
||||
} else if (gadget_is_musbhdrc(gadget)) {
|
||||
if ((USB_ENDPOINT_XFER_BULK == type) ||
|
||||
(USB_ENDPOINT_XFER_ISOC == type)) {
|
||||
if (USB_DIR_IN & desc->bEndpointAddress)
|
||||
ep = find_ep (gadget, "ep5in");
|
||||
else
|
||||
ep = find_ep (gadget, "ep6out");
|
||||
} else if (USB_ENDPOINT_XFER_INT == type) {
|
||||
if (USB_DIR_IN & desc->bEndpointAddress)
|
||||
ep = find_ep(gadget, "ep1in");
|
||||
else
|
||||
ep = find_ep(gadget, "ep2out");
|
||||
} else
|
||||
ep = NULL;
|
||||
if (ep && ep_matches(gadget, ep, desc, ep_comp))
|
||||
goto found_ep;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Second, look at endpoints until an unclaimed one looks usable */
|
||||
list_for_each_entry (ep, &gadget->ep_list, ep_list) {
|
||||
if (ep_matches(gadget, ep, desc, ep_comp))
|
||||
if (usb_gadget_ep_match_desc(gadget, ep, desc, ep_comp))
|
||||
goto found_ep;
|
||||
}
|
||||
|
||||
/* Fail */
|
||||
return NULL;
|
||||
found_ep:
|
||||
|
||||
/*
|
||||
* If the protocol driver hasn't yet decided on wMaxPacketSize
|
||||
* and wants to know the maximum possible, provide the info.
|
||||
*/
|
||||
if (desc->wMaxPacketSize == 0)
|
||||
desc->wMaxPacketSize = cpu_to_le16(ep->maxpacket_limit);
|
||||
|
||||
/* report address */
|
||||
desc->bEndpointAddress &= USB_DIR_IN;
|
||||
if (isdigit(ep->name[2])) {
|
||||
u8 num = simple_strtoul(&ep->name[2], NULL, 10);
|
||||
desc->bEndpointAddress |= num;
|
||||
} else if (desc->bEndpointAddress & USB_DIR_IN) {
|
||||
if (++gadget->in_epnum > 15)
|
||||
return NULL;
|
||||
desc->bEndpointAddress = USB_DIR_IN | gadget->in_epnum;
|
||||
} else {
|
||||
if (++gadget->out_epnum > 15)
|
||||
return NULL;
|
||||
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;
|
||||
ep->claimed = true;
|
||||
return ep;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_ep_autoconfig_ss);
|
||||
@ -354,7 +158,7 @@ EXPORT_SYMBOL_GPL(usb_ep_autoconfig_ss);
|
||||
* 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, claim it
|
||||
* by assigning ep->driver_data to some non-null value.
|
||||
* by assigning ep->claimed to true.
|
||||
*
|
||||
* On failure, this returns a null endpoint descriptor.
|
||||
*/
|
||||
@ -373,7 +177,7 @@ EXPORT_SYMBOL_GPL(usb_ep_autoconfig);
|
||||
*
|
||||
* Use this for devices where one configuration may need to assign
|
||||
* endpoint resources very differently from the next one. It clears
|
||||
* state such as ep->driver_data and the record of assigned endpoints
|
||||
* state such as ep->claimed and the record of assigned endpoints
|
||||
* used by usb_ep_autoconfig().
|
||||
*/
|
||||
void usb_ep_autoconfig_reset (struct usb_gadget *gadget)
|
||||
@ -381,7 +185,7 @@ void usb_ep_autoconfig_reset (struct usb_gadget *gadget)
|
||||
struct usb_ep *ep;
|
||||
|
||||
list_for_each_entry (ep, &gadget->ep_list, ep_list) {
|
||||
ep->driver_data = NULL;
|
||||
ep->claimed = false;
|
||||
}
|
||||
gadget->in_epnum = 0;
|
||||
gadget->out_epnum = 0;
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include <linux/err.h>
|
||||
|
||||
#include "u_serial.h"
|
||||
#include "gadget_chips.h"
|
||||
|
||||
|
||||
/*
|
||||
|
@ -585,8 +585,8 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
||||
/* Enable zlps by default for ECM conformance;
|
||||
* override for musb_hdrc (avoids txdma ovhead).
|
||||
*/
|
||||
ecm->port.is_zlp_ok = !(gadget_is_musbhdrc(cdev->gadget)
|
||||
);
|
||||
ecm->port.is_zlp_ok =
|
||||
gadget_is_zlp_supported(cdev->gadget);
|
||||
ecm->port.cdc_filter = DEFAULT_FILTER;
|
||||
DBG(cdev, "activate ecm\n");
|
||||
net = gether_connect(&ecm->port);
|
||||
|
@ -2897,11 +2897,17 @@ static int ffs_func_bind(struct usb_configuration *c,
|
||||
struct usb_function *f)
|
||||
{
|
||||
struct f_fs_opts *ffs_opts = ffs_do_functionfs_bind(f, c);
|
||||
struct ffs_function *func = ffs_func_from_usb(f);
|
||||
int ret;
|
||||
|
||||
if (IS_ERR(ffs_opts))
|
||||
return PTR_ERR(ffs_opts);
|
||||
|
||||
return _ffs_func_bind(c, f);
|
||||
ret = _ffs_func_bind(c, f);
|
||||
if (ret && !--ffs_opts->refcnt)
|
||||
functionfs_unbind(func->ffs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
@ -28,11 +28,6 @@
|
||||
* This takes messages of various sizes written OUT to a device, and loops
|
||||
* them back so they can be read IN from it. It has been used by certain
|
||||
* test applications. It supports limited testing of data queueing logic.
|
||||
*
|
||||
*
|
||||
* This is currently packaged as a configuration driver, which can't be
|
||||
* combined with other functions to make composite devices. However, it
|
||||
* can be combined with other independent configurations.
|
||||
*/
|
||||
struct f_loopback {
|
||||
struct usb_function function;
|
||||
|
@ -54,7 +54,7 @@
|
||||
* following fields:
|
||||
*
|
||||
* nluns Number of LUNs function have (anywhere from 1
|
||||
* to FSG_MAX_LUNS which is 8).
|
||||
* to FSG_MAX_LUNS).
|
||||
* luns An array of LUN configuration values. This
|
||||
* should be filled for each LUN that
|
||||
* function will include (ie. for "nluns"
|
||||
@ -214,12 +214,12 @@
|
||||
#include <linux/string.h>
|
||||
#include <linux/freezer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <linux/usb/ch9.h>
|
||||
#include <linux/usb/gadget.h>
|
||||
#include <linux/usb/composite.h>
|
||||
|
||||
#include "gadget_chips.h"
|
||||
#include "configfs.h"
|
||||
|
||||
|
||||
@ -279,9 +279,8 @@ struct fsg_common {
|
||||
int cmnd_size;
|
||||
u8 cmnd[MAX_COMMAND_SIZE];
|
||||
|
||||
unsigned int nluns;
|
||||
unsigned int lun;
|
||||
struct fsg_lun **luns;
|
||||
struct fsg_lun *luns[FSG_MAX_LUNS];
|
||||
struct fsg_lun *curlun;
|
||||
|
||||
unsigned int bulk_out_maxpacket;
|
||||
@ -490,6 +489,16 @@ static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
|
||||
spin_unlock(&common->lock);
|
||||
}
|
||||
|
||||
static int _fsg_common_get_max_lun(struct fsg_common *common)
|
||||
{
|
||||
int i = ARRAY_SIZE(common->luns) - 1;
|
||||
|
||||
while (i >= 0 && !common->luns[i])
|
||||
--i;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static int fsg_setup(struct usb_function *f,
|
||||
const struct usb_ctrlrequest *ctrl)
|
||||
{
|
||||
@ -533,7 +542,7 @@ static int fsg_setup(struct usb_function *f,
|
||||
w_length != 1)
|
||||
return -EDOM;
|
||||
VDBG(fsg, "get max LUN\n");
|
||||
*(u8 *)req->buf = fsg->common->nluns - 1;
|
||||
*(u8 *)req->buf = _fsg_common_get_max_lun(fsg->common);
|
||||
|
||||
/* Respond with data/status */
|
||||
req->length = min((u16)1, w_length);
|
||||
@ -2131,8 +2140,9 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
|
||||
}
|
||||
|
||||
/* Is the CBW meaningful? */
|
||||
if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~US_BULK_FLAG_IN ||
|
||||
cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) {
|
||||
if (cbw->Lun >= ARRAY_SIZE(common->luns) ||
|
||||
cbw->Flags & ~US_BULK_FLAG_IN || cbw->Length <= 0 ||
|
||||
cbw->Length > MAX_COMMAND_SIZE) {
|
||||
DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
|
||||
"cmdlen %u\n",
|
||||
cbw->Lun, cbw->Flags, cbw->Length);
|
||||
@ -2159,7 +2169,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
|
||||
if (common->data_size == 0)
|
||||
common->data_dir = DATA_DIR_NONE;
|
||||
common->lun = cbw->Lun;
|
||||
if (common->lun < common->nluns)
|
||||
if (common->lun < ARRAY_SIZE(common->luns))
|
||||
common->curlun = common->luns[common->lun];
|
||||
else
|
||||
common->curlun = NULL;
|
||||
@ -2307,7 +2317,7 @@ reset:
|
||||
}
|
||||
|
||||
common->running = 1;
|
||||
for (i = 0; i < common->nluns; ++i)
|
||||
for (i = 0; i < ARRAY_SIZE(common->luns); ++i)
|
||||
if (common->luns[i])
|
||||
common->luns[i]->unit_attention_data =
|
||||
SS_RESET_OCCURRED;
|
||||
@ -2409,7 +2419,7 @@ static void handle_exception(struct fsg_common *common)
|
||||
if (old_state == FSG_STATE_ABORT_BULK_OUT)
|
||||
common->state = FSG_STATE_STATUS_PHASE;
|
||||
else {
|
||||
for (i = 0; i < common->nluns; ++i) {
|
||||
for (i = 0; i < ARRAY_SIZE(common->luns); ++i) {
|
||||
curlun = common->luns[i];
|
||||
if (!curlun)
|
||||
continue;
|
||||
@ -2453,7 +2463,7 @@ static void handle_exception(struct fsg_common *common)
|
||||
* a waste of time. Ditto for the INTERFACE_CHANGE and
|
||||
* CONFIG_CHANGE cases.
|
||||
*/
|
||||
/* for (i = 0; i < common->nluns; ++i) */
|
||||
/* for (i = 0; i < common->ARRAY_SIZE(common->luns); ++i) */
|
||||
/* if (common->luns[i]) */
|
||||
/* common->luns[i]->unit_attention_data = */
|
||||
/* SS_RESET_OCCURRED; */
|
||||
@ -2552,12 +2562,11 @@ static int fsg_main_thread(void *common_)
|
||||
|
||||
if (!common->ops || !common->ops->thread_exits
|
||||
|| common->ops->thread_exits(common) < 0) {
|
||||
struct fsg_lun **curlun_it = common->luns;
|
||||
unsigned i = common->nluns;
|
||||
int i;
|
||||
|
||||
down_write(&common->filesem);
|
||||
for (; i--; ++curlun_it) {
|
||||
struct fsg_lun *curlun = *curlun_it;
|
||||
for (i = 0; i < ARRAY_SIZE(common->luns); --i) {
|
||||
struct fsg_lun *curlun = common->luns[i];
|
||||
if (!curlun || !fsg_lun_is_open(curlun))
|
||||
continue;
|
||||
|
||||
@ -2676,6 +2685,7 @@ static struct fsg_common *fsg_common_setup(struct fsg_common *common)
|
||||
init_completion(&common->thread_notifier);
|
||||
init_waitqueue_head(&common->fsg_wait);
|
||||
common->state = FSG_STATE_TERMINATED;
|
||||
memset(common->luns, 0, sizeof(common->luns));
|
||||
|
||||
return common;
|
||||
}
|
||||
@ -2742,9 +2752,9 @@ error_release:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fsg_common_set_num_buffers);
|
||||
|
||||
void fsg_common_remove_lun(struct fsg_lun *lun, bool sysfs)
|
||||
void fsg_common_remove_lun(struct fsg_lun *lun)
|
||||
{
|
||||
if (sysfs)
|
||||
if (device_is_registered(&lun->dev))
|
||||
device_unregister(&lun->dev);
|
||||
fsg_lun_close(lun);
|
||||
kfree(lun);
|
||||
@ -2757,48 +2767,16 @@ static void _fsg_common_remove_luns(struct fsg_common *common, int n)
|
||||
|
||||
for (i = 0; i < n; ++i)
|
||||
if (common->luns[i]) {
|
||||
fsg_common_remove_lun(common->luns[i], common->sysfs);
|
||||
fsg_common_remove_lun(common->luns[i]);
|
||||
common->luns[i] = NULL;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fsg_common_remove_luns);
|
||||
|
||||
void fsg_common_remove_luns(struct fsg_common *common)
|
||||
{
|
||||
_fsg_common_remove_luns(common, common->nluns);
|
||||
_fsg_common_remove_luns(common, ARRAY_SIZE(common->luns));
|
||||
}
|
||||
|
||||
void fsg_common_free_luns(struct fsg_common *common)
|
||||
{
|
||||
fsg_common_remove_luns(common);
|
||||
kfree(common->luns);
|
||||
common->luns = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fsg_common_free_luns);
|
||||
|
||||
int fsg_common_set_nluns(struct fsg_common *common, int nluns)
|
||||
{
|
||||
struct fsg_lun **curlun;
|
||||
|
||||
/* Find out how many LUNs there should be */
|
||||
if (nluns < 1 || nluns > FSG_MAX_LUNS) {
|
||||
pr_err("invalid number of LUNs: %u\n", nluns);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
curlun = kcalloc(FSG_MAX_LUNS, sizeof(*curlun), GFP_KERNEL);
|
||||
if (unlikely(!curlun))
|
||||
return -ENOMEM;
|
||||
|
||||
if (common->luns)
|
||||
fsg_common_free_luns(common);
|
||||
|
||||
common->luns = curlun;
|
||||
common->nluns = nluns;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fsg_common_set_nluns);
|
||||
EXPORT_SYMBOL_GPL(fsg_common_remove_luns);
|
||||
|
||||
void fsg_common_set_ops(struct fsg_common *common,
|
||||
const struct fsg_operations *ops)
|
||||
@ -2836,7 +2814,8 @@ int fsg_common_set_cdev(struct fsg_common *common,
|
||||
* halt bulk endpoints correctly. If one of them is present,
|
||||
* disable stalls.
|
||||
*/
|
||||
common->can_stall = can_stall && !(gadget_is_at91(common->gadget));
|
||||
common->can_stall = can_stall &&
|
||||
gadget_is_stall_supported(common->gadget);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -2880,7 +2859,7 @@ int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg,
|
||||
char *pathbuf, *p;
|
||||
int rc = -ENOMEM;
|
||||
|
||||
if (!common->nluns || !common->luns)
|
||||
if (id >= ARRAY_SIZE(common->luns))
|
||||
return -ENODEV;
|
||||
|
||||
if (common->luns[id])
|
||||
@ -2949,7 +2928,7 @@ int fsg_common_create_lun(struct fsg_common *common, struct fsg_lun_config *cfg,
|
||||
return 0;
|
||||
|
||||
error_lun:
|
||||
if (common->sysfs)
|
||||
if (device_is_registered(&lun->dev))
|
||||
device_unregister(&lun->dev);
|
||||
fsg_lun_close(lun);
|
||||
common->luns[id] = NULL;
|
||||
@ -2964,14 +2943,16 @@ int fsg_common_create_luns(struct fsg_common *common, struct fsg_config *cfg)
|
||||
char buf[8]; /* enough for 100000000 different numbers, decimal */
|
||||
int i, rc;
|
||||
|
||||
for (i = 0; i < common->nluns; ++i) {
|
||||
fsg_common_remove_luns(common);
|
||||
|
||||
for (i = 0; i < cfg->nluns; ++i) {
|
||||
snprintf(buf, sizeof(buf), "lun%d", i);
|
||||
rc = fsg_common_create_lun(common, &cfg->luns[i], i, buf, NULL);
|
||||
if (rc)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pr_info("Number of LUNs=%d\n", common->nluns);
|
||||
pr_info("Number of LUNs=%d\n", cfg->nluns);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -3020,6 +3001,7 @@ EXPORT_SYMBOL_GPL(fsg_common_run_thread);
|
||||
static void fsg_common_release(struct kref *ref)
|
||||
{
|
||||
struct fsg_common *common = container_of(ref, struct fsg_common, ref);
|
||||
int i;
|
||||
|
||||
/* If the thread isn't already dead, tell it to exit now */
|
||||
if (common->state != FSG_STATE_TERMINATED) {
|
||||
@ -3027,22 +3009,14 @@ static void fsg_common_release(struct kref *ref)
|
||||
wait_for_completion(&common->thread_notifier);
|
||||
}
|
||||
|
||||
if (likely(common->luns)) {
|
||||
struct fsg_lun **lun_it = common->luns;
|
||||
unsigned i = common->nluns;
|
||||
|
||||
/* In error recovery common->nluns may be zero. */
|
||||
for (; i; --i, ++lun_it) {
|
||||
struct fsg_lun *lun = *lun_it;
|
||||
if (!lun)
|
||||
continue;
|
||||
fsg_lun_close(lun);
|
||||
if (common->sysfs)
|
||||
device_unregister(&lun->dev);
|
||||
kfree(lun);
|
||||
}
|
||||
|
||||
kfree(common->luns);
|
||||
for (i = 0; i < ARRAY_SIZE(common->luns); ++i) {
|
||||
struct fsg_lun *lun = common->luns[i];
|
||||
if (!lun)
|
||||
continue;
|
||||
fsg_lun_close(lun);
|
||||
if (device_is_registered(&lun->dev))
|
||||
device_unregister(&lun->dev);
|
||||
kfree(lun);
|
||||
}
|
||||
|
||||
_fsg_common_free_buffers(common->buffhds, common->fsg_num_buffers);
|
||||
@ -3056,6 +3030,7 @@ static void fsg_common_release(struct kref *ref)
|
||||
static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
{
|
||||
struct fsg_dev *fsg = fsg_from_func(f);
|
||||
struct fsg_common *common = fsg->common;
|
||||
struct usb_gadget *gadget = c->cdev->gadget;
|
||||
int i;
|
||||
struct usb_ep *ep;
|
||||
@ -3063,6 +3038,13 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
int ret;
|
||||
struct fsg_opts *opts;
|
||||
|
||||
/* Don't allow to bind if we don't have at least one LUN */
|
||||
ret = _fsg_common_get_max_lun(common);
|
||||
if (ret < 0) {
|
||||
pr_err("There should be at least one LUN.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
opts = fsg_opts_from_func_inst(f->fi);
|
||||
if (!opts->no_configfs) {
|
||||
ret = fsg_common_set_cdev(fsg->common, c->cdev,
|
||||
@ -3080,7 +3062,7 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
/* New interface */
|
||||
i = usb_interface_id(c, f);
|
||||
if (i < 0)
|
||||
return i;
|
||||
goto fail;
|
||||
fsg_intf_desc.bInterfaceNumber = i;
|
||||
fsg->interface_number = i;
|
||||
|
||||
@ -3123,7 +3105,14 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
|
||||
autoconf_fail:
|
||||
ERROR(fsg, "unable to autoconfigure all endpoints\n");
|
||||
return -ENOTSUPP;
|
||||
i = -ENOTSUPP;
|
||||
fail:
|
||||
/* terminate the thread */
|
||||
if (fsg->common->state != FSG_STATE_TERMINATED) {
|
||||
raise_exception(fsg->common, FSG_STATE_EXIT);
|
||||
wait_for_completion(&fsg->common->thread_notifier);
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/****************************** ALLOCATE FUNCTION *************************/
|
||||
@ -3355,7 +3344,7 @@ static void fsg_lun_drop(struct config_group *group, struct config_item *item)
|
||||
unregister_gadget_item(gadget);
|
||||
}
|
||||
|
||||
fsg_common_remove_lun(lun_opts->lun, fsg_opts->common->sysfs);
|
||||
fsg_common_remove_lun(lun_opts->lun);
|
||||
fsg_opts->common->luns[lun_opts->lun_id] = NULL;
|
||||
lun_opts->lun_id = 0;
|
||||
mutex_unlock(&fsg_opts->lock);
|
||||
@ -3509,14 +3498,11 @@ static struct usb_function_instance *fsg_alloc_inst(void)
|
||||
rc = PTR_ERR(opts->common);
|
||||
goto release_opts;
|
||||
}
|
||||
rc = fsg_common_set_nluns(opts->common, FSG_MAX_LUNS);
|
||||
if (rc)
|
||||
goto release_opts;
|
||||
|
||||
rc = fsg_common_set_num_buffers(opts->common,
|
||||
CONFIG_USB_GADGET_STORAGE_NUM_BUFFERS);
|
||||
if (rc)
|
||||
goto release_luns;
|
||||
goto release_opts;
|
||||
|
||||
pr_info(FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n");
|
||||
|
||||
@ -3524,6 +3510,9 @@ static struct usb_function_instance *fsg_alloc_inst(void)
|
||||
config.removable = true;
|
||||
rc = fsg_common_create_lun(opts->common, &config, 0, "lun.0",
|
||||
(const char **)&opts->func_inst.group.cg_item.ci_name);
|
||||
if (rc)
|
||||
goto release_buffers;
|
||||
|
||||
opts->lun0.lun = opts->common->luns[0];
|
||||
opts->lun0.lun_id = 0;
|
||||
config_group_init_type_name(&opts->lun0.group, "lun.0", &fsg_lun_type);
|
||||
@ -3534,8 +3523,8 @@ static struct usb_function_instance *fsg_alloc_inst(void)
|
||||
|
||||
return &opts->func_inst;
|
||||
|
||||
release_luns:
|
||||
kfree(opts->common->luns);
|
||||
release_buffers:
|
||||
fsg_common_free_buffers(opts->common);
|
||||
release_opts:
|
||||
kfree(opts);
|
||||
return ERR_PTR(rc);
|
||||
@ -3561,23 +3550,12 @@ static struct usb_function *fsg_alloc(struct usb_function_instance *fi)
|
||||
struct fsg_opts *opts = fsg_opts_from_func_inst(fi);
|
||||
struct fsg_common *common = opts->common;
|
||||
struct fsg_dev *fsg;
|
||||
unsigned nluns, i;
|
||||
|
||||
fsg = kzalloc(sizeof(*fsg), GFP_KERNEL);
|
||||
if (unlikely(!fsg))
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
mutex_lock(&opts->lock);
|
||||
if (!opts->refcnt) {
|
||||
for (nluns = i = 0; i < FSG_MAX_LUNS; ++i)
|
||||
if (common->luns[i])
|
||||
nluns = i + 1;
|
||||
if (!nluns)
|
||||
pr_warn("No LUNS defined, continuing anyway\n");
|
||||
else
|
||||
common->nluns = nluns;
|
||||
pr_info("Number of LUNs=%u\n", common->nluns);
|
||||
}
|
||||
opts->refcnt++;
|
||||
mutex_unlock(&opts->lock);
|
||||
|
||||
|
@ -137,14 +137,10 @@ void fsg_common_free_buffers(struct fsg_common *common);
|
||||
int fsg_common_set_cdev(struct fsg_common *common,
|
||||
struct usb_composite_dev *cdev, bool can_stall);
|
||||
|
||||
void fsg_common_remove_lun(struct fsg_lun *lun, bool sysfs);
|
||||
void fsg_common_remove_lun(struct fsg_lun *lun);
|
||||
|
||||
void fsg_common_remove_luns(struct fsg_common *common);
|
||||
|
||||
void fsg_common_free_luns(struct fsg_common *common);
|
||||
|
||||
int fsg_common_set_nluns(struct fsg_common *common, int nluns);
|
||||
|
||||
void fsg_common_set_ops(struct fsg_common *common,
|
||||
const struct fsg_operations *ops);
|
||||
|
||||
|
@ -329,6 +329,10 @@ static int f_midi_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
||||
unsigned i;
|
||||
int err;
|
||||
|
||||
/* For Control Device interface we do nothing */
|
||||
if (intf == 0)
|
||||
return 0;
|
||||
|
||||
err = f_midi_start_ep(midi, f, midi->in_ep);
|
||||
if (err)
|
||||
return err;
|
||||
|
@ -853,9 +853,8 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
||||
/* Enable zlps by default for NCM conformance;
|
||||
* override for musb_hdrc (avoids txdma ovhead)
|
||||
*/
|
||||
ncm->port.is_zlp_ok = !(
|
||||
gadget_is_musbhdrc(cdev->gadget)
|
||||
);
|
||||
ncm->port.is_zlp_ok =
|
||||
gadget_is_zlp_supported(cdev->gadget);
|
||||
ncm->port.cdc_filter = DEFAULT_FILTER;
|
||||
DBG(cdev, "activate ncm\n");
|
||||
net = gether_connect(&ncm->port);
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "u_serial.h"
|
||||
#include "gadget_chips.h"
|
||||
|
||||
|
||||
/*
|
||||
@ -37,7 +36,6 @@ struct f_obex {
|
||||
u8 data_id;
|
||||
u8 cur_alt;
|
||||
u8 port_num;
|
||||
u8 can_activate;
|
||||
};
|
||||
|
||||
static inline struct f_obex *func_to_obex(struct usb_function *f)
|
||||
@ -268,9 +266,6 @@ static void obex_connect(struct gserial *g)
|
||||
struct usb_composite_dev *cdev = g->func.config->cdev;
|
||||
int status;
|
||||
|
||||
if (!obex->can_activate)
|
||||
return;
|
||||
|
||||
status = usb_function_activate(&g->func);
|
||||
if (status)
|
||||
dev_dbg(&cdev->gadget->dev,
|
||||
@ -284,9 +279,6 @@ static void obex_disconnect(struct gserial *g)
|
||||
struct usb_composite_dev *cdev = g->func.config->cdev;
|
||||
int status;
|
||||
|
||||
if (!obex->can_activate)
|
||||
return;
|
||||
|
||||
status = usb_function_deactivate(&g->func);
|
||||
if (status)
|
||||
dev_dbg(&cdev->gadget->dev,
|
||||
@ -304,7 +296,7 @@ static inline bool can_support_obex(struct usb_configuration *c)
|
||||
*
|
||||
* Altsettings are mandatory, however...
|
||||
*/
|
||||
if (!gadget_supports_altsettings(c->cdev->gadget))
|
||||
if (!gadget_is_altset_supported(c->cdev->gadget))
|
||||
return false;
|
||||
|
||||
/* everything else is *probably* fine ... */
|
||||
@ -378,17 +370,6 @@ static int obex_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
if (status)
|
||||
goto fail;
|
||||
|
||||
/* Avoid letting this gadget enumerate until the userspace
|
||||
* OBEX server is active.
|
||||
*/
|
||||
status = usb_function_deactivate(f);
|
||||
if (status < 0)
|
||||
WARNING(cdev, "obex ttyGS%d: can't prevent enumeration, %d\n",
|
||||
obex->port_num, status);
|
||||
else
|
||||
obex->can_activate = true;
|
||||
|
||||
|
||||
dev_dbg(&cdev->gadget->dev, "obex ttyGS%d: %s speed IN/%s OUT/%s\n",
|
||||
obex->port_num,
|
||||
gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
|
||||
@ -529,6 +510,7 @@ static struct usb_function *obex_alloc(struct usb_function_instance *fi)
|
||||
obex->port.func.get_alt = obex_get_alt;
|
||||
obex->port.func.disable = obex_disable;
|
||||
obex->port.func.free_func = obex_free;
|
||||
obex->port.func.bind_deactivated = true;
|
||||
|
||||
return &obex->port.func;
|
||||
}
|
||||
|
@ -804,6 +804,8 @@ done:
|
||||
|
||||
static void printer_reset_interface(struct printer_dev *dev)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (dev->interface < 0)
|
||||
return;
|
||||
|
||||
@ -815,9 +817,11 @@ static void printer_reset_interface(struct printer_dev *dev)
|
||||
if (dev->out_ep->desc)
|
||||
usb_ep_disable(dev->out_ep);
|
||||
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
dev->in_ep->desc = NULL;
|
||||
dev->out_ep->desc = NULL;
|
||||
dev->interface = -1;
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
}
|
||||
|
||||
/* Change our operational Interface. */
|
||||
@ -1131,13 +1135,10 @@ static int printer_func_set_alt(struct usb_function *f,
|
||||
static void printer_func_disable(struct usb_function *f)
|
||||
{
|
||||
struct printer_dev *dev = func_to_printer(f);
|
||||
unsigned long flags;
|
||||
|
||||
DBG(dev, "%s\n", __func__);
|
||||
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
printer_reset_interface(dev);
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
}
|
||||
|
||||
static inline struct f_printer_opts
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include <linux/device.h>
|
||||
|
||||
#include "u_serial.h"
|
||||
#include "gadget_chips.h"
|
||||
|
||||
|
||||
/*
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include <linux/err.h>
|
||||
|
||||
#include "g_zero.h"
|
||||
#include "gadget_chips.h"
|
||||
#include "u_f.h"
|
||||
|
||||
/*
|
||||
@ -42,11 +41,6 @@
|
||||
* queues are relatively independent, will receive a range of packet sizes,
|
||||
* and can often be made to run out completely. Those issues are important
|
||||
* when stress testing peripheral controller drivers.
|
||||
*
|
||||
*
|
||||
* This is currently packaged as a configuration driver, which can't be
|
||||
* combined with other functions to make composite devices. However, it
|
||||
* can be combined with other independent configurations.
|
||||
*/
|
||||
struct f_sourcesink {
|
||||
struct usb_function function;
|
||||
|
@ -975,6 +975,29 @@ free_ep(struct uac2_rtd_params *prm, struct usb_ep *ep)
|
||||
"%s:%d Error!\n", __func__, __LINE__);
|
||||
}
|
||||
|
||||
static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts,
|
||||
struct usb_endpoint_descriptor *ep_desc,
|
||||
unsigned int factor, bool is_playback)
|
||||
{
|
||||
int chmask, srate, ssize;
|
||||
u16 max_packet_size;
|
||||
|
||||
if (is_playback) {
|
||||
chmask = uac2_opts->p_chmask;
|
||||
srate = uac2_opts->p_srate;
|
||||
ssize = uac2_opts->p_ssize;
|
||||
} else {
|
||||
chmask = uac2_opts->c_chmask;
|
||||
srate = uac2_opts->c_srate;
|
||||
ssize = uac2_opts->c_ssize;
|
||||
}
|
||||
|
||||
max_packet_size = num_channels(chmask) * ssize *
|
||||
DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1)));
|
||||
ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_packet_size,
|
||||
le16_to_cpu(ep_desc->wMaxPacketSize)));
|
||||
}
|
||||
|
||||
static int
|
||||
afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
|
||||
{
|
||||
@ -1070,10 +1093,14 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
|
||||
uac2->p_prm.uac2 = uac2;
|
||||
uac2->c_prm.uac2 = uac2;
|
||||
|
||||
/* Calculate wMaxPacketSize according to audio bandwidth */
|
||||
set_ep_max_packet_size(uac2_opts, &fs_epin_desc, 1000, true);
|
||||
set_ep_max_packet_size(uac2_opts, &fs_epout_desc, 1000, false);
|
||||
set_ep_max_packet_size(uac2_opts, &hs_epin_desc, 8000, true);
|
||||
set_ep_max_packet_size(uac2_opts, &hs_epout_desc, 8000, false);
|
||||
|
||||
hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress;
|
||||
hs_epout_desc.wMaxPacketSize = fs_epout_desc.wMaxPacketSize;
|
||||
hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress;
|
||||
hs_epin_desc.wMaxPacketSize = fs_epin_desc.wMaxPacketSize;
|
||||
|
||||
ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, NULL);
|
||||
if (ret)
|
||||
|
@ -733,12 +733,6 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
|
||||
uvc->control_req->complete = uvc_function_ep0_complete;
|
||||
uvc->control_req->context = uvc;
|
||||
|
||||
/* Avoid letting this gadget enumerate until the userspace server is
|
||||
* active.
|
||||
*/
|
||||
if ((ret = usb_function_deactivate(f)) < 0)
|
||||
goto error;
|
||||
|
||||
if (v4l2_device_register(&cdev->gadget->dev, &uvc->v4l2_dev)) {
|
||||
printk(KERN_INFO "v4l2_device_register failed\n");
|
||||
goto error;
|
||||
@ -949,6 +943,7 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
|
||||
uvc->func.disable = uvc_function_disable;
|
||||
uvc->func.setup = uvc_function_setup;
|
||||
uvc->func.free_func = uvc_free;
|
||||
uvc->func.bind_deactivated = true;
|
||||
|
||||
return &uvc->func;
|
||||
}
|
||||
|
@ -123,7 +123,7 @@ static inline bool fsg_lun_is_open(struct fsg_lun *curlun)
|
||||
#define FSG_BUFLEN ((u32)16384)
|
||||
|
||||
/* Maximal number of LUNs supported in mass storage function */
|
||||
#define FSG_MAX_LUNS 8
|
||||
#define FSG_MAX_LUNS 16
|
||||
|
||||
enum fsg_buffer_state {
|
||||
BUF_STATE_EMPTY = 0,
|
||||
|
@ -20,8 +20,6 @@
|
||||
#include <linux/usb/cdc.h>
|
||||
#include <linux/netdevice.h>
|
||||
|
||||
#include "gadget_chips.h"
|
||||
|
||||
#define QMULT_DEFAULT 5
|
||||
|
||||
/*
|
||||
@ -259,7 +257,7 @@ void gether_disconnect(struct gether *);
|
||||
/* Some controllers can't support CDC Ethernet (ECM) ... */
|
||||
static inline bool can_support_ecm(struct usb_gadget *gadget)
|
||||
{
|
||||
if (!gadget_supports_altsettings(gadget))
|
||||
if (!gadget_is_altset_supported(gadget))
|
||||
return false;
|
||||
|
||||
/* Everything else is *presumably* fine ... but this is a bit
|
||||
|
@ -21,8 +21,6 @@
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include "gadget_chips.h"
|
||||
|
||||
#define FILE_PCM_PLAYBACK "/dev/snd/pcmC0D0p"
|
||||
#define FILE_PCM_CAPTURE "/dev/snd/pcmC0D0c"
|
||||
#define FILE_CONTROL "/dev/snd/controlC0"
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user