diff options
162 files changed, 2925 insertions, 667 deletions
| diff --git a/Documentation/ABI/testing/configfs-usb-gadget-rndis b/Documentation/ABI/testing/configfs-usb-gadget-rndis index e32879b84b4d..137399095d74 100644 --- a/Documentation/ABI/testing/configfs-usb-gadget-rndis +++ b/Documentation/ABI/testing/configfs-usb-gadget-rndis @@ -12,3 +12,6 @@ Description:  				Ethernet over USB link  		dev_addr	- MAC address of device's end of this  				Ethernet over USB link +		class		- USB interface class, default is 02 (hex) +		subclass	- USB interface subclass, default is 06 (hex) +		protocol	- USB interface protocol, default is 00 (hex) diff --git a/Documentation/ABI/testing/sysfs-bus-usb-lvstest b/Documentation/ABI/testing/sysfs-bus-usb-lvstest index 5151290cf8e7..ee0046dc4192 100644 --- a/Documentation/ABI/testing/sysfs-bus-usb-lvstest +++ b/Documentation/ABI/testing/sysfs-bus-usb-lvstest @@ -45,3 +45,16 @@ Contact:	Pratyush Anand <[email protected]>  Description:  		Write to this node to issue "U3 exit" for Link Layer  		Validation device. It is needed for TD.7.36. + +What:		/sys/bus/usb/devices/.../enable_compliance +Date:		July 2017 +Description: +		Write to this node to set the port to compliance mode to test +		with Link Layer Validation device. It is needed for TD.7.34. + +What:		/sys/bus/usb/devices/.../warm_reset +Date:		July 2017 +Description: +		Write to this node to issue "Warm Reset" for Link Layer Validation +		device. It may be needed to properly reset an xHCI 1.1 host port if +		compliance mode needed to be explicitly enabled. diff --git a/Documentation/devicetree/bindings/mfd/wm831x.txt b/Documentation/devicetree/bindings/mfd/wm831x.txt index 9f8b7430673c..505709403d3f 100644 --- a/Documentation/devicetree/bindings/mfd/wm831x.txt +++ b/Documentation/devicetree/bindings/mfd/wm831x.txt @@ -31,6 +31,7 @@ Required properties:      ../interrupt-controller/interrupts.txt  Optional sub-nodes: +  - phys : Contains a phandle to the USB PHY.    - regulators : Contains sub-nodes for each of the regulators supplied by      the device. The regulators are bound using their names listed below: diff --git a/Documentation/devicetree/bindings/phy/phy-mt65xx-usb.txt b/Documentation/devicetree/bindings/phy/phy-mtk-tphy.txt index 0acc5a99fb79..faf18084a33a 100644 --- a/Documentation/devicetree/bindings/phy/phy-mt65xx-usb.txt +++ b/Documentation/devicetree/bindings/phy/phy-mtk-tphy.txt @@ -1,13 +1,18 @@ -mt65xx USB3.0 PHY binding +MediaTek T-PHY binding  -------------------------- -This binding describes a usb3.0 phy for mt65xx platforms of Medaitek SoC. +T-phy controller supports physical layer functionality for a number of +controllers on MediaTek SoCs, such as, USB2.0, USB3.0, PCIe, and SATA.  Required properties (controller (parent) node):   - compatible	: should be one of -		  "mediatek,mt2701-u3phy" -		  "mediatek,mt2712-u3phy" -		  "mediatek,mt8173-u3phy" +		  "mediatek,generic-tphy-v1" +		  "mediatek,generic-tphy-v2" +		  "mediatek,mt2701-u3phy" (deprecated) +		  "mediatek,mt2712-u3phy" (deprecated) +		  "mediatek,mt8173-u3phy"; +		  make use of "mediatek,generic-tphy-v1" on mt2701 instead and +		  "mediatek,generic-tphy-v2" on mt2712 instead.   - clocks	: (deprecated, use port's clocks instead) a list of phandle +  		  clock-specifier pairs, one for each entry in clock-names   - clock-names	: (deprecated, use port's one instead) must contain @@ -35,6 +40,8 @@ Required properties (port (child) node):  		  cell after port phandle is phy type from:  			- PHY_TYPE_USB2  			- PHY_TYPE_USB3 +			- PHY_TYPE_PCIE +			- PHY_TYPE_SATA  Example: diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt index 84d59b0db8df..a67ef2a3874f 100644 --- a/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt @@ -6,6 +6,7 @@ Required properties (phy (parent) node):  	* "rockchip,rk3328-usb2phy"  	* "rockchip,rk3366-usb2phy"  	* "rockchip,rk3399-usb2phy" +	* "rockchip,rv1108-usb2phy"   - reg : the address offset of grf for usb-phy configuration.   - #clock-cells : should be 0.   - clock-output-names : specify the 480m output clock name. @@ -18,6 +19,10 @@ Optional properties:  		 usb-phy output 480m and xin24m.  		 Refer to clk/clock-bindings.txt for generic clock  		 consumer properties. + - rockchip,usbgrf : phandle to the syscon managing the "usb general +		 register files". When set driver will request its +		 phandle as one companion-grf for some special SoCs +		 (e.g RV1108).  Required nodes : a sub-node is required for each port the phy provides.  		 The sub-node name is used to identify host or otg port, @@ -28,10 +33,14 @@ Required nodes : a sub-node is required for each port the phy provides.  Required properties (port (child) node):   - #phy-cells : must be 0. See ./phy-bindings.txt for details.   - interrupts : specify an interrupt for each entry in interrupt-names. - - interrupt-names : a list which shall be the following entries: + - interrupt-names : a list which should be one of the following cases: +	Regular case:  	* "otg-id" : for the otg id interrupt.  	* "otg-bvalid" : for the otg vbus interrupt.  	* "linestate" : for the host/otg linestate interrupt. +	Some SoCs use one interrupt with the above muxed together, so for these +	* "otg-mux" : otg-port interrupt, which mux otg-id/otg-bvalid/linestate +		to one.  Optional properties:   - phy-supply : phandle to a regulator that provides power to VBUS. diff --git a/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt b/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt index e11c563a65ec..b6a9f2b92bab 100644 --- a/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt +++ b/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt @@ -6,6 +6,7 @@ controllers on Qualcomm chipsets, such as, PCIe, UFS, and USB.  Required properties:   - compatible: compatible list, contains: +	       "qcom,ipq8074-qmp-pcie-phy" for PCIe phy on IPQ8074  	       "qcom,msm8996-qmp-pcie-phy" for 14nm PCIe phy on msm8996,  	       "qcom,msm8996-qmp-usb3-phy" for 14nm USB3 phy on msm8996. @@ -38,6 +39,8 @@ Required properties:  		 "phy", "common", "cfg".  		For "qcom,msm8996-qmp-usb3-phy" must contain  		 "phy", "common". +		For "qcom,ipq8074-qmp-pcie-phy" must contain: +		 "phy", "common".   - vdda-phy-supply: Phandle to a regulator supply to PHY core block.   - vdda-pll-supply: Phandle to 1.8V regulator supply to PHY refclk pll block. @@ -60,6 +63,13 @@ Required properties for child node:  	   one for each entry in clock-names.   - clock-names: Must contain following for pcie and usb qmp phys:  		 "pipe<lane-number>" for pipe clock specific to each lane. + - clock-output-names: Name of the PHY clock that will be the parent for +		       the above pipe clock. + +	For "qcom,ipq8074-qmp-pcie-phy": +		- "pcie20_phy0_pipe_clk"	Pipe Clock parent +			(or) +		  "pcie20_phy1_pipe_clk"   - resets: a list of phandles and reset controller specifier pairs,  	   one for each entry in reset-names. @@ -96,6 +106,7 @@ Example:  			clocks = <&gcc GCC_PCIE_0_PIPE_CLK>;  			clock-names = "pipe0"; +			clock-output-names = "pcie_0_pipe_clk_src";  			resets = <&gcc GCC_PCIE_0_PHY_BCR>;  			reset-names = "lane0";  		}; diff --git a/Documentation/devicetree/bindings/phy/ralink-usb-phy.txt b/Documentation/devicetree/bindings/phy/ralink-usb-phy.txt new file mode 100644 index 000000000000..9d2868a437ab --- /dev/null +++ b/Documentation/devicetree/bindings/phy/ralink-usb-phy.txt @@ -0,0 +1,23 @@ +Mediatek/Ralink USB PHY + +Required properties: + - compatible: "ralink,rt3352-usbphy" +	       "mediatek,mt7620-usbphy" +	       "mediatek,mt7628-usbphy" + - reg: required for "mediatek,mt7628-usbphy", unused otherwise + - #phy-cells: should be 0 + - ralink,sysctl: a phandle to a ralink syscon register region + - resets: the two reset controllers for host and device + - reset-names: the names of the 2 reset controllers + +Example: + +usbphy: phy { +	compatible = "mediatek,mt7628-usbphy"; +	reg = <0x10120000 0x1000>; +	#phy-cells = <0>; + +	ralink,sysctl = <&sysc>; +	resets = <&rstctrl 22 &rstctrl 25>; +	reset-names = "host", "device"; +}; diff --git a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt index 005bc22938ff..cbc7847dbf6c 100644 --- a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt +++ b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt @@ -9,6 +9,7 @@ Required properties:    * allwinner,sun7i-a20-usb-phy    * allwinner,sun8i-a23-usb-phy    * allwinner,sun8i-a33-usb-phy +  * allwinner,sun8i-a83t-usb-phy    * allwinner,sun8i-h3-usb-phy    * allwinner,sun8i-v3s-usb-phy    * allwinner,sun50i-a64-usb-phy @@ -17,18 +18,22 @@ Required properties:    * "phy_ctrl"    * "pmu0" for H3, V3s and A64    * "pmu1" -  * "pmu2" for sun4i, sun6i or sun7i +  * "pmu2" for sun4i, sun6i, sun7i, sun8i-a83t or sun8i-h3 +  * "pmu3" for sun8i-h3  - #phy-cells : from the generic phy bindings, must be 1  - clocks : phandle + clock specifier for the phy clocks  - clock-names :    * "usb_phy" for sun4i, sun5i or sun7i    * "usb0_phy", "usb1_phy" and "usb2_phy" for sun6i    * "usb0_phy", "usb1_phy" for sun8i +  * "usb0_phy", "usb1_phy", "usb2_phy" and "usb2_hsic_12M" for sun8i-a83t +  * "usb0_phy", "usb1_phy", "usb2_phy" and "usb3_phy" for sun8i-h3  - resets : a list of phandle + reset specifier pairs  - reset-names :    * "usb0_reset"    * "usb1_reset" -  * "usb2_reset" for sun4i, sun6i or sun7i +  * "usb2_reset" for sun4i, sun6i, sun7i, sun8i-a83t or sun8i-h3 +  * "usb3_reset" for sun8i-h3  Optional properties:  - usb0_id_det-gpios : gpio phandle for reading the otg id pin value @@ -37,6 +42,7 @@ Optional properties:  - 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 +- usb3_vbus-supply : regulator phandle for controller usb3 vbus  Example:  	usbphy: phy@0x01c13400 { diff --git a/Documentation/devicetree/bindings/usb/brcm,bdc.txt b/Documentation/devicetree/bindings/usb/brcm,bdc.txt new file mode 100644 index 000000000000..63e63af3bf59 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/brcm,bdc.txt @@ -0,0 +1,29 @@ +Broadcom USB Device Controller (BDC) +==================================== + +Required properties: + +- compatible: must be one of: +                "brcm,bdc-v0.16" +                "brcm,bdc" +- reg: the base register address and length +- interrupts: the interrupt line for this controller + +Optional properties: + +On Broadcom STB platforms, these properties are required: + +- phys: phandle to one or two USB PHY blocks +        NOTE: Some SoC's have a single phy and some have +        USB 2.0 and USB 3.0 phys +- clocks: phandle to the functional clock of this block + +Example: + +        bdc@f0b02000 { +                compatible = "brcm,bdc-v0.16"; +                reg = <0xf0b02000 0xfc4>; +                interrupts = <0x0 0x60 0x0>; +                phys = <&usbphy_0 0x0>; +                clocks = <&sw_usbd>; +        }; diff --git a/Documentation/devicetree/bindings/usb/keystone-usb.txt b/Documentation/devicetree/bindings/usb/keystone-usb.txt index 60527d335b58..2d1bef16f149 100644 --- a/Documentation/devicetree/bindings/usb/keystone-usb.txt +++ b/Documentation/devicetree/bindings/usb/keystone-usb.txt @@ -12,8 +12,21 @@ Required properties:     MPU.   - ranges: allows valid 1:1 translation between child's address space and     parent's address space. - - clocks: Clock IDs array as required by the controller. - - clock-names: names of clocks correseponding to IDs in the clock property. + +SoC-specific Required Properties: +The following are mandatory properties for Keystone 2 66AK2HK, 66AK2L and 66AK2E +SoCs only: + +- clocks:		Clock ID for USB functional clock. +- clock-names:		Must be "usb". + + +The following are mandatory properties for Keystone 2 66AK2G SoCs only: + +- power-domains:	Should contain a phandle to a PM domain provider node +			and an args specifier containing the USB device id +			value. This property is as per the binding, +			Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt  Sub-nodes:  The dwc3 core should be added as subnode to Keystone DWC3 glue. diff --git a/Documentation/devicetree/bindings/usb/mt8173-xhci.txt b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.txt index 0acfc8acbea1..5611a2e4ddf0 100644 --- a/Documentation/devicetree/bindings/usb/mt8173-xhci.txt +++ b/Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.txt @@ -11,7 +11,11 @@ into two parts.  ------------------------------------------------------------------------  Required properties: - - compatible : should contain "mediatek,mt8173-xhci" + - compatible : should be "mediatek,<soc-model>-xhci", "mediatek,mtk-xhci", +	soc-model is the name of SoC, such as mt8173, mt2712 etc, when using +	"mediatek,mtk-xhci" compatible string, you need SoC specific ones in +	addition, one of: +	- "mediatek,mt8173-xhci"   - reg : specifies physical base address and size of the registers   - reg-names: should be "mac" for xHCI MAC and "ippc" for IP port control   - interrupts : interrupt used by the controller @@ -68,10 +72,14 @@ usb30: usb@11270000 {  In the case, xhci is added as subnode to mtu3. An example and the DT binding  details of mtu3 can be found in: -Documentation/devicetree/bindings/usb/mt8173-mtu3.txt +Documentation/devicetree/bindings/usb/mediatek,mtu3.txt  Required properties: - - compatible : should contain "mediatek,mt8173-xhci" + - compatible : should be "mediatek,<soc-model>-xhci", "mediatek,mtk-xhci", +	soc-model is the name of SoC, such as mt8173, mt2712 etc, when using +	"mediatek,mtk-xhci" compatible string, you need SoC specific ones in +	addition, one of: +	- "mediatek,mt8173-xhci"   - reg : specifies physical base address and size of the registers   - reg-names: should be "mac" for xHCI MAC   - interrupts : interrupt used by the host controller diff --git a/Documentation/devicetree/bindings/usb/mt8173-mtu3.txt b/Documentation/devicetree/bindings/usb/mediatek,mtu3.txt index 1d7c3bc677f7..838ae48eafc1 100644 --- a/Documentation/devicetree/bindings/usb/mt8173-mtu3.txt +++ b/Documentation/devicetree/bindings/usb/mediatek,mtu3.txt @@ -1,7 +1,11 @@  The device node for Mediatek USB3.0 DRD controller  Required properties: - - compatible : should be "mediatek,mt8173-mtu3" + - compatible : should be "mediatek,<soc-model>-mtu3", "mediatek,mtu3", +	soc-model is the name of SoC, such as mt8173, mt2712 etc, +	when using "mediatek,mtu3" compatible string, you need SoC specific +	ones in addition, one of: +	- "mediatek,mt8173-mtu3"   - reg : specifies physical base address and size of the registers   - reg-names: should be "mac" for device IP and "ippc" for IP port control   - interrupts : interrupt used by the device IP @@ -44,7 +48,7 @@ Optional properties:  Sub-nodes:  The xhci should be added as subnode to mtu3 as shown in the following example  if host mode is enabled. The DT binding details of xhci can be found in: -Documentation/devicetree/bindings/usb/mt8173-xhci.txt +Documentation/devicetree/bindings/usb/mediatek,mtk-xhci.txt  Example:  ssusb: usb@11271000 { diff --git a/Documentation/devicetree/bindings/usb/renesas_usb3.txt b/Documentation/devicetree/bindings/usb/renesas_usb3.txt index 8d52766f07b9..e28025883b79 100644 --- a/Documentation/devicetree/bindings/usb/renesas_usb3.txt +++ b/Documentation/devicetree/bindings/usb/renesas_usb3.txt @@ -3,20 +3,30 @@ Renesas Electronics USB3.0 Peripheral driver  Required properties:    - compatible: Must contain one of the following:  	- "renesas,r8a7795-usb3-peri" +	- "renesas,r8a7796-usb3-peri" +	- "renesas,rcar-gen3-usb3-peri" for a generic R-Car Gen3 compatible +	  device + +    When compatible with the generic version, nodes must list the +    SoC-specific version corresponding to the platform first +    followed by the generic version. +    - reg: Base address and length of the register for the USB3.0 Peripheral    - interrupts: Interrupt specifier for the USB3.0 Peripheral    - clocks: clock phandle and specifier pair -Example: +Example of R-Car H3 ES1.x:  	usb3_peri0: usb@ee020000 { -		compatible = "renesas,r8a7795-usb3-peri"; +		compatible = "renesas,r8a7795-usb3-peri", +			     "renesas,rcar-gen3-usb3-peri";  		reg = <0 0xee020000 0 0x400>;  		interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;  		clocks = <&cpg CPG_MOD 328>;  	};  	usb3_peri1: usb@ee060000 { -		compatible = "renesas,r8a7795-usb3-peri"; +		compatible = "renesas,r8a7795-usb3-peri", +			     "renesas,rcar-gen3-usb3-peri";  		reg = <0 0xee060000 0 0x400>;  		interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;  		clocks = <&cpg CPG_MOD 327>; diff --git a/MAINTAINERS b/MAINTAINERS index 8ef4694af6e8..8a28bad13e13 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1570,7 +1570,7 @@ M:	Chunfeng Yun <[email protected]>  L:	[email protected] (moderated for non-subscribers)  L:	[email protected] (moderated for non-subscribers)  S:	Maintained -F:	drivers/phy/phy-mt65xx-usb3.c +F:	drivers/phy/mediatek/phy-mtk-tphy.c  ARM/MICREL KS8695 ARCHITECTURE  M:	Greg Ungerer <[email protected]> @@ -8475,6 +8475,14 @@ M:	Sean Wang <[email protected]>  S:	Maintained  F:	drivers/char/hw_random/mtk-rng.c +MEDIATEK USB3 DRD IP DRIVER +M:	Chunfeng Yun <[email protected]> +L:	[email protected] (moderated for non-subscribers) +L:	[email protected] (moderated for non-subscribers) +L:	[email protected] (moderated for non-subscribers) +S:	Maintained +F:	drivers/usb/mtu3/ +  MEGACHIPS STDPXXXX-GE-B850V3-FW LVDS/DP++ BRIDGES  M:	Peter Senna Tschudin <[email protected]>  M:	Martin Donnelly <[email protected]> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index c1807d4a0079..441912c10b82 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -26,14 +26,6 @@ config PHY_LPC18XX_USB_OTG  	  This driver is need for USB0 support on LPC18xx/43xx and takes  	  care of enabling and clock setup. -config PHY_MT65XX_USB3 -	tristate "Mediatek USB3.0 PHY Driver" -	depends on ARCH_MEDIATEK && OF -	select GENERIC_PHY -	help -	  Say 'Y' here to add support for Mediatek USB3.0 PHY driver, -	  it supports multiple usb2.0 and usb3.0 ports. -  config PHY_PISTACHIO_USB  	tristate "IMG Pistachio USB2.0 PHY driver"  	depends on MACH_PISTACHIO @@ -53,8 +45,10 @@ source "drivers/phy/amlogic/Kconfig"  source "drivers/phy/broadcom/Kconfig"  source "drivers/phy/hisilicon/Kconfig"  source "drivers/phy/marvell/Kconfig" +source "drivers/phy/mediatek/Kconfig"  source "drivers/phy/motorola/Kconfig"  source "drivers/phy/qualcomm/Kconfig" +source "drivers/phy/ralink/Kconfig"  source "drivers/phy/renesas/Kconfig"  source "drivers/phy/rockchip/Kconfig"  source "drivers/phy/samsung/Kconfig" diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index f252201e0ec9..06f3c500030d 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -4,12 +4,12 @@  obj-$(CONFIG_GENERIC_PHY)		+= phy-core.o  obj-$(CONFIG_PHY_LPC18XX_USB_OTG)	+= phy-lpc18xx-usb-otg.o -obj-$(CONFIG_PHY_MT65XX_USB3)		+= phy-mt65xx-usb3.o  obj-$(CONFIG_PHY_XGENE)			+= phy-xgene.o  obj-$(CONFIG_PHY_PISTACHIO_USB)		+= phy-pistachio-usb.o  obj-$(CONFIG_ARCH_SUNXI)		+= allwinner/  obj-$(CONFIG_ARCH_MESON)		+= amlogic/ +obj-$(CONFIG_ARCH_MEDIATEK)		+= mediatek/  obj-$(CONFIG_ARCH_RENESAS)		+= renesas/  obj-$(CONFIG_ARCH_ROCKCHIP)		+= rockchip/  obj-$(CONFIG_ARCH_TEGRA)		+= tegra/ @@ -18,6 +18,7 @@ obj-y					+= broadcom/	\  					   marvell/	\  					   motorola/	\  					   qualcomm/	\ +					   ralink/	\  					   samsung/	\  					   st/		\  					   ti/ diff --git a/drivers/phy/allwinner/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c index bbf06cfe5898..1161e11fb3cf 100644 --- a/drivers/phy/allwinner/phy-sun4i-usb.c +++ b/drivers/phy/allwinner/phy-sun4i-usb.c @@ -87,6 +87,16 @@  #define PHY_DISCON_TH_SEL		0x2a  #define PHY_SQUELCH_DETECT		0x3c +/* A83T specific control bits for PHY0 */ +#define PHY_CTL_VBUSVLDEXT		BIT(5) +#define PHY_CTL_SIDDQ			BIT(3) + +/* A83T specific control bits for PHY2 HSIC */ +#define SUNXI_EHCI_HS_FORCE		BIT(20) +#define SUNXI_HSIC_CONNECT_DET		BIT(17) +#define SUNXI_HSIC_CONNECT_INT		BIT(16) +#define SUNXI_HSIC			BIT(1) +  #define MAX_PHYS			4  /* @@ -100,6 +110,7 @@ enum sun4i_usb_phy_type {  	sun4i_a10_phy,  	sun6i_a31_phy,  	sun8i_a33_phy, +	sun8i_a83t_phy,  	sun8i_h3_phy,  	sun8i_v3s_phy,  	sun50i_a64_phy, @@ -107,6 +118,7 @@ enum sun4i_usb_phy_type {  struct sun4i_usb_phy_cfg {  	int num_phys; +	int hsic_index;  	enum sun4i_usb_phy_type type;  	u32 disc_thresh;  	u8 phyctl_offset; @@ -126,6 +138,7 @@ struct sun4i_usb_phy_data {  		struct regulator *vbus;  		struct reset_control *reset;  		struct clk *clk; +		struct clk *clk2;  		bool regulator_on;  		int index;  	} phys[MAX_PHYS]; @@ -232,6 +245,7 @@ static void sun4i_usb_phy_write(struct sun4i_usb_phy *phy, u32 addr, u32 data,  static void sun4i_usb_phy_passby(struct sun4i_usb_phy *phy, int enable)  { +	struct sun4i_usb_phy_data *phy_data = to_sun4i_usb_phy_data(phy);  	u32 bits, reg_value;  	if (!phy->pmu) @@ -240,6 +254,11 @@ static void sun4i_usb_phy_passby(struct sun4i_usb_phy *phy, int enable)  	bits = SUNXI_AHB_ICHR8_EN | SUNXI_AHB_INCR4_BURST_EN |  		SUNXI_AHB_INCRX_ALIGN_EN | SUNXI_ULPI_BYPASS_EN; +	/* A83T USB2 is HSIC */ +	if (phy_data->cfg->type == sun8i_a83t_phy && phy->index == 2) +		bits |= SUNXI_EHCI_HS_FORCE | SUNXI_HSIC_CONNECT_INT | +			SUNXI_HSIC; +  	reg_value = readl(phy->pmu);  	if (enable) @@ -261,27 +280,43 @@ static int sun4i_usb_phy_init(struct phy *_phy)  	if (ret)  		return ret; -	ret = reset_control_deassert(phy->reset); +	ret = clk_prepare_enable(phy->clk2);  	if (ret) {  		clk_disable_unprepare(phy->clk);  		return ret;  	} -	if (phy->pmu && data->cfg->enable_pmu_unk1) { -		val = readl(phy->pmu + REG_PMU_UNK1); -		writel(val & ~2, phy->pmu + REG_PMU_UNK1); +	ret = reset_control_deassert(phy->reset); +	if (ret) { +		clk_disable_unprepare(phy->clk2); +		clk_disable_unprepare(phy->clk); +		return ret;  	} -	/* Enable USB 45 Ohm resistor calibration */ -	if (phy->index == 0) -		sun4i_usb_phy_write(phy, PHY_RES45_CAL_EN, 0x01, 1); +	if (data->cfg->type == sun8i_a83t_phy) { +		if (phy->index == 0) { +			val = readl(data->base + data->cfg->phyctl_offset); +			val |= PHY_CTL_VBUSVLDEXT; +			val &= ~PHY_CTL_SIDDQ; +			writel(val, data->base + data->cfg->phyctl_offset); +		} +	} else { +		if (phy->pmu && data->cfg->enable_pmu_unk1) { +			val = readl(phy->pmu + REG_PMU_UNK1); +			writel(val & ~2, phy->pmu + REG_PMU_UNK1); +		} -	/* Adjust PHY's magnitude and rate */ -	sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE, 0x14, 5); +		/* Enable USB 45 Ohm resistor calibration */ +		if (phy->index == 0) +			sun4i_usb_phy_write(phy, PHY_RES45_CAL_EN, 0x01, 1); -	/* Disconnect threshold adjustment */ -	sun4i_usb_phy_write(phy, PHY_DISCON_TH_SEL, -			    data->cfg->disc_thresh, 2); +		/* Adjust PHY's magnitude and rate */ +		sun4i_usb_phy_write(phy, PHY_TX_AMPLITUDE_TUNE, 0x14, 5); + +		/* Disconnect threshold adjustment */ +		sun4i_usb_phy_write(phy, PHY_DISCON_TH_SEL, +				    data->cfg->disc_thresh, 2); +	}  	sun4i_usb_phy_passby(phy, 1); @@ -307,6 +342,13 @@ static int sun4i_usb_phy_exit(struct phy *_phy)  	struct sun4i_usb_phy_data *data = to_sun4i_usb_phy_data(phy);  	if (phy->index == 0) { +		if (data->cfg->type == sun8i_a83t_phy) { +			void __iomem *phyctl = data->base + +				data->cfg->phyctl_offset; + +			writel(readl(phyctl) | PHY_CTL_SIDDQ, phyctl); +		} +  		/* 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); @@ -315,6 +357,7 @@ static int sun4i_usb_phy_exit(struct phy *_phy)  	sun4i_usb_phy_passby(phy, 0);  	reset_control_assert(phy->reset); +	clk_disable_unprepare(phy->clk2);  	clk_disable_unprepare(phy->clk);  	return 0; @@ -653,19 +696,25 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)  	data->id_det_gpio = devm_gpiod_get_optional(dev, "usb0_id_det",  						    GPIOD_IN); -	if (IS_ERR(data->id_det_gpio)) +	if (IS_ERR(data->id_det_gpio)) { +		dev_err(dev, "Couldn't request ID GPIO\n");  		return PTR_ERR(data->id_det_gpio); +	}  	data->vbus_det_gpio = devm_gpiod_get_optional(dev, "usb0_vbus_det",  						      GPIOD_IN); -	if (IS_ERR(data->vbus_det_gpio)) +	if (IS_ERR(data->vbus_det_gpio)) { +		dev_err(dev, "Couldn't request VBUS detect GPIO\n");  		return PTR_ERR(data->vbus_det_gpio); +	}  	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)) +		if (IS_ERR(data->vbus_power_supply)) { +			dev_err(dev, "Couldn't get the VBUS power supply\n");  			return PTR_ERR(data->vbus_power_supply); +		}  		if (!data->vbus_power_supply)  			return -EPROBE_DEFER; @@ -674,8 +723,10 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)  	data->dr_mode = of_usb_get_dr_mode_by_phy(np, 0);  	data->extcon = devm_extcon_dev_allocate(dev, sun4i_usb_phy0_cable); -	if (IS_ERR(data->extcon)) +	if (IS_ERR(data->extcon)) { +		dev_err(dev, "Couldn't allocate our extcon device\n");  		return PTR_ERR(data->extcon); +	}  	ret = devm_extcon_dev_register(dev, data->extcon);  	if (ret) { @@ -690,8 +741,13 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)  		snprintf(name, sizeof(name), "usb%d_vbus", i);  		phy->vbus = devm_regulator_get_optional(dev, name);  		if (IS_ERR(phy->vbus)) { -			if (PTR_ERR(phy->vbus) == -EPROBE_DEFER) +			if (PTR_ERR(phy->vbus) == -EPROBE_DEFER) { +				dev_err(dev, +					"Couldn't get regulator %s... Deferring probe\n", +					name);  				return -EPROBE_DEFER; +			} +  			phy->vbus = NULL;  		} @@ -706,6 +762,17 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)  			return PTR_ERR(phy->clk);  		} +		/* The first PHY is always tied to OTG, and never HSIC */ +		if (data->cfg->hsic_index && i == data->cfg->hsic_index) { +			/* HSIC needs secondary clock */ +			snprintf(name, sizeof(name), "usb%d_hsic_12M", i); +			phy->clk2 = devm_clk_get(dev, name); +			if (IS_ERR(phy->clk2)) { +				dev_err(dev, "failed to get clock %s\n", name); +				return PTR_ERR(phy->clk2); +			} +		} +  		snprintf(name, sizeof(name), "usb%d_reset", i);  		phy->reset = devm_reset_control_get(dev, name);  		if (IS_ERR(phy->reset)) { @@ -775,6 +842,8 @@ static int sun4i_usb_phy_probe(struct platform_device *pdev)  		return PTR_ERR(phy_provider);  	} +	dev_dbg(dev, "successfully loaded\n"); +  	return 0;  } @@ -832,6 +901,14 @@ static const struct sun4i_usb_phy_cfg sun8i_a33_cfg = {  	.enable_pmu_unk1 = false,  }; +static const struct sun4i_usb_phy_cfg sun8i_a83t_cfg = { +	.num_phys = 3, +	.hsic_index = 2, +	.type = sun8i_a83t_phy, +	.phyctl_offset = REG_PHYCTL_A33, +	.dedicated_clocks = true, +}; +  static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = {  	.num_phys = 4,  	.type = sun8i_h3_phy, @@ -868,6 +945,7 @@ static const struct of_device_id sun4i_usb_phy_of_match[] = {  	{ .compatible = "allwinner,sun7i-a20-usb-phy", .data = &sun7i_a20_cfg },  	{ .compatible = "allwinner,sun8i-a23-usb-phy", .data = &sun8i_a23_cfg },  	{ .compatible = "allwinner,sun8i-a33-usb-phy", .data = &sun8i_a33_cfg }, +	{ .compatible = "allwinner,sun8i-a83t-usb-phy", .data = &sun8i_a83t_cfg },  	{ .compatible = "allwinner,sun8i-h3-usb-phy", .data = &sun8i_h3_cfg },  	{ .compatible = "allwinner,sun8i-v3s-usb-phy", .data = &sun8i_v3s_cfg },  	{ .compatible = "allwinner,sun50i-a64-usb-phy", diff --git a/drivers/phy/broadcom/phy-brcm-sata.c b/drivers/phy/broadcom/phy-brcm-sata.c index e6544c8b1ace..9d7f74fe3d7c 100644 --- a/drivers/phy/broadcom/phy-brcm-sata.c +++ b/drivers/phy/broadcom/phy-brcm-sata.c @@ -335,7 +335,7 @@ static int brcm_nsp_sata_init(struct brcm_sata_port *port)  	/* Wait for pll_seq_done bit */  	try = 50; -	while (try--) { +	while (--try) {  		val = brcm_sata_phy_rd(base, BLOCK0_REG_BANK,  					BLOCK0_XGXSSTATUS);  		if (val & BLOCK0_XGXSSTATUS_PLL_LOCK) diff --git a/drivers/phy/mediatek/Kconfig b/drivers/phy/mediatek/Kconfig new file mode 100644 index 000000000000..88ab4e25e34f --- /dev/null +++ b/drivers/phy/mediatek/Kconfig @@ -0,0 +1,14 @@ +# +# Phy drivers for Mediatek devices +# +config PHY_MTK_TPHY +    tristate "MediaTek T-PHY Driver" +    depends on ARCH_MEDIATEK && OF +    select GENERIC_PHY +    help +      Say 'Y' here to add support for MediaTek T-PHY driver, +      it supports multiple usb2.0, usb3.0 ports, PCIe and +	  SATA, and meanwhile supports two version T-PHY which have +	  different banks layout, the T-PHY with shared banks between +	  multi-ports is first version, otherwise is second veriosn, +	  so you can easily distinguish them by banks layout. diff --git a/drivers/phy/mediatek/Makefile b/drivers/phy/mediatek/Makefile new file mode 100644 index 000000000000..763a92eefa00 --- /dev/null +++ b/drivers/phy/mediatek/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the phy drivers. +# + +obj-$(CONFIG_PHY_MTK_TPHY)		+= phy-mtk-tphy.o diff --git a/drivers/phy/phy-mt65xx-usb3.c b/drivers/phy/mediatek/phy-mtk-tphy.c index 59b110f795c3..e3baad78521f 100644 --- a/drivers/phy/phy-mt65xx-usb3.c +++ b/drivers/phy/mediatek/phy-mtk-tphy.c @@ -29,7 +29,7 @@  #define SSUSB_SIFSLV_V1_U2FREQ		0x100	/* shared by u2 phys */  /* u2 phy bank */  #define SSUSB_SIFSLV_V1_U2PHY_COM	0x000 -/* u3 phy banks */ +/* u3/pcie/sata phy banks */  #define SSUSB_SIFSLV_V1_U3PHYD		0x000  #define SSUSB_SIFSLV_V1_U3PHYA		0x200 @@ -38,7 +38,7 @@  #define SSUSB_SIFSLV_V2_MISC		0x000  #define SSUSB_SIFSLV_V2_U2FREQ		0x100  #define SSUSB_SIFSLV_V2_U2PHY_COM	0x300 -/* u3 phy banks */ +/* u3/pcie/sata phy banks */  #define SSUSB_SIFSLV_V2_SPLLC		0x000  #define SSUSB_SIFSLV_V2_CHIP		0x100  #define SSUSB_SIFSLV_V2_U3PHYD		0x200 @@ -99,6 +99,23 @@  #define P2C_RG_SESSEND			BIT(4)  #define P2C_RG_AVALID			BIT(2) +#define U3P_U3_CHIP_GPIO_CTLD		0x0c +#define P3C_REG_IP_SW_RST		BIT(31) +#define P3C_MCU_BUS_CK_GATE_EN		BIT(30) +#define P3C_FORCE_IP_SW_RST		BIT(29) + +#define U3P_U3_CHIP_GPIO_CTLE		0x10 +#define P3C_RG_SWRST_U3_PHYD		BIT(25) +#define P3C_RG_SWRST_U3_PHYD_FORCE_EN	BIT(24) + +#define U3P_U3_PHYA_REG0	0x000 +#define P3A_RG_CLKDRV_OFF		GENMASK(3, 2) +#define P3A_RG_CLKDRV_OFF_VAL(x)	((0x3 & (x)) << 2) + +#define U3P_U3_PHYA_REG1	0x004 +#define P3A_RG_CLKDRV_AMP		GENMASK(31, 29) +#define P3A_RG_CLKDRV_AMP_VAL(x)	((0x7 & (x)) << 29) +  #define U3P_U3_PHYA_REG6	0x018  #define P3A_RG_TX_EIDLE_CM		GENMASK(31, 28)  #define P3A_RG_TX_EIDLE_CM_VAL(x)	((0xf & (x)) << 28) @@ -108,9 +125,40 @@  #define P3A_RG_RX_DAC_MUX_VAL(x)	((0x1f & (x)) << 1)  #define U3P_U3_PHYA_DA_REG0	0x100 +#define P3A_RG_XTAL_EXT_PE2H		GENMASK(17, 16) +#define P3A_RG_XTAL_EXT_PE2H_VAL(x)	((0x3 & (x)) << 16) +#define P3A_RG_XTAL_EXT_PE1H		GENMASK(13, 12) +#define P3A_RG_XTAL_EXT_PE1H_VAL(x)	((0x3 & (x)) << 12)  #define P3A_RG_XTAL_EXT_EN_U3		GENMASK(11, 10)  #define P3A_RG_XTAL_EXT_EN_U3_VAL(x)	((0x3 & (x)) << 10) +#define U3P_U3_PHYA_DA_REG4	0x108 +#define P3A_RG_PLL_DIVEN_PE2H		GENMASK(21, 19) +#define P3A_RG_PLL_BC_PE2H		GENMASK(7, 6) +#define P3A_RG_PLL_BC_PE2H_VAL(x)	((0x3 & (x)) << 6) + +#define U3P_U3_PHYA_DA_REG5	0x10c +#define P3A_RG_PLL_BR_PE2H		GENMASK(29, 28) +#define P3A_RG_PLL_BR_PE2H_VAL(x)	((0x3 & (x)) << 28) +#define P3A_RG_PLL_IC_PE2H		GENMASK(15, 12) +#define P3A_RG_PLL_IC_PE2H_VAL(x)	((0xf & (x)) << 12) + +#define U3P_U3_PHYA_DA_REG6	0x110 +#define P3A_RG_PLL_IR_PE2H		GENMASK(19, 16) +#define P3A_RG_PLL_IR_PE2H_VAL(x)	((0xf & (x)) << 16) + +#define U3P_U3_PHYA_DA_REG7	0x114 +#define P3A_RG_PLL_BP_PE2H		GENMASK(19, 16) +#define P3A_RG_PLL_BP_PE2H_VAL(x)	((0xf & (x)) << 16) + +#define U3P_U3_PHYA_DA_REG20	0x13c +#define P3A_RG_PLL_DELTA1_PE2H		GENMASK(31, 16) +#define P3A_RG_PLL_DELTA1_PE2H_VAL(x)	((0xffff & (x)) << 16) + +#define U3P_U3_PHYA_DA_REG25	0x148 +#define P3A_RG_PLL_DELTA_PE2H		GENMASK(15, 0) +#define P3A_RG_PLL_DELTA_PE2H_VAL(x)	(0xffff & (x)) +  #define U3P_U3_PHYD_LFPS1		0x00c  #define P3D_RG_FWAKE_TH		GENMASK(21, 16)  #define P3D_RG_FWAKE_TH_VAL(x)	((0x3f & (x)) << 16) @@ -151,15 +199,74 @@  #define U3P_SR_COEF_DIVISOR	1000  #define U3P_FM_DET_CYCLE_CNT	1024 -enum mt_phy_version { -	MT_PHY_V1 = 1, -	MT_PHY_V2, +/* SATA register setting */ +#define PHYD_CTRL_SIGNAL_MODE4		0x1c +/* CDR Charge Pump P-path current adjustment */ +#define RG_CDR_BICLTD1_GEN1_MSK		GENMASK(23, 20) +#define RG_CDR_BICLTD1_GEN1_VAL(x)	((0xf & (x)) << 20) +#define RG_CDR_BICLTD0_GEN1_MSK		GENMASK(11, 8) +#define RG_CDR_BICLTD0_GEN1_VAL(x)	((0xf & (x)) << 8) + +#define PHYD_DESIGN_OPTION2		0x24 +/* Symbol lock count selection */ +#define RG_LOCK_CNT_SEL_MSK		GENMASK(5, 4) +#define RG_LOCK_CNT_SEL_VAL(x)		((0x3 & (x)) << 4) + +#define PHYD_DESIGN_OPTION9	0x40 +/* COMWAK GAP width window */ +#define RG_TG_MAX_MSK		GENMASK(20, 16) +#define RG_TG_MAX_VAL(x)	((0x1f & (x)) << 16) +/* COMINIT GAP width window */ +#define RG_T2_MAX_MSK		GENMASK(13, 8) +#define RG_T2_MAX_VAL(x)	((0x3f & (x)) << 8) +/* COMWAK GAP width window */ +#define RG_TG_MIN_MSK		GENMASK(7, 5) +#define RG_TG_MIN_VAL(x)	((0x7 & (x)) << 5) +/* COMINIT GAP width window */ +#define RG_T2_MIN_MSK		GENMASK(4, 0) +#define RG_T2_MIN_VAL(x)	(0x1f & (x)) + +#define ANA_RG_CTRL_SIGNAL1		0x4c +/* TX driver tail current control for 0dB de-empahsis mdoe for Gen1 speed */ +#define RG_IDRV_0DB_GEN1_MSK		GENMASK(13, 8) +#define RG_IDRV_0DB_GEN1_VAL(x)		((0x3f & (x)) << 8) + +#define ANA_RG_CTRL_SIGNAL4		0x58 +#define RG_CDR_BICLTR_GEN1_MSK		GENMASK(23, 20) +#define RG_CDR_BICLTR_GEN1_VAL(x)	((0xf & (x)) << 20) +/* Loop filter R1 resistance adjustment for Gen1 speed */ +#define RG_CDR_BR_GEN2_MSK		GENMASK(10, 8) +#define RG_CDR_BR_GEN2_VAL(x)		((0x7 & (x)) << 8) + +#define ANA_RG_CTRL_SIGNAL6		0x60 +/* I-path capacitance adjustment for Gen1 */ +#define RG_CDR_BC_GEN1_MSK		GENMASK(28, 24) +#define RG_CDR_BC_GEN1_VAL(x)		((0x1f & (x)) << 24) +#define RG_CDR_BIRLTR_GEN1_MSK		GENMASK(4, 0) +#define RG_CDR_BIRLTR_GEN1_VAL(x)	(0x1f & (x)) + +#define ANA_EQ_EYE_CTRL_SIGNAL1		0x6c +/* RX Gen1 LEQ tuning step */ +#define RG_EQ_DLEQ_LFI_GEN1_MSK		GENMASK(11, 8) +#define RG_EQ_DLEQ_LFI_GEN1_VAL(x)	((0xf & (x)) << 8) + +#define ANA_EQ_EYE_CTRL_SIGNAL4		0xd8 +#define RG_CDR_BIRLTD0_GEN1_MSK		GENMASK(20, 16) +#define RG_CDR_BIRLTD0_GEN1_VAL(x)	((0x1f & (x)) << 16) + +#define ANA_EQ_EYE_CTRL_SIGNAL5		0xdc +#define RG_CDR_BIRLTD0_GEN3_MSK		GENMASK(4, 0) +#define RG_CDR_BIRLTD0_GEN3_VAL(x)	(0x1f & (x)) + +enum mtk_phy_version { +	MTK_PHY_V1 = 1, +	MTK_PHY_V2,  }; -struct mt65xx_phy_pdata { +struct mtk_phy_pdata {  	/* avoid RX sensitivity level degradation only for mt8173 */  	bool avoid_rx_sen_degradation; -	enum mt_phy_version version; +	enum mtk_phy_version version;  };  struct u2phy_banks { @@ -175,7 +282,7 @@ struct u3phy_banks {  	void __iomem *phya; /* include u3phya_da */  }; -struct mt65xx_phy_instance { +struct mtk_phy_instance {  	struct phy *phy;  	void __iomem *port_base;  	union { @@ -187,18 +294,18 @@ struct mt65xx_phy_instance {  	u8 type;  }; -struct mt65xx_u3phy { +struct mtk_tphy {  	struct device *dev;  	void __iomem *sif_base;	/* only shared sif */  	/* deprecated, use @ref_clk instead in phy instance */  	struct clk *u3phya_ref;	/* reference clock of usb3 anolog phy */ -	const struct mt65xx_phy_pdata *pdata; -	struct mt65xx_phy_instance **phys; +	const struct mtk_phy_pdata *pdata; +	struct mtk_phy_instance **phys;  	int nphys;  }; -static void hs_slew_rate_calibrate(struct mt65xx_u3phy *u3phy, -	struct mt65xx_phy_instance *instance) +static void hs_slew_rate_calibrate(struct mtk_tphy *tphy, +	struct mtk_phy_instance *instance)  {  	struct u2phy_banks *u2_banks = &instance->u2_banks;  	void __iomem *fmreg = u2_banks->fmreg; @@ -222,7 +329,7 @@ static void hs_slew_rate_calibrate(struct mt65xx_u3phy *u3phy,  	tmp = readl(fmreg + U3P_U2FREQ_FMCR0);  	tmp &= ~(P2F_RG_CYCLECNT | P2F_RG_MONCLK_SEL);  	tmp |= P2F_RG_CYCLECNT_VAL(U3P_FM_DET_CYCLE_CNT); -	if (u3phy->pdata->version == MT_PHY_V1) +	if (tphy->pdata->version == MTK_PHY_V1)  		tmp |= P2F_RG_MONCLK_SEL_VAL(instance->index >> 1);  	writel(tmp, fmreg + U3P_U2FREQ_FMCR0); @@ -257,7 +364,7 @@ static void hs_slew_rate_calibrate(struct mt65xx_u3phy *u3phy,  		/* if FM detection fail, set default value */  		calibration_val = 4;  	} -	dev_dbg(u3phy->dev, "phy:%d, fm_out:%d, calib:%d\n", +	dev_dbg(tphy->dev, "phy:%d, fm_out:%d, calib:%d\n",  		instance->index, fm_out, calibration_val);  	/* set HS slew rate */ @@ -272,8 +379,8 @@ static void hs_slew_rate_calibrate(struct mt65xx_u3phy *u3phy,  	writel(tmp, com + U3P_USBPHYACR5);  } -static void u3_phy_instance_init(struct mt65xx_u3phy *u3phy, -	struct mt65xx_phy_instance *instance) +static void u3_phy_instance_init(struct mtk_tphy *tphy, +	struct mtk_phy_instance *instance)  {  	struct u3phy_banks *u3_banks = &instance->u3_banks;  	u32 tmp; @@ -319,11 +426,11 @@ static void u3_phy_instance_init(struct mt65xx_u3phy *u3phy,  	tmp |= P3D_RG_RXDET_STB2_SET_P3_VAL(0x10);  	writel(tmp, u3_banks->phyd + U3P_U3_PHYD_RXDET2); -	dev_dbg(u3phy->dev, "%s(%d)\n", __func__, instance->index); +	dev_dbg(tphy->dev, "%s(%d)\n", __func__, instance->index);  } -static void phy_instance_init(struct mt65xx_u3phy *u3phy, -	struct mt65xx_phy_instance *instance) +static void u2_phy_instance_init(struct mtk_tphy *tphy, +	struct mtk_phy_instance *instance)  {  	struct u2phy_banks *u2_banks = &instance->u2_banks;  	void __iomem *com = u2_banks->com; @@ -355,7 +462,7 @@ static void phy_instance_init(struct mt65xx_u3phy *u3phy,  		writel(tmp, com + U3P_U2PHYACR4);  	} -	if (u3phy->pdata->avoid_rx_sen_degradation) { +	if (tphy->pdata->avoid_rx_sen_degradation) {  		if (!index) {  			tmp = readl(com + U3P_USBPHYACR2);  			tmp |= PA2_RG_SIF_U2PLL_FORCE_EN; @@ -381,11 +488,11 @@ static void phy_instance_init(struct mt65xx_u3phy *u3phy,  	tmp |= PA6_RG_U2_SQTH_VAL(2);  	writel(tmp, com + U3P_USBPHYACR6); -	dev_dbg(u3phy->dev, "%s(%d)\n", __func__, index); +	dev_dbg(tphy->dev, "%s(%d)\n", __func__, index);  } -static void phy_instance_power_on(struct mt65xx_u3phy *u3phy, -	struct mt65xx_phy_instance *instance) +static void u2_phy_instance_power_on(struct mtk_tphy *tphy, +	struct mtk_phy_instance *instance)  {  	struct u2phy_banks *u2_banks = &instance->u2_banks;  	void __iomem *com = u2_banks->com; @@ -408,7 +515,7 @@ static void phy_instance_power_on(struct mt65xx_u3phy *u3phy,  	tmp &= ~P2C_RG_SESSEND;  	writel(tmp, com + U3P_U2PHYDTM1); -	if (u3phy->pdata->avoid_rx_sen_degradation && index) { +	if (tphy->pdata->avoid_rx_sen_degradation && index) {  		tmp = readl(com + U3D_U2PHYDCR0);  		tmp |= P2C_RG_SIF_U2PLL_FORCE_ON;  		writel(tmp, com + U3D_U2PHYDCR0); @@ -417,11 +524,11 @@ static void phy_instance_power_on(struct mt65xx_u3phy *u3phy,  		tmp |= P2C_RG_SUSPENDM | P2C_FORCE_SUSPENDM;  		writel(tmp, com + U3P_U2PHYDTM0);  	} -	dev_dbg(u3phy->dev, "%s(%d)\n", __func__, index); +	dev_dbg(tphy->dev, "%s(%d)\n", __func__, index);  } -static void phy_instance_power_off(struct mt65xx_u3phy *u3phy, -	struct mt65xx_phy_instance *instance) +static void u2_phy_instance_power_off(struct mtk_tphy *tphy, +	struct mtk_phy_instance *instance)  {  	struct u2phy_banks *u2_banks = &instance->u2_banks;  	void __iomem *com = u2_banks->com; @@ -449,24 +556,24 @@ static void phy_instance_power_off(struct mt65xx_u3phy *u3phy,  	tmp |= P2C_RG_SESSEND;  	writel(tmp, com + U3P_U2PHYDTM1); -	if (u3phy->pdata->avoid_rx_sen_degradation && index) { +	if (tphy->pdata->avoid_rx_sen_degradation && index) {  		tmp = readl(com + U3D_U2PHYDCR0);  		tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;  		writel(tmp, com + U3D_U2PHYDCR0);  	} -	dev_dbg(u3phy->dev, "%s(%d)\n", __func__, index); +	dev_dbg(tphy->dev, "%s(%d)\n", __func__, index);  } -static void phy_instance_exit(struct mt65xx_u3phy *u3phy, -	struct mt65xx_phy_instance *instance) +static void u2_phy_instance_exit(struct mtk_tphy *tphy, +	struct mtk_phy_instance *instance)  {  	struct u2phy_banks *u2_banks = &instance->u2_banks;  	void __iomem *com = u2_banks->com;  	u32 index = instance->index;  	u32 tmp; -	if (u3phy->pdata->avoid_rx_sen_degradation && index) { +	if (tphy->pdata->avoid_rx_sen_degradation && index) {  		tmp = readl(com + U3D_U2PHYDCR0);  		tmp &= ~P2C_RG_SIF_U2PLL_FORCE_ON;  		writel(tmp, com + U3D_U2PHYDCR0); @@ -477,109 +584,307 @@ static void phy_instance_exit(struct mt65xx_u3phy *u3phy,  	}  } -static void phy_v1_banks_init(struct mt65xx_u3phy *u3phy, -			      struct mt65xx_phy_instance *instance) +static void pcie_phy_instance_init(struct mtk_tphy *tphy, +	struct mtk_phy_instance *instance) +{ +	struct u3phy_banks *u3_banks = &instance->u3_banks; +	u32 tmp; + +	if (tphy->pdata->version != MTK_PHY_V1) +		return; + +	tmp = readl(u3_banks->phya + U3P_U3_PHYA_DA_REG0); +	tmp &= ~(P3A_RG_XTAL_EXT_PE1H | P3A_RG_XTAL_EXT_PE2H); +	tmp |= P3A_RG_XTAL_EXT_PE1H_VAL(0x2) | P3A_RG_XTAL_EXT_PE2H_VAL(0x2); +	writel(tmp, u3_banks->phya + U3P_U3_PHYA_DA_REG0); + +	/* ref clk drive */ +	tmp = readl(u3_banks->phya + U3P_U3_PHYA_REG1); +	tmp &= ~P3A_RG_CLKDRV_AMP; +	tmp |= P3A_RG_CLKDRV_AMP_VAL(0x4); +	writel(tmp, u3_banks->phya + U3P_U3_PHYA_REG1); + +	tmp = readl(u3_banks->phya + U3P_U3_PHYA_REG0); +	tmp &= ~P3A_RG_CLKDRV_OFF; +	tmp |= P3A_RG_CLKDRV_OFF_VAL(0x1); +	writel(tmp, u3_banks->phya + U3P_U3_PHYA_REG0); + +	/* SSC delta -5000ppm */ +	tmp = readl(u3_banks->phya + U3P_U3_PHYA_DA_REG20); +	tmp &= ~P3A_RG_PLL_DELTA1_PE2H; +	tmp |= P3A_RG_PLL_DELTA1_PE2H_VAL(0x3c); +	writel(tmp, u3_banks->phya + U3P_U3_PHYA_DA_REG20); + +	tmp = readl(u3_banks->phya + U3P_U3_PHYA_DA_REG25); +	tmp &= ~P3A_RG_PLL_DELTA_PE2H; +	tmp |= P3A_RG_PLL_DELTA_PE2H_VAL(0x36); +	writel(tmp, u3_banks->phya + U3P_U3_PHYA_DA_REG25); + +	/* change pll BW 0.6M */ +	tmp = readl(u3_banks->phya + U3P_U3_PHYA_DA_REG5); +	tmp &= ~(P3A_RG_PLL_BR_PE2H | P3A_RG_PLL_IC_PE2H); +	tmp |= P3A_RG_PLL_BR_PE2H_VAL(0x1) | P3A_RG_PLL_IC_PE2H_VAL(0x1); +	writel(tmp, u3_banks->phya + U3P_U3_PHYA_DA_REG5); + +	tmp = readl(u3_banks->phya + U3P_U3_PHYA_DA_REG4); +	tmp &= ~(P3A_RG_PLL_DIVEN_PE2H | P3A_RG_PLL_BC_PE2H); +	tmp |= P3A_RG_PLL_BC_PE2H_VAL(0x3); +	writel(tmp, u3_banks->phya + U3P_U3_PHYA_DA_REG4); + +	tmp = readl(u3_banks->phya + U3P_U3_PHYA_DA_REG6); +	tmp &= ~P3A_RG_PLL_IR_PE2H; +	tmp |= P3A_RG_PLL_IR_PE2H_VAL(0x2); +	writel(tmp, u3_banks->phya + U3P_U3_PHYA_DA_REG6); + +	tmp = readl(u3_banks->phya + U3P_U3_PHYA_DA_REG7); +	tmp &= ~P3A_RG_PLL_BP_PE2H; +	tmp |= P3A_RG_PLL_BP_PE2H_VAL(0xa); +	writel(tmp, u3_banks->phya + U3P_U3_PHYA_DA_REG7); + +	/* Tx Detect Rx Timing: 10us -> 5us */ +	tmp = readl(u3_banks->phyd + U3P_U3_PHYD_RXDET1); +	tmp &= ~P3D_RG_RXDET_STB2_SET; +	tmp |= P3D_RG_RXDET_STB2_SET_VAL(0x10); +	writel(tmp, u3_banks->phyd + U3P_U3_PHYD_RXDET1); + +	tmp = readl(u3_banks->phyd + U3P_U3_PHYD_RXDET2); +	tmp &= ~P3D_RG_RXDET_STB2_SET_P3; +	tmp |= P3D_RG_RXDET_STB2_SET_P3_VAL(0x10); +	writel(tmp, u3_banks->phyd + U3P_U3_PHYD_RXDET2); + +	/* wait for PCIe subsys register to active */ +	usleep_range(2500, 3000); +	dev_dbg(tphy->dev, "%s(%d)\n", __func__, instance->index); +} + +static void pcie_phy_instance_power_on(struct mtk_tphy *tphy, +	struct mtk_phy_instance *instance) +{ +	struct u3phy_banks *bank = &instance->u3_banks; +	u32 tmp; + +	tmp = readl(bank->chip + U3P_U3_CHIP_GPIO_CTLD); +	tmp &= ~(P3C_FORCE_IP_SW_RST | P3C_MCU_BUS_CK_GATE_EN | +		P3C_REG_IP_SW_RST); +	writel(tmp, bank->chip + U3P_U3_CHIP_GPIO_CTLD); + +	tmp = readl(bank->chip + U3P_U3_CHIP_GPIO_CTLE); +	tmp &= ~(P3C_RG_SWRST_U3_PHYD_FORCE_EN | P3C_RG_SWRST_U3_PHYD); +	writel(tmp, bank->chip + U3P_U3_CHIP_GPIO_CTLE); +} + +static void pcie_phy_instance_power_off(struct mtk_tphy *tphy, +	struct mtk_phy_instance *instance) + +{ +	struct u3phy_banks *bank = &instance->u3_banks; +	u32 tmp; + +	tmp = readl(bank->chip + U3P_U3_CHIP_GPIO_CTLD); +	tmp |= P3C_FORCE_IP_SW_RST | P3C_REG_IP_SW_RST; +	writel(tmp, bank->chip + U3P_U3_CHIP_GPIO_CTLD); + +	tmp = readl(bank->chip + U3P_U3_CHIP_GPIO_CTLE); +	tmp |= P3C_RG_SWRST_U3_PHYD_FORCE_EN | P3C_RG_SWRST_U3_PHYD; +	writel(tmp, bank->chip + U3P_U3_CHIP_GPIO_CTLE); +} + +static void sata_phy_instance_init(struct mtk_tphy *tphy, +	struct mtk_phy_instance *instance) +{ +	struct u3phy_banks *u3_banks = &instance->u3_banks; +	void __iomem *phyd = u3_banks->phyd; +	u32 tmp; + +	/* charge current adjustment */ +	tmp = readl(phyd + ANA_RG_CTRL_SIGNAL6); +	tmp &= ~(RG_CDR_BIRLTR_GEN1_MSK | RG_CDR_BC_GEN1_MSK); +	tmp |= RG_CDR_BIRLTR_GEN1_VAL(0x6) | RG_CDR_BC_GEN1_VAL(0x1a); +	writel(tmp, phyd + ANA_RG_CTRL_SIGNAL6); + +	tmp = readl(phyd + ANA_EQ_EYE_CTRL_SIGNAL4); +	tmp &= ~RG_CDR_BIRLTD0_GEN1_MSK; +	tmp |= RG_CDR_BIRLTD0_GEN1_VAL(0x18); +	writel(tmp, phyd + ANA_EQ_EYE_CTRL_SIGNAL4); + +	tmp = readl(phyd + ANA_EQ_EYE_CTRL_SIGNAL5); +	tmp &= ~RG_CDR_BIRLTD0_GEN3_MSK; +	tmp |= RG_CDR_BIRLTD0_GEN3_VAL(0x06); +	writel(tmp, phyd + ANA_EQ_EYE_CTRL_SIGNAL5); + +	tmp = readl(phyd + ANA_RG_CTRL_SIGNAL4); +	tmp &= ~(RG_CDR_BICLTR_GEN1_MSK | RG_CDR_BR_GEN2_MSK); +	tmp |= RG_CDR_BICLTR_GEN1_VAL(0x0c) | RG_CDR_BR_GEN2_VAL(0x07); +	writel(tmp, phyd + ANA_RG_CTRL_SIGNAL4); + +	tmp = readl(phyd + PHYD_CTRL_SIGNAL_MODE4); +	tmp &= ~(RG_CDR_BICLTD0_GEN1_MSK | RG_CDR_BICLTD1_GEN1_MSK); +	tmp |= RG_CDR_BICLTD0_GEN1_VAL(0x08) | RG_CDR_BICLTD1_GEN1_VAL(0x02); +	writel(tmp, phyd + PHYD_CTRL_SIGNAL_MODE4); + +	tmp = readl(phyd + PHYD_DESIGN_OPTION2); +	tmp &= ~RG_LOCK_CNT_SEL_MSK; +	tmp |= RG_LOCK_CNT_SEL_VAL(0x02); +	writel(tmp, phyd + PHYD_DESIGN_OPTION2); + +	tmp = readl(phyd + PHYD_DESIGN_OPTION9); +	tmp &= ~(RG_T2_MIN_MSK | RG_TG_MIN_MSK | +		 RG_T2_MAX_MSK | RG_TG_MAX_MSK); +	tmp |= RG_T2_MIN_VAL(0x12) | RG_TG_MIN_VAL(0x04) | +	       RG_T2_MAX_VAL(0x31) | RG_TG_MAX_VAL(0x0e); +	writel(tmp, phyd + PHYD_DESIGN_OPTION9); + +	tmp = readl(phyd + ANA_RG_CTRL_SIGNAL1); +	tmp &= ~RG_IDRV_0DB_GEN1_MSK; +	tmp |= RG_IDRV_0DB_GEN1_VAL(0x20); +	writel(tmp, phyd + ANA_RG_CTRL_SIGNAL1); + +	tmp = readl(phyd + ANA_EQ_EYE_CTRL_SIGNAL1); +	tmp &= ~RG_EQ_DLEQ_LFI_GEN1_MSK; +	tmp |= RG_EQ_DLEQ_LFI_GEN1_VAL(0x03); +	writel(tmp, phyd + ANA_EQ_EYE_CTRL_SIGNAL1); + +	dev_dbg(tphy->dev, "%s(%d)\n", __func__, instance->index); +} + +static void phy_v1_banks_init(struct mtk_tphy *tphy, +			      struct mtk_phy_instance *instance)  {  	struct u2phy_banks *u2_banks = &instance->u2_banks;  	struct u3phy_banks *u3_banks = &instance->u3_banks; -	if (instance->type == PHY_TYPE_USB2) { +	switch (instance->type) { +	case PHY_TYPE_USB2:  		u2_banks->misc = NULL; -		u2_banks->fmreg = u3phy->sif_base + SSUSB_SIFSLV_V1_U2FREQ; +		u2_banks->fmreg = tphy->sif_base + SSUSB_SIFSLV_V1_U2FREQ;  		u2_banks->com = instance->port_base + SSUSB_SIFSLV_V1_U2PHY_COM; -	} else if (instance->type == PHY_TYPE_USB3) { -		u3_banks->spllc = u3phy->sif_base + SSUSB_SIFSLV_V1_SPLLC; +		break; +	case PHY_TYPE_USB3: +	case PHY_TYPE_PCIE: +		u3_banks->spllc = tphy->sif_base + SSUSB_SIFSLV_V1_SPLLC;  		u3_banks->chip = NULL;  		u3_banks->phyd = instance->port_base + SSUSB_SIFSLV_V1_U3PHYD;  		u3_banks->phya = instance->port_base + SSUSB_SIFSLV_V1_U3PHYA; +		break; +	case PHY_TYPE_SATA: +		u3_banks->phyd = instance->port_base + SSUSB_SIFSLV_V1_U3PHYD; +		break; +	default: +		dev_err(tphy->dev, "incompatible PHY type\n"); +		return;  	}  } -static void phy_v2_banks_init(struct mt65xx_u3phy *u3phy, -			      struct mt65xx_phy_instance *instance) +static void phy_v2_banks_init(struct mtk_tphy *tphy, +			      struct mtk_phy_instance *instance)  {  	struct u2phy_banks *u2_banks = &instance->u2_banks;  	struct u3phy_banks *u3_banks = &instance->u3_banks; -	if (instance->type == PHY_TYPE_USB2) { +	switch (instance->type) { +	case PHY_TYPE_USB2:  		u2_banks->misc = instance->port_base + SSUSB_SIFSLV_V2_MISC;  		u2_banks->fmreg = instance->port_base + SSUSB_SIFSLV_V2_U2FREQ;  		u2_banks->com = instance->port_base + SSUSB_SIFSLV_V2_U2PHY_COM; -	} else if (instance->type == PHY_TYPE_USB3) { +		break; +	case PHY_TYPE_USB3: +	case PHY_TYPE_PCIE:  		u3_banks->spllc = instance->port_base + SSUSB_SIFSLV_V2_SPLLC;  		u3_banks->chip = instance->port_base + SSUSB_SIFSLV_V2_CHIP;  		u3_banks->phyd = instance->port_base + SSUSB_SIFSLV_V2_U3PHYD;  		u3_banks->phya = instance->port_base + SSUSB_SIFSLV_V2_U3PHYA; +		break; +	default: +		dev_err(tphy->dev, "incompatible PHY type\n"); +		return;  	}  } -static int mt65xx_phy_init(struct phy *phy) +static int mtk_phy_init(struct phy *phy)  { -	struct mt65xx_phy_instance *instance = phy_get_drvdata(phy); -	struct mt65xx_u3phy *u3phy = dev_get_drvdata(phy->dev.parent); +	struct mtk_phy_instance *instance = phy_get_drvdata(phy); +	struct mtk_tphy *tphy = dev_get_drvdata(phy->dev.parent);  	int ret; -	ret = clk_prepare_enable(u3phy->u3phya_ref); +	ret = clk_prepare_enable(tphy->u3phya_ref);  	if (ret) { -		dev_err(u3phy->dev, "failed to enable u3phya_ref\n"); +		dev_err(tphy->dev, "failed to enable u3phya_ref\n");  		return ret;  	}  	ret = clk_prepare_enable(instance->ref_clk);  	if (ret) { -		dev_err(u3phy->dev, "failed to enable ref_clk\n"); +		dev_err(tphy->dev, "failed to enable ref_clk\n");  		return ret;  	} -	if (instance->type == PHY_TYPE_USB2) -		phy_instance_init(u3phy, instance); -	else -		u3_phy_instance_init(u3phy, instance); +	switch (instance->type) { +	case PHY_TYPE_USB2: +		u2_phy_instance_init(tphy, instance); +		break; +	case PHY_TYPE_USB3: +		u3_phy_instance_init(tphy, instance); +		break; +	case PHY_TYPE_PCIE: +		pcie_phy_instance_init(tphy, instance); +		break; +	case PHY_TYPE_SATA: +		sata_phy_instance_init(tphy, instance); +		break; +	default: +		dev_err(tphy->dev, "incompatible PHY type\n"); +		return -EINVAL; +	}  	return 0;  } -static int mt65xx_phy_power_on(struct phy *phy) +static int mtk_phy_power_on(struct phy *phy)  { -	struct mt65xx_phy_instance *instance = phy_get_drvdata(phy); -	struct mt65xx_u3phy *u3phy = dev_get_drvdata(phy->dev.parent); +	struct mtk_phy_instance *instance = phy_get_drvdata(phy); +	struct mtk_tphy *tphy = dev_get_drvdata(phy->dev.parent);  	if (instance->type == PHY_TYPE_USB2) { -		phy_instance_power_on(u3phy, instance); -		hs_slew_rate_calibrate(u3phy, instance); +		u2_phy_instance_power_on(tphy, instance); +		hs_slew_rate_calibrate(tphy, instance); +	} else if (instance->type == PHY_TYPE_PCIE) { +		pcie_phy_instance_power_on(tphy, instance);  	} +  	return 0;  } -static int mt65xx_phy_power_off(struct phy *phy) +static int mtk_phy_power_off(struct phy *phy)  { -	struct mt65xx_phy_instance *instance = phy_get_drvdata(phy); -	struct mt65xx_u3phy *u3phy = dev_get_drvdata(phy->dev.parent); +	struct mtk_phy_instance *instance = phy_get_drvdata(phy); +	struct mtk_tphy *tphy = dev_get_drvdata(phy->dev.parent);  	if (instance->type == PHY_TYPE_USB2) -		phy_instance_power_off(u3phy, instance); +		u2_phy_instance_power_off(tphy, instance); +	else if (instance->type == PHY_TYPE_PCIE) +		pcie_phy_instance_power_off(tphy, instance);  	return 0;  } -static int mt65xx_phy_exit(struct phy *phy) +static int mtk_phy_exit(struct phy *phy)  { -	struct mt65xx_phy_instance *instance = phy_get_drvdata(phy); -	struct mt65xx_u3phy *u3phy = dev_get_drvdata(phy->dev.parent); +	struct mtk_phy_instance *instance = phy_get_drvdata(phy); +	struct mtk_tphy *tphy = dev_get_drvdata(phy->dev.parent);  	if (instance->type == PHY_TYPE_USB2) -		phy_instance_exit(u3phy, instance); +		u2_phy_instance_exit(tphy, instance);  	clk_disable_unprepare(instance->ref_clk); -	clk_disable_unprepare(u3phy->u3phya_ref); +	clk_disable_unprepare(tphy->u3phya_ref);  	return 0;  } -static struct phy *mt65xx_phy_xlate(struct device *dev, +static struct phy *mtk_phy_xlate(struct device *dev,  					struct of_phandle_args *args)  { -	struct mt65xx_u3phy *u3phy = dev_get_drvdata(dev); -	struct mt65xx_phy_instance *instance = NULL; +	struct mtk_tphy *tphy = dev_get_drvdata(dev); +	struct mtk_phy_instance *instance = NULL;  	struct device_node *phy_np = args->np;  	int index; @@ -588,9 +893,9 @@ static struct phy *mt65xx_phy_xlate(struct device *dev,  		return ERR_PTR(-EINVAL);  	} -	for (index = 0; index < u3phy->nphys; index++) -		if (phy_np == u3phy->phys[index]->phy->dev.of_node) { -			instance = u3phy->phys[index]; +	for (index = 0; index < tphy->nphys; index++) +		if (phy_np == tphy->phys[index]->phy->dev.of_node) { +			instance = tphy->phys[index];  			break;  		} @@ -601,15 +906,17 @@ static struct phy *mt65xx_phy_xlate(struct device *dev,  	instance->type = args->args[0];  	if (!(instance->type == PHY_TYPE_USB2 || -	      instance->type == PHY_TYPE_USB3)) { +	      instance->type == PHY_TYPE_USB3 || +	      instance->type == PHY_TYPE_PCIE || +	      instance->type == PHY_TYPE_SATA)) {  		dev_err(dev, "unsupported device type: %d\n", instance->type);  		return ERR_PTR(-EINVAL);  	} -	if (u3phy->pdata->version == MT_PHY_V1) { -		phy_v1_banks_init(u3phy, instance); -	} else if (u3phy->pdata->version == MT_PHY_V2) { -		phy_v2_banks_init(u3phy, instance); +	if (tphy->pdata->version == MTK_PHY_V1) { +		phy_v1_banks_init(tphy, instance); +	} else if (tphy->pdata->version == MTK_PHY_V2) { +		phy_v2_banks_init(tphy, instance);  	} else {  		dev_err(dev, "phy version is not supported\n");  		return ERR_PTR(-EINVAL); @@ -618,38 +925,40 @@ static struct phy *mt65xx_phy_xlate(struct device *dev,  	return instance->phy;  } -static const struct phy_ops mt65xx_u3phy_ops = { -	.init		= mt65xx_phy_init, -	.exit		= mt65xx_phy_exit, -	.power_on	= mt65xx_phy_power_on, -	.power_off	= mt65xx_phy_power_off, +static const struct phy_ops mtk_tphy_ops = { +	.init		= mtk_phy_init, +	.exit		= mtk_phy_exit, +	.power_on	= mtk_phy_power_on, +	.power_off	= mtk_phy_power_off,  	.owner		= THIS_MODULE,  }; -static const struct mt65xx_phy_pdata mt2701_pdata = { +static const struct mtk_phy_pdata tphy_v1_pdata = {  	.avoid_rx_sen_degradation = false, -	.version = MT_PHY_V1, +	.version = MTK_PHY_V1,  }; -static const struct mt65xx_phy_pdata mt2712_pdata = { +static const struct mtk_phy_pdata tphy_v2_pdata = {  	.avoid_rx_sen_degradation = false, -	.version = MT_PHY_V2, +	.version = MTK_PHY_V2,  }; -static const struct mt65xx_phy_pdata mt8173_pdata = { +static const struct mtk_phy_pdata mt8173_pdata = {  	.avoid_rx_sen_degradation = true, -	.version = MT_PHY_V1, +	.version = MTK_PHY_V1,  }; -static const struct of_device_id mt65xx_u3phy_id_table[] = { -	{ .compatible = "mediatek,mt2701-u3phy", .data = &mt2701_pdata }, -	{ .compatible = "mediatek,mt2712-u3phy", .data = &mt2712_pdata }, +static const struct of_device_id mtk_tphy_id_table[] = { +	{ .compatible = "mediatek,mt2701-u3phy", .data = &tphy_v1_pdata }, +	{ .compatible = "mediatek,mt2712-u3phy", .data = &tphy_v2_pdata },  	{ .compatible = "mediatek,mt8173-u3phy", .data = &mt8173_pdata }, +	{ .compatible = "mediatek,generic-tphy-v1", .data = &tphy_v1_pdata }, +	{ .compatible = "mediatek,generic-tphy-v2", .data = &tphy_v2_pdata },  	{ },  }; -MODULE_DEVICE_TABLE(of, mt65xx_u3phy_id_table); +MODULE_DEVICE_TABLE(of, mtk_tphy_id_table); -static int mt65xx_u3phy_probe(struct platform_device *pdev) +static int mtk_tphy_probe(struct platform_device *pdev)  {  	const struct of_device_id *match;  	struct device *dev = &pdev->dev; @@ -657,50 +966,50 @@ static int mt65xx_u3phy_probe(struct platform_device *pdev)  	struct device_node *child_np;  	struct phy_provider *provider;  	struct resource *sif_res; -	struct mt65xx_u3phy *u3phy; +	struct mtk_tphy *tphy;  	struct resource res;  	int port, retval; -	match = of_match_node(mt65xx_u3phy_id_table, pdev->dev.of_node); +	match = of_match_node(mtk_tphy_id_table, pdev->dev.of_node);  	if (!match)  		return -EINVAL; -	u3phy = devm_kzalloc(dev, sizeof(*u3phy), GFP_KERNEL); -	if (!u3phy) +	tphy = devm_kzalloc(dev, sizeof(*tphy), GFP_KERNEL); +	if (!tphy)  		return -ENOMEM; -	u3phy->pdata = match->data; -	u3phy->nphys = of_get_child_count(np); -	u3phy->phys = devm_kcalloc(dev, u3phy->nphys, -				       sizeof(*u3phy->phys), GFP_KERNEL); -	if (!u3phy->phys) +	tphy->pdata = match->data; +	tphy->nphys = of_get_child_count(np); +	tphy->phys = devm_kcalloc(dev, tphy->nphys, +				       sizeof(*tphy->phys), GFP_KERNEL); +	if (!tphy->phys)  		return -ENOMEM; -	u3phy->dev = dev; -	platform_set_drvdata(pdev, u3phy); +	tphy->dev = dev; +	platform_set_drvdata(pdev, tphy); -	if (u3phy->pdata->version == MT_PHY_V1) { +	if (tphy->pdata->version == MTK_PHY_V1) {  		/* get banks shared by multiple phys */  		sif_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -		u3phy->sif_base = devm_ioremap_resource(dev, sif_res); -		if (IS_ERR(u3phy->sif_base)) { +		tphy->sif_base = devm_ioremap_resource(dev, sif_res); +		if (IS_ERR(tphy->sif_base)) {  			dev_err(dev, "failed to remap sif regs\n"); -			return PTR_ERR(u3phy->sif_base); +			return PTR_ERR(tphy->sif_base);  		}  	}  	/* it's deprecated, make it optional for backward compatibility */ -	u3phy->u3phya_ref = devm_clk_get(dev, "u3phya_ref"); -	if (IS_ERR(u3phy->u3phya_ref)) { -		if (PTR_ERR(u3phy->u3phya_ref) == -EPROBE_DEFER) +	tphy->u3phya_ref = devm_clk_get(dev, "u3phya_ref"); +	if (IS_ERR(tphy->u3phya_ref)) { +		if (PTR_ERR(tphy->u3phya_ref) == -EPROBE_DEFER)  			return -EPROBE_DEFER; -		u3phy->u3phya_ref = NULL; +		tphy->u3phya_ref = NULL;  	}  	port = 0;  	for_each_child_of_node(np, child_np) { -		struct mt65xx_phy_instance *instance; +		struct mtk_phy_instance *instance;  		struct phy *phy;  		instance = devm_kzalloc(dev, sizeof(*instance), GFP_KERNEL); @@ -709,9 +1018,9 @@ static int mt65xx_u3phy_probe(struct platform_device *pdev)  			goto put_child;  		} -		u3phy->phys[port] = instance; +		tphy->phys[port] = instance; -		phy = devm_phy_create(dev, child_np, &mt65xx_u3phy_ops); +		phy = devm_phy_create(dev, child_np, &mtk_tphy_ops);  		if (IS_ERR(phy)) {  			dev_err(dev, "failed to create phy\n");  			retval = PTR_ERR(phy); @@ -738,7 +1047,7 @@ static int mt65xx_u3phy_probe(struct platform_device *pdev)  		port++;  		/* if deprecated clock is provided, ignore instance's one */ -		if (u3phy->u3phya_ref) +		if (tphy->u3phya_ref)  			continue;  		instance->ref_clk = devm_clk_get(&phy->dev, "ref"); @@ -749,7 +1058,7 @@ static int mt65xx_u3phy_probe(struct platform_device *pdev)  		}  	} -	provider = devm_of_phy_provider_register(dev, mt65xx_phy_xlate); +	provider = devm_of_phy_provider_register(dev, mtk_phy_xlate);  	return PTR_ERR_OR_ZERO(provider);  put_child: @@ -757,16 +1066,16 @@ put_child:  	return retval;  } -static struct platform_driver mt65xx_u3phy_driver = { -	.probe		= mt65xx_u3phy_probe, +static struct platform_driver mtk_tphy_driver = { +	.probe		= mtk_tphy_probe,  	.driver		= { -		.name	= "mt65xx-u3phy", -		.of_match_table = mt65xx_u3phy_id_table, +		.name	= "mtk-tphy", +		.of_match_table = mtk_tphy_id_table,  	},  }; -module_platform_driver(mt65xx_u3phy_driver); +module_platform_driver(mtk_tphy_driver);  MODULE_AUTHOR("Chunfeng Yun <[email protected]>"); -MODULE_DESCRIPTION("mt65xx USB PHY driver"); +MODULE_DESCRIPTION("MediaTek T-PHY driver");  MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/motorola/phy-cpcap-usb.c b/drivers/phy/motorola/phy-cpcap-usb.c index 9b63efa5ae4d..accaaaccb662 100644 --- a/drivers/phy/motorola/phy-cpcap-usb.c +++ b/drivers/phy/motorola/phy-cpcap-usb.c @@ -506,7 +506,7 @@ static void cpcap_usb_init_optional_gpios(struct cpcap_phy_ddata *ddata)  		if (IS_ERR(ddata->gpio[i])) {  			dev_info(ddata->dev, "no mode change GPIO%i: %li\n",  				 i, PTR_ERR(ddata->gpio[i])); -				 ddata->gpio[i] = NULL; +			ddata->gpio[i] = NULL;  		}  	}  } diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c index 78ca62897784..e17f0351ccc2 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp.c @@ -59,6 +59,7 @@  #define QSERDES_COM_PLL_RCTRL_MODE1			0x088  #define QSERDES_COM_PLL_CCTRL_MODE0			0x090  #define QSERDES_COM_PLL_CCTRL_MODE1			0x094 +#define QSERDES_COM_BIAS_EN_CTRL_BY_PSM			0x0a8  #define QSERDES_COM_SYSCLK_EN_SEL			0x0ac  #define QSERDES_COM_RESETSM_CNTRL			0x0b4  #define QSERDES_COM_RESTRIM_CTRL			0x0bc @@ -143,6 +144,11 @@  #define QPHY_LOCK_DETECT_CONFIG3			0x88  #define QPHY_PWRUP_RESET_DLY_TIME_AUXCLK		0xa0  #define QPHY_LP_WAKEUP_DLY_TIME_AUXCLK			0xa4 +#define QPHY_PLL_LOCK_CHK_DLY_TIME_AUXCLK_LSB		0x1A8 +#define QPHY_OSC_DTCT_ACTIONS				0x1AC +#define QPHY_RX_SIGDET_LVL				0x1D8 +#define QPHY_L1SS_WAKEUP_DLY_TIME_AUXCLK_LSB		0x1DC +#define QPHY_L1SS_WAKEUP_DLY_TIME_AUXCLK_MSB		0x1E0  /* QPHY_SW_RESET bit */  #define SW_RESET				BIT(0) @@ -382,6 +388,85 @@ static const struct qmp_phy_init_tbl msm8996_usb3_pcs_tbl[] = {  	QMP_PHY_INIT_CFG(QPHY_POWER_STATE_CONFIG2, 0x08),  }; +static const struct qmp_phy_init_tbl ipq8074_pcie_serdes_tbl[] = { +	QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x18), +	QMP_PHY_INIT_CFG(QSERDES_COM_CLK_ENABLE1, 0x10), +	QMP_PHY_INIT_CFG(QSERDES_COM_BG_TRIM, 0xf), +	QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_EN, 0x1), +	QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x0), +	QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER1, 0x1f), +	QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_TIMER2, 0x3f), +	QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x6), +	QMP_PHY_INIT_CFG(QSERDES_COM_PLL_IVCO, 0xf), +	QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x0), +	QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x1), +	QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x20), +	QMP_PHY_INIT_CFG(QSERDES_COM_CORECLK_DIV, 0xa), +	QMP_PHY_INIT_CFG(QSERDES_COM_RESETSM_CNTRL, 0x20), +	QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0xa), +	QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0xa), +	QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x82), +	QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x3), +	QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x55), +	QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x55), +	QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x0), +	QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0xD), +	QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0xD04), +	QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x33), +	QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x2), +	QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_BUF_ENABLE, 0x1f), +	QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0xb), +	QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16), +	QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28), +	QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x0), +	QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80), +	QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CTRL_BY_PSM, 0x1), +	QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_CTRL, 0xa), +	QMP_PHY_INIT_CFG(QSERDES_COM_SSC_EN_CENTER, 0x1), +	QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER1, 0x31), +	QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER2, 0x1), +	QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER1, 0x2), +	QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER2, 0x0), +	QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE1, 0x2f), +	QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE2, 0x19), +	QMP_PHY_INIT_CFG(QSERDES_COM_CLK_EP_DIV, 0x19), +	QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_CNTRL, 0x7), +}; + +static const struct qmp_phy_init_tbl ipq8074_pcie_tx_tbl[] = { +	QMP_PHY_INIT_CFG(QSERDES_TX_HIGHZ_TRANSCEIVEREN_BIAS_DRVR_EN, 0x45), +	QMP_PHY_INIT_CFG(QSERDES_TX_LANE_MODE, 0x6), +	QMP_PHY_INIT_CFG(QSERDES_TX_RES_CODE_LANE_OFFSET, 0x2), +	QMP_PHY_INIT_CFG(QSERDES_TX_RCV_DETECT_LVL_2, 0x12), +}; + +static const struct qmp_phy_init_tbl ipq8074_pcie_rx_tbl[] = { +	QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_ENABLES, 0x1c), +	QMP_PHY_INIT_CFG(QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x14), +	QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x1), +	QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL3, 0x0), +	QMP_PHY_INIT_CFG(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL4, 0xdb), +	QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x4b), +	QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SO_GAIN, 0x4), +	QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_SO_GAIN_HALF, 0x4), +}; + +static const struct qmp_phy_init_tbl ipq8074_pcie_pcs_tbl[] = { +	QMP_PHY_INIT_CFG(QPHY_ENDPOINT_REFCLK_DRIVE, 0x4), +	QMP_PHY_INIT_CFG(QPHY_OSC_DTCT_ACTIONS, 0x0), +	QMP_PHY_INIT_CFG(QPHY_PWRUP_RESET_DLY_TIME_AUXCLK, 0x40), +	QMP_PHY_INIT_CFG(QPHY_L1SS_WAKEUP_DLY_TIME_AUXCLK_MSB, 0x0), +	QMP_PHY_INIT_CFG(QPHY_L1SS_WAKEUP_DLY_TIME_AUXCLK_LSB, 0x40), +	QMP_PHY_INIT_CFG(QPHY_PLL_LOCK_CHK_DLY_TIME_AUXCLK_LSB, 0x0), +	QMP_PHY_INIT_CFG(QPHY_LP_WAKEUP_DLY_TIME_AUXCLK, 0x40), +	QMP_PHY_INIT_CFG_L(QPHY_PLL_LOCK_CHK_DLY_TIME, 0x73), +	QMP_PHY_INIT_CFG(QPHY_RX_SIGDET_LVL, 0x99), +	QMP_PHY_INIT_CFG(QPHY_TXDEEMPH_M6DB_V0, 0x15), +	QMP_PHY_INIT_CFG(QPHY_TXDEEMPH_M3P5DB_V0, 0xe), +	QMP_PHY_INIT_CFG_L(QPHY_SW_RESET, 0x0), +	QMP_PHY_INIT_CFG_L(QPHY_START_CTRL, 0x3), +}; +  /* struct qmp_phy_cfg - per-PHY initialization config */  struct qmp_phy_cfg {  	/* phy-type - PCIE/UFS/USB */ @@ -580,6 +665,42 @@ static const struct qmp_phy_cfg msm8996_usb3phy_cfg = {  	.mask_pcs_ready		= PHYSTATUS,  }; +/* list of resets */ +static const char * const ipq8074_pciephy_reset_l[] = { +	"phy", "common", +}; + +static const struct qmp_phy_cfg ipq8074_pciephy_cfg = { +	.type			= PHY_TYPE_PCIE, +	.nlanes			= 1, + +	.serdes_tbl		= ipq8074_pcie_serdes_tbl, +	.serdes_tbl_num		= ARRAY_SIZE(ipq8074_pcie_serdes_tbl), +	.tx_tbl			= ipq8074_pcie_tx_tbl, +	.tx_tbl_num		= ARRAY_SIZE(ipq8074_pcie_tx_tbl), +	.rx_tbl			= ipq8074_pcie_rx_tbl, +	.rx_tbl_num		= ARRAY_SIZE(ipq8074_pcie_rx_tbl), +	.pcs_tbl		= ipq8074_pcie_pcs_tbl, +	.pcs_tbl_num		= ARRAY_SIZE(ipq8074_pcie_pcs_tbl), +	.clk_list		= NULL, +	.num_clks		= 0, +	.reset_list		= ipq8074_pciephy_reset_l, +	.num_resets		= ARRAY_SIZE(ipq8074_pciephy_reset_l), +	.vreg_list		= NULL, +	.num_vregs		= 0, +	.regs			= pciephy_regs_layout, + +	.start_ctrl		= SERDES_START | PCS_START, +	.pwrdn_ctrl		= SW_PWRDN | REFCLK_DRV_DSBL, +	.mask_pcs_ready		= PHYSTATUS, + +	.has_phy_com_ctrl	= false, +	.has_lane_rst		= false, +	.has_pwrdn_delay	= true, +	.pwrdn_delay_min	= 995,		/* us */ +	.pwrdn_delay_max	= 1005,		/* us */ +}; +  static void qcom_qmp_phy_configure(void __iomem *base,  				   const unsigned int *regs,  				   const struct qmp_phy_init_tbl tbl[], @@ -654,8 +775,6 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)  		if (ret) {  			dev_err(qmp->dev, "%s reset deassert failed\n",  				qmp->cfg->reset_list[i]); -			while (--i >= 0) -				reset_control_assert(qmp->resets[i]);  			goto err_rst;  		}  	} @@ -684,7 +803,7 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)  		if (ret) {  			dev_err(qmp->dev,  				"phy common block init timed-out\n"); -			goto err_com_init; +			goto err_rst;  		}  	} @@ -692,11 +811,11 @@ static int qcom_qmp_phy_com_init(struct qcom_qmp *qmp)  	return 0; -err_com_init: +err_rst:  	while (--i >= 0)  		reset_control_assert(qmp->resets[i]); -err_rst:  	mutex_unlock(&qmp->phy_mutex); +  	return ret;  } @@ -749,14 +868,13 @@ static int qcom_qmp_phy_init(struct phy *phy)  		if (ret) {  			dev_err(qmp->dev, "failed to enable %s clk, err=%d\n",  				qmp->cfg->clk_list[i], ret); -			while (--i >= 0) -				clk_disable_unprepare(qmp->clks[i]); +			goto err_clk;  		}  	}  	ret = qcom_qmp_phy_com_init(qmp);  	if (ret) -		goto err_com_init; +		goto err_clk;  	if (cfg->has_lane_rst) {  		ret = reset_control_deassert(qphy->lane_rst); @@ -804,7 +922,7 @@ err_pcs_ready:  		reset_control_assert(qphy->lane_rst);  err_lane_rst:  	qcom_qmp_phy_com_exit(qmp); -err_com_init: +err_clk:  	while (--i >= 0)  		clk_disable_unprepare(qmp->clks[i]); @@ -925,29 +1043,28 @@ static int qcom_qmp_phy_clk_init(struct device *dev)   *    clk  |   +-------+   |                   +-----+   *         +---------------+   */ -static int phy_pipe_clk_register(struct qcom_qmp *qmp, int id) +static int phy_pipe_clk_register(struct qcom_qmp *qmp, struct device_node *np)  { -	char name[24];  	struct clk_fixed_rate *fixed;  	struct clk_init_data init = { }; +	int ret; -	switch (qmp->cfg->type) { -	case PHY_TYPE_USB3: -		snprintf(name, sizeof(name), "usb3_phy_pipe_clk_src"); -		break; -	case PHY_TYPE_PCIE: -		snprintf(name, sizeof(name), "pcie_%d_pipe_clk_src", id); -		break; -	default: +	if ((qmp->cfg->type != PHY_TYPE_USB3) && +	    (qmp->cfg->type != PHY_TYPE_PCIE)) {  		/* not all phys register pipe clocks, so return success */  		return 0;  	} +	ret = of_property_read_string(np, "clock-output-names", &init.name); +	if (ret) { +		dev_err(qmp->dev, "%s: No clock-output-names\n", np->name); +		return ret; +	} +  	fixed = devm_kzalloc(qmp->dev, sizeof(*fixed), GFP_KERNEL);  	if (!fixed)  		return -ENOMEM; -	init.name = name;  	init.ops = &clk_fixed_rate_ops;  	/* controllers using QMP phys use 125MHz pipe clock interface */ @@ -1049,6 +1166,9 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = {  	}, {  		.compatible = "qcom,msm8996-qmp-usb3-phy",  		.data = &msm8996_usb3phy_cfg, +	}, { +		.compatible = "qcom,ipq8074-qmp-pcie-phy", +		.data = &ipq8074_pciephy_cfg,  	},  	{ },  }; @@ -1122,7 +1242,7 @@ static int qcom_qmp_phy_probe(struct platform_device *pdev)  		 * Register the pipe clock provided by phy.  		 * See function description to see details of this pipe clock.  		 */ -		ret = phy_pipe_clk_register(qmp, id); +		ret = phy_pipe_clk_register(qmp, child);  		if (ret) {  			dev_err(qmp->dev,  				"failed to register pipe clock source\n"); diff --git a/drivers/phy/ralink/Kconfig b/drivers/phy/ralink/Kconfig new file mode 100644 index 000000000000..b17635b407bc --- /dev/null +++ b/drivers/phy/ralink/Kconfig @@ -0,0 +1,11 @@ +# +# PHY drivers for Ralink platforms. +# +config PHY_RALINK_USB +	tristate "Ralink USB PHY driver" +	depends on RALINK || COMPILE_TEST +	select GENERIC_PHY +	select MFD_SYSCON +	help +	  This option enables support for the Ralink USB PHY found inside +	  RT3352, MT7620, MT7628 and MT7688. diff --git a/drivers/phy/ralink/Makefile b/drivers/phy/ralink/Makefile new file mode 100644 index 000000000000..5c9e326e8757 --- /dev/null +++ b/drivers/phy/ralink/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_PHY_RALINK_USB)	+= phy-ralink-usb.o diff --git a/drivers/phy/ralink/phy-ralink-usb.c b/drivers/phy/ralink/phy-ralink-usb.c new file mode 100644 index 000000000000..4fea31f8ac1c --- /dev/null +++ b/drivers/phy/ralink/phy-ralink-usb.c @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2017 John Crispin <[email protected]> + * + * Based on code from + * Allwinner Technology Co., Ltd. <www.allwinnertech.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + */ + +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/mfd/syscon.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of_platform.h> +#include <linux/phy/phy.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/reset.h> + +#define RT_SYSC_REG_SYSCFG1		0x014 +#define RT_SYSC_REG_CLKCFG1		0x030 +#define RT_SYSC_REG_USB_PHY_CFG		0x05c + +#define OFS_U2_PHY_AC0			0x800 +#define OFS_U2_PHY_AC1			0x804 +#define OFS_U2_PHY_AC2			0x808 +#define OFS_U2_PHY_ACR0			0x810 +#define OFS_U2_PHY_ACR1			0x814 +#define OFS_U2_PHY_ACR2			0x818 +#define OFS_U2_PHY_ACR3			0x81C +#define OFS_U2_PHY_ACR4			0x820 +#define OFS_U2_PHY_AMON0		0x824 +#define OFS_U2_PHY_DCR0			0x860 +#define OFS_U2_PHY_DCR1			0x864 +#define OFS_U2_PHY_DTM0			0x868 +#define OFS_U2_PHY_DTM1			0x86C + +#define RT_RSTCTRL_UDEV			BIT(25) +#define RT_RSTCTRL_UHST			BIT(22) +#define RT_SYSCFG1_USB0_HOST_MODE	BIT(10) + +#define MT7620_CLKCFG1_UPHY0_CLK_EN	BIT(25) +#define MT7620_CLKCFG1_UPHY1_CLK_EN	BIT(22) +#define RT_CLKCFG1_UPHY1_CLK_EN		BIT(20) +#define RT_CLKCFG1_UPHY0_CLK_EN		BIT(18) + +#define USB_PHY_UTMI_8B60M		BIT(1) +#define UDEV_WAKEUP			BIT(0) + +struct ralink_usb_phy { +	struct reset_control	*rstdev; +	struct reset_control	*rsthost; +	u32			clk; +	struct phy		*phy; +	void __iomem		*base; +	struct regmap		*sysctl; +}; + +static void u2_phy_w32(struct ralink_usb_phy *phy, u32 val, u32 reg) +{ +	writel(val, phy->base + reg); +} + +static u32 u2_phy_r32(struct ralink_usb_phy *phy, u32 reg) +{ +	return readl(phy->base + reg); +} + +static void ralink_usb_phy_init(struct ralink_usb_phy *phy) +{ +	u2_phy_r32(phy, OFS_U2_PHY_AC2); +	u2_phy_r32(phy, OFS_U2_PHY_ACR0); +	u2_phy_r32(phy, OFS_U2_PHY_DCR0); + +	u2_phy_w32(phy, 0x00ffff02, OFS_U2_PHY_DCR0); +	u2_phy_r32(phy, OFS_U2_PHY_DCR0); +	u2_phy_w32(phy, 0x00555502, OFS_U2_PHY_DCR0); +	u2_phy_r32(phy, OFS_U2_PHY_DCR0); +	u2_phy_w32(phy, 0x00aaaa02, OFS_U2_PHY_DCR0); +	u2_phy_r32(phy, OFS_U2_PHY_DCR0); +	u2_phy_w32(phy, 0x00000402, OFS_U2_PHY_DCR0); +	u2_phy_r32(phy, OFS_U2_PHY_DCR0); +	u2_phy_w32(phy, 0x0048086a, OFS_U2_PHY_AC0); +	u2_phy_w32(phy, 0x4400001c, OFS_U2_PHY_AC1); +	u2_phy_w32(phy, 0xc0200000, OFS_U2_PHY_ACR3); +	u2_phy_w32(phy, 0x02000000, OFS_U2_PHY_DTM0); +} + +static int ralink_usb_phy_power_on(struct phy *_phy) +{ +	struct ralink_usb_phy *phy = phy_get_drvdata(_phy); +	u32 t; + +	/* enable the phy */ +	regmap_update_bits(phy->sysctl, RT_SYSC_REG_CLKCFG1, +			   phy->clk, phy->clk); + +	/* setup host mode */ +	regmap_update_bits(phy->sysctl, RT_SYSC_REG_SYSCFG1, +			   RT_SYSCFG1_USB0_HOST_MODE, +			   RT_SYSCFG1_USB0_HOST_MODE); + +	/* deassert the reset lines */ +	reset_control_deassert(phy->rsthost); +	reset_control_deassert(phy->rstdev); + +	/* +	 * The SDK kernel had a delay of 100ms. however on device +	 * testing showed that 10ms is enough +	 */ +	mdelay(10); + +	if (phy->base) +		ralink_usb_phy_init(phy); + +	/* print some status info */ +	regmap_read(phy->sysctl, RT_SYSC_REG_USB_PHY_CFG, &t); +	dev_info(&phy->phy->dev, "remote usb device wakeup %s\n", +		(t & UDEV_WAKEUP) ? ("enabled") : ("disabled")); +	if (t & USB_PHY_UTMI_8B60M) +		dev_info(&phy->phy->dev, "UTMI 8bit 60MHz\n"); +	else +		dev_info(&phy->phy->dev, "UTMI 16bit 30MHz\n"); + +	return 0; +} + +static int ralink_usb_phy_power_off(struct phy *_phy) +{ +	struct ralink_usb_phy *phy = phy_get_drvdata(_phy); + +	/* disable the phy */ +	regmap_update_bits(phy->sysctl, RT_SYSC_REG_CLKCFG1, +			   phy->clk, 0); + +	/* assert the reset lines */ +	reset_control_assert(phy->rstdev); +	reset_control_assert(phy->rsthost); + +	return 0; +} + +static struct phy_ops ralink_usb_phy_ops = { +	.power_on	= ralink_usb_phy_power_on, +	.power_off	= ralink_usb_phy_power_off, +	.owner		= THIS_MODULE, +}; + +static const struct of_device_id ralink_usb_phy_of_match[] = { +	{ +		.compatible = "ralink,rt3352-usbphy", +		.data = (void *)(uintptr_t)(RT_CLKCFG1_UPHY1_CLK_EN | +					    RT_CLKCFG1_UPHY0_CLK_EN) +	}, +	{ +		.compatible = "mediatek,mt7620-usbphy", +		.data = (void *)(uintptr_t)(MT7620_CLKCFG1_UPHY1_CLK_EN | +					    MT7620_CLKCFG1_UPHY0_CLK_EN) +	}, +	{ +		.compatible = "mediatek,mt7628-usbphy", +		.data = (void *)(uintptr_t)(MT7620_CLKCFG1_UPHY1_CLK_EN | +					    MT7620_CLKCFG1_UPHY0_CLK_EN) }, +	{ }, +}; +MODULE_DEVICE_TABLE(of, ralink_usb_phy_of_match); + +static int ralink_usb_phy_probe(struct platform_device *pdev) +{ +	struct device *dev = &pdev->dev; +	struct resource *res; +	struct phy_provider *phy_provider; +	const struct of_device_id *match; +	struct ralink_usb_phy *phy; + +	match = of_match_device(ralink_usb_phy_of_match, &pdev->dev); +	if (!match) +		return -ENODEV; + +	phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); +	if (!phy) +		return -ENOMEM; + +	phy->clk = (uintptr_t)match->data; +	phy->base = NULL; + +	phy->sysctl = syscon_regmap_lookup_by_phandle(dev->of_node, "ralink,sysctl"); +	if (IS_ERR(phy->sysctl)) { +		dev_err(dev, "failed to get sysctl registers\n"); +		return PTR_ERR(phy->sysctl); +	} + +	/* The MT7628 and MT7688 require extra setup of PHY registers. */ +	if (of_device_is_compatible(dev->of_node, "mediatek,mt7628-usbphy")) { +		res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +		phy->base = devm_ioremap_resource(&pdev->dev, res); +		if (IS_ERR(phy->base)) { +			dev_err(dev, "failed to remap register memory\n"); +			return PTR_ERR(phy->base); +		} +	} + +	phy->rsthost = devm_reset_control_get(&pdev->dev, "host"); +	if (IS_ERR(phy->rsthost)) { +		dev_err(dev, "host reset is missing\n"); +		return PTR_ERR(phy->rsthost); +	} + +	phy->rstdev = devm_reset_control_get(&pdev->dev, "device"); +	if (IS_ERR(phy->rstdev)) { +		dev_err(dev, "device reset is missing\n"); +		return PTR_ERR(phy->rstdev); +	} + +	phy->phy = devm_phy_create(dev, NULL, &ralink_usb_phy_ops); +	if (IS_ERR(phy->phy)) { +		dev_err(dev, "failed to create PHY\n"); +		return PTR_ERR(phy->phy); +	} +	phy_set_drvdata(phy->phy, phy); + +	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + +	return PTR_ERR_OR_ZERO(phy_provider); +} + +static struct platform_driver ralink_usb_phy_driver = { +	.probe	= ralink_usb_phy_probe, +	.driver = { +		.of_match_table	= ralink_usb_phy_of_match, +		.name  = "ralink-usb-phy", +	} +}; +module_platform_driver(ralink_usb_phy_driver); + +MODULE_DESCRIPTION("Ralink USB phy driver"); +MODULE_AUTHOR("John Crispin <[email protected]>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c index 626883d9d176..994cc1a08f50 100644 --- a/drivers/phy/rockchip/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -172,6 +172,8 @@ struct rockchip_usb2phy_cfg {   * @vbus_attached: otg device vbus status.   * @bvalid_irq: IRQ number assigned for vbus valid rise detection.   * @ls_irq: IRQ number assigned for linestate detection. + * @otg_mux_irq: IRQ number which multiplex otg-id/otg-bvalid/linestate + *		 irqs to one irq in otg-port.   * @mutex: for register updating in sm_work.   * @chg_work: charge detect work.   * @otg_sm_work: OTG state machine work. @@ -189,6 +191,7 @@ struct rockchip_usb2phy_port {  	bool		vbus_attached;  	int		bvalid_irq;  	int		ls_irq; +	int		otg_mux_irq;  	struct mutex	mutex;  	struct		delayed_work chg_work;  	struct		delayed_work otg_sm_work; @@ -202,6 +205,7 @@ struct rockchip_usb2phy_port {  /**   * struct rockchip_usb2phy: usb2.0 phy driver data.   * @grf: General Register Files regmap. + * @usbgrf: USB General Register Files regmap.   * @clk: clock struct of phy input clk.   * @clk480m: clock struct of phy output clk.   * @clk_hw: clock struct of phy output clk management. @@ -216,6 +220,7 @@ struct rockchip_usb2phy_port {  struct rockchip_usb2phy {  	struct device	*dev;  	struct regmap	*grf; +	struct regmap	*usbgrf;  	struct clk	*clk;  	struct clk	*clk480m;  	struct clk_hw	clk480m_hw; @@ -227,7 +232,12 @@ struct rockchip_usb2phy {  	struct rockchip_usb2phy_port	ports[USB2PHY_NUM_PORTS];  }; -static inline int property_enable(struct rockchip_usb2phy *rphy, +static inline struct regmap *get_reg_base(struct rockchip_usb2phy *rphy) +{ +	return rphy->usbgrf == NULL ? rphy->grf : rphy->usbgrf; +} + +static inline int property_enable(struct regmap *base,  				  const struct usb2phy_reg *reg, bool en)  {  	unsigned int val, mask, tmp; @@ -236,17 +246,17 @@ static inline int property_enable(struct rockchip_usb2phy *rphy,  	mask = GENMASK(reg->bitend, reg->bitstart);  	val = (tmp << reg->bitstart) | (mask << BIT_WRITEABLE_SHIFT); -	return regmap_write(rphy->grf, reg->offset, val); +	return regmap_write(base, reg->offset, val);  } -static inline bool property_enabled(struct rockchip_usb2phy *rphy, +static inline bool property_enabled(struct regmap *base,  				    const struct usb2phy_reg *reg)  {  	int ret;  	unsigned int tmp, orig;  	unsigned int mask = GENMASK(reg->bitend, reg->bitstart); -	ret = regmap_read(rphy->grf, reg->offset, &orig); +	ret = regmap_read(base, reg->offset, &orig);  	if (ret)  		return false; @@ -258,11 +268,12 @@ static int rockchip_usb2phy_clk480m_prepare(struct clk_hw *hw)  {  	struct rockchip_usb2phy *rphy =  		container_of(hw, struct rockchip_usb2phy, clk480m_hw); +	struct regmap *base = get_reg_base(rphy);  	int ret;  	/* turn on 480m clk output if it is off */ -	if (!property_enabled(rphy, &rphy->phy_cfg->clkout_ctl)) { -		ret = property_enable(rphy, &rphy->phy_cfg->clkout_ctl, true); +	if (!property_enabled(base, &rphy->phy_cfg->clkout_ctl)) { +		ret = property_enable(base, &rphy->phy_cfg->clkout_ctl, true);  		if (ret)  			return ret; @@ -277,17 +288,19 @@ static void rockchip_usb2phy_clk480m_unprepare(struct clk_hw *hw)  {  	struct rockchip_usb2phy *rphy =  		container_of(hw, struct rockchip_usb2phy, clk480m_hw); +	struct regmap *base = get_reg_base(rphy);  	/* turn off 480m clk output */ -	property_enable(rphy, &rphy->phy_cfg->clkout_ctl, false); +	property_enable(base, &rphy->phy_cfg->clkout_ctl, false);  }  static int rockchip_usb2phy_clk480m_prepared(struct clk_hw *hw)  {  	struct rockchip_usb2phy *rphy =  		container_of(hw, struct rockchip_usb2phy, clk480m_hw); +	struct regmap *base = get_reg_base(rphy); -	return property_enabled(rphy, &rphy->phy_cfg->clkout_ctl); +	return property_enabled(base, &rphy->phy_cfg->clkout_ctl);  }  static unsigned long @@ -409,13 +422,13 @@ static int rockchip_usb2phy_init(struct phy *phy)  		if (rport->mode != USB_DR_MODE_HOST &&  		    rport->mode != USB_DR_MODE_UNKNOWN) {  			/* clear bvalid status and enable bvalid detect irq */ -			ret = property_enable(rphy, +			ret = property_enable(rphy->grf,  					      &rport->port_cfg->bvalid_det_clr,  					      true);  			if (ret)  				goto out; -			ret = property_enable(rphy, +			ret = property_enable(rphy->grf,  					      &rport->port_cfg->bvalid_det_en,  					      true);  			if (ret) @@ -429,11 +442,13 @@ static int rockchip_usb2phy_init(struct phy *phy)  		}  	} else if (rport->port_id == USB2PHY_PORT_HOST) {  		/* clear linestate and enable linestate detect irq */ -		ret = property_enable(rphy, &rport->port_cfg->ls_det_clr, true); +		ret = property_enable(rphy->grf, +				      &rport->port_cfg->ls_det_clr, true);  		if (ret)  			goto out; -		ret = property_enable(rphy, &rport->port_cfg->ls_det_en, true); +		ret = property_enable(rphy->grf, +				      &rport->port_cfg->ls_det_en, true);  		if (ret)  			goto out; @@ -449,6 +464,7 @@ static int rockchip_usb2phy_power_on(struct phy *phy)  {  	struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);  	struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent); +	struct regmap *base = get_reg_base(rphy);  	int ret;  	dev_dbg(&rport->phy->dev, "port power on\n"); @@ -460,7 +476,7 @@ static int rockchip_usb2phy_power_on(struct phy *phy)  	if (ret)  		return ret; -	ret = property_enable(rphy, &rport->port_cfg->phy_sus, false); +	ret = property_enable(base, &rport->port_cfg->phy_sus, false);  	if (ret)  		return ret; @@ -475,6 +491,7 @@ static int rockchip_usb2phy_power_off(struct phy *phy)  {  	struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);  	struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent); +	struct regmap *base = get_reg_base(rphy);  	int ret;  	dev_dbg(&rport->phy->dev, "port power off\n"); @@ -482,7 +499,7 @@ static int rockchip_usb2phy_power_off(struct phy *phy)  	if (rport->suspended)  		return 0; -	ret = property_enable(rphy, &rport->port_cfg->phy_sus, true); +	ret = property_enable(base, &rport->port_cfg->phy_sus, true);  	if (ret)  		return ret; @@ -526,11 +543,11 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)  	bool vbus_attach, sch_work, notify_charger;  	if (rport->utmi_avalid) -		vbus_attach = -			property_enabled(rphy, &rport->port_cfg->utmi_avalid); +		vbus_attach = property_enabled(rphy->grf, +					       &rport->port_cfg->utmi_avalid);  	else -		vbus_attach = -			property_enabled(rphy, &rport->port_cfg->utmi_bvalid); +		vbus_attach = property_enabled(rphy->grf, +					       &rport->port_cfg->utmi_bvalid);  	sch_work = false;  	notify_charger = false; @@ -650,22 +667,28 @@ static const char *chg_to_string(enum power_supply_type chg_type)  static void rockchip_chg_enable_dcd(struct rockchip_usb2phy *rphy,  				    bool en)  { -	property_enable(rphy, &rphy->phy_cfg->chg_det.rdm_pdwn_en, en); -	property_enable(rphy, &rphy->phy_cfg->chg_det.idp_src_en, en); +	struct regmap *base = get_reg_base(rphy); + +	property_enable(base, &rphy->phy_cfg->chg_det.rdm_pdwn_en, en); +	property_enable(base, &rphy->phy_cfg->chg_det.idp_src_en, en);  }  static void rockchip_chg_enable_primary_det(struct rockchip_usb2phy *rphy,  					    bool en)  { -	property_enable(rphy, &rphy->phy_cfg->chg_det.vdp_src_en, en); -	property_enable(rphy, &rphy->phy_cfg->chg_det.idm_sink_en, en); +	struct regmap *base = get_reg_base(rphy); + +	property_enable(base, &rphy->phy_cfg->chg_det.vdp_src_en, en); +	property_enable(base, &rphy->phy_cfg->chg_det.idm_sink_en, en);  }  static void rockchip_chg_enable_secondary_det(struct rockchip_usb2phy *rphy,  					      bool en)  { -	property_enable(rphy, &rphy->phy_cfg->chg_det.vdm_src_en, en); -	property_enable(rphy, &rphy->phy_cfg->chg_det.idp_sink_en, en); +	struct regmap *base = get_reg_base(rphy); + +	property_enable(base, &rphy->phy_cfg->chg_det.vdm_src_en, en); +	property_enable(base, &rphy->phy_cfg->chg_det.idp_sink_en, en);  }  #define CHG_DCD_POLL_TIME	(100 * HZ / 1000) @@ -677,6 +700,7 @@ static void rockchip_chg_detect_work(struct work_struct *work)  	struct rockchip_usb2phy_port *rport =  		container_of(work, struct rockchip_usb2phy_port, chg_work.work);  	struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent); +	struct regmap *base = get_reg_base(rphy);  	bool is_dcd, tmout, vout;  	unsigned long delay; @@ -687,7 +711,7 @@ static void rockchip_chg_detect_work(struct work_struct *work)  		if (!rport->suspended)  			rockchip_usb2phy_power_off(rport->phy);  		/* put the controller in non-driving mode */ -		property_enable(rphy, &rphy->phy_cfg->chg_det.opmode, false); +		property_enable(base, &rphy->phy_cfg->chg_det.opmode, false);  		/* Start DCD processing stage 1 */  		rockchip_chg_enable_dcd(rphy, true);  		rphy->chg_state = USB_CHG_STATE_WAIT_FOR_DCD; @@ -696,7 +720,8 @@ static void rockchip_chg_detect_work(struct work_struct *work)  		break;  	case USB_CHG_STATE_WAIT_FOR_DCD:  		/* get data contact detection status */ -		is_dcd = property_enabled(rphy, &rphy->phy_cfg->chg_det.dp_det); +		is_dcd = property_enabled(rphy->grf, +					  &rphy->phy_cfg->chg_det.dp_det);  		tmout = ++rphy->dcd_retries == CHG_DCD_MAX_RETRIES;  		/* stage 2 */  		if (is_dcd || tmout) { @@ -713,7 +738,8 @@ static void rockchip_chg_detect_work(struct work_struct *work)  		}  		break;  	case USB_CHG_STATE_DCD_DONE: -		vout = property_enabled(rphy, &rphy->phy_cfg->chg_det.cp_det); +		vout = property_enabled(rphy->grf, +					&rphy->phy_cfg->chg_det.cp_det);  		rockchip_chg_enable_primary_det(rphy, false);  		if (vout) {  			/* Voltage Source on DM, Probe on DP  */ @@ -734,7 +760,8 @@ static void rockchip_chg_detect_work(struct work_struct *work)  		}  		break;  	case USB_CHG_STATE_PRIMARY_DONE: -		vout = property_enabled(rphy, &rphy->phy_cfg->chg_det.dcp_det); +		vout = property_enabled(rphy->grf, +					&rphy->phy_cfg->chg_det.dcp_det);  		/* Turn off voltage source */  		rockchip_chg_enable_secondary_det(rphy, false);  		if (vout) @@ -748,7 +775,7 @@ static void rockchip_chg_detect_work(struct work_struct *work)  		/* fall through */  	case USB_CHG_STATE_DETECTED:  		/* put the controller in normal mode */ -		property_enable(rphy, &rphy->phy_cfg->chg_det.opmode, true); +		property_enable(base, &rphy->phy_cfg->chg_det.opmode, true);  		rockchip_usb2phy_otg_sm_work(&rport->otg_sm_work.work);  		dev_info(&rport->phy->dev, "charger = %s\n",  			 chg_to_string(rphy->chg_type)); @@ -790,8 +817,7 @@ static void rockchip_usb2phy_sm_work(struct work_struct *work)  	if (ret < 0)  		goto next_schedule; -	ret = regmap_read(rphy->grf, rport->port_cfg->utmi_hstdet.offset, -			  &uhd); +	ret = regmap_read(rphy->grf, rport->port_cfg->utmi_hstdet.offset, &uhd);  	if (ret < 0)  		goto next_schedule; @@ -845,8 +871,8 @@ static void rockchip_usb2phy_sm_work(struct work_struct *work)  		 * activate the linestate detection to get the next device  		 * plug-in irq.  		 */ -		property_enable(rphy, &rport->port_cfg->ls_det_clr, true); -		property_enable(rphy, &rport->port_cfg->ls_det_en, true); +		property_enable(rphy->grf, &rport->port_cfg->ls_det_clr, true); +		property_enable(rphy->grf, &rport->port_cfg->ls_det_en, true);  		/*  		 * we don't need to rearm the delayed work when the phy port @@ -869,14 +895,14 @@ static irqreturn_t rockchip_usb2phy_linestate_irq(int irq, void *data)  	struct rockchip_usb2phy_port *rport = data;  	struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent); -	if (!property_enabled(rphy, &rport->port_cfg->ls_det_st)) +	if (!property_enabled(rphy->grf, &rport->port_cfg->ls_det_st))  		return IRQ_NONE;  	mutex_lock(&rport->mutex);  	/* disable linestate detect irq and clear its status */ -	property_enable(rphy, &rport->port_cfg->ls_det_en, false); -	property_enable(rphy, &rport->port_cfg->ls_det_clr, true); +	property_enable(rphy->grf, &rport->port_cfg->ls_det_en, false); +	property_enable(rphy->grf, &rport->port_cfg->ls_det_clr, true);  	mutex_unlock(&rport->mutex); @@ -896,13 +922,13 @@ static irqreturn_t rockchip_usb2phy_bvalid_irq(int irq, void *data)  	struct rockchip_usb2phy_port *rport = data;  	struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent); -	if (!property_enabled(rphy, &rport->port_cfg->bvalid_det_st)) +	if (!property_enabled(rphy->grf, &rport->port_cfg->bvalid_det_st))  		return IRQ_NONE;  	mutex_lock(&rport->mutex);  	/* clear bvalid detect irq pending status */ -	property_enable(rphy, &rport->port_cfg->bvalid_det_clr, true); +	property_enable(rphy->grf, &rport->port_cfg->bvalid_det_clr, true);  	mutex_unlock(&rport->mutex); @@ -911,6 +937,17 @@ static irqreturn_t rockchip_usb2phy_bvalid_irq(int irq, void *data)  	return IRQ_HANDLED;  } +static irqreturn_t rockchip_usb2phy_otg_mux_irq(int irq, void *data) +{ +	struct rockchip_usb2phy_port *rport = data; +	struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent); + +	if (property_enabled(rphy->grf, &rport->port_cfg->bvalid_det_st)) +		return rockchip_usb2phy_bvalid_irq(irq, data); +	else +		return IRQ_NONE; +} +  static int rockchip_usb2phy_host_port_init(struct rockchip_usb2phy *rphy,  					   struct rockchip_usb2phy_port *rport,  					   struct device_node *child_np) @@ -987,20 +1024,43 @@ static int rockchip_usb2phy_otg_port_init(struct rockchip_usb2phy *rphy,  	rport->utmi_avalid =  		of_property_read_bool(child_np, "rockchip,utmi-avalid"); -	rport->bvalid_irq = of_irq_get_byname(child_np, "otg-bvalid"); -	if (rport->bvalid_irq < 0) { -		dev_err(rphy->dev, "no vbus valid irq provided\n"); -		ret = rport->bvalid_irq; -		goto out; -	} +	/* +	 * Some SoCs use one interrupt with otg-id/otg-bvalid/linestate +	 * interrupts muxed together, so probe the otg-mux interrupt first, +	 * if not found, then look for the regular interrupts one by one. +	 */ +	rport->otg_mux_irq = of_irq_get_byname(child_np, "otg-mux"); +	if (rport->otg_mux_irq > 0) { +		ret = devm_request_threaded_irq(rphy->dev, rport->otg_mux_irq, +						NULL, +						rockchip_usb2phy_otg_mux_irq, +						IRQF_ONESHOT, +						"rockchip_usb2phy_otg", +						rport); +		if (ret) { +			dev_err(rphy->dev, +				"failed to request otg-mux irq handle\n"); +			goto out; +		} +	} else { +		rport->bvalid_irq = of_irq_get_byname(child_np, "otg-bvalid"); +		if (rport->bvalid_irq < 0) { +			dev_err(rphy->dev, "no vbus valid irq provided\n"); +			ret = rport->bvalid_irq; +			goto out; +		} -	ret = devm_request_threaded_irq(rphy->dev, rport->bvalid_irq, NULL, -					rockchip_usb2phy_bvalid_irq, -					IRQF_ONESHOT, -					"rockchip_usb2phy_bvalid", rport); -	if (ret) { -		dev_err(rphy->dev, "failed to request otg-bvalid irq handle\n"); -		goto out; +		ret = devm_request_threaded_irq(rphy->dev, rport->bvalid_irq, +						NULL, +						rockchip_usb2phy_bvalid_irq, +						IRQF_ONESHOT, +						"rockchip_usb2phy_bvalid", +						rport); +		if (ret) { +			dev_err(rphy->dev, +				"failed to request otg-bvalid irq handle\n"); +			goto out; +		}  	}  	if (!IS_ERR(rphy->edev)) { @@ -1045,6 +1105,16 @@ static int rockchip_usb2phy_probe(struct platform_device *pdev)  	if (IS_ERR(rphy->grf))  		return PTR_ERR(rphy->grf); +	if (of_device_is_compatible(np, "rockchip,rv1108-usb2phy")) { +		rphy->usbgrf = +			syscon_regmap_lookup_by_phandle(dev->of_node, +							"rockchip,usbgrf"); +		if (IS_ERR(rphy->usbgrf)) +			return PTR_ERR(rphy->usbgrf); +	} else { +		rphy->usbgrf = NULL; +	} +  	if (of_property_read_u32(np, "reg", ®)) {  		dev_err(dev, "the reg property is not assigned in %s node\n",  			np->name); @@ -1327,11 +1397,54 @@ static const struct rockchip_usb2phy_cfg rk3399_phy_cfgs[] = {  	{ /* sentinel */ }  }; +static const struct rockchip_usb2phy_cfg rv1108_phy_cfgs[] = { +	{ +		.reg = 0x100, +		.num_ports	= 2, +		.clkout_ctl	= { 0x108, 4, 4, 1, 0 }, +		.port_cfgs	= { +			[USB2PHY_PORT_OTG] = { +				.phy_sus	= { 0x0100, 15, 0, 0, 0x1d1 }, +				.bvalid_det_en	= { 0x0680, 3, 3, 0, 1 }, +				.bvalid_det_st	= { 0x0690, 3, 3, 0, 1 }, +				.bvalid_det_clr = { 0x06a0, 3, 3, 0, 1 }, +				.ls_det_en	= { 0x0680, 2, 2, 0, 1 }, +				.ls_det_st	= { 0x0690, 2, 2, 0, 1 }, +				.ls_det_clr	= { 0x06a0, 2, 2, 0, 1 }, +				.utmi_bvalid	= { 0x0804, 10, 10, 0, 1 }, +				.utmi_ls	= { 0x0804, 13, 12, 0, 1 }, +			}, +			[USB2PHY_PORT_HOST] = { +				.phy_sus	= { 0x0104, 15, 0, 0, 0x1d1 }, +				.ls_det_en	= { 0x0680, 4, 4, 0, 1 }, +				.ls_det_st	= { 0x0690, 4, 4, 0, 1 }, +				.ls_det_clr	= { 0x06a0, 4, 4, 0, 1 }, +				.utmi_ls	= { 0x0804, 9, 8, 0, 1 }, +				.utmi_hstdet	= { 0x0804, 7, 7, 0, 1 } +			} +		}, +		.chg_det = { +			.opmode		= { 0x0100, 3, 0, 5, 1 }, +			.cp_det		= { 0x0804, 1, 1, 0, 1 }, +			.dcp_det	= { 0x0804, 0, 0, 0, 1 }, +			.dp_det		= { 0x0804, 2, 2, 0, 1 }, +			.idm_sink_en	= { 0x0108, 8, 8, 0, 1 }, +			.idp_sink_en	= { 0x0108, 7, 7, 0, 1 }, +			.idp_src_en	= { 0x0108, 9, 9, 0, 1 }, +			.rdm_pdwn_en	= { 0x0108, 10, 10, 0, 1 }, +			.vdm_src_en	= { 0x0108, 12, 12, 0, 1 }, +			.vdp_src_en	= { 0x0108, 11, 11, 0, 1 }, +		}, +	}, +	{ /* sentinel */ } +}; +  static const struct of_device_id rockchip_usb2phy_dt_match[] = {  	{ .compatible = "rockchip,rk3228-usb2phy", .data = &rk3228_phy_cfgs },  	{ .compatible = "rockchip,rk3328-usb2phy", .data = &rk3328_phy_cfgs },  	{ .compatible = "rockchip,rk3366-usb2phy", .data = &rk3366_phy_cfgs },  	{ .compatible = "rockchip,rk3399-usb2phy", .data = &rk3399_phy_cfgs }, +	{ .compatible = "rockchip,rv1108-usb2phy", .data = &rv1108_phy_cfgs },  	{}  };  MODULE_DEVICE_TABLE(of, rockchip_usb2phy_dt_match); diff --git a/drivers/phy/rockchip/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c index 7cfb0f8995de..4d2c57f21d76 100644 --- a/drivers/phy/rockchip/phy-rockchip-typec.c +++ b/drivers/phy/rockchip/phy-rockchip-typec.c @@ -622,12 +622,11 @@ static int tcphy_get_mode(struct rockchip_typec_phy *tcphy)  	struct extcon_dev *edev = tcphy->extcon;  	union extcon_property_value property;  	unsigned int id; -	bool dfp, ufp, dp; +	bool ufp, dp;  	u8 mode;  	int ret;  	ufp = extcon_get_state(edev, EXTCON_USB); -	dfp = extcon_get_state(edev, EXTCON_USB_HOST);  	dp = extcon_get_state(edev, EXTCON_DISP_DP);  	mode = MODE_DFP_USB; diff --git a/drivers/phy/samsung/phy-exynos-dp-video.c b/drivers/phy/samsung/phy-exynos-dp-video.c index bb3279dbf88c..2dd6dd1f37a8 100644 --- a/drivers/phy/samsung/phy-exynos-dp-video.c +++ b/drivers/phy/samsung/phy-exynos-dp-video.c @@ -16,6 +16,7 @@  #include <linux/mfd/syscon.h>  #include <linux/of.h>  #include <linux/of_address.h> +#include <linux/of_device.h>  #include <linux/phy/phy.h>  #include <linux/platform_device.h>  #include <linux/regmap.h> @@ -78,7 +79,6 @@ static int exynos_dp_video_phy_probe(struct platform_device *pdev)  {  	struct exynos_dp_video_phy *state;  	struct device *dev = &pdev->dev; -	const struct of_device_id *match;  	struct phy_provider *phy_provider;  	struct phy *phy; @@ -93,8 +93,7 @@ static int exynos_dp_video_phy_probe(struct platform_device *pdev)  		return PTR_ERR(state->regs);  	} -	match = of_match_node(exynos_dp_video_phy_of_match, dev->of_node); -	state->drvdata = match->data; +	state->drvdata = of_device_get_match_data(dev);  	phy = devm_phy_create(dev, NULL, &exynos_dp_video_phy_ops);  	if (IS_ERR(phy)) { diff --git a/drivers/phy/samsung/phy-exynos5-usbdrd.c b/drivers/phy/samsung/phy-exynos5-usbdrd.c index 7c41daa2c625..22c68f58b181 100644 --- a/drivers/phy/samsung/phy-exynos5-usbdrd.c +++ b/drivers/phy/samsung/phy-exynos5-usbdrd.c @@ -18,6 +18,7 @@  #include <linux/module.h>  #include <linux/of.h>  #include <linux/of_address.h> +#include <linux/of_device.h>  #include <linux/phy/phy.h>  #include <linux/platform_device.h>  #include <linux/mutex.h> @@ -662,7 +663,6 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)  	struct exynos5_usbdrd_phy *phy_drd;  	struct phy_provider *phy_provider;  	struct resource *res; -	const struct of_device_id *match;  	const struct exynos5_usbdrd_phy_drvdata *drv_data;  	struct regmap *reg_pmu;  	u32 pmu_offset; @@ -681,9 +681,10 @@ static int exynos5_usbdrd_phy_probe(struct platform_device *pdev)  	if (IS_ERR(phy_drd->reg_phy))  		return PTR_ERR(phy_drd->reg_phy); -	match = of_match_node(exynos5_usbdrd_phy_of_match, pdev->dev.of_node); +	drv_data = of_device_get_match_data(dev); +	if (!drv_data) +		return -EINVAL; -	drv_data = match->data;  	phy_drd->drv_data = drv_data;  	ret = exynos5_usbdrd_phy_clk_handle(phy_drd); diff --git a/drivers/phy/samsung/phy-samsung-usb2.c b/drivers/phy/samsung/phy-samsung-usb2.c index 1d22d93b552d..ea818866985a 100644 --- a/drivers/phy/samsung/phy-samsung-usb2.c +++ b/drivers/phy/samsung/phy-samsung-usb2.c @@ -14,6 +14,7 @@  #include <linux/module.h>  #include <linux/of.h>  #include <linux/of_address.h> +#include <linux/of_device.h>  #include <linux/phy/phy.h>  #include <linux/platform_device.h>  #include <linux/spinlock.h> @@ -142,7 +143,6 @@ MODULE_DEVICE_TABLE(of, samsung_usb2_phy_of_match);  static int samsung_usb2_phy_probe(struct platform_device *pdev)  { -	const struct of_device_id *match;  	const struct samsung_usb2_phy_config *cfg;  	struct device *dev = &pdev->dev;  	struct phy_provider *phy_provider; @@ -155,12 +155,9 @@ static int samsung_usb2_phy_probe(struct platform_device *pdev)  		return -EINVAL;  	} -	match = of_match_node(samsung_usb2_phy_of_match, pdev->dev.of_node); -	if (!match) { -		dev_err(dev, "of_match_node() failed\n"); +	cfg = of_device_get_match_data(dev); +	if (!cfg)  		return -EINVAL; -	} -	cfg = match->data;  	drv = devm_kzalloc(dev, sizeof(struct samsung_usb2_phy_driver) +  		cfg->num_phys * sizeof(struct samsung_usb2_phy_instance), diff --git a/drivers/phy/ti/phy-ti-pipe3.c b/drivers/phy/ti/phy-ti-pipe3.c index 9c84d32c6f60..0e564f32749f 100644 --- a/drivers/phy/ti/phy-ti-pipe3.c +++ b/drivers/phy/ti/phy-ti-pipe3.c @@ -118,12 +118,12 @@ static struct pipe3_dpll_map dpll_map_usb[] = {  };  static struct pipe3_dpll_map dpll_map_sata[] = { -	{12000000, {1000, 7, 4, 6, 0} },	/* 12 MHz */ -	{16800000, {714, 7, 4, 6, 0} },		/* 16.8 MHz */ +	{12000000, {625, 4, 4, 6, 0} },	/* 12 MHz */ +	{16800000, {625, 6, 4, 7, 0} },		/* 16.8 MHz */  	{19200000, {625, 7, 4, 6, 0} },		/* 19.2 MHz */ -	{20000000, {600, 7, 4, 6, 0} },		/* 20 MHz */ -	{26000000, {461, 7, 4, 6, 0} },		/* 26 MHz */ -	{38400000, {312, 7, 4, 6, 0} },		/* 38.4 MHz */ +	{20000000, {750, 9, 4, 6, 0} },		/* 20 MHz */ +	{26000000, {750, 12, 4, 6, 0} },	/* 26 MHz */ +	{38400000, {625, 15, 4, 6, 0} },	/* 38.4 MHz */  	{ },					/* Terminator */  }; diff --git a/drivers/phy/ti/phy-twl4030-usb.c b/drivers/phy/ti/phy-twl4030-usb.c index 2990b3965460..0e9013868188 100644 --- a/drivers/phy/ti/phy-twl4030-usb.c +++ b/drivers/phy/ti/phy-twl4030-usb.c @@ -185,7 +185,7 @@ struct twl4030_usb {  static int twl4030_i2c_write_u8_verify(struct twl4030_usb *twl,  		u8 module, u8 data, u8 address)  { -	u8 check; +	u8 check = 0xFF;  	if ((twl_i2c_write_u8(module, data, address) >= 0) &&  	    (twl_i2c_read_u8(module, &check, address) >= 0) && diff --git a/drivers/power/supply/wm831x_power.c b/drivers/power/supply/wm831x_power.c index 7082301da945..927050d4444d 100644 --- a/drivers/power/supply/wm831x_power.c +++ b/drivers/power/supply/wm831x_power.c @@ -13,6 +13,7 @@  #include <linux/platform_device.h>  #include <linux/power_supply.h>  #include <linux/slab.h> +#include <linux/usb/phy.h>  #include <linux/mfd/wm831x/core.h>  #include <linux/mfd/wm831x/auxadc.h> @@ -31,6 +32,8 @@ struct wm831x_power {  	char usb_name[20];  	char battery_name[20];  	bool have_battery; +	struct usb_phy *usb_phy; +	struct notifier_block usb_notify;  };  static int wm831x_power_check_online(struct wm831x *wm831x, int supply, @@ -125,6 +128,43 @@ static enum power_supply_property wm831x_usb_props[] = {  	POWER_SUPPLY_PROP_VOLTAGE_NOW,  }; +/* In milliamps */ +static const unsigned int wm831x_usb_limits[] = { +	0, +	2, +	100, +	500, +	900, +	1500, +	1800, +	550, +}; + +static int wm831x_usb_limit_change(struct notifier_block *nb, +				   unsigned long limit, void *data) +{ +	struct wm831x_power *wm831x_power = container_of(nb, +							 struct wm831x_power, +							 usb_notify); +	unsigned int i, best; + +	/* Find the highest supported limit */ +	best = 0; +	for (i = 0; i < ARRAY_SIZE(wm831x_usb_limits); i++) { +		if (limit >= wm831x_usb_limits[i] && +		    wm831x_usb_limits[best] < wm831x_usb_limits[i]) +			best = i; +	} + +	dev_dbg(wm831x_power->wm831x->dev, +		"Limiting USB current to %umA", wm831x_usb_limits[best]); + +	wm831x_set_bits(wm831x_power->wm831x, WM831X_POWER_STATE, +		        WM831X_USB_ILIM_MASK, best); + +	return 0; +} +  /*********************************************************************   *		Battery properties   *********************************************************************/ @@ -607,6 +647,33 @@ static int wm831x_power_probe(struct platform_device *pdev)  		}  	} +	power->usb_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "phys", 0); +	ret = PTR_ERR_OR_ZERO(power->usb_phy); + +	switch (ret) { +	case 0: +		power->usb_notify.notifier_call = wm831x_usb_limit_change; +		ret = usb_register_notifier(power->usb_phy, &power->usb_notify); +		if (ret) { +			dev_err(&pdev->dev, "Failed to register notifier: %d\n", +				ret); +			goto err_bat_irq; +		} +		break; +	case -EINVAL: +	case -ENODEV: +		/* ignore missing usb-phy, it's optional */ +		power->usb_phy = NULL; +		ret = 0; +		break; +	default: +		dev_err(&pdev->dev, "Failed to find USB phy: %d\n", ret); +		/* fall-through */ +	case -EPROBE_DEFER: +		goto err_bat_irq; +		break; +	} +  	return ret;  err_bat_irq: @@ -637,6 +704,11 @@ static int wm831x_power_remove(struct platform_device *pdev)  	struct wm831x *wm831x = wm831x_power->wm831x;  	int irq, i; +	if (wm831x_power->usb_phy) { +		usb_unregister_notifier(wm831x_power->usb_phy, +					&wm831x_power->usb_notify); +	} +  	for (i = 0; i < ARRAY_SIZE(wm831x_bat_irqs); i++) {  		irq = wm831x_irq(wm831x,   				 platform_get_irq_byname(pdev, diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index d65a64c29b85..5160a4a966b3 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -43,7 +43,6 @@  #include "usbatm.h"  #define DRIVER_AUTHOR	"Roman Kagan, David Woodhouse, Duncan Sands, Simon Arlott" -#define DRIVER_VERSION	"0.4"  #define DRIVER_DESC	"Conexant AccessRunner ADSL USB modem driver"  static const char cxacru_driver_name[] = "cxacru"; @@ -1380,4 +1379,3 @@ module_usb_driver(cxacru_usb_driver);  MODULE_AUTHOR(DRIVER_AUTHOR);  MODULE_DESCRIPTION(DRIVER_DESC);  MODULE_LICENSE("GPL"); -MODULE_VERSION(DRIVER_VERSION); diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 5083eb5b0d5e..3676adb40d89 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -40,8 +40,7 @@  #include "usbatm.h"  #define DRIVER_AUTHOR	"Johan Verrept, Duncan Sands <[email protected]>" -#define DRIVER_VERSION	"1.10" -#define DRIVER_DESC	"Alcatel SpeedTouch USB driver version " DRIVER_VERSION +#define DRIVER_DESC	"Alcatel SpeedTouch USB driver"  static const char speedtch_driver_name[] = "speedtch"; @@ -738,7 +737,7 @@ static int speedtch_post_reset(struct usb_interface *intf)  **  USB  **  **********/ -static struct usb_device_id speedtch_usb_ids[] = { +static const struct usb_device_id speedtch_usb_ids[] = {  	{USB_DEVICE(0x06b9, 0x4061)},  	{}  }; @@ -962,4 +961,3 @@ module_usb_driver(speedtch_usb_driver);  MODULE_AUTHOR(DRIVER_AUTHOR);  MODULE_DESCRIPTION(DRIVER_DESC);  MODULE_LICENSE("GPL"); -MODULE_VERSION(DRIVER_VERSION); diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index df67815f74e6..ba7616395db2 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -2212,7 +2212,7 @@ static int uea_boot(struct uea_softc *sc)  	ret = usb_submit_urb(sc->urb_int, GFP_KERNEL);  	if (ret < 0) {  		uea_err(INS_TO_USBDEV(sc), -		       "urb submition failed with error %d\n", ret); +		       "urb submission failed with error %d\n", ret);  		goto err1;  	} @@ -2522,7 +2522,7 @@ static struct attribute *attrs[] = {  	&dev_attr_stat_firmid.attr,  	NULL,  }; -static struct attribute_group attr_grp = { +static const struct attribute_group attr_grp = {  	.attrs = attrs,  }; diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index 3e80aa3b917a..8607af758bbd 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -93,8 +93,7 @@ static int usbatm_print_packet(struct usbatm_data *instance, const unsigned char  #endif  #define DRIVER_AUTHOR	"Johan Verrept, Duncan Sands <[email protected]>" -#define DRIVER_VERSION	"1.10" -#define DRIVER_DESC	"Generic USB ATM/DSL I/O, version " DRIVER_VERSION +#define DRIVER_DESC	"Generic USB ATM/DSL I/O"  static const char usbatm_driver_name[] = "usbatm"; @@ -174,7 +173,7 @@ static int usbatm_atm_ioctl(struct atm_dev *atm_dev, unsigned int cmd, void __us  static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb);  static int usbatm_atm_proc_read(struct atm_dev *atm_dev, loff_t *pos, char *page); -static struct atmdev_ops usbatm_atm_devops = { +static const struct atmdev_ops usbatm_atm_devops = {  	.dev_close	= usbatm_atm_dev_close,  	.open		= usbatm_atm_open,  	.close		= usbatm_atm_close, @@ -1315,7 +1314,6 @@ module_exit(usbatm_usb_exit);  MODULE_AUTHOR(DRIVER_AUTHOR);  MODULE_DESCRIPTION(DRIVER_DESC);  MODULE_LICENSE("GPL"); -MODULE_VERSION(DRIVER_VERSION);  /************  **  debug  ** diff --git a/drivers/usb/atm/xusbatm.c b/drivers/usb/atm/xusbatm.c index a87597f88a84..c73c1ec3005e 100644 --- a/drivers/usb/atm/xusbatm.c +++ b/drivers/usb/atm/xusbatm.c @@ -228,4 +228,3 @@ module_exit(xusbatm_exit);  MODULE_AUTHOR("Roman Kagan, Duncan Sands");  MODULE_DESCRIPTION("Driver for USB ADSL modems initialized in userspace");  MODULE_LICENSE("GPL"); -MODULE_VERSION("0.1"); diff --git a/drivers/usb/c67x00/c67x00-hcd.c b/drivers/usb/c67x00/c67x00-hcd.c index c2d13968da82..30d3f346686e 100644 --- a/drivers/usb/c67x00/c67x00-hcd.c +++ b/drivers/usb/c67x00/c67x00-hcd.c @@ -305,7 +305,7 @@ static int c67x00_hcd_get_frame(struct usb_hcd *hcd)  	return temp_val ? (temp_val - 1) : HOST_FRAME_MASK;  } -static struct hc_driver c67x00_hc_driver = { +static const struct hc_driver c67x00_hc_driver = {  	.description	= "c67x00-hcd",  	.product_desc	= "Cypress C67X00 Host Controller",  	.hcd_priv_size	= sizeof(struct c67x00_hcd), diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile index 39fca5715ed3..ddcbddf8361a 100644 --- a/drivers/usb/chipidea/Makefile +++ b/drivers/usb/chipidea/Makefile @@ -15,3 +15,4 @@ obj-$(CONFIG_USB_CHIPIDEA)	+= ci_hdrc_zevio.o  obj-$(CONFIG_USB_CHIPIDEA_PCI)	+= ci_hdrc_pci.o  obj-$(CONFIG_USB_CHIPIDEA_OF)	+= usbmisc_imx.o ci_hdrc_imx.o +obj-$(CONFIG_USB_CHIPIDEA_OF)	+= ci_hdrc_tegra.o diff --git a/drivers/usb/chipidea/ci_hdrc_msm.c b/drivers/usb/chipidea/ci_hdrc_msm.c index 0bdfcdcbf7a5..bb626120296f 100644 --- a/drivers/usb/chipidea/ci_hdrc_msm.c +++ b/drivers/usb/chipidea/ci_hdrc_msm.c @@ -251,7 +251,7 @@ static int ci_hdrc_msm_probe(struct platform_device *pdev)  	if (ret)  		goto err_mux; -	ulpi_node = of_find_node_by_name(pdev->dev.of_node, "ulpi"); +	ulpi_node = of_find_node_by_name(of_node_get(pdev->dev.of_node), "ulpi");  	if (ulpi_node) {  		phy_node = of_get_next_available_child(ulpi_node, NULL);  		ci->hsic = of_device_is_compatible(phy_node, "qcom,usb-hsic-phy"); diff --git a/drivers/usb/chipidea/ci_hdrc_pci.c b/drivers/usb/chipidea/ci_hdrc_pci.c index b635ab67490d..39414e4b2d81 100644 --- a/drivers/usb/chipidea/ci_hdrc_pci.c +++ b/drivers/usb/chipidea/ci_hdrc_pci.c @@ -170,5 +170,4 @@ module_pci_driver(ci_hdrc_pci_driver);  MODULE_AUTHOR("MIPS - David Lopo <[email protected]>");  MODULE_DESCRIPTION("MIPS CI13XXX USB Peripheral Controller");  MODULE_LICENSE("GPL"); -MODULE_VERSION("June 2008");  MODULE_ALIAS("platform:ci13xxx_pci"); diff --git a/drivers/usb/chipidea/ci_hdrc_tegra.c b/drivers/usb/chipidea/ci_hdrc_tegra.c new file mode 100644 index 000000000000..bfcee2702d50 --- /dev/null +++ b/drivers/usb/chipidea/ci_hdrc_tegra.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2016, NVIDIA Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + */ + +#include <linux/clk.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/reset.h> + +#include <linux/usb/chipidea.h> + +#include "ci.h" + +struct tegra_udc { +	struct ci_hdrc_platform_data data; +	struct platform_device *dev; + +	struct usb_phy *phy; +	struct clk *clk; +}; + +struct tegra_udc_soc_info { +	unsigned long flags; +}; + +static const struct tegra_udc_soc_info tegra20_udc_soc_info = { +	.flags = CI_HDRC_REQUIRES_ALIGNED_DMA, +}; + +static const struct tegra_udc_soc_info tegra30_udc_soc_info = { +	.flags = 0, +}; + +static const struct tegra_udc_soc_info tegra114_udc_soc_info = { +	.flags = 0, +}; + +static const struct tegra_udc_soc_info tegra124_udc_soc_info = { +	.flags = 0, +}; + +static const struct of_device_id tegra_udc_of_match[] = { +	{ +		.compatible = "nvidia,tegra20-udc", +		.data = &tegra20_udc_soc_info, +	}, { +		.compatible = "nvidia,tegra30-udc", +		.data = &tegra30_udc_soc_info, +	}, { +		.compatible = "nvidia,tegra114-udc", +		.data = &tegra114_udc_soc_info, +	}, { +		.compatible = "nvidia,tegra124-udc", +		.data = &tegra124_udc_soc_info, +	}, { +		/* sentinel */ +	} +}; +MODULE_DEVICE_TABLE(of, tegra_udc_of_match); + +static int tegra_udc_probe(struct platform_device *pdev) +{ +	const struct tegra_udc_soc_info *soc; +	struct tegra_udc *udc; +	int err; + +	udc = devm_kzalloc(&pdev->dev, sizeof(*udc), GFP_KERNEL); +	if (!udc) +		return -ENOMEM; + +	soc = of_device_get_match_data(&pdev->dev); +	if (!soc) { +		dev_err(&pdev->dev, "failed to match OF data\n"); +		return -EINVAL; +	} + +	udc->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "nvidia,phy", 0); +	if (IS_ERR(udc->phy)) { +		err = PTR_ERR(udc->phy); +		dev_err(&pdev->dev, "failed to get PHY: %d\n", err); +		return err; +	} + +	udc->clk = devm_clk_get(&pdev->dev, NULL); +	if (IS_ERR(udc->clk)) { +		err = PTR_ERR(udc->clk); +		dev_err(&pdev->dev, "failed to get clock: %d\n", err); +		return err; +	} + +	err = clk_prepare_enable(udc->clk); +	if (err < 0) { +		dev_err(&pdev->dev, "failed to enable clock: %d\n", err); +		return err; +	} + +	/* +	 * Tegra's USB PHY driver doesn't implement optional phy_init() +	 * hook, so we have to power on UDC controller before ChipIdea +	 * driver initialization kicks in. +	 */ +	usb_phy_set_suspend(udc->phy, 0); + +	/* setup and register ChipIdea HDRC device */ +	udc->data.name = "tegra-udc"; +	udc->data.flags = soc->flags; +	udc->data.usb_phy = udc->phy; +	udc->data.capoffset = DEF_CAPOFFSET; + +	udc->dev = ci_hdrc_add_device(&pdev->dev, pdev->resource, +				      pdev->num_resources, &udc->data); +	if (IS_ERR(udc->dev)) { +		err = PTR_ERR(udc->dev); +		dev_err(&pdev->dev, "failed to add HDRC device: %d\n", err); +		goto fail_power_off; +	} + +	platform_set_drvdata(pdev, udc); + +	return 0; + +fail_power_off: +	usb_phy_set_suspend(udc->phy, 1); +	clk_disable_unprepare(udc->clk); +	return err; +} + +static int tegra_udc_remove(struct platform_device *pdev) +{ +	struct tegra_udc *udc = platform_get_drvdata(pdev); + +	usb_phy_set_suspend(udc->phy, 1); +	clk_disable_unprepare(udc->clk); + +	return 0; +} + +static struct platform_driver tegra_udc_driver = { +	.driver = { +		.name = "tegra-udc", +		.of_match_table = tegra_udc_of_match, +	}, +	.probe = tegra_udc_probe, +	.remove = tegra_udc_remove, +}; +module_platform_driver(tegra_udc_driver); + +MODULE_DESCRIPTION("NVIDIA Tegra USB device mode driver"); +MODULE_AUTHOR("Thierry Reding <[email protected]>"); +MODULE_ALIAS("platform:tegra-udc"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/chipidea/ci_hdrc_usb2.c b/drivers/usb/chipidea/ci_hdrc_usb2.c index d162cc0bb8ce..99425db9ba62 100644 --- a/drivers/usb/chipidea/ci_hdrc_usb2.c +++ b/drivers/usb/chipidea/ci_hdrc_usb2.c @@ -52,6 +52,8 @@ static int ci_hdrc_usb2_probe(struct platform_device *pdev)  	if (!ci_pdata) {  		ci_pdata = devm_kmalloc(dev, sizeof(*ci_pdata), GFP_KERNEL); +		if (!ci_pdata) +			return -ENOMEM;  		*ci_pdata = ci_default_pdata;	/* struct copy */  	} diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index b17ed3a9a304..43ea5fb87b9a 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -736,7 +736,7 @@ static int ci_extcon_register(struct ci_hdrc *ci)  	id = &ci->platdata->id_extcon;  	id->ci = ci; -	if (!IS_ERR(id->edev)) { +	if (!IS_ERR_OR_NULL(id->edev)) {  		ret = devm_extcon_register_notifier(ci->dev, id->edev,  						EXTCON_USB_HOST, &id->nb);  		if (ret < 0) { @@ -747,7 +747,7 @@ static int ci_extcon_register(struct ci_hdrc *ci)  	vbus = &ci->platdata->vbus_extcon;  	vbus->ci = ci; -	if (!IS_ERR(vbus->edev)) { +	if (!IS_ERR_OR_NULL(vbus->edev)) {  		ret = devm_extcon_register_notifier(ci->dev, vbus->edev,  						EXTCON_USB, &vbus->nb);  		if (ret < 0) { @@ -887,7 +887,7 @@ static struct attribute *ci_attrs[] = {  	NULL,  }; -static struct attribute_group ci_attr_group = { +static const struct attribute_group ci_attr_group = {  	.attrs = ci_attrs,  }; diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c index 949183ede16f..5ea0246f650d 100644 --- a/drivers/usb/chipidea/otg_fsm.c +++ b/drivers/usb/chipidea/otg_fsm.c @@ -193,7 +193,7 @@ static struct attribute *inputs_attrs[] = {  	NULL,  }; -static struct attribute_group inputs_attr_group = { +static const struct attribute_group inputs_attr_group = {  	.name = "inputs",  	.attrs = inputs_attrs,  }; diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index d68b125796f9..fe8a90543ea3 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -944,7 +944,6 @@ isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req)   */  static int isr_setup_status_phase(struct ci_hdrc *ci)  { -	int retval;  	struct ci_hw_ep *hwep;  	/* @@ -960,9 +959,7 @@ static int isr_setup_status_phase(struct ci_hdrc *ci)  	ci->status->context = ci;  	ci->status->complete = isr_setup_status_complete; -	retval = _ep_queue(&hwep->ep, ci->status, GFP_ATOMIC); - -	return retval; +	return _ep_queue(&hwep->ep, ci->status, GFP_ATOMIC);  }  /** @@ -1899,6 +1896,9 @@ static int udc_start(struct ci_hdrc *ci)  	ci->gadget.name         = ci->platdata->name;  	ci->gadget.otg_caps	= otg_caps; +	if (ci->platdata->flags & CI_HDRC_REQUIRES_ALIGNED_DMA) +		ci->gadget.quirk_avoids_skb_reserve = 1; +  	if (ci->is_otg && (otg_caps->hnp_support || otg_caps->srp_support ||  						otg_caps->adp_support))  		ci->gadget.is_otg = 1; diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 8f972247b1c1..5aacea1978a5 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -26,10 +26,6 @@  #include <asm/unaligned.h>  #include <linux/usb/cdc-wdm.h> -/* - * Version Information - */ -#define DRIVER_VERSION "v0.03"  #define DRIVER_AUTHOR "Oliver Neukum"  #define DRIVER_DESC "USB Abstract Control Model driver for USB WCM Device Management" diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c index 578f424decc2..6ebfabfa0dc7 100644 --- a/drivers/usb/class/usbtmc.c +++ b/drivers/usb/class/usbtmc.c @@ -1085,7 +1085,7 @@ static struct attribute *capability_attrs[] = {  	NULL,  }; -static struct attribute_group capability_attr_grp = { +static const struct attribute_group capability_attr_grp = {  	.attrs = capability_attrs,  }; @@ -1151,7 +1151,7 @@ static struct attribute *data_attrs[] = {  	NULL,  }; -static struct attribute_group data_attr_grp = { +static const struct attribute_group data_attr_grp = {  	.attrs = data_attrs,  }; diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c index 5ef8da6e67c3..552ff7ac5a6b 100644 --- a/drivers/usb/common/common.c +++ b/drivers/usb/common/common.c @@ -190,10 +190,7 @@ EXPORT_SYMBOL_GPL(of_usb_get_dr_mode_by_phy);   */  bool of_usb_host_tpl_support(struct device_node *np)  { -	if (of_find_property(np, "tpl-support", NULL)) -		return true; - -	return false; +	return of_property_read_bool(np, "tpl-support");  }  EXPORT_SYMBOL_GPL(of_usb_host_tpl_support); @@ -227,8 +224,8 @@ int of_usb_update_otg_caps(struct device_node *np,  				otg_caps->otg_rev = otg_rev;  			break;  		default: -			pr_err("%s: unsupported otg-rev: 0x%x\n", -						np->full_name, otg_rev); +			pr_err("%pOF: unsupported otg-rev: 0x%x\n", +						np, otg_rev);  			return -EINVAL;  		}  	} else { @@ -240,11 +237,11 @@ int of_usb_update_otg_caps(struct device_node *np,  		otg_caps->otg_rev = 0;  	} -	if (of_find_property(np, "hnp-disable", NULL)) +	if (of_property_read_bool(np, "hnp-disable"))  		otg_caps->hnp_support = false; -	if (of_find_property(np, "srp-disable", NULL)) +	if (of_property_read_bool(np, "srp-disable"))  		otg_caps->srp_support = false; -	if (of_find_property(np, "adp-disable", NULL) || +	if (of_property_read_bool(np, "adp-disable") ||  				(otg_caps->otg_rev < 0x0200))  		otg_caps->adp_support = false; diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c index 930e8f35f8df..4aa5195db8ea 100644 --- a/drivers/usb/common/ulpi.c +++ b/drivers/usb/common/ulpi.c @@ -135,7 +135,7 @@ static void ulpi_dev_release(struct device *dev)  	kfree(to_ulpi_dev(dev));  } -static struct device_type ulpi_dev_type = { +static const struct device_type ulpi_dev_type = {  	.name = "ulpi_device",  	.groups = ulpi_dev_attr_groups,  	.release = ulpi_dev_release, diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index ebe27595c4af..318bb3b96687 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -210,7 +210,7 @@ static void usbdev_vm_close(struct vm_area_struct *vma)  	dec_usb_memory_use_count(usbm, &usbm->vma_use_count);  } -static struct vm_operations_struct usbdev_vm_ops = { +static const struct vm_operations_struct usbdev_vm_ops = {  	.open = usbdev_vm_open,  	.close = usbdev_vm_close  }; @@ -623,6 +623,8 @@ static void async_completed(struct urb *urb)  	if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET &&  			as->status != -ENOENT)  		cancel_bulk_urbs(ps, as->bulk_addr); + +	wake_up(&ps->wait);  	spin_unlock(&ps->lock);  	if (signr) { @@ -630,8 +632,6 @@ static void async_completed(struct urb *urb)  		put_pid(pid);  		put_cred(cred);  	} - -	wake_up(&ps->wait);  }  static void destroy_async(struct usb_dev_state *ps, struct list_head *list) diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 7f277b092b5b..75ad6718858c 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -972,7 +972,7 @@ static struct attribute *usb_bus_attrs[] = {  		NULL,  }; -static struct attribute_group usb_bus_attr_group = { +static const struct attribute_group usb_bus_attr_group = {  	.name = NULL,	/* we want them in the same directory */  	.attrs = usb_bus_attrs,  }; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 822f8c50e423..41eaf0b52518 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2614,7 +2614,7 @@ static unsigned hub_is_wusb(struct usb_hub *hub)  #define SET_CONFIG_TRIES	(2 * (use_both_schemes + 1))  #define USE_NEW_SCHEME(i)	((i) / 2 == (int)old_scheme_first) -#define HUB_ROOT_RESET_TIME	50	/* times are in msec */ +#define HUB_ROOT_RESET_TIME	60	/* times are in msec */  #define HUB_SHORT_RESET_TIME	10  #define HUB_BH_RESET_TIME	50  #define HUB_LONG_RESET_TIME	200 @@ -4342,6 +4342,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,  	enum usb_device_speed	oldspeed = udev->speed;  	const char		*speed;  	int			devnum = udev->devnum; +	const char		*driver_name;  	/* root hub ports have a slightly longer reset period  	 * (from USB 2.0 spec, section 7.1.7.5) @@ -4409,11 +4410,23 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,  	else  		speed = usb_speed_string(udev->speed); +	/* +	 * The controller driver may be NULL if the controller device +	 * is the middle device between platform device and roothub. +	 * This middle device may not need a device driver due to +	 * all hardware control can be at platform device driver, this +	 * platform device is usually a dual-role USB controller device. +	 */ +	if (udev->bus->controller->driver) +		driver_name = udev->bus->controller->driver->name; +	else +		driver_name = udev->bus->sysdev->driver->name; +  	if (udev->speed < USB_SPEED_SUPER)  		dev_info(&udev->dev,  				"%s %s USB device number %d using %s\n",  				(udev->config) ? "reset" : "new", speed, -				devnum, udev->bus->controller->driver->name); +				devnum, driver_name);  	/* Set up TT records, if needed  */  	if (hdev->tt) { @@ -4545,7 +4558,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1,  						"%s SuperSpeed%s USB device number %d using %s\n",  						(udev->config) ? "reset" : "new",  					 (udev->speed == USB_SPEED_SUPER_PLUS) ? "Plus" : "", -						devnum, udev->bus->controller->driver->name); +					 devnum, driver_name);  			}  			/* cope with hardware quirkiness: diff --git a/drivers/usb/core/ledtrig-usbport.c b/drivers/usb/core/ledtrig-usbport.c index 16c19a31dad1..1af877942110 100644 --- a/drivers/usb/core/ledtrig-usbport.c +++ b/drivers/usb/core/ledtrig-usbport.c @@ -149,8 +149,8 @@ static bool usbport_trig_port_observed(struct usbport_trig_data *usbport_data,  	count = of_count_phandle_with_args(led_np, "trigger-sources",  					   "#trigger-source-cells");  	if (count < 0) { -		dev_warn(dev, "Failed to get trigger sources for %s\n", -			 led_np->full_name); +		dev_warn(dev, "Failed to get trigger sources for %pOF\n", +			 led_np);  		return false;  	} @@ -205,6 +205,7 @@ static int usbport_trig_add_port(struct usbport_trig_data *usbport_data,  	}  	snprintf(port->port_name, len, "%s-port%d", hub_name, portnum); +	sysfs_attr_init(&port->attr.attr);  	port->attr.attr.name = port->port_name;  	port->attr.attr.mode = S_IRUSR | S_IWUSR;  	port->attr.show = usbport_trig_port_show; diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 574da2b4529c..82806e311202 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -57,8 +57,9 @@ static const struct usb_device_id usb_quirk_list[] = {  	/* Microsoft LifeCam-VX700 v2.0 */  	{ USB_DEVICE(0x045e, 0x0770), .driver_info = USB_QUIRK_RESET_RESUME }, -	/* Logitech HD Pro Webcams C920 and C930e */ +	/* Logitech HD Pro Webcams C920, C920-C and C930e */  	{ USB_DEVICE(0x046d, 0x082d), .driver_info = USB_QUIRK_DELAY_INIT }, +	{ USB_DEVICE(0x046d, 0x0841), .driver_info = USB_QUIRK_DELAY_INIT },  	{ USB_DEVICE(0x046d, 0x0843), .driver_info = USB_QUIRK_DELAY_INIT },  	/* Logitech ConferenceCam CC3000e */ @@ -217,6 +218,9 @@ static const struct usb_device_id usb_quirk_list[] = {  	{ USB_DEVICE(0x1a0a, 0x0200), .driver_info =  			USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL }, +	/* Corsair Strafe RGB */ +	{ USB_DEVICE(0x1b1c, 0x1b20), .driver_info = USB_QUIRK_DELAY_INIT }, +  	/* Acer C120 LED Projector */  	{ USB_DEVICE(0x1de1, 0xc102), .driver_info = USB_QUIRK_NO_LPM }, diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index dfc68ed24db1..d930bfda4010 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -113,7 +113,7 @@ static ssize_t devspec_show(struct device *dev, struct device_attribute *attr,  {  	struct device_node *of_node = dev->of_node; -	return sprintf(buf, "%s\n", of_node_full_name(of_node)); +	return sprintf(buf, "%pOF\n", of_node);  }  static DEVICE_ATTR_RO(devspec);  #endif diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index c4066cd77e47..0d8e09ccb59c 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -4179,7 +4179,7 @@ static int dwc2_hsotg_ep_sethalt_lock(struct usb_ep *ep, int value)  	return ret;  } -static struct usb_ep_ops dwc2_hsotg_ep_ops = { +static const struct usb_ep_ops dwc2_hsotg_ep_ops = {  	.enable		= dwc2_hsotg_ep_enable,  	.disable	= dwc2_hsotg_ep_disable,  	.alloc_request	= dwc2_hsotg_ep_alloc_request, diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 740c7e86d31b..c2631145f404 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -4388,6 +4388,9 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd)  	spin_lock_irqsave(&hsotg->lock, flags); +	if (dwc2_is_device_mode(hsotg)) +		goto unlock; +  	if (hsotg->lx_state != DWC2_L0)  		goto unlock; @@ -4446,6 +4449,9 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)  	spin_lock_irqsave(&hsotg->lock, flags); +	if (dwc2_is_device_mode(hsotg)) +		goto unlock; +  	if (hsotg->lx_state != DWC2_L2)  		goto unlock; diff --git a/drivers/usb/dwc3/dwc3-keystone.c b/drivers/usb/dwc3/dwc3-keystone.c index 12ee23f53cdd..d2ed9523e77c 100644 --- a/drivers/usb/dwc3/dwc3-keystone.c +++ b/drivers/usb/dwc3/dwc3-keystone.c @@ -15,7 +15,6 @@   * GNU General Public License for more details.   */ -#include <linux/clk.h>  #include <linux/module.h>  #include <linux/kernel.h>  #include <linux/interrupt.h> @@ -23,6 +22,7 @@  #include <linux/dma-mapping.h>  #include <linux/io.h>  #include <linux/of_platform.h> +#include <linux/pm_runtime.h>  /* USBSS register offsets */  #define USBSS_REVISION		0x0000 @@ -41,7 +41,6 @@  struct dwc3_keystone {  	struct device			*dev; -	struct clk			*clk;  	void __iomem			*usbss;  }; @@ -106,17 +105,13 @@ static int kdwc3_probe(struct platform_device *pdev)  	if (IS_ERR(kdwc->usbss))  		return PTR_ERR(kdwc->usbss); -	kdwc->clk = devm_clk_get(kdwc->dev, "usb"); -	if (IS_ERR(kdwc->clk)) { -		dev_err(kdwc->dev, "unable to get usb clock\n"); -		return PTR_ERR(kdwc->clk); -	} +	pm_runtime_enable(kdwc->dev); -	error = clk_prepare_enable(kdwc->clk); +	error = pm_runtime_get_sync(kdwc->dev);  	if (error < 0) { -		dev_err(kdwc->dev, "unable to enable usb clock, error %d\n", +		dev_err(kdwc->dev, "pm_runtime_get_sync failed, error %d\n",  			error); -		return error; +		goto err_irq;  	}  	irq = platform_get_irq(pdev, 0); @@ -147,7 +142,8 @@ static int kdwc3_probe(struct platform_device *pdev)  err_core:  	kdwc3_disable_irqs(kdwc);  err_irq: -	clk_disable_unprepare(kdwc->clk); +	pm_runtime_put_sync(kdwc->dev); +	pm_runtime_disable(kdwc->dev);  	return error;  } @@ -167,7 +163,9 @@ static int kdwc3_remove(struct platform_device *pdev)  	kdwc3_disable_irqs(kdwc);  	device_for_each_child(&pdev->dev, NULL, kdwc3_remove_core); -	clk_disable_unprepare(kdwc->clk); +	pm_runtime_put_sync(kdwc->dev); +	pm_runtime_disable(kdwc->dev); +  	platform_set_drvdata(pdev, NULL);  	return 0; diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of-simple.c index fe414e7a9c78..4cef7d4f9cd0 100644 --- a/drivers/usb/dwc3/dwc3-of-simple.c +++ b/drivers/usb/dwc3/dwc3-of-simple.c @@ -25,7 +25,6 @@  #include <linux/platform_device.h>  #include <linux/dma-mapping.h>  #include <linux/clk.h> -#include <linux/clk-provider.h>  #include <linux/of.h>  #include <linux/of_platform.h>  #include <linux/pm_runtime.h> @@ -96,7 +95,8 @@ static int dwc3_of_simple_probe(struct platform_device *pdev)  	platform_set_drvdata(pdev, simple);  	simple->dev = dev; -	ret = dwc3_of_simple_clk_init(simple, of_clk_get_parent_count(np)); +	ret = dwc3_of_simple_clk_init(simple, of_count_phandle_with_args(np, +						"clocks", "#clock-cells"));  	if (ret)  		return ret; diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index f5aaa0cf3873..3530795bbb8f 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -478,8 +478,8 @@ static int dwc3_omap_probe(struct platform_device *pdev)  	irq = platform_get_irq(pdev, 0);  	if (irq < 0) { -		dev_err(dev, "missing IRQ resource\n"); -		return -EINVAL; +		dev_err(dev, "missing IRQ resource: %d\n", irq); +		return irq;  	}  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 7e995df7a797..54343fbd85ee 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -345,7 +345,7 @@ static int dwc3_pci_resume(struct device *dev)  }  #endif /* CONFIG_PM_SLEEP */ -static struct dev_pm_ops dwc3_pci_dev_pm_ops = { +static const struct dev_pm_ops dwc3_pci_dev_pm_ops = {  	SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_suspend, dwc3_pci_resume)  	SET_RUNTIME_PM_OPS(dwc3_pci_runtime_suspend, dwc3_pci_runtime_resume,  		NULL) diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 35cc641d9f31..31cce7805eb2 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -130,7 +130,7 @@ config USB_GADGET_STORAGE_NUM_BUFFERS  config U_SERIAL_CONSOLE  	bool "Serial gadget console support" -	depends on USB_G_SERIAL +	depends on USB_U_SERIAL  	help  	   It supports the serial gadget can be used as a console. diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index d21874b35cf6..9990944a7245 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -961,10 +961,9 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)  		/* In the meantime, endpoint got disabled or changed. */  		ret = -ESHUTDOWN;  	} else if (halt) { -		/* Halt */ -		if (likely(epfile->ep == ep) && !WARN_ON(!ep->ep)) -			usb_ep_set_halt(ep->ep); -		ret = -EBADMSG; +		ret = usb_ep_set_halt(ep->ep); +		if (!ret) +			ret = -EBADMSG;  	} else if (unlikely(data_len == -EINVAL)) {  		/*  		 * Sanity Check: even though data_len can't be used diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index 5eea44823ca0..d8e359ef6eb1 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -44,6 +44,7 @@ struct f_hidg {  	/* configuration */  	unsigned char			bInterfaceSubClass;  	unsigned char			bInterfaceProtocol; +	unsigned char			protocol;  	unsigned short			report_desc_length;  	char				*report_desc;  	unsigned short			report_length; @@ -527,7 +528,9 @@ static int hidg_setup(struct usb_function *f,  	case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8  		  | HID_REQ_GET_PROTOCOL):  		VDBG(cdev, "get_protocol\n"); -		goto stall; +		length = min_t(unsigned int, length, 1); +		((u8 *) req->buf)[0] = hidg->protocol; +		goto respond;  		break;  	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8 @@ -539,6 +542,17 @@ static int hidg_setup(struct usb_function *f,  	case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8  		  | HID_REQ_SET_PROTOCOL):  		VDBG(cdev, "set_protocol\n"); +		if (value > HID_REPORT_PROTOCOL) +			goto stall; +		length = 0; +		/* +		 * We assume that programs implementing the Boot protocol +		 * are also compatible with the Report Protocol +		 */ +		if (hidg->bInterfaceSubClass == USB_INTERFACE_SUBCLASS_BOOT) { +			hidg->protocol = value; +			goto respond; +		}  		goto stall;  		break; @@ -768,6 +782,7 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f)  	/* set descriptor dynamic values */  	hidg_interface_desc.bInterfaceSubClass = hidg->bInterfaceSubClass;  	hidg_interface_desc.bInterfaceProtocol = hidg->bInterfaceProtocol; +	hidg->protocol = HID_REPORT_PROTOCOL;  	hidg_ss_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);  	hidg_ss_in_comp_desc.wBytesPerInterval =  				cpu_to_le16(hidg->report_length); diff --git a/drivers/usb/gadget/function/f_midi.c b/drivers/usb/gadget/function/f_midi.c index a5719f271bf0..5d3d7941d2c2 100644 --- a/drivers/usb/gadget/function/f_midi.c +++ b/drivers/usb/gadget/function/f_midi.c @@ -98,6 +98,7 @@ struct f_midi {  	DECLARE_KFIFO_PTR(in_req_fifo, struct usb_request *);  	spinlock_t transmit_lock;  	unsigned int in_last_port; +	unsigned char free_ref;  	struct gmidi_in_port	in_ports_array[/* in_ports */];  }; @@ -108,6 +109,7 @@ static inline struct f_midi *func_to_midi(struct usb_function *f)  }  static void f_midi_transmit(struct f_midi *midi); +static void f_midi_rmidi_free(struct snd_rawmidi *rmidi);  DECLARE_UAC_AC_HEADER_DESCRIPTOR(1);  DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1); @@ -163,6 +165,13 @@ static struct usb_endpoint_descriptor bulk_out_desc = {  	.bmAttributes =		USB_ENDPOINT_XFER_BULK,  }; +static struct usb_ss_ep_comp_descriptor bulk_out_ss_comp_desc = { +	.bLength                = sizeof(bulk_out_ss_comp_desc), +	.bDescriptorType        = USB_DT_SS_ENDPOINT_COMP, +	/* .bMaxBurst           = 0, */ +	/* .bmAttributes        = 0, */ +}; +  /* B.5.2  Class-specific MS Bulk OUT Endpoint Descriptor */  static struct usb_ms_endpoint_descriptor_16 ms_out_desc = {  	/* .bLength =		DYNAMIC */ @@ -180,6 +189,13 @@ static struct usb_endpoint_descriptor bulk_in_desc = {  	.bmAttributes =		USB_ENDPOINT_XFER_BULK,  }; +static struct usb_ss_ep_comp_descriptor bulk_in_ss_comp_desc = { +	.bLength                = sizeof(bulk_in_ss_comp_desc), +	.bDescriptorType        = USB_DT_SS_ENDPOINT_COMP, +	/* .bMaxBurst           = 0, */ +	/* .bmAttributes        = 0, */ +}; +  /* B.6.2  Class-specific MS Bulk IN Endpoint Descriptor */  static struct usb_ms_endpoint_descriptor_16 ms_in_desc = {  	/* .bLength =		DYNAMIC */ @@ -755,13 +771,13 @@ static void f_midi_out_trigger(struct snd_rawmidi_substream *substream, int up)  		clear_bit(substream->number, &midi->out_triggered);  } -static struct snd_rawmidi_ops gmidi_in_ops = { +static const struct snd_rawmidi_ops gmidi_in_ops = {  	.open = f_midi_in_open,  	.close = f_midi_in_close,  	.trigger = f_midi_in_trigger,  }; -static struct snd_rawmidi_ops gmidi_out_ops = { +static const struct snd_rawmidi_ops gmidi_out_ops = {  	.open = f_midi_out_open,  	.close = f_midi_out_close,  	.trigger = f_midi_out_trigger @@ -818,6 +834,8 @@ static int f_midi_register_card(struct f_midi *midi)  			    SNDRV_RAWMIDI_INFO_INPUT |  			    SNDRV_RAWMIDI_INFO_DUPLEX;  	rmidi->private_data = midi; +	rmidi->private_free = f_midi_rmidi_free; +	midi->free_ref++;  	/*  	 * Yes, rawmidi OUTPUT = USB IN, and rawmidi INPUT = USB OUT. @@ -853,7 +871,7 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)  	struct usb_composite_dev *cdev = c->cdev;  	struct f_midi *midi = func_to_midi(f);  	struct usb_string *us; -	int status, n, jack = 1, i = 0; +	int status, n, jack = 1, i = 0, endpoint_descriptor_index = 0;  	midi->gadget = cdev->gadget;  	tasklet_init(&midi->tasklet, f_midi_in_tasklet, (unsigned long) midi); @@ -895,7 +913,7 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)  		goto fail;  	/* allocate temporary function list */ -	midi_function = kcalloc((MAX_PORTS * 4) + 9, sizeof(*midi_function), +	midi_function = kcalloc((MAX_PORTS * 4) + 11, sizeof(*midi_function),  				GFP_KERNEL);  	if (!midi_function) {  		status = -ENOMEM; @@ -985,6 +1003,7 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)  	ms_in_desc.bNumEmbMIDIJack = midi->out_ports;  	/* ... and add them to the list */ +	endpoint_descriptor_index = i;  	midi_function[i++] = (struct usb_descriptor_header *) &bulk_out_desc;  	midi_function[i++] = (struct usb_descriptor_header *) &ms_out_desc;  	midi_function[i++] = (struct usb_descriptor_header *) &bulk_in_desc; @@ -1009,13 +1028,34 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)  			goto fail_f_midi;  	} +	if (gadget_is_superspeed(c->cdev->gadget)) { +		bulk_in_desc.wMaxPacketSize = cpu_to_le16(1024); +		bulk_out_desc.wMaxPacketSize = cpu_to_le16(1024); +		i = endpoint_descriptor_index; +		midi_function[i++] = (struct usb_descriptor_header *) +				     &bulk_out_desc; +		midi_function[i++] = (struct usb_descriptor_header *) +				     &bulk_out_ss_comp_desc; +		midi_function[i++] = (struct usb_descriptor_header *) +				     &ms_out_desc; +		midi_function[i++] = (struct usb_descriptor_header *) +				     &bulk_in_desc; +		midi_function[i++] = (struct usb_descriptor_header *) +				     &bulk_in_ss_comp_desc; +		midi_function[i++] = (struct usb_descriptor_header *) +				     &ms_in_desc; +		f->ss_descriptors = usb_copy_descriptors(midi_function); +		if (!f->ss_descriptors) +			goto fail_f_midi; +	} +  	kfree(midi_function);  	return 0;  fail_f_midi:  	kfree(midi_function); -	usb_free_descriptors(f->hs_descriptors); +	usb_free_all_descriptors(f);  fail:  	f_midi_unregister_card(midi);  fail_register: @@ -1197,14 +1237,21 @@ static void f_midi_free(struct usb_function *f)  	midi = func_to_midi(f);  	opts = container_of(f->fi, struct f_midi_opts, func_inst); -	kfree(midi->id);  	mutex_lock(&opts->lock); -	kfifo_free(&midi->in_req_fifo); -	kfree(midi); -	--opts->refcnt; +	if (!--midi->free_ref) { +		kfree(midi->id); +		kfifo_free(&midi->in_req_fifo); +		kfree(midi); +		--opts->refcnt; +	}  	mutex_unlock(&opts->lock);  } +static void f_midi_rmidi_free(struct snd_rawmidi *rmidi) +{ +	f_midi_free(rmidi->private_data); +} +  static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f)  {  	struct usb_composite_dev *cdev = f->config->cdev; @@ -1219,7 +1266,7 @@ static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f)  	card = midi->card;  	midi->card = NULL;  	if (card) -		snd_card_free(card); +		snd_card_free_when_closed(card);  	usb_free_all_descriptors(f);  } @@ -1263,6 +1310,7 @@ static struct usb_function *f_midi_alloc(struct usb_function_instance *fi)  	midi->buflen = opts->buflen;  	midi->qlen = opts->qlen;  	midi->in_last_port = 0; +	midi->free_ref = 1;  	status = kfifo_alloc(&midi->in_req_fifo, midi->qlen, GFP_KERNEL);  	if (status) diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index 24e34cfcb4bd..45b334ceaf2e 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -925,8 +925,6 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)  			 */  			ncm->port.is_zlp_ok =  				gadget_is_zlp_supported(cdev->gadget); -			ncm->port.no_skb_reserve = -				gadget_avoids_skb_reserve(cdev->gadget);  			ncm->port.cdc_filter = DEFAULT_FILTER;  			DBG(cdev, "activate ncm\n");  			net = gether_connect(&ncm->port); diff --git a/drivers/usb/gadget/function/f_rndis.c b/drivers/usb/gadget/function/f_rndis.c index 16562e461121..e1d5853ef1e4 100644 --- a/drivers/usb/gadget/function/f_rndis.c +++ b/drivers/usb/gadget/function/f_rndis.c @@ -691,6 +691,10 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)  		f->os_desc_table[0].os_desc = &rndis_opts->rndis_os_desc;  	} +	rndis_iad_descriptor.bFunctionClass = rndis_opts->class; +	rndis_iad_descriptor.bFunctionSubClass = rndis_opts->subclass; +	rndis_iad_descriptor.bFunctionProtocol = rndis_opts->protocol; +  	/*  	 * in drivers/usb/gadget/configfs.c:configfs_composite_bind()  	 * configurations are bound in sequence with list_for_each_entry, @@ -866,11 +870,23 @@ USB_ETHERNET_CONFIGFS_ITEM_ATTR_QMULT(rndis);  /* f_rndis_opts_ifname */  USB_ETHERNET_CONFIGFS_ITEM_ATTR_IFNAME(rndis); +/* f_rndis_opts_class */ +USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(rndis, class); + +/* f_rndis_opts_subclass */ +USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(rndis, subclass); + +/* f_rndis_opts_protocol */ +USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(rndis, protocol); +  static struct configfs_attribute *rndis_attrs[] = {  	&rndis_opts_attr_dev_addr,  	&rndis_opts_attr_host_addr,  	&rndis_opts_attr_qmult,  	&rndis_opts_attr_ifname, +	&rndis_opts_attr_class, +	&rndis_opts_attr_subclass, +	&rndis_opts_attr_protocol,  	NULL,  }; @@ -916,6 +932,10 @@ static struct usb_function_instance *rndis_alloc_inst(void)  	}  	INIT_LIST_HEAD(&opts->rndis_os_desc.ext_prop); +	opts->class = rndis_iad_descriptor.bFunctionClass; +	opts->subclass = rndis_iad_descriptor.bFunctionSubClass; +	opts->protocol = rndis_iad_descriptor.bFunctionProtocol; +  	descs[0] = &opts->rndis_os_desc;  	names[0] = "rndis";  	config_group_init_type_name(&opts->func_inst.group, "", diff --git a/drivers/usb/gadget/function/u_audio.c b/drivers/usb/gadget/function/u_audio.c index 5dd73b9e5172..3971bbab88bd 100644 --- a/drivers/usb/gadget/function/u_audio.c +++ b/drivers/usb/gadget/function/u_audio.c @@ -79,7 +79,7 @@ struct snd_uac_chip {  	unsigned int p_framesize;  }; -static struct snd_pcm_hardware uac_pcm_hardware = { +static const struct snd_pcm_hardware uac_pcm_hardware = {  	.info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER  		 | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID  		 | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, @@ -354,7 +354,7 @@ static int uac_pcm_null(struct snd_pcm_substream *substream)  	return 0;  } -static struct snd_pcm_ops uac_pcm_ops = { +static const struct snd_pcm_ops uac_pcm_ops = {  	.open = uac_pcm_open,  	.close = uac_pcm_null,  	.ioctl = snd_pcm_lib_ioctl, diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index a8b40d07e927..bdbc3fdc7c4f 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -1073,7 +1073,7 @@ struct net_device *gether_connect(struct gether *link)  	if (result == 0) {  		dev->zlp = link->is_zlp_ok; -		dev->no_skb_reserve = link->no_skb_reserve; +		dev->no_skb_reserve = gadget_avoids_skb_reserve(dev->gadget);  		DBG(dev, "qlen %d\n", qlen(dev->gadget, dev->qmult));  		dev->header_len = link->header_len; diff --git a/drivers/usb/gadget/function/u_ether.h b/drivers/usb/gadget/function/u_ether.h index 81d94a7ae4b4..c77145bd6b5b 100644 --- a/drivers/usb/gadget/function/u_ether.h +++ b/drivers/usb/gadget/function/u_ether.h @@ -64,7 +64,6 @@ struct gether {  	struct usb_ep			*out_ep;  	bool				is_zlp_ok; -	bool				no_skb_reserve;  	u16				cdc_filter; diff --git a/drivers/usb/gadget/function/u_ether_configfs.h b/drivers/usb/gadget/function/u_ether_configfs.h index c71133de17e7..e4c3f84af4c3 100644 --- a/drivers/usb/gadget/function/u_ether_configfs.h +++ b/drivers/usb/gadget/function/u_ether_configfs.h @@ -153,4 +153,39 @@ out:									\  									\  	CONFIGFS_ATTR_RO(_f_##_opts_, ifname) +#define USB_ETHER_CONFIGFS_ITEM_ATTR_U8_RW(_f_, _n_)			\ +	static ssize_t _f_##_opts_##_n_##_show(struct config_item *item,\ +					       char *page)		\ +	{								\ +		struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item);	\ +		int ret;						\ +									\ +		mutex_lock(&opts->lock);				\ +		ret = sprintf(page, "%02x\n", opts->_n_);		\ +		mutex_unlock(&opts->lock);				\ +									\ +		return ret;						\ +	}								\ +									\ +	static ssize_t _f_##_opts_##_n_##_store(struct config_item *item,\ +						const char *page,	\ +						size_t len)		\ +	{								\ +		struct f_##_f_##_opts *opts = to_f_##_f_##_opts(item);	\ +		int ret;						\ +		u8 val;							\ +									\ +		mutex_lock(&opts->lock);				\ +		ret = sscanf(page, "%02hhx", &val);			\ +		if (ret > 0) {						\ +			opts->_n_ = val;				\ +			ret = len;					\ +		}							\ +		mutex_unlock(&opts->lock);				\ +									\ +		return ret;						\ +	}								\ +									\ +	CONFIGFS_ATTR(_f_##_opts_, _n_) +  #endif /* __U_ETHER_CONFIGFS_H */ diff --git a/drivers/usb/gadget/function/u_rndis.h b/drivers/usb/gadget/function/u_rndis.h index 4eafd5050545..a35ee3c2545d 100644 --- a/drivers/usb/gadget/function/u_rndis.h +++ b/drivers/usb/gadget/function/u_rndis.h @@ -29,6 +29,10 @@ struct f_rndis_opts {  	struct usb_os_desc		rndis_os_desc;  	char				rndis_ext_compat_id[16]; +	u8				class; +	u8				subclass; +	u8				protocol; +  	/*  	 * Read/write access to configfs attributes is handled by configfs.  	 * diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c index 9b0805f55ad7..4176216d54be 100644 --- a/drivers/usb/gadget/function/u_serial.c +++ b/drivers/usb/gadget/function/u_serial.c @@ -537,7 +537,7 @@ static void gs_rx_push(unsigned long _port)  		}  		/* push data to (open) tty */ -		if (req->actual) { +		if (req->actual && tty) {  			char		*packet = req->buf;  			unsigned	size = req->actual;  			unsigned	n; diff --git a/drivers/usb/gadget/legacy/webcam.c b/drivers/usb/gadget/legacy/webcam.c index f9661cd627c8..82c13fce9232 100644 --- a/drivers/usb/gadget/legacy/webcam.c +++ b/drivers/usb/gadget/legacy/webcam.c @@ -436,5 +436,4 @@ module_usb_composite_driver(webcam_driver);  MODULE_AUTHOR("Laurent Pinchart");  MODULE_DESCRIPTION("Webcam Video Gadget");  MODULE_LICENSE("GPL"); -MODULE_VERSION("0.1.0"); diff --git a/drivers/usb/gadget/udc/bdc/Kconfig b/drivers/usb/gadget/udc/bdc/Kconfig index eb8b55392360..c74ac25dddcd 100644 --- a/drivers/usb/gadget/udc/bdc/Kconfig +++ b/drivers/usb/gadget/udc/bdc/Kconfig @@ -1,6 +1,7 @@  config USB_BDC_UDC  	tristate "Broadcom USB3.0 device controller IP driver(BDC)"  	depends on USB_GADGET && HAS_DMA +	default ARCH_BRCMSTB  	help  	BDC is Broadcom's USB3.0 device controller IP. If your SOC has a BDC IP diff --git a/drivers/usb/gadget/udc/bdc/bdc.h b/drivers/usb/gadget/udc/bdc/bdc.h index 916d47135cac..6df0352cdc50 100644 --- a/drivers/usb/gadget/udc/bdc/bdc.h +++ b/drivers/usb/gadget/udc/bdc/bdc.h @@ -27,8 +27,8 @@  #include <linux/usb/gadget.h>  #include <asm/unaligned.h> -#define BRCM_BDC_NAME "bdc_usb3" -#define BRCM_BDC_DESC "BDC device controller driver" +#define BRCM_BDC_NAME "bdc" +#define BRCM_BDC_DESC "Broadcom USB Device Controller driver"  #define DMA_ADDR_INVALID        (~(dma_addr_t)0) @@ -83,14 +83,14 @@  #define BDC_DVCSA	0x50  #define BDC_DVCSB	0x54 -#define BDC_EPSTS0(n)	(0x60 + (n * 0x10)) -#define BDC_EPSTS1(n)	(0x64 + (n * 0x10)) -#define BDC_EPSTS2(n)	(0x68 + (n * 0x10)) -#define BDC_EPSTS3(n)	(0x6c + (n * 0x10)) -#define BDC_EPSTS4(n)	(0x70 + (n * 0x10)) -#define BDC_EPSTS5(n)	(0x74 + (n * 0x10)) -#define BDC_EPSTS6(n)	(0x78 + (n * 0x10)) -#define BDC_EPSTS7(n)	(0x7c + (n * 0x10)) +#define BDC_EPSTS0	0x60 +#define BDC_EPSTS1	0x64 +#define BDC_EPSTS2	0x68 +#define BDC_EPSTS3	0x6c +#define BDC_EPSTS4	0x70 +#define BDC_EPSTS5	0x74 +#define BDC_EPSTS6	0x78 +#define BDC_EPSTS7	0x7c  #define BDC_SRRBAL(n)	(0x200 + (n * 0x10))  #define BDC_SRRBAH(n)	(0x204 + (n * 0x10))  #define BDC_SRRINT(n)	(0x208 + (n * 0x10)) @@ -413,6 +413,9 @@ struct bdc {  	/* device lock */  	spinlock_t	lock; +	/* generic phy */ +	struct phy      **phys; +	int num_phys;  	/* num of endpoints for a particular instantiation of IP */  	unsigned int num_eps;  	/* @@ -454,6 +457,7 @@ struct bdc {  	 * Func Wake packet every 2.5 secs. Refer to USB3 spec section 8.5.6.4  	 */  	struct delayed_work	func_wake_notify; +	struct clk		*clk;  };  static inline u32 bdc_readl(void __iomem *base, u32 offset) diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c index e9bd8d4abca0..7a8af4b916cf 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_core.c +++ b/drivers/usb/gadget/udc/bdc/bdc_core.c @@ -24,9 +24,11 @@  #include <linux/dma-mapping.h>  #include <linux/dmapool.h>  #include <linux/of.h> +#include <linux/phy/phy.h>  #include <linux/moduleparam.h>  #include <linux/usb/ch9.h>  #include <linux/usb/gadget.h> +#include <linux/clk.h>  #include "bdc.h"  #include "bdc_dbg.h" @@ -444,6 +446,43 @@ static int bdc_hw_init(struct bdc *bdc)  	return 0;  } +static int bdc_phy_init(struct bdc *bdc) +{ +	int phy_num; +	int ret; + +	for (phy_num = 0; phy_num < bdc->num_phys; phy_num++) { +		ret = phy_init(bdc->phys[phy_num]); +		if (ret) +			goto err_exit_phy; +		ret = phy_power_on(bdc->phys[phy_num]); +		if (ret) { +			phy_exit(bdc->phys[phy_num]); +			goto err_exit_phy; +		} +	} + +	return 0; + +err_exit_phy: +	while (--phy_num >= 0) { +		phy_power_off(bdc->phys[phy_num]); +		phy_exit(bdc->phys[phy_num]); +	} + +	return ret; +} + +static void bdc_phy_exit(struct bdc *bdc) +{ +	int phy_num; + +	for (phy_num = 0; phy_num < bdc->num_phys; phy_num++) { +		phy_power_off(bdc->phys[phy_num]); +		phy_exit(bdc->phys[phy_num]); +	} +} +  static int bdc_probe(struct platform_device *pdev)  {  	struct bdc *bdc; @@ -452,12 +491,29 @@ static int bdc_probe(struct platform_device *pdev)  	int irq;  	u32 temp;  	struct device *dev = &pdev->dev; +	struct clk *clk; +	int phy_num;  	dev_dbg(dev, "%s()\n", __func__); + +	clk = devm_clk_get(dev, "sw_usbd"); +	if (IS_ERR(clk)) { +		dev_info(dev, "Clock not found in Device Tree\n"); +		clk = NULL; +	} + +	ret = clk_prepare_enable(clk); +	if (ret) { +		dev_err(dev, "could not enable clock\n"); +		return ret; +	} +  	bdc = devm_kzalloc(dev, sizeof(*bdc), GFP_KERNEL);  	if (!bdc)  		return -ENOMEM; +	bdc->clk = clk; +  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	bdc->regs = devm_ioremap_resource(dev, res);  	if (IS_ERR(bdc->regs)) { @@ -473,35 +529,66 @@ static int bdc_probe(struct platform_device *pdev)  	platform_set_drvdata(pdev, bdc);  	bdc->irq = irq;  	bdc->dev = dev; -	dev_dbg(bdc->dev, "bdc->regs: %p irq=%d\n", bdc->regs, bdc->irq); +	dev_dbg(dev, "bdc->regs: %p irq=%d\n", bdc->regs, bdc->irq); + +	bdc->num_phys = of_count_phandle_with_args(dev->of_node, +						"phys", "#phy-cells"); +	if (bdc->num_phys > 0) { +		bdc->phys = devm_kcalloc(dev, bdc->num_phys, +					sizeof(struct phy *), GFP_KERNEL); +		if (!bdc->phys) +			return -ENOMEM; +	} else { +		bdc->num_phys = 0; +	} +	dev_info(dev, "Using %d phy(s)\n", bdc->num_phys); + +	for (phy_num = 0; phy_num < bdc->num_phys; phy_num++) { +		bdc->phys[phy_num] = devm_of_phy_get_by_index( +			dev, dev->of_node, phy_num); +		if (IS_ERR(bdc->phys[phy_num])) { +			ret = PTR_ERR(bdc->phys[phy_num]); +			dev_err(bdc->dev, +				"BDC phy specified but not found:%d\n", ret); +			return ret; +		} +	} + +	ret = bdc_phy_init(bdc); +	if (ret) { +		dev_err(bdc->dev, "BDC phy init failure:%d\n", ret); +		return ret; +	}  	temp = bdc_readl(bdc->regs, BDC_BDCCAP1);  	if ((temp & BDC_P64) &&  			!dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64))) { -		dev_dbg(bdc->dev, "Using 64-bit address\n"); +		dev_dbg(dev, "Using 64-bit address\n");  	} else { -		ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); +		ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));  		if (ret) { -			dev_err(bdc->dev, "No suitable DMA config available, abort\n"); +			dev_err(dev, +				"No suitable DMA config available, abort\n");  			return -ENOTSUPP;  		} -		dev_dbg(bdc->dev, "Using 32-bit address\n"); +		dev_dbg(dev, "Using 32-bit address\n");  	}  	ret = bdc_hw_init(bdc);  	if (ret) { -		dev_err(bdc->dev, "BDC init failure:%d\n", ret); -		return ret; +		dev_err(dev, "BDC init failure:%d\n", ret); +		goto phycleanup;  	}  	ret = bdc_udc_init(bdc);  	if (ret) { -		dev_err(bdc->dev, "BDC Gadget init failure:%d\n", ret); +		dev_err(dev, "BDC Gadget init failure:%d\n", ret);  		goto cleanup;  	}  	return 0;  cleanup:  	bdc_hw_exit(bdc); - +phycleanup: +	bdc_phy_exit(bdc);  	return ret;  } @@ -513,13 +600,56 @@ static int bdc_remove(struct platform_device *pdev)  	dev_dbg(bdc->dev, "%s ()\n", __func__);  	bdc_udc_exit(bdc);  	bdc_hw_exit(bdc); +	bdc_phy_exit(bdc); +	clk_disable_unprepare(bdc->clk); +	return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int bdc_suspend(struct device *dev) +{ +	struct bdc *bdc = dev_get_drvdata(dev); +	clk_disable_unprepare(bdc->clk);  	return 0;  } +static int bdc_resume(struct device *dev) +{ +	struct bdc *bdc = dev_get_drvdata(dev); +	int ret; + +	ret = clk_prepare_enable(bdc->clk); +	if (ret) { +		dev_err(bdc->dev, "err enabling the clock\n"); +		return ret; +	} +	ret = bdc_reinit(bdc); +	if (ret) { +		dev_err(bdc->dev, "err in bdc reinit\n"); +		return ret; +	} + +	return 0; +} + +#endif /* CONFIG_PM_SLEEP */ + +static SIMPLE_DEV_PM_OPS(bdc_pm_ops, bdc_suspend, +		bdc_resume); + +static const struct of_device_id bdc_of_match[] = { +	{ .compatible = "brcm,bdc-v0.16" }, +	{ .compatible = "brcm,bdc" }, +	{ /* sentinel */ } +}; +  static struct platform_driver bdc_driver = {  	.driver		= {  		.name	= BRCM_BDC_NAME, +		.owner	= THIS_MODULE, +		.pm = &bdc_pm_ops, +		.of_match_table	= bdc_of_match,  	},  	.probe		= bdc_probe,  	.remove		= bdc_remove, diff --git a/drivers/usb/gadget/udc/bdc/bdc_dbg.c b/drivers/usb/gadget/udc/bdc/bdc_dbg.c index 5945dbc47825..ac98f6f681b7 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_dbg.c +++ b/drivers/usb/gadget/udc/bdc/bdc_dbg.c @@ -40,28 +40,28 @@ void bdc_dump_epsts(struct bdc *bdc)  {  	u32 temp; -	temp = bdc_readl(bdc->regs, BDC_EPSTS0(0)); +	temp = bdc_readl(bdc->regs, BDC_EPSTS0);  	dev_vdbg(bdc->dev, "BDC_EPSTS0:0x%08x\n", temp); -	temp = bdc_readl(bdc->regs, BDC_EPSTS1(0)); +	temp = bdc_readl(bdc->regs, BDC_EPSTS1);  	dev_vdbg(bdc->dev, "BDC_EPSTS1:0x%x\n", temp); -	temp = bdc_readl(bdc->regs, BDC_EPSTS2(0)); +	temp = bdc_readl(bdc->regs, BDC_EPSTS2);  	dev_vdbg(bdc->dev, "BDC_EPSTS2:0x%08x\n", temp); -	temp = bdc_readl(bdc->regs, BDC_EPSTS3(0)); +	temp = bdc_readl(bdc->regs, BDC_EPSTS3);  	dev_vdbg(bdc->dev, "BDC_EPSTS3:0x%08x\n", temp); -	temp = bdc_readl(bdc->regs, BDC_EPSTS4(0)); +	temp = bdc_readl(bdc->regs, BDC_EPSTS4);  	dev_vdbg(bdc->dev, "BDC_EPSTS4:0x%08x\n", temp); -	temp = bdc_readl(bdc->regs, BDC_EPSTS5(0)); +	temp = bdc_readl(bdc->regs, BDC_EPSTS5);  	dev_vdbg(bdc->dev, "BDC_EPSTS5:0x%08x\n", temp); -	temp = bdc_readl(bdc->regs, BDC_EPSTS6(0)); +	temp = bdc_readl(bdc->regs, BDC_EPSTS6);  	dev_vdbg(bdc->dev, "BDC_EPSTS6:0x%08x\n", temp); -	temp = bdc_readl(bdc->regs, BDC_EPSTS7(0)); +	temp = bdc_readl(bdc->regs, BDC_EPSTS7);  	dev_vdbg(bdc->dev, "BDC_EPSTS7:0x%08x\n", temp);  } diff --git a/drivers/usb/gadget/udc/bdc/bdc_ep.c b/drivers/usb/gadget/udc/bdc/bdc_ep.c index ff1ef24d1777..bfd8f7ade935 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_ep.c +++ b/drivers/usb/gadget/udc/bdc/bdc_ep.c @@ -777,9 +777,9 @@ static int ep_dequeue(struct bdc_ep *ep, struct bdc_req *req)  	 */  	/* The current hw dequeue pointer */ -	tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS0(0)); +	tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS0);  	deq_ptr_64 = tmp_32; -	tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS1(0)); +	tmp_32 = bdc_readl(bdc->regs, BDC_EPSTS1);  	deq_ptr_64 |= ((u64)tmp_32 << 32);  	/* we have the dma addr of next bd that will be fetched by hardware */ diff --git a/drivers/usb/gadget/udc/bdc/bdc_udc.c b/drivers/usb/gadget/udc/bdc/bdc_udc.c index aae7458d8986..c84346146456 100644 --- a/drivers/usb/gadget/udc/bdc/bdc_udc.c +++ b/drivers/usb/gadget/udc/bdc/bdc_udc.c @@ -249,6 +249,7 @@ void bdc_sr_uspc(struct bdc *bdc, struct bdc_sr *sreport)  			disconn = true;  		else if ((uspc & BDC_PCS) && !BDC_PST(uspc))  			connected = true; +		clear_flags |= BDC_PCC;  	}  	/* Change in VBus and VBus is present */ @@ -259,16 +260,16 @@ void bdc_sr_uspc(struct bdc *bdc, struct bdc_sr *sreport)  			bdc_softconn(bdc);  			usb_gadget_set_state(&bdc->gadget, USB_STATE_POWERED);  		} -		clear_flags = BDC_VBC; +		clear_flags |= BDC_VBC;  	} else if ((uspc & BDC_PRS) || (uspc & BDC_PRC) || disconn) {  		/* Hot reset, warm reset, 2.0 bus reset or disconn */  		dev_dbg(bdc->dev, "Port reset or disconn\n");  		bdc_uspc_disconnected(bdc, disconn); -		clear_flags = BDC_PCC|BDC_PCS|BDC_PRS|BDC_PRC; +		clear_flags |= BDC_PRC;  	} else if ((uspc & BDC_PSC) && (uspc & BDC_PCS)) {  		/* Change in Link state */  		handle_link_state_change(bdc, uspc); -		clear_flags = BDC_PSC|BDC_PCS; +		clear_flags |= BDC_PSC;  	}  	/* diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index e6f04eee95c4..75c51ca4ee0f 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -812,6 +812,8 @@ int usb_gadget_map_request_by_dev(struct device *dev,  			dev_err(dev, "failed to map buffer\n");  			return -EFAULT;  		} + +		req->dma_mapped = 1;  	}  	return 0; @@ -836,9 +838,10 @@ void usb_gadget_unmap_request_by_dev(struct device *dev,  				is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);  		req->num_mapped_sgs = 0; -	} else { +	} else if (req->dma_mapped) {  		dma_unmap_single(dev, req->dma, req->length,  				is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE); +		req->dma_mapped = 0;  	}  }  EXPORT_SYMBOL_GPL(usb_gadget_unmap_request_by_dev); @@ -1130,6 +1133,7 @@ static int check_pending_gadget_drivers(struct usb_udc *udc)   * @release: a gadget release function.   *   * Returns zero on success, negative errno otherwise. + * Calls the gadget release function in the latter case.   */  int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,  		void (*release)(struct device *dev)) @@ -1137,10 +1141,6 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,  	struct usb_udc		*udc;  	int			ret = -ENOMEM; -	udc = kzalloc(sizeof(*udc), GFP_KERNEL); -	if (!udc) -		goto err1; -  	dev_set_name(&gadget->dev, "gadget");  	INIT_WORK(&gadget->work, usb_gadget_state_work);  	gadget->dev.parent = parent; @@ -1150,7 +1150,13 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,  	else  		gadget->dev.release = usb_udc_nop_release; -	ret = device_register(&gadget->dev); +	device_initialize(&gadget->dev); + +	udc = kzalloc(sizeof(*udc), GFP_KERNEL); +	if (!udc) +		goto err1; + +	ret = device_add(&gadget->dev);  	if (ret)  		goto err2; @@ -1197,10 +1203,10 @@ err3:  	device_del(&gadget->dev);  err2: -	put_device(&gadget->dev);  	kfree(udc);  err1: +	put_device(&gadget->dev);  	return ret;  }  EXPORT_SYMBOL_GPL(usb_add_gadget_udc_release); diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 3c3760315910..a030d7923d7d 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c @@ -2776,7 +2776,7 @@ static int __init init(void)  		if (retval < 0) {  			i--;  			while (i >= 0) -				platform_device_del(the_udc_pdev[i]); +				platform_device_del(the_udc_pdev[i--]);  			goto err_add_udc;  		}  	} diff --git a/drivers/usb/gadget/udc/fsl_qe_udc.c b/drivers/usb/gadget/udc/fsl_qe_udc.c index 303328ce59ee..a3e72d690eef 100644 --- a/drivers/usb/gadget/udc/fsl_qe_udc.c +++ b/drivers/usb/gadget/udc/fsl_qe_udc.c @@ -62,7 +62,7 @@ static const char *const ep_name[] = {  	"ep3",  }; -static struct usb_endpoint_descriptor qe_ep0_desc = { +static const struct usb_endpoint_descriptor qe_ep0_desc = {  	.bLength =		USB_DT_ENDPOINT_SIZE,  	.bDescriptorType =	USB_DT_ENDPOINT, diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c index 8a708d0a1042..4103bf7cf52a 100644 --- a/drivers/usb/gadget/udc/mv_udc_core.c +++ b/drivers/usb/gadget/udc/mv_udc_core.c @@ -39,7 +39,6 @@  #include "mv_udc.h"  #define DRIVER_DESC		"Marvell PXA USB Device Controller driver" -#define DRIVER_VERSION		"8 Nov 2010"  #define ep_dir(ep)	(((ep)->ep_num == 0) ? \  				((ep)->udc->ep0_dir) : ((ep)->direction)) @@ -2427,5 +2426,4 @@ module_platform_driver(udc_driver);  MODULE_ALIAS("platform:mv-udc");  MODULE_DESCRIPTION(DRIVER_DESC);  MODULE_AUTHOR("Chao Xie <[email protected]>"); -MODULE_VERSION(DRIVER_VERSION);  MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index e1de8fe599a3..df37c1e6e9d5 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -8,6 +8,7 @@   * the Free Software Foundation; version 2 of the License.   */ +#include <linux/debugfs.h>  #include <linux/delay.h>  #include <linux/dma-mapping.h>  #include <linux/err.h> @@ -20,6 +21,8 @@  #include <linux/pm_runtime.h>  #include <linux/sizes.h>  #include <linux/slab.h> +#include <linux/sys_soc.h> +#include <linux/uaccess.h>  #include <linux/usb/ch9.h>  #include <linux/usb/gadget.h> @@ -347,6 +350,7 @@ struct renesas_usb3 {  	bool workaround_for_vbus;  	bool extcon_host;		/* check id and set EXTCON_USB_HOST */  	bool extcon_usb;		/* check vbus and set EXTCON_USB */ +	bool forced_b_device;  };  #define gadget_to_renesas_usb3(_gadget)	\ @@ -663,7 +667,9 @@ static void usb3_mode_config(struct renesas_usb3 *usb3, bool host, bool a_dev)  	spin_lock_irqsave(&usb3->lock, flags);  	usb3_set_mode(usb3, host);  	usb3_vbus_out(usb3, a_dev); -	if (!host && a_dev)		/* for A-Peripheral */ +	/* for A-Peripheral or forced B-device mode */ +	if ((!host && a_dev) || +	    (usb3->workaround_for_vbus && usb3->forced_b_device))  		usb3_connect(usb3);  	spin_unlock_irqrestore(&usb3->lock, flags);  } @@ -677,7 +683,7 @@ static void usb3_check_id(struct renesas_usb3 *usb3)  {  	usb3->extcon_host = usb3_is_a_device(usb3); -	if (usb3->extcon_host) +	if (usb3->extcon_host && !usb3->forced_b_device)  		usb3_mode_config(usb3, true, true);  	else  		usb3_mode_config(usb3, false, false); @@ -2192,7 +2198,7 @@ static void renesas_usb3_ep_fifo_flush(struct usb_ep *_ep)  	}  } -static struct usb_ep_ops renesas_usb3_ep_ops = { +static const struct usb_ep_ops renesas_usb3_ep_ops = {  	.enable		= renesas_usb3_ep_enable,  	.disable	= renesas_usb3_ep_disable, @@ -2283,6 +2289,9 @@ static ssize_t role_store(struct device *dev, struct device_attribute *attr,  	if (!usb3->driver)  		return -ENODEV; +	if (usb3->forced_b_device) +		return -EBUSY; +  	if (!strncmp(buf, "host", strlen("host")))  		new_mode_is_host = true;  	else if (!strncmp(buf, "peripheral", strlen("peripheral"))) @@ -2310,6 +2319,70 @@ static ssize_t role_show(struct device *dev, struct device_attribute *attr,  }  static DEVICE_ATTR_RW(role); +static int renesas_usb3_b_device_show(struct seq_file *s, void *unused) +{ +	struct renesas_usb3 *usb3 = s->private; + +	seq_printf(s, "%d\n", usb3->forced_b_device); + +	return 0; +} + +static int renesas_usb3_b_device_open(struct inode *inode, struct file *file) +{ +	return single_open(file, renesas_usb3_b_device_show, inode->i_private); +} + +static ssize_t renesas_usb3_b_device_write(struct file *file, +					   const char __user *ubuf, +					   size_t count, loff_t *ppos) +{ +	struct seq_file *s = file->private_data; +	struct renesas_usb3 *usb3 = s->private; +	char buf[32]; + +	if (!usb3->driver) +		return -ENODEV; + +	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) +		return -EFAULT; + +	if (!strncmp(buf, "1", 1)) +		usb3->forced_b_device = true; +	else +		usb3->forced_b_device = false; + +	/* Let this driver call usb3_connect() anyway */ +	usb3_check_id(usb3); + +	return count; +} + +static const struct file_operations renesas_usb3_b_device_fops = { +	.open = renesas_usb3_b_device_open, +	.write = renesas_usb3_b_device_write, +	.read = seq_read, +	.llseek = seq_lseek, +	.release = single_release, +}; + +static void renesas_usb3_debugfs_init(struct renesas_usb3 *usb3, +				      struct device *dev) +{ +	struct dentry *root, *file; + +	root = debugfs_create_dir(dev_name(dev), NULL); +	if (IS_ERR_OR_NULL(root)) { +		dev_info(dev, "%s: Can't create the root\n", __func__); +		return; +	} + +	file = debugfs_create_file("b_device", 0644, root, usb3, +				   &renesas_usb3_b_device_fops); +	if (!file) +		dev_info(dev, "%s: Can't create debugfs mode\n", __func__); +} +  /*------- platform_driver ------------------------------------------------*/  static int renesas_usb3_remove(struct platform_device *pdev)  { @@ -2432,22 +2505,40 @@ static void renesas_usb3_init_ram(struct renesas_usb3 *usb3, struct device *dev,  	}  } -static const struct renesas_usb3_priv renesas_usb3_priv_r8a7795 = { +static const struct renesas_usb3_priv renesas_usb3_priv_r8a7795_es1 = {  	.ramsize_per_ramif = SZ_16K,  	.num_ramif = 2,  	.ramsize_per_pipe = SZ_4K,  	.workaround_for_vbus = true,  }; +static const struct renesas_usb3_priv renesas_usb3_priv_gen3 = { +	.ramsize_per_ramif = SZ_16K, +	.num_ramif = 4, +	.ramsize_per_pipe = SZ_4K, +}; +  static const struct of_device_id usb3_of_match[] = {  	{  		.compatible = "renesas,r8a7795-usb3-peri", -		.data = &renesas_usb3_priv_r8a7795, +		.data = &renesas_usb3_priv_gen3, +	}, +	{ +		.compatible = "renesas,rcar-gen3-usb3-peri", +		.data = &renesas_usb3_priv_gen3,  	},  	{ },  };  MODULE_DEVICE_TABLE(of, usb3_of_match); +static const struct soc_device_attribute renesas_usb3_quirks_match[] = { +	{ +		.soc_id = "r8a7795", .revision = "ES1.*", +		.data = &renesas_usb3_priv_r8a7795_es1, +	}, +	{ /* sentinel */ }, +}; +  static const unsigned int renesas_usb3_cable[] = {  	EXTCON_USB,  	EXTCON_USB_HOST, @@ -2461,15 +2552,23 @@ static int renesas_usb3_probe(struct platform_device *pdev)  	const struct of_device_id *match;  	int irq, ret;  	const struct renesas_usb3_priv *priv; +	const struct soc_device_attribute *attr;  	match = of_match_node(usb3_of_match, pdev->dev.of_node);  	if (!match)  		return -ENODEV; -	priv = match->data; + +	attr = soc_device_match(renesas_usb3_quirks_match); +	if (attr) +		priv = attr->data; +	else +		priv = match->data;  	irq = platform_get_irq(pdev, 0); -	if (irq < 0) -		return -ENODEV; +	if (irq < 0) { +		dev_err(&pdev->dev, "Failed to get IRQ: %d\n", irq); +		return irq; +	}  	usb3 = devm_kzalloc(&pdev->dev, sizeof(*usb3), GFP_KERNEL);  	if (!usb3) @@ -2527,6 +2626,8 @@ static int renesas_usb3_probe(struct platform_device *pdev)  	usb3->workaround_for_vbus = priv->workaround_for_vbus; +	renesas_usb3_debugfs_init(usb3, &pdev->dev); +  	dev_info(&pdev->dev, "probed\n");  	return 0; diff --git a/drivers/usb/gadget/udc/s3c2410_udc.c b/drivers/usb/gadget/udc/s3c2410_udc.c index 4643a01262b4..394abd5d65c0 100644 --- a/drivers/usb/gadget/udc/s3c2410_udc.c +++ b/drivers/usb/gadget/udc/s3c2410_udc.c @@ -51,7 +51,6 @@  #include "s3c2410_udc.h"  #define DRIVER_DESC	"S3C2410 USB Device Controller Gadget" -#define DRIVER_VERSION	"29 Apr 2007"  #define DRIVER_AUTHOR	"Herbert Pötzl <[email protected]>, " \  			"Arnaud Patard <[email protected]>" @@ -1996,7 +1995,7 @@ static int __init udc_init(void)  {  	int retval; -	dprintk(DEBUG_NORMAL, "%s: version %s\n", gadget_name, DRIVER_VERSION); +	dprintk(DEBUG_NORMAL, "%s\n", gadget_name);  	s3c2410_udc_debugfs_root = debugfs_create_dir(gadget_name, NULL);  	if (IS_ERR(s3c2410_udc_debugfs_root)) { @@ -2027,5 +2026,4 @@ module_exit(udc_exit);  MODULE_AUTHOR(DRIVER_AUTHOR);  MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION);  MODULE_LICENSE("GPL"); diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 4a08b70c81aa..d025cc06dda7 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -642,7 +642,7 @@ static int ehci_start_port_reset(struct usb_hcd *hcd, unsigned port)  #define ehci_start_port_reset	NULL  #endif /* CONFIG_USB_OTG */ -static struct ehci_driver_overrides ehci_fsl_overrides __initdata = { +static const struct ehci_driver_overrides ehci_fsl_overrides __initconst = {  	.extra_priv_size = sizeof(struct ehci_fsl),  	.reset = ehci_fsl_setup,  }; diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index 94ea9fff13e6..4d308533bc83 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -130,8 +130,8 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)  	irq = platform_get_irq(pdev, 0);  	if (irq < 0) { -		dev_err(dev, "EHCI irq failed\n"); -		return -ENODEV; +		dev_err(dev, "EHCI irq failed: %d\n", irq); +		return irq;  	}  	res =  platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index e90ddb530765..ba557cdba8ef 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -55,8 +55,8 @@ static struct fsl_usb2_dev_data *get_dr_mode_data(struct device_node *np)  				return &dr_mode_data[i];  		}  	} -	pr_warn("%s: Invalid 'dr_mode' property, fallback to host mode\n", -		np->full_name); +	pr_warn("%pOF: Invalid 'dr_mode' property, fallback to host mode\n", +		np);  	return &dr_mode_data[0]; /* mode not specified, use host */  } diff --git a/drivers/usb/host/hwa-hc.c b/drivers/usb/host/hwa-hc.c index 1db0626c8bf4..da3b18038d23 100644 --- a/drivers/usb/host/hwa-hc.c +++ b/drivers/usb/host/hwa-hc.c @@ -614,7 +614,7 @@ error:  	return result;  } -static struct hc_driver hwahc_hc_driver = { +static const struct hc_driver hwahc_hc_driver = {  	.description = "hwa-hcd",  	.product_desc = "Wireless USB HWA host controller",  	.hcd_priv_size = sizeof(struct hwahc) - sizeof(struct usb_hcd), @@ -860,7 +860,7 @@ static void hwahc_disconnect(struct usb_interface *usb_iface)  	usb_put_hcd(usb_hcd);  } -static struct usb_device_id hwahc_id_table[] = { +static const struct usb_device_id hwahc_id_table[] = {  	/* Alereon 5310 */  	{ USB_DEVICE_AND_INTERFACE_INFO(0x13dc, 0x5310, 0xe0, 0x02, 0x01),  	  .driver_info = WUSB_QUIRK_ALEREON_HWA_CONCAT_ISOC | diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c index f542045dc2a6..39ae7fb64b6f 100644 --- a/drivers/usb/host/imx21-hcd.c +++ b/drivers/usb/host/imx21-hcd.c @@ -1779,7 +1779,7 @@ static void imx21_hc_stop(struct usb_hcd *hcd)  /* Driver glue		 			*/  /* =========================================== */ -static struct hc_driver imx21_hc_driver = { +static const struct hc_driver imx21_hc_driver = {  	.description = hcd_name,  	.product_desc = "IMX21 USB Host Controller",  	.hcd_priv_size = sizeof(struct imx21), @@ -1849,8 +1849,10 @@ static int imx21_probe(struct platform_device *pdev)  	if (!res)  		return -ENODEV;  	irq = platform_get_irq(pdev, 0); -	if (irq < 0) -		return -ENXIO; +	if (irq < 0) { +		dev_err(&pdev->dev, "Failed to get IRQ: %d\n", irq); +		return irq; +	}  	hcd = usb_create_hcd(&imx21_hc_driver,  		&pdev->dev, dev_name(&pdev->dev)); diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index d089b3fb7a13..73fec38754f9 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c @@ -1511,7 +1511,7 @@ static int isp116x_bus_resume(struct usb_hcd *hcd)  #endif -static struct hc_driver isp116x_hc_driver = { +static const struct hc_driver isp116x_hc_driver = {  	.description = hcd_name,  	.product_desc = "ISP116x Host Controller",  	.hcd_priv_size = sizeof(struct isp116x), diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c index 0f2b4b358e1a..9b7e307e2d54 100644 --- a/drivers/usb/host/isp1362-hcd.c +++ b/drivers/usb/host/isp1362-hcd.c @@ -2591,7 +2591,7 @@ static int isp1362_hc_start(struct usb_hcd *hcd)  /*-------------------------------------------------------------------------*/ -static struct hc_driver isp1362_hc_driver = { +static const struct hc_driver isp1362_hc_driver = {  	.description =		hcd_name,  	.product_desc =		"ISP1362 Host Controller",  	.hcd_priv_size =	sizeof(struct isp1362_hcd), diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c index 369869a29ebd..0ece9a9341e5 100644 --- a/drivers/usb/host/max3421-hcd.c +++ b/drivers/usb/host/max3421-hcd.c @@ -1811,7 +1811,7 @@ max3421_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)  {  } -static struct hc_driver max3421_hcd_desc = { +static const struct hc_driver max3421_hcd_desc = {  	.description =		"max3421",  	.product_desc =		DRIVER_DESC,  	.hcd_priv_size =	sizeof(struct max3421_hcd), diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index c8f38649f749..658d9d1f9ea3 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -142,29 +142,30 @@ static int amd_chipset_sb_type_init(struct amd_chipset_info *pinfo)  			pinfo->sb_type.gen = AMD_CHIPSET_SB700;  		else if (rev >= 0x40 && rev <= 0x4f)  			pinfo->sb_type.gen = AMD_CHIPSET_SB800; -	} -	pinfo->smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD, -					  0x145c, NULL); -	if (pinfo->smbus_dev) { -		pinfo->sb_type.gen = AMD_CHIPSET_TAISHAN;  	} else {  		pinfo->smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD,  				PCI_DEVICE_ID_AMD_HUDSON2_SMBUS, NULL); -		if (!pinfo->smbus_dev) { -			pinfo->sb_type.gen = NOT_AMD_CHIPSET; -			return 0; +		if (pinfo->smbus_dev) { +			rev = pinfo->smbus_dev->revision; +			if (rev >= 0x11 && rev <= 0x14) +				pinfo->sb_type.gen = AMD_CHIPSET_HUDSON2; +			else if (rev >= 0x15 && rev <= 0x18) +				pinfo->sb_type.gen = AMD_CHIPSET_BOLTON; +			else if (rev >= 0x39 && rev <= 0x3a) +				pinfo->sb_type.gen = AMD_CHIPSET_YANGTZE; +		} else { +			pinfo->smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD, +							  0x145c, NULL); +			if (pinfo->smbus_dev) { +				rev = pinfo->smbus_dev->revision; +				pinfo->sb_type.gen = AMD_CHIPSET_TAISHAN; +			} else { +				pinfo->sb_type.gen = NOT_AMD_CHIPSET; +				return 0; +			}  		} - -		rev = pinfo->smbus_dev->revision; -		if (rev >= 0x11 && rev <= 0x14) -			pinfo->sb_type.gen = AMD_CHIPSET_HUDSON2; -		else if (rev >= 0x15 && rev <= 0x18) -			pinfo->sb_type.gen = AMD_CHIPSET_BOLTON; -		else if (rev >= 0x39 && rev <= 0x3a) -			pinfo->sb_type.gen = AMD_CHIPSET_YANGTZE;  	} -  	pinfo->sb_type.rev = rev;  	return 1;  } diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 7bf78be1fd32..5e5fc9d7d533 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -2312,7 +2312,7 @@ static int r8a66597_bus_resume(struct usb_hcd *hcd)  #define	r8a66597_bus_resume	NULL  #endif -static struct hc_driver r8a66597_hc_driver = { +static const struct hc_driver r8a66597_hc_driver = {  	.description =		hcd_name,  	.hcd_priv_size =	sizeof(struct r8a66597),  	.irq =			r8a66597_irq, diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c index fd2a11473be7..24ad1d6cec25 100644 --- a/drivers/usb/host/sl811-hcd.c +++ b/drivers/usb/host/sl811-hcd.c @@ -1554,7 +1554,7 @@ sl811h_start(struct usb_hcd *hcd)  /*-------------------------------------------------------------------------*/ -static struct hc_driver sl811h_hc_driver = { +static const struct hc_driver sl811h_hc_driver = {  	.description =		hcd_name,  	.hcd_priv_size =	sizeof(struct sl811), diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 43d52931b5bf..c38855aed62c 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -2941,7 +2941,7 @@ static int u132_bus_resume(struct usb_hcd *hcd)  #define u132_bus_suspend NULL  #define u132_bus_resume NULL  #endif -static struct hc_driver u132_hc_driver = { +static const struct hc_driver u132_hc_driver = {  	.description = hcd_name,  	.hcd_priv_size = sizeof(struct u132),  	.irq = NULL, diff --git a/drivers/usb/host/whci/hcd.c b/drivers/usb/host/whci/hcd.c index 5b3603c360ab..cf84269c3e6d 100644 --- a/drivers/usb/host/whci/hcd.c +++ b/drivers/usb/host/whci/hcd.c @@ -213,7 +213,7 @@ static void whc_endpoint_reset(struct usb_hcd *usb_hcd,  } -static struct hc_driver whc_hc_driver = { +static const struct hc_driver whc_hc_driver = {  	.description = "whci-hcd",  	.product_desc = "Wireless host controller",  	.hcd_priv_size = sizeof(struct whc) - sizeof(struct usb_hcd), diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 00721e8807ab..ad89a6d4111b 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -1179,6 +1179,39 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,  				break;  			} +			/* +			 * For xHCI 1.1 according to section 4.19.1.2.4.1 a +			 * root hub port's transition to compliance mode upon +			 * detecting LFPS timeout may be controlled by an +			 * Compliance Transition Enabled (CTE) flag (not +			 * software visible). This flag is set by writing 0xA +			 * to PORTSC PLS field which will allow transition to +			 * compliance mode the next time LFPS timeout is +			 * encountered. A warm reset will clear it. +			 * +			 * The CTE flag is only supported if the HCCPARAMS2 CTC +			 * flag is set, otherwise, the compliance substate is +			 * automatically entered as on 1.0 and prior. +			 */ +			if (link_state == USB_SS_PORT_LS_COMP_MOD) { +				if (!HCC2_CTC(xhci->hcc_params2)) { +					xhci_dbg(xhci, "CTC flag is 0, port already supports entering compliance mode\n"); +					break; +				} + +				if ((temp & PORT_CONNECT)) { +					xhci_warn(xhci, "Can't set compliance mode when port is connected\n"); +					goto error; +				} + +				xhci_dbg(xhci, "Enable compliance mode transition for port %d\n", +						wIndex); +				xhci_set_link_state(xhci, port_array, wIndex, +						link_state); +				temp = readl(port_array[wIndex]); +				break; +			} +  			/* Software should not attempt to set  			 * port link state above '3' (U3) and the port  			 * must be enabled. @@ -1521,15 +1554,14 @@ static bool xhci_port_missing_cas_quirk(int port_index,  int xhci_bus_resume(struct usb_hcd *hcd)  {  	struct xhci_hcd	*xhci = hcd_to_xhci(hcd); -	int max_ports, port_index; -	__le32 __iomem **port_array;  	struct xhci_bus_state *bus_state; -	u32 temp; +	__le32 __iomem **port_array;  	unsigned long flags; -	unsigned long port_was_suspended = 0; -	bool need_usb2_u3_exit = false; +	int max_ports, port_index;  	int slot_id;  	int sret; +	u32 next_state; +	u32 temp, portsc;  	max_ports = xhci_get_ports(hcd, &port_array);  	bus_state = &xhci->bus_state[hcd_index(hcd)]; @@ -1548,68 +1580,77 @@ int xhci_bus_resume(struct usb_hcd *hcd)  	temp &= ~CMD_EIE;  	writel(temp, &xhci->op_regs->command); +	/* bus specific resume for ports we suspended at bus_suspend */ +	if (hcd->speed >= HCD_USB3) +		next_state = XDEV_U0; +	else +		next_state = XDEV_RESUME; +  	port_index = max_ports;  	while (port_index--) { -		/* Check whether need resume ports. If needed -		   resume port and disable remote wakeup */ -		u32 temp; - -		temp = readl(port_array[port_index]); +		portsc = readl(port_array[port_index]);  		/* warm reset CAS limited ports stuck in polling/compliance */  		if ((xhci->quirks & XHCI_MISSING_CAS) &&  		    (hcd->speed >= HCD_USB3) &&  		    xhci_port_missing_cas_quirk(port_index, port_array)) {  			xhci_dbg(xhci, "reset stuck port %d\n", port_index); +			clear_bit(port_index, &bus_state->bus_suspended);  			continue;  		} -		if (DEV_SUPERSPEED_ANY(temp)) -			temp &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS); -		else -			temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); -		if (test_bit(port_index, &bus_state->bus_suspended) && -		    (temp & PORT_PLS_MASK)) { -			set_bit(port_index, &port_was_suspended); -			if (!DEV_SUPERSPEED_ANY(temp)) { -				xhci_set_link_state(xhci, port_array, -						port_index, XDEV_RESUME); -				need_usb2_u3_exit = true; +		/* resume if we suspended the link, and it is still suspended */ +		if (test_bit(port_index, &bus_state->bus_suspended)) +			switch (portsc & PORT_PLS_MASK) { +			case XDEV_U3: +				portsc = xhci_port_state_to_neutral(portsc); +				portsc &= ~PORT_PLS_MASK; +				portsc |= PORT_LINK_STROBE | next_state; +				break; +			case XDEV_RESUME: +				/* resume already initiated */ +				break; +			default: +				/* not in a resumeable state, ignore it */ +				clear_bit(port_index, +					  &bus_state->bus_suspended); +				break;  			} -		} else -			writel(temp, port_array[port_index]); -	} - -	if (need_usb2_u3_exit) { -		spin_unlock_irqrestore(&xhci->lock, flags); -		msleep(USB_RESUME_TIMEOUT); -		spin_lock_irqsave(&xhci->lock, flags); +		/* disable wake for all ports, write new link state if needed */ +		portsc &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS); +		writel(portsc, port_array[port_index]);  	} -	port_index = max_ports; -	while (port_index--) { -		if (!(port_was_suspended & BIT(port_index))) -			continue; -		/* Clear PLC to poll it later after XDEV_U0 */ -		xhci_test_and_clear_bit(xhci, port_array, port_index, PORT_PLC); -		xhci_set_link_state(xhci, port_array, port_index, XDEV_U0); +	/* USB2 specific resume signaling delay and U0 link state transition */ +	if (hcd->speed < HCD_USB3) { +		if (bus_state->bus_suspended) { +			spin_unlock_irqrestore(&xhci->lock, flags); +			msleep(USB_RESUME_TIMEOUT); +			spin_lock_irqsave(&xhci->lock, flags); +		} +		for_each_set_bit(port_index, &bus_state->bus_suspended, +				 BITS_PER_LONG) { +			/* Clear PLC to poll it later for U0 transition */ +			xhci_test_and_clear_bit(xhci, port_array, port_index, +						PORT_PLC); +			xhci_set_link_state(xhci, port_array, port_index, +					    XDEV_U0); +		}  	} -	port_index = max_ports; -	while (port_index--) { -		if (!(port_was_suspended & BIT(port_index))) -			continue; -		/* Poll and Clear PLC */ +	/* poll for U0 link state complete, both USB2 and USB3 */ +	for_each_set_bit(port_index, &bus_state->bus_suspended, BITS_PER_LONG) {  		sret = xhci_handshake(port_array[port_index], PORT_PLC,  				      PORT_PLC, 10 * 1000); -		if (sret) +		if (sret) {  			xhci_warn(xhci, "port %d resume PLC timeout\n",  				  port_index); +			continue; +		}  		xhci_test_and_clear_bit(xhci, port_array, port_index, PORT_PLC);  		slot_id = xhci_find_slot_id_by_port(hcd, xhci, port_index + 1);  		if (slot_id)  			xhci_ring_device(xhci, slot_id);  	} -  	(void) readl(&xhci->op_regs->command);  	bus_state->next_statechange = jiffies + msecs_to_jiffies(5); diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c index 67d5dc79b6b5..8fb60657ed4f 100644 --- a/drivers/usb/host/xhci-mtk.c +++ b/drivers/usb/host/xhci-mtk.c @@ -795,6 +795,7 @@ static const struct dev_pm_ops xhci_mtk_pm_ops = {  #ifdef CONFIG_OF  static const struct of_device_id mtk_xhci_of_match[] = {  	{ .compatible = "mediatek,mt8173-xhci"}, +	{ .compatible = "mediatek,mtk-xhci"},  	{ },  };  MODULE_DEVICE_TABLE(of, mtk_xhci_of_match); diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index c04144b25a67..163bafde709f 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -107,14 +107,6 @@ static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen2 = {  };  static const struct xhci_plat_priv xhci_plat_renesas_rcar_gen3 = { -	.firmware_name = XHCI_RCAR_FIRMWARE_NAME_V2, -	.init_quirk = xhci_rcar_init_quirk, -	.plat_start = xhci_rcar_start, -	.resume_quirk = xhci_rcar_resume_quirk, -}; - -static const struct xhci_plat_priv xhci_plat_renesas_rcar_r8a7796 = { -	.firmware_name = XHCI_RCAR_FIRMWARE_NAME_V3,  	.init_quirk = xhci_rcar_init_quirk,  	.plat_start = xhci_rcar_start,  	.resume_quirk = xhci_rcar_resume_quirk, @@ -145,7 +137,7 @@ static const struct of_device_id usb_xhci_of_match[] = {  		.data = &xhci_plat_renesas_rcar_gen3,  	}, {  		.compatible = "renesas,xhci-r8a7796", -		.data = &xhci_plat_renesas_rcar_r8a7796, +		.data = &xhci_plat_renesas_rcar_gen3,  	}, {  		.compatible = "renesas,rcar-gen2-xhci",  		.data = &xhci_plat_renesas_rcar_gen2, diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c index 07278228214b..198bc188ab25 100644 --- a/drivers/usb/host/xhci-rcar.c +++ b/drivers/usb/host/xhci-rcar.c @@ -13,13 +13,15 @@  #include <linux/platform_device.h>  #include <linux/of.h>  #include <linux/usb/phy.h> +#include <linux/sys_soc.h>  #include "xhci.h"  #include "xhci-plat.h"  #include "xhci-rcar.h"  /* -* - The V3 firmware is for r8a7796 (with good performance). +* - The V3 firmware is for r8a7796 (with good performance) and r8a7795 es2.0 +*   or later.  * - The V2 firmware can be used on both r8a7795 (es1.x) and r8a7796.  * - The V2 firmware is possible to use on R-Car Gen2. However, the V2 causes  *   performance degradation. So, this driver continues to use the V1 if R-Car @@ -67,6 +69,26 @@ MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V3);  #define RCAR_USB3_RX_POL_VAL	BIT(21)  #define RCAR_USB3_TX_POL_VAL	BIT(4) +/* For soc_device_attribute */ +#define RCAR_XHCI_FIRMWARE_V2   BIT(0) /* FIRMWARE V2 */ +#define RCAR_XHCI_FIRMWARE_V3   BIT(1) /* FIRMWARE V3 */ + +static const struct soc_device_attribute rcar_quirks_match[]  = { +	{ +		.soc_id = "r8a7795", .revision = "ES1.*", +		.data = (void *)RCAR_XHCI_FIRMWARE_V2, +	}, +	{ +		.soc_id = "r8a7795", +		.data = (void *)RCAR_XHCI_FIRMWARE_V3, +	}, +	{ +		.soc_id = "r8a7796", +		.data = (void *)RCAR_XHCI_FIRMWARE_V3, +	}, +	{ /* sentinel */ }, +}; +  static void xhci_rcar_start_gen2(struct usb_hcd *hcd)  {  	/* LCLK Select */ @@ -122,9 +144,23 @@ static int xhci_rcar_download_firmware(struct usb_hcd *hcd)  	int retval, index, j, time;  	int timeout = 10000;  	u32 data, val, temp; +	u32 quirks = 0; +	const struct soc_device_attribute *attr; +	const char *firmware_name; + +	attr = soc_device_match(rcar_quirks_match); +	if (attr) +		quirks = (uintptr_t)attr->data; + +	if (quirks & RCAR_XHCI_FIRMWARE_V2) +		firmware_name = XHCI_RCAR_FIRMWARE_NAME_V2; +	else if (quirks & RCAR_XHCI_FIRMWARE_V3) +		firmware_name = XHCI_RCAR_FIRMWARE_NAME_V3; +	else +		firmware_name = priv->firmware_name;  	/* request R-Car USB3.0 firmware */ -	retval = request_firmware(&fw, priv->firmware_name, dev); +	retval = request_firmware(&fw, firmware_name, dev);  	if (retval)  		return retval; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index cc368ad2b51e..a9443651ce0f 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1572,7 +1572,7 @@ static void handle_port_status(struct xhci_hcd *xhci,  {  	struct usb_hcd *hcd;  	u32 port_id; -	u32 temp, temp1; +	u32 portsc, cmd_reg;  	int max_ports;  	int slot_id;  	unsigned int faked_port_index; @@ -1636,26 +1636,28 @@ static void handle_port_status(struct xhci_hcd *xhci,  	/* Find the faked port hub number */  	faked_port_index = find_faked_portnum_from_hw_portnum(hcd, xhci,  			port_id); +	portsc = readl(port_array[faked_port_index]); + +	trace_xhci_handle_port_status(faked_port_index, portsc); -	temp = readl(port_array[faked_port_index]);  	if (hcd->state == HC_STATE_SUSPENDED) {  		xhci_dbg(xhci, "resume root hub\n");  		usb_hcd_resume_root_hub(hcd);  	} -	if (hcd->speed >= HCD_USB3 && (temp & PORT_PLS_MASK) == XDEV_INACTIVE) +	if (hcd->speed >= HCD_USB3 && (portsc & PORT_PLS_MASK) == XDEV_INACTIVE)  		bus_state->port_remote_wakeup &= ~(1 << faked_port_index); -	if ((temp & PORT_PLC) && (temp & PORT_PLS_MASK) == XDEV_RESUME) { +	if ((portsc & PORT_PLC) && (portsc & PORT_PLS_MASK) == XDEV_RESUME) {  		xhci_dbg(xhci, "port resume event for port %d\n", port_id); -		temp1 = readl(&xhci->op_regs->command); -		if (!(temp1 & CMD_RUN)) { +		cmd_reg = readl(&xhci->op_regs->command); +		if (!(cmd_reg & CMD_RUN)) {  			xhci_warn(xhci, "xHC is not running.\n");  			goto cleanup;  		} -		if (DEV_SUPERSPEED_ANY(temp)) { +		if (DEV_SUPERSPEED_ANY(portsc)) {  			xhci_dbg(xhci, "remote wake SS port %d\n", port_id);  			/* Set a flag to say the port signaled remote wakeup,  			 * so we can tell the difference between the end of @@ -1683,8 +1685,8 @@ static void handle_port_status(struct xhci_hcd *xhci,  		}  	} -	if ((temp & PORT_PLC) && (temp & PORT_PLS_MASK) == XDEV_U0 && -			DEV_SUPERSPEED_ANY(temp)) { +	if ((portsc & PORT_PLC) && (portsc & PORT_PLS_MASK) == XDEV_U0 && +			DEV_SUPERSPEED_ANY(portsc)) {  		xhci_dbg(xhci, "resume SS port %d finished\n", port_id);  		/* We've just brought the device into U0 through either the  		 * Resume state after a device remote wakeup, or through the @@ -1714,7 +1716,7 @@ static void handle_port_status(struct xhci_hcd *xhci,  	 * RExit to a disconnect state).  If so, let the the driver know it's  	 * out of the RExit state.  	 */ -	if (!DEV_SUPERSPEED_ANY(temp) && +	if (!DEV_SUPERSPEED_ANY(portsc) &&  			test_and_clear_bit(faked_port_index,  				&bus_state->rexit_ports)) {  		complete(&bus_state->rexit_done[faked_port_index]); diff --git a/drivers/usb/host/xhci-trace.h b/drivers/usb/host/xhci-trace.h index 8ce96de10e8a..f20753b99624 100644 --- a/drivers/usb/host/xhci-trace.h +++ b/drivers/usb/host/xhci-trace.h @@ -453,6 +453,29 @@ DEFINE_EVENT(xhci_log_ring, xhci_inc_deq,  	TP_PROTO(struct xhci_ring *ring),  	TP_ARGS(ring)  ); + +DECLARE_EVENT_CLASS(xhci_log_portsc, +		    TP_PROTO(u32 portnum, u32 portsc), +		    TP_ARGS(portnum, portsc), +		    TP_STRUCT__entry( +				     __field(u32, portnum) +				     __field(u32, portsc) +				     ), +		    TP_fast_assign( +				   __entry->portnum = portnum; +				   __entry->portsc = portsc; +				   ), +		    TP_printk("port-%d: %s", +			      __entry->portnum, +			      xhci_decode_portsc(__entry->portsc) +			      ) +); + +DEFINE_EVENT(xhci_log_portsc, xhci_handle_port_status, +	     TP_PROTO(u32 portnum, u32 portsc), +	     TP_ARGS(portnum, portsc) +); +  #endif /* __XHCI_TRACE_H */  /* this part must be outside header guard */ diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index e3e935291ed6..2abaa4d6d39d 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -311,12 +311,19 @@ struct xhci_op_regs {   */  #define PORT_PLS_MASK	(0xf << 5)  #define XDEV_U0		(0x0 << 5) +#define XDEV_U1		(0x1 << 5)  #define XDEV_U2		(0x2 << 5)  #define XDEV_U3		(0x3 << 5) +#define XDEV_DISABLED	(0x4 << 5) +#define XDEV_RXDETECT	(0x5 << 5)  #define XDEV_INACTIVE	(0x6 << 5)  #define XDEV_POLLING	(0x7 << 5) -#define XDEV_COMP_MODE  (0xa << 5) +#define XDEV_RECOVERY	(0x8 << 5) +#define XDEV_HOT_RESET	(0x9 << 5) +#define XDEV_COMP_MODE	(0xa << 5) +#define XDEV_TEST_MODE	(0xb << 5)  #define XDEV_RESUME	(0xf << 5) +  /* true: port has power (see HCC_PPC) */  #define PORT_POWER	(1 << 9)  /* bits 10:13 indicate device speed: @@ -2392,6 +2399,87 @@ static inline const char *xhci_decode_slot_context(u32 info, u32 info2,  	return str;  } + +static inline const char *xhci_portsc_link_state_string(u32 portsc) +{ +	switch (portsc & PORT_PLS_MASK) { +	case XDEV_U0: +		return "U0"; +	case XDEV_U1: +		return "U1"; +	case XDEV_U2: +		return "U2"; +	case XDEV_U3: +		return "U3"; +	case XDEV_DISABLED: +		return "Disabled"; +	case XDEV_RXDETECT: +		return "RxDetect"; +	case XDEV_INACTIVE: +		return "Inactive"; +	case XDEV_POLLING: +		return "Polling"; +	case XDEV_RECOVERY: +		return "Recovery"; +	case XDEV_HOT_RESET: +		return "Hot Reset"; +	case XDEV_COMP_MODE: +		return "Compliance mode"; +	case XDEV_TEST_MODE: +		return "Test mode"; +	case XDEV_RESUME: +		return "Resume"; +	default: +		break; +	} +	return "Unknown"; +} + +static inline const char *xhci_decode_portsc(u32 portsc) +{ +	static char str[256]; +	int ret; + +	ret = sprintf(str, "%s %s %s Link:%s ", +		      portsc & PORT_POWER	? "Powered" : "Powered-off", +		      portsc & PORT_CONNECT	? "Connected" : "Not-connected", +		      portsc & PORT_PE		? "Enabled" : "Disabled", +		      xhci_portsc_link_state_string(portsc)); + +	if (portsc & PORT_OC) +		ret += sprintf(str + ret, "OverCurrent "); +	if (portsc & PORT_RESET) +		ret += sprintf(str + ret, "In-Reset "); + +	ret += sprintf(str + ret, "Change: "); +	if (portsc & PORT_CSC) +		ret += sprintf(str + ret, "CSC "); +	if (portsc & PORT_PEC) +		ret += sprintf(str + ret, "PEC "); +	if (portsc & PORT_WRC) +		ret += sprintf(str + ret, "WRC "); +	if (portsc & PORT_OCC) +		ret += sprintf(str + ret, "OCC "); +	if (portsc & PORT_RC) +		ret += sprintf(str + ret, "PRC "); +	if (portsc & PORT_PLC) +		ret += sprintf(str + ret, "PLC "); +	if (portsc & PORT_CEC) +		ret += sprintf(str + ret, "CEC "); +	if (portsc & PORT_CAS) +		ret += sprintf(str + ret, "CAS "); + +	ret += sprintf(str + ret, "Wake: "); +	if (portsc & PORT_WKCONN_E) +		ret += sprintf(str + ret, "WCE "); +	if (portsc & PORT_WKDISC_E) +		ret += sprintf(str + ret, "WDE "); +	if (portsc & PORT_WKOC_E) +		ret += sprintf(str + ret, "WOE "); + +	return str; +} +  static inline const char *xhci_ep_state_string(u8 state)  {  	switch (state) { diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c index a4dbb0cd80da..0b21ba757bba 100644 --- a/drivers/usb/image/microtek.c +++ b/drivers/usb/image/microtek.c @@ -137,10 +137,6 @@  #include "microtek.h" -/* - * Version Information - */ -#define DRIVER_VERSION "v0.4.3"  #define DRIVER_AUTHOR "John Fremlin <[email protected]>, Oliver Neukum <[email protected]>"  #define DRIVER_DESC "Microtek Scanmaker X6 USB scanner driver" diff --git a/drivers/usb/isp1760/isp1760-hcd.c b/drivers/usb/isp1760/isp1760-hcd.c index ac31d19cc54b..8e59e0c02b8a 100644 --- a/drivers/usb/isp1760/isp1760-hcd.c +++ b/drivers/usb/isp1760/isp1760-hcd.c @@ -396,7 +396,6 @@ static int handshake(struct usb_hcd *hcd, u32 reg,  /* reset a non-running (STS_HALT == 1) controller */  static int ehci_reset(struct usb_hcd *hcd)  { -	int retval;  	struct isp1760_hcd *priv = hcd_to_priv(hcd);  	u32 command = reg_read32(hcd->regs, HC_USBCMD); @@ -405,9 +404,8 @@ static int ehci_reset(struct usb_hcd *hcd)  	reg_write32(hcd->regs, HC_USBCMD, command);  	hcd->state = HC_STATE_HALT;  	priv->next_statechange = jiffies; -	retval = handshake(hcd, HC_USBCMD, -			    CMD_RESET, 0, 250 * 1000); -	return retval; + +	return handshake(hcd, HC_USBCMD, CMD_RESET, 0, 250 * 1000);  }  static struct isp1760_qh *qh_alloc(gfp_t flags) diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index dfd54ea4808f..1c0ada75c35d 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -29,8 +29,6 @@  #include <linux/mutex.h>  #include <linux/uaccess.h> -/* Version Information */ -#define DRIVER_VERSION "v0.0.13"  #define DRIVER_AUTHOR "John Homppi"  #define DRIVER_DESC "adutux (see www.ontrak.net)" diff --git a/drivers/usb/misc/chaoskey.c b/drivers/usb/misc/chaoskey.c index 15d4e64d3b65..abec6e604a62 100644 --- a/drivers/usb/misc/chaoskey.c +++ b/drivers/usb/misc/chaoskey.c @@ -42,12 +42,10 @@ static int chaoskey_rng_read(struct hwrng *rng, void *data,  	dev_err(&(usb_if)->dev, format, ## arg)  /* Version Information */ -#define DRIVER_VERSION	"v0.1"  #define DRIVER_AUTHOR	"Keith Packard, [email protected]"  #define DRIVER_DESC	"Altus Metrum ChaosKey driver"  #define DRIVER_SHORT	"chaoskey" -MODULE_VERSION(DRIVER_VERSION);  MODULE_AUTHOR(DRIVER_AUTHOR);  MODULE_DESCRIPTION(DRIVER_DESC);  MODULE_LICENSE("GPL"); diff --git a/drivers/usb/misc/cytherm.c b/drivers/usb/misc/cytherm.c index 9d8bb8dacdcd..63207c42acf6 100644 --- a/drivers/usb/misc/cytherm.c +++ b/drivers/usb/misc/cytherm.c @@ -20,7 +20,6 @@  #include <linux/module.h>  #include <linux/usb.h> -#define DRIVER_VERSION "v1.0"  #define DRIVER_AUTHOR "Erik Rigtorp"  #define DRIVER_DESC "Cypress USB Thermometer driver" diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index 8291499d0581..424ff12f3b51 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -305,9 +305,9 @@ static int ftdi_elan_command_engine(struct usb_ftdi *ftdi);  static int ftdi_elan_respond_engine(struct usb_ftdi *ftdi);  static int ftdi_elan_hcd_init(struct usb_ftdi *ftdi)  { -	int result;  	if (ftdi->platform_dev.dev.parent)  		return -EBUSY; +  	ftdi_elan_get_kref(ftdi);  	ftdi->platform_data.potpg = 100;  	ftdi->platform_data.reset = NULL; @@ -324,8 +324,8 @@ static int ftdi_elan_hcd_init(struct usb_ftdi *ftdi)  	request_module("u132_hcd");  	dev_info(&ftdi->udev->dev, "registering '%s'\n",  		 ftdi->platform_dev.name); -	result = platform_device_register(&ftdi->platform_dev); -	return result; + +	return platform_device_register(&ftdi->platform_dev);  }  static void ftdi_elan_abandon_completions(struct usb_ftdi *ftdi) @@ -857,7 +857,7 @@ static char *have_ed_set_response(struct usb_ftdi *ftdi,  	target->actual = 0;  	target->non_null = (ed_length >> 15) & 0x0001;  	target->repeat_number = (ed_length >> 11) & 0x000F; -	if (ed_type == 0x02) { +	if (ed_type == 0x02 || ed_type == 0x03) {  		if (payload == 0 || target->abandoning > 0) {  			target->abandoning = 0;  			mutex_unlock(&ftdi->u132_lock); @@ -873,31 +873,6 @@ static char *have_ed_set_response(struct usb_ftdi *ftdi,  			mutex_unlock(&ftdi->u132_lock);  			return b;  		} -	} else if (ed_type == 0x03) { -		if (payload == 0 || target->abandoning > 0) { -			target->abandoning = 0; -			mutex_unlock(&ftdi->u132_lock); -			ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, -					      payload); -			ftdi->received = 0; -			ftdi->expected = 4; -			ftdi->ed_found = 0; -			return ftdi->response; -		} else { -			ftdi->expected = 4 + payload; -			ftdi->ed_found = 1; -			mutex_unlock(&ftdi->u132_lock); -			return b; -		} -	} else if (ed_type == 0x01) { -		target->abandoning = 0; -		mutex_unlock(&ftdi->u132_lock); -		ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, -				      payload); -		ftdi->received = 0; -		ftdi->expected = 4; -		ftdi->ed_found = 0; -		return ftdi->response;  	} else {  		target->abandoning = 0;  		mutex_unlock(&ftdi->u132_lock); diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c index 81fcbf024c65..39d8fedfaf3b 100644 --- a/drivers/usb/misc/idmouse.c +++ b/drivers/usb/misc/idmouse.c @@ -33,8 +33,6 @@  #define HEADER "P5 225 289 255 "  #define IMGSIZE ((WIDTH * HEIGHT) + sizeof(HEADER)-1) -/* version information */ -#define DRIVER_VERSION "0.6"  #define DRIVER_SHORT   "idmouse"  #define DRIVER_AUTHOR  "Florian 'Floe' Echtler <[email protected]>"  #define DRIVER_DESC    "Siemens ID Mouse FingerTIP Sensor Driver" diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index 7ca4c7e0ea0d..be5881303681 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -21,10 +21,8 @@  #include <linux/poll.h>  #include <linux/usb/iowarrior.h> -/* Version Information */ -#define DRIVER_VERSION "v0.4.0"  #define DRIVER_AUTHOR "Christian Lucht <[email protected]>" -#define DRIVER_DESC "USB IO-Warrior driver (Linux 2.6.x)" +#define DRIVER_DESC "USB IO-Warrior driver"  #define USB_VENDOR_ID_CODEMERCS		1984  /* low speed iowarrior */ diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index 9d9487c66f87..680bddb3ce05 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c @@ -112,7 +112,6 @@ static const struct usb_device_id ld_usb_table[] = {  	{ }					/* Terminating entry */  };  MODULE_DEVICE_TABLE(usb, ld_usb_table); -MODULE_VERSION("V0.14");  MODULE_AUTHOR("Michael Hund <[email protected]>");  MODULE_DESCRIPTION("LD USB Driver");  MODULE_LICENSE("GPL"); diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index 0782ac6f5edf..5628f678ab59 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -88,8 +88,6 @@  #include <linux/poll.h> -/* Version Information */ -#define DRIVER_VERSION "v0.96"  #define DRIVER_AUTHOR "Juergen Stuber <[email protected]>"  #define DRIVER_DESC "LEGO USB Tower Driver" diff --git a/drivers/usb/misc/lvstest.c b/drivers/usb/misc/lvstest.c index 2142132a1f82..ddddd6387f66 100644 --- a/drivers/usb/misc/lvstest.c +++ b/drivers/usb/misc/lvstest.c @@ -178,6 +178,25 @@ static ssize_t hot_reset_store(struct device *dev,  }  static DEVICE_ATTR_WO(hot_reset); +static ssize_t warm_reset_store(struct device *dev, +		struct device_attribute *attr, const char *buf, size_t count) +{ +	struct usb_interface *intf = to_usb_interface(dev); +	struct usb_device *hdev = interface_to_usbdev(intf); +	struct lvs_rh *lvs = usb_get_intfdata(intf); +	int ret; + +	ret = lvs_rh_set_port_feature(hdev, lvs->portnum, +			USB_PORT_FEAT_BH_PORT_RESET); +	if (ret < 0) { +		dev_err(dev, "can't issue warm reset %d\n", ret); +		return ret; +	} + +	return count; +} +static DEVICE_ATTR_WO(warm_reset); +  static ssize_t u2_timeout_store(struct device *dev,  		struct device_attribute *attr, const char *buf, size_t count)  { @@ -274,13 +293,35 @@ free_desc:  }  static DEVICE_ATTR_WO(get_dev_desc); +static ssize_t enable_compliance_store(struct device *dev, +		struct device_attribute *attr, const char *buf, size_t count) +{ +	struct usb_interface *intf = to_usb_interface(dev); +	struct usb_device *hdev = interface_to_usbdev(intf); +	struct lvs_rh *lvs = usb_get_intfdata(intf); +	int ret; + +	ret = lvs_rh_set_port_feature(hdev, +			lvs->portnum | USB_SS_PORT_LS_COMP_MOD << 3, +			USB_PORT_FEAT_LINK_STATE); +	if (ret < 0) { +		dev_err(dev, "can't enable compliance mode %d\n", ret); +		return ret; +	} + +	return count; +} +static DEVICE_ATTR_WO(enable_compliance); +  static struct attribute *lvs_attributes[] = {  	&dev_attr_get_dev_desc.attr,  	&dev_attr_u1_timeout.attr,  	&dev_attr_u2_timeout.attr,  	&dev_attr_hot_reset.attr, +	&dev_attr_warm_reset.attr,  	&dev_attr_u3_entry.attr,  	&dev_attr_u3_exit.attr, +	&dev_attr_enable_compliance.attr,  	NULL  }; diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c index b106ce76997b..ddfebb144aaa 100644 --- a/drivers/usb/misc/rio500.c +++ b/drivers/usb/misc/rio500.c @@ -43,10 +43,6 @@  #include "rio500_usb.h" -/* - * Version Information - */ -#define DRIVER_VERSION "v1.1"  #define DRIVER_AUTHOR "Cesar Miquel <[email protected]>"  #define DRIVER_DESC "USB Rio 500 driver" diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 440d7fef58cc..30774e0aeadd 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -610,13 +610,11 @@ static int sisusb_write_memio_byte(struct sisusb_usb_data *sisusb, int type,  		u32 addr, u8 data)  {  	struct sisusb_packet packet; -	int ret;  	packet.header  = (1 << (addr & 3)) | (type << 6);  	packet.address = addr & ~3;  	packet.data    = data << ((addr & 3) << 3); -	ret = sisusb_send_packet(sisusb, 10, &packet); -	return ret; +	return sisusb_send_packet(sisusb, 10, &packet);  }  static int sisusb_write_memio_word(struct sisusb_usb_data *sisusb, int type, @@ -1333,13 +1331,11 @@ static int sisusb_write_pci_config(struct sisusb_usb_data *sisusb,  		int regnum, u32 data)  {  	struct sisusb_packet packet; -	int ret;  	packet.header = 0x008f;  	packet.address = regnum | 0x10000;  	packet.data = data; -	ret = sisusb_send_packet(sisusb, 10, &packet); -	return ret; +	return sisusb_send_packet(sisusb, 10, &packet);  }  static int sisusb_read_pci_config(struct sisusb_usb_data *sisusb, @@ -2982,14 +2978,11 @@ err_out:  static long sisusb_compat_ioctl(struct file *f, unsigned int cmd,  		unsigned long arg)  { -	long retval; -  	switch (cmd) {  	case SISUSB_GET_CONFIG_SIZE:  	case SISUSB_GET_CONFIG:  	case SISUSB_COMMAND: -		retval = sisusb_ioctl(f, cmd, arg); -		return retval; +		return sisusb_ioctl(f, cmd, arg);  	default:  		return -ENOIOCTLCMD; diff --git a/drivers/usb/misc/trancevibrator.c b/drivers/usb/misc/trancevibrator.c index 9795457723d8..1862ed15ce28 100644 --- a/drivers/usb/misc/trancevibrator.c +++ b/drivers/usb/misc/trancevibrator.c @@ -25,8 +25,6 @@  #include <linux/module.h>  #include <linux/usb.h> -/* Version Information */ -#define DRIVER_VERSION "v1.1"  #define DRIVER_AUTHOR "Sam Hocevar, [email protected]"  #define DRIVER_DESC "PlayStation 2 Trance Vibrator driver" diff --git a/drivers/usb/misc/usb251xb.c b/drivers/usb/misc/usb251xb.c index 91f66d68bcb7..135c91c434bf 100644 --- a/drivers/usb/misc/usb251xb.c +++ b/drivers/usb/misc/usb251xb.c @@ -114,7 +114,6 @@  #define DRIVER_NAME	"usb251xb"  #define DRIVER_DESC	"Microchip USB 2.0 Hi-Speed Hub Controller" -#define DRIVER_VERSION	"1.0"  struct usb251xb {  	struct device *dev; diff --git a/drivers/usb/misc/usbsevseg.c b/drivers/usb/misc/usbsevseg.c index 388fae6373db..3f6a28045b53 100644 --- a/drivers/usb/misc/usbsevseg.c +++ b/drivers/usb/misc/usbsevseg.c @@ -330,7 +330,7 @@ static struct attribute *dev_attrs[] = {  	NULL  }; -static struct attribute_group dev_attr_grp = { +static const struct attribute_group dev_attr_grp = {  	.attrs = dev_attrs,  }; diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c index 5947373700a1..8a13b2fcf3e1 100644 --- a/drivers/usb/misc/uss720.c +++ b/drivers/usb/misc/uss720.c @@ -52,10 +52,6 @@  #include <linux/slab.h>  #include <linux/sched/signal.h> -/* - * Version Information - */ -#define DRIVER_VERSION "v0.6"  #define DRIVER_AUTHOR "Thomas M. Sailer, [email protected]"  #define DRIVER_DESC "USB Parport Cable driver for Cables using the Lucent Technologies USS720 Chip" @@ -816,8 +812,7 @@ static int __init uss720_init(void)  	if (retval)  		goto out; -	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" -	       DRIVER_DESC "\n"); +	printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");  	printk(KERN_INFO KBUILD_MODNAME ": NOTE: this is a special purpose "  	       "driver to allow nonstandard\n");  	printk(KERN_INFO KBUILD_MODNAME ": protocols (eg. bitbang) over " diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h index 7b6dc23d77e9..b26fffc58446 100644 --- a/drivers/usb/mtu3/mtu3.h +++ b/drivers/usb/mtu3/mtu3.h @@ -288,6 +288,7 @@ static inline struct ssusb_mtk *dev_to_ssusb(struct device *dev)   *		MTU3_U3_IP_SLOT_DEFAULT for U3 IP   * @may_wakeup: means device's remote wakeup is enabled   * @is_self_powered: is reported in device status and the config descriptor + * @delayed_status: true when function drivers ask for delayed status   * @ep0_req: dummy request used while handling standard USB requests   *		for GET_STATUS and SET_SEL   * @setup_buf: ep0 response buffer for GET_STATUS and SET_SEL requests @@ -327,6 +328,7 @@ struct mtu3 {  	unsigned u1_enable:1;  	unsigned u2_enable:1;  	unsigned is_u3_ip:1; +	unsigned delayed_status:1;  	u8 address;  	u8 test_mode_nr; diff --git a/drivers/usb/mtu3/mtu3_dr.c b/drivers/usb/mtu3/mtu3_dr.c index 11a0d3b84c5e..560256115b23 100644 --- a/drivers/usb/mtu3/mtu3_dr.c +++ b/drivers/usb/mtu3/mtu3_dr.c @@ -322,23 +322,65 @@ static const struct file_operations ssusb_mode_fops = {  	.release = single_release,  }; +static int ssusb_vbus_show(struct seq_file *sf, void *unused) +{ +	struct ssusb_mtk *ssusb = sf->private; +	struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; + +	seq_printf(sf, "vbus state: %s\n(echo on/off)\n", +		regulator_is_enabled(otg_sx->vbus) ? "on" : "off"); + +	return 0; +} + +static int ssusb_vbus_open(struct inode *inode, struct file *file) +{ +	return single_open(file, ssusb_vbus_show, inode->i_private); +} + +static ssize_t ssusb_vbus_write(struct file *file, +	const char __user *ubuf, size_t count, loff_t *ppos) +{ +	struct seq_file *sf = file->private_data; +	struct ssusb_mtk *ssusb = sf->private; +	struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; +	char buf[16]; +	bool enable; + +	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) +		return -EFAULT; + +	if (kstrtobool(buf, &enable)) { +		dev_err(ssusb->dev, "wrong setting\n"); +		return -EINVAL; +	} + +	ssusb_set_vbus(otg_sx, enable); + +	return count; +} + +static const struct file_operations ssusb_vbus_fops = { +	.open = ssusb_vbus_open, +	.write = ssusb_vbus_write, +	.read = seq_read, +	.llseek = seq_lseek, +	.release = single_release, +}; +  static void ssusb_debugfs_init(struct ssusb_mtk *ssusb)  {  	struct dentry *root; -	struct dentry *file;  	root = debugfs_create_dir(dev_name(ssusb->dev), usb_debug_root); -	if (IS_ERR_OR_NULL(root)) { -		if (!root) -			dev_err(ssusb->dev, "create debugfs root failed\n"); +	if (!root) { +		dev_err(ssusb->dev, "create debugfs root failed\n");  		return;  	}  	ssusb->dbgfs_root = root; -	file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root, -			ssusb, &ssusb_mode_fops); -	if (!file) -		dev_dbg(ssusb->dev, "create debugfs mode failed\n"); +	debugfs_create_file("mode", 0644, root, ssusb, &ssusb_mode_fops); +	debugfs_create_file("vbus", 0644, root, ssusb, &ssusb_vbus_fops);  }  static void ssusb_debugfs_exit(struct ssusb_mtk *ssusb) diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c index 9dd2441b4fa1..434fca58143c 100644 --- a/drivers/usb/mtu3/mtu3_gadget.c +++ b/drivers/usb/mtu3/mtu3_gadget.c @@ -663,6 +663,7 @@ int mtu3_gadget_setup(struct mtu3 *mtu)  	mtu->g.sg_supported = 0;  	mtu->g.name = MTU3_DRIVER_NAME;  	mtu->is_active = 0; +	mtu->delayed_status = false;  	mtu3_gadget_init_eps(mtu); @@ -727,4 +728,7 @@ void mtu3_gadget_reset(struct mtu3 *mtu)  	mtu->address = 0;  	mtu->ep0_state = MU3D_EP0_STATE_SETUP;  	mtu->may_wakeup = 0; +	mtu->u1_enable = 0; +	mtu->u2_enable = 0; +	mtu->delayed_status = false;  } diff --git a/drivers/usb/mtu3/mtu3_gadget_ep0.c b/drivers/usb/mtu3/mtu3_gadget_ep0.c index 2d7427b48775..958d74dd2b78 100644 --- a/drivers/usb/mtu3/mtu3_gadget_ep0.c +++ b/drivers/usb/mtu3/mtu3_gadget_ep0.c @@ -16,6 +16,8 @@   *   */ +#include <linux/usb/composite.h> +  #include "mtu3.h"  /* ep0 is always mtu3->in_eps[0] */ @@ -150,6 +152,7 @@ static void ep0_stall_set(struct mtu3_ep *mep0, bool set, u32 pktrdy)  		csr = (csr & ~EP0_SENDSTALL) | EP0_SENTSTALL;  	mtu3_writel(mtu->mac_base, U3D_EP0CSR, csr); +	mtu->delayed_status = false;  	mtu->ep0_state = MU3D_EP0_STATE_SETUP;  	dev_dbg(mtu->dev, "ep0: %s STALL, ep0_state: %s\n", @@ -656,6 +659,9 @@ stall:  finish:  	if (mtu->test_mode) {  		;	/* nothing to do */ +	} else if (handled == USB_GADGET_DELAYED_STATUS) { +		/* handle the delay STATUS phase till receive ep_queue on ep0 */ +		mtu->delayed_status = true;  	} else if (le16_to_cpu(setup.wLength) == 0) { /* no data stage */  		mtu3_writel(mbase, U3D_EP0CSR, @@ -775,9 +781,6 @@ static int ep0_queue(struct mtu3_ep *mep, struct mtu3_request *mreq)  	dev_dbg(mtu->dev, "%s %s (ep0_state: %s), len#%d\n", __func__,  		mep->name, decode_ep0_state(mtu), mreq->request.length); -	if (!list_empty(&mep->req_list)) -		return -EBUSY; -  	switch (mtu->ep0_state) {  	case MU3D_EP0_STATE_SETUP:  	case MU3D_EP0_STATE_RX:	/* control-OUT data */ @@ -789,6 +792,20 @@ static int ep0_queue(struct mtu3_ep *mep, struct mtu3_request *mreq)  		return -EINVAL;  	} +	if (mtu->delayed_status) { +		u32 csr; + +		mtu->delayed_status = false; +		csr = mtu3_readl(mtu->mac_base, U3D_EP0CSR) & EP0_W1C_BITS; +		csr |= EP0_SETUPPKTRDY | EP0_DATAEND; +		mtu3_writel(mtu->mac_base, U3D_EP0CSR, csr); +		/* needn't giveback the request for handling delay STATUS */ +		return 0; +	} + +	if (!list_empty(&mep->req_list)) +		return -EBUSY; +  	list_add_tail(&mreq->list, &mep->req_list);  	/* sequence #1, IN ... start writing the data */ diff --git a/drivers/usb/mtu3/mtu3_host.c b/drivers/usb/mtu3/mtu3_host.c index cd4d01087855..e42d308b8dc2 100644 --- a/drivers/usb/mtu3/mtu3_host.c +++ b/drivers/usb/mtu3/mtu3_host.c @@ -258,8 +258,8 @@ int ssusb_host_init(struct ssusb_mtk *ssusb, struct device_node *parent_dn)  	ret = of_platform_populate(parent_dn, NULL, NULL, parent_dev);  	if (ret) { -		dev_dbg(parent_dev, "failed to create child devices at %s\n", -				parent_dn->full_name); +		dev_dbg(parent_dev, "failed to create child devices at %pOF\n", +				parent_dn);  		return ret;  	} diff --git a/drivers/usb/mtu3/mtu3_hw_regs.h b/drivers/usb/mtu3/mtu3_hw_regs.h index 212367295276..06b29664470f 100644 --- a/drivers/usb/mtu3/mtu3_hw_regs.h +++ b/drivers/usb/mtu3/mtu3_hw_regs.h @@ -462,10 +462,12 @@  #define SSUSB_U3_PORT_DIS		BIT(0)  /* U3D_SSUSB_U2_CTRL_0P */ +#define SSUSB_U2_PORT_VBUSVALID	BIT(9)  #define SSUSB_U2_PORT_OTG_SEL		BIT(7) -#define SSUSB_U2_PORT_HOST_SEL		BIT(2) +#define SSUSB_U2_PORT_HOST		BIT(2)  #define SSUSB_U2_PORT_PDN		BIT(1)  #define SSUSB_U2_PORT_DIS		BIT(0) +#define SSUSB_U2_PORT_HOST_SEL	(SSUSB_U2_PORT_VBUSVALID | SSUSB_U2_PORT_HOST)  /* U3D_SSUSB_DEV_RST_CTRL */  #define SSUSB_DEV_SW_RST		BIT(0) diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c index 0d3ebb353e08..088e3e685c4f 100644 --- a/drivers/usb/mtu3/mtu3_plat.c +++ b/drivers/usb/mtu3/mtu3_plat.c @@ -500,6 +500,7 @@ static const struct dev_pm_ops mtu3_pm_ops = {  static const struct of_device_id mtu3_of_match[] = {  	{.compatible = "mediatek,mt8173-mtu3",}, +	{.compatible = "mediatek,mtu3",},  	{},  }; diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 87cbd56cc761..029692053dd3 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1156,8 +1156,8 @@ static struct musb_fifo_cfg mode_2_cfg[] = {  { .hw_ep_num = 1, .style = FIFO_RX,   .maxpacket = 512, },  { .hw_ep_num = 2, .style = FIFO_TX,   .maxpacket = 512, },  { .hw_ep_num = 2, .style = FIFO_RX,   .maxpacket = 512, }, -{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 256, }, -{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 256, }, +{ .hw_ep_num = 3, .style = FIFO_RXTX, .maxpacket = 960, }, +{ .hw_ep_num = 4, .style = FIFO_RXTX, .maxpacket = 1024, },  };  /* mode 3 - fits in 4KB */ @@ -2671,6 +2671,13 @@ static int musb_suspend(struct device *dev)  {  	struct musb	*musb = dev_to_musb(dev);  	unsigned long	flags; +	int ret; + +	ret = pm_runtime_get_sync(dev); +	if (ret < 0) { +		pm_runtime_put_noidle(dev); +		return ret; +	}  	musb_platform_disable(musb);  	musb_disable_interrupts(musb); @@ -2721,14 +2728,6 @@ static int musb_resume(struct device *dev)  	if ((devctl & mask) != (musb->context.devctl & mask))  		musb->port1_status = 0; -	/* -	 * The USB HUB code expects the device to be in RPM_ACTIVE once it came -	 * out of suspend -	 */ -	pm_runtime_disable(dev); -	pm_runtime_set_active(dev); -	pm_runtime_enable(dev); -  	musb_start(musb);  	spin_lock_irqsave(&musb->lock, flags); @@ -2738,6 +2737,9 @@ static int musb_resume(struct device *dev)  			error);  	spin_unlock_irqrestore(&musb->lock, flags); +	pm_runtime_mark_last_busy(dev); +	pm_runtime_put_autosuspend(dev); +  	return 0;  } diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 9f22c5b8ce37..c748f4ac1154 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -465,6 +465,30 @@ static inline struct musb *gadget_to_musb(struct usb_gadget *g)  	return container_of(g, struct musb, g);  } +static inline char *musb_ep_xfertype_string(u8 type) +{ +	char *s; + +	switch (type) { +	case USB_ENDPOINT_XFER_CONTROL: +		s = "ctrl"; +		break; +	case USB_ENDPOINT_XFER_ISOC: +		s = "iso"; +		break; +	case USB_ENDPOINT_XFER_BULK: +		s = "bulk"; +		break; +	case USB_ENDPOINT_XFER_INT: +		s = "int"; +		break; +	default: +		s = ""; +		break; +	} +	return s; +} +  #ifdef CONFIG_BLACKFIN  static inline int musb_read_fifosize(struct musb *musb,  		struct musb_hw_ep *hw_ep, u8 epnum) diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index bc6a9be2ccc5..f6b526606ad1 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -1015,13 +1015,20 @@ static int dsps_suspend(struct device *dev)  	const struct dsps_musb_wrapper *wrp = glue->wrp;  	struct musb *musb = platform_get_drvdata(glue->musb);  	void __iomem *mbase; - -	del_timer_sync(&glue->timer); +	int ret;  	if (!musb)  		/* This can happen if the musb device is in -EPROBE_DEFER */  		return 0; +	ret = pm_runtime_get_sync(dev); +	if (ret < 0) { +		pm_runtime_put_noidle(dev); +		return ret; +	} + +	del_timer_sync(&glue->timer); +  	mbase = musb->ctrl_base;  	glue->context.control = musb_readl(mbase, wrp->control);  	glue->context.epintr = musb_readl(mbase, wrp->epintr_set); @@ -1060,6 +1067,8 @@ static int dsps_resume(struct device *dev)  	    musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE)  		dsps_mod_timer(glue, -1); +	pm_runtime_put(dev); +  	return 0;  }  #endif diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 1acc4864f9f6..bc6d1717c9ec 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1105,11 +1105,7 @@ static int musb_gadget_enable(struct usb_ep *ep,  	pr_debug("%s periph: enabled %s for %s %s, %smaxpacket %d\n",  			musb_driver_name, musb_ep->end_point.name, -			({ char *s; switch (musb_ep->type) { -			case USB_ENDPOINT_XFER_BULK:	s = "bulk"; break; -			case USB_ENDPOINT_XFER_INT:	s = "int"; break; -			default:			s = "iso"; break; -			} s; }), +			musb_ep_xfertype_string(musb_ep->type),  			musb_ep->is_in ? "IN" : "OUT",  			musb_ep->dma ? "dma, " : "",  			musb_ep->packet_sz); diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 3344ffd5bb13..b17450a59882 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -2152,6 +2152,10 @@ static int musb_schedule(  				(USB_SPEED_HIGH == qh->dev->speed) ? 8 : 4;  		goto success;  	} else if (best_end < 0) { +		dev_err(musb->controller, +				"%s hwep alloc failed for %dx%d\n", +				musb_ep_xfertype_string(qh->type), +				qh->hb_mult, qh->maxpacket);  		return -ENOSPC;  	} @@ -2244,6 +2248,10 @@ static int musb_urb_enqueue(  			ok = (usb_pipein(urb->pipe) && musb->hb_iso_rx)  				|| (usb_pipeout(urb->pipe) && musb->hb_iso_tx);  		if (!ok) { +			dev_err(musb->controller, +				"high bandwidth %s (%dx%d) not supported\n", +				musb_ep_xfertype_string(qh->type), +				qh->hb_mult, qh->maxpacket & 0x7ff);  			ret = -EMSGSIZE;  			goto done;  		} diff --git a/drivers/usb/phy/phy-mv-usb.c b/drivers/usb/phy/phy-mv-usb.c index 697a741a0cb1..0e315694adc9 100644 --- a/drivers/usb/phy/phy-mv-usb.c +++ b/drivers/usb/phy/phy-mv-usb.c @@ -29,10 +29,8 @@  #include "phy-mv-usb.h"  #define	DRIVER_DESC	"Marvell USB OTG transceiver driver" -#define	DRIVER_VERSION	"Jan 20, 2010"  MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_VERSION(DRIVER_VERSION);  MODULE_LICENSE("GPL");  static const char driver_name[] = "mv-otg"; @@ -650,7 +648,7 @@ static struct attribute *inputs_attrs[] = {  	NULL,  }; -static struct attribute_group inputs_attr_group = { +static const struct attribute_group inputs_attr_group = {  	.name = "inputs",  	.attrs = inputs_attrs,  }; diff --git a/drivers/usb/phy/phy-qcom-8x16-usb.c b/drivers/usb/phy/phy-qcom-8x16-usb.c index b6a83a5cbad3..679afeaaa9a8 100644 --- a/drivers/usb/phy/phy-qcom-8x16-usb.c +++ b/drivers/usb/phy/phy-qcom-8x16-usb.c @@ -270,12 +270,9 @@ static int phy_8x16_probe(struct platform_device *pdev)  	platform_set_drvdata(pdev, qphy);  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!res) -		return -EINVAL; - -	qphy->regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); -	if (!qphy->regs) -		return -ENOMEM; +	qphy->regs = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(qphy->regs)) +		return PTR_ERR(qphy->regs);  	phy			= &qphy->phy;  	phy->dev		= &pdev->dev; diff --git a/drivers/usb/phy/phy-tahvo.c b/drivers/usb/phy/phy-tahvo.c index a31c8682e998..8babd318c0ed 100644 --- a/drivers/usb/phy/phy-tahvo.c +++ b/drivers/usb/phy/phy-tahvo.c @@ -326,7 +326,7 @@ static struct attribute *tahvo_attributes[] = {  	NULL  }; -static struct attribute_group tahvo_attr_group = { +static const struct attribute_group tahvo_attr_group = {  	.attrs = tahvo_attributes,  }; diff --git a/drivers/usb/phy/phy.c b/drivers/usb/phy/phy.c index 032f5afaad4b..89f4ac4cd93e 100644 --- a/drivers/usb/phy/phy.c +++ b/drivers/usb/phy/phy.c @@ -18,6 +18,18 @@  #include <linux/usb/phy.h> +/* Default current range by charger type. */ +#define DEFAULT_SDP_CUR_MIN	2 +#define DEFAULT_SDP_CUR_MAX	500 +#define DEFAULT_SDP_CUR_MIN_SS	150 +#define DEFAULT_SDP_CUR_MAX_SS	900 +#define DEFAULT_DCP_CUR_MIN	500 +#define DEFAULT_DCP_CUR_MAX	5000 +#define DEFAULT_CDP_CUR_MIN	1500 +#define DEFAULT_CDP_CUR_MAX	5000 +#define DEFAULT_ACA_CUR_MIN	1500 +#define DEFAULT_ACA_CUR_MAX	5000 +  static LIST_HEAD(phy_list);  static LIST_HEAD(phy_bind_list);  static DEFINE_SPINLOCK(phy_lock); @@ -77,6 +89,221 @@ static struct usb_phy *__of_usb_find_phy(struct device_node *node)  	return ERR_PTR(-EPROBE_DEFER);  } +static void usb_phy_set_default_current(struct usb_phy *usb_phy) +{ +	usb_phy->chg_cur.sdp_min = DEFAULT_SDP_CUR_MIN; +	usb_phy->chg_cur.sdp_max = DEFAULT_SDP_CUR_MAX; +	usb_phy->chg_cur.dcp_min = DEFAULT_DCP_CUR_MIN; +	usb_phy->chg_cur.dcp_max = DEFAULT_DCP_CUR_MAX; +	usb_phy->chg_cur.cdp_min = DEFAULT_CDP_CUR_MIN; +	usb_phy->chg_cur.cdp_max = DEFAULT_CDP_CUR_MAX; +	usb_phy->chg_cur.aca_min = DEFAULT_ACA_CUR_MIN; +	usb_phy->chg_cur.aca_max = DEFAULT_ACA_CUR_MAX; +} + +/** + * usb_phy_notify_charger_work - notify the USB charger state + * @work - the charger work to notify the USB charger state + * + * This work can be issued when USB charger state has been changed or + * USB charger current has been changed, then we can notify the current + * what can be drawn to power user and the charger state to userspace. + * + * If we get the charger type from extcon subsystem, we can notify the + * charger state to power user automatically by usb_phy_get_charger_type() + * issuing from extcon subsystem. + * + * If we get the charger type from ->charger_detect() instead of extcon + * subsystem, the usb phy driver should issue usb_phy_set_charger_state() + * to set charger state when the charger state has been changed. + */ +static void usb_phy_notify_charger_work(struct work_struct *work) +{ +	struct usb_phy *usb_phy = container_of(work, struct usb_phy, chg_work); +	char uchger_state[50] = { 0 }; +	char *envp[] = { uchger_state, NULL }; +	unsigned int min, max; + +	switch (usb_phy->chg_state) { +	case USB_CHARGER_PRESENT: +		usb_phy_get_charger_current(usb_phy, &min, &max); + +		atomic_notifier_call_chain(&usb_phy->notifier, max, usb_phy); +		snprintf(uchger_state, ARRAY_SIZE(uchger_state), +			 "USB_CHARGER_STATE=%s", "USB_CHARGER_PRESENT"); +		break; +	case USB_CHARGER_ABSENT: +		usb_phy_set_default_current(usb_phy); + +		atomic_notifier_call_chain(&usb_phy->notifier, 0, usb_phy); +		snprintf(uchger_state, ARRAY_SIZE(uchger_state), +			 "USB_CHARGER_STATE=%s", "USB_CHARGER_ABSENT"); +		break; +	default: +		dev_warn(usb_phy->dev, "Unknown USB charger state: %d\n", +			 usb_phy->chg_state); +		return; +	} + +	kobject_uevent_env(&usb_phy->dev->kobj, KOBJ_CHANGE, envp); +} + +static void __usb_phy_get_charger_type(struct usb_phy *usb_phy) +{ +	if (extcon_get_state(usb_phy->edev, EXTCON_CHG_USB_SDP) > 0) { +		usb_phy->chg_type = SDP_TYPE; +		usb_phy->chg_state = USB_CHARGER_PRESENT; +	} else if (extcon_get_state(usb_phy->edev, EXTCON_CHG_USB_CDP) > 0) { +		usb_phy->chg_type = CDP_TYPE; +		usb_phy->chg_state = USB_CHARGER_PRESENT; +	} else if (extcon_get_state(usb_phy->edev, EXTCON_CHG_USB_DCP) > 0) { +		usb_phy->chg_type = DCP_TYPE; +		usb_phy->chg_state = USB_CHARGER_PRESENT; +	} else if (extcon_get_state(usb_phy->edev, EXTCON_CHG_USB_ACA) > 0) { +		usb_phy->chg_type = ACA_TYPE; +		usb_phy->chg_state = USB_CHARGER_PRESENT; +	} else { +		usb_phy->chg_type = UNKNOWN_TYPE; +		usb_phy->chg_state = USB_CHARGER_ABSENT; +	} + +	schedule_work(&usb_phy->chg_work); +} + +/** + * usb_phy_get_charger_type - get charger type from extcon subsystem + * @nb -the notifier block to determine charger type + * @state - the cable state + * @data - private data + * + * Determin the charger type from extcon subsystem which also means the + * charger state has been chaned, then we should notify this event. + */ +static int usb_phy_get_charger_type(struct notifier_block *nb, +				    unsigned long state, void *data) +{ +	struct usb_phy *usb_phy = container_of(nb, struct usb_phy, type_nb); + +	__usb_phy_get_charger_type(usb_phy); +	return NOTIFY_OK; +} + +/** + * usb_phy_set_charger_current - set the USB charger current + * @usb_phy - the USB phy to be used + * @mA - the current need to be set + * + * Usually we only change the charger default current when USB finished the + * enumeration as one SDP charger. As one SDP charger, usb_phy_set_power() + * will issue this function to change charger current when after setting USB + * configuration, or suspend/resume USB. For other type charger, we should + * use the default charger current and we do not suggest to issue this function + * to change the charger current. + * + * When USB charger current has been changed, we need to notify the power users. + */ +void usb_phy_set_charger_current(struct usb_phy *usb_phy, unsigned int mA) +{ +	switch (usb_phy->chg_type) { +	case SDP_TYPE: +		if (usb_phy->chg_cur.sdp_max == mA) +			return; + +		usb_phy->chg_cur.sdp_max = (mA > DEFAULT_SDP_CUR_MAX_SS) ? +			DEFAULT_SDP_CUR_MAX_SS : mA; +		break; +	case DCP_TYPE: +		if (usb_phy->chg_cur.dcp_max == mA) +			return; + +		usb_phy->chg_cur.dcp_max = (mA > DEFAULT_DCP_CUR_MAX) ? +			DEFAULT_DCP_CUR_MAX : mA; +		break; +	case CDP_TYPE: +		if (usb_phy->chg_cur.cdp_max == mA) +			return; + +		usb_phy->chg_cur.cdp_max = (mA > DEFAULT_CDP_CUR_MAX) ? +			DEFAULT_CDP_CUR_MAX : mA; +		break; +	case ACA_TYPE: +		if (usb_phy->chg_cur.aca_max == mA) +			return; + +		usb_phy->chg_cur.aca_max = (mA > DEFAULT_ACA_CUR_MAX) ? +			DEFAULT_ACA_CUR_MAX : mA; +		break; +	default: +		return; +	} + +	schedule_work(&usb_phy->chg_work); +} +EXPORT_SYMBOL_GPL(usb_phy_set_charger_current); + +/** + * usb_phy_get_charger_current - get the USB charger current + * @usb_phy - the USB phy to be used + * @min - the minimum current + * @max - the maximum current + * + * Usually we will notify the maximum current to power user, but for some + * special case, power user also need the minimum current value. Then the + * power user can issue this function to get the suitable current. + */ +void usb_phy_get_charger_current(struct usb_phy *usb_phy, +				 unsigned int *min, unsigned int *max) +{ +	switch (usb_phy->chg_type) { +	case SDP_TYPE: +		*min = usb_phy->chg_cur.sdp_min; +		*max = usb_phy->chg_cur.sdp_max; +		break; +	case DCP_TYPE: +		*min = usb_phy->chg_cur.dcp_min; +		*max = usb_phy->chg_cur.dcp_max; +		break; +	case CDP_TYPE: +		*min = usb_phy->chg_cur.cdp_min; +		*max = usb_phy->chg_cur.cdp_max; +		break; +	case ACA_TYPE: +		*min = usb_phy->chg_cur.aca_min; +		*max = usb_phy->chg_cur.aca_max; +		break; +	default: +		*min = 0; +		*max = 0; +		break; +	} +} +EXPORT_SYMBOL_GPL(usb_phy_get_charger_current); + +/** + * usb_phy_set_charger_state - set the USB charger state + * @usb_phy - the USB phy to be used + * @state - the new state need to be set for charger + * + * The usb phy driver can issue this function when the usb phy driver + * detected the charger state has been changed, in this case the charger + * type should be get from ->charger_detect(). + */ +void usb_phy_set_charger_state(struct usb_phy *usb_phy, +			       enum usb_charger_state state) +{ +	if (usb_phy->chg_state == state || !usb_phy->charger_detect) +		return; + +	usb_phy->chg_state = state; +	if (usb_phy->chg_state == USB_CHARGER_PRESENT) +		usb_phy->chg_type = usb_phy->charger_detect(usb_phy); +	else +		usb_phy->chg_type = UNKNOWN_TYPE; + +	schedule_work(&usb_phy->chg_work); +} +EXPORT_SYMBOL_GPL(usb_phy_set_charger_state); +  static void devm_usb_phy_release(struct device *dev, void *res)  {  	struct usb_phy *phy = *(struct usb_phy **)res; @@ -124,6 +351,44 @@ static int usb_add_extcon(struct usb_phy *x)  					"register VBUS notifier failed\n");  				return ret;  			} +		} else { +			x->type_nb.notifier_call = usb_phy_get_charger_type; + +			ret = devm_extcon_register_notifier(x->dev, x->edev, +							    EXTCON_CHG_USB_SDP, +							    &x->type_nb); +			if (ret) { +				dev_err(x->dev, +					"register extcon USB SDP failed.\n"); +				return ret; +			} + +			ret = devm_extcon_register_notifier(x->dev, x->edev, +							    EXTCON_CHG_USB_CDP, +							    &x->type_nb); +			if (ret) { +				dev_err(x->dev, +					"register extcon USB CDP failed.\n"); +				return ret; +			} + +			ret = devm_extcon_register_notifier(x->dev, x->edev, +							    EXTCON_CHG_USB_DCP, +							    &x->type_nb); +			if (ret) { +				dev_err(x->dev, +					"register extcon USB DCP failed.\n"); +				return ret; +			} + +			ret = devm_extcon_register_notifier(x->dev, x->edev, +							    EXTCON_CHG_USB_ACA, +							    &x->type_nb); +			if (ret) { +				dev_err(x->dev, +					"register extcon USB ACA failed.\n"); +				return ret; +			}  		}  		if (x->id_nb.notifier_call) { @@ -145,6 +410,13 @@ static int usb_add_extcon(struct usb_phy *x)  		}  	} +	usb_phy_set_default_current(x); +	INIT_WORK(&x->chg_work, usb_phy_notify_charger_work); +	x->chg_type = UNKNOWN_TYPE; +	x->chg_state = USB_CHARGER_DEFAULT; +	if (x->type_nb.notifier_call) +		__usb_phy_get_charger_type(x); +  	return 0;  } @@ -302,8 +574,8 @@ struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev,  	node = of_parse_phandle(dev->of_node, phandle, index);  	if (!node) { -		dev_dbg(dev, "failed to get %s phandle in %s node\n", phandle, -			dev->of_node->full_name); +		dev_dbg(dev, "failed to get %s phandle in %pOF node\n", phandle, +			dev->of_node);  		return ERR_PTR(-ENODEV);  	}  	phy = devm_usb_get_phy_by_node(dev, node, NULL); diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 2c8161bcf5b5..c068b673420b 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -764,7 +764,7 @@ static int usbhsg_ep_set_wedge(struct usb_ep *ep)  	return __usbhsg_ep_set_halt_wedge(ep, 1, 1);  } -static struct usb_ep_ops usbhsg_ep_ops = { +static const struct usb_ep_ops usbhsg_ep_ops = {  	.enable		= usbhsg_ep_enable,  	.disable	= usbhsg_ep_disable, @@ -1082,7 +1082,6 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv)  		ret = -ENOMEM;  		goto usbhs_mod_gadget_probe_err_gpriv;  	} -	spin_lock_init(&uep->lock);  	gpriv->transceiver = usb_get_phy(USB_PHY_TYPE_UNDEFINED);  	dev_info(dev, "%stransceiver found\n", @@ -1132,6 +1131,7 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv)  		uep->ep.name		= uep->ep_name;  		uep->ep.ops		= &usbhsg_ep_ops;  		INIT_LIST_HEAD(&uep->ep.ep_list); +		spin_lock_init(&uep->lock);  		/* init DCP */  		if (usbhsg_is_dcp(uep)) { diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index dfb346e9bd0c..e256351cb72d 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -1285,7 +1285,7 @@ static int usbhsh_bus_nop(struct usb_hcd *hcd)  	return 0;  } -static struct hc_driver usbhsh_driver = { +static const struct hc_driver usbhsh_driver = {  	.description =		usbhsh_hcd_name,  	.hcd_priv_size =	sizeof(struct usbhsh_hpriv), diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c index 9396a8c14af8..d811f0550c04 100644 --- a/drivers/usb/renesas_usbhs/pipe.c +++ b/drivers/usb/renesas_usbhs/pipe.c @@ -401,7 +401,7 @@ static int usbhsp_setup_pipecfg(struct usbhs_pipe *pipe, int is_host,  	u16 dir = 0;  	u16 epnum = 0;  	u16 shtnak = 0; -	u16 type_array[] = { +	static const u16 type_array[] = {  		[USB_ENDPOINT_XFER_BULK] = TYPE_BULK,  		[USB_ENDPOINT_XFER_INT]  = TYPE_INT,  		[USB_ENDPOINT_XFER_ISOC] = TYPE_ISO, diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index fe123153b1a5..54bfef13966a 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -2016,13 +2016,11 @@ static const struct usb_device_id option_ids[] = {  	{ USB_DEVICE(TPLINK_VENDOR_ID, 0x9000),					/* TP-Link MA260 */  	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist },  	{ USB_DEVICE(CHANGHONG_VENDOR_ID, CHANGHONG_PRODUCT_CH690) }, -	{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d01, 0xff, 0x02, 0x01) },	/* D-Link DWM-156 (variant) */ -	{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d01, 0xff, 0x00, 0x00) },	/* D-Link DWM-156 (variant) */ -	{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d02, 0xff, 0x02, 0x01) }, -	{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d02, 0xff, 0x00, 0x00) }, -	{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x02, 0x01) }, -	{ USB_DEVICE_AND_INTERFACE_INFO(0x2001, 0x7d03, 0xff, 0x00, 0x00) }, +	{ USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7d01, 0xff) },			/* D-Link DWM-156 (variant) */ +	{ USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7d02, 0xff) }, +	{ USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7d03, 0xff) },  	{ USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7d04, 0xff) },			/* D-Link DWM-158 */ +	{ USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7d0e, 0xff) },			/* D-Link DWM-157 C1 */  	{ USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7e19, 0xff),			/* D-Link DWM-221 B1 */  	  .driver_info = (kernel_ulong_t)&net_intf4_blacklist },  	{ USB_DEVICE_INTERFACE_CLASS(0x2001, 0x7e35, 0xff),			/* D-Link DWM-222 */ diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c index 4176d1af9bf2..ec83b3b5efa9 100644 --- a/drivers/usb/storage/realtek_cr.c +++ b/drivers/usb/storage/realtek_cr.c @@ -47,7 +47,6 @@  MODULE_DESCRIPTION("Driver for Realtek USB Card Reader");  MODULE_AUTHOR("wwang <[email protected]>");  MODULE_LICENSE("GPL"); -MODULE_VERSION("1.03");  static int auto_delink_en = 1;  module_param(auto_delink_en, int, S_IRUGO | S_IWUSR); diff --git a/drivers/usb/usbip/stub_main.c b/drivers/usb/usbip/stub_main.c index 660180a5d5c4..7170404e8979 100644 --- a/drivers/usb/usbip/stub_main.c +++ b/drivers/usb/usbip/stub_main.c @@ -302,7 +302,6 @@ static int __init usbip_host_init(void)  		goto err_create_file;  	} -	pr_info(DRIVER_DESC " v" USBIP_VERSION "\n");  	return ret;  err_create_file: @@ -335,4 +334,3 @@ module_exit(usbip_host_exit);  MODULE_AUTHOR(DRIVER_AUTHOR);  MODULE_DESCRIPTION(DRIVER_DESC);  MODULE_LICENSE("GPL"); -MODULE_VERSION(USBIP_VERSION); diff --git a/drivers/usb/usbip/usbip_common.c b/drivers/usb/usbip/usbip_common.c index cab2b71a80d0..2281f3562870 100644 --- a/drivers/usb/usbip/usbip_common.c +++ b/drivers/usb/usbip/usbip_common.c @@ -763,7 +763,6 @@ static int __init usbip_core_init(void)  {  	int ret; -	pr_info(DRIVER_DESC " v" USBIP_VERSION "\n");  	ret = usbip_init_eh();  	if (ret)  		return ret; @@ -783,4 +782,3 @@ module_exit(usbip_core_exit);  MODULE_AUTHOR(DRIVER_AUTHOR);  MODULE_DESCRIPTION(DRIVER_DESC);  MODULE_LICENSE("GPL"); -MODULE_VERSION(USBIP_VERSION); diff --git a/drivers/usb/usbip/usbip_common.h b/drivers/usb/usbip/usbip_common.h index f8573a52e41a..3050fc99a417 100644 --- a/drivers/usb/usbip/usbip_common.h +++ b/drivers/usb/usbip/usbip_common.h @@ -34,8 +34,6 @@  #include <linux/sched/task.h>  #include <uapi/linux/usbip.h> -#define USBIP_VERSION "1.0.0" -  #undef pr_fmt  #ifdef DEBUG diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index 2c4b2fd40406..11b9a22799cc 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -1274,7 +1274,7 @@ static int vhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev,  	return 0;  } -static struct hc_driver vhci_hc_driver = { +static const struct hc_driver vhci_hc_driver = {  	.description	= driver_name,  	.product_desc	= driver_desc,  	.hcd_priv_size	= sizeof(struct vhci_hcd), @@ -1516,7 +1516,6 @@ static int __init vhci_hcd_init(void)  		}  	} -	pr_info(DRIVER_DESC " v" USBIP_VERSION "\n");  	return ret;  err_add_hcd: @@ -1542,4 +1541,3 @@ module_exit(vhci_hcd_exit);  MODULE_AUTHOR(DRIVER_AUTHOR);  MODULE_DESCRIPTION(DRIVER_DESC);  MODULE_LICENSE("GPL"); -MODULE_VERSION(USBIP_VERSION); diff --git a/drivers/usb/usbip/vhci_sysfs.c b/drivers/usb/usbip/vhci_sysfs.c index 5778b640ba9c..1b9f60a22e0b 100644 --- a/drivers/usb/usbip/vhci_sysfs.c +++ b/drivers/usb/usbip/vhci_sysfs.c @@ -366,7 +366,11 @@ static ssize_t store_attach(struct device *dev, struct device_attribute *attr,  		sockfd_put(socket);  		dev_err(dev, "port %d already used\n", rhport); -		return -EINVAL; +		/* +		 * Will be retried from userspace +		 * if there's another free port. +		 */ +		return -EBUSY;  	}  	dev_info(dev, "pdev(%u) rhport(%u) sockfd(%d)\n", diff --git a/drivers/usb/wusbcore/cbaf.c b/drivers/usb/wusbcore/cbaf.c index fb70cbef0671..aa4e440e9975 100644 --- a/drivers/usb/wusbcore/cbaf.c +++ b/drivers/usb/wusbcore/cbaf.c @@ -586,7 +586,7 @@ static struct attribute *cbaf_dev_attrs[] = {  	NULL,  }; -static struct attribute_group cbaf_dev_attr_group = { +static const struct attribute_group cbaf_dev_attr_group = {  	.name = NULL,	/* we want them in the same directory */  	.attrs = cbaf_dev_attrs,  }; diff --git a/drivers/usb/wusbcore/dev-sysfs.c b/drivers/usb/wusbcore/dev-sysfs.c index d4de56b93d68..78212f8180ce 100644 --- a/drivers/usb/wusbcore/dev-sysfs.c +++ b/drivers/usb/wusbcore/dev-sysfs.c @@ -114,7 +114,7 @@ static struct attribute *wusb_dev_attrs[] = {  		NULL,  }; -static struct attribute_group wusb_dev_attr_group = { +static const struct attribute_group wusb_dev_attr_group = {  	.name = NULL,	/* we want them in the same directory */  	.attrs = wusb_dev_attrs,  }; diff --git a/drivers/usb/wusbcore/wusbhc.c b/drivers/usb/wusbcore/wusbhc.c index a273a91cf667..5338e42533c8 100644 --- a/drivers/usb/wusbcore/wusbhc.c +++ b/drivers/usb/wusbcore/wusbhc.c @@ -244,7 +244,7 @@ static struct attribute *wusbhc_attrs[] = {  		NULL,  }; -static struct attribute_group wusbhc_attr_group = { +static const struct attribute_group wusbhc_attr_group = {  	.name = NULL,	/* we want them in the same directory */  	.attrs = wusbhc_attrs,  }; diff --git a/drivers/uwb/lc-rc.c b/drivers/uwb/lc-rc.c index 97ee1b46db69..b0816c753a63 100644 --- a/drivers/uwb/lc-rc.c +++ b/drivers/uwb/lc-rc.c @@ -228,7 +228,7 @@ static struct attribute *rc_attrs[] = {  		NULL,  }; -static struct attribute_group rc_attr_group = { +static const struct attribute_group rc_attr_group = {  	.attrs = rc_attrs,  }; diff --git a/include/linux/hid.h b/include/linux/hid.h index 5006f9b5d837..6519cdc4c7d3 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -363,6 +363,12 @@ struct hid_item {  #define HID_GROUP_LOGITECH_DJ_DEVICE		0x0102  /* + * HID protocol status + */ +#define HID_REPORT_PROTOCOL	1 +#define HID_BOOT_PROTOCOL	0 + +/*   * This is the global environment of the parser. This information is   * persistent for main-items. The global environment can be saved and   * restored with PUSH/POP statements. diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index c5fdfcf99828..d725cff7268d 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -58,6 +58,7 @@ struct ci_hdrc_platform_data {  #define CI_HDRC_OVERRIDE_TX_BURST	BIT(10)  #define CI_HDRC_OVERRIDE_RX_BURST	BIT(11)  #define CI_HDRC_OVERRIDE_PHY_CONTROL	BIT(12) /* Glue layer manages phy */ +#define CI_HDRC_REQUIRES_ALIGNED_DMA	BIT(13)  	enum usb_dr_mode	dr_mode;  #define CI_HDRC_CONTROLLER_RESET_EVENT		0  #define CI_HDRC_CONTROLLER_STOPPED_EVENT	1 diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h index 1a4a4bacfae6..21468a722c4a 100644 --- a/include/linux/usb/gadget.h +++ b/include/linux/usb/gadget.h @@ -48,6 +48,7 @@ struct usb_ep;   *     by adding a zero length packet as needed;   * @short_not_ok: When reading data, makes short packets be   *     treated as errors (queue stops advancing till cleanup). + * @dma_mapped: Indicates if request has been mapped to DMA (internal)   * @complete: Function called when request completes, so this request and   *	its buffer may be re-used.  The function will always be called with   *	interrupts disabled, and it must not sleep. @@ -103,6 +104,7 @@ struct usb_request {  	unsigned		no_interrupt:1;  	unsigned		zero:1;  	unsigned		short_not_ok:1; +	unsigned		dma_mapped:1;  	void			(*complete)(struct usb_ep *ep,  					struct usb_request *req); diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h index 299245105610..8c6914873a16 100644 --- a/include/linux/usb/phy.h +++ b/include/linux/usb/phy.h @@ -12,6 +12,7 @@  #include <linux/extcon.h>  #include <linux/notifier.h>  #include <linux/usb.h> +#include <uapi/linux/usb/charger.h>  enum usb_phy_interface {  	USBPHY_INTERFACE_MODE_UNKNOWN, @@ -72,6 +73,17 @@ struct usb_phy_io_ops {  	int (*write)(struct usb_phy *x, u32 val, u32 reg);  }; +struct usb_charger_current { +	unsigned int sdp_min; +	unsigned int sdp_max; +	unsigned int dcp_min; +	unsigned int dcp_max; +	unsigned int cdp_min; +	unsigned int cdp_max; +	unsigned int aca_min; +	unsigned int aca_max; +}; +  struct usb_phy {  	struct device		*dev;  	const char		*label; @@ -91,6 +103,13 @@ struct usb_phy {  	struct extcon_dev	*id_edev;  	struct notifier_block	vbus_nb;  	struct notifier_block	id_nb; +	struct notifier_block	type_nb; + +	/* Support USB charger */ +	enum usb_charger_type	chg_type; +	enum usb_charger_state	chg_state; +	struct usb_charger_current	chg_cur; +	struct work_struct		chg_work;  	/* for notification of usb_phy_events */  	struct atomic_notifier_head	notifier; @@ -129,6 +148,12 @@ struct usb_phy {  			enum usb_device_speed speed);  	int	(*notify_disconnect)(struct usb_phy *x,  			enum usb_device_speed speed); + +	/* +	 * Charger detection method can be implemented if you need to +	 * manually detect the charger type. +	 */ +	enum usb_charger_type (*charger_detect)(struct usb_phy *x);  };  /** @@ -219,6 +244,12 @@ extern void devm_usb_put_phy(struct device *dev, struct usb_phy *x);  extern int usb_bind_phy(const char *dev_name, u8 index,  				const char *phy_dev_name);  extern void usb_phy_set_event(struct usb_phy *x, unsigned long event); +extern void usb_phy_set_charger_current(struct usb_phy *usb_phy, +					unsigned int mA); +extern void usb_phy_get_charger_current(struct usb_phy *usb_phy, +					unsigned int *min, unsigned int *max); +extern void usb_phy_set_charger_state(struct usb_phy *usb_phy, +				      enum usb_charger_state state);  #else  static inline struct usb_phy *usb_get_phy(enum usb_phy_type type)  { @@ -270,12 +301,33 @@ static inline int usb_bind_phy(const char *dev_name, u8 index,  static inline void usb_phy_set_event(struct usb_phy *x, unsigned long event)  {  } + +static inline void usb_phy_set_charger_current(struct usb_phy *usb_phy, +					       unsigned int mA) +{ +} + +static inline void usb_phy_get_charger_current(struct usb_phy *usb_phy, +					       unsigned int *min, +					       unsigned int *max) +{ +} + +static inline void usb_phy_set_charger_state(struct usb_phy *usb_phy, +					     enum usb_charger_state state) +{ +}  #endif  static inline int  usb_phy_set_power(struct usb_phy *x, unsigned mA)  { -	if (x && x->set_power) +	if (!x) +		return 0; + +	usb_phy_set_charger_current(x, mA); + +	if (x->set_power)  		return x->set_power(x, mA);  	return 0;  } diff --git a/include/uapi/linux/usb/charger.h b/include/uapi/linux/usb/charger.h new file mode 100644 index 000000000000..5f72af35b3ed --- /dev/null +++ b/include/uapi/linux/usb/charger.h @@ -0,0 +1,31 @@ +/* + * This file defines the USB charger type and state that are needed for + * USB device APIs. + */ + +#ifndef _UAPI__LINUX_USB_CHARGER_H +#define _UAPI__LINUX_USB_CHARGER_H + +/* + * USB charger type: + * SDP (Standard Downstream Port) + * DCP (Dedicated Charging Port) + * CDP (Charging Downstream Port) + * ACA (Accessory Charger Adapters) + */ +enum usb_charger_type { +	UNKNOWN_TYPE, +	SDP_TYPE, +	DCP_TYPE, +	CDP_TYPE, +	ACA_TYPE, +}; + +/* USB charger state */ +enum usb_charger_state { +	USB_CHARGER_DEFAULT, +	USB_CHARGER_PRESENT, +	USB_CHARGER_ABSENT, +}; + +#endif /* _UAPI__LINUX_USB_CHARGER_H */ diff --git a/tools/usb/usbip/src/usbip_attach.c b/tools/usb/usbip/src/usbip_attach.c index 6e89768ffe30..7f07b2d50f59 100644 --- a/tools/usb/usbip/src/usbip_attach.c +++ b/tools/usb/usbip/src/usbip_attach.c @@ -99,29 +99,34 @@ static int import_device(int sockfd, struct usbip_usb_device *udev)  	rc = usbip_vhci_driver_open();  	if (rc < 0) {  		err("open vhci_driver"); -		return -1; +		goto err_out;  	} -	port = usbip_vhci_get_free_port(speed); -	if (port < 0) { -		err("no free port"); -		usbip_vhci_driver_close(); -		return -1; -	} +	do { +		port = usbip_vhci_get_free_port(speed); +		if (port < 0) { +			err("no free port"); +			goto err_driver_close; +		} -	dbg("got free port %d", port); +		dbg("got free port %d", port); -	rc = usbip_vhci_attach_device(port, sockfd, udev->busnum, -				      udev->devnum, udev->speed); -	if (rc < 0) { -		err("import device"); -		usbip_vhci_driver_close(); -		return -1; -	} +		rc = usbip_vhci_attach_device(port, sockfd, udev->busnum, +					      udev->devnum, udev->speed); +		if (rc < 0 && errno != EBUSY) { +			err("import device"); +			goto err_driver_close; +		} +	} while (rc < 0);  	usbip_vhci_driver_close();  	return port; + +err_driver_close: +	usbip_vhci_driver_close(); +err_out: +	return -1;  }  static int query_import_device(int sockfd, char *busid) |