diff options
193 files changed, 7780 insertions, 4460 deletions
diff --git a/Documentation/devicetree/bindings/phy/brcm,nsp-usb3-phy.txt b/Documentation/devicetree/bindings/phy/brcm,nsp-usb3-phy.txt new file mode 100644 index 000000000000..e68ae5dec9c9 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/brcm,nsp-usb3-phy.txt @@ -0,0 +1,39 @@ +Broadcom USB3 phy binding for northstar plus SoC +The USB3 phy is internal to the SoC and is accessed using mdio interface. + +Required mdio bus properties: +- reg: Should be 0x0 for SoC internal USB3 phy +- #address-cells: must be 1 +- #size-cells: must be 0 + +Required USB3 PHY properties: +- compatible: should be "brcm,nsp-usb3-phy" +- reg: USB3 Phy address on SoC internal MDIO bus and it should be 0x10. +- usb3-ctrl-syscon: handler of syscon node defining physical address + of usb3 control register. +- #phy-cells: must be 0 + +Required usb3 control properties: +- compatible: should be "brcm,nsp-usb3-ctrl" +- reg: offset and length of the control registers + +Example: + + mdio@0 { + reg = <0x0>; + #address-cells = <1>; + #size-cells = <0>; + + usb3_phy: usb-phy@10 { + compatible = "brcm,nsp-usb3-phy"; + reg = <0x10>; + usb3-ctrl-syscon = <&usb3_ctrl>; + #phy-cells = <0>; + status = "disabled"; + }; + }; + + usb3_ctrl: syscon@104408 { + compatible = "brcm,nsp-usb3-ctrl", "syscon"; + reg = <0x104408 0x3fc>; + }; diff --git a/Documentation/devicetree/bindings/phy/qcom,usb-hs-phy.txt b/Documentation/devicetree/bindings/phy/qcom,usb-hs-phy.txt new file mode 100644 index 000000000000..b3b75c1e6285 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/qcom,usb-hs-phy.txt @@ -0,0 +1,84 @@ +Qualcomm's USB HS PHY + +PROPERTIES + +- compatible: + Usage: required + Value type: <string> + Definition: Should contain "qcom,usb-hs-phy" and more specifically one of the + following: + + "qcom,usb-hs-phy-apq8064" + "qcom,usb-hs-phy-msm8916" + "qcom,usb-hs-phy-msm8974" + +- #phy-cells: + Usage: required + Value type: <u32> + Definition: Should contain 0 + +- clocks: + Usage: required + Value type: <prop-encoded-array> + Definition: Should contain clock specifier for the reference and sleep + clocks + +- clock-names: + Usage: required + Value type: <stringlist> + Definition: Should contain "ref" and "sleep" for the reference and sleep + clocks respectively + +- resets: + Usage: required + Value type: <prop-encoded-array> + Definition: Should contain the phy and POR resets + +- reset-names: + Usage: required + Value type: <stringlist> + Definition: Should contain "phy" and "por" for the phy and POR resets + respectively + +- v3p3-supply: + Usage: required + Value type: <phandle> + Definition: Should contain a reference to the 3.3V supply + +- v1p8-supply: + Usage: required + Value type: <phandle> + Definition: Should contain a reference to the 1.8V supply + +- extcon: + Usage: optional + Value type: <prop-encoded-array> + Definition: Should contain the vbus extcon + +- qcom,init-seq: + Usage: optional + Value type: <u8 array> + Definition: Should contain a sequence of ULPI address and value pairs to + program into the ULPI_EXT_VENDOR_SPECIFIC area. This is related + to Device Mode Eye Diagram test. The addresses are offsets + from the ULPI_EXT_VENDOR_SPECIFIC address, for example, + <0x1 0x53> would mean "write the value 0x53 to address 0x81". + +EXAMPLE + +otg: usb-controller { + ulpi { + phy { + compatible = "qcom,usb-hs-phy-msm8974", "qcom,usb-hs-phy"; + #phy-cells = <0>; + clocks = <&xo_board>, <&gcc GCC_USB2A_PHY_SLEEP_CLK>; + clock-names = "ref", "sleep"; + resets = <&gcc GCC_USB2A_PHY_BCR>, <&otg 0>; + reset-names = "phy", "por"; + v3p3-supply = <&pm8941_l24>; + v1p8-supply = <&pm8941_l6>; + extcon = <&smbb>; + qcom,init-seq = /bits/ 8 <0x1 0x63>; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/phy/qcom,usb-hsic-phy.txt b/Documentation/devicetree/bindings/phy/qcom,usb-hsic-phy.txt new file mode 100644 index 000000000000..3c7cb2be4b12 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/qcom,usb-hsic-phy.txt @@ -0,0 +1,65 @@ +Qualcomm's USB HSIC PHY + +PROPERTIES + +- compatible: + Usage: required + Value type: <string> + Definition: Should contain "qcom,usb-hsic-phy" and more specifically one of the + following: + + "qcom,usb-hsic-phy-mdm9615" + "qcom,usb-hsic-phy-msm8974" + +- #phy-cells: + Usage: required + Value type: <u32> + Definition: Should contain 0 + +- clocks: + Usage: required + Value type: <prop-encoded-array> + Definition: Should contain clock specifier for phy, calibration and + a calibration sleep clock + +- clock-names: + Usage: required + Value type: <stringlist> + Definition: Should contain "phy, "cal" and "cal_sleep" + +- pinctrl-names: + Usage: required + Value type: <stringlist> + Definition: Should contain "init" and "default" in that order + +- pinctrl-0: + Usage: required + Value type: <prop-encoded-array> + Definition: List of pinctrl settings to apply to keep HSIC pins in a glitch + free state + +- pinctrl-1: + Usage: required + Value type: <prop-encoded-array> + Definition: List of pinctrl settings to apply to mux out the HSIC pins + +EXAMPLE + +usb-controller { + ulpi { + phy { + compatible = "qcom,usb-hsic-phy-msm8974", + "qcom,usb-hsic-phy"; + #phy-cells = <0>; + pinctrl-names = "init", "default"; + pinctrl-0 = <&hsic_sleep>; + pinctrl-1 = <&hsic_default>; + clocks = <&gcc GCC_USB_HSIC_CLK>, + <&gcc GCC_USB_HSIC_IO_CAL_CLK>, + <&gcc GCC_USB_HSIC_IO_CAL_SLEEP_CLK>; + clock-names = "phy", "cal", "cal_sleep"; + assigned-clocks = <&gcc GCC_USB_HSIC_IO_CAL_CLK>; + assigned-clock-rates = <960000>; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt index 287150db6db4..e42334258185 100644 --- a/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt +++ b/Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt @@ -10,6 +10,7 @@ Required properties: * allwinner,sun8i-a23-usb-phy * allwinner,sun8i-a33-usb-phy * allwinner,sun8i-h3-usb-phy + * allwinner,sun8i-v3s-usb-phy * allwinner,sun50i-a64-usb-phy - reg : a list of offset + length pairs - reg-names : diff --git a/Documentation/devicetree/bindings/ufs/ufs-qcom.txt b/Documentation/devicetree/bindings/ufs/ufs-qcom.txt index b6b5130e5f65..1f69ee1a61ea 100644 --- a/Documentation/devicetree/bindings/ufs/ufs-qcom.txt +++ b/Documentation/devicetree/bindings/ufs/ufs-qcom.txt @@ -29,7 +29,6 @@ Optional properties: - vdda-pll-max-microamp : specifies max. load that can be drawn from pll supply - vddp-ref-clk-supply : phandle to UFS device ref_clk pad power supply - vddp-ref-clk-max-microamp : specifies max. load that can be drawn from this supply -- vddp-ref-clk-always-on : specifies if this supply needs to be kept always on Example: diff --git a/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt index 862cd7c79805..d9b42da016f3 100644 --- a/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt +++ b/Documentation/devicetree/bindings/usb/allwinner,sun4i-a10-musb.txt @@ -2,8 +2,8 @@ Allwinner sun4i A10 musb DRC/OTG controller ------------------------------------------- Required properties: - - compatible : "allwinner,sun4i-a10-musb", "allwinner,sun6i-a31-musb" - or "allwinner,sun8i-a33-musb" + - compatible : "allwinner,sun4i-a10-musb", "allwinner,sun6i-a31-musb", + "allwinner,sun8i-a33-musb" or "allwinner,sun8i-h3-musb" - reg : mmio address range of the musb controller - clocks : clock specifier for the musb controller ahb gate clock - reset : reset specifier for the ahb reset (A31 and newer only) diff --git a/Documentation/devicetree/bindings/usb/dwc3-st.txt b/Documentation/devicetree/bindings/usb/dwc3-st.txt index 01c71b1258f4..50dee3b44665 100644 --- a/Documentation/devicetree/bindings/usb/dwc3-st.txt +++ b/Documentation/devicetree/bindings/usb/dwc3-st.txt @@ -20,10 +20,10 @@ See: Documentation/devicetree/bindings/reset/reset.txt with 'reg' property - pinctl-names : A pinctrl state named "default" must be defined -See: Documentation/devicetree/bindings/pinctrl/pinctrl-binding.txt +See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt - pinctrl-0 : Pin control group -See: Documentation/devicetree/bindings/pinctrl/pinctrl-binding.txt +See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt - ranges : allows valid 1:1 translation between child's address space and parent's address space diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt index e3e6983288e3..f658f394c2d3 100644 --- a/Documentation/devicetree/bindings/usb/dwc3.txt +++ b/Documentation/devicetree/bindings/usb/dwc3.txt @@ -56,6 +56,10 @@ Optional properties: - <DEPRECATED> tx-fifo-resize: determines if the FIFO *has* to be reallocated. + - in addition all properties from usb-xhci.txt from the current directory are + supported as well + + This is usually a subnode to DWC3 glue to which it is connected. dwc3@4a030000 { diff --git a/Documentation/devicetree/bindings/usb/ehci-st.txt b/Documentation/devicetree/bindings/usb/ehci-st.txt index fb45fa5770bb..410d922cfdd7 100644 --- a/Documentation/devicetree/bindings/usb/ehci-st.txt +++ b/Documentation/devicetree/bindings/usb/ehci-st.txt @@ -7,7 +7,7 @@ Required properties: - interrupts : one EHCI interrupt should be described here - pinctrl-names : a pinctrl state named "default" must be defined - pinctrl-0 : phandle referencing pin configuration of the USB controller -See: Documentation/devicetree/bindings/pinctrl/pinctrl-binding.txt +See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt - clocks : phandle list of usb clocks - clock-names : should be "ic" for interconnect clock and "clk48" See: Documentation/devicetree/bindings/clock/clock-bindings.txt diff --git a/Documentation/devicetree/bindings/usb/mt8173-mtu3.txt b/Documentation/devicetree/bindings/usb/mt8173-mtu3.txt index e049d199bf0d..1d7c3bc677f7 100644 --- a/Documentation/devicetree/bindings/usb/mt8173-mtu3.txt +++ b/Documentation/devicetree/bindings/usb/mt8173-mtu3.txt @@ -10,7 +10,7 @@ Required properties: - vusb33-supply : regulator of USB avdd3.3v - clocks : a list of phandle + clock-specifier pairs, one for each entry in clock-names - - clock-names : must contain "sys_ck" for clock of controller; + - clock-names : must contain "sys_ck" and "ref_ck" for clock of controller; "wakeup_deb_p0" and "wakeup_deb_p1" are optional, they are depends on "mediatek,enable-wakeup" - phys : a list of phandle + phy specifier pairs @@ -30,7 +30,7 @@ Optional properties: "id_float" and "id_ground" are optinal which depends on "mediatek,enable-manual-drd" - pinctrl-0 : pin control group - See: Documentation/devicetree/bindings/pinctrl/pinctrl-binding.txt + See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt - maximum-speed : valid arguments are "super-speed", "high-speed" and "full-speed"; refer to usb/generic.txt @@ -56,10 +56,10 @@ ssusb: usb@11271000 { phys = <&phy_port0 PHY_TYPE_USB3>, <&phy_port1 PHY_TYPE_USB2>; power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>; - clocks = <&topckgen CLK_TOP_USB30_SEL>, + clocks = <&topckgen CLK_TOP_USB30_SEL>, <&clk26m>, <&pericfg CLK_PERI_USB0>, <&pericfg CLK_PERI_USB1>; - clock-names = "sys_ck", + clock-names = "sys_ck", "ref_ck", "wakeup_deb_p0", "wakeup_deb_p1"; vusb33-supply = <&mt6397_vusb_reg>; @@ -79,8 +79,8 @@ ssusb: usb@11271000 { reg-names = "mac"; interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_LOW>; power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>; - clocks = <&topckgen CLK_TOP_USB30_SEL>; - clock-names = "sys_ck"; + clocks = <&topckgen CLK_TOP_USB30_SEL>, <&clk26m>; + clock-names = "sys_ck", "ref_ck"; vusb33-supply = <&mt6397_vusb_reg>; status = "disabled"; }; diff --git a/Documentation/devicetree/bindings/usb/mt8173-xhci.txt b/Documentation/devicetree/bindings/usb/mt8173-xhci.txt index 2a930bd52b94..0acfc8acbea1 100644 --- a/Documentation/devicetree/bindings/usb/mt8173-xhci.txt +++ b/Documentation/devicetree/bindings/usb/mt8173-xhci.txt @@ -23,6 +23,7 @@ Required properties: entry in clock-names - clock-names : must contain "sys_ck": for clock of xHCI MAC + "ref_ck": for reference clock of xHCI MAC "wakeup_deb_p0": for USB wakeup debounce clock of port0 "wakeup_deb_p1": for USB wakeup debounce clock of port1 @@ -37,7 +38,7 @@ Optional properties: - usb3-lpm-capable : supports USB3.0 LPM - pinctrl-names : a pinctrl state named "default" must be defined - pinctrl-0 : pin control group - See: Documentation/devicetree/bindings/pinctrl/pinctrl-binding.txt + See: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt Example: usb30: usb@11270000 { @@ -47,10 +48,10 @@ usb30: usb@11270000 { reg-names = "mac", "ippc"; interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_LOW>; power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>; - clocks = <&topckgen CLK_TOP_USB30_SEL>, + clocks = <&topckgen CLK_TOP_USB30_SEL>, <&clk26m>, <&pericfg CLK_PERI_USB0>, <&pericfg CLK_PERI_USB1>; - clock-names = "sys_ck", + clock-names = "sys_ck", "ref_ck", "wakeup_deb_p0", "wakeup_deb_p1"; phys = <&phy_port0 PHY_TYPE_USB3>, @@ -67,7 +68,7 @@ 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/mtu3.txt +Documentation/devicetree/bindings/usb/mt8173-mtu3.txt Required properties: - compatible : should contain "mediatek,mt8173-xhci" @@ -82,6 +83,7 @@ Required properties: entry in clock-names - clock-names : must be "sys_ck": for clock of xHCI MAC + "ref_ck": for reference clock of xHCI MAC Optional properties: - vbus-supply : reference to the VBUS regulator; @@ -94,8 +96,8 @@ usb30: usb@11270000 { reg-names = "mac"; interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_LOW>; power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>; - clocks = <&topckgen CLK_TOP_USB30_SEL>; - clock-names = "sys_ck"; + clocks = <&topckgen CLK_TOP_USB30_SEL>, <&clk26m>; + clock-names = "sys_ck", "ref_ck"; vusb33-supply = <&mt6397_vusb_reg>; usb3-lpm-capable; }; diff --git a/Documentation/devicetree/bindings/usb/qcom,dwc3.txt b/Documentation/devicetree/bindings/usb/qcom,dwc3.txt index 39acb084bce9..73cc0963e823 100644 --- a/Documentation/devicetree/bindings/usb/qcom,dwc3.txt +++ b/Documentation/devicetree/bindings/usb/qcom,dwc3.txt @@ -18,7 +18,7 @@ A child node must exist to represent the core DWC3 IP block. The name of the node is not important. The content of the node is defined in dwc3.txt. Phy documentation is provided in the following places: -Documentation/devicetree/bindings/phy/qcom,dwc3-usb-phy.txt +Documentation/devicetree/bindings/phy/qcom-dwc3-usb-phy.txt Example device nodes: diff --git a/Documentation/devicetree/bindings/usb/ulpi.txt b/Documentation/devicetree/bindings/usb/ulpi.txt new file mode 100644 index 000000000000..ca179dc4bd50 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/ulpi.txt @@ -0,0 +1,20 @@ +ULPI bus binding +---------------- + +Phys that are behind a ULPI connection can be described with the following +binding. The host controller shall have a "ulpi" named node as a child, and +that node shall have one enabled node underneath it representing the ulpi +device on the bus. + +EXAMPLE +------- + +usb { + compatible = "vendor,usb-controller"; + + ulpi { + phy { + compatible = "vendor,phy"; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/usb/usb-xhci.txt b/Documentation/devicetree/bindings/usb/usb-xhci.txt index 0b7d8576001c..2d80b60eeabe 100644 --- a/Documentation/devicetree/bindings/usb/usb-xhci.txt +++ b/Documentation/devicetree/bindings/usb/usb-xhci.txt @@ -27,6 +27,7 @@ Required properties: Optional properties: - clocks: reference to a clock - usb3-lpm-capable: determines if platform is USB3 LPM capable + - quirk-broken-port-ped: set if the controller has broken port disable mechanism Example: usb@f0931000 { diff --git a/Documentation/devicetree/bindings/usb/usb251xb.txt b/Documentation/devicetree/bindings/usb/usb251xb.txt new file mode 100644 index 000000000000..0c065f77658f --- /dev/null +++ b/Documentation/devicetree/bindings/usb/usb251xb.txt @@ -0,0 +1,83 @@ +Microchip USB 2.0 Hi-Speed Hub Controller + +The device node for the configuration of a Microchip USB251xB/xBi USB 2.0 +Hi-Speed Controller. + +Required properties : + - compatible : Should be "microchip,usb251xb" or one of the specific types: + "microchip,usb2512b", "microchip,usb2512bi", "microchip,usb2513b", + "microchip,usb2513bi", "microchip,usb2514b", "microchip,usb2514bi" + - hub-reset-gpios : Should specify the gpio for hub reset + +Optional properties : + - reg : I2C address on the selected bus (default is <0x2C>) + - skip-config : Skip Hub configuration, but only send the USB-Attach command + - vendor-id : USB Vendor ID of the hub (16 bit, default is 0x0424) + - product-id : USB Product ID of the hub (16 bit, default depends on type) + - device-id : USB Device ID of the hub (16 bit, default is 0x0bb3) + - language-id : USB Language ID (16 bit, default is 0x0000) + - manufacturer : USB Manufacturer string (max 31 characters long) + - product : USB Product string (max 31 characters long) + - serial : USB Serial string (max 31 characters long) + - {bus,self}-powered : selects between self- and bus-powered operation (default + is self-powered) + - disable-hi-speed : disable USB Hi-Speed support + - {multi,single}-tt : selects between multi- and single-transaction-translator + (default is multi-tt) + - disable-eop : disable End of Packet generation in full-speed mode + - {ganged,individual}-sensing : select over-current sense type in self-powered + mode (default is individual) + - {ganged,individual}-port-switching : select port power switching mode + (default is individual) + - dynamic-power-switching : enable auto-switching from self- to bus-powered + operation if the local power source is removed or unavailable + - oc-delay-{100us,4ms,8ms,16ms} : set over current timer delay (default is 8ms) + - compound-device : indicated the hub is part of a compound device + - port-mapping-mode : enable port mapping mode + - string-support : enable string descriptor support (required for manufacturer, + product and serial string configuration) + - non-removable-ports : Should specify the ports which have a non-removable + device connected. + - sp-disabled-ports : Specifies the ports which will be self-power disabled + - bp-disabled-ports : Specifies the ports which will be bus-power disabled + - max-sp-power : Specifies the maximum current the hub consumes from an + upstream port when operating as self-powered hub including the power + consumption of a permanently attached peripheral if the hub is + configured as a compound device. The value is given in mA in a 0 - 500 + range (default is 2). + - max-bp-power : Specifies the maximum current the hub consumes from an + upstream port when operating as bus-powered hub including the power + consumption of a permanently attached peripheral if the hub is + configured as a compound device. The value is given in mA in a 0 - 500 + range (default is 100). + - max-sp-current : Specifies the maximum current the hub consumes from an + upstream port when operating as self-powered hub EXCLUDING the power + consumption of a permanently attached peripheral if the hub is + configured as a compound device. The value is given in mA in a 0 - 500 + range (default is 2). + - max-bp-current : Specifies the maximum current the hub consumes from an + upstream port when operating as bus-powered hub EXCLUDING the power + consumption of a permanently attached peripheral if the hub is + configured as a compound device. The value is given in mA in a 0 - 500 + range (default is 100). + - power-on-time : Specifies the time it takes from the time the host initiates + the power-on sequence to a port until the port has adequate power. The + value is given in ms in a 0 - 510 range (default is 100ms). + +Examples: + usb2512b@2c { + compatible = "microchip,usb2512b"; + hub-reset-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>; + }; + + usb2514b@2c { + compatible = "microchip,usb2514b"; + reg = <0x2c>; + reset-gpios = <&gpio1 4 GPIO_ACTIVE_LOW>; + vendor-id = /bits/ 16 <0x0000>; + product-id = /bits/ 16 <0x0000>; + string-support; + manufacturer = "Foo"; + product = "Foo-Bar"; + serial = "1234567890A"; + }; diff --git a/Documentation/usb/gadget-testing.txt b/Documentation/usb/gadget-testing.txt index 581960574889..fb0cc4df1765 100644 --- a/Documentation/usb/gadget-testing.txt +++ b/Documentation/usb/gadget-testing.txt @@ -632,6 +632,8 @@ The uac2 function provides these attributes in its function directory: p_chmask - playback channel mask p_srate - playback sampling rate p_ssize - playback sample size (bytes) + req_number - the number of pre-allocated request for both capture + and playback The attributes have sane default values. diff --git a/MAINTAINERS b/MAINTAINERS index 2d79f8fcb265..d6e91e96f4e5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8233,6 +8233,14 @@ F: drivers/media/platform/atmel/atmel-isc.c F: drivers/media/platform/atmel/atmel-isc-regs.h F: devicetree/bindings/media/atmel-isc.txt +MICROCHIP USB251XB DRIVER +M: Richard Leitner <richard.leitner@skidata.com> +L: linux-usb@vger.kernel.org +S: Maintained +F: drivers/usb/misc/usb251xb.c +F: include/linux/platform_data/usb251xb.h +F: Documentation/devicetree/bindings/usb/usb251xb.txt + MICROSOFT SURFACE PRO 3 BUTTON DRIVER M: Chen Yu <yu.c.chen@intel.com> L: platform-driver-x86@vger.kernel.org diff --git a/arch/arm64/boot/dts/mediatek/mt8173.dtsi b/arch/arm64/boot/dts/mediatek/mt8173.dtsi index 12e702771f5c..40a02b29213e 100644 --- a/arch/arm64/boot/dts/mediatek/mt8173.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8173.dtsi @@ -728,9 +728,11 @@ <&phy_port1 PHY_TYPE_USB2>; power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>; clocks = <&topckgen CLK_TOP_USB30_SEL>, + <&clk26m>, <&pericfg CLK_PERI_USB0>, <&pericfg CLK_PERI_USB1>; clock-names = "sys_ck", + "ref_ck", "wakeup_deb_p0", "wakeup_deb_p1"; mediatek,syscon-wakeup = <&pericfg>; @@ -745,8 +747,8 @@ reg-names = "mac"; interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_LOW>; power-domains = <&scpsys MT8173_POWER_DOMAIN_USB>; - clocks = <&topckgen CLK_TOP_USB30_SEL>; - clock-names = "sys_ck"; + clocks = <&topckgen CLK_TOP_USB30_SEL>, <&clk26m>; + clock-names = "sys_ck", "ref_ck"; status = "disabled"; }; }; diff --git a/drivers/dma/cppi41.c b/drivers/dma/cppi41.c index 200828c60db9..d74cee077842 100644 --- a/drivers/dma/cppi41.c +++ b/drivers/dma/cppi41.c @@ -79,14 +79,6 @@ #define QMGR_QUEUE_C(n) (0x2008 + (n) * 0x10) #define QMGR_QUEUE_D(n) (0x200c + (n) * 0x10) -/* Glue layer specific */ -/* USBSS / USB AM335x */ -#define USBSS_IRQ_STATUS 0x28 -#define USBSS_IRQ_ENABLER 0x2c -#define USBSS_IRQ_CLEARR 0x30 - -#define USBSS_IRQ_PD_COMP (1 << 2) - /* Packet Descriptor */ #define PD2_ZERO_LENGTH (1 << 19) @@ -294,14 +286,8 @@ static irqreturn_t cppi41_irq(int irq, void *data) { struct cppi41_dd *cdd = data; struct cppi41_channel *c; - u32 status; int i; - status = cppi_readl(cdd->usbss_mem + USBSS_IRQ_STATUS); - if (!(status & USBSS_IRQ_PD_COMP)) - return IRQ_NONE; - cppi_writel(status, cdd->usbss_mem + USBSS_IRQ_STATUS); - for (i = QMGR_PENDING_SLOT_Q(FIST_COMPLETION_QUEUE); i < QMGR_NUM_PEND; i++) { u32 val; @@ -618,6 +604,7 @@ static void cppi41_compute_td_desc(struct cppi41_desc *d) static int cppi41_tear_down_chan(struct cppi41_channel *c) { + struct dmaengine_result abort_result; struct cppi41_dd *cdd = c->cdd; struct cppi41_desc *td; u32 reg; @@ -701,6 +688,12 @@ static int cppi41_tear_down_chan(struct cppi41_channel *c) c->td_seen = 0; c->td_desc_seen = 0; cppi_writel(0, c->gcr_reg); + + /* Invoke the callback to do the necessary clean-up */ + abort_result.result = DMA_TRANS_ABORTED; + dma_cookie_complete(&c->txd); + dmaengine_desc_get_callback_invoke(&c->txd, &abort_result); + return 0; } @@ -1066,8 +1059,6 @@ static int cppi41_dma_probe(struct platform_device *pdev) goto err_irq; } - cppi_writel(USBSS_IRQ_PD_COMP, cdd->usbss_mem + USBSS_IRQ_ENABLER); - ret = devm_request_irq(&pdev->dev, irq, glue_info->isr, IRQF_SHARED, dev_name(dev), cdd); if (ret) @@ -1091,7 +1082,6 @@ err_of: dma_async_device_unregister(&cdd->ddev); err_dma_reg: err_irq: - cppi_writel(0, cdd->usbss_mem + USBSS_IRQ_CLEARR); cleanup_chans(cdd); err_chans: deinit_cppi41(dev, cdd); @@ -1119,7 +1109,6 @@ static int cppi41_dma_remove(struct platform_device *pdev) of_dma_controller_free(pdev->dev.of_node); dma_async_device_unregister(&cdd->ddev); - cppi_writel(0, cdd->usbss_mem + USBSS_IRQ_CLEARR); devm_free_irq(&pdev->dev, cdd->irq, cdd); cleanup_chans(cdd); deinit_cppi41(&pdev->dev, cdd); @@ -1138,7 +1127,6 @@ static int __maybe_unused cppi41_suspend(struct device *dev) struct cppi41_dd *cdd = dev_get_drvdata(dev); cdd->dma_tdfdq = cppi_readl(cdd->ctrl_mem + DMA_TDFDQ); - cppi_writel(0, cdd->usbss_mem + USBSS_IRQ_CLEARR); disable_sched(cdd); return 0; @@ -1164,8 +1152,6 @@ static int __maybe_unused cppi41_resume(struct device *dev) cppi_writel(QMGR_SCRATCH_SIZE, cdd->qmgr_mem + QMGR_LRAM_SIZE); cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM1_BASE); - cppi_writel(USBSS_IRQ_PD_COMP, cdd->usbss_mem + USBSS_IRQ_ENABLER); - return 0; } diff --git a/drivers/of/device.c b/drivers/of/device.c index fd5cfad7c403..b1e6bebda3f3 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -225,6 +225,30 @@ ssize_t of_device_get_modalias(struct device *dev, char *str, ssize_t len) return tsize; } +EXPORT_SYMBOL_GPL(of_device_get_modalias); + +int of_device_request_module(struct device *dev) +{ + char *str; + ssize_t size; + int ret; + + size = of_device_get_modalias(dev, NULL, 0); + if (size < 0) + return size; + + str = kmalloc(size + 1, GFP_KERNEL); + if (!str) + return -ENOMEM; + + of_device_get_modalias(dev, str, size); + str[size] = '\0'; + ret = request_module(str); + kfree(str); + + return ret; +} +EXPORT_SYMBOL_GPL(of_device_request_module); /** * of_device_uevent - Display OF related uevent information @@ -287,3 +311,4 @@ int of_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env) return 0; } +EXPORT_SYMBOL_GPL(of_device_uevent_modalias); diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index e8eb7f225a88..bb5cf6f49b06 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -363,6 +363,7 @@ config PHY_ROCKCHIP_INNO_USB2 tristate "Rockchip INNO USB2PHY Driver" depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF depends on COMMON_CLK + depends on EXTCON depends on USB_SUPPORT select GENERIC_PHY select USB_COMMON @@ -437,6 +438,21 @@ config PHY_QCOM_UFS help Support for UFS PHY on QCOM chipsets. +config PHY_QCOM_USB_HS + tristate "Qualcomm USB HS PHY module" + depends on USB_ULPI_BUS + select GENERIC_PHY + help + Support for the USB high-speed ULPI compliant phy on Qualcomm + chipsets. + +config PHY_QCOM_USB_HSIC + tristate "Qualcomm USB HSIC ULPI PHY module" + depends on USB_ULPI_BUS + select GENERIC_PHY + help + Support for the USB HSIC ULPI compliant PHY on QCOM chipsets. + config PHY_TUSB1210 tristate "TI TUSB1210 ULPI PHY module" depends on USB_ULPI_BUS @@ -486,4 +502,12 @@ config PHY_MESON8B_USB2 and GXBB SoCs. If unsure, say N. +config PHY_NSP_USB3 + tristate "Broadcom NorthStar plus USB3 PHY driver" + depends on OF && (ARCH_BCM_NSP || COMPILE_TEST) + select GENERIC_PHY + default ARCH_BCM_NSP + help + Enable this to support the Broadcom Northstar plus USB3 PHY. + If unsure, say N. endmenu diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 65eb2f436a41..9f008004f75d 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -52,6 +52,8 @@ obj-$(CONFIG_PHY_STIH407_USB) += phy-stih407-usb.o obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o +obj-$(CONFIG_PHY_QCOM_USB_HS) += phy-qcom-usb-hs.o +obj-$(CONFIG_PHY_QCOM_USB_HSIC) += phy-qcom-usb-hsic.o obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o obj-$(CONFIG_PHY_BRCM_SATA) += phy-brcm-sata.o obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o @@ -59,3 +61,4 @@ obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o obj-$(CONFIG_ARCH_TEGRA) += tegra/ obj-$(CONFIG_PHY_NS2_PCIE) += phy-bcm-ns2-pcie.o obj-$(CONFIG_PHY_MESON8B_USB2) += phy-meson8b-usb2.o +obj-$(CONFIG_PHY_NSP_USB3) += phy-bcm-nsp-usb3.o diff --git a/drivers/phy/phy-bcm-cygnus-pcie.c b/drivers/phy/phy-bcm-cygnus-pcie.c index 082c03f6438f..0f4ac5d63cff 100644 --- a/drivers/phy/phy-bcm-cygnus-pcie.c +++ b/drivers/phy/phy-bcm-cygnus-pcie.c @@ -114,7 +114,7 @@ static int cygnus_pcie_phy_power_off(struct phy *p) return cygnus_pcie_power_config(phy, false); } -static struct phy_ops cygnus_pcie_phy_ops = { +static const struct phy_ops cygnus_pcie_phy_ops = { .power_on = cygnus_pcie_phy_power_on, .power_off = cygnus_pcie_phy_power_off, .owner = THIS_MODULE, diff --git a/drivers/phy/phy-bcm-nsp-usb3.c b/drivers/phy/phy-bcm-nsp-usb3.c new file mode 100644 index 000000000000..49024eaa5545 --- /dev/null +++ b/drivers/phy/phy-bcm-nsp-usb3.c @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2016 Broadcom + * + * 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 version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; 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/io.h> +#include <linux/kernel.h> +#include <linux/mfd/syscon.h> +#include <linux/mdio.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/phy/phy.h> +#include <linux/regmap.h> + +#define NSP_USB3_RST_CTRL_OFFSET 0x3f8 + +/* mdio reg access */ +#define NSP_USB3_PHY_BASE_ADDR_REG 0x1f + +#define NSP_USB3_PHY_PLL30_BLOCK 0x8000 +#define NSP_USB3_PLL_CONTROL 0x01 +#define NSP_USB3_PLLA_CONTROL0 0x0a +#define NSP_USB3_PLLA_CONTROL1 0x0b + +#define NSP_USB3_PHY_TX_PMD_BLOCK 0x8040 +#define NSP_USB3_TX_PMD_CONTROL1 0x01 + +#define NSP_USB3_PHY_PIPE_BLOCK 0x8060 +#define NSP_USB3_LFPS_CMP 0x02 +#define NSP_USB3_LFPS_DEGLITCH 0x03 + +struct nsp_usb3_phy { + struct regmap *usb3_ctrl; + struct phy *phy; + struct mdio_device *mdiodev; +}; + +static int nsp_usb3_phy_init(struct phy *phy) +{ + struct nsp_usb3_phy *iphy = phy_get_drvdata(phy); + struct mii_bus *bus = iphy->mdiodev->bus; + int addr = iphy->mdiodev->addr; + u32 data; + int rc; + + rc = regmap_read(iphy->usb3_ctrl, 0, &data); + if (rc) + return rc; + data |= 1; + rc = regmap_write(iphy->usb3_ctrl, 0, data); + if (rc) + return rc; + + rc = regmap_write(iphy->usb3_ctrl, NSP_USB3_RST_CTRL_OFFSET, 1); + if (rc) + return rc; + + rc = mdiobus_write(bus, addr, NSP_USB3_PHY_BASE_ADDR_REG, + NSP_USB3_PHY_PLL30_BLOCK); + if (rc) + return rc; + + rc = mdiobus_write(bus, addr, NSP_USB3_PLL_CONTROL, 0x1000); + if (rc) + return rc; + + rc = mdiobus_write(bus, addr, NSP_USB3_PLLA_CONTROL0, 0x6400); + if (rc) + return rc; + + rc = mdiobus_write(bus, addr, NSP_USB3_PLLA_CONTROL1, 0xc000); + if (rc) + return rc; + + rc = mdiobus_write(bus, addr, NSP_USB3_PLLA_CONTROL1, 0x8000); + if (rc) + return rc; + + rc = regmap_write(iphy->usb3_ctrl, NSP_USB3_RST_CTRL_OFFSET, 0); + if (rc) + return rc; + + rc = mdiobus_write(bus, addr, NSP_USB3_PLL_CONTROL, 0x9000); + if (rc) + return rc; + + rc = mdiobus_write(bus, addr, NSP_USB3_PHY_BASE_ADDR_REG, + NSP_USB3_PHY_PIPE_BLOCK); + if (rc) + return rc; + + rc = mdiobus_write(bus, addr, NSP_USB3_LFPS_CMP, 0xf30d); + if (rc) + return rc; + + rc = mdiobus_write(bus, addr, NSP_USB3_LFPS_DEGLITCH, 0x6302); + if (rc) + return rc; + + rc = mdiobus_write(bus, addr, NSP_USB3_PHY_BASE_ADDR_REG, + NSP_USB3_PHY_TX_PMD_BLOCK); + if (rc) + return rc; + + rc = mdiobus_write(bus, addr, NSP_USB3_TX_PMD_CONTROL1, 0x1003); + + return rc; +} + +static struct phy_ops nsp_usb3_phy_ops = { + .init = nsp_usb3_phy_init, + .owner = THIS_MODULE, +}; + +static int nsp_usb3_phy_probe(struct mdio_device *mdiodev) +{ + struct device *dev = &mdiodev->dev; + struct phy_provider *provider; + struct nsp_usb3_phy *iphy; + + iphy = devm_kzalloc(dev, sizeof(*iphy), GFP_KERNEL); + if (!iphy) + return -ENOMEM; + iphy->mdiodev = mdiodev; + + iphy->usb3_ctrl = syscon_regmap_lookup_by_phandle(dev->of_node, + "usb3-ctrl-syscon"); + if (IS_ERR(iphy->usb3_ctrl)) + return PTR_ERR(iphy->usb3_ctrl); + + iphy->phy = devm_phy_create(dev, dev->of_node, &nsp_usb3_phy_ops); + if (IS_ERR(iphy->phy)) { + dev_err(dev, "failed to create PHY\n"); + return PTR_ERR(iphy->phy); + } + + phy_set_drvdata(iphy->phy, iphy); + + provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (IS_ERR(provider)) { + dev_err(dev, "could not register PHY provider\n"); + return PTR_ERR(provider); + } + + return 0; +} + +static const struct of_device_id nsp_usb3_phy_of_match[] = { + {.compatible = "brcm,nsp-usb3-phy",}, + { /* sentinel */ } +}; + +static struct mdio_driver nsp_usb3_phy_driver = { + .mdiodrv = { + .driver = { + .name = "nsp-usb3-phy", + .of_match_table = nsp_usb3_phy_of_match, + }, + }, + .probe = nsp_usb3_phy_probe, +}; + +mdio_module_driver(nsp_usb3_phy_driver); + +MODULE_DESCRIPTION("Broadcom NSP USB3 PHY driver"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Yendapally Reddy Dhananjaya Reddy <yendapally.reddy@broadcom.com"); diff --git a/drivers/phy/phy-hi6220-usb.c b/drivers/phy/phy-hi6220-usb.c index b2141cbd4cf6..398c1021deec 100644 --- a/drivers/phy/phy-hi6220-usb.c +++ b/drivers/phy/phy-hi6220-usb.c @@ -112,7 +112,7 @@ static int hi6220_phy_exit(struct phy *phy) return hi6220_phy_setup(priv, false); } -static struct phy_ops hi6220_phy_ops = { +static const struct phy_ops hi6220_phy_ops = { .init = hi6220_phy_start, .exit = hi6220_phy_exit, .owner = THIS_MODULE, diff --git a/drivers/phy/phy-mt65xx-usb3.c b/drivers/phy/phy-mt65xx-usb3.c index 4d85e730ccab..d9720675b9db 100644 --- a/drivers/phy/phy-mt65xx-usb3.c +++ b/drivers/phy/phy-mt65xx-usb3.c @@ -506,7 +506,7 @@ static struct phy *mt65xx_phy_xlate(struct device *dev, return instance->phy; } -static struct phy_ops mt65xx_u3phy_ops = { +static const struct phy_ops mt65xx_u3phy_ops = { .init = mt65xx_phy_init, .exit = mt65xx_phy_exit, .power_on = mt65xx_phy_power_on, diff --git a/drivers/phy/phy-qcom-ufs-i.h b/drivers/phy/phy-qcom-ufs-i.h index d505d98cf5f8..13b02b7de30b 100644 --- a/drivers/phy/phy-qcom-ufs-i.h +++ b/drivers/phy/phy-qcom-ufs-i.h @@ -77,7 +77,6 @@ struct ufs_qcom_phy_vreg { int min_uV; int max_uV; bool enabled; - bool is_always_on; }; struct ufs_qcom_phy { diff --git a/drivers/phy/phy-qcom-ufs-qmp-14nm.c b/drivers/phy/phy-qcom-ufs-qmp-14nm.c index c71c84734916..12a1b498dc4b 100644 --- a/drivers/phy/phy-qcom-ufs-qmp-14nm.c +++ b/drivers/phy/phy-qcom-ufs-qmp-14nm.c @@ -132,27 +132,18 @@ static int ufs_qcom_phy_qmp_14nm_probe(struct platform_device *pdev) &ufs_qcom_phy_qmp_14nm_phy_ops, &phy_14nm_ops); if (!generic_phy) { - dev_err(dev, "%s: ufs_qcom_phy_generic_probe() failed\n", - __func__); err = -EIO; goto out; } err = ufs_qcom_phy_init_clks(phy_common); - if (err) { - dev_err(phy_common->dev, - "%s: ufs_qcom_phy_init_clks() failed %d\n", - __func__, err); + if (err) goto out; - } err = ufs_qcom_phy_init_vregulators(phy_common); - if (err) { - dev_err(phy_common->dev, - "%s: ufs_qcom_phy_init_vregulators() failed %d\n", - __func__, err); + if (err) goto out; - } + phy_common->vdda_phy.max_uV = UFS_PHY_VDDA_PHY_UV; phy_common->vdda_phy.min_uV = UFS_PHY_VDDA_PHY_UV; diff --git a/drivers/phy/phy-qcom-ufs-qmp-20nm.c b/drivers/phy/phy-qcom-ufs-qmp-20nm.c index 1a26a64e06d3..4f68acb58b73 100644 --- a/drivers/phy/phy-qcom-ufs-qmp-20nm.c +++ b/drivers/phy/phy-qcom-ufs-qmp-20nm.c @@ -190,25 +190,17 @@ static int ufs_qcom_phy_qmp_20nm_probe(struct platform_device *pdev) &ufs_qcom_phy_qmp_20nm_phy_ops, &phy_20nm_ops); if (!generic_phy) { - dev_err(dev, "%s: ufs_qcom_phy_generic_probe() failed\n", - __func__); err = -EIO; goto out; } err = ufs_qcom_phy_init_clks(phy_common); - if (err) { - dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_clks() failed %d\n", - __func__, err); + if (err) goto out; - } err = ufs_qcom_phy_init_vregulators(phy_common); - if (err) { - dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_vregulators() failed %d\n", - __func__, err); + if (err) goto out; - } ufs_qcom_phy_qmp_20nm_advertise_quirks(phy_common); diff --git a/drivers/phy/phy-qcom-ufs.c b/drivers/phy/phy-qcom-ufs.c index c69568b8543d..43865ef340e2 100644 --- a/drivers/phy/phy-qcom-ufs.c +++ b/drivers/phy/phy-qcom-ufs.c @@ -189,12 +189,12 @@ int ufs_qcom_phy_init_clks(struct ufs_qcom_phy *phy_common) if (err) goto out; +skip_txrx_clk: err = ufs_qcom_phy_clk_get(phy_common->dev, "ref_clk_src", &phy_common->ref_clk_src); if (err) goto out; -skip_txrx_clk: /* * "ref_clk_parent" is optional hence don't abort init if it's not * found. @@ -210,25 +210,19 @@ out: } EXPORT_SYMBOL_GPL(ufs_qcom_phy_init_clks); -static int __ufs_qcom_phy_init_vreg(struct device *dev, - struct ufs_qcom_phy_vreg *vreg, const char *name, bool optional) +static int ufs_qcom_phy_init_vreg(struct device *dev, + struct ufs_qcom_phy_vreg *vreg, + const char *name) { int err = 0; char prop_name[MAX_PROP_NAME]; - vreg->name = devm_kstrdup(dev, name, GFP_KERNEL); - if (!vreg->name) { - err = -ENOMEM; - goto out; - } - + vreg->name = name; vreg->reg = devm_regulator_get(dev, name); if (IS_ERR(vreg->reg)) { err = PTR_ERR(vreg->reg); - vreg->reg = NULL; - if (!optional) - dev_err(dev, "failed to get %s, %d\n", name, err); + dev_err(dev, "failed to get %s, %d\n", name, err); goto out; } @@ -248,9 +242,6 @@ static int __ufs_qcom_phy_init_vreg(struct device *dev, } err = 0; } - snprintf(prop_name, MAX_PROP_NAME, "%s-always-on", name); - vreg->is_always_on = of_property_read_bool(dev->of_node, - prop_name); } if (!strcmp(name, "vdda-pll")) { @@ -265,17 +256,9 @@ static int __ufs_qcom_phy_init_vreg(struct device *dev, } out: - if (err) - kfree(vreg->name); return err; } -static int ufs_qcom_phy_init_vreg(struct device *dev, - struct ufs_qcom_phy_vreg *vreg, const char *name) -{ - return __ufs_qcom_phy_init_vreg(dev, vreg, name, false); -} - int ufs_qcom_phy_init_vregulators(struct ufs_qcom_phy *phy_common) { int err; @@ -291,9 +274,9 @@ int ufs_qcom_phy_init_vregulators(struct ufs_qcom_phy *phy_common) if (err) goto out; - /* vddp-ref-clk-* properties are optional */ - __ufs_qcom_phy_init_vreg(phy_common->dev, &phy_common->vddp_ref_clk, - "vddp-ref-clk", true); + err = ufs_qcom_phy_init_vreg(phy_common->dev, &phy_common->vddp_ref_clk, + "vddp-ref-clk"); + out: return err; } @@ -416,7 +399,7 @@ static int ufs_qcom_phy_disable_vreg(struct device *dev, { int ret = 0; - if (!vreg || !vreg->enabled || vreg->is_always_on) + if (!vreg || !vreg->enabled) goto out; ret = regulator_disable(vreg->reg); diff --git a/drivers/phy/phy-qcom-usb-hs.c b/drivers/phy/phy-qcom-usb-hs.c new file mode 100644 index 000000000000..94dfbfd739c3 --- /dev/null +++ b/drivers/phy/phy-qcom-usb-hs.c @@ -0,0 +1,296 @@ +/** + * Copyright (C) 2016 Linaro Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/module.h> +#include <linux/ulpi/driver.h> +#include <linux/ulpi/regs.h> +#include <linux/clk.h> +#include <linux/regulator/consumer.h> +#include <linux/of_device.h> +#include <linux/reset.h> +#include <linux/extcon.h> +#include <linux/notifier.h> + +#include "ulpi_phy.h" + +#define ULPI_PWR_CLK_MNG_REG 0x88 +# define ULPI_PWR_OTG_COMP_DISABLE BIT(0) + +#define ULPI_MISC_A 0x96 +# define ULPI_MISC_A_VBUSVLDEXTSEL BIT(1) +# define ULPI_MISC_A_VBUSVLDEXT BIT(0) + + +struct ulpi_seq { + u8 addr; + u8 val; +}; + +struct qcom_usb_hs_phy { + struct ulpi *ulpi; + struct phy *phy; + struct clk *ref_clk; + struct clk *sleep_clk; + struct regulator *v1p8; + struct regulator *v3p3; + struct reset_control *reset; + struct ulpi_seq *init_seq; + struct extcon_dev *vbus_edev; + struct notifier_block vbus_notify; +}; + +static int qcom_usb_hs_phy_set_mode(struct phy *phy, enum phy_mode mode) +{ + struct qcom_usb_hs_phy *uphy = phy_get_drvdata(phy); + u8 addr; + int ret; + + if (!uphy->vbus_edev) { + u8 val = 0; + + switch (mode) { + case PHY_MODE_USB_OTG: + case PHY_MODE_USB_HOST: + val |= ULPI_INT_IDGRD; + case PHY_MODE_USB_DEVICE: + val |= ULPI_INT_SESS_VALID; + default: + break; + } + + ret = ulpi_write(uphy->ulpi, ULPI_USB_INT_EN_RISE, val); + if (ret) + return ret; + ret = ulpi_write(uphy->ulpi, ULPI_USB_INT_EN_FALL, val); + } else { + switch (mode) { + case PHY_MODE_USB_OTG: + case PHY_MODE_USB_DEVICE: + addr = ULPI_SET(ULPI_MISC_A); + break; + case PHY_MODE_USB_HOST: + addr = ULPI_CLR(ULPI_MISC_A); + break; + default: + return -EINVAL; + } + + ret = ulpi_write(uphy->ulpi, ULPI_SET(ULPI_PWR_CLK_MNG_REG), + ULPI_PWR_OTG_COMP_DISABLE); + if (ret) + return ret; + ret = ulpi_write(uphy->ulpi, addr, ULPI_MISC_A_VBUSVLDEXTSEL); + } + + return ret; +} + +static int +qcom_usb_hs_phy_vbus_notifier(struct notifier_block *nb, unsigned long event, + void *ptr) +{ + struct qcom_usb_hs_phy *uphy; + u8 addr; + + uphy = container_of(nb, struct qcom_usb_hs_phy, vbus_notify); + + if (event) + addr = ULPI_SET(ULPI_MISC_A); + else + addr = ULPI_CLR(ULPI_MISC_A); + + return ulpi_write(uphy->ulpi, addr, ULPI_MISC_A_VBUSVLDEXT); +} + +static int qcom_usb_hs_phy_power_on(struct phy *phy) +{ + struct qcom_usb_hs_phy *uphy = phy_get_drvdata(phy); + struct ulpi *ulpi = uphy->ulpi; + const struct ulpi_seq *seq; + int ret, state; + + ret = clk_prepare_enable(uphy->ref_clk); + if (ret) + return ret; + + ret = clk_prepare_enable(uphy->sleep_clk); + if (ret) + goto err_sleep; + + ret = regulator_set_load(uphy->v1p8, 50000); + if (ret < 0) + goto err_1p8; + + ret = regulator_enable(uphy->v1p8); + if (ret) + goto err_1p8; + + ret = regulator_set_voltage_triplet(uphy->v3p3, 3050000, 3300000, + 3300000); + if (ret) + goto err_3p3; + + ret = regulator_set_load(uphy->v3p3, 50000); + if (ret < 0) + goto err_3p3; + + ret = regulator_enable(uphy->v3p3); + if (ret) + goto err_3p3; + + for (seq = uphy->init_seq; seq->addr; seq++) { + ret = ulpi_write(ulpi, ULPI_EXT_VENDOR_SPECIFIC + seq->addr, + seq->val); + if (ret) + goto err_ulpi; + } + + if (uphy->reset) { + ret = reset_control_reset(uphy->reset); + if (ret) + goto err_ulpi; + } + + if (uphy->vbus_edev) { + state = extcon_get_cable_state_(uphy->vbus_edev, EXTCON_USB); + /* setup initial state */ + qcom_usb_hs_phy_vbus_notifier(&uphy->vbus_notify, state, + uphy->vbus_edev); + ret = extcon_register_notifier(uphy->vbus_edev, EXTCON_USB, + &uphy->vbus_notify); + if (ret) + goto err_ulpi; + } + + return 0; +err_ulpi: + regulator_disable(uphy->v3p3); +err_3p3: + regulator_disable(uphy->v1p8); +err_1p8: + clk_disable_unprepare(uphy->sleep_clk); +err_sleep: + clk_disable_unprepare(uphy->ref_clk); + return ret; +} + +static int qcom_usb_hs_phy_power_off(struct phy *phy) +{ + int ret; + struct qcom_usb_hs_phy *uphy = phy_get_drvdata(phy); + + if (uphy->vbus_edev) { + ret = extcon_unregister_notifier(uphy->vbus_edev, EXTCON_USB, + &uphy->vbus_notify); + if (ret) + return ret; + } + + regulator_disable(uphy->v3p3); + regulator_disable(uphy->v1p8); + clk_disable_unprepare(uphy->sleep_clk); + clk_disable_unprepare(uphy->ref_clk); + + return 0; +} + +static const struct phy_ops qcom_usb_hs_phy_ops = { + .power_on = qcom_usb_hs_phy_power_on, + .power_off = qcom_usb_hs_phy_power_off, + .set_mode = qcom_usb_hs_phy_set_mode, + .owner = THIS_MODULE, +}; + +static int qcom_usb_hs_phy_probe(struct ulpi *ulpi) +{ + struct qcom_usb_hs_phy *uphy; + struct phy_provider *p; + struct clk *clk; + struct regulator *reg; + struct reset_control *reset; + int size; + int ret; + + uphy = devm_kzalloc(&ulpi->dev, sizeof(*uphy), GFP_KERNEL); + if (!uphy) + return -ENOMEM; + ulpi_set_drvdata(ulpi, uphy); + uphy->ulpi = ulpi; + + size = of_property_count_u8_elems(ulpi->dev.of_node, "qcom,init-seq"); + if (size < 0) + size = 0; + uphy->init_seq = devm_kmalloc_array(&ulpi->dev, (size / 2) + 1, + sizeof(*uphy->init_seq), GFP_KERNEL); + if (!uphy->init_seq) + return -ENOMEM; + ret = of_property_read_u8_array(ulpi->dev.of_node, "qcom,init-seq", + (u8 *)uphy->init_seq, size); + if (ret && size) + return ret; + /* NUL terminate */ + uphy->init_seq[size / 2].addr = uphy->init_seq[size / 2].val = 0; + + uphy->ref_clk = clk = devm_clk_get(&ulpi->dev, "ref"); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + uphy->sleep_clk = clk = devm_clk_get(&ulpi->dev, "sleep"); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + uphy->v1p8 = reg = devm_regulator_get(&ulpi->dev, "v1p8"); + if (IS_ERR(reg)) + return PTR_ERR(reg); + + uphy->v3p3 = reg = devm_regulator_get(&ulpi->dev, "v3p3"); + if (IS_ERR(reg)) + return PTR_ERR(reg); + + uphy->reset = reset = devm_reset_control_get(&ulpi->dev, "por"); + if (IS_ERR(reset)) { + if (PTR_ERR(reset) == -EPROBE_DEFER) + return PTR_ERR(reset); + uphy->reset = NULL; + } + + uphy->phy = devm_phy_create(&ulpi->dev, ulpi->dev.of_node, + &qcom_usb_hs_phy_ops); + if (IS_ERR(uphy->phy)) + return PTR_ERR(uphy->phy); + + uphy->vbus_edev = extcon_get_edev_by_phandle(&ulpi->dev, 0); + if (IS_ERR(uphy->vbus_edev)) { + if (PTR_ERR(uphy->vbus_edev) != -ENODEV) + return PTR_ERR(uphy->vbus_edev); + uphy->vbus_edev = NULL; + } + + uphy->vbus_notify.notifier_call = qcom_usb_hs_phy_vbus_notifier; + phy_set_drvdata(uphy->phy, uphy); + + p = devm_of_phy_provider_register(&ulpi->dev, of_phy_simple_xlate); + return PTR_ERR_OR_ZERO(p); +} + +static const struct of_device_id qcom_usb_hs_phy_match[] = { + { .compatible = "qcom,usb-hs-phy", }, + { } +}; +MODULE_DEVICE_TABLE(of, qcom_usb_hs_phy_match); + +static struct ulpi_driver qcom_usb_hs_phy_driver = { + .probe = qcom_usb_hs_phy_probe, + .driver = { + .name = "qcom_usb_hs_phy", + .of_match_table = qcom_usb_hs_phy_match, + }, +}; +module_ulpi_driver(qcom_usb_hs_phy_driver); + +MODULE_DESCRIPTION("Qualcomm USB HS phy"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/phy-qcom-usb-hsic.c b/drivers/phy/phy-qcom-usb-hsic.c new file mode 100644 index 000000000000..47690f9945b9 --- /dev/null +++ b/drivers/phy/phy-qcom-usb-hsic.c @@ -0,0 +1,160 @@ +/** + * Copyright (C) 2016 Linaro Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/module.h> +#include <linux/ulpi/driver.h> +#include <linux/ulpi/regs.h> +#include <linux/pinctrl/consumer.h> +#include <linux/pinctrl/pinctrl-state.h> +#include <linux/delay.h> +#include <linux/clk.h> + +#include "ulpi_phy.h" + +#define ULPI_HSIC_CFG 0x30 +#define ULPI_HSIC_IO_CAL 0x33 + +struct qcom_usb_hsic_phy { + struct ulpi *ulpi; + struct phy *phy; + struct pinctrl *pctl; + struct clk *phy_clk; + struct clk *cal_clk; + struct clk *cal_sleep_clk; +}; + +static int qcom_usb_hsic_phy_power_on(struct phy *phy) +{ + struct qcom_usb_hsic_phy *uphy = phy_get_drvdata(phy); + struct ulpi *ulpi = uphy->ulpi; + struct pinctrl_state *pins_default; + int ret; + + ret = clk_prepare_enable(uphy->phy_clk); + if (ret) + return ret; + + ret = clk_prepare_enable(uphy->cal_clk); + if (ret) + goto err_cal; + + ret = clk_prepare_enable(uphy->cal_sleep_clk); + if (ret) + goto err_sleep; + + /* Set periodic calibration interval to ~2.048sec in HSIC_IO_CAL_REG */ + ret = ulpi_write(ulpi, ULPI_HSIC_IO_CAL, 0xff); + if (ret) + goto err_ulpi; + + /* Enable periodic IO calibration in HSIC_CFG register */ + ret = ulpi_write(ulpi, ULPI_HSIC_CFG, 0xa8); + if (ret) + goto err_ulpi; + + /* Configure pins for HSIC functionality */ + pins_default = pinctrl_lookup_state(uphy->pctl, PINCTRL_STATE_DEFAULT); + if (IS_ERR(pins_default)) + return PTR_ERR(pins_default); + + ret = pinctrl_select_state(uphy->pctl, pins_default); + if (ret) + goto err_ulpi; + + /* Enable HSIC mode in HSIC_CFG register */ + ret = ulpi_write(ulpi, ULPI_SET(ULPI_HSIC_CFG), 0x01); + if (ret) + goto err_ulpi; + + /* Disable auto-resume */ + ret = ulpi_write(ulpi, ULPI_CLR(ULPI_IFC_CTRL), + ULPI_IFC_CTRL_AUTORESUME); + if (ret) + goto err_ulpi; + + return ret; +err_ulpi: + clk_disable_unprepare(uphy->cal_sleep_clk); +err_sleep: + clk_disable_unprepare(uphy->cal_clk); +err_cal: + clk_disable_unprepare(uphy->phy_clk); + return ret; +} + +static int qcom_usb_hsic_phy_power_off(struct phy *phy) +{ + struct qcom_usb_hsic_phy *uphy = phy_get_drvdata(phy); + + clk_disable_unprepare(uphy->cal_sleep_clk); + clk_disable_unprepare(uphy->cal_clk); + clk_disable_unprepare(uphy->phy_clk); + + return 0; +} + +static const struct phy_ops qcom_usb_hsic_phy_ops = { + .power_on = qcom_usb_hsic_phy_power_on, + .power_off = qcom_usb_hsic_phy_power_off, + .owner = THIS_MODULE, +}; + +static int qcom_usb_hsic_phy_probe(struct ulpi *ulpi) +{ + struct qcom_usb_hsic_phy *uphy; + struct phy_provider *p; + struct clk *clk; + + uphy = devm_kzalloc(&ulpi->dev, sizeof(*uphy), GFP_KERNEL); + if (!uphy) + return -ENOMEM; + ulpi_set_drvdata(ulpi, uphy); + + uphy->ulpi = ulpi; + uphy->pctl = devm_pinctrl_get(&ulpi->dev); + if (IS_ERR(uphy->pctl)) + return PTR_ERR(uphy->pctl); + + uphy->phy_clk = clk = devm_clk_get(&ulpi->dev, "phy"); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + uphy->cal_clk = clk = devm_clk_get(&ulpi->dev, "cal"); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + uphy->cal_sleep_clk = clk = devm_clk_get(&ulpi->dev, "cal_sleep"); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + uphy->phy = devm_phy_create(&ulpi->dev, ulpi->dev.of_node, + &qcom_usb_hsic_phy_ops); + if (IS_ERR(uphy->phy)) + return PTR_ERR(uphy->phy); + phy_set_drvdata(uphy->phy, uphy); + + p = devm_of_phy_provider_register(&ulpi->dev, of_phy_simple_xlate); + return PTR_ERR_OR_ZERO(p); +} + +static const struct of_device_id qcom_usb_hsic_phy_match[] = { + { .compatible = "qcom,usb-hsic-phy", }, + { } +}; +MODULE_DEVICE_TABLE(of, qcom_usb_hsic_phy_match); + +static struct ulpi_driver qcom_usb_hsic_phy_driver = { + .probe = qcom_usb_hsic_phy_probe, + .driver = { + .name = "qcom_usb_hsic_phy", + .of_match_table = qcom_usb_hsic_phy_match, + }, +}; +module_ulpi_driver(qcom_usb_hsic_phy_driver); + +MODULE_DESCRIPTION("Qualcomm USB HSIC phy"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/phy-rcar-gen3-usb2.c b/drivers/phy/phy-rcar-gen3-usb2.c index c63da1b955c1..afb4d048d3e9 100644 --- a/drivers/phy/phy-rcar-gen3-usb2.c +++ b/drivers/phy/phy-rcar-gen3-usb2.c @@ -94,11 +94,11 @@ static void rcar_gen3_phy_usb2_work(struct work_struct *work) work); if (ch->extcon_host) { - extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, true); - extcon_set_cable_state_(ch->extcon, EXTCON_USB, false); + extcon_set_state_sync(ch->extcon, EXTCON_USB_HOST, true); + extcon_set_state_sync(ch->extcon, EXTCON_USB, false); } else { - extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, false); - extcon_set_cable_state_(ch->extcon, EXTCON_USB, true); + extcon_set_state_sync(ch->extcon, EXTCON_USB_HOST, false); + extcon_set_state_sync(ch->extcon, EXTCON_USB, true); } } @@ -350,7 +350,7 @@ static int rcar_gen3_phy_usb2_power_off(struct phy *p) return ret; } -static struct phy_ops rcar_gen3_phy_usb2_ops = { +static const struct phy_ops rcar_gen3_phy_usb2_ops = { .init = rcar_gen3_phy_usb2_init, .exit = rcar_gen3_phy_usb2_exit, .power_on = rcar_gen3_phy_usb2_power_on, diff --git a/drivers/phy/phy-rockchip-inno-usb2.c b/drivers/phy/phy-rockchip-inno-usb2.c index 2f99ec95079c..4ea95c28a66f 100644 --- a/drivers/phy/phy-rockchip-inno-usb2.c +++ b/drivers/phy/phy-rockchip-inno-usb2.c @@ -595,9 +595,14 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work) if (rport->vbus_attached != vbus_attach) { rport->vbus_attached = vbus_attach; - if (notify_charger && rphy->edev) + if (notify_charger && rphy->edev) { extcon_set_cable_state_(rphy->edev, cable, vbus_attach); + if (cable == EXTCON_CHG_USB_SDP) + extcon_set_state_sync(rphy->edev, + EXTCON_USB, + vbus_attach); + } } break; case OTG_STATE_B_PERIPHERAL: diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/phy-sun4i-usb.c index bf28a0fdd569..a21b5f24a340 100644 --- a/drivers/phy/phy-sun4i-usb.c +++ b/drivers/phy/phy-sun4i-usb.c @@ -99,6 +99,7 @@ enum sun4i_usb_phy_type { sun6i_a31_phy, sun8i_a33_phy, sun8i_h3_phy, + sun8i_v3s_phy, sun50i_a64_phy, }; @@ -188,7 +189,8 @@ static void sun4i_usb_phy_write(struct sun4i_usb_phy *phy, u32 addr, u32 data, spin_lock_irqsave(&phy_data->reg_lock, flags); if (phy_data->cfg->type == sun8i_a33_phy || - phy_data->cfg->type == sun50i_a64_phy) { + phy_data->cfg->type == sun50i_a64_phy || + phy_data->cfg->type == sun8i_v3s_phy) { /* A33 or A64 needs us to set phyctl to 0 explicitly */ writel(0, phyctl); } @@ -534,7 +536,7 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) mutex_unlock(&phy0->mutex); if (id_notify) { - extcon_set_cable_state_(data->extcon, EXTCON_USB_HOST, + extcon_set_state_sync(data->extcon, EXTCON_USB_HOST, !id_det); /* When leaving host mode force end the session here */ if (force_session_end && id_det == 1) { @@ -547,7 +549,7 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work) } if (vbus_notify) - extcon_set_cable_state_(data->extcon, EXTCON_USB, vbus_det); + extcon_set_state_sync(data->extcon, EXTCON_USB, vbus_det); if (sun4i_usb_phy0_poll(data)) queue_delayed_work(system_wq, &data->detect, POLL_TIME); @@ -825,6 +827,15 @@ static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = { .enable_pmu_unk1 = true, }; +static const struct sun4i_usb_phy_cfg sun8i_v3s_cfg = { + .num_phys = 1, + .type = sun8i_v3s_phy, + .disc_thresh = 3, + .phyctl_offset = REG_PHYCTL_A33, + .dedicated_clocks = true, + .enable_pmu_unk1 = true, +}; + static const struct sun4i_usb_phy_cfg sun50i_a64_cfg = { .num_phys = 2, .type = sun50i_a64_phy, @@ -842,6 +853,7 @@ static const struct of_device_id sun4i_usb_phy_of_match[] = { { .compatible = "allwinner,sun8i-a23-usb-phy", .data = &sun8i_a23_cfg }, { .compatible = "allwinner,sun8i-a33-usb-phy", .data = &sun8i_a33_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", .data = &sun50i_a64_cfg}, { }, diff --git a/drivers/usb/chipidea/Kconfig b/drivers/usb/chipidea/Kconfig index 5e5b9eb7ebf6..fc96f5cdcb5c 100644 --- a/drivers/usb/chipidea/Kconfig +++ b/drivers/usb/chipidea/Kconfig @@ -2,6 +2,7 @@ config USB_CHIPIDEA tristate "ChipIdea Highspeed Dual Role Controller" depends on ((USB_EHCI_HCD && USB_GADGET) || (USB_EHCI_HCD && !USB_GADGET) || (!USB_EHCI_HCD && USB_GADGET)) && HAS_DMA select EXTCON + select RESET_CONTROLLER help Say Y here if your system has a dual role high speed USB controller based on ChipIdea silicon IP. It supports: @@ -38,4 +39,11 @@ config USB_CHIPIDEA_HOST Say Y here to enable host controller functionality of the ChipIdea driver. +config USB_CHIPIDEA_ULPI + bool "ChipIdea ULPI PHY support" + depends on USB_ULPI_BUS=y || USB_ULPI_BUS=USB_CHIPIDEA + help + Say Y here if you have a ULPI PHY attached to your ChipIdea + controller. + endif diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile index 518e445476c3..39fca5715ed3 100644 --- a/drivers/usb/chipidea/Makefile +++ b/drivers/usb/chipidea/Makefile @@ -4,6 +4,7 @@ ci_hdrc-y := core.o otg.o debug.o ci_hdrc-$(CONFIG_USB_CHIPIDEA_UDC) += udc.o ci_hdrc-$(CONFIG_USB_CHIPIDEA_HOST) += host.o ci_hdrc-$(CONFIG_USB_OTG_FSM) += otg_fsm.o +ci_hdrc-$(CONFIG_USB_CHIPIDEA_ULPI) += ulpi.o # Glue/Bridge layers go here diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index cd414559040f..59e22389c10b 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -18,6 +18,8 @@ #include <linux/usb.h> #include <linux/usb/gadget.h> #include <linux/usb/otg-fsm.h> +#include <linux/usb/otg.h> +#include <linux/ulpi/interface.h> /****************************************************************************** * DEFINE @@ -52,6 +54,7 @@ enum ci_hw_regs { OP_ENDPTLISTADDR, OP_TTCTRL, OP_BURSTSIZE, + OP_ULPI_VIEWPORT, OP_PORTSC, OP_DEVLC, OP_OTGSC, @@ -187,6 +190,8 @@ struct hw_bank { * @test_mode: the selected test mode * @platdata: platform specific information supplied by parent device * @vbus_active: is VBUS active + * @ulpi: pointer to ULPI device, if any + * @ulpi_ops: ULPI read/write ops for this device * @phy: pointer to PHY, if any * @usb_phy: pointer to USB PHY, if any and if using the USB PHY framework * @hcd: pointer to usb_hcd for ehci host driver @@ -236,6 +241,10 @@ struct ci_hdrc { struct ci_hdrc_platform_data *platdata; int vbus_active; +#ifdef CONFIG_USB_CHIPIDEA_ULPI + struct ulpi *ulpi; + struct ulpi_ops ulpi_ops; +#endif struct phy *phy; /* old usb_phy interface */ struct usb_phy *usb_phy; @@ -418,6 +427,16 @@ static inline bool ci_otg_is_fsm_mode(struct ci_hdrc *ci) #endif } +#if IS_ENABLED(CONFIG_USB_CHIPIDEA_ULPI) +int ci_ulpi_init(struct ci_hdrc *ci); +void ci_ulpi_exit(struct ci_hdrc *ci); +int ci_ulpi_resume(struct ci_hdrc *ci); +#else +static inline int ci_ulpi_init(struct ci_hdrc *ci) { return 0; } +static inline void ci_ulpi_exit(struct ci_hdrc *ci) { } +static inline int ci_ulpi_resume(struct ci_hdrc *ci) { return 0; } +#endif + u32 hw_read_intr_enable(struct ci_hdrc *ci); u32 hw_read_intr_status(struct ci_hdrc *ci); @@ -428,8 +447,7 @@ int hw_port_test_set(struct ci_hdrc *ci, u8 mode); u8 hw_port_test_get(struct ci_hdrc *ci); -int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask, - u32 value, unsigned int timeout_ms); +void hw_phymode_configure(struct ci_hdrc *ci); void ci_platform_configure(struct ci_hdrc *ci); diff --git a/drivers/usb/chipidea/ci_hdrc_msm.c b/drivers/usb/chipidea/ci_hdrc_msm.c index 3889809fd0c4..0bdfcdcbf7a5 100644 --- a/drivers/usb/chipidea/ci_hdrc_msm.c +++ b/drivers/usb/chipidea/ci_hdrc_msm.c @@ -8,90 +8,292 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> -#include <linux/usb/msm_hsusb_hw.h> -#include <linux/usb/ulpi.h> -#include <linux/usb/gadget.h> #include <linux/usb/chipidea.h> +#include <linux/clk.h> +#include <linux/reset.h> +#include <linux/mfd/syscon.h> +#include <linux/regmap.h> +#include <linux/io.h> +#include <linux/reset-controller.h> +#include <linux/extcon.h> +#include <linux/of.h> #include "ci.h" -#define MSM_USB_BASE (ci->hw_bank.abs) +#define HS_PHY_AHB_MODE 0x0098 -static void ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event) +#define HS_PHY_GENCONFIG 0x009c +#define HS_PHY_TXFIFO_IDLE_FORCE_DIS BIT(4) + +#define HS_PHY_GENCONFIG_2 0x00a0 +#define HS_PHY_SESS_VLD_CTRL_EN BIT(7) +#define HS_PHY_ULPI_TX_PKT_EN_CLR_FIX BIT(19) + +#define HSPHY_SESS_VLD_CTRL BIT(25) + +/* Vendor base starts at 0x200 beyond CI base */ +#define HS_PHY_CTRL 0x0040 +#define HS_PHY_SEC_CTRL 0x0078 +#define HS_PHY_DIG_CLAMP_N BIT(16) +#define HS_PHY_POR_ASSERT BIT(0) + +struct ci_hdrc_msm { + struct platform_device *ci; + struct clk *core_clk; + struct clk *iface_clk; + struct clk *fs_clk; + struct ci_hdrc_platform_data pdata; + struct reset_controller_dev rcdev; + bool secondary_phy; + bool hsic; + void __iomem *base; +}; + +static int +ci_hdrc_msm_por_reset(struct reset_controller_dev *r, unsigned long id) { - struct device *dev = ci->gadget.dev.parent; + struct ci_hdrc_msm *ci_msm = container_of(r, struct ci_hdrc_msm, rcdev); + void __iomem *addr = ci_msm->base; + u32 val; + + if (id) + addr += HS_PHY_SEC_CTRL; + else + addr += HS_PHY_CTRL; + + val = readl_relaxed(addr); + val |= HS_PHY_POR_ASSERT; + writel(val, addr); + /* + * wait for minimum 10 microseconds as suggested by manual. + * Use a slightly larger value since the exact value didn't + * work 100% of the time. + */ + udelay(12); + val &= ~HS_PHY_POR_ASSERT; + writel(val, addr); + + return 0; +} + +static const struct reset_control_ops ci_hdrc_msm_reset_ops = { + .reset = ci_hdrc_msm_por_reset, +}; + +static int ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event) +{ + struct device *dev = ci->dev->parent; + struct ci_hdrc_msm *msm_ci = dev_get_drvdata(dev); + int ret; switch (event) { case CI_HDRC_CONTROLLER_RESET_EVENT: dev_dbg(dev, "CI_HDRC_CONTROLLER_RESET_EVENT received\n"); - writel(0, USB_AHBBURST); + + hw_phymode_configure(ci); + if (msm_ci->secondary_phy) { + u32 val = readl_relaxed(msm_ci->base + HS_PHY_SEC_CTRL); + val |= HS_PHY_DIG_CLAMP_N; + writel_relaxed(val, msm_ci->base + HS_PHY_SEC_CTRL); + } + + ret = phy_init(ci->phy); + if (ret) + return ret; + + ret = phy_power_on(ci->phy); + if (ret) { + phy_exit(ci->phy); + return ret; + } + /* use AHB transactor, allow posted data writes */ - writel(0x8, USB_AHBMODE); - usb_phy_init(ci->usb_phy); + hw_write_id_reg(ci, HS_PHY_AHB_MODE, 0xffffffff, 0x8); + + /* workaround for rx buffer collision issue */ + hw_write_id_reg(ci, HS_PHY_GENCONFIG, + HS_PHY_TXFIFO_IDLE_FORCE_DIS, 0); + + if (!msm_ci->hsic) + hw_write_id_reg(ci, HS_PHY_GENCONFIG_2, + HS_PHY_ULPI_TX_PKT_EN_CLR_FIX, 0); + + if (!IS_ERR(ci->platdata->vbus_extcon.edev)) { + hw_write_id_reg(ci, HS_PHY_GENCONFIG_2, + HS_PHY_SESS_VLD_CTRL_EN, + HS_PHY_SESS_VLD_CTRL_EN); + hw_write(ci, OP_USBCMD, HSPHY_SESS_VLD_CTRL, + HSPHY_SESS_VLD_CTRL); + + } break; case CI_HDRC_CONTROLLER_STOPPED_EVENT: dev_dbg(dev, "CI_HDRC_CONTROLLER_STOPPED_EVENT received\n"); - /* - * Put the phy in non-driving mode. Otherwise host - * may not detect soft-disconnection. - */ - usb_phy_notify_disconnect(ci->usb_phy, USB_SPEED_UNKNOWN); + phy_power_off(ci->phy); + phy_exit(ci->phy); break; default: dev_dbg(dev, "unknown ci_hdrc event\n"); break; } + + return 0; } -static struct ci_hdrc_platform_data ci_hdrc_msm_platdata = { - .name = "ci_hdrc_msm", - .capoffset = DEF_CAPOFFSET, - .flags = CI_HDRC_REGS_SHARED | - CI_HDRC_DISABLE_STREAMING, +static int ci_hdrc_msm_mux_phy(struct ci_hdrc_msm *ci, + struct platform_device *pdev) +{ + struct regmap *regmap; + struct device *dev = &pdev->dev; + struct of_phandle_args args; + u32 val; + int ret; - .notify_event = ci_hdrc_msm_notify_event, -}; + ret = of_parse_phandle_with_fixed_args(dev->of_node, "phy-select", 2, 0, + &args); + if (ret) + return 0; + + regmap = syscon_node_to_regmap(args.np); + of_node_put(args.np); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + ret = regmap_write(regmap, args.args[0], args.args[1]); + if (ret) + return ret; + + ci->secondary_phy = !!args.args[1]; + if (ci->secondary_phy) { + val = readl_relaxed(ci->base + HS_PHY_SEC_CTRL); + val |= HS_PHY_DIG_CLAMP_N; + writel_relaxed(val, ci->base + HS_PHY_SEC_CTRL); + } + + return 0; +} static int ci_hdrc_msm_probe(struct platform_device *pdev) { + struct ci_hdrc_msm *ci; struct platform_device *plat_ci; - struct usb_phy *phy; + struct clk *clk; + struct reset_control *reset; + struct resource *res; + int ret; + struct device_node *ulpi_node, *phy_node; dev_dbg(&pdev->dev, "ci_hdrc_msm_probe\n"); - /* - * OTG(PHY) driver takes care of PHY initialization, clock management, - * powering up VBUS, mapping of registers address space and power - * management. - */ - phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0); - if (IS_ERR(phy)) - return PTR_ERR(phy); + ci = devm_kzalloc(&pdev->dev, sizeof(*ci), GFP_KERNEL); + if (!ci) + return -ENOMEM; + platform_set_drvdata(pdev, ci); + + ci->pdata.name = "ci_hdrc_msm"; + ci->pdata.capoffset = DEF_CAPOFFSET; + ci->pdata.flags = CI_HDRC_REGS_SHARED | CI_HDRC_DISABLE_STREAMING | + CI_HDRC_OVERRIDE_AHB_BURST | + CI_HDRC_OVERRIDE_PHY_CONTROL; + ci->pdata.notify_event = ci_hdrc_msm_notify_event; + + reset = devm_reset_control_get(&pdev->dev, "core"); + if (IS_ERR(reset)) + return PTR_ERR(reset); + + ci->core_clk = clk = devm_clk_get(&pdev->dev, "core"); + if (IS_ERR(clk)) + return PTR_ERR(clk); - ci_hdrc_msm_platdata.usb_phy = phy; + ci->iface_clk = clk = devm_clk_get(&pdev->dev, "iface"); + if (IS_ERR(clk)) + return PTR_ERR(clk); - plat_ci = ci_hdrc_add_device(&pdev->dev, - pdev->resource, pdev->num_resources, - &ci_hdrc_msm_platdata); + ci->fs_clk = clk = devm_clk_get(&pdev->dev, "fs"); + if (IS_ERR(clk)) { + if (PTR_ERR(clk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + ci->fs_clk = NULL; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + ci->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(ci->base)) + return PTR_ERR(ci->base); + + ci->rcdev.owner = THIS_MODULE; + ci->rcdev.ops = &ci_hdrc_msm_reset_ops; + ci->rcdev.of_node = pdev->dev.of_node; + ci->rcdev.nr_resets = 2; + ret = reset_controller_register(&ci->rcdev); + if (ret) + return ret; + + ret = clk_prepare_enable(ci->fs_clk); + if (ret) + goto err_fs; + + reset_control_assert(reset); + usleep_range(10000, 12000); + reset_control_deassert(reset); + + clk_disable_unprepare(ci->fs_clk); + + ret = clk_prepare_enable(ci->core_clk); + if (ret) + goto err_fs; + + ret = clk_prepare_enable(ci->iface_clk); + if (ret) + goto err_iface; + + ret = ci_hdrc_msm_mux_phy(ci, pdev); + if (ret) + goto err_mux; + + ulpi_node = of_find_node_by_name(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"); + of_node_put(phy_node); + } + of_node_put(ulpi_node); + + plat_ci = ci_hdrc_add_device(&pdev->dev, pdev->resource, + pdev->num_resources, &ci->pdata); if (IS_ERR(plat_ci)) { - dev_err(&pdev->dev, "ci_hdrc_add_device failed!\n"); - return PTR_ERR(plat_ci); + ret = PTR_ERR(plat_ci); + if (ret != -EPROBE_DEFER) + dev_err(&pdev->dev, "ci_hdrc_add_device failed!\n"); + goto err_mux; } - platform_set_drvdata(pdev, plat_ci); + ci->ci = plat_ci; + pm_runtime_set_active(&pdev->dev); pm_runtime_no_callbacks(&pdev->dev); pm_runtime_enable(&pdev->dev); return 0; + +err_mux: + clk_disable_unprepare(ci->iface_clk); +err_iface: + clk_disable_unprepare(ci->core_clk); +err_fs: + reset_controller_unregister(&ci->rcdev); + return ret; } static int ci_hdrc_msm_remove(struct platform_device *pdev) { - struct platform_device *plat_ci = platform_get_drvdata(pdev); + struct ci_hdrc_msm *ci = platform_get_drvdata(pdev); pm_runtime_disable(&pdev->dev); - ci_hdrc_remove_device(plat_ci); + ci_hdrc_remove_device(ci->ci); + clk_disable_unprepare(ci->iface_clk); + clk_disable_unprepare(ci->core_clk); + reset_controller_unregister(&ci->rcdev); return 0; } diff --git a/drivers/usb/chipidea/ci_hdrc_usb2.c b/drivers/usb/chipidea/ci_hdrc_usb2.c index 4456d2cf80ff..d162cc0bb8ce 100644 --- a/drivers/usb/chipidea/ci_hdrc_usb2.c +++ b/drivers/usb/chipidea/ci_hdrc_usb2.c @@ -74,10 +74,6 @@ static int ci_hdrc_usb2_probe(struct platform_device *pdev) } } - ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); - if (ret) - goto clk_err; - ci_pdata->name = dev_name(dev); priv->ci_pdev = ci_hdrc_add_device(dev, pdev->resource, diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 3dbb4a21ab44..79ad8e91632e 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -62,7 +62,6 @@ #include <linux/usb/chipidea.h> #include <linux/usb/of.h> #include <linux/of.h> -#include <linux/phy.h> #include <linux/regulator/consumer.h> #include <linux/usb/ehci_def.h> @@ -86,6 +85,7 @@ static const u8 ci_regs_nolpm[] = { [OP_ENDPTLISTADDR] = 0x18U, [OP_TTCTRL] = 0x1CU, [OP_BURSTSIZE] = 0x20U, + [OP_ULPI_VIEWPORT] = 0x30U, [OP_PORTSC] = 0x44U, [OP_DEVLC] = 0x84U, [OP_OTGSC] = 0x64U, @@ -110,6 +110,7 @@ static const u8 ci_regs_lpm[] = { [OP_ENDPTLISTADDR] = 0x18U, [OP_TTCTRL] = 0x1CU, [OP_BURSTSIZE] = 0x20U, + [OP_ULPI_VIEWPORT] = 0x30U, [OP_PORTSC] = 0x44U, [OP_DEVLC] = 0x84U, [OP_OTGSC] = 0xC4U, @@ -285,7 +286,7 @@ static int hw_device_init(struct ci_hdrc *ci, void __iomem *base) return 0; } -static void hw_phymode_configure(struct ci_hdrc *ci) +void hw_phymode_configure(struct ci_hdrc *ci) { u32 portsc, lpm, sts = 0; @@ -325,6 +326,7 @@ static void hw_phymode_configure(struct ci_hdrc *ci) hw_write(ci, OP_PORTSC, PORTSC_STS, PORTSC_STS); } } +EXPORT_SYMBOL_GPL(hw_phymode_configure); /** * _ci_usb_phy_init: initialize phy taking in account both phy and usb_phy @@ -361,6 +363,9 @@ static int _ci_usb_phy_init(struct ci_hdrc *ci) */ static void ci_usb_phy_exit(struct ci_hdrc *ci) { + if (ci->platdata->flags & CI_HDRC_OVERRIDE_PHY_CONTROL) + return; + if (ci->phy) { phy_power_off(ci->phy); phy_exit(ci->phy); @@ -379,6 +384,9 @@ static int ci_usb_phy_init(struct ci_hdrc *ci) { int ret; + if (ci->platdata->flags & CI_HDRC_OVERRIDE_PHY_CONTROL) + return 0; + switch (ci->platdata->phy_mode) { case USBPHY_INTERFACE_MODE_UTMI: case USBPHY_INTERFACE_MODE_UTMIW: @@ -419,13 +427,21 @@ void ci_platform_configure(struct ci_hdrc *ci) is_device_mode = hw_read(ci, OP_USBMODE, USBMODE_CM) == USBMODE_CM_DC; is_host_mode = hw_read(ci, OP_USBMODE, USBMODE_CM) == USBMODE_CM_HC; - if (is_device_mode && - (ci->platdata->flags & CI_HDRC_DISABLE_DEVICE_STREAMING)) - hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS); + if (is_device_mode) { + phy_set_mode(ci->phy, PHY_MODE_USB_DEVICE); + + if (ci->platdata->flags & CI_HDRC_DISABLE_DEVICE_STREAMING) + hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, + USBMODE_CI_SDIS); + } + + if (is_host_mode) { + phy_set_mode(ci->phy, PHY_MODE_USB_HOST); - if (is_host_mode && - (ci->platdata->flags & CI_HDRC_DISABLE_HOST_STREAMING)) - hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS); + if (ci->platdata->flags & CI_HDRC_DISABLE_HOST_STREAMING) + hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, + USBMODE_CI_SDIS); + } if (ci->platdata->flags & CI_HDRC_FORCE_FULLSPEED) { if (ci->hw_bank.lpm) @@ -495,9 +511,12 @@ int hw_device_reset(struct ci_hdrc *ci) return ret; } - if (ci->platdata->notify_event) - ci->platdata->notify_event(ci, + if (ci->platdata->notify_event) { + ret = ci->platdata->notify_event(ci, CI_HDRC_CONTROLLER_RESET_EVENT); + if (ret) + return ret; + } /* USBMODE should be configured step by step */ hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE); @@ -516,38 +535,6 @@ int hw_device_reset(struct ci_hdrc *ci) return 0; } -/** - * hw_wait_reg: wait the register value - * - * Sometimes, it needs to wait register value before going on. - * Eg, when switch to device mode, the vbus value should be lower - * than OTGSC_BSV before connects to host. - * - * @ci: the controller - * @reg: register index - * @mask: mast bit - * @value: the bit value to wait - * @timeout_ms: timeout in millisecond - * - * This function returns an error code if timeout - */ -int hw_wait_reg(struct ci_hdrc *ci, enum ci_hw_regs reg, u32 mask, - u32 value, unsigned int timeout_ms) -{ - unsigned long elapse = jiffies + msecs_to_jiffies(timeout_ms); - - while (hw_read(ci, reg, mask) != value) { - if (time_after(jiffies, elapse)) { - dev_err(ci->dev, "timeout waiting for %08x in %d\n", - mask, reg); - return -ETIMEDOUT; - } - msleep(20); - } - - return 0; -} - static irqreturn_t ci_irq(int irq, void *data) { struct ci_hdrc *ci = data; @@ -601,35 +588,14 @@ static irqreturn_t ci_irq(int irq, void *data) return ret; } -static int ci_vbus_notifier(struct notifier_block *nb, unsigned long event, - void *ptr) -{ - struct ci_hdrc_cable *vbus = container_of(nb, struct ci_hdrc_cable, nb); - struct ci_hdrc *ci = vbus->ci; - - if (event) - vbus->state = true; - else - vbus->state = false; - - vbus->changed = true; - - ci_irq(ci->irq, ci); - return NOTIFY_DONE; -} - -static int ci_id_notifier(struct notifier_block *nb, unsigned long event, - void *ptr) +static int ci_cable_notifier(struct notifier_block *nb, unsigned long event, + void *ptr) { - struct ci_hdrc_cable *id = container_of(nb, struct ci_hdrc_cable, nb); - struct ci_hdrc *ci = id->ci; + struct ci_hdrc_cable *cbl = container_of(nb, struct ci_hdrc_cable, nb); + struct ci_hdrc *ci = cbl->ci; - if (event) - id->state = false; - else - id->state = true; - - id->changed = true; + cbl->connected = event; + cbl->changed = true; ci_irq(ci->irq, ci); return NOTIFY_DONE; @@ -738,27 +704,27 @@ static int ci_get_platdata(struct device *dev, } cable = &platdata->vbus_extcon; - cable->nb.notifier_call = ci_vbus_notifier; + cable->nb.notifier_call = ci_cable_notifier; cable->edev = ext_vbus; if (!IS_ERR(ext_vbus)) { - ret = extcon_get_cable_state_(cable->edev, EXTCON_USB); + ret = extcon_get_state(cable->edev, EXTCON_USB); if (ret) - cable->state = true; + cable->connected = true; else - cable->state = false; + cable->connected = false; } cable = &platdata->id_extcon; - cable->nb.notifier_call = ci_id_notifier; + cable->nb.notifier_call = ci_cable_notifier; cable->edev = ext_id; if (!IS_ERR(ext_id)) { - ret = extcon_get_cable_state_(cable->edev, EXTCON_USB_HOST); + ret = extcon_get_state(cable->edev, EXTCON_USB_HOST); if (ret) - cable->state = false; + cable->connected = true; else - cable->state = true; + cable->connected = false; } return 0; } @@ -771,8 +737,8 @@ static int ci_extcon_register(struct ci_hdrc *ci) id = &ci->platdata->id_extcon; id->ci = ci; if (!IS_ERR(id->edev)) { - ret = extcon_register_notifier(id->edev, EXTCON_USB_HOST, - &id->nb); + ret = devm_extcon_register_notifier(ci->dev, id->edev, + EXTCON_USB_HOST, &id->nb); if (ret < 0) { dev_err(ci->dev, "register ID failed\n"); return ret; @@ -782,11 +748,9 @@ static int ci_extcon_register(struct ci_hdrc *ci) vbus = &ci->platdata->vbus_extcon; vbus->ci = ci; if (!IS_ERR(vbus->edev)) { - ret = extcon_register_notifier(vbus->edev, EXTCON_USB, - &vbus->nb); + ret = devm_extcon_register_notifier(ci->dev, vbus->edev, + EXTCON_USB, &vbus->nb); if (ret < 0) { - extcon_unregister_notifier(id->edev, EXTCON_USB_HOST, - &id->nb); dev_err(ci->dev, "register VBUS failed\n"); return ret; } @@ -795,20 +759,6 @@ static int ci_extcon_register(struct ci_hdrc *ci) return 0; } -static void ci_extcon_unregister(struct ci_hdrc *ci) -{ - struct ci_hdrc_cable *cable; - - cable = &ci->platdata->id_extcon; - if (!IS_ERR(cable->edev)) - extcon_unregister_notifier(cable->edev, EXTCON_USB_HOST, - &cable->nb); - - cable = &ci->platdata->vbus_extcon; - if (!IS_ERR(cable->edev)) - extcon_unregister_notifier(cable->edev, EXTCON_USB, &cable->nb); -} - static DEFINE_IDA(ci_ida); struct platform_device *ci_hdrc_add_device(struct device *dev, @@ -921,6 +871,7 @@ static int ci_hdrc_probe(struct platform_device *pdev) CI_HDRC_IMX28_WRITE_FIX); ci->supports_runtime_pm = !!(ci->platdata->flags & CI_HDRC_SUPPORTS_RUNTIME_PM); + platform_set_drvdata(pdev, ci); ret = hw_device_init(ci, base); if (ret < 0) { @@ -928,6 +879,10 @@ static int ci_hdrc_probe(struct platform_device *pdev) return -ENODEV; } + ret = ci_ulpi_init(ci); + if (ret) + return ret; + if (ci->platdata->phy) { ci->phy = ci->platdata->phy; } else if (ci->platdata->usb_phy) { @@ -938,11 +893,15 @@ static int ci_hdrc_probe(struct platform_device *pdev) /* if both generic PHY and USB PHY layers aren't enabled */ if (PTR_ERR(ci->phy) == -ENOSYS && - PTR_ERR(ci->usb_phy) == -ENXIO) - return -ENXIO; + PTR_ERR(ci->usb_phy) == -ENXIO) { + ret = -ENXIO; + goto ulpi_exit; + } - if (IS_ERR(ci->phy) && IS_ERR(ci->usb_phy)) - return -EPROBE_DEFER; + if (IS_ERR(ci->phy) && IS_ERR(ci->usb_phy)) { + ret = -EPROBE_DEFER; + goto ulpi_exit; + } if (IS_ERR(ci->phy)) ci->phy = NULL; @@ -1027,7 +986,6 @@ static int ci_hdrc_probe(struct platform_device *pdev) } } - platform_set_drvdata(pdev, ci); ret = devm_request_irq(dev, ci->irq, ci_irq, IRQF_SHARED, ci->platdata->name, ci); if (ret) @@ -1054,11 +1012,12 @@ static int ci_hdrc_probe(struct platform_device *pdev) if (!ret) return 0; - ci_extcon_unregister(ci); stop: ci_role_destroy(ci); deinit_phy: ci_usb_phy_exit(ci); +ulpi_exit: + ci_ulpi_exit(ci); return ret; } @@ -1074,10 +1033,10 @@ static int ci_hdrc_remove(struct platform_device *pdev) } dbg_remove_files(ci); - ci_extcon_unregister(ci); ci_role_destroy(ci); ci_hdrc_enter_lpm(ci, true); ci_usb_phy_exit(ci); + ci_ulpi_exit(ci); return 0; } @@ -1125,6 +1084,7 @@ static void ci_controller_suspend(struct ci_hdrc *ci) static int ci_controller_resume(struct device *dev) { struct ci_hdrc *ci = dev_get_drvdata(dev); + int ret; dev_dbg(dev, "at %s\n", __func__); @@ -1134,6 +1094,11 @@ static int ci_controller_resume(struct device *dev) } ci_hdrc_enter_lpm(ci, false); + + ret = ci_ulpi_resume(ci); + if (ret) + return ret; + if (ci->usb_phy) { usb_phy_set_suspend(ci->usb_phy, 0); usb_phy_set_wakeup(ci->usb_phy, false); diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index 111b0e0b8698..915f3e91586e 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -90,6 +90,13 @@ static int ehci_ci_reset(struct usb_hcd *hcd) ehci->need_io_watchdog = 0; + if (ci->platdata->notify_event) { + ret = ci->platdata->notify_event(ci, + CI_HDRC_CONTROLLER_RESET_EVENT); + if (ret) + return ret; + } + ci_platform_configure(ci); return ret; @@ -187,6 +194,9 @@ static void host_stop(struct ci_hdrc *ci) struct usb_hcd *hcd = ci->hcd; if (hcd) { + if (ci->platdata->notify_event) + ci->platdata->notify_event(ci, + CI_HDRC_CONTROLLER_STOPPED_EVENT); usb_remove_hcd(hcd); ci->role = CI_ROLE_END; synchronize_irq(ci->irq); diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c index 03b6743461d1..10236fe71522 100644 --- a/drivers/usb/chipidea/otg.c +++ b/drivers/usb/chipidea/otg.c @@ -44,12 +44,15 @@ u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask) else val &= ~OTGSC_BSVIS; - cable->changed = false; - - if (cable->state) + if (cable->connected) val |= OTGSC_BSV; else val &= ~OTGSC_BSV; + + if (cable->enabled) + val |= OTGSC_BSVIE; + else + val &= ~OTGSC_BSVIE; } cable = &ci->platdata->id_extcon; @@ -59,15 +62,18 @@ u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask) else val &= ~OTGSC_IDIS; - cable->changed = false; + if (cable->connected) + val &= ~OTGSC_ID; /* host */ + else + val |= OTGSC_ID; /* device */ - if (cable->state) - val |= OTGSC_ID; + if (cable->enabled) + val |= OTGSC_IDIE; else - val &= ~OTGSC_ID; + val &= ~OTGSC_IDIE; } - return val; + return val & mask; } /** @@ -77,6 +83,36 @@ u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask) */ void hw_write_otgsc(struct ci_hdrc *ci, u32 mask, u32 data) { + struct ci_hdrc_cable *cable; + + cable = &ci->platdata->vbus_extcon; + if (!IS_ERR(cable->edev)) { + if (data & mask & OTGSC_BSVIS) + cable->changed = false; + + /* Don't enable vbus interrupt if using external notifier */ + if (data & mask & OTGSC_BSVIE) { + cable->enabled = true; + data &= ~OTGSC_BSVIE; + } else if (mask & OTGSC_BSVIE) { + cable->enabled = false; + } + } + + cable = &ci->platdata->id_extcon; + if (!IS_ERR(cable->edev)) { + if (data & mask & OTGSC_IDIS) + cable->changed = false; + + /* Don't enable id interrupt if using external notifier */ + if (data & mask & OTGSC_IDIE) { + cable->enabled = true; + data &= ~OTGSC_IDIE; + } else if (mask & OTGSC_IDIE) { + cable->enabled = false; + } + } + hw_write(ci, OP_OTGSC, mask | OTGSC_INT_STATUS_BITS, data); } @@ -98,13 +134,37 @@ void ci_handle_vbus_change(struct ci_hdrc *ci) if (!ci->is_otg) return; - if (hw_read_otgsc(ci, OTGSC_BSV)) + if (hw_read_otgsc(ci, OTGSC_BSV) && !ci->vbus_active) usb_gadget_vbus_connect(&ci->gadget); - else + else if (!hw_read_otgsc(ci, OTGSC_BSV) && ci->vbus_active) usb_gadget_vbus_disconnect(&ci->gadget); } -#define CI_VBUS_STABLE_TIMEOUT_MS 5000 +/** + * When we switch to device mode, the vbus value should be lower + * than OTGSC_BSV before connecting to host. + * + * @ci: the controller + * + * This function returns an error code if timeout + */ +static int hw_wait_vbus_lower_bsv(struct ci_hdrc *ci) +{ + unsigned long elapse = jiffies + msecs_to_jiffies(5000); + u32 mask = OTGSC_BSV; + + while (hw_read_otgsc(ci, mask)) { + if (time_after(jiffies, elapse)) { + dev_err(ci->dev, "timeout waiting for %08x in OTGSC\n", + mask); + return -ETIMEDOUT; + } + msleep(20); + } + + return 0; +} + static void ci_handle_id_switch(struct ci_hdrc *ci) { enum ci_role role = ci_otg_role(ci); @@ -115,12 +175,21 @@ static void ci_handle_id_switch(struct ci_hdrc *ci) ci_role_stop(ci); - if (role == CI_ROLE_GADGET) - /* wait vbus lower than OTGSC_BSV */ - hw_wait_reg(ci, OP_OTGSC, OTGSC_BSV, 0, - CI_VBUS_STABLE_TIMEOUT_MS); + if (role == CI_ROLE_GADGET && + IS_ERR(ci->platdata->vbus_extcon.edev)) + /* + * Wait vbus lower than OTGSC_BSV before connecting + * to host. If connecting status is from an external + * connector instead of register, we don't need to + * care vbus on the board, since it will not affect + * external connector status. + */ + hw_wait_vbus_lower_bsv(ci); ci_role_start(ci, role); + /* vbus change may have already occurred */ + if (role == CI_ROLE_GADGET) + ci_handle_vbus_change(ci); } } /** diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index cf132f057137..f88e9157fad0 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1725,7 +1725,6 @@ static int ci_udc_start(struct usb_gadget *gadget, struct usb_gadget_driver *driver) { struct ci_hdrc *ci = container_of(gadget, struct ci_hdrc, gadget); - unsigned long flags; int retval = -ENOMEM; if (driver->disconnect == NULL) @@ -1752,7 +1751,6 @@ static int ci_udc_start(struct usb_gadget *gadget, pm_runtime_get_sync(&ci->gadget.dev); if (ci->vbus_active) { - spin_lock_irqsave(&ci->lock, flags); hw_device_reset(ci); } else { usb_udc_vbus_handler(&ci->gadget, false); @@ -1761,7 +1759,6 @@ static int ci_udc_start(struct usb_gadget *gadget, } retval = hw_device_state(ci, ci->ep0out->qh.dma); - spin_unlock_irqrestore(&ci->lock, flags); if (retval) pm_runtime_put_sync(&ci->gadget.dev); @@ -1796,10 +1793,10 @@ static int ci_udc_stop(struct usb_gadget *gadget) if (ci->vbus_active) { hw_device_state(ci, 0); + spin_unlock_irqrestore(&ci->lock, flags); if (ci->platdata->notify_event) ci->platdata->notify_event(ci, CI_HDRC_CONTROLLER_STOPPED_EVENT); - spin_unlock_irqrestore(&ci->lock, flags); _gadget_stop_activity(&ci->gadget); spin_lock_irqsave(&ci->lock, flags); pm_runtime_put(&ci->gadget.dev); diff --git a/drivers/usb/chipidea/ulpi.c b/drivers/usb/chipidea/ulpi.c new file mode 100644 index 000000000000..1219583dc1b2 --- /dev/null +++ b/drivers/usb/chipidea/ulpi.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2016 Linaro Ltd. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/device.h> +#include <linux/usb/chipidea.h> +#include <linux/ulpi/interface.h> + +#include "ci.h" + +#define ULPI_WAKEUP BIT(31) +#define ULPI_RUN BIT(30) +#define ULPI_WRITE BIT(29) +#define ULPI_SYNC_STATE BIT(27) +#define ULPI_ADDR(n) ((n) << 16) +#define ULPI_DATA(n) (n) + +static int ci_ulpi_wait(struct ci_hdrc *ci, u32 mask) +{ + unsigned long usec = 10000; + + while (usec--) { + if (!hw_read(ci, OP_ULPI_VIEWPORT, mask)) + return 0; + + udelay(1); + } + + return -ETIMEDOUT; +} + +static int ci_ulpi_read(struct device *dev, u8 addr) +{ + struct ci_hdrc *ci = dev_get_drvdata(dev); + int ret; + + hw_write(ci, OP_ULPI_VIEWPORT, 0xffffffff, ULPI_WRITE | ULPI_WAKEUP); + ret = ci_ulpi_wait(ci, ULPI_WAKEUP); + if (ret) + return ret; + + hw_write(ci, OP_ULPI_VIEWPORT, 0xffffffff, ULPI_RUN | ULPI_ADDR(addr)); + ret = ci_ulpi_wait(ci, ULPI_RUN); + if (ret) + return ret; + + return hw_read(ci, OP_ULPI_VIEWPORT, GENMASK(15, 8)) >> 8; +} + +static int ci_ulpi_write(struct device *dev, u8 addr, u8 val) +{ + struct ci_hdrc *ci = dev_get_drvdata(dev); + int ret; + + hw_write(ci, OP_ULPI_VIEWPORT, 0xffffffff, ULPI_WRITE | ULPI_WAKEUP); + ret = ci_ulpi_wait(ci, ULPI_WAKEUP); + if (ret) + return ret; + + hw_write(ci, OP_ULPI_VIEWPORT, 0xffffffff, + ULPI_RUN | ULPI_WRITE | ULPI_ADDR(addr) | val); + return ci_ulpi_wait(ci, ULPI_RUN); +} + +int ci_ulpi_init(struct ci_hdrc *ci) +{ + if (ci->platdata->phy_mode != USBPHY_INTERFACE_MODE_ULPI) + return 0; + + /* + * Set PORTSC correctly so we can read/write ULPI registers for + * identification purposes + */ + hw_phymode_configure(ci); + + ci->ulpi_ops.read = ci_ulpi_read; + ci->ulpi_ops.write = ci_ulpi_write; + ci->ulpi = ulpi_register_interface(ci->dev, &ci->ulpi_ops); + if (IS_ERR(ci->ulpi)) + dev_err(ci->dev, "failed to register ULPI interface"); + + return PTR_ERR_OR_ZERO(ci->ulpi); +} + +void ci_ulpi_exit(struct ci_hdrc *ci) +{ + if (ci->ulpi) { + ulpi_unregister_interface(ci->ulpi); + ci->ulpi = NULL; + } +} + +int ci_ulpi_resume(struct ci_hdrc *ci) +{ + int cnt = 100000; + + while (cnt-- > 0) { + if (hw_read(ci, OP_ULPI_VIEWPORT, ULPI_SYNC_STATE)) + return 0; + udelay(1); + } + + return -ETIMEDOUT; +} diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index e35b1508d3eb..235e305f8473 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -913,7 +913,6 @@ static int get_serial_info(struct acm *acm, struct serial_struct __user *info) struct serial_struct tmp; memset(&tmp, 0, sizeof(tmp)); - tmp.flags = ASYNC_LOW_LATENCY; tmp.xmit_fifo_size = acm->writesize; tmp.baud_base = le32_to_cpu(acm->line.dwDTERate); tmp.close_delay = acm->port.close_delay / 10; diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 0a6369510f2d..8fda45a45bd3 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -531,7 +531,7 @@ retry: i++; if (file->f_flags & O_NONBLOCK) { if (!test_bit(WDM_READ, &desc->flags)) { - rv = cntr ? cntr : -EAGAIN; + rv = -EAGAIN; goto err; } rv = 0; diff --git a/drivers/usb/common/ulpi.c b/drivers/usb/common/ulpi.c index 8b317702d761..c9480d77810c 100644 --- a/drivers/usb/common/ulpi.c +++ b/drivers/usb/common/ulpi.c @@ -16,6 +16,9 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/acpi.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/clk/clk-conf.h> /* -------------------------------------------------------------------------- */ @@ -39,6 +42,10 @@ static int ulpi_match(struct device *dev, struct device_driver *driver) struct ulpi *ulpi = to_ulpi_dev(dev); const struct ulpi_device_id *id; + /* Some ULPI devices don't have a vendor id so rely on OF match */ + if (ulpi->id.vendor == 0) + return of_driver_match_device(dev, driver); + for (id = drv->id_table; id->vendor; id++) if (id->vendor == ulpi->id.vendor && id->product == ulpi->id.product) @@ -50,6 +57,11 @@ static int ulpi_match(struct device *dev, struct device_driver *driver) static int ulpi_uevent(struct device *dev, struct kobj_uevent_env *env) { struct ulpi *ulpi = to_ulpi_dev(dev); + int ret; + + ret = of_device_uevent_modalias(dev, env); + if (ret != -ENODEV) + return ret; if (add_uevent_var(env, "MODALIAS=ulpi:v%04xp%04x", ulpi->id.vendor, ulpi->id.product)) @@ -60,6 +72,11 @@ static int ulpi_uevent(struct device *dev, struct kobj_uevent_env *env) static int ulpi_probe(struct device *dev) { struct ulpi_driver *drv = to_ulpi_driver(dev->driver); + int ret; + + ret = of_clk_set_defaults(dev->of_node, false); + if (ret < 0) + return ret; return drv->probe(to_ulpi_dev(dev)); } @@ -87,8 +104,13 @@ static struct bus_type ulpi_bus = { static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) { + int len; struct ulpi *ulpi = to_ulpi_dev(dev); + len = of_device_get_modalias(dev, buf, PAGE_SIZE - 1); + if (len != -ENODEV) + return len; + return sprintf(buf, "ulpi:v%04xp%04x\n", ulpi->id.vendor, ulpi->id.product); } @@ -153,23 +175,45 @@ EXPORT_SYMBOL_GPL(ulpi_unregister_driver); /* -------------------------------------------------------------------------- */ -static int ulpi_register(struct device *dev, struct ulpi *ulpi) +static int ulpi_of_register(struct ulpi *ulpi) { - int ret; + struct device_node *np = NULL, *child; + struct device *parent; + + /* Find a ulpi bus underneath the parent or the grandparent */ + parent = ulpi->dev.parent; + if (parent->of_node) + np = of_find_node_by_name(parent->of_node, "ulpi"); + else if (parent->parent && parent->parent->of_node) + np = of_find_node_by_name(parent->parent->of_node, "ulpi"); + if (!np) + return 0; + + child = of_get_next_available_child(np, NULL); + of_node_put(np); + if (!child) + return -EINVAL; - ulpi->dev.parent = dev; /* needed early for ops */ + ulpi->dev.of_node = child; + + return 0; +} + +static int ulpi_read_id(struct ulpi *ulpi) +{ + int ret; /* Test the interface */ ret = ulpi_write(ulpi, ULPI_SCRATCH, 0xaa); if (ret < 0) - return ret; + goto err; ret = ulpi_read(ulpi, ULPI_SCRATCH); if (ret < 0) return ret; if (ret != 0xaa) - return -ENODEV; + goto err; ulpi->id.vendor = ulpi_read(ulpi, ULPI_VENDOR_ID_LOW); ulpi->id.vendor |= ulpi_read(ulpi, ULPI_VENDOR_ID_HIGH) << 8; @@ -177,13 +221,35 @@ static int ulpi_register(struct device *dev, struct ulpi *ulpi) ulpi->id.product = ulpi_read(ulpi, ULPI_PRODUCT_ID_LOW); ulpi->id.product |= ulpi_read(ulpi, ULPI_PRODUCT_ID_HIGH) << 8; + /* Some ULPI devices don't have a vendor id so rely on OF match */ + if (ulpi->id.vendor == 0) + goto err; + + request_module("ulpi:v%04xp%04x", ulpi->id.vendor, ulpi->id.product); + return 0; +err: + of_device_request_module(&ulpi->dev); + return 0; +} + +static int ulpi_register(struct device *dev, struct ulpi *ulpi) +{ + int ret; + + ulpi->dev.parent = dev; /* needed early for ops */ ulpi->dev.bus = &ulpi_bus; ulpi->dev.type = &ulpi_dev_type; dev_set_name(&ulpi->dev, "%s.ulpi", dev_name(dev)); ACPI_COMPANION_SET(&ulpi->dev, ACPI_COMPANION(dev)); - request_module("ulpi:v%04xp%04x", ulpi->id.vendor, ulpi->id.product); + ret = ulpi_of_register(ulpi); + if (ret) + return ret; + + ret = ulpi_read_id(ulpi); + if (ret) + return ret; ret = device_register(&ulpi->dev); if (ret) @@ -234,6 +300,7 @@ EXPORT_SYMBOL_GPL(ulpi_register_interface); */ void ulpi_unregister_interface(struct ulpi *ulpi) { + of_node_put(ulpi->dev.of_node); device_unregister(&ulpi->dev); } EXPORT_SYMBOL_GPL(ulpi_unregister_interface); diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 4016dae7433b..52747b6ac89a 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -134,42 +134,35 @@ enum snoop_when { #define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0) /* Limit on the total amount of memory we can allocate for transfers */ -static unsigned usbfs_memory_mb = 16; +static u32 usbfs_memory_mb = 16; module_param(usbfs_memory_mb, uint, 0644); MODULE_PARM_DESC(usbfs_memory_mb, "maximum MB allowed for usbfs buffers (0 = no limit)"); -/* Hard limit, necessary to avoid arithmetic overflow */ -#define USBFS_XFER_MAX (UINT_MAX / 2 - 1000000) - -static atomic_t usbfs_memory_usage; /* Total memory currently allocated */ +static atomic64_t usbfs_memory_usage; /* Total memory currently allocated */ /* Check whether it's okay to allocate more memory for a transfer */ -static int usbfs_increase_memory_usage(unsigned amount) +static int usbfs_increase_memory_usage(u64 amount) { - unsigned lim; + u64 lim; - /* - * Convert usbfs_memory_mb to bytes, avoiding overflows. - * 0 means use the hard limit (effectively unlimited). - */ lim = ACCESS_ONCE(usbfs_memory_mb); - if (lim == 0 || lim > (USBFS_XFER_MAX >> 20)) - lim = USBFS_XFER_MAX; - else - lim <<= 20; + lim <<= 20; - atomic_add(amount, &usbfs_memory_usage); - if (atomic_read(&usbfs_memory_usage) <= lim) - return 0; - atomic_sub(amount, &usbfs_memory_usage); - return -ENOMEM; + atomic64_add(amount, &usbfs_memory_usage); + + if (lim > 0 && atomic64_read(&usbfs_memory_usage) > lim) { + atomic64_sub(amount, &usbfs_memory_usage); + return -ENOMEM; + } + + return 0; } /* Memory for a transfer is being deallocated */ -static void usbfs_decrease_memory_usage(unsigned amount) +static void usbfs_decrease_memory_usage(u64 amount) { - atomic_sub(amount, &usbfs_memory_usage); + atomic64_sub(amount, &usbfs_memory_usage); } static int connected(struct usb_dev_state *ps) @@ -1191,7 +1184,7 @@ static int proc_bulk(struct usb_dev_state *ps, void __user *arg) if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN))) return -EINVAL; len1 = bulk.len; - if (len1 >= USBFS_XFER_MAX) + if (len1 >= (INT_MAX - sizeof(struct urb))) return -EINVAL; ret = usbfs_increase_memory_usage(len1 + sizeof(struct urb)); if (ret) @@ -1584,10 +1577,6 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb return -EINVAL; } - if (uurb->buffer_length >= USBFS_XFER_MAX) { - ret = -EINVAL; - goto error; - } if (uurb->buffer_length > 0 && !access_ok(is_in ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) { diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 479e223f9cff..612fab6e54fb 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -3017,6 +3017,7 @@ void usb_remove_hcd(struct usb_hcd *hcd) } usb_put_invalidate_rhdev(hcd); + hcd->flags = 0; } EXPORT_SYMBOL_GPL(usb_remove_hcd); diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index dea55914d641..2184ef40a82a 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -122,12 +122,11 @@ static int usb_internal_control_msg(struct usb_device *usb_dev, * This function sends a simple control message to a specified endpoint and * waits for the message to complete, or timeout. * - * Don't use this function from within an interrupt context, like a bottom half - * handler. If you need an asynchronous message, or need to send a message - * from within interrupt context, use usb_submit_urb(). - * If a thread in your driver uses this call, make sure your disconnect() - * method can wait for it to complete. Since you don't have a handle on the - * URB used, you can't cancel the request. + * Don't use this function from within an interrupt context. If you need + * an asynchronous message, or need to send a message from within interrupt + * context, use usb_submit_urb(). If a thread in your driver uses this call, + * make sure your disconnect() method can wait for it to complete. Since you + * don't have a handle on the URB used, you can't cancel the request. * * Return: If successful, the number of bytes transferred. Otherwise, a negative * error number. @@ -173,12 +172,11 @@ EXPORT_SYMBOL_GPL(usb_control_msg); * This function sends a simple interrupt message to a specified endpoint and * waits for the message to complete, or timeout. * - * Don't use this function from within an interrupt context, like a bottom half - * handler. If you need an asynchronous message, or need to send a message - * from within interrupt context, use usb_submit_urb() If a thread in your - * driver uses this call, make sure your disconnect() method can wait for it to - * complete. Since you don't have a handle on the URB used, you can't cancel - * the request. + * Don't use this function from within an interrupt context. If you need + * an asynchronous message, or need to send a message from within interrupt + * context, use usb_submit_urb() If a thread in your driver uses this call, + * make sure your disconnect() method can wait for it to complete. Since you + * don't have a handle on the URB used, you can't cancel the request. * * Return: * If successful, 0. Otherwise a negative error number. The number of actual @@ -207,12 +205,11 @@ EXPORT_SYMBOL_GPL(usb_interrupt_msg); * This function sends a simple bulk message to a specified endpoint * and waits for the message to complete, or timeout. * - * Don't use this function from within an interrupt context, like a bottom half - * handler. If you need an asynchronous message, or need to send a message - * from within interrupt context, use usb_submit_urb() If a thread in your - * driver uses this call, make sure your disconnect() method can wait for it to - * complete. Since you don't have a handle on the URB used, you can't cancel - * the request. + * Don't use this function from within an interrupt context. If you need + * an asynchronous message, or need to send a message from within interrupt + * context, use usb_submit_urb() If a thread in your driver uses this call, + * make sure your disconnect() method can wait for it to complete. Since you + * don't have a handle on the URB used, you can't cancel the request. * * Because there is no usb_interrupt_msg() and no USBDEVFS_INTERRUPT ioctl, * users are forced to abuse this routine by using it to submit URBs for diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c index 11d8ae9aead1..1b6612c2cdda 100644 --- a/drivers/usb/dwc2/core.c +++ b/drivers/usb/dwc2/core.c @@ -104,7 +104,7 @@ static int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg) gr = &hsotg->gr_backup; if (!gr->valid) { dev_err(hsotg->dev, "%s: no global registers to restore\n", - __func__); + __func__); return -EINVAL; } gr->valid = false; @@ -155,21 +155,21 @@ int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, bool restore) ret = dwc2_restore_global_registers(hsotg); if (ret) { dev_err(hsotg->dev, "%s: failed to restore registers\n", - __func__); + __func__); return ret; } if (dwc2_is_host_mode(hsotg)) { ret = dwc2_restore_host_registers(hsotg); if (ret) { dev_err(hsotg->dev, "%s: failed to restore host registers\n", - __func__); + __func__); return ret; } } else { ret = dwc2_restore_device_registers(hsotg); if (ret) { dev_err(hsotg->dev, "%s: failed to restore device registers\n", - __func__); + __func__); return ret; } } @@ -195,7 +195,7 @@ int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg) ret = dwc2_backup_global_registers(hsotg); if (ret) { dev_err(hsotg->dev, "%s: failed to backup global registers\n", - __func__); + __func__); return ret; } @@ -203,14 +203,14 @@ int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg) ret = dwc2_backup_host_registers(hsotg); if (ret) { dev_err(hsotg->dev, "%s: failed to backup host registers\n", - __func__); + __func__); return ret; } } else { ret = dwc2_backup_device_registers(hsotg); if (ret) { dev_err(hsotg->dev, "%s: failed to backup device registers\n", - __func__); + __func__); return ret; } } @@ -313,7 +313,7 @@ static bool dwc2_iddig_filter_enabled(struct dwc2_hsotg *hsotg) * Do core a soft reset of the core. Be careful with this because it * resets all the internal state machines of the core. */ -int dwc2_core_reset(struct dwc2_hsotg *hsotg) +int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait) { u32 greset; int count = 0; @@ -369,7 +369,7 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg) } } while (!(greset & GRSTCTL_AHBIDLE)); - if (wait_for_host_mode) + if (wait_for_host_mode && !skip_wait) dwc2_wait_for_mode(hsotg, true); return 0; @@ -455,7 +455,7 @@ void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg) dwc2_writel(gusbcfg, hsotg->regs + GUSBCFG); if (dwc2_iddig_filter_enabled(hsotg)) - usleep_range(100000, 110000); + msleep(100); } /* @@ -500,7 +500,7 @@ int dwc2_core_reset_and_force_dr_mode(struct dwc2_hsotg *hsotg) { int retval; - retval = dwc2_core_reset(hsotg); + retval = dwc2_core_reset(hsotg, false); if (retval) return retval; @@ -541,7 +541,7 @@ void dwc2_dump_host_registers(struct dwc2_hsotg *hsotg) addr = hsotg->regs + HAINTMSK; dev_dbg(hsotg->dev, "HAINTMSK @0x%08lX : 0x%08X\n", (unsigned long)addr, dwc2_readl(addr)); - if (hsotg->params.dma_desc_enable > 0) { + if (hsotg->params.dma_desc_enable) { addr = hsotg->regs + HFLBADDR; dev_dbg(hsotg->dev, "HFLBADDR @0x%08lX : 0x%08X\n", (unsigned long)addr, dwc2_readl(addr)); @@ -571,7 +571,7 @@ void dwc2_dump_host_registers(struct dwc2_hsotg *hsotg) addr = hsotg->regs + HCDMA(i); dev_dbg(hsotg->dev, "HCDMA @0x%08lX : 0x%08X\n", (unsigned long)addr, dwc2_readl(addr)); - if (hsotg->params.dma_desc_enable > 0) { + if (hsotg->params.dma_desc_enable) { addr = hsotg->regs + HCDMAB(i); dev_dbg(hsotg->dev, "HCDMAB @0x%08lX : 0x%08X\n", (unsigned long)addr, dwc2_readl(addr)); @@ -751,11 +751,6 @@ bool dwc2_force_mode_if_needed(struct dwc2_hsotg *hsotg, bool host) return dwc2_force_mode(hsotg, host); } -u16 dwc2_get_otg_version(struct dwc2_hsotg *hsotg) -{ - return hsotg->params.otg_ver == 1 ? 0x0200 : 0x0103; -} - bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg) { if (dwc2_readl(hsotg->regs + GSNPSID) == 0xffffffff) @@ -793,7 +788,7 @@ void dwc2_disable_global_interrupts(struct dwc2_hsotg *hsotg) } /* Returns the controller's GHWCFG2.OTG_MODE. */ -unsigned dwc2_op_mode(struct dwc2_hsotg *hsotg) +unsigned int dwc2_op_mode(struct dwc2_hsotg *hsotg) { u32 ghwcfg2 = dwc2_readl(hsotg->regs + GHWCFG2); @@ -804,7 +799,7 @@ unsigned dwc2_op_mode(struct dwc2_hsotg *hsotg) /* Returns true if the controller is capable of DRD. */ bool dwc2_hw_is_otg(struct dwc2_hsotg *hsotg) { - unsigned op_mode = dwc2_op_mode(hsotg); + unsigned int op_mode = dwc2_op_mode(hsotg); return (op_mode == GHWCFG2_OP_MODE_HNP_SRP_CAPABLE) || (op_mode == GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE) || @@ -814,7 +809,7 @@ bool dwc2_hw_is_otg(struct dwc2_hsotg *hsotg) /* Returns true if the controller is host-only. */ bool dwc2_hw_is_host(struct dwc2_hsotg *hsotg) { - unsigned op_mode = dwc2_op_mode(hsotg); + unsigned int op_mode = dwc2_op_mode(hsotg); return (op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_HOST) || (op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_HOST); @@ -823,7 +818,7 @@ bool dwc2_hw_is_host(struct dwc2_hsotg *hsotg) /* Returns true if the controller is device-only. */ bool dwc2_hw_is_device(struct dwc2_hsotg *hsotg) { - unsigned op_mode = dwc2_op_mode(hsotg); + unsigned int op_mode = dwc2_op_mode(hsotg); return (op_mode == GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE) || (op_mode == GHWCFG2_OP_MODE_NO_SRP_CAPABLE_DEVICE); diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 302b8f5f7d27..1a7e83005082 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -127,6 +127,8 @@ static const char * const dwc2_hsotg_supply_names[] = { "vusb_a", /* analog USB supply, 1.1V */ }; +#define DWC2_NUM_SUPPLIES ARRAY_SIZE(dwc2_hsotg_supply_names) + /* * EP0_MPS_LIMIT * @@ -246,7 +248,8 @@ struct dwc2_hsotg_req { void *saved_req_buf; }; -#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) +#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \ + IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) #define call_gadget(_hs, _entry) \ do { \ if ((_hs)->gadget.speed != USB_SPEED_UNKNOWN && \ @@ -271,13 +274,6 @@ enum dwc2_lx_state { DWC2_L3, /* Off state */ }; -/* - * Gadget periodic tx fifo sizes as used by legacy driver - * EP0 is not included - */ -#define DWC2_G_P_LEGACY_TX_FIFO_SIZE {256, 256, 256, 256, 768, 768, 768, \ - 768, 0, 0, 0, 0, 0, 0, 0} - /* Gadget ep0 states */ enum dwc2_ep0_state { DWC2_EP0_SETUP, @@ -295,9 +291,6 @@ enum dwc2_ep0_state { * 1 - SRP Only capable * 2 - No HNP/SRP capable (always available) * Defaults to best available option (0, 1, then 2) - * @otg_ver: OTG version supported - * 0 - 1.3 (default) - * 1 - 2.0 * @host_dma: Specifies whether to use slave or DMA mode for accessing * the data FIFOs. The driver will automatically detect the * value for this parameter if none is specified. @@ -444,6 +437,11 @@ enum dwc2_ep0_state { * in DWORDS with possible values from from * 16-32768 (default: 256, 256, 256, 256, 768, * 768, 768, 768, 0, 0, 0, 0, 0, 0, 0). + * @change_speed_quirk: Change speed configuration to DWC2_SPEED_PARAM_FULL + * while full&low speed device connect. And change speed + * back to DWC2_SPEED_PARAM_HIGH while device is gone. + * 0 - No (default) + * 1 - Yes * * The following parameters may be specified when starting the module. These * parameters define how the DWC_otg controller should be configured. A @@ -452,63 +450,48 @@ enum dwc2_ep0_state { * default described above. */ struct dwc2_core_params { - /* - * Don't add any non-int members here, this will break - * dwc2_set_all_params! - */ - int otg_cap; + u8 otg_cap; #define DWC2_CAP_PARAM_HNP_SRP_CAPABLE 0 #define DWC2_CAP_PARAM_SRP_ONLY_CAPABLE 1 #define DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE 2 - int otg_ver; - int dma_desc_enable; - int dma_desc_fs_enable; - int speed; -#define DWC2_SPEED_PARAM_HIGH 0 -#define DWC2_SPEED_PARAM_FULL 1 -#define DWC2_SPEED_PARAM_LOW 2 - - int enable_dynamic_fifo; - int en_multiple_tx_fifo; - int host_rx_fifo_size; - int host_nperio_tx_fifo_size; - int host_perio_tx_fifo_size; - int max_transfer_size; - int max_packet_count; - int host_channels; - int phy_type; + u8 phy_type; #define DWC2_PHY_TYPE_PARAM_FS 0 #define DWC2_PHY_TYPE_PARAM_UTMI 1 #define DWC2_PHY_TYPE_PARAM_ULPI 2 - int phy_utmi_width; - int phy_ulpi_ddr; - int phy_ulpi_ext_vbus; -#define DWC2_PHY_ULPI_INTERNAL_VBUS 0 -#define DWC2_PHY_ULPI_EXTERNAL_VBUS 1 - - int i2c_enable; - int ulpi_fs_ls; - int host_support_fs_ls_low_power; - int host_ls_low_power_phy_clk; -#define DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ 0 -#define DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ 1 - - int ts_dline; - int reload_ctl; - int ahbcfg; - int uframe_sched; - int external_id_pin_ctl; - int hibernation; + u8 speed; +#define DWC2_SPEED_PARAM_HIGH 0 +#define DWC2_SPEED_PARAM_FULL 1 +#define DWC2_SPEED_PARAM_LOW 2 - /* - * The following parameters are *only* set via device - * properties and cannot be set directly in this structure. - */ + u8 phy_utmi_width; + bool phy_ulpi_ddr; + bool phy_ulpi_ext_vbus; + bool enable_dynamic_fifo; + bool en_multiple_tx_fifo; + bool i2c_enable; + bool ulpi_fs_ls; + bool ts_dline; + bool reload_ctl; + bool uframe_sched; + bool external_id_pin_ctl; + bool hibernation; + u16 max_packet_count; + u32 max_transfer_size; + u32 ahbcfg; /* Host parameters */ bool host_dma; + bool dma_desc_enable; + bool dma_desc_fs_enable; + bool host_support_fs_ls_low_power; + bool host_ls_low_power_phy_clk; + + u8 host_channels; + u16 host_rx_fifo_size; + u16 host_nperio_tx_fifo_size; + u16 host_perio_tx_fifo_size; /* Gadget parameters */ bool g_dma; @@ -516,6 +499,8 @@ struct dwc2_core_params { u32 g_rx_fifo_size; u32 g_np_tx_fifo_size; u32 g_tx_fifo_size[MAX_EPS_CHANNELS]; + + bool change_speed_quirk; }; /** @@ -603,8 +588,8 @@ struct dwc2_hw_params { #define DWC2_CTRL_BUFF_SIZE 8 /** - * struct dwc2_gregs_backup - Holds global registers state before entering partial - * power down + * struct dwc2_gregs_backup - Holds global registers state before + * entering partial power down * @gotgctl: Backup of GOTGCTL register * @gintmsk: Backup of GINTMSK register * @gahbcfg: Backup of GAHBCFG register @@ -634,8 +619,8 @@ struct dwc2_gregs_backup { }; /** - * struct dwc2_dregs_backup - Holds device registers state before entering partial - * power down + * struct dwc2_dregs_backup - Holds device registers state before + * entering partial power down * @dcfg: Backup of DCFG register * @dctl: Backup of DCTL register * @daintmsk: Backup of DAINTMSK register @@ -664,8 +649,8 @@ struct dwc2_dregs_backup { }; /** - * struct dwc2_hregs_backup - Holds host registers state before entering partial - * power down + * struct dwc2_hregs_backup - Holds host registers state before + * entering partial power down * @hcfg: Backup of HCFG register * @haintmsk: Backup of HAINTMSK register * @hcintmsk: Backup of HCINTMSK register @@ -782,9 +767,10 @@ struct dwc2_hregs_backup { * @gadget_enabled Peripheral mode sub-driver initialization indicator. * @ll_hw_enabled Status of low-level hardware resources. * @phy: The otg phy transceiver structure for phy control. - * @uphy: The otg phy transceiver structure for old USB phy control. - * @plat: The platform specific configuration data. This can be removed once - * all SoCs support usb transceiver. + * @uphy: The otg phy transceiver structure for old USB phy + * control. + * @plat: The platform specific configuration data. This can be + * removed once all SoCs support usb transceiver. * @supplies: Definition of USB power supplies * @phyif: PHY interface width * @lock: Spinlock that protects all the driver data structures @@ -921,7 +907,7 @@ struct dwc2_hsotg { struct phy *phy; struct usb_phy *uphy; struct dwc2_hsotg_plat *plat; - struct regulator_bulk_data supplies[ARRAY_SIZE(dwc2_hsotg_supply_names)]; + struct regulator_bulk_data supplies[DWC2_NUM_SUPPLIES]; u32 phyif; spinlock_t lock; @@ -947,6 +933,7 @@ struct dwc2_hsotg { /* DWC OTG HW Release versions */ #define DWC2_CORE_REV_2_71a 0x4f54271a #define DWC2_CORE_REV_2_90a 0x4f54290a +#define DWC2_CORE_REV_2_91a 0x4f54291a #define DWC2_CORE_REV_2_92a 0x4f54292a #define DWC2_CORE_REV_2_94a 0x4f54294a #define DWC2_CORE_REV_3_00a 0x4f54300a @@ -1033,7 +1020,8 @@ struct dwc2_hsotg { #endif #endif /* CONFIG_USB_DWC2_HOST || CONFIG_USB_DWC2_DUAL_ROLE */ -#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) +#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \ + IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) /* Gadget structures */ struct usb_gadget_driver *driver; int fifo_mem; @@ -1101,37 +1089,37 @@ static inline bool dwc2_is_hs_iot(struct dwc2_hsotg *hsotg) * The following functions support initialization of the core driver component * and the DWC_otg controller */ -extern int dwc2_core_reset(struct dwc2_hsotg *hsotg); -extern int dwc2_core_reset_and_force_dr_mode(struct dwc2_hsotg *hsotg); -extern int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg); -extern int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, bool restore); +int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait); +int dwc2_core_reset_and_force_dr_mode(struct dwc2_hsotg *hsotg); +int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg); +int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, bool restore); bool dwc2_force_mode_if_needed(struct dwc2_hsotg *hsotg, bool host); void dwc2_clear_force_mode(struct dwc2_hsotg *hsotg); void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg); -extern bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg); +bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg); /* * Common core Functions. * The following functions support managing the DWC_otg controller in either * device or host mode. */ -extern void dwc2_read_packet(struct dwc2_hsotg *hsotg, u8 *dest, u16 bytes); -extern void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num); -extern void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg); +void dwc2_read_packet(struct dwc2_hsotg *hsotg, u8 *dest, u16 bytes); +void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num); +void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg); -extern void dwc2_enable_global_interrupts(struct dwc2_hsotg *hcd); -extern void dwc2_disable_global_interrupts(struct dwc2_hsotg *hcd); +void dwc2_enable_global_interrupts(struct dwc2_hsotg *hcd); +void dwc2_disable_global_interrupts(struct dwc2_hsotg *hcd); /* This function should be called on every hardware interrupt. */ -extern irqreturn_t dwc2_handle_common_intr(int irq, void *dev); +irqreturn_t dwc2_handle_common_intr(int irq, void *dev); /* The device ID match table */ extern const struct of_device_id dwc2_of_match_table[]; -extern int dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg); -extern int dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg); +int dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg); +int dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg); /* Parameters */ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg); @@ -1145,7 +1133,7 @@ int dwc2_init_params(struct dwc2_hsotg *hsotg); * are read in and cached so they always read directly from the * GHWCFG2 register. */ -unsigned dwc2_op_mode(struct dwc2_hsotg *hsotg); +unsigned int dwc2_op_mode(struct dwc2_hsotg *hsotg); bool dwc2_hw_is_otg(struct dwc2_hsotg *hsotg); bool dwc2_hw_is_host(struct dwc2_hsotg *hsotg); bool dwc2_hw_is_device(struct dwc2_hsotg *hsotg); @@ -1157,6 +1145,7 @@ static inline int dwc2_is_host_mode(struct dwc2_hsotg *hsotg) { return (dwc2_readl(hsotg->regs + GINTSTS) & GINTSTS_CURMODE_HOST) != 0; } + static inline int dwc2_is_device_mode(struct dwc2_hsotg *hsotg) { return (dwc2_readl(hsotg->regs + GINTSTS) & GINTSTS_CURMODE_HOST) == 0; @@ -1165,29 +1154,28 @@ static inline int dwc2_is_device_mode(struct dwc2_hsotg *hsotg) /* * Dump core registers and SPRAM */ -extern void dwc2_dump_dev_registers(struct dwc2_hsotg *hsotg); -extern void dwc2_dump_host_registers(struct dwc2_hsotg *hsotg); -extern void dwc2_dump_global_registers(struct dwc2_hsotg *hsotg); - -/* - * Return OTG version - either 1.3 or 2.0 - */ -extern u16 dwc2_get_otg_version(struct dwc2_hsotg *hsotg); +void dwc2_dump_dev_registers(struct dwc2_hsotg *hsotg); +void dwc2_dump_host_registers(struct dwc2_hsotg *hsotg); +void dwc2_dump_global_registers(struct dwc2_hsotg *hsotg); /* Gadget defines */ -#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) -extern int dwc2_hsotg_remove(struct dwc2_hsotg *hsotg); -extern int dwc2_hsotg_suspend(struct dwc2_hsotg *dwc2); -extern int dwc2_hsotg_resume(struct dwc2_hsotg *dwc2); -extern int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq); -extern void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2, - bool reset); -extern void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg); -extern void dwc2_hsotg_disconnect(struct dwc2_hsotg *dwc2); -extern int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode); +#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || \ + IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) +int dwc2_hsotg_remove(struct dwc2_hsotg *hsotg); +int dwc2_hsotg_suspend(struct dwc2_hsotg *dwc2); +int dwc2_hsotg_resume(struct dwc2_hsotg *dwc2); +int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq); +void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2, + bool reset); +void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg); +void dwc2_hsotg_disconnect(struct dwc2_hsotg *dwc2); +int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode); #define dwc2_is_device_connected(hsotg) (hsotg->connected) int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg); int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg); +int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg); +int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg); +int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg); #else static inline int dwc2_hsotg_remove(struct dwc2_hsotg *dwc2) { return 0; } @@ -1198,25 +1186,31 @@ static inline int dwc2_hsotg_resume(struct dwc2_hsotg *dwc2) static inline int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq) { return 0; } static inline void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2, - bool reset) {} + bool reset) {} static inline void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg) {} static inline void dwc2_hsotg_disconnect(struct dwc2_hsotg *dwc2) {} static inline int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, - int testmode) + int testmode) { return 0; } #define dwc2_is_device_connected(hsotg) (0) static inline int dwc2_backup_device_registers(struct dwc2_hsotg *hsotg) { return 0; } static inline int dwc2_restore_device_registers(struct dwc2_hsotg *hsotg) { return 0; } +static inline int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg) +{ return 0; } +static inline int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg) +{ return 0; } +static inline int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg) +{ return 0; } #endif #if IS_ENABLED(CONFIG_USB_DWC2_HOST) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE) -extern int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg); -extern int dwc2_hcd_get_future_frame_number(struct dwc2_hsotg *hsotg, int us); -extern void dwc2_hcd_connect(struct dwc2_hsotg *hsotg); -extern void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool force); -extern void dwc2_hcd_start(struct dwc2_hsotg *hsotg); +int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg); +int dwc2_hcd_get_future_frame_number(struct dwc2_hsotg *hsotg, int us); +void dwc2_hcd_connect(struct dwc2_hsotg *hsotg); +void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool force); +void dwc2_hcd_start(struct dwc2_hsotg *hsotg); int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg); int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg); #else @@ -1229,7 +1223,7 @@ static inline void dwc2_hcd_connect(struct dwc2_hsotg *hsotg) {} static inline void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg, bool force) {} static inline void dwc2_hcd_start(struct dwc2_hsotg *hsotg) {} static inline void dwc2_hcd_remove(struct dwc2_hsotg *hsotg) {} -static inline int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq) +static inline int dwc2_hcd_init(struct dwc2_hsotg *hsotg) { return 0; } static inline int dwc2_backup_host_registers(struct dwc2_hsotg *hsotg) { return 0; } diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c index 5b228ba6045f..b8bcb007c92a 100644 --- a/drivers/usb/dwc2/core_intr.c +++ b/drivers/usb/dwc2/core_intr.c @@ -159,9 +159,8 @@ static void dwc2_handle_otg_intr(struct dwc2_hsotg *hsotg) " ++OTG Interrupt: Session Request Success Status Change++\n"); gotgctl = dwc2_readl(hsotg->regs + GOTGCTL); if (gotgctl & GOTGCTL_SESREQSCS) { - if (hsotg->params.phy_type == - DWC2_PHY_TYPE_PARAM_FS - && hsotg->params.i2c_enable > 0) { + if (hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS && + hsotg->params.i2c_enable) { hsotg->srp_success = 1; } else { /* Clear Session Request */ @@ -317,7 +316,7 @@ static void dwc2_handle_session_req_intr(struct dwc2_hsotg *hsotg) dwc2_writel(GINTSTS_SESSREQINT, hsotg->regs + GINTSTS); dev_dbg(hsotg->dev, "Session request interrupt - lx_state=%d\n", - hsotg->lx_state); + hsotg->lx_state); if (dwc2_is_device_mode(hsotg)) { if (hsotg->lx_state == DWC2_L2) { @@ -437,7 +436,7 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg) /* Ignore suspend request before enumeration */ if (!dwc2_is_device_connected(hsotg)) { dev_dbg(hsotg->dev, - "ignore suspend request before enumeration\n"); + "ignore suspend request before enumeration\n"); return; } @@ -445,7 +444,7 @@ static void dwc2_handle_usb_suspend_intr(struct dwc2_hsotg *hsotg) if (ret) { if (ret != -ENOTSUPP) dev_err(hsotg->dev, - "enter hibernation failed\n"); + "enter hibernation failed\n"); goto skip_power_saving; } diff --git a/drivers/usb/dwc2/debug.h b/drivers/usb/dwc2/debug.h index 12dbd1daec87..8222783e6822 100644 --- a/drivers/usb/dwc2/debug.h +++ b/drivers/usb/dwc2/debug.h @@ -17,8 +17,8 @@ #include "core.h" #ifdef CONFIG_DEBUG_FS -extern int dwc2_debugfs_init(struct dwc2_hsotg *); -extern void dwc2_debugfs_exit(struct dwc2_hsotg *); +int dwc2_debugfs_init(struct dwc2_hsotg *hsotg); +void dwc2_debugfs_exit(struct dwc2_hsotg *hsotg); #else static inline int dwc2_debugfs_init(struct dwc2_hsotg *hsotg) { return 0; } diff --git a/drivers/usb/dwc2/debugfs.c b/drivers/usb/dwc2/debugfs.c index 0a130916a91c..794b959a7c8c 100644 --- a/drivers/usb/dwc2/debugfs.c +++ b/drivers/usb/dwc2/debugfs.c @@ -137,7 +137,7 @@ static int state_show(struct seq_file *seq, void *v) int idx; seq_printf(seq, "DCFG=0x%08x, DCTL=0x%08x, DSTS=0x%08x\n", - dwc2_readl(regs + DCFG), + dwc2_readl(regs + DCFG), dwc2_readl(regs + DCTL), dwc2_readl(regs + DSTS)); @@ -338,23 +338,23 @@ static void dwc2_hsotg_create_debug(struct dwc2_hsotg *hsotg) { struct dentry *root; struct dentry *file; - unsigned epidx; + unsigned int epidx; root = hsotg->debug_root; /* create general state file */ - file = debugfs_create_file("state", S_IRUGO, root, hsotg, &state_fops); + file = debugfs_create_file("state", 0444, root, hsotg, &state_fops); if (IS_ERR(file)) dev_err(hsotg->dev, "%s: failed to create state\n", __func__); - file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root, hsotg, - &testmode_fops); + file = debugfs_create_file("testmode", 0644, root, hsotg, + &testmode_fops); if (IS_ERR(file)) dev_err(hsotg->dev, "%s: failed to create testmode\n", - __func__); + __func__); - file = debugfs_create_file("fifo", S_IRUGO, root, hsotg, &fifo_fops); + file = debugfs_create_file("fifo", 0444, root, hsotg, &fifo_fops); if (IS_ERR(file)) dev_err(hsotg->dev, "%s: failed to create fifo\n", __func__); @@ -364,8 +364,8 @@ static void dwc2_hsotg_create_debug(struct dwc2_hsotg *hsotg) ep = hsotg->eps_out[epidx]; if (ep) { - file = debugfs_create_file(ep->name, S_IRUGO, - root, ep, &ep_fops); + file = debugfs_create_file(ep->name, 0444, + root, ep, &ep_fops); if (IS_ERR(file)) dev_err(hsotg->dev, "failed to create %s debug file\n", ep->name); @@ -377,8 +377,8 @@ static void dwc2_hsotg_create_debug(struct dwc2_hsotg *hsotg) ep = hsotg->eps_in[epidx]; if (ep) { - file = debugfs_create_file(ep->name, S_IRUGO, - root, ep, &ep_fops); + file = debugfs_create_file(ep->name, 0444, + root, ep, &ep_fops); if (IS_ERR(file)) dev_err(hsotg->dev, "failed to create %s debug file\n", ep->name); @@ -725,6 +725,143 @@ static const struct debugfs_reg32 dwc2_regs[] = { dump_register(HCDMAB(15)), }; +#define print_param(_seq, _ptr, _param) \ +seq_printf((_seq), "%-30s: %d\n", #_param, (_ptr)->_param) + +#define print_param_hex(_seq, _ptr, _param) \ +seq_printf((_seq), "%-30s: 0x%x\n", #_param, (_ptr)->_param) + +static int params_show(struct seq_file *seq, void *v) +{ + struct dwc2_hsotg *hsotg = seq->private; + struct dwc2_core_params *p = &hsotg->params; + int i; + + print_param(seq, p, otg_cap); + print_param(seq, p, dma_desc_enable); + print_param(seq, p, dma_desc_fs_enable); + print_param(seq, p, speed); + print_param(seq, p, enable_dynamic_fifo); + print_param(seq, p, en_multiple_tx_fifo); + print_param(seq, p, host_rx_fifo_size); + print_param(seq, p, host_nperio_tx_fifo_size); + print_param(seq, p, host_perio_tx_fifo_size); + print_param(seq, p, max_transfer_size); + print_param(seq, p, max_packet_count); + print_param(seq, p, host_channels); + print_param(seq, p, phy_type); + print_param(seq, p, phy_utmi_width); + print_param(seq, p, phy_ulpi_ddr); + print_param(seq, p, phy_ulpi_ext_vbus); + print_param(seq, p, i2c_enable); + print_param(seq, p, ulpi_fs_ls); + print_param(seq, p, host_support_fs_ls_low_power); + print_param(seq, p, host_ls_low_power_phy_clk); + print_param(seq, p, ts_dline); + print_param(seq, p, reload_ctl); + print_param_hex(seq, p, ahbcfg); + print_param(seq, p, uframe_sched); + print_param(seq, p, external_id_pin_ctl); + print_param(seq, p, hibernation); + print_param(seq, p, host_dma); + print_param(seq, p, g_dma); + print_param(seq, p, g_dma_desc); + print_param(seq, p, g_rx_fifo_size); + print_param(seq, p, g_np_tx_fifo_size); + + for (i = 0; i < MAX_EPS_CHANNELS; i++) { + char str[32]; + + snprintf(str, 32, "g_tx_fifo_size[%d]", i); + seq_printf(seq, "%-30s: %d\n", str, p->g_tx_fifo_size[i]); + } + + return 0; +} + +static int params_open(struct inode *inode, struct file *file) +{ + return single_open(file, params_show, inode->i_private); +} + +static const struct file_operations params_fops = { + .owner = THIS_MODULE, + .open = params_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int hw_params_show(struct seq_file *seq, void *v) +{ + struct dwc2_hsotg *hsotg = seq->private; + struct dwc2_hw_params *hw = &hsotg->hw_params; + + print_param(seq, hw, op_mode); + print_param(seq, hw, arch); + print_param(seq, hw, dma_desc_enable); + print_param(seq, hw, enable_dynamic_fifo); + print_param(seq, hw, en_multiple_tx_fifo); + print_param(seq, hw, rx_fifo_size); + print_param(seq, hw, host_nperio_tx_fifo_size); + print_param(seq, hw, dev_nperio_tx_fifo_size); + print_param(seq, hw, host_perio_tx_fifo_size); + print_param(seq, hw, nperio_tx_q_depth); + print_param(seq, hw, host_perio_tx_q_depth); + print_param(seq, hw, dev_token_q_depth); + print_param(seq, hw, max_transfer_size); + print_param(seq, hw, max_packet_count); + print_param(seq, hw, host_channels); + print_param(seq, hw, hs_phy_type); + print_param(seq, hw, fs_phy_type); + print_param(seq, hw, i2c_enable); + print_param(seq, hw, num_dev_ep); + print_param(seq, hw, num_dev_perio_in_ep); + print_param(seq, hw, total_fifo_size); + print_param(seq, hw, power_optimized); + print_param(seq, hw, utmi_phy_data_width); + print_param_hex(seq, hw, snpsid); + print_param_hex(seq, hw, dev_ep_dirs); + + return 0; +} + +static int hw_params_open(struct inode *inode, struct file *file) +{ + return single_open(file, hw_params_show, inode->i_private); +} + +static const struct file_operations hw_params_fops = { + .owner = THIS_MODULE, + .open = hw_params_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static int dr_mode_show(struct seq_file *seq, void *v) +{ + struct dwc2_hsotg *hsotg = seq->private; + const char *dr_mode = ""; + + device_property_read_string(hsotg->dev, "dr_mode", &dr_mode); + seq_printf(seq, "%s\n", dr_mode); + return 0; +} + +static int dr_mode_open(struct inode *inode, struct file *file) +{ + return single_open(file, dr_mode_show, inode->i_private); +} + +static const struct file_operations dr_mode_fops = { + .owner = THIS_MODULE, + .open = dr_mode_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + int dwc2_debugfs_init(struct dwc2_hsotg *hsotg) { int ret; @@ -736,6 +873,25 @@ int dwc2_debugfs_init(struct dwc2_hsotg *hsotg) goto err0; } + file = debugfs_create_file("params", 0444, + hsotg->debug_root, + hsotg, ¶ms_fops); + if (IS_ERR(file)) + dev_err(hsotg->dev, "%s: failed to create params\n", __func__); + + file = debugfs_create_file("hw_params", 0444, + hsotg->debug_root, + hsotg, &hw_params_fops); + if (IS_ERR(file)) + dev_err(hsotg->dev, "%s: failed to create hw_params\n", + __func__); + + file = debugfs_create_file("dr_mode", 0444, + hsotg->debug_root, + hsotg, &dr_mode_fops); + if (IS_ERR(file)) + dev_err(hsotg->dev, "%s: failed to create dr_mode\n", __func__); + /* Add gadget debugfs nodes */ dwc2_hsotg_create_debug(hsotg); @@ -750,8 +906,8 @@ int dwc2_debugfs_init(struct dwc2_hsotg *hsotg) hsotg->regset->nregs = ARRAY_SIZE(dwc2_regs); hsotg->regset->base = hsotg->regs; - file = debugfs_create_regset32("regdump", S_IRUGO, hsotg->debug_root, - hsotg->regset); + file = debugfs_create_regset32("regdump", 0444, hsotg->debug_root, + hsotg->regset); if (!file) { ret = -ENOMEM; goto err1; diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 77c5fcf3a5bf..bc3b3fda5000 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c @@ -171,7 +171,7 @@ static void dwc2_hsotg_disable_gsint(struct dwc2_hsotg *hsotg, u32 ints) * request. */ static void dwc2_hsotg_ctrl_epint(struct dwc2_hsotg *hsotg, - unsigned int ep, unsigned int dir_in, + unsigned int ep, unsigned int dir_in, unsigned int en) { unsigned long flags; @@ -192,6 +192,99 @@ static void dwc2_hsotg_ctrl_epint(struct dwc2_hsotg *hsotg, } /** + * dwc2_hsotg_tx_fifo_count - return count of TX FIFOs in device mode + */ +int dwc2_hsotg_tx_fifo_count(struct dwc2_hsotg *hsotg) +{ + if (hsotg->hw_params.en_multiple_tx_fifo) + /* In dedicated FIFO mode we need count of IN EPs */ + return (dwc2_readl(hsotg->regs + GHWCFG4) & + GHWCFG4_NUM_IN_EPS_MASK) >> GHWCFG4_NUM_IN_EPS_SHIFT; + else + /* In shared FIFO mode we need count of Periodic IN EPs */ + return hsotg->hw_params.num_dev_perio_in_ep; +} + +/** + * dwc2_hsotg_ep_info_size - return Endpoint Info Control block size in DWORDs + */ +static int dwc2_hsotg_ep_info_size(struct dwc2_hsotg *hsotg) +{ + int val = 0; + int i; + u32 ep_dirs; + + /* + * Don't need additional space for ep info control registers in + * slave mode. + */ + if (!using_dma(hsotg)) { + dev_dbg(hsotg->dev, "Buffer DMA ep info size 0\n"); + return 0; + } + + /* + * Buffer DMA mode - 1 location per endpoit + * Descriptor DMA mode - 4 locations per endpoint + */ + ep_dirs = hsotg->hw_params.dev_ep_dirs; + + for (i = 0; i <= hsotg->hw_params.num_dev_ep; i++) { + val += ep_dirs & 3 ? 1 : 2; + ep_dirs >>= 2; + } + + if (using_desc_dma(hsotg)) + val = val * 4; + + return val; +} + +/** + * dwc2_hsotg_tx_fifo_total_depth - return total FIFO depth available for + * device mode TX FIFOs + */ +int dwc2_hsotg_tx_fifo_total_depth(struct dwc2_hsotg *hsotg) +{ + int ep_info_size; + int addr; + int tx_addr_max; + u32 np_tx_fifo_size; + + np_tx_fifo_size = min_t(u32, hsotg->hw_params.dev_nperio_tx_fifo_size, + hsotg->params.g_np_tx_fifo_size); + + /* Get Endpoint Info Control block size in DWORDs. */ + ep_info_size = dwc2_hsotg_ep_info_size(hsotg); + tx_addr_max = hsotg->hw_params.total_fifo_size - ep_info_size; + + addr = hsotg->params.g_rx_fifo_size + np_tx_fifo_size; + if (tx_addr_max <= addr) + return 0; + + return tx_addr_max - addr; +} + +/** + * dwc2_hsotg_tx_fifo_average_depth - returns average depth of device mode + * TX FIFOs + */ +int dwc2_hsotg_tx_fifo_average_depth(struct dwc2_hsotg *hsotg) +{ + int tx_fifo_count; + int tx_fifo_depth; + + tx_fifo_depth = dwc2_hsotg_tx_fifo_total_depth(hsotg); + + tx_fifo_count = dwc2_hsotg_tx_fifo_count(hsotg); + + if (!tx_fifo_count) + return tx_fifo_depth; + else + return tx_fifo_depth / tx_fifo_count; +} + +/** * dwc2_hsotg_init_fifo - initialise non-periodic FIFOs * @hsotg: The device instance. */ @@ -241,6 +334,9 @@ static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg) val = dwc2_readl(hsotg->regs + DPTXFSIZN(ep)); } + dwc2_writel(hsotg->hw_params.total_fifo_size | + addr << GDFIFOCFG_EPINFOBASE_SHIFT, + hsotg->regs + GDFIFOCFG); /* * according to p428 of the design guide, we need to ensure that * all fifos are flushed before continuing @@ -277,11 +373,11 @@ static void dwc2_hsotg_init_fifo(struct dwc2_hsotg *hsotg) * Allocate a new USB request structure appropriate for the specified endpoint */ static struct usb_request *dwc2_hsotg_ep_alloc_request(struct usb_ep *ep, - gfp_t flags) + gfp_t flags) { struct dwc2_hsotg_req *req; - req = kzalloc(sizeof(struct dwc2_hsotg_req), flags); + req = kzalloc(sizeof(*req), flags); if (!req) return NULL; @@ -312,10 +408,11 @@ static inline int is_ep_periodic(struct dwc2_hsotg_ep *hs_ep) * of a request to ensure the buffer is ready for access by the caller. */ static void dwc2_hsotg_unmap_dma(struct dwc2_hsotg *hsotg, - struct dwc2_hsotg_ep *hs_ep, + struct dwc2_hsotg_ep *hs_ep, struct dwc2_hsotg_req *hs_req) { struct usb_request *req = &hs_req->req; + usb_gadget_unmap_request(&hsotg->gadget, req, hs_ep->dir_in); } @@ -384,7 +481,7 @@ fail: * This routine is only needed for PIO */ static int dwc2_hsotg_write_fifo(struct dwc2_hsotg *hsotg, - struct dwc2_hsotg_ep *hs_ep, + struct dwc2_hsotg_ep *hs_ep, struct dwc2_hsotg_req *hs_req) { bool periodic = is_ep_periodic(hs_ep); @@ -466,7 +563,7 @@ static int dwc2_hsotg_write_fifo(struct dwc2_hsotg *hsotg, max_transfer = hs_ep->ep.maxpacket * hs_ep->mc; dev_dbg(hsotg->dev, "%s: GNPTXSTS=%08x, can=%d, to=%d, max_transfer %d\n", - __func__, gnptxsts, can_write, to_write, max_transfer); + __func__, gnptxsts, can_write, to_write, max_transfer); /* * limit to 512 bytes of data, it seems at least on the non-periodic @@ -487,7 +584,7 @@ static int dwc2_hsotg_write_fifo(struct dwc2_hsotg *hsotg, /* it's needed only when we do not use dedicated fifos */ if (!hsotg->dedicated_fifos) dwc2_hsotg_en_gsint(hsotg, - periodic ? GINTSTS_PTXFEMP : + periodic ? GINTSTS_PTXFEMP : GINTSTS_NPTXFEMP); } @@ -516,12 +613,12 @@ static int dwc2_hsotg_write_fifo(struct dwc2_hsotg *hsotg, /* it's needed only when we do not use dedicated fifos */ if (!hsotg->dedicated_fifos) dwc2_hsotg_en_gsint(hsotg, - periodic ? GINTSTS_PTXFEMP : + periodic ? GINTSTS_PTXFEMP : GINTSTS_NPTXFEMP); } dev_dbg(hsotg->dev, "write %d/%d, can_write %d, done %d\n", - to_write, hs_req->req.length, can_write, buf_pos); + to_write, hs_req->req.length, can_write, buf_pos); if (to_write <= 0) return -ENOSPC; @@ -547,17 +644,17 @@ static int dwc2_hsotg_write_fifo(struct dwc2_hsotg *hsotg, * Return the maximum data that can be queued in one go on a given endpoint * so that transfers that are too long can be split. */ -static unsigned get_ep_limit(struct dwc2_hsotg_ep *hs_ep) +static unsigned int get_ep_limit(struct dwc2_hsotg_ep *hs_ep) { int index = hs_ep->index; - unsigned maxsize; - unsigned maxpkt; + unsigned int maxsize; + unsigned int maxpkt; if (index != 0) { maxsize = DXEPTSIZ_XFERSIZE_LIMIT + 1; maxpkt = DXEPTSIZ_PKTCNT_LIMIT + 1; } else { - maxsize = 64+64; + maxsize = 64 + 64; if (hs_ep->dir_in) maxpkt = DIEPTSIZ0_PKTCNT_LIMIT + 1; else @@ -580,11 +677,11 @@ static unsigned get_ep_limit(struct dwc2_hsotg_ep *hs_ep) } /** -* dwc2_hsotg_read_frameno - read current frame number -* @hsotg: The device instance -* -* Return the current frame number -*/ + * dwc2_hsotg_read_frameno - read current frame number + * @hsotg: The device instance + * + * Return the current frame number + */ static u32 dwc2_hsotg_read_frameno(struct dwc2_hsotg *hsotg) { u32 dsts; @@ -874,7 +971,7 @@ static void dwc2_gadget_start_isoc_ddma(struct dwc2_hsotg_ep *hs_ep) * appropriately, and writing any data to the FIFOs. */ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg, - struct dwc2_hsotg_ep *hs_ep, + struct dwc2_hsotg_ep *hs_ep, struct dwc2_hsotg_req *hs_req, bool continuing) { @@ -885,9 +982,9 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg, u32 epsize_reg; u32 epsize; u32 ctrl; - unsigned length; - unsigned packets; - unsigned maxreq; + unsigned int length; + unsigned int packets; + unsigned int maxreq; unsigned int dma_reg; if (index != 0) { @@ -966,7 +1063,7 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg, if (dir_in && ureq->zero && !continuing) { /* Test if zlp is actually required. */ if ((ureq->length >= hs_ep->ep.maxpacket) && - !(ureq->length % hs_ep->ep.maxpacket)) + !(ureq->length % hs_ep->ep.maxpacket)) hs_ep->send_zlp = 1; } @@ -1070,7 +1167,7 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg, /* check ep is enabled */ if (!(dwc2_readl(hsotg->regs + epctrl_reg) & DXEPCTL_EPENA)) dev_dbg(hsotg->dev, - "ep%d: failed to become enabled (DXEPCTL=0x%08x)?\n", + "ep%d: failed to become enabled (DXEPCTL=0x%08x)?\n", index, dwc2_readl(hsotg->regs + epctrl_reg)); dev_dbg(hsotg->dev, "%s: DXEPCTL=0x%08x\n", @@ -1093,7 +1190,7 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg, * cleanup on completion. */ static int dwc2_hsotg_map_dma(struct dwc2_hsotg *hsotg, - struct dwc2_hsotg_ep *hs_ep, + struct dwc2_hsotg_ep *hs_ep, struct usb_request *req) { int ret; @@ -1112,7 +1209,8 @@ dma_error: } static int dwc2_hsotg_handle_unaligned_buf_start(struct dwc2_hsotg *hsotg, - struct dwc2_hsotg_ep *hs_ep, struct dwc2_hsotg_req *hs_req) + struct dwc2_hsotg_ep *hs_ep, + struct dwc2_hsotg_req *hs_req) { void *req_buf = hs_req->req.buf; @@ -1123,7 +1221,7 @@ static int dwc2_hsotg_handle_unaligned_buf_start(struct dwc2_hsotg *hsotg, WARN_ON(hs_req->saved_req_buf); dev_dbg(hsotg->dev, "%s: %s: buf=%p length=%d\n", __func__, - hs_ep->ep.name, req_buf, hs_req->req.length); + hs_ep->ep.name, req_buf, hs_req->req.length); hs_req->req.buf = kmalloc(hs_req->req.length, GFP_ATOMIC); if (!hs_req->req.buf) { @@ -1142,8 +1240,10 @@ static int dwc2_hsotg_handle_unaligned_buf_start(struct dwc2_hsotg *hsotg, return 0; } -static void dwc2_hsotg_handle_unaligned_buf_complete(struct dwc2_hsotg *hsotg, - struct dwc2_hsotg_ep *hs_ep, struct dwc2_hsotg_req *hs_req) +static void +dwc2_hsotg_handle_unaligned_buf_complete(struct dwc2_hsotg *hsotg, + struct dwc2_hsotg_ep *hs_ep, + struct dwc2_hsotg_req *hs_req) { /* If dma is not being used or buffer was aligned */ if (!using_dma(hsotg) || !hs_req->saved_req_buf) @@ -1155,7 +1255,7 @@ static void dwc2_hsotg_handle_unaligned_buf_complete(struct dwc2_hsotg *hsotg, /* Copy data from bounce buffer on successful out transfer */ if (!hs_ep->dir_in && !hs_req->req.status) memcpy(hs_req->saved_req_buf, hs_req->req.buf, - hs_req->req.actual); + hs_req->req.actual); /* Free bounce buffer */ kfree(hs_req->req.buf); @@ -1224,7 +1324,7 @@ static int dwc2_gadget_set_ep0_desc_chain(struct dwc2_hsotg *hsotg, } static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, - gfp_t gfp_flags) + gfp_t gfp_flags) { struct dwc2_hsotg_req *hs_req = our_req(req); struct dwc2_hsotg_ep *hs_ep = our_ep(ep); @@ -1239,7 +1339,7 @@ static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, /* Prevent new request submission when controller is suspended */ if (hs->lx_state == DWC2_L2) { dev_dbg(hs->dev, "%s: don't submit request while suspended\n", - __func__); + __func__); return -EAGAIN; } @@ -1300,7 +1400,7 @@ static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, } static int dwc2_hsotg_ep_queue_lock(struct usb_ep *ep, struct usb_request *req, - gfp_t gfp_flags) + gfp_t gfp_flags) { struct dwc2_hsotg_ep *hs_ep = our_ep(ep); struct dwc2_hsotg *hs = hs_ep->parent; @@ -1315,7 +1415,7 @@ static int dwc2_hsotg_ep_queue_lock(struct usb_ep *ep, struct usb_request *req, } static void dwc2_hsotg_ep_free_request(struct usb_ep *ep, - struct usb_request *req) + struct usb_request *req) { struct dwc2_hsotg_req *hs_req = our_req(req); @@ -1331,7 +1431,7 @@ static void dwc2_hsotg_ep_free_request(struct usb_ep *ep, * submitted that need cleaning up. */ static void dwc2_hsotg_complete_oursetup(struct usb_ep *ep, - struct usb_request *req) + struct usb_request *req) { struct dwc2_hsotg_ep *hs_ep = our_ep(ep); struct dwc2_hsotg *hsotg = hs_ep->parent; @@ -1350,7 +1450,7 @@ static void dwc2_hsotg_complete_oursetup(struct usb_ep *ep, * structure, or return NULL if it is not a valid endpoint. */ static struct dwc2_hsotg_ep *ep_from_windex(struct dwc2_hsotg *hsotg, - u32 windex) + u32 windex) { struct dwc2_hsotg_ep *ep; int dir = (windex & USB_DIR_IN) ? 1 : 0; @@ -1407,7 +1507,7 @@ int dwc2_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode) * an internal method of sending replies to certain control requests, etc. */ static int dwc2_hsotg_send_reply(struct dwc2_hsotg *hsotg, - struct dwc2_hsotg_ep *ep, + struct dwc2_hsotg_ep *ep, void *buff, int length) { @@ -1450,7 +1550,7 @@ static int dwc2_hsotg_send_reply(struct dwc2_hsotg *hsotg, * @ctrl: USB control request */ static int dwc2_hsotg_process_req_status(struct dwc2_hsotg *hsotg, - struct usb_ctrlrequest *ctrl) + struct usb_ctrlrequest *ctrl) { struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; struct dwc2_hsotg_ep *ep; @@ -1466,8 +1566,11 @@ static int dwc2_hsotg_process_req_status(struct dwc2_hsotg *hsotg, switch (ctrl->bRequestType & USB_RECIP_MASK) { case USB_RECIP_DEVICE: - reply = cpu_to_le16(0); /* bit 0 => self powered, - * bit 1 => remote wakeup */ + /* + * bit 0 => self powered + * bit 1 => remote wakeup + */ + reply = cpu_to_le16(0); break; case USB_RECIP_INTERFACE: @@ -1555,7 +1658,7 @@ static void dwc2_gadget_start_next_request(struct dwc2_hsotg_ep *hs_ep) * @ctrl: USB control request */ static int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg, - struct usb_ctrlrequest *ctrl) + struct usb_ctrlrequest *ctrl) { struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; struct dwc2_hsotg_req *hs_req; @@ -1640,9 +1743,8 @@ static int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg, } /* If we have pending request, then start it */ - if (!ep->req) { + if (!ep->req) dwc2_gadget_start_next_request(ep); - } } break; @@ -1705,7 +1807,7 @@ static void dwc2_hsotg_stall_ep0(struct dwc2_hsotg *hsotg) * gadget driver). */ static void dwc2_hsotg_process_control(struct dwc2_hsotg *hsotg, - struct usb_ctrlrequest *ctrl) + struct usb_ctrlrequest *ctrl) { struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; int ret = 0; @@ -1781,7 +1883,7 @@ static void dwc2_hsotg_process_control(struct dwc2_hsotg *hsotg, * EP0 setup packets */ static void dwc2_hsotg_complete_setup(struct usb_ep *ep, - struct usb_request *req) + struct usb_request *req) { struct dwc2_hsotg_ep *hs_ep = our_ep(ep); struct dwc2_hsotg *hsotg = hs_ep->parent; @@ -1839,7 +1941,7 @@ static void dwc2_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg) } static void dwc2_hsotg_program_zlp(struct dwc2_hsotg *hsotg, - struct dwc2_hsotg_ep *hs_ep) + struct dwc2_hsotg_ep *hs_ep) { u32 ctrl; u8 index = hs_ep->index; @@ -1885,11 +1987,10 @@ static void dwc2_hsotg_program_zlp(struct dwc2_hsotg *hsotg, * Note, expects the ep to already be locked as appropriate. */ static void dwc2_hsotg_complete_request(struct dwc2_hsotg *hsotg, - struct dwc2_hsotg_ep *hs_ep, + struct dwc2_hsotg_ep *hs_ep, struct dwc2_hsotg_req *hs_req, int result) { - if (!hs_req) { dev_dbg(hsotg->dev, "%s: nothing to complete?\n", __func__); return; @@ -1935,9 +2036,8 @@ static void dwc2_hsotg_complete_request(struct dwc2_hsotg *hsotg, * so be careful when doing this. */ - if (!hs_ep->req && result >= 0) { + if (!hs_ep->req && result >= 0) dwc2_gadget_start_next_request(hs_ep); - } } /* @@ -2068,13 +2168,12 @@ static void dwc2_hsotg_rx_data(struct dwc2_hsotg *hsotg, int ep_idx, int size) int max_req; int read_ptr; - if (!hs_req) { u32 epctl = dwc2_readl(hsotg->regs + DOEPCTL(ep_idx)); int ptr; dev_dbg(hsotg->dev, - "%s: FIFO %d bytes on ep%d but no req (DXEPCTl=0x%08x)\n", + "%s: FIFO %d bytes on ep%d but no req (DXEPCTl=0x%08x)\n", __func__, size, ep_idx, epctl); /* dump the data from the FIFO, we've nothing we can do */ @@ -2134,7 +2233,7 @@ static void dwc2_hsotg_ep0_zlp(struct dwc2_hsotg *hsotg, bool dir_in) } static void dwc2_hsotg_change_ep_iso_parity(struct dwc2_hsotg *hsotg, - u32 epctl_reg) + u32 epctl_reg) { u32 ctrl; @@ -2191,7 +2290,7 @@ static void dwc2_hsotg_handle_outdone(struct dwc2_hsotg *hsotg, int epnum) struct dwc2_hsotg_ep *hs_ep = hsotg->eps_out[epnum]; struct dwc2_hsotg_req *hs_req = hs_ep->req; struct usb_request *req = &hs_req->req; - unsigned size_left = DXEPTSIZ_XFERSIZE_GET(epsize); + unsigned int size_left = DXEPTSIZ_XFERSIZE_GET(epsize); int result = 0; if (!hs_req) { @@ -2210,7 +2309,7 @@ static void dwc2_hsotg_handle_outdone(struct dwc2_hsotg *hsotg, int epnum) size_left = dwc2_gadget_get_xfersize_ddma(hs_ep); if (using_dma(hsotg)) { - unsigned size_done; + unsigned int size_done; /* * Calculate the size of the transfer by checking how much @@ -2295,7 +2394,7 @@ static void dwc2_hsotg_handle_rx(struct dwc2_hsotg *hsotg) size >>= GRXSTS_BYTECNT_SHIFT; dev_dbg(hsotg->dev, "%s: GRXSTSP=0x%08x (%d@%d)\n", - __func__, grxstsr, size, epnum); + __func__, grxstsr, size, epnum); switch ((status & GRXSTS_PKTSTS_MASK) >> GRXSTS_PKTSTS_SHIFT) { case GRXSTS_PKTSTS_GLOBALOUTNAK: @@ -2470,7 +2569,7 @@ static void dwc2_hsotg_txfifo_flush(struct dwc2_hsotg *hsotg, unsigned int idx) * make an attempt to write data into the FIFO. */ static int dwc2_hsotg_trytx(struct dwc2_hsotg *hsotg, - struct dwc2_hsotg_ep *hs_ep) + struct dwc2_hsotg_ep *hs_ep) { struct dwc2_hsotg_req *hs_req = hs_ep->req; @@ -2481,7 +2580,7 @@ static int dwc2_hsotg_trytx(struct dwc2_hsotg *hsotg, */ if (hs_ep->index != 0) dwc2_hsotg_ctrl_epint(hsotg, hs_ep->index, - hs_ep->dir_in, 0); + hs_ep->dir_in, 0); return 0; } @@ -2503,7 +2602,7 @@ static int dwc2_hsotg_trytx(struct dwc2_hsotg *hsotg, * call the relevant completion routines. */ static void dwc2_hsotg_complete_in(struct dwc2_hsotg *hsotg, - struct dwc2_hsotg_ep *hs_ep) + struct dwc2_hsotg_ep *hs_ep) { struct dwc2_hsotg_req *hs_req = hs_ep->req; u32 epsize = dwc2_readl(hsotg->regs + DIEPTSIZ(hs_ep->index)); @@ -2531,7 +2630,7 @@ static void dwc2_hsotg_complete_in(struct dwc2_hsotg *hsotg, ret = dwc2_hsotg_set_test_mode(hsotg, hsotg->test_mode); if (ret < 0) { dev_dbg(hsotg->dev, "Invalid Test #%d\n", - hsotg->test_mode); + hsotg->test_mode); dwc2_hsotg_stall_ep0(hsotg); return; } @@ -2751,19 +2850,19 @@ static void dwc2_gadget_handle_out_token_ep_disabled(struct dwc2_hsotg_ep *ep) } /** -* dwc2_gadget_handle_nak - handle NAK interrupt -* @hs_ep: The endpoint on which interrupt is asserted. -* -* This is starting point for ISOC-IN transfer, synchronization done with -* first IN token received from host while corresponding EP is disabled. -* -* Device does not know when first one token will arrive from host. On first -* token arrival HW generates 2 interrupts: 'in token received while FIFO empty' -* and 'NAK'. NAK interrupt for ISOC-IN means that token has arrived and ZLP was -* sent in response to that as there was no data in FIFO. SW is basing on this -* interrupt to obtain frame in which token has come and then based on the -* interval calculates next frame for transfer. -*/ + * dwc2_gadget_handle_nak - handle NAK interrupt + * @hs_ep: The endpoint on which interrupt is asserted. + * + * This is starting point for ISOC-IN transfer, synchronization done with + * first IN token received from host while corresponding EP is disabled. + * + * Device does not know when first one token will arrive from host. On first + * token arrival HW generates 2 interrupts: 'in token received while FIFO empty' + * and 'NAK'. NAK interrupt for ISOC-IN means that token has arrived and ZLP was + * sent in response to that as there was no data in FIFO. SW is basing on this + * interrupt to obtain frame in which token has come and then based on the + * interval calculates next frame for transfer. + */ static void dwc2_gadget_handle_nak(struct dwc2_hsotg_ep *hs_ep) { struct dwc2_hsotg *hsotg = hs_ep->parent; @@ -2807,7 +2906,7 @@ static void dwc2_gadget_handle_nak(struct dwc2_hsotg_ep *hs_ep) * Process and clear any interrupt pending for an individual endpoint */ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx, - int dir_in) + int dir_in) { struct dwc2_hsotg_ep *hs_ep = index_to_ep(hsotg, idx, dir_in); u32 epint_reg = dir_in ? DIEPINT(idx) : DOEPINT(idx); @@ -2824,7 +2923,7 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx, if (!hs_ep) { dev_err(hsotg->dev, "%s:Interrupt for unconfigured ep%d(%s)\n", - __func__, idx, dir_in ? "in" : "out"); + __func__, idx, dir_in ? "in" : "out"); return; } @@ -3059,13 +3158,13 @@ static void kill_all_requests(struct dwc2_hsotg *hsotg, int result) { struct dwc2_hsotg_req *req, *treq; - unsigned size; + unsigned int size; ep->req = NULL; list_for_each_entry_safe(req, treq, &ep->queue, queue) dwc2_hsotg_complete_request(hsotg, ep, req, - result); + result); if (!hsotg->dedicated_fifos) return; @@ -3084,7 +3183,7 @@ static void kill_all_requests(struct dwc2_hsotg *hsotg, */ void dwc2_hsotg_disconnect(struct dwc2_hsotg *hsotg) { - unsigned ep; + unsigned int ep; if (!hsotg->connected) return; @@ -3095,10 +3194,10 @@ void dwc2_hsotg_disconnect(struct dwc2_hsotg *hsotg) for (ep = 0; ep < hsotg->num_of_eps; ep++) { if (hsotg->eps_in[ep]) kill_all_requests(hsotg, hsotg->eps_in[ep], - -ESHUTDOWN); + -ESHUTDOWN); if (hsotg->eps_out[ep]) kill_all_requests(hsotg, hsotg->eps_out[ep], - -ESHUTDOWN); + -ESHUTDOWN); } call_gadget(hsotg, disconnect); @@ -3147,7 +3246,7 @@ static void dwc2_hsotg_irq_fifoempty(struct dwc2_hsotg *hsotg, bool periodic) * Issue a soft reset to the core, and await the core finishing it. */ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, - bool is_usb_reset) + bool is_usb_reset) { u32 intmsk; u32 val; @@ -3158,7 +3257,7 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET); if (!is_usb_reset) - if (dwc2_core_reset(hsotg)) + if (dwc2_core_reset(hsotg, true)) return; /* @@ -3221,7 +3320,7 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, if (!using_desc_dma(hsotg)) intmsk |= GINTSTS_INCOMPL_SOIN | GINTSTS_INCOMPL_SOOUT; - if (hsotg->params.external_id_pin_ctl <= 0) + if (!hsotg->params.external_id_pin_ctl) intmsk |= GINTSTS_CONIDSTSCHNG; dwc2_writel(intmsk, hsotg->regs + GINTMSK); @@ -3462,7 +3561,6 @@ irq_retry: } if (gintsts & (GINTSTS_USBRST | GINTSTS_RESETDET)) { - u32 usb_status = dwc2_readl(hsotg->regs + GOTGCTL); u32 connected = hsotg->connected; @@ -3601,7 +3699,7 @@ irq_retry: */ if (gintsts & IRQ_RETRY_MASK && --retry_count > 0) - goto irq_retry; + goto irq_retry; spin_unlock(&hsotg->lock); @@ -3705,7 +3803,7 @@ static void dwc2_hsotg_ep_stop_xfr(struct dwc2_hsotg *hsotg, * This is called from the USB gadget code's usb_ep_enable(). */ static int dwc2_hsotg_ep_enable(struct usb_ep *ep, - const struct usb_endpoint_descriptor *desc) + const struct usb_endpoint_descriptor *desc) { struct dwc2_hsotg_ep *hs_ep = our_ep(ep); struct dwc2_hsotg *hsotg = hs_ep->parent; @@ -3827,12 +3925,13 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep, if (dir_in && hsotg->dedicated_fifos) { u32 fifo_index = 0; u32 fifo_size = UINT_MAX; - size = hs_ep->ep.maxpacket*hs_ep->mc; + + size = hs_ep->ep.maxpacket * hs_ep->mc; for (i = 1; i < hsotg->num_of_eps; ++i) { - if (hsotg->fifo_map & (1<<i)) + if (hsotg->fifo_map & (1 << i)) continue; val = dwc2_readl(hsotg->regs + DPTXFSIZN(i)); - val = (val >> FIFOSIZE_DEPTH_SHIFT)*4; + val = (val >> FIFOSIZE_DEPTH_SHIFT) * 4; if (val < size) continue; /* Search for smallest acceptable fifo */ @@ -4033,23 +4132,22 @@ static int dwc2_hsotg_ep_sethalt(struct usb_ep *ep, int value, bool now) epctl &= ~DXEPCTL_STALL; xfertype = epctl & DXEPCTL_EPTYPE_MASK; if (xfertype == DXEPCTL_EPTYPE_BULK || - xfertype == DXEPCTL_EPTYPE_INTERRUPT) - epctl |= DXEPCTL_SETD0PID; + xfertype == DXEPCTL_EPTYPE_INTERRUPT) + epctl |= DXEPCTL_SETD0PID; } dwc2_writel(epctl, hs->regs + epreg); } else { - epreg = DOEPCTL(index); epctl = dwc2_readl(hs->regs + epreg); - if (value) + if (value) { epctl |= DXEPCTL_STALL; - else { + } else { epctl &= ~DXEPCTL_STALL; xfertype = epctl & DXEPCTL_EPTYPE_MASK; if (xfertype == DXEPCTL_EPTYPE_BULK || - xfertype == DXEPCTL_EPTYPE_INTERRUPT) - epctl |= DXEPCTL_SETD0PID; + xfertype == DXEPCTL_EPTYPE_INTERRUPT) + epctl |= DXEPCTL_SETD0PID; } dwc2_writel(epctl, hs->regs + epreg); } @@ -4090,7 +4188,7 @@ static struct usb_ep_ops dwc2_hsotg_ep_ops = { }; /** - * dwc2_hsotg_init - initalize the usb core + * dwc2_hsotg_init - initialize the usb core * @hsotg: The driver state */ static void dwc2_hsotg_init(struct dwc2_hsotg *hsotg) @@ -4144,7 +4242,7 @@ static void dwc2_hsotg_init(struct dwc2_hsotg *hsotg) * to work. */ static int dwc2_hsotg_udc_start(struct usb_gadget *gadget, - struct usb_gadget_driver *driver) + struct usb_gadget_driver *driver) { struct dwc2_hsotg *hsotg = to_hsotg(gadget); unsigned long flags; @@ -4267,7 +4365,7 @@ static int dwc2_hsotg_pullup(struct usb_gadget *gadget, int is_on) unsigned long flags = 0; dev_dbg(hsotg->dev, "%s: is_on: %d op_state: %d\n", __func__, is_on, - hsotg->op_state); + hsotg->op_state); /* Don't modify pullup state while in host mode */ if (hsotg->op_state != OTG_STATE_B_PERIPHERAL) { @@ -4329,7 +4427,7 @@ static int dwc2_hsotg_vbus_session(struct usb_gadget *gadget, int is_active) * * Report how much power the device may consume to the phy. */ -static int dwc2_hsotg_vbus_draw(struct usb_gadget *gadget, unsigned mA) +static int dwc2_hsotg_vbus_draw(struct usb_gadget *gadget, unsigned int mA) { struct dwc2_hsotg *hsotg = to_hsotg(gadget); @@ -4358,7 +4456,7 @@ static const struct usb_gadget_ops dwc2_hsotg_gadget_ops = { * direction information and other state that may be required. */ static void dwc2_hsotg_initep(struct dwc2_hsotg *hsotg, - struct dwc2_hsotg_ep *hs_ep, + struct dwc2_hsotg_ep *hs_ep, int epnum, bool dir_in) { @@ -4415,6 +4513,7 @@ static void dwc2_hsotg_initep(struct dwc2_hsotg *hsotg, if (using_dma(hsotg)) { u32 next = DXEPCTL_NEXTEP((epnum + 1) % 15); + if (dir_in) dwc2_writel(next, hsotg->regs + DIEPCTL(epnum)); else @@ -4441,8 +4540,9 @@ static int dwc2_hsotg_hw_cfg(struct dwc2_hsotg *hsotg) /* Add ep0 */ hsotg->num_of_eps++; - hsotg->eps_in[0] = devm_kzalloc(hsotg->dev, sizeof(struct dwc2_hsotg_ep), - GFP_KERNEL); + hsotg->eps_in[0] = devm_kzalloc(hsotg->dev, + sizeof(struct dwc2_hsotg_ep), + GFP_KERNEL); if (!hsotg->eps_in[0]) return -ENOMEM; /* Same dwc2_hsotg_ep is used in both directions for ep0 */ @@ -4521,7 +4621,6 @@ static void dwc2_hsotg_dump(struct dwc2_hsotg *hsotg) idx, dwc2_readl(regs + DOEPCTL(idx)), dwc2_readl(regs + DOEPTSIZ(idx)), dwc2_readl(regs + DOEPDMA(idx))); - } dev_info(dev, "DVBUSDIS=0x%08x, DVBUSPULSE=%08x\n", @@ -4576,7 +4675,7 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq) } ret = devm_request_irq(hsotg->dev, irq, dwc2_hsotg_irq, IRQF_SHARED, - dev_name(hsotg->dev), hsotg); + dev_name(hsotg->dev), hsotg); if (ret < 0) { dev_err(dev, "cannot claim IRQ for gadget\n"); return ret; @@ -4607,10 +4706,10 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq) for (epnum = 0; epnum < hsotg->num_of_eps; epnum++) { if (hsotg->eps_in[epnum]) dwc2_hsotg_initep(hsotg, hsotg->eps_in[epnum], - epnum, 1); + epnum, 1); if (hsotg->eps_out[epnum]) dwc2_hsotg_initep(hsotg, hsotg->eps_out[epnum], - epnum, 0); + epnum, 0); } ret = usb_add_gadget_udc(dev, &hsotg->gadget); diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 46d0ad5105e4..a73722e27d07 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -42,6 +42,7 @@ #include <linux/module.h> #include <linux/spinlock.h> #include <linux/interrupt.h> +#include <linux/platform_device.h> #include <linux/dma-mapping.h> #include <linux/delay.h> #include <linux/io.h> @@ -54,6 +55,8 @@ #include "core.h" #include "hcd.h" +static void dwc2_port_resume(struct dwc2_hsotg *hsotg); + /* * ========================================================================= * Host Core Layer Functions @@ -79,9 +82,9 @@ static void dwc2_enable_common_interrupts(struct dwc2_hsotg *hsotg) /* Enable the interrupts in the GINTMSK */ intmsk = GINTSTS_MODEMIS | GINTSTS_OTGINT; - if (hsotg->params.host_dma <= 0) + if (!hsotg->params.host_dma) intmsk |= GINTSTS_RXFLVL; - if (hsotg->params.external_id_pin_ctl <= 0) + if (!hsotg->params.external_id_pin_ctl) intmsk |= GINTSTS_CONIDSTSCHNG; intmsk |= GINTSTS_WKUPINT | GINTSTS_USBSUSP | @@ -100,7 +103,7 @@ static void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg) if ((hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI && hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED && - hsotg->params.ulpi_fs_ls > 0) || + hsotg->params.ulpi_fs_ls) || hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS) { /* Full speed PHY */ val = HCFG_FSLSPCLKSEL_48_MHZ; @@ -152,7 +155,7 @@ static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) if (dwc2_is_host_mode(hsotg)) dwc2_init_fs_ls_pclk_sel(hsotg); - if (hsotg->params.i2c_enable > 0) { + if (hsotg->params.i2c_enable) { dev_dbg(hsotg->dev, "FS PHY enabling I2C\n"); /* Program GUSBCFG.OtgUtmiFsSel to I2C */ @@ -195,7 +198,7 @@ static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) dev_dbg(hsotg->dev, "HS ULPI PHY selected\n"); usbcfg |= GUSBCFG_ULPI_UTMI_SEL; usbcfg &= ~(GUSBCFG_PHYIF16 | GUSBCFG_DDRSEL); - if (hsotg->params.phy_ulpi_ddr > 0) + if (hsotg->params.phy_ulpi_ddr) usbcfg |= GUSBCFG_DDRSEL; break; case DWC2_PHY_TYPE_PARAM_UTMI: @@ -246,7 +249,7 @@ static int dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) if (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI && hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED && - hsotg->params.ulpi_fs_ls > 0) { + hsotg->params.ulpi_fs_ls) { dev_dbg(hsotg->dev, "Setting ULPI FSLS\n"); usbcfg = dwc2_readl(hsotg->regs + GUSBCFG); usbcfg |= GUSBCFG_ULPI_FS_LS; @@ -290,17 +293,17 @@ static int dwc2_gahbcfg_init(struct dwc2_hsotg *hsotg) hsotg->params.host_dma, hsotg->params.dma_desc_enable); - if (hsotg->params.host_dma > 0) { - if (hsotg->params.dma_desc_enable > 0) + if (hsotg->params.host_dma) { + if (hsotg->params.dma_desc_enable) dev_dbg(hsotg->dev, "Using Descriptor DMA mode\n"); else dev_dbg(hsotg->dev, "Using Buffer DMA mode\n"); } else { dev_dbg(hsotg->dev, "Using Slave mode\n"); - hsotg->params.dma_desc_enable = 0; + hsotg->params.dma_desc_enable = false; } - if (hsotg->params.host_dma > 0) + if (hsotg->params.host_dma) ahbcfg |= GAHBCFG_DMA_EN; dwc2_writel(ahbcfg, hsotg->regs + GAHBCFG); @@ -491,9 +494,10 @@ static void dwc2_config_fifos(struct dwc2_hsotg *hsotg) dev_dbg(hsotg->dev, "new hptxfsiz=%08x\n", dwc2_readl(hsotg->regs + HPTXFSIZ)); - if (hsotg->params.en_multiple_tx_fifo > 0 && - hsotg->hw_params.snpsid <= DWC2_CORE_REV_2_94a) { + if (hsotg->params.en_multiple_tx_fifo && + hsotg->hw_params.snpsid >= DWC2_CORE_REV_2_91a) { /* + * This feature was implemented in 2.91a version * Global DFIFOCFG calculation for Host mode - * include RxFIFO, NPTXFIFO and HPTXFIFO */ @@ -771,7 +775,7 @@ static void dwc2_hc_enable_dma_ints(struct dwc2_hsotg *hsotg, * For Descriptor DMA mode core halts the channel on AHB error. * Interrupt is not required. */ - if (hsotg->params.dma_desc_enable <= 0) { + if (!hsotg->params.dma_desc_enable) { if (dbg_hc(chan)) dev_vdbg(hsotg->dev, "desc DMA disabled\n"); hcintmsk |= HCINTMSK_AHBERR; @@ -804,7 +808,7 @@ static void dwc2_hc_enable_ints(struct dwc2_hsotg *hsotg, { u32 intmsk; - if (hsotg->params.host_dma > 0) { + if (hsotg->params.host_dma) { if (dbg_hc(chan)) dev_vdbg(hsotg->dev, "DMA enabled\n"); dwc2_hc_enable_dma_ints(hsotg, chan); @@ -1024,7 +1028,7 @@ void dwc2_hc_halt(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan, /* No need to set the bit in DDMA for disabling the channel */ /* TODO check it everywhere channel is disabled */ - if (hsotg->params.dma_desc_enable <= 0) { + if (!hsotg->params.dma_desc_enable) { if (dbg_hc(chan)) dev_vdbg(hsotg->dev, "desc DMA disabled\n"); hcchar |= HCCHAR_CHENA; @@ -1034,7 +1038,7 @@ void dwc2_hc_halt(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan, } hcchar |= HCCHAR_CHDIS; - if (hsotg->params.host_dma <= 0) { + if (!hsotg->params.host_dma) { if (dbg_hc(chan)) dev_vdbg(hsotg->dev, "DMA not enabled\n"); hcchar |= HCCHAR_CHENA; @@ -1380,7 +1384,7 @@ static void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg, dev_vdbg(hsotg->dev, "%s()\n", __func__); if (chan->do_ping) { - if (hsotg->params.host_dma <= 0) { + if (!hsotg->params.host_dma) { if (dbg_hc(chan)) dev_vdbg(hsotg->dev, "ping, no DMA\n"); dwc2_hc_do_ping(hsotg, chan); @@ -1508,7 +1512,7 @@ static void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg, TSIZ_SC_MC_PID_SHIFT); } - if (hsotg->params.host_dma > 0) { + if (hsotg->params.host_dma) { dwc2_writel((u32)chan->xfer_dma, hsotg->regs + HCDMA(chan->hc_num)); if (dbg_hc(chan)) @@ -1551,7 +1555,7 @@ static void dwc2_hc_start_transfer(struct dwc2_hsotg *hsotg, chan->xfer_started = 1; chan->requests++; - if (hsotg->params.host_dma <= 0 && + if (!hsotg->params.host_dma && !chan->ep_is_in && chan->xfer_len > 0) /* Load OUT packet into the appropriate Tx FIFO */ dwc2_hc_write_packet(hsotg, chan); @@ -1834,7 +1838,7 @@ static void dwc2_hcd_cleanup_channels(struct dwc2_hsotg *hsotg) u32 hcchar; int i; - if (hsotg->params.host_dma <= 0) { + if (!hsotg->params.host_dma) { /* Flush out any channel requests in slave mode */ for (i = 0; i < num_channels; i++) { channel = hsotg->hc_ptr_array[i]; @@ -1870,7 +1874,7 @@ static void dwc2_hcd_cleanup_channels(struct dwc2_hsotg *hsotg) channel->qh = NULL; } /* All channels have been freed, mark them available */ - if (hsotg->params.uframe_sched > 0) { + if (hsotg->params.uframe_sched) { hsotg->available_host_channels = hsotg->params.host_channels; } else { @@ -2107,7 +2111,7 @@ static int dwc2_hcd_urb_dequeue(struct dwc2_hsotg *hsotg, * Free the QTD and clean up the associated QH. Leave the QH in the * schedule if it has any remaining QTDs. */ - if (hsotg->params.dma_desc_enable <= 0) { + if (!hsotg->params.dma_desc_enable) { u8 in_process = urb_qtd->in_process; dwc2_hcd_qtd_unlink_and_free(hsotg, urb_qtd, qh); @@ -2150,7 +2154,7 @@ static int dwc2_hcd_endpoint_disable(struct dwc2_hsotg *hsotg, } spin_unlock_irqrestore(&hsotg->lock, flags); - usleep_range(20000, 40000); + msleep(20); spin_lock_irqsave(&hsotg->lock, flags); qh = ep->hcpriv; if (!qh) { @@ -2215,13 +2219,12 @@ static int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup) /* Set ULPI External VBUS bit if needed */ usbcfg &= ~GUSBCFG_ULPI_EXT_VBUS_DRV; - if (hsotg->params.phy_ulpi_ext_vbus == - DWC2_PHY_ULPI_EXTERNAL_VBUS) + if (hsotg->params.phy_ulpi_ext_vbus) usbcfg |= GUSBCFG_ULPI_EXT_VBUS_DRV; /* Set external TS Dline pulsing bit if needed */ usbcfg &= ~GUSBCFG_TERMSELDLPULSE; - if (hsotg->params.ts_dline > 0) + if (hsotg->params.ts_dline) usbcfg |= GUSBCFG_TERMSELDLPULSE; dwc2_writel(usbcfg, hsotg->regs + GUSBCFG); @@ -2260,10 +2263,7 @@ static int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup) /* Program the GOTGCTL register */ otgctl = dwc2_readl(hsotg->regs + GOTGCTL); otgctl &= ~GOTGCTL_OTGVER; - if (hsotg->params.otg_ver > 0) - otgctl |= GOTGCTL_OTGVER; dwc2_writel(otgctl, hsotg->regs + GOTGCTL); - dev_dbg(hsotg->dev, "OTG VER PARAM: %d\n", hsotg->params.otg_ver); /* Clear the SRP success bit for FS-I2c */ hsotg->srp_success = 0; @@ -2319,13 +2319,13 @@ static void dwc2_core_host_init(struct dwc2_hsotg *hsotg) * runtime. This bit needs to be programmed during initial configuration * and its value must not be changed during runtime. */ - if (hsotg->params.reload_ctl > 0) { + if (hsotg->params.reload_ctl) { hfir = dwc2_readl(hsotg->regs + HFIR); hfir |= HFIR_RLDCTRL; dwc2_writel(hfir, hsotg->regs + HFIR); } - if (hsotg->params.dma_desc_enable > 0) { + if (hsotg->params.dma_desc_enable) { u32 op_mode = hsotg->hw_params.op_mode; if (hsotg->hw_params.snpsid < DWC2_CORE_REV_2_90a || @@ -2337,7 +2337,7 @@ static void dwc2_core_host_init(struct dwc2_hsotg *hsotg) "Hardware does not support descriptor DMA mode -\n"); dev_err(hsotg->dev, "falling back to buffer DMA mode.\n"); - hsotg->params.dma_desc_enable = 0; + hsotg->params.dma_desc_enable = false; } else { hcfg = dwc2_readl(hsotg->regs + HCFG); hcfg |= HCFG_DESCDMA; @@ -2363,7 +2363,7 @@ static void dwc2_core_host_init(struct dwc2_hsotg *hsotg) otgctl &= ~GOTGCTL_HSTSETHNPEN; dwc2_writel(otgctl, hsotg->regs + GOTGCTL); - if (hsotg->params.dma_desc_enable <= 0) { + if (!hsotg->params.dma_desc_enable) { int num_channels, i; u32 hcchar; @@ -2430,7 +2430,7 @@ static void dwc2_hcd_reinit(struct dwc2_hsotg *hsotg) hsotg->flags.d32 = 0; hsotg->non_periodic_qh_ptr = &hsotg->non_periodic_sched_active; - if (hsotg->params.uframe_sched > 0) { + if (hsotg->params.uframe_sched) { hsotg->available_host_channels = hsotg->params.host_channels; } else { @@ -2488,7 +2488,7 @@ static void dwc2_hc_init_xfer(struct dwc2_hsotg *hsotg, chan->do_ping = 0; chan->ep_is_in = 0; chan->data_pid_start = DWC2_HC_PID_SETUP; - if (hsotg->params.host_dma > 0) + if (hsotg->params.host_dma) chan->xfer_dma = urb->setup_dma; else chan->xfer_buf = urb->setup_packet; @@ -2515,7 +2515,7 @@ static void dwc2_hc_init_xfer(struct dwc2_hsotg *hsotg, chan->do_ping = 0; chan->data_pid_start = DWC2_HC_PID_DATA1; chan->xfer_len = 0; - if (hsotg->params.host_dma > 0) + if (hsotg->params.host_dma) chan->xfer_dma = hsotg->status_buf_dma; else chan->xfer_buf = hsotg->status_buf; @@ -2533,13 +2533,13 @@ static void dwc2_hc_init_xfer(struct dwc2_hsotg *hsotg, case USB_ENDPOINT_XFER_ISOC: chan->ep_type = USB_ENDPOINT_XFER_ISOC; - if (hsotg->params.dma_desc_enable > 0) + if (hsotg->params.dma_desc_enable) break; frame_desc = &urb->iso_descs[qtd->isoc_frame_index]; frame_desc->status = 0; - if (hsotg->params.host_dma > 0) { + if (hsotg->params.host_dma) { chan->xfer_dma = urb->dma; chan->xfer_dma += frame_desc->offset + qtd->isoc_split_offset; @@ -2577,7 +2577,7 @@ static void dwc2_free_dma_aligned_buffer(struct urb *urb) return; temp = container_of(urb->transfer_buffer, - struct dma_aligned_buffer, data); + struct dma_aligned_buffer, data); if (usb_urb_dir_in(urb)) memcpy(temp->old_xfer_buffer, temp->data, @@ -2621,7 +2621,7 @@ static int dwc2_alloc_dma_aligned_buffer(struct urb *urb, gfp_t mem_flags) } static int dwc2_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, - gfp_t mem_flags) + gfp_t mem_flags) { int ret; @@ -2718,10 +2718,10 @@ static int dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) chan->multi_count = 1; if (urb->actual_length > urb->length && - !dwc2_hcd_is_pipe_in(&urb->pipe_info)) + !dwc2_hcd_is_pipe_in(&urb->pipe_info)) urb->actual_length = urb->length; - if (hsotg->params.host_dma > 0) + if (hsotg->params.host_dma) chan->xfer_dma = urb->dma + urb->actual_length; else chan->xfer_buf = (u8 *)urb->buf + urb->actual_length; @@ -2746,7 +2746,7 @@ static int dwc2_assign_and_init_hc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) */ chan->multi_count = dwc2_hb_mult(qh->maxp); - if (hsotg->params.dma_desc_enable > 0) { + if (hsotg->params.dma_desc_enable) { chan->desc_list_addr = qh->desc_list_dma; chan->desc_list_sz = qh->desc_list_sz; } @@ -2783,7 +2783,7 @@ enum dwc2_transaction_type dwc2_hcd_select_transactions( while (qh_ptr != &hsotg->periodic_sched_ready) { if (list_empty(&hsotg->free_hc_list)) break; - if (hsotg->params.uframe_sched > 0) { + if (hsotg->params.uframe_sched) { if (hsotg->available_host_channels <= 1) break; hsotg->available_host_channels--; @@ -2810,14 +2810,14 @@ enum dwc2_transaction_type dwc2_hcd_select_transactions( num_channels = hsotg->params.host_channels; qh_ptr = hsotg->non_periodic_sched_inactive.next; while (qh_ptr != &hsotg->non_periodic_sched_inactive) { - if (hsotg->params.uframe_sched <= 0 && + if (!hsotg->params.uframe_sched && hsotg->non_periodic_channels >= num_channels - hsotg->periodic_channels) break; if (list_empty(&hsotg->free_hc_list)) break; qh = list_entry(qh_ptr, struct dwc2_qh, qh_list_entry); - if (hsotg->params.uframe_sched > 0) { + if (hsotg->params.uframe_sched) { if (hsotg->available_host_channels < 1) break; hsotg->available_host_channels--; @@ -2839,7 +2839,7 @@ enum dwc2_transaction_type dwc2_hcd_select_transactions( else ret_val = DWC2_TRANSACTION_ALL; - if (hsotg->params.uframe_sched <= 0) + if (!hsotg->params.uframe_sched) hsotg->non_periodic_channels++; } @@ -2878,8 +2878,8 @@ static int dwc2_queue_transaction(struct dwc2_hsotg *hsotg, list_move_tail(&chan->split_order_list_entry, &hsotg->split_order); - if (hsotg->params.host_dma > 0) { - if (hsotg->params.dma_desc_enable > 0) { + if (hsotg->params.host_dma) { + if (hsotg->params.dma_desc_enable) { if (!chan->xfer_started || chan->ep_type == USB_ENDPOINT_XFER_ISOC) { dwc2_hcd_start_xfer_ddma(hsotg, chan->qh); @@ -2967,7 +2967,7 @@ static void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg) qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >> TXSTS_QSPCAVAIL_SHIFT; if (qspcavail == 0) { - no_queue_space = 1; + no_queue_space = true; break; } @@ -2988,15 +2988,15 @@ static void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg) * The flag prevents any halts to get into the request queue in * the middle of multiple high-bandwidth packets getting queued. */ - if (hsotg->params.host_dma <= 0 && - qh->channel->multi_count > 1) + if (!hsotg->params.host_dma && + qh->channel->multi_count > 1) hsotg->queuing_high_bandwidth = 1; fspcavail = (tx_status & TXSTS_FSPCAVAIL_MASK) >> TXSTS_FSPCAVAIL_SHIFT; status = dwc2_queue_transaction(hsotg, qh->channel, fspcavail); if (status < 0) { - no_fifo_space = 1; + no_fifo_space = true; break; } @@ -3007,7 +3007,7 @@ static void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg) * controller automatically handles multiple packets for * high-bandwidth transfers. */ - if (hsotg->params.host_dma > 0 || status == 0 || + if (hsotg->params.host_dma || status == 0 || qh->channel->requests == qh->channel->multi_count) { qh_ptr = qh_ptr->next; /* @@ -3024,7 +3024,7 @@ static void dwc2_process_periodic_channels(struct dwc2_hsotg *hsotg) exit: if (no_queue_space || no_fifo_space || - (hsotg->params.host_dma <= 0 && + (!hsotg->params.host_dma && !list_empty(&hsotg->periodic_sched_assigned))) { /* * May need to queue more transactions as the request @@ -3045,7 +3045,7 @@ exit: * now. This function is called from interrupt * handlers to queue more transactions as transfer * states change. - */ + */ gintmsk = dwc2_readl(hsotg->regs + GINTMSK); if (gintmsk & GINTSTS_PTXFEMP) { gintmsk &= ~GINTSTS_PTXFEMP; @@ -3104,7 +3104,7 @@ static void dwc2_process_non_periodic_channels(struct dwc2_hsotg *hsotg) tx_status = dwc2_readl(hsotg->regs + GNPTXSTS); qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >> TXSTS_QSPCAVAIL_SHIFT; - if (hsotg->params.host_dma <= 0 && qspcavail == 0) { + if (!hsotg->params.host_dma && qspcavail == 0) { no_queue_space = 1; break; } @@ -3137,7 +3137,7 @@ next: hsotg->non_periodic_qh_ptr->next; } while (hsotg->non_periodic_qh_ptr != orig_qh_ptr); - if (hsotg->params.host_dma <= 0) { + if (!hsotg->params.host_dma) { tx_status = dwc2_readl(hsotg->regs + GNPTXSTS); qspcavail = (tx_status & TXSTS_QSPCAVAIL_MASK) >> TXSTS_QSPCAVAIL_SHIFT; @@ -3235,12 +3235,25 @@ static void dwc2_conn_id_status_change(struct work_struct *work) if (gotgctl & GOTGCTL_CONID_B) { /* Wait for switch to device mode */ dev_dbg(hsotg->dev, "connId B\n"); + if (hsotg->bus_suspended) { + dev_info(hsotg->dev, + "Do port resume before switching to device mode\n"); + dwc2_port_resume(hsotg); + } while (!dwc2_is_device_mode(hsotg)) { dev_info(hsotg->dev, "Waiting for Peripheral Mode, Mode=%s\n", dwc2_is_host_mode(hsotg) ? "Host" : "Peripheral"); - usleep_range(20000, 40000); + msleep(20); + /* + * Sometimes the initial GOTGCTRL read is wrong, so + * check it again and jump to host mode if that was + * the case. + */ + gotgctl = dwc2_readl(hsotg->regs + GOTGCTL); + if (!(gotgctl & GOTGCTL_CONID_B)) + goto host; if (++count > 250) break; } @@ -3255,13 +3268,14 @@ static void dwc2_conn_id_status_change(struct work_struct *work) spin_unlock_irqrestore(&hsotg->lock, flags); dwc2_hsotg_core_connect(hsotg); } else { +host: /* A-Device connector (Host Mode) */ dev_dbg(hsotg->dev, "connId A\n"); while (!dwc2_is_host_mode(hsotg)) { dev_info(hsotg->dev, "Waiting for Host Mode, Mode=%s\n", dwc2_is_host_mode(hsotg) ? "Host" : "Peripheral"); - usleep_range(20000, 40000); + msleep(20); if (++count > 250) break; } @@ -3296,7 +3310,7 @@ static void dwc2_wakeup_detected(unsigned long data) dwc2_readl(hsotg->regs + HPRT0)); dwc2_hcd_rem_wakeup(hsotg); - hsotg->bus_suspended = 0; + hsotg->bus_suspended = false; /* Change to L0 state */ hsotg->lx_state = DWC2_L0; @@ -3332,7 +3346,7 @@ static void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex) hprt0 |= HPRT0_SUSP; dwc2_writel(hprt0, hsotg->regs + HPRT0); - hsotg->bus_suspended = 1; + hsotg->bus_suspended = true; /* * If hibernation is supported, Phy clock will be suspended @@ -3354,7 +3368,7 @@ static void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex) spin_unlock_irqrestore(&hsotg->lock, flags); - usleep_range(200000, 250000); + msleep(200); } else { spin_unlock_irqrestore(&hsotg->lock, flags); } @@ -3378,7 +3392,7 @@ static void dwc2_port_resume(struct dwc2_hsotg *hsotg) pcgctl &= ~PCGCTL_STOPPCLK; dwc2_writel(pcgctl, hsotg->regs + PCGCTL); spin_unlock_irqrestore(&hsotg->lock, flags); - usleep_range(20000, 40000); + msleep(20); spin_lock_irqsave(&hsotg->lock, flags); } @@ -3394,7 +3408,7 @@ static void dwc2_port_resume(struct dwc2_hsotg *hsotg) hprt0 = dwc2_read_hprt0(hsotg); hprt0 &= ~(HPRT0_RES | HPRT0_SUSP); dwc2_writel(hprt0, hsotg->regs + HPRT0); - hsotg->bus_suspended = 0; + hsotg->bus_suspended = false; spin_unlock_irqrestore(&hsotg->lock, flags); } @@ -3614,7 +3628,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, u32 hcfg; dev_info(hsotg->dev, "Enabling descriptor DMA mode\n"); - hsotg->params.dma_desc_enable = 1; + hsotg->params.dma_desc_enable = true; hcfg = dwc2_readl(hsotg->regs + HCFG); hcfg |= HCFG_DESCDMA; dwc2_writel(hcfg, hsotg->regs + HCFG); @@ -3691,7 +3705,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, } /* Clear reset bit in 10ms (FS/LS) or 50ms (HS) */ - usleep_range(50000, 70000); + msleep(50); hprt0 &= ~HPRT0_RST; dwc2_writel(hprt0, hsotg->regs + HPRT0); hsotg->lx_state = DWC2_L0; /* Now back to On state */ @@ -4047,7 +4061,7 @@ static struct dwc2_hsotg *dwc2_hcd_to_hsotg(struct usb_hcd *hcd) { struct wrapper_priv_data *p; - p = (struct wrapper_priv_data *) &hcd->hcd_priv; + p = (struct wrapper_priv_data *)&hcd->hcd_priv; return p->hsotg; } @@ -4082,7 +4096,7 @@ struct dwc2_tt *dwc2_host_get_tt_info(struct dwc2_hsotg *hsotg, void *context, *ttport = urb->dev->ttport; dwc_tt = urb->dev->tt->hcpriv; - if (dwc_tt == NULL) { + if (!dwc_tt) { size_t bitmap_size; /* @@ -4096,7 +4110,7 @@ struct dwc2_tt *dwc2_host_get_tt_info(struct dwc2_hsotg *hsotg, void *context, dwc_tt = kzalloc(sizeof(*dwc_tt) + bitmap_size, mem_flags); - if (dwc_tt == NULL) + if (!dwc_tt) return NULL; dwc_tt->usb_tt = urb->dev->tt; @@ -4123,7 +4137,7 @@ struct dwc2_tt *dwc2_host_get_tt_info(struct dwc2_hsotg *hsotg, void *context, void dwc2_host_put_tt_info(struct dwc2_hsotg *hsotg, struct dwc2_tt *dwc_tt) { /* Model kfree and make put of NULL a no-op */ - if (dwc_tt == NULL) + if (!dwc_tt) return; WARN_ON(dwc_tt->refcount < 1); @@ -4206,7 +4220,6 @@ void dwc2_host_complete(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd, usb_pipein(urb->pipe) ? "IN" : "OUT", status, urb->actual_length); - if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { urb->error_count = dwc2_hcd_urb_get_error_count(qtd->urb); for (i = 0; i < urb->number_of_packets; ++i) { @@ -4587,7 +4600,7 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, dwc2_dump_urb_info(hcd, urb, "urb_enqueue"); } - if (ep == NULL) + if (!ep) return -EINVAL; if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS || @@ -4657,7 +4670,7 @@ static int _dwc2_hcd_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, urb->iso_frame_desc[i].length); urb->hcpriv = dwc2_urb; - qh = (struct dwc2_qh *) ep->hcpriv; + qh = (struct dwc2_qh *)ep->hcpriv; /* Create QH for the endpoint if it doesn't exist */ if (!qh) { qh = dwc2_hcd_qh_create(hsotg, dwc2_urb, mem_flags); @@ -4712,7 +4725,7 @@ fail1: dwc2_hcd_qh_unlink(hsotg, qh); /* Free each QTD in the QH's QTD list */ list_for_each_entry_safe(qtd2, qtd2_tmp, &qh->qtd_list, - qtd_list_entry) + qtd_list_entry) dwc2_hcd_qtd_unlink_and_free(hsotg, qtd2, qh); dwc2_hcd_qh_free(hsotg, qh); } @@ -4860,6 +4873,61 @@ static void _dwc2_hcd_clear_tt_buffer_complete(struct usb_hcd *hcd, spin_unlock_irqrestore(&hsotg->lock, flags); } +/* + * HPRT0_SPD_HIGH_SPEED: high speed + * HPRT0_SPD_FULL_SPEED: full speed + */ +static void dwc2_change_bus_speed(struct usb_hcd *hcd, int speed) +{ + struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); + + if (hsotg->params.speed == speed) + return; + + hsotg->params.speed = speed; + queue_work(hsotg->wq_otg, &hsotg->wf_otg); +} + +static void dwc2_free_dev(struct usb_hcd *hcd, struct usb_device *udev) +{ + struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); + + if (!hsotg->params.change_speed_quirk) + return; + + /* + * On removal, set speed to default high-speed. + */ + if (udev->parent && udev->parent->speed > USB_SPEED_UNKNOWN && + udev->parent->speed < USB_SPEED_HIGH) { + dev_info(hsotg->dev, "Set speed to default high-speed\n"); + dwc2_change_bus_speed(hcd, HPRT0_SPD_HIGH_SPEED); + } +} + +static int dwc2_reset_device(struct usb_hcd *hcd, struct usb_device *udev) +{ + struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); + + if (!hsotg->params.change_speed_quirk) + return 0; + + if (udev->speed == USB_SPEED_HIGH) { + dev_info(hsotg->dev, "Set speed to high-speed\n"); + dwc2_change_bus_speed(hcd, HPRT0_SPD_HIGH_SPEED); + } else if ((udev->speed == USB_SPEED_FULL || + udev->speed == USB_SPEED_LOW)) { + /* + * Change speed setting to full-speed if there's + * a full-speed or low-speed device plugged in. + */ + dev_info(hsotg->dev, "Set speed to full-speed\n"); + dwc2_change_bus_speed(hcd, HPRT0_SPD_FULL_SPEED); + } + + return 0; +} + static struct hc_driver dwc2_hc_driver = { .description = "dwc2_hsotg", .product_desc = "DWC OTG Controller", @@ -4911,7 +4979,7 @@ static void dwc2_hcd_free(struct dwc2_hsotg *hsotg) for (i = 0; i < MAX_EPS_CHANNELS; i++) { struct dwc2_host_chan *chan = hsotg->hc_ptr_array[i]; - if (chan != NULL) { + if (chan) { dev_dbg(hsotg->dev, "HCD Free channel #%i, chan=%p\n", i, chan); hsotg->hc_ptr_array[i] = NULL; @@ -4919,7 +4987,7 @@ static void dwc2_hcd_free(struct dwc2_hsotg *hsotg) } } - if (hsotg->params.host_dma > 0) { + if (hsotg->params.host_dma) { if (hsotg->status_buf) { dma_free_coherent(hsotg->dev, DWC2_HCD_STATUS_BUF_SIZE, hsotg->status_buf, @@ -4967,8 +5035,10 @@ static void dwc2_hcd_release(struct dwc2_hsotg *hsotg) * USB bus with the core and calls the hc_driver->start() function. It returns * a negative error on failure. */ -int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq) +int dwc2_hcd_init(struct dwc2_hsotg *hsotg) { + struct platform_device *pdev = to_platform_device(hsotg->dev); + struct resource *res; struct usb_hcd *hcd; struct dwc2_host_chan *channel; u32 hcfg; @@ -4999,32 +5069,41 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq) hsotg->last_frame_num = HFNUM_MAX_FRNUM; /* Check if the bus driver or platform code has setup a dma_mask */ - if (hsotg->params.host_dma > 0 && - hsotg->dev->dma_mask == NULL) { + if (hsotg->params.host_dma && + !hsotg->dev->dma_mask) { dev_warn(hsotg->dev, "dma_mask not set, disabling DMA\n"); - hsotg->params.host_dma = 0; - hsotg->params.dma_desc_enable = 0; + hsotg->params.host_dma = false; + hsotg->params.dma_desc_enable = false; } /* Set device flags indicating whether the HCD supports DMA */ - if (hsotg->params.host_dma > 0) { + if (hsotg->params.host_dma) { if (dma_set_mask(hsotg->dev, DMA_BIT_MASK(32)) < 0) dev_warn(hsotg->dev, "can't set DMA mask\n"); if (dma_set_coherent_mask(hsotg->dev, DMA_BIT_MASK(32)) < 0) dev_warn(hsotg->dev, "can't set coherent DMA mask\n"); } + if (hsotg->params.change_speed_quirk) { + dwc2_hc_driver.free_dev = dwc2_free_dev; + dwc2_hc_driver.reset_device = dwc2_reset_device; + } + hcd = usb_create_hcd(&dwc2_hc_driver, hsotg->dev, dev_name(hsotg->dev)); if (!hcd) goto error1; - if (hsotg->params.host_dma <= 0) + if (!hsotg->params.host_dma) hcd->self.uses_dma = 0; hcd->has_tt = 1; - ((struct wrapper_priv_data *) &hcd->hcd_priv)->hsotg = hsotg; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); + + ((struct wrapper_priv_data *)&hcd->hcd_priv)->hsotg = hsotg; hsotg->priv = hcd; /* @@ -5072,7 +5151,7 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq) for (i = 0; i < num_channels; i++) { channel = kzalloc(sizeof(*channel), GFP_KERNEL); - if (channel == NULL) + if (!channel) goto error3; channel->hc_num = i; INIT_LIST_HEAD(&channel->split_order_list_entry); @@ -5091,7 +5170,7 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq) * done after usb_add_hcd since that function allocates the DMA buffer * pool. */ - if (hsotg->params.host_dma > 0) + if (hsotg->params.host_dma) hsotg->status_buf = dma_alloc_coherent(hsotg->dev, DWC2_HCD_STATUS_BUF_SIZE, &hsotg->status_buf_dma, GFP_KERNEL); @@ -5121,8 +5200,8 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq) * Disable descriptor dma mode since it will not be * usable. */ - hsotg->params.dma_desc_enable = 0; - hsotg->params.dma_desc_fs_enable = 0; + hsotg->params.dma_desc_enable = false; + hsotg->params.dma_desc_fs_enable = false; } hsotg->desc_hsisoc_cache = kmem_cache_create("dwc2-hsisoc-desc", @@ -5138,8 +5217,8 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq) * Disable descriptor dma mode since it will not be * usable. */ - hsotg->params.dma_desc_enable = 0; - hsotg->params.dma_desc_fs_enable = 0; + hsotg->params.dma_desc_enable = false; + hsotg->params.dma_desc_fs_enable = false; } } @@ -5164,7 +5243,7 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq) * allocates the DMA buffer pool, registers the USB bus, requests the * IRQ line, and calls hcd_start method. */ - retval = usb_add_hcd(hcd, irq, IRQF_SHARED); + retval = usb_add_hcd(hcd, hsotg->irq, IRQF_SHARED); if (retval < 0) goto error4; diff --git a/drivers/usb/dwc2/hcd.h b/drivers/usb/dwc2/hcd.h index 1ed5fa2beff4..11c3c145b793 100644 --- a/drivers/usb/dwc2/hcd.h +++ b/drivers/usb/dwc2/hcd.h @@ -521,29 +521,29 @@ static inline u8 dwc2_hcd_is_pipe_out(struct dwc2_hcd_pipe_info *pipe) return !dwc2_hcd_is_pipe_in(pipe); } -extern int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq); -extern void dwc2_hcd_remove(struct dwc2_hsotg *hsotg); +int dwc2_hcd_init(struct dwc2_hsotg *hsotg); +void dwc2_hcd_remove(struct dwc2_hsotg *hsotg); /* Transaction Execution Functions */ -extern enum dwc2_transaction_type dwc2_hcd_select_transactions( +enum dwc2_transaction_type dwc2_hcd_select_transactions( struct dwc2_hsotg *hsotg); -extern void dwc2_hcd_queue_transactions(struct dwc2_hsotg *hsotg, - enum dwc2_transaction_type tr_type); +void dwc2_hcd_queue_transactions(struct dwc2_hsotg *hsotg, + enum dwc2_transaction_type tr_type); /* Schedule Queue Functions */ /* Implemented in hcd_queue.c */ -extern struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg, - struct dwc2_hcd_urb *urb, +struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg, + struct dwc2_hcd_urb *urb, gfp_t mem_flags); -extern void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh); -extern int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh); -extern void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh); -extern void dwc2_hcd_qh_deactivate(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, - int sched_csplit); +void dwc2_hcd_qh_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh); +int dwc2_hcd_qh_add(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh); +void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh); +void dwc2_hcd_qh_deactivate(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, + int sched_csplit); -extern void dwc2_hcd_qtd_init(struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb); -extern int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd, - struct dwc2_qh *qh); +void dwc2_hcd_qtd_init(struct dwc2_qtd *qtd, struct dwc2_hcd_urb *urb); +int dwc2_hcd_qtd_add(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd, + struct dwc2_qh *qh); /* Unlinks and frees a QTD */ static inline void dwc2_hcd_qtd_unlink_and_free(struct dwc2_hsotg *hsotg, @@ -556,15 +556,15 @@ static inline void dwc2_hcd_qtd_unlink_and_free(struct dwc2_hsotg *hsotg, } /* Descriptor DMA support functions */ -extern void dwc2_hcd_start_xfer_ddma(struct dwc2_hsotg *hsotg, - struct dwc2_qh *qh); -extern void dwc2_hcd_complete_xfer_ddma(struct dwc2_hsotg *hsotg, - struct dwc2_host_chan *chan, int chnum, +void dwc2_hcd_start_xfer_ddma(struct dwc2_hsotg *hsotg, + struct dwc2_qh *qh); +void dwc2_hcd_complete_xfer_ddma(struct dwc2_hsotg *hsotg, + struct dwc2_host_chan *chan, int chnum, enum dwc2_halt_status halt_status); -extern int dwc2_hcd_qh_init_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, - gfp_t mem_flags); -extern void dwc2_hcd_qh_free_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh); +int dwc2_hcd_qh_init_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, + gfp_t mem_flags); +void dwc2_hcd_qh_free_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh); /* Check if QH is non-periodic */ #define dwc2_qh_is_non_per(_qh_ptr_) \ @@ -732,8 +732,8 @@ static inline u16 dwc2_hcd_get_ep_bandwidth(struct dwc2_hsotg *hsotg, return qh->host_us; } -extern void dwc2_hcd_save_data_toggle(struct dwc2_hsotg *hsotg, - struct dwc2_host_chan *chan, int chnum, +void dwc2_hcd_save_data_toggle(struct dwc2_hsotg *hsotg, + struct dwc2_host_chan *chan, int chnum, struct dwc2_qtd *qtd); /* HCD Core API */ @@ -746,14 +746,14 @@ extern void dwc2_hcd_save_data_toggle(struct dwc2_hsotg *hsotg, * Returns IRQ_HANDLED if interrupt is handled * Return IRQ_NONE if interrupt is not handled */ -extern irqreturn_t dwc2_handle_hcd_intr(struct dwc2_hsotg *hsotg); +irqreturn_t dwc2_handle_hcd_intr(struct dwc2_hsotg *hsotg); /** * dwc2_hcd_stop() - Halts the DWC_otg host mode operation * * @hsotg: The DWC2 HCD */ -extern void dwc2_hcd_stop(struct dwc2_hsotg *hsotg); +void dwc2_hcd_stop(struct dwc2_hsotg *hsotg); /** * dwc2_hcd_is_b_host() - Returns 1 if core currently is acting as B host, @@ -761,7 +761,7 @@ extern void dwc2_hcd_stop(struct dwc2_hsotg *hsotg); * * @hsotg: The DWC2 HCD */ -extern int dwc2_hcd_is_b_host(struct dwc2_hsotg *hsotg); +int dwc2_hcd_is_b_host(struct dwc2_hsotg *hsotg); /** * dwc2_hcd_dump_state() - Dumps hsotg state @@ -771,7 +771,7 @@ extern int dwc2_hcd_is_b_host(struct dwc2_hsotg *hsotg); * NOTE: This function will be removed once the peripheral controller code * is integrated and the driver is stable */ -extern void dwc2_hcd_dump_state(struct dwc2_hsotg *hsotg); +void dwc2_hcd_dump_state(struct dwc2_hsotg *hsotg); /** * dwc2_hcd_dump_frrem() - Dumps the average frame remaining at SOF @@ -784,7 +784,7 @@ extern void dwc2_hcd_dump_state(struct dwc2_hsotg *hsotg); * NOTE: This function will be removed once the peripheral controller code * is integrated and the driver is stable */ -extern void dwc2_hcd_dump_frrem(struct dwc2_hsotg *hsotg); +void dwc2_hcd_dump_frrem(struct dwc2_hsotg *hsotg); /* URB interface */ @@ -793,15 +793,15 @@ extern void dwc2_hcd_dump_frrem(struct dwc2_hsotg *hsotg); #define URB_SEND_ZERO_PACKET 0x2 /* Host driver callbacks */ -extern struct dwc2_tt *dwc2_host_get_tt_info(struct dwc2_hsotg *hsotg, - void *context, gfp_t mem_flags, - int *ttport); - -extern void dwc2_host_put_tt_info(struct dwc2_hsotg *hsotg, - struct dwc2_tt *dwc_tt); -extern int dwc2_host_get_speed(struct dwc2_hsotg *hsotg, void *context); -extern void dwc2_host_complete(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd, - int status); +struct dwc2_tt *dwc2_host_get_tt_info(struct dwc2_hsotg *hsotg, + void *context, gfp_t mem_flags, + int *ttport); + +void dwc2_host_put_tt_info(struct dwc2_hsotg *hsotg, + struct dwc2_tt *dwc_tt); +int dwc2_host_get_speed(struct dwc2_hsotg *hsotg, void *context); +void dwc2_host_complete(struct dwc2_hsotg *hsotg, struct dwc2_qtd *qtd, + int status); #ifdef DEBUG /* diff --git a/drivers/usb/dwc2/hcd_ddma.c b/drivers/usb/dwc2/hcd_ddma.c index cf0367768cb3..b8bdf545c3a7 100644 --- a/drivers/usb/dwc2/hcd_ddma.c +++ b/drivers/usb/dwc2/hcd_ddma.c @@ -89,8 +89,8 @@ static int dwc2_desc_list_alloc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, { struct kmem_cache *desc_cache; - if (qh->ep_type == USB_ENDPOINT_XFER_ISOC - && qh->dev_speed == USB_SPEED_HIGH) + if (qh->ep_type == USB_ENDPOINT_XFER_ISOC && + qh->dev_speed == USB_SPEED_HIGH) desc_cache = hsotg->desc_hsisoc_cache; else desc_cache = hsotg->desc_gen_cache; @@ -106,7 +106,7 @@ static int dwc2_desc_list_alloc(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, qh->desc_list_sz, DMA_TO_DEVICE); - qh->n_bytes = kzalloc(sizeof(u32) * dwc2_max_desc_num(qh), flags); + qh->n_bytes = kcalloc(dwc2_max_desc_num(qh), sizeof(u32), flags); if (!qh->n_bytes) { dma_unmap_single(hsotg->dev, qh->desc_list_dma, qh->desc_list_sz, @@ -123,8 +123,8 @@ static void dwc2_desc_list_free(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) { struct kmem_cache *desc_cache; - if (qh->ep_type == USB_ENDPOINT_XFER_ISOC - && qh->dev_speed == USB_SPEED_HIGH) + if (qh->ep_type == USB_ENDPOINT_XFER_ISOC && + qh->dev_speed == USB_SPEED_HIGH) desc_cache = hsotg->desc_hsisoc_cache; else desc_cache = hsotg->desc_gen_cache; @@ -175,7 +175,6 @@ static void dwc2_frame_list_free(struct dwc2_hsotg *hsotg) hsotg->frame_list = NULL; spin_unlock_irqrestore(&hsotg->lock, flags); - } static void dwc2_per_sched_enable(struct dwc2_hsotg *hsotg, u32 fr_list_en) @@ -297,7 +296,7 @@ static void dwc2_release_channel_ddma(struct dwc2_hsotg *hsotg, struct dwc2_host_chan *chan = qh->channel; if (dwc2_qh_is_non_per(qh)) { - if (hsotg->params.uframe_sched > 0) + if (hsotg->params.uframe_sched) hsotg->available_host_channels++; else hsotg->non_periodic_channels--; @@ -404,7 +403,7 @@ void dwc2_hcd_qh_free_ddma(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) if ((qh->ep_type == USB_ENDPOINT_XFER_ISOC || qh->ep_type == USB_ENDPOINT_XFER_INT) && - (hsotg->params.uframe_sched > 0 || + (hsotg->params.uframe_sched || !hsotg->periodic_channels) && hsotg->frame_list) { dwc2_per_sched_disable(hsotg); dwc2_frame_list_free(hsotg); @@ -570,7 +569,7 @@ static void dwc2_fill_host_isoc_dma_desc(struct dwc2_hsotg *hsotg, #endif dma_sync_single_for_device(hsotg->dev, - qh->desc_list_dma + + qh->desc_list_dma + (idx * sizeof(struct dwc2_dma_desc)), sizeof(struct dwc2_dma_desc), DMA_TO_DEVICE); @@ -776,7 +775,7 @@ static void dwc2_init_non_isoc_dma_desc(struct dwc2_hsotg *hsotg, n_desc - 1, &qh->desc_list[n_desc - 1]); dma_sync_single_for_device(hsotg->dev, - qh->desc_list_dma + + qh->desc_list_dma + ((n_desc - 1) * sizeof(struct dwc2_dma_desc)), sizeof(struct dwc2_dma_desc), @@ -816,7 +815,7 @@ static void dwc2_init_non_isoc_dma_desc(struct dwc2_hsotg *hsotg, dev_vdbg(hsotg->dev, "set A bit in desc 0 (%p)\n", &qh->desc_list[0]); dma_sync_single_for_device(hsotg->dev, - qh->desc_list_dma, + qh->desc_list_dma, sizeof(struct dwc2_dma_desc), DMA_TO_DEVICE); } @@ -1064,7 +1063,7 @@ stop_scan: } static int dwc2_update_non_isoc_urb_state_ddma(struct dwc2_hsotg *hsotg, - struct dwc2_host_chan *chan, + struct dwc2_host_chan *chan, struct dwc2_qtd *qtd, struct dwc2_dma_desc *dma_desc, enum dwc2_halt_status halt_status, diff --git a/drivers/usb/dwc2/hcd_intr.c b/drivers/usb/dwc2/hcd_intr.c index b8f4b6aaf1d0..28a8210710b1 100644 --- a/drivers/usb/dwc2/hcd_intr.c +++ b/drivers/usb/dwc2/hcd_intr.c @@ -60,7 +60,7 @@ static void dwc2_track_missed_sofs(struct dwc2_hsotg *hsotg) if (expected != curr_frame_number) dwc2_sch_vdbg(hsotg, "MISSED SOF %04x != %04x\n", - expected, curr_frame_number); + expected, curr_frame_number); #ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS if (hsotg->frame_num_idx < FRAME_NUM_ARRAY_SIZE) { @@ -163,7 +163,7 @@ static void dwc2_sof_intr(struct dwc2_hsotg *hsotg) * (micro)frame */ list_move_tail(&qh->qh_list_entry, - &hsotg->periodic_sched_ready); + &hsotg->periodic_sched_ready); } } tr_type = dwc2_hcd_select_transactions(hsotg); @@ -297,8 +297,7 @@ static void dwc2_hprt0_enable(struct dwc2_hsotg *hsotg, u32 hprt0, HCFG_FSLSPCLKSEL_SHIFT; if (prtspd == HPRT0_SPD_LOW_SPEED && - params->host_ls_low_power_phy_clk == - DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ) { + params->host_ls_low_power_phy_clk) { /* 6 MHZ */ dev_vdbg(hsotg->dev, "FS_PHY programming HCFG to 6 MHz\n"); @@ -398,7 +397,7 @@ static void dwc2_port_intr(struct dwc2_hsotg *hsotg) if (hsotg->params.dma_desc_fs_enable) { u32 hcfg; - hsotg->params.dma_desc_enable = 0; + hsotg->params.dma_desc_enable = false; hsotg->new_connection = false; hcfg = dwc2_readl(hsotg->regs + HCFG); hcfg &= ~HCFG_DESCDMA; @@ -442,7 +441,7 @@ static u32 dwc2_get_actual_xfer_length(struct dwc2_hsotg *hsotg, count = (hctsiz & TSIZ_XFERSIZE_MASK) >> TSIZ_XFERSIZE_SHIFT; length = chan->xfer_len - count; - if (short_read != NULL) + if (short_read) *short_read = (count != 0); } else if (chan->qh->do_split) { length = qtd->ssplit_out_xfer_count; @@ -604,7 +603,7 @@ static enum dwc2_halt_status dwc2_update_isoc_urb_state( /* Skip whole frame */ if (chan->qh->do_split && chan->ep_type == USB_ENDPOINT_XFER_ISOC && chan->ep_is_in && - hsotg->params.host_dma > 0) { + hsotg->params.host_dma) { qtd->complete_split = 0; qtd->isoc_split_offset = 0; } @@ -743,7 +742,7 @@ cleanup: dwc2_hc_cleanup(hsotg, chan); list_add_tail(&chan->hc_list_entry, &hsotg->free_hc_list); - if (hsotg->params.uframe_sched > 0) { + if (hsotg->params.uframe_sched) { hsotg->available_host_channels++; } else { switch (chan->ep_type) { @@ -789,7 +788,7 @@ static void dwc2_halt_channel(struct dwc2_hsotg *hsotg, if (dbg_hc(chan)) dev_vdbg(hsotg->dev, "%s()\n", __func__); - if (hsotg->params.host_dma > 0) { + if (hsotg->params.host_dma) { if (dbg_hc(chan)) dev_vdbg(hsotg->dev, "DMA enabled\n"); dwc2_release_channel(hsotg, chan, qtd, halt_status); @@ -823,7 +822,7 @@ static void dwc2_halt_channel(struct dwc2_hsotg *hsotg, * processed. */ list_move_tail(&chan->qh->qh_list_entry, - &hsotg->periodic_sched_assigned); + &hsotg->periodic_sched_assigned); /* * Make sure the Periodic Tx FIFO Empty interrupt is @@ -979,7 +978,7 @@ static void dwc2_hc_xfercomp_intr(struct dwc2_hsotg *hsotg, pipe_type = dwc2_hcd_get_pipe_type(&urb->pipe_info); - if (hsotg->params.dma_desc_enable > 0) { + if (hsotg->params.dma_desc_enable) { dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum, halt_status); if (pipe_type == USB_ENDPOINT_XFER_ISOC) /* Do not disable the interrupt, just clear it */ @@ -990,7 +989,7 @@ static void dwc2_hc_xfercomp_intr(struct dwc2_hsotg *hsotg, /* Handle xfer complete on CSPLIT */ if (chan->qh->do_split) { if (chan->ep_type == USB_ENDPOINT_XFER_ISOC && chan->ep_is_in && - hsotg->params.host_dma > 0) { + hsotg->params.host_dma) { if (qtd->complete_split && dwc2_xfercomp_isoc_split_in(hsotg, chan, chnum, qtd)) @@ -1078,7 +1077,8 @@ static void dwc2_hc_xfercomp_intr(struct dwc2_hsotg *hsotg, dev_vdbg(hsotg->dev, " Isochronous transfer complete\n"); if (qtd->isoc_split_pos == DWC2_HCSPLT_XACTPOS_ALL) halt_status = dwc2_update_isoc_urb_state(hsotg, chan, - chnum, qtd, DWC2_HC_XFER_COMPLETE); + chnum, qtd, + DWC2_HC_XFER_COMPLETE); dwc2_complete_periodic_xfer(hsotg, chan, chnum, qtd, halt_status); break; @@ -1102,7 +1102,7 @@ static void dwc2_hc_stall_intr(struct dwc2_hsotg *hsotg, dev_dbg(hsotg->dev, "--Host Channel %d Interrupt: STALL Received--\n", chnum); - if (hsotg->params.dma_desc_enable > 0) { + if (hsotg->params.dma_desc_enable) { dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum, DWC2_HC_XFER_STALL); goto handle_stall_done; @@ -1212,7 +1212,7 @@ static void dwc2_hc_nak_intr(struct dwc2_hsotg *hsotg, switch (dwc2_hcd_get_pipe_type(&qtd->urb->pipe_info)) { case USB_ENDPOINT_XFER_CONTROL: case USB_ENDPOINT_XFER_BULK: - if (hsotg->params.host_dma > 0 && chan->ep_is_in) { + if (hsotg->params.host_dma && chan->ep_is_in) { /* * NAK interrupts are enabled on bulk/control IN * transfers in DMA mode for the sole purpose of @@ -1358,7 +1358,7 @@ static void dwc2_hc_nyet_intr(struct dwc2_hsotg *hsotg, */ if (chan->do_split && chan->complete_split) { if (chan->ep_is_in && chan->ep_type == USB_ENDPOINT_XFER_ISOC && - hsotg->params.host_dma > 0) { + hsotg->params.host_dma) { qtd->complete_split = 0; qtd->isoc_split_offset = 0; qtd->isoc_frame_index++; @@ -1379,7 +1379,7 @@ static void dwc2_hc_nyet_intr(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh = chan->qh; bool past_end; - if (hsotg->params.uframe_sched <= 0) { + if (!hsotg->params.uframe_sched) { int frnum = dwc2_hcd_get_frame_number(hsotg); /* Don't have num_hs_transfers; simple logic */ @@ -1389,22 +1389,27 @@ static void dwc2_hc_nyet_intr(struct dwc2_hsotg *hsotg, int end_frnum; /* - * Figure out the end frame based on schedule. - * - * We don't want to go on trying again and again - * forever. Let's stop when we've done all the - * transfers that were scheduled. - * - * We're going to be comparing start_active_frame - * and next_active_frame, both of which are 1 - * before the time the packet goes on the wire, - * so that cancels out. Basically if had 1 - * transfer and we saw 1 NYET then we're done. - * We're getting a NYET here so if next >= - * (start + num_transfers) we're done. The - * complexity is that for all but ISOC_OUT we - * skip one slot. - */ + * Figure out the end frame based on + * schedule. + * + * We don't want to go on trying again + * and again forever. Let's stop when + * we've done all the transfers that + * were scheduled. + * + * We're going to be comparing + * start_active_frame and + * next_active_frame, both of which + * are 1 before the time the packet + * goes on the wire, so that cancels + * out. Basically if had 1 transfer + * and we saw 1 NYET then we're done. + * We're getting a NYET here so if + * next >= (start + num_transfers) + * we're done. The complexity is that + * for all but ISOC_OUT we skip one + * slot. + */ end_frnum = dwc2_frame_num_inc( qh->start_active_frame, qh->num_hs_transfers); @@ -1472,7 +1477,7 @@ static void dwc2_hc_babble_intr(struct dwc2_hsotg *hsotg, dwc2_hc_handle_tt_clear(hsotg, chan, qtd); - if (hsotg->params.dma_desc_enable > 0) { + if (hsotg->params.dma_desc_enable) { dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum, DWC2_HC_XFER_BABBLE_ERR); goto disable_int; @@ -1577,7 +1582,7 @@ static void dwc2_hc_ahberr_intr(struct dwc2_hsotg *hsotg, dev_err(hsotg->dev, " Interval: %d\n", urb->interval); /* Core halts the channel for Descriptor DMA mode */ - if (hsotg->params.dma_desc_enable > 0) { + if (hsotg->params.dma_desc_enable) { dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum, DWC2_HC_XFER_AHB_ERR); goto handle_ahberr_done; @@ -1609,7 +1614,7 @@ static void dwc2_hc_xacterr_intr(struct dwc2_hsotg *hsotg, dwc2_hc_handle_tt_clear(hsotg, chan, qtd); - if (hsotg->params.dma_desc_enable > 0) { + if (hsotg->params.dma_desc_enable) { dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum, DWC2_HC_XFER_XACT_ERR); goto handle_xacterr_done; @@ -1620,7 +1625,6 @@ static void dwc2_hc_xacterr_intr(struct dwc2_hsotg *hsotg, case USB_ENDPOINT_XFER_BULK: qtd->error_count++; if (!chan->qh->ping_state) { - dwc2_update_urb_state_abn(hsotg, chan, chnum, qtd->urb, qtd, DWC2_HC_XFER_XACT_ERR); dwc2_hcd_save_data_toggle(hsotg, chan, chnum, qtd); @@ -1645,7 +1649,7 @@ static void dwc2_hc_xacterr_intr(struct dwc2_hsotg *hsotg, enum dwc2_halt_status halt_status; halt_status = dwc2_update_isoc_urb_state(hsotg, chan, - chnum, qtd, DWC2_HC_XFER_XACT_ERR); + chnum, qtd, DWC2_HC_XFER_XACT_ERR); dwc2_halt_channel(hsotg, chan, qtd, halt_status); } break; @@ -1803,8 +1807,8 @@ static void dwc2_hc_chhltd_intr_dma(struct dwc2_hsotg *hsotg, if (chan->halt_status == DWC2_HC_XFER_URB_DEQUEUE || (chan->halt_status == DWC2_HC_XFER_AHB_ERR && - hsotg->params.dma_desc_enable <= 0)) { - if (hsotg->params.dma_desc_enable > 0) + !hsotg->params.dma_desc_enable)) { + if (hsotg->params.dma_desc_enable) dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum, chan->halt_status); else @@ -1835,7 +1839,7 @@ static void dwc2_hc_chhltd_intr_dma(struct dwc2_hsotg *hsotg, } else if (chan->hcint & HCINTMSK_STALL) { dwc2_hc_stall_intr(hsotg, chan, chnum, qtd); } else if ((chan->hcint & HCINTMSK_XACTERR) && - hsotg->params.dma_desc_enable <= 0) { + !hsotg->params.dma_desc_enable) { if (out_nak_enh) { if (chan->hcint & (HCINTMSK_NYET | HCINTMSK_NAK | HCINTMSK_ACK)) { @@ -1855,10 +1859,10 @@ static void dwc2_hc_chhltd_intr_dma(struct dwc2_hsotg *hsotg, */ dwc2_hc_xacterr_intr(hsotg, chan, chnum, qtd); } else if ((chan->hcint & HCINTMSK_XCS_XACT) && - hsotg->params.dma_desc_enable > 0) { + hsotg->params.dma_desc_enable) { dwc2_hc_xacterr_intr(hsotg, chan, chnum, qtd); } else if ((chan->hcint & HCINTMSK_AHBERR) && - hsotg->params.dma_desc_enable > 0) { + hsotg->params.dma_desc_enable) { dwc2_hc_ahberr_intr(hsotg, chan, chnum, qtd); } else if (chan->hcint & HCINTMSK_BBLERR) { dwc2_hc_babble_intr(hsotg, chan, chnum, qtd); @@ -1951,7 +1955,7 @@ static void dwc2_hc_chhltd_intr(struct dwc2_hsotg *hsotg, dev_vdbg(hsotg->dev, "--Host Channel %d Interrupt: Channel Halted--\n", chnum); - if (hsotg->params.host_dma > 0) { + if (hsotg->params.host_dma) { dwc2_hc_chhltd_intr_dma(hsotg, chan, chnum, qtd); } else { if (!dwc2_halt_status_ok(hsotg, chan, chnum, qtd)) @@ -1970,7 +1974,7 @@ static bool dwc2_check_qtd_still_ok(struct dwc2_qtd *qtd, struct dwc2_qh *qh) { struct dwc2_qtd *cur_head; - if (qh == NULL) + if (!qh) return false; cur_head = list_first_entry(&qh->qtd_list, struct dwc2_qtd, @@ -2028,7 +2032,7 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum) * interrupt unmasked */ WARN_ON(hcint != HCINTMSK_CHHLTD); - if (hsotg->params.dma_desc_enable > 0) + if (hsotg->params.dma_desc_enable) dwc2_hcd_complete_xfer_ddma(hsotg, chan, chnum, chan->halt_status); else @@ -2056,7 +2060,7 @@ static void dwc2_hc_n_intr(struct dwc2_hsotg *hsotg, int chnum) qtd = list_first_entry(&chan->qh->qtd_list, struct dwc2_qtd, qtd_list_entry); - if (hsotg->params.host_dma <= 0) { + if (!hsotg->params.host_dma) { if ((hcint & HCINTMSK_CHHLTD) && hcint != HCINTMSK_CHHLTD) hcint &= ~HCINTMSK_CHHLTD; } diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c index 5713f03a4e56..3ae8b1bbaa55 100644 --- a/drivers/usb/dwc2/hcd_queue.c +++ b/drivers/usb/dwc2/hcd_queue.c @@ -76,14 +76,13 @@ static int dwc2_periodic_channel_available(struct dwc2_hsotg *hsotg) int num_channels; num_channels = hsotg->params.host_channels; - if (hsotg->periodic_channels + hsotg->non_periodic_channels < - num_channels - && hsotg->periodic_channels < num_channels - 1) { + if ((hsotg->periodic_channels + hsotg->non_periodic_channels < + num_channels) && (hsotg->periodic_channels < num_channels - 1)) { status = 0; } else { dev_dbg(hsotg->dev, - "%s: Total channels: %d, Periodic: %d, " - "Non-periodic: %d\n", __func__, num_channels, + "%s: Total channels: %d, Periodic: %d, Non-periodic: %d\n", + __func__, num_channels, hsotg->periodic_channels, hsotg->non_periodic_channels); status = -ENOSPC; } @@ -485,7 +484,6 @@ static void pmap_print(unsigned long *map, int bits_per_period, } } - struct dwc2_qh_print_data { struct dwc2_hsotg *hsotg; struct dwc2_qh *qh; @@ -558,7 +556,6 @@ static void dwc2_qh_schedule_print(struct dwc2_hsotg *hsotg, DWC2_HS_SCHEDULE_UFRAMES, "uFrame", "us", dwc2_qh_print, &print_data); } - return; } #else static inline void dwc2_qh_schedule_print(struct dwc2_hsotg *hsotg, @@ -587,7 +584,7 @@ static int dwc2_ls_pmap_schedule(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, unsigned long *map = dwc2_get_ls_map(hsotg, qh); int slice; - if (map == NULL) + if (!map) return -EINVAL; /* @@ -626,7 +623,7 @@ static void dwc2_ls_pmap_unschedule(struct dwc2_hsotg *hsotg, unsigned long *map = dwc2_get_ls_map(hsotg, qh); /* Schedule should have failed, so no worries about no error code */ - if (map == NULL) + if (!map) return; pmap_unschedule(map, DWC2_LS_PERIODIC_SLICES_PER_FRAME, @@ -1107,7 +1104,7 @@ static void dwc2_pick_first_frame(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) next_active_frame = earliest_frame; /* Get the "no microframe schduler" out of the way... */ - if (hsotg->params.uframe_sched <= 0) { + if (!hsotg->params.uframe_sched) { if (qh->do_split) /* Splits are active at microframe 0 minus 1 */ next_active_frame |= 0x7; @@ -1182,7 +1179,7 @@ exit: qh->start_active_frame = next_active_frame; dwc2_sch_vdbg(hsotg, "QH=%p First fn=%04x nxt=%04x\n", - qh, frame_number, qh->next_active_frame); + qh, frame_number, qh->next_active_frame); } /** @@ -1200,7 +1197,7 @@ static int dwc2_do_reserve(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) { int status; - if (hsotg->params.uframe_sched > 0) { + if (hsotg->params.uframe_sched) { status = dwc2_uframe_schedule(hsotg, qh); } else { status = dwc2_periodic_channel_available(hsotg); @@ -1221,7 +1218,7 @@ static int dwc2_do_reserve(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) return status; } - if (hsotg->params.uframe_sched <= 0) + if (!hsotg->params.uframe_sched) /* Reserve periodic channel */ hsotg->periodic_channels++; @@ -1257,7 +1254,7 @@ static void dwc2_do_unreserve(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) /* Update claimed usecs per (micro)frame */ hsotg->periodic_usecs -= qh->host_us; - if (hsotg->params.uframe_sched > 0) { + if (hsotg->params.uframe_sched) { dwc2_uframe_unschedule(hsotg, qh); } else { /* Release periodic channel reservation */ @@ -1394,7 +1391,7 @@ static int dwc2_schedule_periodic(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) qh->unreserve_pending = 0; - if (hsotg->params.dma_desc_enable > 0) + if (hsotg->params.dma_desc_enable) /* Don't rely on SOF and start in ready schedule */ list_add_tail(&qh->qh_list_entry, &hsotg->periodic_sched_ready); else @@ -1501,7 +1498,6 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, device_ns += dwc_tt->usb_tt->think_time; qh->device_us = NS_TO_US(device_ns); - qh->device_interval = urb->interval; qh->host_interval = urb->interval * (do_split ? 8 : 1); @@ -1587,7 +1583,7 @@ static void dwc2_qh_init(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, * Return: Pointer to the newly allocated QH, or NULL on error */ struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg, - struct dwc2_hcd_urb *urb, + struct dwc2_hcd_urb *urb, gfp_t mem_flags) { struct dwc2_qh *qh; @@ -1602,7 +1598,7 @@ struct dwc2_qh *dwc2_hcd_qh_create(struct dwc2_hsotg *hsotg, dwc2_qh_init(hsotg, qh, urb, mem_flags); - if (hsotg->params.dma_desc_enable > 0 && + if (hsotg->params.dma_desc_enable && dwc2_hcd_qh_init_ddma(hsotg, qh, mem_flags) < 0) { dwc2_hcd_qh_free(hsotg, qh); return NULL; @@ -1714,7 +1710,7 @@ void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) dwc2_deschedule_periodic(hsotg, qh); hsotg->periodic_qh_count--; if (!hsotg->periodic_qh_count && - hsotg->params.dma_desc_enable <= 0) { + !hsotg->params.dma_desc_enable) { intr_mask = dwc2_readl(hsotg->regs + GINTMSK); intr_mask &= ~GINTSTS_SOF; dwc2_writel(intr_mask, hsotg->regs + GINTMSK); @@ -1741,7 +1737,7 @@ void dwc2_hcd_qh_unlink(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) * Return: number missed by (or 0 if we didn't miss). */ static int dwc2_next_for_periodic_split(struct dwc2_hsotg *hsotg, - struct dwc2_qh *qh, u16 frame_number) + struct dwc2_qh *qh, u16 frame_number) { u16 old_frame = qh->next_active_frame; u16 prev_frame_number = dwc2_frame_num_dec(frame_number, 1); @@ -1804,7 +1800,7 @@ static int dwc2_next_for_periodic_split(struct dwc2_hsotg *hsotg, * Return: number missed by (or 0 if we didn't miss). */ static int dwc2_next_periodic_start(struct dwc2_hsotg *hsotg, - struct dwc2_qh *qh, u16 frame_number) + struct dwc2_qh *qh, u16 frame_number) { int missed = 0; u16 interval = qh->host_interval; @@ -1926,7 +1922,7 @@ void dwc2_hcd_qh_deactivate(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh, missed = dwc2_next_periodic_start(hsotg, qh, frame_number); dwc2_sch_vdbg(hsotg, - "QH=%p next(%d) fn=%04x, sch=%04x=>%04x (%+d) miss=%d %s\n", + "QH=%p next(%d) fn=%04x, sch=%04x=>%04x (%+d) miss=%d %s\n", qh, sched_next_periodic_split, frame_number, old_frame, qh->next_active_frame, dwc2_frame_num_dec(qh->next_active_frame, old_frame), diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h index 5be056b39e5c..bde72489ae66 100644 --- a/drivers/usb/dwc2/hw.h +++ b/drivers/usb/dwc2/hw.h @@ -40,37 +40,37 @@ #define HSOTG_REG(x) (x) #define GOTGCTL HSOTG_REG(0x000) -#define GOTGCTL_CHIRPEN (1 << 27) +#define GOTGCTL_CHIRPEN BIT(27) #define GOTGCTL_MULT_VALID_BC_MASK (0x1f << 22) #define GOTGCTL_MULT_VALID_BC_SHIFT 22 -#define GOTGCTL_OTGVER (1 << 20) -#define GOTGCTL_BSESVLD (1 << 19) -#define GOTGCTL_ASESVLD (1 << 18) -#define GOTGCTL_DBNC_SHORT (1 << 17) -#define GOTGCTL_CONID_B (1 << 16) -#define GOTGCTL_DBNCE_FLTR_BYPASS (1 << 15) -#define GOTGCTL_DEVHNPEN (1 << 11) -#define GOTGCTL_HSTSETHNPEN (1 << 10) -#define GOTGCTL_HNPREQ (1 << 9) -#define GOTGCTL_HSTNEGSCS (1 << 8) -#define GOTGCTL_SESREQ (1 << 1) -#define GOTGCTL_SESREQSCS (1 << 0) +#define GOTGCTL_OTGVER BIT(20) +#define GOTGCTL_BSESVLD BIT(19) +#define GOTGCTL_ASESVLD BIT(18) +#define GOTGCTL_DBNC_SHORT BIT(17) +#define GOTGCTL_CONID_B BIT(16) +#define GOTGCTL_DBNCE_FLTR_BYPASS BIT(15) +#define GOTGCTL_DEVHNPEN BIT(11) +#define GOTGCTL_HSTSETHNPEN BIT(10) +#define GOTGCTL_HNPREQ BIT(9) +#define GOTGCTL_HSTNEGSCS BIT(8) +#define GOTGCTL_SESREQ BIT(1) +#define GOTGCTL_SESREQSCS BIT(0) #define GOTGINT HSOTG_REG(0x004) -#define GOTGINT_DBNCE_DONE (1 << 19) -#define GOTGINT_A_DEV_TOUT_CHG (1 << 18) -#define GOTGINT_HST_NEG_DET (1 << 17) -#define GOTGINT_HST_NEG_SUC_STS_CHNG (1 << 9) -#define GOTGINT_SES_REQ_SUC_STS_CHNG (1 << 8) -#define GOTGINT_SES_END_DET (1 << 2) +#define GOTGINT_DBNCE_DONE BIT(19) +#define GOTGINT_A_DEV_TOUT_CHG BIT(18) +#define GOTGINT_HST_NEG_DET BIT(17) +#define GOTGINT_HST_NEG_SUC_STS_CHNG BIT(9) +#define GOTGINT_SES_REQ_SUC_STS_CHNG BIT(8) +#define GOTGINT_SES_END_DET BIT(2) #define GAHBCFG HSOTG_REG(0x008) -#define GAHBCFG_AHB_SINGLE (1 << 23) -#define GAHBCFG_NOTI_ALL_DMA_WRIT (1 << 22) -#define GAHBCFG_REM_MEM_SUPP (1 << 21) -#define GAHBCFG_P_TXF_EMP_LVL (1 << 8) -#define GAHBCFG_NP_TXF_EMP_LVL (1 << 7) -#define GAHBCFG_DMA_EN (1 << 5) +#define GAHBCFG_AHB_SINGLE BIT(23) +#define GAHBCFG_NOTI_ALL_DMA_WRIT BIT(22) +#define GAHBCFG_REM_MEM_SUPP BIT(21) +#define GAHBCFG_P_TXF_EMP_LVL BIT(8) +#define GAHBCFG_NP_TXF_EMP_LVL BIT(7) +#define GAHBCFG_DMA_EN BIT(5) #define GAHBCFG_HBSTLEN_MASK (0xf << 1) #define GAHBCFG_HBSTLEN_SHIFT 1 #define GAHBCFG_HBSTLEN_SINGLE 0 @@ -78,38 +78,38 @@ #define GAHBCFG_HBSTLEN_INCR4 3 #define GAHBCFG_HBSTLEN_INCR8 5 #define GAHBCFG_HBSTLEN_INCR16 7 -#define GAHBCFG_GLBL_INTR_EN (1 << 0) +#define GAHBCFG_GLBL_INTR_EN BIT(0) #define GAHBCFG_CTRL_MASK (GAHBCFG_P_TXF_EMP_LVL | \ GAHBCFG_NP_TXF_EMP_LVL | \ GAHBCFG_DMA_EN | \ GAHBCFG_GLBL_INTR_EN) #define GUSBCFG HSOTG_REG(0x00C) -#define GUSBCFG_FORCEDEVMODE (1 << 30) -#define GUSBCFG_FORCEHOSTMODE (1 << 29) -#define GUSBCFG_TXENDDELAY (1 << 28) -#define GUSBCFG_ICTRAFFICPULLREMOVE (1 << 27) -#define GUSBCFG_ICUSBCAP (1 << 26) -#define GUSBCFG_ULPI_INT_PROT_DIS (1 << 25) -#define GUSBCFG_INDICATORPASSTHROUGH (1 << 24) -#define GUSBCFG_INDICATORCOMPLEMENT (1 << 23) -#define GUSBCFG_TERMSELDLPULSE (1 << 22) -#define GUSBCFG_ULPI_INT_VBUS_IND (1 << 21) -#define GUSBCFG_ULPI_EXT_VBUS_DRV (1 << 20) -#define GUSBCFG_ULPI_CLK_SUSP_M (1 << 19) -#define GUSBCFG_ULPI_AUTO_RES (1 << 18) -#define GUSBCFG_ULPI_FS_LS (1 << 17) -#define GUSBCFG_OTG_UTMI_FS_SEL (1 << 16) -#define GUSBCFG_PHY_LP_CLK_SEL (1 << 15) +#define GUSBCFG_FORCEDEVMODE BIT(30) +#define GUSBCFG_FORCEHOSTMODE BIT(29) +#define GUSBCFG_TXENDDELAY BIT(28) +#define GUSBCFG_ICTRAFFICPULLREMOVE BIT(27) +#define GUSBCFG_ICUSBCAP BIT(26) +#define GUSBCFG_ULPI_INT_PROT_DIS BIT(25) +#define GUSBCFG_INDICATORPASSTHROUGH BIT(24) +#define GUSBCFG_INDICATORCOMPLEMENT BIT(23) +#define GUSBCFG_TERMSELDLPULSE BIT(22) +#define GUSBCFG_ULPI_INT_VBUS_IND BIT(21) +#define GUSBCFG_ULPI_EXT_VBUS_DRV BIT(20) +#define GUSBCFG_ULPI_CLK_SUSP_M BIT(19) +#define GUSBCFG_ULPI_AUTO_RES BIT(18) +#define GUSBCFG_ULPI_FS_LS BIT(17) +#define GUSBCFG_OTG_UTMI_FS_SEL BIT(16) +#define GUSBCFG_PHY_LP_CLK_SEL BIT(15) #define GUSBCFG_USBTRDTIM_MASK (0xf << 10) #define GUSBCFG_USBTRDTIM_SHIFT 10 -#define GUSBCFG_HNPCAP (1 << 9) -#define GUSBCFG_SRPCAP (1 << 8) -#define GUSBCFG_DDRSEL (1 << 7) -#define GUSBCFG_PHYSEL (1 << 6) -#define GUSBCFG_FSINTF (1 << 5) -#define GUSBCFG_ULPI_UTMI_SEL (1 << 4) -#define GUSBCFG_PHYIF16 (1 << 3) +#define GUSBCFG_HNPCAP BIT(9) +#define GUSBCFG_SRPCAP BIT(8) +#define GUSBCFG_DDRSEL BIT(7) +#define GUSBCFG_PHYSEL BIT(6) +#define GUSBCFG_FSINTF BIT(5) +#define GUSBCFG_ULPI_UTMI_SEL BIT(4) +#define GUSBCFG_PHYIF16 BIT(3) #define GUSBCFG_PHYIF8 (0 << 3) #define GUSBCFG_TOUTCAL_MASK (0x7 << 0) #define GUSBCFG_TOUTCAL_SHIFT 0 @@ -117,54 +117,54 @@ #define GUSBCFG_TOUTCAL(_x) ((_x) << 0) #define GRSTCTL HSOTG_REG(0x010) -#define GRSTCTL_AHBIDLE (1 << 31) -#define GRSTCTL_DMAREQ (1 << 30) +#define GRSTCTL_AHBIDLE BIT(31) +#define GRSTCTL_DMAREQ BIT(30) #define GRSTCTL_TXFNUM_MASK (0x1f << 6) #define GRSTCTL_TXFNUM_SHIFT 6 #define GRSTCTL_TXFNUM_LIMIT 0x1f #define GRSTCTL_TXFNUM(_x) ((_x) << 6) -#define GRSTCTL_TXFFLSH (1 << 5) -#define GRSTCTL_RXFFLSH (1 << 4) -#define GRSTCTL_IN_TKNQ_FLSH (1 << 3) -#define GRSTCTL_FRMCNTRRST (1 << 2) -#define GRSTCTL_HSFTRST (1 << 1) -#define GRSTCTL_CSFTRST (1 << 0) +#define GRSTCTL_TXFFLSH BIT(5) +#define GRSTCTL_RXFFLSH BIT(4) +#define GRSTCTL_IN_TKNQ_FLSH BIT(3) +#define GRSTCTL_FRMCNTRRST BIT(2) +#define GRSTCTL_HSFTRST BIT(1) +#define GRSTCTL_CSFTRST BIT(0) #define GINTSTS HSOTG_REG(0x014) #define GINTMSK HSOTG_REG(0x018) -#define GINTSTS_WKUPINT (1 << 31) -#define GINTSTS_SESSREQINT (1 << 30) -#define GINTSTS_DISCONNINT (1 << 29) -#define GINTSTS_CONIDSTSCHNG (1 << 28) -#define GINTSTS_LPMTRANRCVD (1 << 27) -#define GINTSTS_PTXFEMP (1 << 26) -#define GINTSTS_HCHINT (1 << 25) -#define GINTSTS_PRTINT (1 << 24) -#define GINTSTS_RESETDET (1 << 23) -#define GINTSTS_FET_SUSP (1 << 22) -#define GINTSTS_INCOMPL_IP (1 << 21) -#define GINTSTS_INCOMPL_SOOUT (1 << 21) -#define GINTSTS_INCOMPL_SOIN (1 << 20) -#define GINTSTS_OEPINT (1 << 19) -#define GINTSTS_IEPINT (1 << 18) -#define GINTSTS_EPMIS (1 << 17) -#define GINTSTS_RESTOREDONE (1 << 16) -#define GINTSTS_EOPF (1 << 15) -#define GINTSTS_ISOUTDROP (1 << 14) -#define GINTSTS_ENUMDONE (1 << 13) -#define GINTSTS_USBRST (1 << 12) -#define GINTSTS_USBSUSP (1 << 11) -#define GINTSTS_ERLYSUSP (1 << 10) -#define GINTSTS_I2CINT (1 << 9) -#define GINTSTS_ULPI_CK_INT (1 << 8) -#define GINTSTS_GOUTNAKEFF (1 << 7) -#define GINTSTS_GINNAKEFF (1 << 6) -#define GINTSTS_NPTXFEMP (1 << 5) -#define GINTSTS_RXFLVL (1 << 4) -#define GINTSTS_SOF (1 << 3) -#define GINTSTS_OTGINT (1 << 2) -#define GINTSTS_MODEMIS (1 << 1) -#define GINTSTS_CURMODE_HOST (1 << 0) +#define GINTSTS_WKUPINT BIT(31) +#define GINTSTS_SESSREQINT BIT(30) +#define GINTSTS_DISCONNINT BIT(29) +#define GINTSTS_CONIDSTSCHNG BIT(28) +#define GINTSTS_LPMTRANRCVD BIT(27) +#define GINTSTS_PTXFEMP BIT(26) +#define GINTSTS_HCHINT BIT(25) +#define GINTSTS_PRTINT BIT(24) +#define GINTSTS_RESETDET BIT(23) +#define GINTSTS_FET_SUSP BIT(22) +#define GINTSTS_INCOMPL_IP BIT(21) +#define GINTSTS_INCOMPL_SOOUT BIT(21) +#define GINTSTS_INCOMPL_SOIN BIT(20) +#define GINTSTS_OEPINT BIT(19) +#define GINTSTS_IEPINT BIT(18) +#define GINTSTS_EPMIS BIT(17) +#define GINTSTS_RESTOREDONE BIT(16) +#define GINTSTS_EOPF BIT(15) +#define GINTSTS_ISOUTDROP BIT(14) +#define GINTSTS_ENUMDONE BIT(13) +#define GINTSTS_USBRST BIT(12) +#define GINTSTS_USBSUSP BIT(11) +#define GINTSTS_ERLYSUSP BIT(10) +#define GINTSTS_I2CINT BIT(9) +#define GINTSTS_ULPI_CK_INT BIT(8) +#define GINTSTS_GOUTNAKEFF BIT(7) +#define GINTSTS_GINNAKEFF BIT(6) +#define GINTSTS_NPTXFEMP BIT(5) +#define GINTSTS_RXFLVL BIT(4) +#define GINTSTS_SOF BIT(3) +#define GINTSTS_OTGINT BIT(2) +#define GINTSTS_MODEMIS BIT(1) +#define GINTSTS_CURMODE_HOST BIT(0) #define GRXSTSR HSOTG_REG(0x01C) #define GRXSTSP HSOTG_REG(0x020) @@ -208,14 +208,14 @@ #define GNPTXSTS_NP_TXF_SPC_AVAIL_GET(_v) (((_v) >> 0) & 0xffff) #define GI2CCTL HSOTG_REG(0x0030) -#define GI2CCTL_BSYDNE (1 << 31) -#define GI2CCTL_RW (1 << 30) -#define GI2CCTL_I2CDATSE0 (1 << 28) +#define GI2CCTL_BSYDNE BIT(31) +#define GI2CCTL_RW BIT(30) +#define GI2CCTL_I2CDATSE0 BIT(28) #define GI2CCTL_I2CDEVADDR_MASK (0x3 << 26) #define GI2CCTL_I2CDEVADDR_SHIFT 26 -#define GI2CCTL_I2CSUSPCTL (1 << 25) -#define GI2CCTL_ACK (1 << 24) -#define GI2CCTL_I2CEN (1 << 23) +#define GI2CCTL_I2CSUSPCTL BIT(25) +#define GI2CCTL_ACK BIT(24) +#define GI2CCTL_I2CEN BIT(23) #define GI2CCTL_ADDR_MASK (0x7f << 16) #define GI2CCTL_ADDR_SHIFT 16 #define GI2CCTL_REGADDR_MASK (0xff << 8) @@ -230,16 +230,16 @@ #define GHWCFG1 HSOTG_REG(0x0044) #define GHWCFG2 HSOTG_REG(0x0048) -#define GHWCFG2_OTG_ENABLE_IC_USB (1 << 31) +#define GHWCFG2_OTG_ENABLE_IC_USB BIT(31) #define GHWCFG2_DEV_TOKEN_Q_DEPTH_MASK (0x1f << 26) #define GHWCFG2_DEV_TOKEN_Q_DEPTH_SHIFT 26 #define GHWCFG2_HOST_PERIO_TX_Q_DEPTH_MASK (0x3 << 24) #define GHWCFG2_HOST_PERIO_TX_Q_DEPTH_SHIFT 24 #define GHWCFG2_NONPERIO_TX_Q_DEPTH_MASK (0x3 << 22) #define GHWCFG2_NONPERIO_TX_Q_DEPTH_SHIFT 22 -#define GHWCFG2_MULTI_PROC_INT (1 << 20) -#define GHWCFG2_DYNAMIC_FIFO (1 << 19) -#define GHWCFG2_PERIO_EP_SUPPORTED (1 << 18) +#define GHWCFG2_MULTI_PROC_INT BIT(20) +#define GHWCFG2_DYNAMIC_FIFO BIT(19) +#define GHWCFG2_PERIO_EP_SUPPORTED BIT(18) #define GHWCFG2_NUM_HOST_CHAN_MASK (0xf << 14) #define GHWCFG2_NUM_HOST_CHAN_SHIFT 14 #define GHWCFG2_NUM_DEV_EP_MASK (0xf << 10) @@ -256,7 +256,7 @@ #define GHWCFG2_HS_PHY_TYPE_UTMI 1 #define GHWCFG2_HS_PHY_TYPE_ULPI 2 #define GHWCFG2_HS_PHY_TYPE_UTMI_ULPI 3 -#define GHWCFG2_POINT2POINT (1 << 5) +#define GHWCFG2_POINT2POINT BIT(5) #define GHWCFG2_ARCHITECTURE_MASK (0x3 << 3) #define GHWCFG2_ARCHITECTURE_SHIFT 3 #define GHWCFG2_SLAVE_ONLY_ARCH 0 @@ -276,32 +276,32 @@ #define GHWCFG3 HSOTG_REG(0x004c) #define GHWCFG3_DFIFO_DEPTH_MASK (0xffff << 16) #define GHWCFG3_DFIFO_DEPTH_SHIFT 16 -#define GHWCFG3_OTG_LPM_EN (1 << 15) -#define GHWCFG3_BC_SUPPORT (1 << 14) -#define GHWCFG3_OTG_ENABLE_HSIC (1 << 13) -#define GHWCFG3_ADP_SUPP (1 << 12) -#define GHWCFG3_SYNCH_RESET_TYPE (1 << 11) -#define GHWCFG3_OPTIONAL_FEATURES (1 << 10) -#define GHWCFG3_VENDOR_CTRL_IF (1 << 9) -#define GHWCFG3_I2C (1 << 8) -#define GHWCFG3_OTG_FUNC (1 << 7) +#define GHWCFG3_OTG_LPM_EN BIT(15) +#define GHWCFG3_BC_SUPPORT BIT(14) +#define GHWCFG3_OTG_ENABLE_HSIC BIT(13) +#define GHWCFG3_ADP_SUPP BIT(12) +#define GHWCFG3_SYNCH_RESET_TYPE BIT(11) +#define GHWCFG3_OPTIONAL_FEATURES BIT(10) +#define GHWCFG3_VENDOR_CTRL_IF BIT(9) +#define GHWCFG3_I2C BIT(8) +#define GHWCFG3_OTG_FUNC BIT(7) #define GHWCFG3_PACKET_SIZE_CNTR_WIDTH_MASK (0x7 << 4) #define GHWCFG3_PACKET_SIZE_CNTR_WIDTH_SHIFT 4 #define GHWCFG3_XFER_SIZE_CNTR_WIDTH_MASK (0xf << 0) #define GHWCFG3_XFER_SIZE_CNTR_WIDTH_SHIFT 0 #define GHWCFG4 HSOTG_REG(0x0050) -#define GHWCFG4_DESC_DMA_DYN (1 << 31) -#define GHWCFG4_DESC_DMA (1 << 30) +#define GHWCFG4_DESC_DMA_DYN BIT(31) +#define GHWCFG4_DESC_DMA BIT(30) #define GHWCFG4_NUM_IN_EPS_MASK (0xf << 26) #define GHWCFG4_NUM_IN_EPS_SHIFT 26 -#define GHWCFG4_DED_FIFO_EN (1 << 25) +#define GHWCFG4_DED_FIFO_EN BIT(25) #define GHWCFG4_DED_FIFO_SHIFT 25 -#define GHWCFG4_SESSION_END_FILT_EN (1 << 24) -#define GHWCFG4_B_VALID_FILT_EN (1 << 23) -#define GHWCFG4_A_VALID_FILT_EN (1 << 22) -#define GHWCFG4_VBUS_VALID_FILT_EN (1 << 21) -#define GHWCFG4_IDDIG_FILT_EN (1 << 20) +#define GHWCFG4_SESSION_END_FILT_EN BIT(24) +#define GHWCFG4_B_VALID_FILT_EN BIT(23) +#define GHWCFG4_A_VALID_FILT_EN BIT(22) +#define GHWCFG4_VBUS_VALID_FILT_EN BIT(21) +#define GHWCFG4_IDDIG_FILT_EN BIT(20) #define GHWCFG4_NUM_DEV_MODE_CTRL_EP_MASK (0xf << 16) #define GHWCFG4_NUM_DEV_MODE_CTRL_EP_SHIFT 16 #define GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK (0x3 << 14) @@ -309,64 +309,64 @@ #define GHWCFG4_UTMI_PHY_DATA_WIDTH_8 0 #define GHWCFG4_UTMI_PHY_DATA_WIDTH_16 1 #define GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16 2 -#define GHWCFG4_XHIBER (1 << 7) -#define GHWCFG4_HIBER (1 << 6) -#define GHWCFG4_MIN_AHB_FREQ (1 << 5) -#define GHWCFG4_POWER_OPTIMIZ (1 << 4) +#define GHWCFG4_XHIBER BIT(7) +#define GHWCFG4_HIBER BIT(6) +#define GHWCFG4_MIN_AHB_FREQ BIT(5) +#define GHWCFG4_POWER_OPTIMIZ BIT(4) #define GHWCFG4_NUM_DEV_PERIO_IN_EP_MASK (0xf << 0) #define GHWCFG4_NUM_DEV_PERIO_IN_EP_SHIFT 0 #define GLPMCFG HSOTG_REG(0x0054) -#define GLPMCFG_INV_SEL_HSIC (1 << 31) -#define GLPMCFG_HSIC_CONNECT (1 << 30) +#define GLPMCFG_INV_SEL_HSIC BIT(31) +#define GLPMCFG_HSIC_CONNECT BIT(30) #define GLPMCFG_RETRY_COUNT_STS_MASK (0x7 << 25) #define GLPMCFG_RETRY_COUNT_STS_SHIFT 25 -#define GLPMCFG_SEND_LPM (1 << 24) +#define GLPMCFG_SEND_LPM BIT(24) #define GLPMCFG_RETRY_COUNT_MASK (0x7 << 21) #define GLPMCFG_RETRY_COUNT_SHIFT 21 #define GLPMCFG_LPM_CHAN_INDEX_MASK (0xf << 17) #define GLPMCFG_LPM_CHAN_INDEX_SHIFT 17 -#define GLPMCFG_SLEEP_STATE_RESUMEOK (1 << 16) -#define GLPMCFG_PRT_SLEEP_STS (1 << 15) +#define GLPMCFG_SLEEP_STATE_RESUMEOK BIT(16) +#define GLPMCFG_PRT_SLEEP_STS BIT(15) #define GLPMCFG_LPM_RESP_MASK (0x3 << 13) #define GLPMCFG_LPM_RESP_SHIFT 13 #define GLPMCFG_HIRD_THRES_MASK (0x1f << 8) #define GLPMCFG_HIRD_THRES_SHIFT 8 #define GLPMCFG_HIRD_THRES_EN (0x10 << 8) -#define GLPMCFG_EN_UTMI_SLEEP (1 << 7) -#define GLPMCFG_REM_WKUP_EN (1 << 6) +#define GLPMCFG_EN_UTMI_SLEEP BIT(7) +#define GLPMCFG_REM_WKUP_EN BIT(6) #define GLPMCFG_HIRD_MASK (0xf << 2) #define GLPMCFG_HIRD_SHIFT 2 -#define GLPMCFG_APPL_RESP (1 << 1) -#define GLPMCFG_LPM_CAP_EN (1 << 0) +#define GLPMCFG_APPL_RESP BIT(1) +#define GLPMCFG_LPM_CAP_EN BIT(0) #define GPWRDN HSOTG_REG(0x0058) #define GPWRDN_MULT_VAL_ID_BC_MASK (0x1f << 24) #define GPWRDN_MULT_VAL_ID_BC_SHIFT 24 -#define GPWRDN_ADP_INT (1 << 23) -#define GPWRDN_BSESSVLD (1 << 22) -#define GPWRDN_IDSTS (1 << 21) +#define GPWRDN_ADP_INT BIT(23) +#define GPWRDN_BSESSVLD BIT(22) +#define GPWRDN_IDSTS BIT(21) #define GPWRDN_LINESTATE_MASK (0x3 << 19) #define GPWRDN_LINESTATE_SHIFT 19 -#define GPWRDN_STS_CHGINT_MSK (1 << 18) -#define GPWRDN_STS_CHGINT (1 << 17) -#define GPWRDN_SRP_DET_MSK (1 << 16) -#define GPWRDN_SRP_DET (1 << 15) -#define GPWRDN_CONNECT_DET_MSK (1 << 14) -#define GPWRDN_CONNECT_DET (1 << 13) -#define GPWRDN_DISCONN_DET_MSK (1 << 12) -#define GPWRDN_DISCONN_DET (1 << 11) -#define GPWRDN_RST_DET_MSK (1 << 10) -#define GPWRDN_RST_DET (1 << 9) -#define GPWRDN_LNSTSCHG_MSK (1 << 8) -#define GPWRDN_LNSTSCHG (1 << 7) -#define GPWRDN_DIS_VBUS (1 << 6) -#define GPWRDN_PWRDNSWTCH (1 << 5) -#define GPWRDN_PWRDNRSTN (1 << 4) -#define GPWRDN_PWRDNCLMP (1 << 3) -#define GPWRDN_RESTORE (1 << 2) -#define GPWRDN_PMUACTV (1 << 1) -#define GPWRDN_PMUINTSEL (1 << 0) +#define GPWRDN_STS_CHGINT_MSK BIT(18) +#define GPWRDN_STS_CHGINT BIT(17) +#define GPWRDN_SRP_DET_MSK BIT(16) +#define GPWRDN_SRP_DET BIT(15) +#define GPWRDN_CONNECT_DET_MSK BIT(14) +#define GPWRDN_CONNECT_DET BIT(13) +#define GPWRDN_DISCONN_DET_MSK BIT(12) +#define GPWRDN_DISCONN_DET BIT(11) +#define GPWRDN_RST_DET_MSK BIT(10) +#define GPWRDN_RST_DET BIT(9) +#define GPWRDN_LNSTSCHG_MSK BIT(8) +#define GPWRDN_LNSTSCHG BIT(7) +#define GPWRDN_DIS_VBUS BIT(6) +#define GPWRDN_PWRDNSWTCH BIT(5) +#define GPWRDN_PWRDNRSTN BIT(4) +#define GPWRDN_PWRDNCLMP BIT(3) +#define GPWRDN_RESTORE BIT(2) +#define GPWRDN_PMUACTV BIT(1) +#define GPWRDN_PMUINTSEL BIT(0) #define GDFIFOCFG HSOTG_REG(0x005c) #define GDFIFOCFG_EPINFOBASE_MASK (0xffff << 16) @@ -377,16 +377,16 @@ #define ADPCTL HSOTG_REG(0x0060) #define ADPCTL_AR_MASK (0x3 << 27) #define ADPCTL_AR_SHIFT 27 -#define ADPCTL_ADP_TMOUT_INT_MSK (1 << 26) -#define ADPCTL_ADP_SNS_INT_MSK (1 << 25) -#define ADPCTL_ADP_PRB_INT_MSK (1 << 24) -#define ADPCTL_ADP_TMOUT_INT (1 << 23) -#define ADPCTL_ADP_SNS_INT (1 << 22) -#define ADPCTL_ADP_PRB_INT (1 << 21) -#define ADPCTL_ADPENA (1 << 20) -#define ADPCTL_ADPRES (1 << 19) -#define ADPCTL_ENASNS (1 << 18) -#define ADPCTL_ENAPRB (1 << 17) +#define ADPCTL_ADP_TMOUT_INT_MSK BIT(26) +#define ADPCTL_ADP_SNS_INT_MSK BIT(25) +#define ADPCTL_ADP_PRB_INT_MSK BIT(24) +#define ADPCTL_ADP_TMOUT_INT BIT(23) +#define ADPCTL_ADP_SNS_INT BIT(22) +#define ADPCTL_ADP_PRB_INT BIT(21) +#define ADPCTL_ADPENA BIT(20) +#define ADPCTL_ADPRES BIT(19) +#define ADPCTL_ENASNS BIT(18) +#define ADPCTL_ENAPRB BIT(17) #define ADPCTL_RTIM_MASK (0x7ff << 6) #define ADPCTL_RTIM_SHIFT 6 #define ADPCTL_PRB_PER_MASK (0x3 << 4) @@ -412,7 +412,7 @@ /* Device mode registers */ #define DCFG HSOTG_REG(0x800) -#define DCFG_DESCDMA_EN (1 << 23) +#define DCFG_DESCDMA_EN BIT(23) #define DCFG_EPMISCNT_MASK (0x1f << 18) #define DCFG_EPMISCNT_SHIFT 18 #define DCFG_EPMISCNT_LIMIT 0x1f @@ -425,7 +425,7 @@ #define DCFG_DEVADDR_SHIFT 4 #define DCFG_DEVADDR_LIMIT 0x7f #define DCFG_DEVADDR(_x) ((_x) << 4) -#define DCFG_NZ_STS_OUT_HSHK (1 << 2) +#define DCFG_NZ_STS_OUT_HSHK BIT(2) #define DCFG_DEVSPD_MASK (0x3 << 0) #define DCFG_DEVSPD_SHIFT 0 #define DCFG_DEVSPD_HS 0 @@ -434,54 +434,54 @@ #define DCFG_DEVSPD_FS48 3 #define DCTL HSOTG_REG(0x804) -#define DCTL_PWRONPRGDONE (1 << 11) -#define DCTL_CGOUTNAK (1 << 10) -#define DCTL_SGOUTNAK (1 << 9) -#define DCTL_CGNPINNAK (1 << 8) -#define DCTL_SGNPINNAK (1 << 7) +#define DCTL_PWRONPRGDONE BIT(11) +#define DCTL_CGOUTNAK BIT(10) +#define DCTL_SGOUTNAK BIT(9) +#define DCTL_CGNPINNAK BIT(8) +#define DCTL_SGNPINNAK BIT(7) #define DCTL_TSTCTL_MASK (0x7 << 4) #define DCTL_TSTCTL_SHIFT 4 -#define DCTL_GOUTNAKSTS (1 << 3) -#define DCTL_GNPINNAKSTS (1 << 2) -#define DCTL_SFTDISCON (1 << 1) -#define DCTL_RMTWKUPSIG (1 << 0) +#define DCTL_GOUTNAKSTS BIT(3) +#define DCTL_GNPINNAKSTS BIT(2) +#define DCTL_SFTDISCON BIT(1) +#define DCTL_RMTWKUPSIG BIT(0) #define DSTS HSOTG_REG(0x808) #define DSTS_SOFFN_MASK (0x3fff << 8) #define DSTS_SOFFN_SHIFT 8 #define DSTS_SOFFN_LIMIT 0x3fff #define DSTS_SOFFN(_x) ((_x) << 8) -#define DSTS_ERRATICERR (1 << 3) +#define DSTS_ERRATICERR BIT(3) #define DSTS_ENUMSPD_MASK (0x3 << 1) #define DSTS_ENUMSPD_SHIFT 1 #define DSTS_ENUMSPD_HS 0 #define DSTS_ENUMSPD_FS 1 #define DSTS_ENUMSPD_LS 2 #define DSTS_ENUMSPD_FS48 3 -#define DSTS_SUSPSTS (1 << 0) +#define DSTS_SUSPSTS BIT(0) #define DIEPMSK HSOTG_REG(0x810) -#define DIEPMSK_NAKMSK (1 << 13) -#define DIEPMSK_BNAININTRMSK (1 << 9) -#define DIEPMSK_TXFIFOUNDRNMSK (1 << 8) -#define DIEPMSK_TXFIFOEMPTY (1 << 7) -#define DIEPMSK_INEPNAKEFFMSK (1 << 6) -#define DIEPMSK_INTKNEPMISMSK (1 << 5) -#define DIEPMSK_INTKNTXFEMPMSK (1 << 4) -#define DIEPMSK_TIMEOUTMSK (1 << 3) -#define DIEPMSK_AHBERRMSK (1 << 2) -#define DIEPMSK_EPDISBLDMSK (1 << 1) -#define DIEPMSK_XFERCOMPLMSK (1 << 0) +#define DIEPMSK_NAKMSK BIT(13) +#define DIEPMSK_BNAININTRMSK BIT(9) +#define DIEPMSK_TXFIFOUNDRNMSK BIT(8) +#define DIEPMSK_TXFIFOEMPTY BIT(7) +#define DIEPMSK_INEPNAKEFFMSK BIT(6) +#define DIEPMSK_INTKNEPMISMSK BIT(5) +#define DIEPMSK_INTKNTXFEMPMSK BIT(4) +#define DIEPMSK_TIMEOUTMSK BIT(3) +#define DIEPMSK_AHBERRMSK BIT(2) +#define DIEPMSK_EPDISBLDMSK BIT(1) +#define DIEPMSK_XFERCOMPLMSK BIT(0) #define DOEPMSK HSOTG_REG(0x814) -#define DOEPMSK_BNAMSK (1 << 9) -#define DOEPMSK_BACK2BACKSETUP (1 << 6) -#define DOEPMSK_STSPHSERCVDMSK (1 << 5) -#define DOEPMSK_OUTTKNEPDISMSK (1 << 4) -#define DOEPMSK_SETUPMSK (1 << 3) -#define DOEPMSK_AHBERRMSK (1 << 2) -#define DOEPMSK_EPDISBLDMSK (1 << 1) -#define DOEPMSK_XFERCOMPLMSK (1 << 0) +#define DOEPMSK_BNAMSK BIT(9) +#define DOEPMSK_BACK2BACKSETUP BIT(6) +#define DOEPMSK_STSPHSERCVDMSK BIT(5) +#define DOEPMSK_OUTTKNEPDISMSK BIT(4) +#define DOEPMSK_SETUPMSK BIT(3) +#define DOEPMSK_AHBERRMSK BIT(2) +#define DOEPMSK_EPDISBLDMSK BIT(1) +#define DOEPMSK_XFERCOMPLMSK BIT(0) #define DAINT HSOTG_REG(0x818) #define DAINTMSK HSOTG_REG(0x81C) @@ -516,30 +516,30 @@ #define D0EPCTL_MPS_16 2 #define D0EPCTL_MPS_8 3 -#define DXEPCTL_EPENA (1 << 31) -#define DXEPCTL_EPDIS (1 << 30) -#define DXEPCTL_SETD1PID (1 << 29) -#define DXEPCTL_SETODDFR (1 << 29) -#define DXEPCTL_SETD0PID (1 << 28) -#define DXEPCTL_SETEVENFR (1 << 28) -#define DXEPCTL_SNAK (1 << 27) -#define DXEPCTL_CNAK (1 << 26) +#define DXEPCTL_EPENA BIT(31) +#define DXEPCTL_EPDIS BIT(30) +#define DXEPCTL_SETD1PID BIT(29) +#define DXEPCTL_SETODDFR BIT(29) +#define DXEPCTL_SETD0PID BIT(28) +#define DXEPCTL_SETEVENFR BIT(28) +#define DXEPCTL_SNAK BIT(27) +#define DXEPCTL_CNAK BIT(26) #define DXEPCTL_TXFNUM_MASK (0xf << 22) #define DXEPCTL_TXFNUM_SHIFT 22 #define DXEPCTL_TXFNUM_LIMIT 0xf #define DXEPCTL_TXFNUM(_x) ((_x) << 22) -#define DXEPCTL_STALL (1 << 21) -#define DXEPCTL_SNP (1 << 20) +#define DXEPCTL_STALL BIT(21) +#define DXEPCTL_SNP BIT(20) #define DXEPCTL_EPTYPE_MASK (0x3 << 18) #define DXEPCTL_EPTYPE_CONTROL (0x0 << 18) #define DXEPCTL_EPTYPE_ISO (0x1 << 18) #define DXEPCTL_EPTYPE_BULK (0x2 << 18) #define DXEPCTL_EPTYPE_INTERRUPT (0x3 << 18) -#define DXEPCTL_NAKSTS (1 << 17) -#define DXEPCTL_DPID (1 << 16) -#define DXEPCTL_EOFRNUM (1 << 16) -#define DXEPCTL_USBACTEP (1 << 15) +#define DXEPCTL_NAKSTS BIT(17) +#define DXEPCTL_DPID BIT(16) +#define DXEPCTL_EOFRNUM BIT(16) +#define DXEPCTL_USBACTEP BIT(15) #define DXEPCTL_NEXTEP_MASK (0xf << 11) #define DXEPCTL_NEXTEP_SHIFT 11 #define DXEPCTL_NEXTEP_LIMIT 0xf @@ -551,26 +551,26 @@ #define DIEPINT(_a) HSOTG_REG(0x908 + ((_a) * 0x20)) #define DOEPINT(_a) HSOTG_REG(0xB08 + ((_a) * 0x20)) -#define DXEPINT_SETUP_RCVD (1 << 15) -#define DXEPINT_NYETINTRPT (1 << 14) -#define DXEPINT_NAKINTRPT (1 << 13) -#define DXEPINT_BBLEERRINTRPT (1 << 12) -#define DXEPINT_PKTDRPSTS (1 << 11) -#define DXEPINT_BNAINTR (1 << 9) -#define DXEPINT_TXFIFOUNDRN (1 << 8) -#define DXEPINT_OUTPKTERR (1 << 8) -#define DXEPINT_TXFEMP (1 << 7) -#define DXEPINT_INEPNAKEFF (1 << 6) -#define DXEPINT_BACK2BACKSETUP (1 << 6) -#define DXEPINT_INTKNEPMIS (1 << 5) -#define DXEPINT_STSPHSERCVD (1 << 5) -#define DXEPINT_INTKNTXFEMP (1 << 4) -#define DXEPINT_OUTTKNEPDIS (1 << 4) -#define DXEPINT_TIMEOUT (1 << 3) -#define DXEPINT_SETUP (1 << 3) -#define DXEPINT_AHBERR (1 << 2) -#define DXEPINT_EPDISBLD (1 << 1) -#define DXEPINT_XFERCOMPL (1 << 0) +#define DXEPINT_SETUP_RCVD BIT(15) +#define DXEPINT_NYETINTRPT BIT(14) +#define DXEPINT_NAKINTRPT BIT(13) +#define DXEPINT_BBLEERRINTRPT BIT(12) +#define DXEPINT_PKTDRPSTS BIT(11) +#define DXEPINT_BNAINTR BIT(9) +#define DXEPINT_TXFIFOUNDRN BIT(8) +#define DXEPINT_OUTPKTERR BIT(8) +#define DXEPINT_TXFEMP BIT(7) +#define DXEPINT_INEPNAKEFF BIT(6) +#define DXEPINT_BACK2BACKSETUP BIT(6) +#define DXEPINT_INTKNEPMIS BIT(5) +#define DXEPINT_STSPHSERCVD BIT(5) +#define DXEPINT_INTKNTXFEMP BIT(4) +#define DXEPINT_OUTTKNEPDIS BIT(4) +#define DXEPINT_TIMEOUT BIT(3) +#define DXEPINT_SETUP BIT(3) +#define DXEPINT_AHBERR BIT(2) +#define DXEPINT_EPDISBLD BIT(1) +#define DXEPINT_XFERCOMPL BIT(0) #define DIEPTSIZ0 HSOTG_REG(0x910) #define DIEPTSIZ0_PKTCNT_MASK (0x3 << 19) @@ -587,7 +587,7 @@ #define DOEPTSIZ0_SUPCNT_SHIFT 29 #define DOEPTSIZ0_SUPCNT_LIMIT 0x3 #define DOEPTSIZ0_SUPCNT(_x) ((_x) << 29) -#define DOEPTSIZ0_PKTCNT (1 << 19) +#define DOEPTSIZ0_PKTCNT BIT(19) #define DOEPTSIZ0_XFERSIZE_MASK (0x7f << 0) #define DOEPTSIZ0_XFERSIZE_SHIFT 0 @@ -614,55 +614,55 @@ #define DTXFSTS(_a) HSOTG_REG(0x918 + ((_a) * 0x20)) #define PCGCTL HSOTG_REG(0x0e00) -#define PCGCTL_IF_DEV_MODE (1 << 31) +#define PCGCTL_IF_DEV_MODE BIT(31) #define PCGCTL_P2HD_PRT_SPD_MASK (0x3 << 29) #define PCGCTL_P2HD_PRT_SPD_SHIFT 29 #define PCGCTL_P2HD_DEV_ENUM_SPD_MASK (0x3 << 27) #define PCGCTL_P2HD_DEV_ENUM_SPD_SHIFT 27 #define PCGCTL_MAC_DEV_ADDR_MASK (0x7f << 20) #define PCGCTL_MAC_DEV_ADDR_SHIFT 20 -#define PCGCTL_MAX_TERMSEL (1 << 19) +#define PCGCTL_MAX_TERMSEL BIT(19) #define PCGCTL_MAX_XCVRSELECT_MASK (0x3 << 17) #define PCGCTL_MAX_XCVRSELECT_SHIFT 17 -#define PCGCTL_PORT_POWER (1 << 16) +#define PCGCTL_PORT_POWER BIT(16) #define PCGCTL_PRT_CLK_SEL_MASK (0x3 << 14) #define PCGCTL_PRT_CLK_SEL_SHIFT 14 -#define PCGCTL_ESS_REG_RESTORED (1 << 13) -#define PCGCTL_EXTND_HIBER_SWITCH (1 << 12) -#define PCGCTL_EXTND_HIBER_PWRCLMP (1 << 11) -#define PCGCTL_ENBL_EXTND_HIBER (1 << 10) -#define PCGCTL_RESTOREMODE (1 << 9) -#define PCGCTL_RESETAFTSUSP (1 << 8) -#define PCGCTL_DEEP_SLEEP (1 << 7) -#define PCGCTL_PHY_IN_SLEEP (1 << 6) -#define PCGCTL_ENBL_SLEEP_GATING (1 << 5) -#define PCGCTL_RSTPDWNMODULE (1 << 3) -#define PCGCTL_PWRCLMP (1 << 2) -#define PCGCTL_GATEHCLK (1 << 1) -#define PCGCTL_STOPPCLK (1 << 0) +#define PCGCTL_ESS_REG_RESTORED BIT(13) +#define PCGCTL_EXTND_HIBER_SWITCH BIT(12) +#define PCGCTL_EXTND_HIBER_PWRCLMP BIT(11) +#define PCGCTL_ENBL_EXTND_HIBER BIT(10) +#define PCGCTL_RESTOREMODE BIT(9) +#define PCGCTL_RESETAFTSUSP BIT(8) +#define PCGCTL_DEEP_SLEEP BIT(7) +#define PCGCTL_PHY_IN_SLEEP BIT(6) +#define PCGCTL_ENBL_SLEEP_GATING BIT(5) +#define PCGCTL_RSTPDWNMODULE BIT(3) +#define PCGCTL_PWRCLMP BIT(2) +#define PCGCTL_GATEHCLK BIT(1) +#define PCGCTL_STOPPCLK BIT(0) #define EPFIFO(_a) HSOTG_REG(0x1000 + ((_a) * 0x1000)) /* Host Mode Registers */ #define HCFG HSOTG_REG(0x0400) -#define HCFG_MODECHTIMEN (1 << 31) -#define HCFG_PERSCHEDENA (1 << 26) +#define HCFG_MODECHTIMEN BIT(31) +#define HCFG_PERSCHEDENA BIT(26) #define HCFG_FRLISTEN_MASK (0x3 << 24) #define HCFG_FRLISTEN_SHIFT 24 #define HCFG_FRLISTEN_8 (0 << 24) #define FRLISTEN_8_SIZE 8 -#define HCFG_FRLISTEN_16 (1 << 24) +#define HCFG_FRLISTEN_16 BIT(24) #define FRLISTEN_16_SIZE 16 #define HCFG_FRLISTEN_32 (2 << 24) #define FRLISTEN_32_SIZE 32 #define HCFG_FRLISTEN_64 (3 << 24) #define FRLISTEN_64_SIZE 64 -#define HCFG_DESCDMA (1 << 23) +#define HCFG_DESCDMA BIT(23) #define HCFG_RESVALID_MASK (0xff << 8) #define HCFG_RESVALID_SHIFT 8 -#define HCFG_ENA32KHZ (1 << 7) -#define HCFG_FSLSSUPP (1 << 2) +#define HCFG_ENA32KHZ BIT(7) +#define HCFG_FSLSSUPP BIT(2) #define HCFG_FSLSPCLKSEL_MASK (0x3 << 0) #define HCFG_FSLSPCLKSEL_SHIFT 0 #define HCFG_FSLSPCLKSEL_30_60_MHZ 0 @@ -672,7 +672,7 @@ #define HFIR HSOTG_REG(0x0404) #define HFIR_FRINT_MASK (0xffff << 0) #define HFIR_FRINT_SHIFT 0 -#define HFIR_RLDCTRL (1 << 16) +#define HFIR_RLDCTRL BIT(16) #define HFNUM HSOTG_REG(0x0408) #define HFNUM_FRREM_MASK (0xffff << 16) @@ -682,12 +682,12 @@ #define HFNUM_MAX_FRNUM 0x3fff #define HPTXSTS HSOTG_REG(0x0410) -#define TXSTS_QTOP_ODD (1 << 31) +#define TXSTS_QTOP_ODD BIT(31) #define TXSTS_QTOP_CHNEP_MASK (0xf << 27) #define TXSTS_QTOP_CHNEP_SHIFT 27 #define TXSTS_QTOP_TOKEN_MASK (0x3 << 25) #define TXSTS_QTOP_TOKEN_SHIFT 25 -#define TXSTS_QTOP_TERMINATE (1 << 24) +#define TXSTS_QTOP_TERMINATE BIT(24) #define TXSTS_QSPCAVAIL_MASK (0xff << 16) #define TXSTS_QSPCAVAIL_SHIFT 16 #define TXSTS_FSPCAVAIL_MASK (0xffff << 0) @@ -705,39 +705,39 @@ #define HPRT0_SPD_LOW_SPEED 2 #define HPRT0_TSTCTL_MASK (0xf << 13) #define HPRT0_TSTCTL_SHIFT 13 -#define HPRT0_PWR (1 << 12) +#define HPRT0_PWR BIT(12) #define HPRT0_LNSTS_MASK (0x3 << 10) #define HPRT0_LNSTS_SHIFT 10 -#define HPRT0_RST (1 << 8) -#define HPRT0_SUSP (1 << 7) -#define HPRT0_RES (1 << 6) -#define HPRT0_OVRCURRCHG (1 << 5) -#define HPRT0_OVRCURRACT (1 << 4) -#define HPRT0_ENACHG (1 << 3) -#define HPRT0_ENA (1 << 2) -#define HPRT0_CONNDET (1 << 1) -#define HPRT0_CONNSTS (1 << 0) +#define HPRT0_RST BIT(8) +#define HPRT0_SUSP BIT(7) +#define HPRT0_RES BIT(6) +#define HPRT0_OVRCURRCHG BIT(5) +#define HPRT0_OVRCURRACT BIT(4) +#define HPRT0_ENACHG BIT(3) +#define HPRT0_ENA BIT(2) +#define HPRT0_CONNDET BIT(1) +#define HPRT0_CONNSTS BIT(0) #define HCCHAR(_ch) HSOTG_REG(0x0500 + 0x20 * (_ch)) -#define HCCHAR_CHENA (1 << 31) -#define HCCHAR_CHDIS (1 << 30) -#define HCCHAR_ODDFRM (1 << 29) +#define HCCHAR_CHENA BIT(31) +#define HCCHAR_CHDIS BIT(30) +#define HCCHAR_ODDFRM BIT(29) #define HCCHAR_DEVADDR_MASK (0x7f << 22) #define HCCHAR_DEVADDR_SHIFT 22 #define HCCHAR_MULTICNT_MASK (0x3 << 20) #define HCCHAR_MULTICNT_SHIFT 20 #define HCCHAR_EPTYPE_MASK (0x3 << 18) #define HCCHAR_EPTYPE_SHIFT 18 -#define HCCHAR_LSPDDEV (1 << 17) -#define HCCHAR_EPDIR (1 << 15) +#define HCCHAR_LSPDDEV BIT(17) +#define HCCHAR_EPDIR BIT(15) #define HCCHAR_EPNUM_MASK (0xf << 11) #define HCCHAR_EPNUM_SHIFT 11 #define HCCHAR_MPS_MASK (0x7ff << 0) #define HCCHAR_MPS_SHIFT 0 #define HCSPLT(_ch) HSOTG_REG(0x0504 + 0x20 * (_ch)) -#define HCSPLT_SPLTENA (1 << 31) -#define HCSPLT_COMPSPLT (1 << 16) +#define HCSPLT_SPLTENA BIT(31) +#define HCSPLT_COMPSPLT BIT(16) #define HCSPLT_XACTPOS_MASK (0x3 << 14) #define HCSPLT_XACTPOS_SHIFT 14 #define HCSPLT_XACTPOS_MID 0 @@ -752,23 +752,23 @@ #define HCINT(_ch) HSOTG_REG(0x0508 + 0x20 * (_ch)) #define HCINTMSK(_ch) HSOTG_REG(0x050c + 0x20 * (_ch)) #define HCINTMSK_RESERVED14_31 (0x3ffff << 14) -#define HCINTMSK_FRM_LIST_ROLL (1 << 13) -#define HCINTMSK_XCS_XACT (1 << 12) -#define HCINTMSK_BNA (1 << 11) -#define HCINTMSK_DATATGLERR (1 << 10) -#define HCINTMSK_FRMOVRUN (1 << 9) -#define HCINTMSK_BBLERR (1 << 8) -#define HCINTMSK_XACTERR (1 << 7) -#define HCINTMSK_NYET (1 << 6) -#define HCINTMSK_ACK (1 << 5) -#define HCINTMSK_NAK (1 << 4) -#define HCINTMSK_STALL (1 << 3) -#define HCINTMSK_AHBERR (1 << 2) -#define HCINTMSK_CHHLTD (1 << 1) -#define HCINTMSK_XFERCOMPL (1 << 0) +#define HCINTMSK_FRM_LIST_ROLL BIT(13) +#define HCINTMSK_XCS_XACT BIT(12) +#define HCINTMSK_BNA BIT(11) +#define HCINTMSK_DATATGLERR BIT(10) +#define HCINTMSK_FRMOVRUN BIT(9) +#define HCINTMSK_BBLERR BIT(8) +#define HCINTMSK_XACTERR BIT(7) +#define HCINTMSK_NYET BIT(6) +#define HCINTMSK_ACK BIT(5) +#define HCINTMSK_NAK BIT(4) +#define HCINTMSK_STALL BIT(3) +#define HCINTMSK_AHBERR BIT(2) +#define HCINTMSK_CHHLTD BIT(1) +#define HCINTMSK_XFERCOMPL BIT(0) #define HCTSIZ(_ch) HSOTG_REG(0x0510 + 0x20 * (_ch)) -#define TSIZ_DOPNG (1 << 31) +#define TSIZ_DOPNG BIT(31) #define TSIZ_SC_MC_PID_MASK (0x3 << 29) #define TSIZ_SC_MC_PID_SHIFT 29 #define TSIZ_SC_MC_PID_DATA0 0 @@ -808,14 +808,14 @@ struct dwc2_dma_desc { /* Host Mode DMA descriptor status quadlet */ -#define HOST_DMA_A (1 << 31) +#define HOST_DMA_A BIT(31) #define HOST_DMA_STS_MASK (0x3 << 28) #define HOST_DMA_STS_SHIFT 28 -#define HOST_DMA_STS_PKTERR (1 << 28) -#define HOST_DMA_EOL (1 << 26) -#define HOST_DMA_IOC (1 << 25) -#define HOST_DMA_SUP (1 << 24) -#define HOST_DMA_ALT_QTD (1 << 23) +#define HOST_DMA_STS_PKTERR BIT(28) +#define HOST_DMA_EOL BIT(26) +#define HOST_DMA_IOC BIT(25) +#define HOST_DMA_SUP BIT(24) +#define HOST_DMA_ALT_QTD BIT(23) #define HOST_DMA_QTD_OFFSET_MASK (0x3f << 17) #define HOST_DMA_QTD_OFFSET_SHIFT 17 #define HOST_DMA_ISOC_NBYTES_MASK (0xfff << 0) @@ -837,11 +837,11 @@ struct dwc2_dma_desc { #define DEV_DMA_STS_SUCC 0 #define DEV_DMA_STS_BUFF_FLUSH 1 #define DEV_DMA_STS_BUFF_ERR 3 -#define DEV_DMA_L (1 << 27) -#define DEV_DMA_SHORT (1 << 26) -#define DEV_DMA_IOC (1 << 25) -#define DEV_DMA_SR (1 << 24) -#define DEV_DMA_MTRF (1 << 23) +#define DEV_DMA_L BIT(27) +#define DEV_DMA_SHORT BIT(26) +#define DEV_DMA_IOC BIT(25) +#define DEV_DMA_SR BIT(24) +#define DEV_DMA_MTRF BIT(23) #define DEV_DMA_ISOC_PID_MASK (0x3 << 23) #define DEV_DMA_ISOC_PID_SHIFT 23 #define DEV_DMA_ISOC_PID_DATA0 0 diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c index bcd1e19b4076..2990c347289f 100644 --- a/drivers/usb/dwc2/params.c +++ b/drivers/usb/dwc2/params.c @@ -38,1157 +38,499 @@ #include "core.h" -static const struct dwc2_core_params params_hi6220 = { - .otg_cap = 2, /* No HNP/SRP capable */ - .otg_ver = 0, /* 1.3 */ - .dma_desc_enable = 0, - .dma_desc_fs_enable = 0, - .speed = 0, /* High Speed */ - .enable_dynamic_fifo = 1, - .en_multiple_tx_fifo = 1, - .host_rx_fifo_size = 512, - .host_nperio_tx_fifo_size = 512, - .host_perio_tx_fifo_size = 512, - .max_transfer_size = 65535, - .max_packet_count = 511, - .host_channels = 16, - .phy_type = 1, /* UTMI */ - .phy_utmi_width = 8, - .phy_ulpi_ddr = 0, /* Single */ - .phy_ulpi_ext_vbus = 0, - .i2c_enable = 0, - .ulpi_fs_ls = 0, - .host_support_fs_ls_low_power = 0, - .host_ls_low_power_phy_clk = 0, /* 48 MHz */ - .ts_dline = 0, - .reload_ctl = 0, - .ahbcfg = GAHBCFG_HBSTLEN_INCR16 << - GAHBCFG_HBSTLEN_SHIFT, - .uframe_sched = 0, - .external_id_pin_ctl = -1, - .hibernation = -1, -}; - -static const struct dwc2_core_params params_bcm2835 = { - .otg_cap = 0, /* HNP/SRP capable */ - .otg_ver = 0, /* 1.3 */ - .dma_desc_enable = 0, - .dma_desc_fs_enable = 0, - .speed = 0, /* High Speed */ - .enable_dynamic_fifo = 1, - .en_multiple_tx_fifo = 1, - .host_rx_fifo_size = 774, /* 774 DWORDs */ - .host_nperio_tx_fifo_size = 256, /* 256 DWORDs */ - .host_perio_tx_fifo_size = 512, /* 512 DWORDs */ - .max_transfer_size = 65535, - .max_packet_count = 511, - .host_channels = 8, - .phy_type = 1, /* UTMI */ - .phy_utmi_width = 8, /* 8 bits */ - .phy_ulpi_ddr = 0, /* Single */ - .phy_ulpi_ext_vbus = 0, - .i2c_enable = 0, - .ulpi_fs_ls = 0, - .host_support_fs_ls_low_power = 0, - .host_ls_low_power_phy_clk = 0, /* 48 MHz */ - .ts_dline = 0, - .reload_ctl = 0, - .ahbcfg = 0x10, - .uframe_sched = 0, - .external_id_pin_ctl = -1, - .hibernation = -1, -}; - -static const struct dwc2_core_params params_rk3066 = { - .otg_cap = 2, /* non-HNP/non-SRP */ - .otg_ver = -1, - .dma_desc_enable = 0, - .dma_desc_fs_enable = 0, - .speed = -1, - .enable_dynamic_fifo = 1, - .en_multiple_tx_fifo = -1, - .host_rx_fifo_size = 525, /* 525 DWORDs */ - .host_nperio_tx_fifo_size = 128, /* 128 DWORDs */ - .host_perio_tx_fifo_size = 256, /* 256 DWORDs */ - .max_transfer_size = -1, - .max_packet_count = -1, - .host_channels = -1, - .phy_type = -1, - .phy_utmi_width = -1, - .phy_ulpi_ddr = -1, - .phy_ulpi_ext_vbus = -1, - .i2c_enable = -1, - .ulpi_fs_ls = -1, - .host_support_fs_ls_low_power = -1, - .host_ls_low_power_phy_clk = -1, - .ts_dline = -1, - .reload_ctl = -1, - .ahbcfg = GAHBCFG_HBSTLEN_INCR16 << - GAHBCFG_HBSTLEN_SHIFT, - .uframe_sched = -1, - .external_id_pin_ctl = -1, - .hibernation = -1, -}; - -static const struct dwc2_core_params params_ltq = { - .otg_cap = 2, /* non-HNP/non-SRP */ - .otg_ver = -1, - .dma_desc_enable = -1, - .dma_desc_fs_enable = -1, - .speed = -1, - .enable_dynamic_fifo = -1, - .en_multiple_tx_fifo = -1, - .host_rx_fifo_size = 288, /* 288 DWORDs */ - .host_nperio_tx_fifo_size = 128, /* 128 DWORDs */ - .host_perio_tx_fifo_size = 96, /* 96 DWORDs */ - .max_transfer_size = 65535, - .max_packet_count = 511, - .host_channels = -1, - .phy_type = -1, - .phy_utmi_width = -1, - .phy_ulpi_ddr = -1, - .phy_ulpi_ext_vbus = -1, - .i2c_enable = -1, - .ulpi_fs_ls = -1, - .host_support_fs_ls_low_power = -1, - .host_ls_low_power_phy_clk = -1, - .ts_dline = -1, - .reload_ctl = -1, - .ahbcfg = GAHBCFG_HBSTLEN_INCR16 << - GAHBCFG_HBSTLEN_SHIFT, - .uframe_sched = -1, - .external_id_pin_ctl = -1, - .hibernation = -1, -}; - -static const struct dwc2_core_params params_amlogic = { - .otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE, - .otg_ver = -1, - .dma_desc_enable = 0, - .dma_desc_fs_enable = 0, - .speed = DWC2_SPEED_PARAM_HIGH, - .enable_dynamic_fifo = 1, - .en_multiple_tx_fifo = -1, - .host_rx_fifo_size = 512, - .host_nperio_tx_fifo_size = 500, - .host_perio_tx_fifo_size = 500, - .max_transfer_size = -1, - .max_packet_count = -1, - .host_channels = 16, - .phy_type = DWC2_PHY_TYPE_PARAM_UTMI, - .phy_utmi_width = -1, - .phy_ulpi_ddr = -1, - .phy_ulpi_ext_vbus = -1, - .i2c_enable = -1, - .ulpi_fs_ls = -1, - .host_support_fs_ls_low_power = -1, - .host_ls_low_power_phy_clk = -1, - .ts_dline = -1, - .reload_ctl = 1, - .ahbcfg = GAHBCFG_HBSTLEN_INCR8 << - GAHBCFG_HBSTLEN_SHIFT, - .uframe_sched = 0, - .external_id_pin_ctl = -1, - .hibernation = -1, -}; - -static const struct dwc2_core_params params_default = { - .otg_cap = -1, - .otg_ver = -1, - - /* - * Disable descriptor dma mode by default as the HW can support - * it, but does not support it for SPLIT transactions. - * Disable it for FS devices as well. - */ - .dma_desc_enable = 0, - .dma_desc_fs_enable = 0, - - .speed = -1, - .enable_dynamic_fifo = -1, - .en_multiple_tx_fifo = -1, - .host_rx_fifo_size = -1, - .host_nperio_tx_fifo_size = -1, - .host_perio_tx_fifo_size = -1, - .max_transfer_size = -1, - .max_packet_count = -1, - .host_channels = -1, - .phy_type = -1, - .phy_utmi_width = -1, - .phy_ulpi_ddr = -1, - .phy_ulpi_ext_vbus = -1, - .i2c_enable = -1, - .ulpi_fs_ls = -1, - .host_support_fs_ls_low_power = -1, - .host_ls_low_power_phy_clk = -1, - .ts_dline = -1, - .reload_ctl = -1, - .ahbcfg = -1, - .uframe_sched = -1, - .external_id_pin_ctl = -1, - .hibernation = -1, -}; - -const struct of_device_id dwc2_of_match_table[] = { - { .compatible = "brcm,bcm2835-usb", .data = ¶ms_bcm2835 }, - { .compatible = "hisilicon,hi6220-usb", .data = ¶ms_hi6220 }, - { .compatible = "rockchip,rk3066-usb", .data = ¶ms_rk3066 }, - { .compatible = "lantiq,arx100-usb", .data = ¶ms_ltq }, - { .compatible = "lantiq,xrx200-usb", .data = ¶ms_ltq }, - { .compatible = "snps,dwc2", .data = NULL }, - { .compatible = "samsung,s3c6400-hsotg", .data = NULL}, - { .compatible = "amlogic,meson8b-usb", .data = ¶ms_amlogic }, - { .compatible = "amlogic,meson-gxbb-usb", .data = ¶ms_amlogic }, - { .compatible = "amcc,dwc-otg", .data = NULL }, - {}, -}; -MODULE_DEVICE_TABLE(of, dwc2_of_match_table); - -static void dwc2_get_device_property(struct dwc2_hsotg *hsotg, - char *property, u8 size, u64 *value) +static void dwc2_set_bcm_params(struct dwc2_hsotg *hsotg) { - u32 val32; - - switch (size) { - case 0: - *value = device_property_read_bool(hsotg->dev, property); - break; - case 1: - case 2: - case 4: - if (device_property_read_u32(hsotg->dev, property, &val32)) - return; - - *value = val32; - break; - case 8: - if (device_property_read_u64(hsotg->dev, property, value)) - return; + struct dwc2_core_params *p = &hsotg->params; - break; - default: - /* - * The size is checked by the only function that calls - * this so this should never happen. - */ - WARN_ON(1); - return; - } + p->host_rx_fifo_size = 774; + p->max_transfer_size = 65535; + p->max_packet_count = 511; + p->ahbcfg = 0x10; + p->uframe_sched = false; } -static void dwc2_set_core_param(void *param, u8 size, u64 value) +static void dwc2_set_his_params(struct dwc2_hsotg *hsotg) { - switch (size) { - case 0: - *((bool *)param) = !!value; - break; - case 1: - *((u8 *)param) = (u8)value; - break; - case 2: - *((u16 *)param) = (u16)value; - break; - case 4: - *((u32 *)param) = (u32)value; - break; - case 8: - *((u64 *)param) = (u64)value; - break; - default: - /* - * The size is checked by the only function that calls - * this so this should never happen. - */ - WARN_ON(1); - return; - } -} + struct dwc2_core_params *p = &hsotg->params; -/** - * dwc2_set_param() - Set a core parameter - * - * @hsotg: Programming view of the DWC_otg controller - * @param: Pointer to the parameter to set - * @lookup: True if the property should be looked up - * @property: The device property to read - * @legacy: The param value to set if @property is not available. This - * will typically be the legacy value set in the static - * params structure. - * @def: The default value - * @min: The minimum value - * @max: The maximum value - * @size: The size of the core parameter in bytes, or 0 for bool. - * - * This function looks up @property and sets the @param to that value. - * If the property doesn't exist it uses the passed-in @value. It will - * verify that the value falls between @min and @max. If it doesn't, - * it will output an error and set the parameter to either @def or, - * failing that, to @min. - * - * The @size is used to write to @param and to query the device - * properties so that this same function can be used with different - * types of parameters. - */ -static void dwc2_set_param(struct dwc2_hsotg *hsotg, void *param, - bool lookup, char *property, u64 legacy, - u64 def, u64 min, u64 max, u8 size) + p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; + p->speed = DWC2_SPEED_PARAM_HIGH; + p->host_rx_fifo_size = 512; + p->host_nperio_tx_fifo_size = 512; + p->host_perio_tx_fifo_size = 512; + p->max_transfer_size = 65535; + p->max_packet_count = 511; + p->host_channels = 16; + p->phy_type = DWC2_PHY_TYPE_PARAM_UTMI; + p->phy_utmi_width = 8; + p->i2c_enable = false; + p->reload_ctl = false; + p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << + GAHBCFG_HBSTLEN_SHIFT; + p->uframe_sched = false; + p->change_speed_quirk = true; +} + +static void dwc2_set_rk_params(struct dwc2_hsotg *hsotg) { - u64 sizemax; - u64 value; - - if (WARN_ON(!hsotg || !param || !property)) - return; - - if (WARN((size > 8) || ((size & (size - 1)) != 0), - "Invalid size %d for %s\n", size, property)) - return; - - dev_vdbg(hsotg->dev, "%s: Setting %s: legacy=%llu, def=%llu, min=%llu, max=%llu, size=%d\n", - __func__, property, legacy, def, min, max, size); - - sizemax = (1ULL << (size * 8)) - 1; - value = legacy; - - /* Override legacy settings. */ - if (lookup) - dwc2_get_device_property(hsotg, property, size, &value); - - /* - * While the value is not valid, try setting it to the default - * value, and failing that, set it to the minimum. - */ - while ((value < min) || (value > max)) { - /* Print an error unless the value is set to auto. */ - if (value != sizemax) - dev_err(hsotg->dev, "Invalid value %llu for param %s\n", - value, property); + struct dwc2_core_params *p = &hsotg->params; - /* - * If we are already the default, just set it to the - * minimum. - */ - if (value == def) { - dev_vdbg(hsotg->dev, "%s: setting value to min=%llu\n", - __func__, min); - value = min; - break; - } + p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; + p->host_rx_fifo_size = 525; + p->host_nperio_tx_fifo_size = 128; + p->host_perio_tx_fifo_size = 256; + p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << + GAHBCFG_HBSTLEN_SHIFT; +} - /* Try the default value */ - dev_vdbg(hsotg->dev, "%s: setting value to default=%llu\n", - __func__, def); - value = def; - } +static void dwc2_set_ltq_params(struct dwc2_hsotg *hsotg) +{ + struct dwc2_core_params *p = &hsotg->params; - dev_dbg(hsotg->dev, "Setting %s to %llu\n", property, value); - dwc2_set_core_param(param, size, value); + p->otg_cap = 2; + p->host_rx_fifo_size = 288; + p->host_nperio_tx_fifo_size = 128; + p->host_perio_tx_fifo_size = 96; + p->max_transfer_size = 65535; + p->max_packet_count = 511; + p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << + GAHBCFG_HBSTLEN_SHIFT; } -/** - * dwc2_set_param_u32() - Set a u32 parameter - * - * See dwc2_set_param(). - */ -static void dwc2_set_param_u32(struct dwc2_hsotg *hsotg, u32 *param, - bool lookup, char *property, u16 legacy, - u16 def, u16 min, u16 max) +static void dwc2_set_amlogic_params(struct dwc2_hsotg *hsotg) { - dwc2_set_param(hsotg, param, lookup, property, - legacy, def, min, max, 4); + struct dwc2_core_params *p = &hsotg->params; + + p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; + p->speed = DWC2_SPEED_PARAM_HIGH; + p->host_rx_fifo_size = 512; + p->host_nperio_tx_fifo_size = 500; + p->host_perio_tx_fifo_size = 500; + p->host_channels = 16; + p->phy_type = DWC2_PHY_TYPE_PARAM_UTMI; + p->ahbcfg = GAHBCFG_HBSTLEN_INCR8 << + GAHBCFG_HBSTLEN_SHIFT; + p->uframe_sched = false; } -/** - * dwc2_set_param_bool() - Set a bool parameter - * - * See dwc2_set_param(). - * - * Note: there is no 'legacy' argument here because there is no legacy - * source of bool params. - */ -static void dwc2_set_param_bool(struct dwc2_hsotg *hsotg, bool *param, - bool lookup, char *property, - bool def, bool min, bool max) +static void dwc2_set_amcc_params(struct dwc2_hsotg *hsotg) { - dwc2_set_param(hsotg, param, lookup, property, - def, def, min, max, 0); + struct dwc2_core_params *p = &hsotg->params; + + p->ahbcfg = GAHBCFG_HBSTLEN_INCR16 << GAHBCFG_HBSTLEN_SHIFT; } -#define DWC2_OUT_OF_BOUNDS(a, b, c) ((a) < (b) || (a) > (c)) +const struct of_device_id dwc2_of_match_table[] = { + { .compatible = "brcm,bcm2835-usb", .data = dwc2_set_bcm_params }, + { .compatible = "hisilicon,hi6220-usb", .data = dwc2_set_his_params }, + { .compatible = "rockchip,rk3066-usb", .data = dwc2_set_rk_params }, + { .compatible = "lantiq,arx100-usb", .data = dwc2_set_ltq_params }, + { .compatible = "lantiq,xrx200-usb", .data = dwc2_set_ltq_params }, + { .compatible = "snps,dwc2" }, + { .compatible = "samsung,s3c6400-hsotg" }, + { .compatible = "amlogic,meson8b-usb", + .data = dwc2_set_amlogic_params }, + { .compatible = "amlogic,meson-gxbb-usb", + .data = dwc2_set_amlogic_params }, + { .compatible = "amcc,dwc-otg", .data = dwc2_set_amcc_params }, + {}, +}; +MODULE_DEVICE_TABLE(of, dwc2_of_match_table); -/* Parameter access functions */ -static void dwc2_set_param_otg_cap(struct dwc2_hsotg *hsotg, int val) +static void dwc2_set_param_otg_cap(struct dwc2_hsotg *hsotg) { - int valid = 1; + u8 val; - switch (val) { - case DWC2_CAP_PARAM_HNP_SRP_CAPABLE: - if (hsotg->hw_params.op_mode != GHWCFG2_OP_MODE_HNP_SRP_CAPABLE) - valid = 0; + switch (hsotg->hw_params.op_mode) { + case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE: + val = DWC2_CAP_PARAM_HNP_SRP_CAPABLE; break; - case DWC2_CAP_PARAM_SRP_ONLY_CAPABLE: - switch (hsotg->hw_params.op_mode) { - case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE: - case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE: - case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE: - case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST: - break; - default: - valid = 0; - break; - } - break; - case DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE: - /* always valid */ + case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE: + case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE: + case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST: + val = DWC2_CAP_PARAM_SRP_ONLY_CAPABLE; break; default: - valid = 0; + val = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; break; } - if (!valid) { - if (val >= 0) - dev_err(hsotg->dev, - "%d invalid for otg_cap parameter. Check HW configuration.\n", - val); - switch (hsotg->hw_params.op_mode) { - case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE: - val = DWC2_CAP_PARAM_HNP_SRP_CAPABLE; - break; - case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE: - case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE: - case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST: - val = DWC2_CAP_PARAM_SRP_ONLY_CAPABLE; - break; - default: - val = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; - break; - } - dev_dbg(hsotg->dev, "Setting otg_cap to %d\n", val); - } - hsotg->params.otg_cap = val; } -static void dwc2_set_param_dma_desc_enable(struct dwc2_hsotg *hsotg, int val) +static void dwc2_set_param_phy_type(struct dwc2_hsotg *hsotg) { - int valid = 1; + int val; + u32 hs_phy_type = hsotg->hw_params.hs_phy_type; - if (val > 0 && (hsotg->params.host_dma <= 0 || - !hsotg->hw_params.dma_desc_enable)) - valid = 0; - if (val < 0) - valid = 0; - - if (!valid) { - if (val >= 0) - dev_err(hsotg->dev, - "%d invalid for dma_desc_enable parameter. Check HW configuration.\n", - val); - val = (hsotg->params.host_dma > 0 && - hsotg->hw_params.dma_desc_enable); - dev_dbg(hsotg->dev, "Setting dma_desc_enable to %d\n", val); + val = DWC2_PHY_TYPE_PARAM_FS; + if (hs_phy_type != GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED) { + if (hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI || + hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI_ULPI) + val = DWC2_PHY_TYPE_PARAM_UTMI; + else + val = DWC2_PHY_TYPE_PARAM_ULPI; } - hsotg->params.dma_desc_enable = val; -} - -static void dwc2_set_param_dma_desc_fs_enable(struct dwc2_hsotg *hsotg, int val) -{ - int valid = 1; - - if (val > 0 && (hsotg->params.host_dma <= 0 || - !hsotg->hw_params.dma_desc_enable)) - valid = 0; - if (val < 0) - valid = 0; - - if (!valid) { - if (val >= 0) - dev_err(hsotg->dev, - "%d invalid for dma_desc_fs_enable parameter. Check HW configuration.\n", - val); - val = (hsotg->params.host_dma > 0 && - hsotg->hw_params.dma_desc_enable); - } + if (dwc2_is_fs_iot(hsotg)) + hsotg->params.phy_type = DWC2_PHY_TYPE_PARAM_FS; - hsotg->params.dma_desc_fs_enable = val; - dev_dbg(hsotg->dev, "Setting dma_desc_fs_enable to %d\n", val); + hsotg->params.phy_type = val; } -static void -dwc2_set_param_host_support_fs_ls_low_power(struct dwc2_hsotg *hsotg, - int val) +static void dwc2_set_param_speed(struct dwc2_hsotg *hsotg) { - if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { - if (val >= 0) { - dev_err(hsotg->dev, - "Wrong value for host_support_fs_low_power\n"); - dev_err(hsotg->dev, - "host_support_fs_low_power must be 0 or 1\n"); - } - val = 0; - dev_dbg(hsotg->dev, - "Setting host_support_fs_low_power to %d\n", val); - } + int val; - hsotg->params.host_support_fs_ls_low_power = val; -} - -static void dwc2_set_param_enable_dynamic_fifo(struct dwc2_hsotg *hsotg, - int val) -{ - int valid = 1; + val = hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS ? + DWC2_SPEED_PARAM_FULL : DWC2_SPEED_PARAM_HIGH; - if (val > 0 && !hsotg->hw_params.enable_dynamic_fifo) - valid = 0; - if (val < 0) - valid = 0; + if (dwc2_is_fs_iot(hsotg)) + val = DWC2_SPEED_PARAM_FULL; - if (!valid) { - if (val >= 0) - dev_err(hsotg->dev, - "%d invalid for enable_dynamic_fifo parameter. Check HW configuration.\n", - val); - val = hsotg->hw_params.enable_dynamic_fifo; - dev_dbg(hsotg->dev, "Setting enable_dynamic_fifo to %d\n", val); - } + if (dwc2_is_hs_iot(hsotg)) + val = DWC2_SPEED_PARAM_HIGH; - hsotg->params.enable_dynamic_fifo = val; + hsotg->params.speed = val; } -static void dwc2_set_param_host_rx_fifo_size(struct dwc2_hsotg *hsotg, int val) +static void dwc2_set_param_phy_utmi_width(struct dwc2_hsotg *hsotg) { - int valid = 1; + int val; - if (val < 16 || val > hsotg->hw_params.rx_fifo_size) - valid = 0; - - if (!valid) { - if (val >= 0) - dev_err(hsotg->dev, - "%d invalid for host_rx_fifo_size. Check HW configuration.\n", - val); - val = hsotg->hw_params.rx_fifo_size; - dev_dbg(hsotg->dev, "Setting host_rx_fifo_size to %d\n", val); - } + val = (hsotg->hw_params.utmi_phy_data_width == + GHWCFG4_UTMI_PHY_DATA_WIDTH_8) ? 8 : 16; - hsotg->params.host_rx_fifo_size = val; + hsotg->params.phy_utmi_width = val; } -static void dwc2_set_param_host_nperio_tx_fifo_size(struct dwc2_hsotg *hsotg, - int val) +static void dwc2_set_param_tx_fifo_sizes(struct dwc2_hsotg *hsotg) { - int valid = 1; - - if (val < 16 || val > hsotg->hw_params.host_nperio_tx_fifo_size) - valid = 0; + struct dwc2_core_params *p = &hsotg->params; + int depth_average; + int fifo_count; + int i; - if (!valid) { - if (val >= 0) - dev_err(hsotg->dev, - "%d invalid for host_nperio_tx_fifo_size. Check HW configuration.\n", - val); - val = hsotg->hw_params.host_nperio_tx_fifo_size; - dev_dbg(hsotg->dev, "Setting host_nperio_tx_fifo_size to %d\n", - val); - } + fifo_count = dwc2_hsotg_tx_fifo_count(hsotg); - hsotg->params.host_nperio_tx_fifo_size = val; + memset(p->g_tx_fifo_size, 0, sizeof(p->g_tx_fifo_size)); + depth_average = dwc2_hsotg_tx_fifo_average_depth(hsotg); + for (i = 1; i <= fifo_count; i++) + p->g_tx_fifo_size[i] = depth_average; } -static void dwc2_set_param_host_perio_tx_fifo_size(struct dwc2_hsotg *hsotg, - int val) +/** + * dwc2_set_default_params() - Set all core parameters to their + * auto-detected default values. + */ +static void dwc2_set_default_params(struct dwc2_hsotg *hsotg) { - int valid = 1; + struct dwc2_hw_params *hw = &hsotg->hw_params; + struct dwc2_core_params *p = &hsotg->params; + bool dma_capable = !(hw->arch == GHWCFG2_SLAVE_ONLY_ARCH); - if (val < 16 || val > hsotg->hw_params.host_perio_tx_fifo_size) - valid = 0; + dwc2_set_param_otg_cap(hsotg); + dwc2_set_param_phy_type(hsotg); + dwc2_set_param_speed(hsotg); + dwc2_set_param_phy_utmi_width(hsotg); + p->phy_ulpi_ddr = false; + p->phy_ulpi_ext_vbus = false; + + p->enable_dynamic_fifo = hw->enable_dynamic_fifo; + p->en_multiple_tx_fifo = hw->en_multiple_tx_fifo; + p->i2c_enable = hw->i2c_enable; + p->ulpi_fs_ls = false; + p->ts_dline = false; + p->reload_ctl = (hw->snpsid >= DWC2_CORE_REV_2_92a); + p->uframe_sched = true; + p->external_id_pin_ctl = false; + p->hibernation = false; + p->max_packet_count = hw->max_packet_count; + p->max_transfer_size = hw->max_transfer_size; + p->ahbcfg = GAHBCFG_HBSTLEN_INCR4 << GAHBCFG_HBSTLEN_SHIFT; - if (!valid) { - if (val >= 0) - dev_err(hsotg->dev, - "%d invalid for host_perio_tx_fifo_size. Check HW configuration.\n", - val); - val = hsotg->hw_params.host_perio_tx_fifo_size; - dev_dbg(hsotg->dev, "Setting host_perio_tx_fifo_size to %d\n", - val); + if ((hsotg->dr_mode == USB_DR_MODE_HOST) || + (hsotg->dr_mode == USB_DR_MODE_OTG)) { + p->host_dma = dma_capable; + p->dma_desc_enable = false; + p->dma_desc_fs_enable = false; + p->host_support_fs_ls_low_power = false; + p->host_ls_low_power_phy_clk = false; + p->host_channels = hw->host_channels; + p->host_rx_fifo_size = hw->rx_fifo_size; + p->host_nperio_tx_fifo_size = hw->host_nperio_tx_fifo_size; + p->host_perio_tx_fifo_size = hw->host_perio_tx_fifo_size; } - hsotg->params.host_perio_tx_fifo_size = val; -} - -static void dwc2_set_param_max_transfer_size(struct dwc2_hsotg *hsotg, int val) -{ - int valid = 1; - - if (val < 2047 || val > hsotg->hw_params.max_transfer_size) - valid = 0; + if ((hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) || + (hsotg->dr_mode == USB_DR_MODE_OTG)) { + p->g_dma = dma_capable; + p->g_dma_desc = hw->dma_desc_enable; - if (!valid) { - if (val >= 0) - dev_err(hsotg->dev, - "%d invalid for max_transfer_size. Check HW configuration.\n", - val); - val = hsotg->hw_params.max_transfer_size; - dev_dbg(hsotg->dev, "Setting max_transfer_size to %d\n", val); + /* + * The values for g_rx_fifo_size (2048) and + * g_np_tx_fifo_size (1024) come from the legacy s3c + * gadget driver. These defaults have been hard-coded + * for some time so many platforms depend on these + * values. Leave them as defaults for now and only + * auto-detect if the hardware does not support the + * default. + */ + p->g_rx_fifo_size = 2048; + p->g_np_tx_fifo_size = 1024; + dwc2_set_param_tx_fifo_sizes(hsotg); } - - hsotg->params.max_transfer_size = val; } -static void dwc2_set_param_max_packet_count(struct dwc2_hsotg *hsotg, int val) +/** + * dwc2_get_device_properties() - Read in device properties. + * + * Read in the device properties and adjust core parameters if needed. + */ +static void dwc2_get_device_properties(struct dwc2_hsotg *hsotg) { - int valid = 1; - - if (val < 15 || val > hsotg->hw_params.max_packet_count) - valid = 0; + struct dwc2_core_params *p = &hsotg->params; + int num; - if (!valid) { - if (val >= 0) - dev_err(hsotg->dev, - "%d invalid for max_packet_count. Check HW configuration.\n", - val); - val = hsotg->hw_params.max_packet_count; - dev_dbg(hsotg->dev, "Setting max_packet_count to %d\n", val); + if ((hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) || + (hsotg->dr_mode == USB_DR_MODE_OTG)) { + device_property_read_u32(hsotg->dev, "g-rx-fifo-size", + &p->g_rx_fifo_size); + + device_property_read_u32(hsotg->dev, "g-np-tx-fifo-size", + &p->g_np_tx_fifo_size); + + num = device_property_read_u32_array(hsotg->dev, + "g-tx-fifo-size", + NULL, 0); + + if (num > 0) { + num = min(num, 15); + memset(p->g_tx_fifo_size, 0, + sizeof(p->g_tx_fifo_size)); + device_property_read_u32_array(hsotg->dev, + "g-tx-fifo-size", + &p->g_tx_fifo_size[1], + num); + } } - - hsotg->params.max_packet_count = val; } -static void dwc2_set_param_host_channels(struct dwc2_hsotg *hsotg, int val) +static void dwc2_check_param_otg_cap(struct dwc2_hsotg *hsotg) { int valid = 1; - if (val < 1 || val > hsotg->hw_params.host_channels) + switch (hsotg->params.otg_cap) { + case DWC2_CAP_PARAM_HNP_SRP_CAPABLE: + if (hsotg->hw_params.op_mode != GHWCFG2_OP_MODE_HNP_SRP_CAPABLE) + valid = 0; + break; + case DWC2_CAP_PARAM_SRP_ONLY_CAPABLE: + switch (hsotg->hw_params.op_mode) { + case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE: + case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE: + case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE: + case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST: + break; + default: + valid = 0; + break; + } + break; + case DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE: + /* always valid */ + break; + default: valid = 0; - - if (!valid) { - if (val >= 0) - dev_err(hsotg->dev, - "%d invalid for host_channels. Check HW configuration.\n", - val); - val = hsotg->hw_params.host_channels; - dev_dbg(hsotg->dev, "Setting host_channels to %d\n", val); + break; } - hsotg->params.host_channels = val; + if (!valid) + dwc2_set_param_otg_cap(hsotg); } -static void dwc2_set_param_phy_type(struct dwc2_hsotg *hsotg, int val) +static void dwc2_check_param_phy_type(struct dwc2_hsotg *hsotg) { int valid = 0; - u32 hs_phy_type, fs_phy_type; - - if (DWC2_OUT_OF_BOUNDS(val, DWC2_PHY_TYPE_PARAM_FS, - DWC2_PHY_TYPE_PARAM_ULPI)) { - if (val >= 0) { - dev_err(hsotg->dev, "Wrong value for phy_type\n"); - dev_err(hsotg->dev, "phy_type must be 0, 1 or 2\n"); - } - - valid = 0; - } + u32 hs_phy_type; + u32 fs_phy_type; hs_phy_type = hsotg->hw_params.hs_phy_type; fs_phy_type = hsotg->hw_params.fs_phy_type; - if (val == DWC2_PHY_TYPE_PARAM_UTMI && - (hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI || - hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI_ULPI)) - valid = 1; - else if (val == DWC2_PHY_TYPE_PARAM_ULPI && - (hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI || - hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI_ULPI)) - valid = 1; - else if (val == DWC2_PHY_TYPE_PARAM_FS && - fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED) - valid = 1; - - if (!valid) { - if (val >= 0) - dev_err(hsotg->dev, - "%d invalid for phy_type. Check HW configuration.\n", - val); - val = DWC2_PHY_TYPE_PARAM_FS; - if (hs_phy_type != GHWCFG2_HS_PHY_TYPE_NOT_SUPPORTED) { - if (hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI || - hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI_ULPI) - val = DWC2_PHY_TYPE_PARAM_UTMI; - else - val = DWC2_PHY_TYPE_PARAM_ULPI; - } - dev_dbg(hsotg->dev, "Setting phy_type to %d\n", val); - } - - hsotg->params.phy_type = val; -} - -static int dwc2_get_param_phy_type(struct dwc2_hsotg *hsotg) -{ - return hsotg->params.phy_type; -} - -static void dwc2_set_param_speed(struct dwc2_hsotg *hsotg, int val) -{ - int valid = 1; - - if (DWC2_OUT_OF_BOUNDS(val, 0, 2)) { - if (val >= 0) { - dev_err(hsotg->dev, "Wrong value for speed parameter\n"); - dev_err(hsotg->dev, "max_speed parameter must be 0, 1, or 2\n"); - } - valid = 0; - } - - if (dwc2_is_hs_iot(hsotg) && - val == DWC2_SPEED_PARAM_LOW) - valid = 0; - - if (val == DWC2_SPEED_PARAM_HIGH && - dwc2_get_param_phy_type(hsotg) == DWC2_PHY_TYPE_PARAM_FS) - valid = 0; - if (!valid) { - if (val >= 0) - dev_err(hsotg->dev, - "%d invalid for speed parameter. Check HW configuration.\n", - val); - val = dwc2_get_param_phy_type(hsotg) == DWC2_PHY_TYPE_PARAM_FS ? - DWC2_SPEED_PARAM_FULL : DWC2_SPEED_PARAM_HIGH; - dev_dbg(hsotg->dev, "Setting speed to %d\n", val); + switch (hsotg->params.phy_type) { + case DWC2_PHY_TYPE_PARAM_FS: + if (fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED) + valid = 1; + break; + case DWC2_PHY_TYPE_PARAM_UTMI: + if ((hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI) || + (hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI_ULPI)) + valid = 1; + break; + case DWC2_PHY_TYPE_PARAM_ULPI: + if ((hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI) || + (hs_phy_type == GHWCFG2_HS_PHY_TYPE_UTMI_ULPI)) + valid = 1; + break; + default: + break; } - hsotg->params.speed = val; + if (!valid) + dwc2_set_param_phy_type(hsotg); } -static void dwc2_set_param_host_ls_low_power_phy_clk(struct dwc2_hsotg *hsotg, - int val) +static void dwc2_check_param_speed(struct dwc2_hsotg *hsotg) { int valid = 1; + int phy_type = hsotg->params.phy_type; + int speed = hsotg->params.speed; - if (DWC2_OUT_OF_BOUNDS(val, DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ, - DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ)) { - if (val >= 0) { - dev_err(hsotg->dev, - "Wrong value for host_ls_low_power_phy_clk parameter\n"); - dev_err(hsotg->dev, - "host_ls_low_power_phy_clk must be 0 or 1\n"); - } - valid = 0; - } - - if (val == DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ && - dwc2_get_param_phy_type(hsotg) == DWC2_PHY_TYPE_PARAM_FS) + switch (speed) { + case DWC2_SPEED_PARAM_HIGH: + if ((hsotg->params.speed == DWC2_SPEED_PARAM_HIGH) && + (phy_type == DWC2_PHY_TYPE_PARAM_FS)) + valid = 0; + break; + case DWC2_SPEED_PARAM_FULL: + case DWC2_SPEED_PARAM_LOW: + break; + default: valid = 0; - - if (!valid) { - if (val >= 0) - dev_err(hsotg->dev, - "%d invalid for host_ls_low_power_phy_clk. Check HW configuration.\n", - val); - val = dwc2_get_param_phy_type(hsotg) == DWC2_PHY_TYPE_PARAM_FS - ? DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_6MHZ - : DWC2_HOST_LS_LOW_POWER_PHY_CLK_PARAM_48MHZ; - dev_dbg(hsotg->dev, "Setting host_ls_low_power_phy_clk to %d\n", - val); - } - - hsotg->params.host_ls_low_power_phy_clk = val; -} - -static void dwc2_set_param_phy_ulpi_ddr(struct dwc2_hsotg *hsotg, int val) -{ - if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { - if (val >= 0) { - dev_err(hsotg->dev, "Wrong value for phy_ulpi_ddr\n"); - dev_err(hsotg->dev, "phy_upli_ddr must be 0 or 1\n"); - } - val = 0; - dev_dbg(hsotg->dev, "Setting phy_upli_ddr to %d\n", val); - } - - hsotg->params.phy_ulpi_ddr = val; -} - -static void dwc2_set_param_phy_ulpi_ext_vbus(struct dwc2_hsotg *hsotg, int val) -{ - if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { - if (val >= 0) { - dev_err(hsotg->dev, - "Wrong value for phy_ulpi_ext_vbus\n"); - dev_err(hsotg->dev, - "phy_ulpi_ext_vbus must be 0 or 1\n"); - } - val = 0; - dev_dbg(hsotg->dev, "Setting phy_ulpi_ext_vbus to %d\n", val); + break; } - hsotg->params.phy_ulpi_ext_vbus = val; + if (!valid) + dwc2_set_param_speed(hsotg); } -static void dwc2_set_param_phy_utmi_width(struct dwc2_hsotg *hsotg, int val) +static void dwc2_check_param_phy_utmi_width(struct dwc2_hsotg *hsotg) { int valid = 0; + int param = hsotg->params.phy_utmi_width; + int width = hsotg->hw_params.utmi_phy_data_width; - switch (hsotg->hw_params.utmi_phy_data_width) { + switch (width) { case GHWCFG4_UTMI_PHY_DATA_WIDTH_8: - valid = (val == 8); + valid = (param == 8); break; case GHWCFG4_UTMI_PHY_DATA_WIDTH_16: - valid = (val == 16); + valid = (param == 16); break; case GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16: - valid = (val == 8 || val == 16); + valid = (param == 8 || param == 16); break; } - if (!valid) { - if (val >= 0) { - dev_err(hsotg->dev, - "%d invalid for phy_utmi_width. Check HW configuration.\n", - val); - } - val = (hsotg->hw_params.utmi_phy_data_width == - GHWCFG4_UTMI_PHY_DATA_WIDTH_8) ? 8 : 16; - dev_dbg(hsotg->dev, "Setting phy_utmi_width to %d\n", val); - } - - hsotg->params.phy_utmi_width = val; -} - -static void dwc2_set_param_ulpi_fs_ls(struct dwc2_hsotg *hsotg, int val) -{ - if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { - if (val >= 0) { - dev_err(hsotg->dev, "Wrong value for ulpi_fs_ls\n"); - dev_err(hsotg->dev, "ulpi_fs_ls must be 0 or 1\n"); - } - val = 0; - dev_dbg(hsotg->dev, "Setting ulpi_fs_ls to %d\n", val); - } - - hsotg->params.ulpi_fs_ls = val; -} - -static void dwc2_set_param_ts_dline(struct dwc2_hsotg *hsotg, int val) -{ - if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { - if (val >= 0) { - dev_err(hsotg->dev, "Wrong value for ts_dline\n"); - dev_err(hsotg->dev, "ts_dline must be 0 or 1\n"); - } - val = 0; - dev_dbg(hsotg->dev, "Setting ts_dline to %d\n", val); - } - - hsotg->params.ts_dline = val; -} - -static void dwc2_set_param_i2c_enable(struct dwc2_hsotg *hsotg, int val) -{ - int valid = 1; - - if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { - if (val >= 0) { - dev_err(hsotg->dev, "Wrong value for i2c_enable\n"); - dev_err(hsotg->dev, "i2c_enable must be 0 or 1\n"); - } - - valid = 0; - } - - if (val == 1 && !(hsotg->hw_params.i2c_enable)) - valid = 0; - - if (!valid) { - if (val >= 0) - dev_err(hsotg->dev, - "%d invalid for i2c_enable. Check HW configuration.\n", - val); - val = hsotg->hw_params.i2c_enable; - dev_dbg(hsotg->dev, "Setting i2c_enable to %d\n", val); - } - - hsotg->params.i2c_enable = val; -} - -static void dwc2_set_param_en_multiple_tx_fifo(struct dwc2_hsotg *hsotg, - int val) -{ - int valid = 1; - - if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { - if (val >= 0) { - dev_err(hsotg->dev, - "Wrong value for en_multiple_tx_fifo,\n"); - dev_err(hsotg->dev, - "en_multiple_tx_fifo must be 0 or 1\n"); - } - valid = 0; - } - - if (val == 1 && !hsotg->hw_params.en_multiple_tx_fifo) - valid = 0; - - if (!valid) { - if (val >= 0) - dev_err(hsotg->dev, - "%d invalid for parameter en_multiple_tx_fifo. Check HW configuration.\n", - val); - val = hsotg->hw_params.en_multiple_tx_fifo; - dev_dbg(hsotg->dev, "Setting en_multiple_tx_fifo to %d\n", val); - } - - hsotg->params.en_multiple_tx_fifo = val; + if (!valid) + dwc2_set_param_phy_utmi_width(hsotg); } -static void dwc2_set_param_reload_ctl(struct dwc2_hsotg *hsotg, int val) +static void dwc2_check_param_tx_fifo_sizes(struct dwc2_hsotg *hsotg) { - int valid = 1; - - if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { - if (val >= 0) { - dev_err(hsotg->dev, - "'%d' invalid for parameter reload_ctl\n", val); - dev_err(hsotg->dev, "reload_ctl must be 0 or 1\n"); - } - valid = 0; - } - - if (val == 1 && hsotg->hw_params.snpsid < DWC2_CORE_REV_2_92a) - valid = 0; - - if (!valid) { - if (val >= 0) - dev_err(hsotg->dev, - "%d invalid for parameter reload_ctl. Check HW configuration.\n", - val); - val = hsotg->hw_params.snpsid >= DWC2_CORE_REV_2_92a; - dev_dbg(hsotg->dev, "Setting reload_ctl to %d\n", val); - } + int fifo_count; + int fifo; + int min; + u32 total = 0; + u32 dptxfszn; - hsotg->params.reload_ctl = val; -} + fifo_count = dwc2_hsotg_tx_fifo_count(hsotg); + min = hsotg->hw_params.en_multiple_tx_fifo ? 16 : 4; -static void dwc2_set_param_ahbcfg(struct dwc2_hsotg *hsotg, int val) -{ - if (val != -1) - hsotg->params.ahbcfg = val; - else - hsotg->params.ahbcfg = GAHBCFG_HBSTLEN_INCR4 << - GAHBCFG_HBSTLEN_SHIFT; -} + for (fifo = 1; fifo <= fifo_count; fifo++) + total += hsotg->params.g_tx_fifo_size[fifo]; -static void dwc2_set_param_otg_ver(struct dwc2_hsotg *hsotg, int val) -{ - if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { - if (val >= 0) { - dev_err(hsotg->dev, - "'%d' invalid for parameter otg_ver\n", val); - dev_err(hsotg->dev, - "otg_ver must be 0 (for OTG 1.3 support) or 1 (for OTG 2.0 support)\n"); - } - val = 0; - dev_dbg(hsotg->dev, "Setting otg_ver to %d\n", val); + if (total > dwc2_hsotg_tx_fifo_total_depth(hsotg) || !total) { + dev_warn(hsotg->dev, "%s: Invalid parameter g-tx-fifo-size, setting to default average\n", + __func__); + dwc2_set_param_tx_fifo_sizes(hsotg); } - hsotg->params.otg_ver = val; -} + for (fifo = 1; fifo <= fifo_count; fifo++) { + dptxfszn = (dwc2_readl(hsotg->regs + DPTXFSIZN(fifo)) & + FIFOSIZE_DEPTH_MASK) >> FIFOSIZE_DEPTH_SHIFT; -static void dwc2_set_param_uframe_sched(struct dwc2_hsotg *hsotg, int val) -{ - if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { - if (val >= 0) { - dev_err(hsotg->dev, - "'%d' invalid for parameter uframe_sched\n", - val); - dev_err(hsotg->dev, "uframe_sched must be 0 or 1\n"); + if (hsotg->params.g_tx_fifo_size[fifo] < min || + hsotg->params.g_tx_fifo_size[fifo] > dptxfszn) { + dev_warn(hsotg->dev, "%s: Invalid parameter g_tx_fifo_size[%d]=%d\n", + __func__, fifo, + hsotg->params.g_tx_fifo_size[fifo]); + hsotg->params.g_tx_fifo_size[fifo] = dptxfszn; } - val = 1; - dev_dbg(hsotg->dev, "Setting uframe_sched to %d\n", val); } - - hsotg->params.uframe_sched = val; } -static void dwc2_set_param_external_id_pin_ctl(struct dwc2_hsotg *hsotg, - int val) -{ - if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { - if (val >= 0) { - dev_err(hsotg->dev, - "'%d' invalid for parameter external_id_pin_ctl\n", - val); - dev_err(hsotg->dev, "external_id_pin_ctl must be 0 or 1\n"); - } - val = 0; - dev_dbg(hsotg->dev, "Setting external_id_pin_ctl to %d\n", val); - } +#define CHECK_RANGE(_param, _min, _max, _def) do { \ + if ((hsotg->params._param) < (_min) || \ + (hsotg->params._param) > (_max)) { \ + dev_warn(hsotg->dev, "%s: Invalid parameter %s=%d\n", \ + __func__, #_param, hsotg->params._param); \ + hsotg->params._param = (_def); \ + } \ + } while (0) - hsotg->params.external_id_pin_ctl = val; -} +#define CHECK_BOOL(_param, _check) do { \ + if (hsotg->params._param && !(_check)) { \ + dev_warn(hsotg->dev, "%s: Invalid parameter %s=%d\n", \ + __func__, #_param, hsotg->params._param); \ + hsotg->params._param = false; \ + } \ + } while (0) -static void dwc2_set_param_hibernation(struct dwc2_hsotg *hsotg, - int val) -{ - if (DWC2_OUT_OF_BOUNDS(val, 0, 1)) { - if (val >= 0) { - dev_err(hsotg->dev, - "'%d' invalid for parameter hibernation\n", - val); - dev_err(hsotg->dev, "hibernation must be 0 or 1\n"); - } - val = 0; - dev_dbg(hsotg->dev, "Setting hibernation to %d\n", val); - } - - hsotg->params.hibernation = val; -} - -static void dwc2_set_param_tx_fifo_sizes(struct dwc2_hsotg *hsotg) -{ - int i; - int num; - char *property = "g-tx-fifo-size"; - struct dwc2_core_params *p = &hsotg->params; - - memset(p->g_tx_fifo_size, 0, sizeof(p->g_tx_fifo_size)); - - /* Read tx fifo sizes */ - num = device_property_read_u32_array(hsotg->dev, property, NULL, 0); - - if (num > 0) { - device_property_read_u32_array(hsotg->dev, property, - &p->g_tx_fifo_size[1], - num); - } else { - u32 p_tx_fifo[] = DWC2_G_P_LEGACY_TX_FIFO_SIZE; - - memcpy(&p->g_tx_fifo_size[1], - p_tx_fifo, - sizeof(p_tx_fifo)); - - num = ARRAY_SIZE(p_tx_fifo); - } - - for (i = 0; i < num; i++) { - if ((i + 1) >= ARRAY_SIZE(p->g_tx_fifo_size)) - break; - - dev_dbg(hsotg->dev, "Setting %s[%d] to %d\n", - property, i + 1, p->g_tx_fifo_size[i + 1]); - } -} - -static void dwc2_set_gadget_dma(struct dwc2_hsotg *hsotg) +static void dwc2_check_params(struct dwc2_hsotg *hsotg) { struct dwc2_hw_params *hw = &hsotg->hw_params; struct dwc2_core_params *p = &hsotg->params; bool dma_capable = !(hw->arch == GHWCFG2_SLAVE_ONLY_ARCH); - /* Buffer DMA */ - dwc2_set_param_bool(hsotg, &p->g_dma, - false, "gadget-dma", - dma_capable, false, - dma_capable); - - /* DMA Descriptor */ - dwc2_set_param_bool(hsotg, &p->g_dma_desc, false, - "gadget-dma-desc", - !!hw->dma_desc_enable, false, - !!hw->dma_desc_enable); -} + dwc2_check_param_otg_cap(hsotg); + dwc2_check_param_phy_type(hsotg); + dwc2_check_param_speed(hsotg); + dwc2_check_param_phy_utmi_width(hsotg); + CHECK_BOOL(enable_dynamic_fifo, hw->enable_dynamic_fifo); + CHECK_BOOL(en_multiple_tx_fifo, hw->en_multiple_tx_fifo); + CHECK_BOOL(i2c_enable, hw->i2c_enable); + CHECK_BOOL(reload_ctl, (hsotg->hw_params.snpsid > DWC2_CORE_REV_2_92a)); + CHECK_RANGE(max_packet_count, + 15, hw->max_packet_count, + hw->max_packet_count); + CHECK_RANGE(max_transfer_size, + 2047, hw->max_transfer_size, + hw->max_transfer_size); -/** - * dwc2_set_parameters() - Set all core parameters. - * - * @hsotg: Programming view of the DWC_otg controller - * @params: The parameters to set - */ -static void dwc2_set_parameters(struct dwc2_hsotg *hsotg, - const struct dwc2_core_params *params) -{ - struct dwc2_hw_params *hw = &hsotg->hw_params; - struct dwc2_core_params *p = &hsotg->params; - bool dma_capable = !(hw->arch == GHWCFG2_SLAVE_ONLY_ARCH); - - dwc2_set_param_otg_cap(hsotg, params->otg_cap); if ((hsotg->dr_mode == USB_DR_MODE_HOST) || (hsotg->dr_mode == USB_DR_MODE_OTG)) { - dev_dbg(hsotg->dev, "Setting HOST parameters\n"); - - dwc2_set_param_bool(hsotg, &p->host_dma, - false, "host-dma", - dma_capable, false, - dma_capable); - dwc2_set_param_host_rx_fifo_size(hsotg, - params->host_rx_fifo_size); - dwc2_set_param_host_nperio_tx_fifo_size(hsotg, - params->host_nperio_tx_fifo_size); - dwc2_set_param_host_perio_tx_fifo_size(hsotg, - params->host_perio_tx_fifo_size); + CHECK_BOOL(host_dma, dma_capable); + CHECK_BOOL(dma_desc_enable, p->host_dma); + CHECK_BOOL(dma_desc_fs_enable, p->dma_desc_enable); + CHECK_BOOL(host_ls_low_power_phy_clk, + p->phy_type == DWC2_PHY_TYPE_PARAM_FS); + CHECK_RANGE(host_channels, + 1, hw->host_channels, + hw->host_channels); + CHECK_RANGE(host_rx_fifo_size, + 16, hw->rx_fifo_size, + hw->rx_fifo_size); + CHECK_RANGE(host_nperio_tx_fifo_size, + 16, hw->host_nperio_tx_fifo_size, + hw->host_nperio_tx_fifo_size); + CHECK_RANGE(host_perio_tx_fifo_size, + 16, hw->host_perio_tx_fifo_size, + hw->host_perio_tx_fifo_size); } - dwc2_set_param_dma_desc_enable(hsotg, params->dma_desc_enable); - dwc2_set_param_dma_desc_fs_enable(hsotg, params->dma_desc_fs_enable); - - dwc2_set_param_host_support_fs_ls_low_power(hsotg, - params->host_support_fs_ls_low_power); - dwc2_set_param_enable_dynamic_fifo(hsotg, - params->enable_dynamic_fifo); - dwc2_set_param_max_transfer_size(hsotg, - params->max_transfer_size); - dwc2_set_param_max_packet_count(hsotg, - params->max_packet_count); - dwc2_set_param_host_channels(hsotg, params->host_channels); - dwc2_set_param_phy_type(hsotg, params->phy_type); - dwc2_set_param_speed(hsotg, params->speed); - dwc2_set_param_host_ls_low_power_phy_clk(hsotg, - params->host_ls_low_power_phy_clk); - dwc2_set_param_phy_ulpi_ddr(hsotg, params->phy_ulpi_ddr); - dwc2_set_param_phy_ulpi_ext_vbus(hsotg, - params->phy_ulpi_ext_vbus); - dwc2_set_param_phy_utmi_width(hsotg, params->phy_utmi_width); - dwc2_set_param_ulpi_fs_ls(hsotg, params->ulpi_fs_ls); - dwc2_set_param_ts_dline(hsotg, params->ts_dline); - dwc2_set_param_i2c_enable(hsotg, params->i2c_enable); - dwc2_set_param_en_multiple_tx_fifo(hsotg, - params->en_multiple_tx_fifo); - dwc2_set_param_reload_ctl(hsotg, params->reload_ctl); - dwc2_set_param_ahbcfg(hsotg, params->ahbcfg); - dwc2_set_param_otg_ver(hsotg, params->otg_ver); - dwc2_set_param_uframe_sched(hsotg, params->uframe_sched); - dwc2_set_param_external_id_pin_ctl(hsotg, params->external_id_pin_ctl); - dwc2_set_param_hibernation(hsotg, params->hibernation); - /* - * Set devicetree-only parameters. These parameters do not - * take any values from @params. - */ if ((hsotg->dr_mode == USB_DR_MODE_PERIPHERAL) || (hsotg->dr_mode == USB_DR_MODE_OTG)) { - dev_dbg(hsotg->dev, "Setting peripheral device properties\n"); - - dwc2_set_gadget_dma(hsotg); - - /* - * The values for g_rx_fifo_size (2048) and - * g_np_tx_fifo_size (1024) come from the legacy s3c - * gadget driver. These defaults have been hard-coded - * for some time so many platforms depend on these - * values. Leave them as defaults for now and only - * auto-detect if the hardware does not support the - * default. - */ - dwc2_set_param_u32(hsotg, &p->g_rx_fifo_size, - true, "g-rx-fifo-size", 2048, - hw->rx_fifo_size, - 16, hw->rx_fifo_size); - - dwc2_set_param_u32(hsotg, &p->g_np_tx_fifo_size, - true, "g-np-tx-fifo-size", 1024, - hw->dev_nperio_tx_fifo_size, - 16, hw->dev_nperio_tx_fifo_size); - - dwc2_set_param_tx_fifo_sizes(hsotg); + CHECK_BOOL(g_dma, dma_capable); + CHECK_BOOL(g_dma_desc, (p->g_dma && hw->dma_desc_enable)); + CHECK_RANGE(g_rx_fifo_size, + 16, hw->rx_fifo_size, + hw->rx_fifo_size); + CHECK_RANGE(g_np_tx_fifo_size, + 16, hw->dev_nperio_tx_fifo_size, + hw->dev_nperio_tx_fifo_size); + dwc2_check_param_tx_fifo_sizes(hsotg); } } @@ -1211,8 +553,6 @@ static void dwc2_get_host_hwparams(struct dwc2_hsotg *hsotg) gnptxfsiz = dwc2_readl(hsotg->regs + GNPTXFSIZ); hptxfsiz = dwc2_readl(hsotg->regs + HPTXFSIZ); - dev_dbg(hsotg->dev, "gnptxfsiz=%08x\n", gnptxfsiz); - dev_dbg(hsotg->dev, "hptxfsiz=%08x\n", hptxfsiz); if (forced) dwc2_clear_force_mode(hsotg); @@ -1240,7 +580,6 @@ static void dwc2_get_dev_hwparams(struct dwc2_hsotg *hsotg) forced = dwc2_force_mode_if_needed(hsotg, false); gnptxfsiz = dwc2_readl(hsotg->regs + GNPTXFSIZ); - dev_dbg(hsotg->dev, "gnptxfsiz=%08x\n", gnptxfsiz); if (forced) dwc2_clear_force_mode(hsotg); @@ -1286,12 +625,6 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg) hwcfg4 = dwc2_readl(hsotg->regs + GHWCFG4); grxfsiz = dwc2_readl(hsotg->regs + GRXFSIZ); - dev_dbg(hsotg->dev, "hwcfg1=%08x\n", hwcfg1); - dev_dbg(hsotg->dev, "hwcfg2=%08x\n", hwcfg2); - dev_dbg(hsotg->dev, "hwcfg3=%08x\n", hwcfg3); - dev_dbg(hsotg->dev, "hwcfg4=%08x\n", hwcfg4); - dev_dbg(hsotg->dev, "grxfsiz=%08x\n", grxfsiz); - /* * Host specific hardware parameters. Reading these parameters * requires the controller to be in host mode. The mode will @@ -1351,73 +684,24 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg) hw->rx_fifo_size = (grxfsiz & GRXFSIZ_DEPTH_MASK) >> GRXFSIZ_DEPTH_SHIFT; - dev_dbg(hsotg->dev, "Detected values from hardware:\n"); - dev_dbg(hsotg->dev, " op_mode=%d\n", - hw->op_mode); - dev_dbg(hsotg->dev, " arch=%d\n", - hw->arch); - dev_dbg(hsotg->dev, " dma_desc_enable=%d\n", - hw->dma_desc_enable); - dev_dbg(hsotg->dev, " power_optimized=%d\n", - hw->power_optimized); - dev_dbg(hsotg->dev, " i2c_enable=%d\n", - hw->i2c_enable); - dev_dbg(hsotg->dev, " hs_phy_type=%d\n", - hw->hs_phy_type); - dev_dbg(hsotg->dev, " fs_phy_type=%d\n", - hw->fs_phy_type); - dev_dbg(hsotg->dev, " utmi_phy_data_width=%d\n", - hw->utmi_phy_data_width); - dev_dbg(hsotg->dev, " num_dev_ep=%d\n", - hw->num_dev_ep); - dev_dbg(hsotg->dev, " num_dev_perio_in_ep=%d\n", - hw->num_dev_perio_in_ep); - dev_dbg(hsotg->dev, " host_channels=%d\n", - hw->host_channels); - dev_dbg(hsotg->dev, " max_transfer_size=%d\n", - hw->max_transfer_size); - dev_dbg(hsotg->dev, " max_packet_count=%d\n", - hw->max_packet_count); - dev_dbg(hsotg->dev, " nperio_tx_q_depth=0x%0x\n", - hw->nperio_tx_q_depth); - dev_dbg(hsotg->dev, " host_perio_tx_q_depth=0x%0x\n", - hw->host_perio_tx_q_depth); - dev_dbg(hsotg->dev, " dev_token_q_depth=0x%0x\n", - hw->dev_token_q_depth); - dev_dbg(hsotg->dev, " enable_dynamic_fifo=%d\n", - hw->enable_dynamic_fifo); - dev_dbg(hsotg->dev, " en_multiple_tx_fifo=%d\n", - hw->en_multiple_tx_fifo); - dev_dbg(hsotg->dev, " total_fifo_size=%d\n", - hw->total_fifo_size); - dev_dbg(hsotg->dev, " rx_fifo_size=%d\n", - hw->rx_fifo_size); - dev_dbg(hsotg->dev, " host_nperio_tx_fifo_size=%d\n", - hw->host_nperio_tx_fifo_size); - dev_dbg(hsotg->dev, " host_perio_tx_fifo_size=%d\n", - hw->host_perio_tx_fifo_size); - dev_dbg(hsotg->dev, "\n"); - return 0; } int dwc2_init_params(struct dwc2_hsotg *hsotg) { const struct of_device_id *match; - struct dwc2_core_params params; + void (*set_params)(void *data); + + dwc2_set_default_params(hsotg); + dwc2_get_device_properties(hsotg); match = of_match_device(dwc2_of_match_table, hsotg->dev); - if (match && match->data) - params = *((struct dwc2_core_params *)match->data); - else - params = params_default; - - if (dwc2_is_fs_iot(hsotg)) { - params.speed = DWC2_SPEED_PARAM_FULL; - params.phy_type = DWC2_PHY_TYPE_PARAM_FS; + if (match && match->data) { + set_params = match->data; + set_params(hsotg); } - dwc2_set_parameters(hsotg, ¶ms); + dwc2_check_params(hsotg); return 0; } diff --git a/drivers/usb/dwc2/pci.c b/drivers/usb/dwc2/pci.c index a23329e3d7cd..fdeb8c7bf30a 100644 --- a/drivers/usb/dwc2/pci.c +++ b/drivers/usb/dwc2/pci.c @@ -87,7 +87,7 @@ static void dwc2_pci_remove(struct pci_dev *pci) } static int dwc2_pci_probe(struct pci_dev *pci, - const struct pci_device_id *id) + const struct pci_device_id *id) { struct resource res[2]; struct platform_device *dwc2; diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index 4fc8c603afb8..9564bc76c56f 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -111,7 +111,7 @@ static int dwc2_get_dr_mode(struct dwc2_hsotg *hsotg) if (mode != hsotg->dr_mode) { dev_warn(hsotg->dev, - "Configuration mismatch. dr_mode forced to %s\n", + "Configuration mismatch. dr_mode forced to %s\n", mode == USB_DR_MODE_HOST ? "host" : "device"); hsotg->dr_mode = mode; @@ -136,11 +136,11 @@ static int __dwc2_lowlevel_hw_enable(struct dwc2_hsotg *hsotg) return ret; } - if (hsotg->uphy) + if (hsotg->uphy) { ret = usb_phy_init(hsotg->uphy); - else if (hsotg->plat && hsotg->plat->phy_init) + } else if (hsotg->plat && hsotg->plat->phy_init) { ret = hsotg->plat->phy_init(pdev, hsotg->plat->phy_type); - else { + } else { ret = phy_power_on(hsotg->phy); if (ret == 0) ret = phy_init(hsotg->phy); @@ -170,11 +170,11 @@ static int __dwc2_lowlevel_hw_disable(struct dwc2_hsotg *hsotg) struct platform_device *pdev = to_platform_device(hsotg->dev); int ret = 0; - if (hsotg->uphy) + if (hsotg->uphy) { usb_phy_shutdown(hsotg->uphy); - else if (hsotg->plat && hsotg->plat->phy_exit) + } else if (hsotg->plat && hsotg->plat->phy_exit) { ret = hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type); - else { + } else { ret = phy_exit(hsotg->phy); if (ret == 0) ret = phy_power_off(hsotg->phy); @@ -445,7 +445,7 @@ static int dwc2_driver_probe(struct platform_device *dev) } if (hsotg->dr_mode != USB_DR_MODE_PERIPHERAL) { - retval = dwc2_hcd_init(hsotg, hsotg->irq); + retval = dwc2_hcd_init(hsotg); if (retval) { if (hsotg->gadget_enabled) dwc2_hsotg_remove(hsotg); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 14b760209680..2b9e4ca3c932 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -40,6 +40,7 @@ /* Global constants */ #define DWC3_PULL_UP_TIMEOUT 500 /* ms */ #define DWC3_ZLP_BUF_SIZE 1024 /* size of a superspeed bulk */ +#define DWC3_BOUNCE_SIZE 1024 /* size of a superspeed bulk */ #define DWC3_EP0_BOUNCE_SIZE 512 #define DWC3_ENDPOINTS_NUM 32 #define DWC3_XHCI_RESOURCES_NUM 2 @@ -724,6 +725,7 @@ struct dwc3_hwparams { * @epnum: endpoint number to which this request refers * @trb: pointer to struct dwc3_trb * @trb_dma: DMA address of @trb + * @unaligned: true for OUT endpoints with length not divisible by maxp * @direction: IN or OUT direction flag * @mapped: true when request has been dma-mapped * @queued: true when request has been queued to HW @@ -740,6 +742,7 @@ struct dwc3_request { struct dwc3_trb *trb; dma_addr_t trb_dma; + unsigned unaligned:1; unsigned direction:1; unsigned mapped:1; unsigned started:1; @@ -857,12 +860,14 @@ struct dwc3_scratchpad_array { struct dwc3 { struct usb_ctrlrequest *ctrl_req; struct dwc3_trb *ep0_trb; + void *bounce; void *ep0_bounce; void *zlp_buf; void *scratchbuf; u8 *setup_buf; dma_addr_t ctrl_req_addr; dma_addr_t ep0_trb_addr; + dma_addr_t bounce_addr; dma_addr_t ep0_bounce_addr; dma_addr_t scratch_addr; struct dwc3_request ep0_usb_req; diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c index e956306d9b0f..1515d45ebcec 100644 --- a/drivers/usb/dwc3/dwc3-exynos.c +++ b/drivers/usb/dwc3/dwc3-exynos.c @@ -128,10 +128,8 @@ static int dwc3_exynos_probe(struct platform_device *pdev) clk_prepare_enable(exynos->clk); exynos->susp_clk = devm_clk_get(dev, "usbdrd30_susp_clk"); - if (IS_ERR(exynos->susp_clk)) { - dev_info(dev, "no suspend clk specified\n"); + if (IS_ERR(exynos->susp_clk)) exynos->susp_clk = NULL; - } clk_prepare_enable(exynos->susp_clk); if (of_device_is_compatible(node, "samsung,exynos7-dwusb3")) { @@ -290,7 +288,6 @@ static struct platform_driver dwc3_exynos_driver = { module_platform_driver(dwc3_exynos_driver); -MODULE_ALIAS("platform:exynos-dwc3"); MODULE_AUTHOR("Anton Tikhomirov <av.tikhomirov@samsung.com>"); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("DesignWare USB3 EXYNOS Glue Layer"); diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index eb1b9cb3f9d1..2092e46b1380 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -426,20 +426,20 @@ static int dwc3_omap_extcon_register(struct dwc3_omap *omap) } omap->vbus_nb.notifier_call = dwc3_omap_vbus_notifier; - ret = extcon_register_notifier(edev, EXTCON_USB, - &omap->vbus_nb); + ret = devm_extcon_register_notifier(omap->dev, edev, + EXTCON_USB, &omap->vbus_nb); if (ret < 0) dev_vdbg(omap->dev, "failed to register notifier for USB\n"); omap->id_nb.notifier_call = dwc3_omap_id_notifier; - ret = extcon_register_notifier(edev, EXTCON_USB_HOST, - &omap->id_nb); + ret = devm_extcon_register_notifier(omap->dev, edev, + EXTCON_USB_HOST, &omap->id_nb); if (ret < 0) dev_vdbg(omap->dev, "failed to register notifier for USB-HOST\n"); - if (extcon_get_cable_state_(edev, EXTCON_USB) == true) + if (extcon_get_state(edev, EXTCON_USB) == true) dwc3_omap_set_mailbox(omap, OMAP_DWC3_VBUS_VALID); - if (extcon_get_cable_state_(edev, EXTCON_USB_HOST) == true) + if (extcon_get_state(edev, EXTCON_USB_HOST) == true) dwc3_omap_set_mailbox(omap, OMAP_DWC3_ID_GROUND); omap->edev = edev; @@ -528,17 +528,13 @@ static int dwc3_omap_probe(struct platform_device *pdev) ret = of_platform_populate(node, NULL, NULL, dev); if (ret) { dev_err(&pdev->dev, "failed to create dwc3 core\n"); - goto err2; + goto err1; } dwc3_omap_enable_irqs(omap); enable_irq(omap->irq); return 0; -err2: - extcon_unregister_notifier(omap->edev, EXTCON_USB, &omap->vbus_nb); - extcon_unregister_notifier(omap->edev, EXTCON_USB_HOST, &omap->id_nb); - err1: pm_runtime_put_sync(dev); pm_runtime_disable(dev); @@ -550,8 +546,6 @@ static int dwc3_omap_remove(struct platform_device *pdev) { struct dwc3_omap *omap = platform_get_drvdata(pdev); - extcon_unregister_notifier(omap->edev, EXTCON_USB, &omap->vbus_nb); - extcon_unregister_notifier(omap->edev, EXTCON_USB_HOST, &omap->id_nb); dwc3_omap_disable_irqs(omap); disable_irq(omap->irq); of_platform_depopulate(omap->dev); diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 9bb1f8526f3e..e689cede9b0e 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -1123,7 +1123,21 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc, dwc->ep0state = EP0_STATUS_PHASE; if (dwc->delayed_status) { + struct dwc3_ep *dep = dwc->eps[0]; + WARN_ON_ONCE(event->endpoint_number != 1); + /* + * We should handle the delay STATUS phase here if the + * request for handling delay STATUS has been queued + * into the list. + */ + if (!list_empty(&dep->pending_list)) { + dwc->delayed_status = false; + usb_gadget_set_state(&dwc->gadget, + USB_STATE_CONFIGURED); + dwc3_ep0_do_control_status(dwc, event); + } + return; } diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 204c754cc647..4db97ecae885 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -833,29 +833,14 @@ static void dwc3_gadget_ep_free_request(struct usb_ep *ep, static u32 dwc3_calc_trbs_left(struct dwc3_ep *dep); -/** - * dwc3_prepare_one_trb - setup one TRB from one request - * @dep: endpoint for which this request is prepared - * @req: dwc3_request pointer - */ -static void dwc3_prepare_one_trb(struct dwc3_ep *dep, - struct dwc3_request *req, dma_addr_t dma, - unsigned length, unsigned chain, unsigned node) +static void __dwc3_prepare_one_trb(struct dwc3_ep *dep, struct dwc3_trb *trb, + dma_addr_t dma, unsigned length, unsigned chain, unsigned node, + unsigned stream_id, unsigned short_not_ok, unsigned no_interrupt) { - struct dwc3_trb *trb; struct dwc3 *dwc = dep->dwc; struct usb_gadget *gadget = &dwc->gadget; enum usb_device_speed speed = gadget->speed; - trb = &dep->trb_pool[dep->trb_enqueue]; - - if (!req->trb) { - dwc3_gadget_move_started_request(req); - req->trb = trb; - req->trb_dma = dwc3_trb_dma_offset(dep, trb); - dep->queued_requests++; - } - dwc3_ep_inc_enq(dep); trb->size = DWC3_TRB_SIZE_LENGTH(length); @@ -900,11 +885,11 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, if (usb_endpoint_dir_out(dep->endpoint.desc)) { trb->ctrl |= DWC3_TRB_CTRL_CSP; - if (req->request.short_not_ok) + if (short_not_ok) trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI; } - if ((!req->request.no_interrupt && !chain) || + if ((!no_interrupt && !chain) || (dwc3_calc_trbs_left(dep) == 0)) trb->ctrl |= DWC3_TRB_CTRL_IOC; @@ -912,7 +897,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, trb->ctrl |= DWC3_TRB_CTRL_CHN; if (usb_endpoint_xfer_bulk(dep->endpoint.desc) && dep->stream_capable) - trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(req->request.stream_id); + trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(stream_id); trb->ctrl |= DWC3_TRB_CTRL_HWO; @@ -920,6 +905,36 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, } /** + * dwc3_prepare_one_trb - setup one TRB from one request + * @dep: endpoint for which this request is prepared + * @req: dwc3_request pointer + * @chain: should this TRB be chained to the next? + * @node: only for isochronous endpoints. First TRB needs different type. + */ +static void dwc3_prepare_one_trb(struct dwc3_ep *dep, + struct dwc3_request *req, unsigned chain, unsigned node) +{ + struct dwc3_trb *trb; + unsigned length = req->request.length; + unsigned stream_id = req->request.stream_id; + unsigned short_not_ok = req->request.short_not_ok; + unsigned no_interrupt = req->request.no_interrupt; + dma_addr_t dma = req->request.dma; + + trb = &dep->trb_pool[dep->trb_enqueue]; + + if (!req->trb) { + dwc3_gadget_move_started_request(req); + req->trb = trb; + req->trb_dma = dwc3_trb_dma_offset(dep, trb); + dep->queued_requests++; + } + + __dwc3_prepare_one_trb(dep, trb, dma, length, chain, node, + stream_id, short_not_ok, no_interrupt); +} + +/** * dwc3_ep_prev_trb() - Returns the previous TRB in the ring * @dep: The endpoint with the TRB ring * @index: The index of the current TRB in the ring @@ -974,21 +989,36 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, { struct scatterlist *sg = req->sg; struct scatterlist *s; - unsigned int length; - dma_addr_t dma; int i; for_each_sg(sg, s, req->num_pending_sgs, i) { + unsigned int length = req->request.length; + unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc); + unsigned int rem = length % maxp; unsigned chain = true; - length = sg_dma_len(s); - dma = sg_dma_address(s); - if (sg_is_last(s)) chain = false; - dwc3_prepare_one_trb(dep, req, dma, length, - chain, i); + if (rem && usb_endpoint_dir_out(dep->endpoint.desc) && !chain) { + struct dwc3 *dwc = dep->dwc; + struct dwc3_trb *trb; + + req->unaligned = true; + + /* prepare normal TRB */ + dwc3_prepare_one_trb(dep, req, true, i); + + /* Now prepare one extra TRB to align transfer size */ + trb = &dep->trb_pool[dep->trb_enqueue]; + __dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, + maxp - rem, false, 0, + req->request.stream_id, + req->request.short_not_ok, + req->request.no_interrupt); + } else { + dwc3_prepare_one_trb(dep, req, chain, i); + } if (!dwc3_calc_trbs_left(dep)) break; @@ -998,14 +1028,28 @@ static void dwc3_prepare_one_trb_sg(struct dwc3_ep *dep, static void dwc3_prepare_one_trb_linear(struct dwc3_ep *dep, struct dwc3_request *req) { - unsigned int length; - dma_addr_t dma; + unsigned int length = req->request.length; + unsigned int maxp = usb_endpoint_maxp(dep->endpoint.desc); + unsigned int rem = length % maxp; + + if (rem && usb_endpoint_dir_out(dep->endpoint.desc)) { + struct dwc3 *dwc = dep->dwc; + struct dwc3_trb *trb; - dma = req->request.dma; - length = req->request.length; + req->unaligned = true; - dwc3_prepare_one_trb(dep, req, dma, length, - false, 0); + /* prepare normal TRB */ + dwc3_prepare_one_trb(dep, req, true, 0); + + /* Now prepare one extra TRB to align transfer size */ + trb = &dep->trb_pool[dep->trb_enqueue]; + __dwc3_prepare_one_trb(dep, trb, dwc->bounce_addr, maxp - rem, + false, 0, req->request.stream_id, + req->request.short_not_ok, + req->request.no_interrupt); + } else { + dwc3_prepare_one_trb(dep, req, false, 0); + } } /* @@ -1335,6 +1379,9 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol) unsigned transfer_in_flight; unsigned started; + if (dep->flags & DWC3_EP_STALL) + return 0; + if (dep->number > 1) trb = dwc3_ep_prev_trb(dep, dep->trb_enqueue); else @@ -1356,6 +1403,8 @@ int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value, int protocol) else dep->flags |= DWC3_EP_STALL; } else { + if (!(dep->flags & DWC3_EP_STALL)) + return 0; ret = dwc3_send_clear_stall_ep_cmd(dep); if (ret) @@ -1918,6 +1967,44 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc, dep->endpoint.ops = &dwc3_gadget_ep0_ops; if (!epnum) dwc->gadget.ep0 = &dep->endpoint; + } else if (direction) { + int mdwidth; + int size; + int ret; + int num; + + mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0); + /* MDWIDTH is represented in bits, we need it in bytes */ + mdwidth /= 8; + + size = dwc3_readl(dwc->regs, DWC3_GTXFIFOSIZ(i)); + size = DWC3_GTXFIFOSIZ_TXFDEF(size); + + /* FIFO Depth is in MDWDITH bytes. Multiply */ + size *= mdwidth; + + num = size / 1024; + if (num == 0) + num = 1; + + /* + * FIFO sizes account an extra MDWIDTH * (num + 1) bytes for + * internal overhead. We don't really know how these are used, + * but documentation say it exists. + */ + size -= mdwidth * (num + 1); + size /= num; + + usb_ep_set_maxpacket_limit(&dep->endpoint, size); + + dep->endpoint.max_streams = 15; + dep->endpoint.ops = &dwc3_gadget_ep_ops; + list_add_tail(&dep->endpoint.ep_list, + &dwc->gadget.ep_list); + + ret = dwc3_alloc_trb_pool(dep); + if (ret) + return ret; } else { int ret; @@ -2029,6 +2116,16 @@ static int __dwc3_cleanup_done_trbs(struct dwc3 *dwc, struct dwc3_ep *dep, if (chain && (trb->ctrl & DWC3_TRB_CTRL_HWO)) trb->ctrl &= ~DWC3_TRB_CTRL_HWO; + /* + * If we're dealing with unaligned size OUT transfer, we will be left + * with one TRB pending in the ring. We need to manually clear HWO bit + * from that TRB. + */ + if (req->unaligned && (trb->ctrl & DWC3_TRB_CTRL_HWO)) { + trb->ctrl &= ~DWC3_TRB_CTRL_HWO; + return 1; + } + if ((trb->ctrl & DWC3_TRB_CTRL_HWO) && status != -ESHUTDOWN) return 1; @@ -2118,6 +2215,13 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, event, status, chain); } + if (req->unaligned) { + trb = &dep->trb_pool[dep->trb_dequeue]; + ret = __dwc3_cleanup_done_trbs(dwc, dep, req, trb, + event, status, false); + req->unaligned = false; + } + req->request.actual = length - req->remaining; if ((req->request.actual < length) && req->num_pending_sgs) @@ -3019,6 +3123,13 @@ int dwc3_gadget_init(struct dwc3 *dwc) goto err4; } + dwc->bounce = dma_alloc_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, + &dwc->bounce_addr, GFP_KERNEL); + if (!dwc->bounce) { + ret = -ENOMEM; + goto err5; + } + init_completion(&dwc->ep0_in_setup); dwc->gadget.ops = &dwc3_gadget_ops; @@ -3050,27 +3161,24 @@ int dwc3_gadget_init(struct dwc3 *dwc) dwc->gadget.max_speed = dwc->maximum_speed; /* - * Per databook, DWC3 needs buffer size to be aligned to MaxPacketSize - * on ep out. - */ - dwc->gadget.quirk_ep_out_aligned_size = true; - - /* * REVISIT: Here we should clear all pending IRQs to be * sure we're starting from a well known location. */ ret = dwc3_gadget_init_endpoints(dwc); if (ret) - goto err5; + goto err6; ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget); if (ret) { dev_err(dwc->dev, "failed to register udc\n"); - goto err5; + goto err6; } return 0; +err6: + dma_free_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce, + dwc->bounce_addr); err5: kfree(dwc->zlp_buf); @@ -3103,6 +3211,8 @@ void dwc3_gadget_exit(struct dwc3 *dwc) dwc3_gadget_free_endpoints(dwc); + dma_free_coherent(dwc->sysdev, DWC3_BOUNCE_SIZE, dwc->bounce, + dwc->bounce_addr); dma_free_coherent(dwc->sysdev, DWC3_EP0_BOUNCE_SIZE, dwc->ep0_bounce, dwc->ep0_bounce_addr); diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index 487f0ff6ae25..76f0b0df37c1 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -54,11 +54,12 @@ out: int dwc3_host_init(struct dwc3 *dwc) { - struct property_entry props[2]; + struct property_entry props[3]; struct platform_device *xhci; int ret, irq; struct resource *res; struct platform_device *dwc3_pdev = to_platform_device(dwc->dev); + int prop_idx = 0; irq = dwc3_host_get_irq(dwc); if (irq < 0) @@ -97,8 +98,22 @@ int dwc3_host_init(struct dwc3 *dwc) memset(props, 0, sizeof(struct property_entry) * ARRAY_SIZE(props)); - if (dwc->usb3_lpm_capable) { - props[0].name = "usb3-lpm-capable"; + if (dwc->usb3_lpm_capable) + props[prop_idx++].name = "usb3-lpm-capable"; + + /** + * WORKAROUND: dwc3 revisions <=3.00a have a limitation + * where Port Disable command doesn't work. + * + * The suggested workaround is that we avoid Port Disable + * completely. + * + * This following flag tells XHCI to do just that. + */ + if (dwc->revision <= DWC3_REVISION_300A) + props[prop_idx++].name = "quirk-broken-port-ped"; + + if (prop_idx) { ret = platform_device_add_properties(xhci, props); if (ret) { dev_err(dwc->dev, "failed to add properties to xHCI\n"); diff --git a/drivers/usb/early/ehci-dbgp.c b/drivers/usb/early/ehci-dbgp.c index ea73afb026d8..e2654443e8eb 100644 --- a/drivers/usb/early/ehci-dbgp.c +++ b/drivers/usb/early/ehci-dbgp.c @@ -580,7 +580,6 @@ try_again: USB_DEBUG_DEVNUM); goto err; } - devnum = USB_DEBUG_DEVNUM; dbgp_printk("debug device renamed to 127\n"); } diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index e6a17455adac..87fccf611b69 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -1230,7 +1230,7 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code, desc = epfile->ep->descs[desc_idx]; spin_unlock_irq(&epfile->ffs->eps_lock); - ret = copy_to_user((void *)value, desc, sizeof(*desc)); + ret = copy_to_user((void *)value, desc, desc->bLength); if (ret) ret = -EFAULT; return ret; @@ -2101,7 +2101,7 @@ static int __ffs_data_do_entity(enum ffs_entity_type type, case FFS_ENDPOINT: d = (void *)desc; helper->eps_count++; - if (helper->eps_count >= 15) + if (helper->eps_count >= FFS_MAX_EPS_COUNT) return -EINVAL; /* Check if descriptors for any speed were already parsed */ if (!helper->ffs->eps_count && !helper->ffs->interfaces_count) diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index 5f8139b8e601..89b48bcc377a 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -50,12 +50,12 @@ struct f_hidg { /* recv report */ struct list_head completed_out_req; - spinlock_t spinlock; + spinlock_t read_spinlock; wait_queue_head_t read_queue; unsigned int qlen; /* send report */ - struct mutex lock; + spinlock_t write_spinlock; bool write_pending; wait_queue_head_t write_queue; struct usb_request *req; @@ -258,28 +258,35 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer, if (!access_ok(VERIFY_WRITE, buffer, count)) return -EFAULT; - spin_lock_irqsave(&hidg->spinlock, flags); + spin_lock_irqsave(&hidg->read_spinlock, flags); #define READ_COND (!list_empty(&hidg->completed_out_req)) /* wait for at least one buffer to complete */ while (!READ_COND) { - spin_unlock_irqrestore(&hidg->spinlock, flags); + spin_unlock_irqrestore(&hidg->read_spinlock, flags); if (file->f_flags & O_NONBLOCK) return -EAGAIN; if (wait_event_interruptible(hidg->read_queue, READ_COND)) return -ERESTARTSYS; - spin_lock_irqsave(&hidg->spinlock, flags); + spin_lock_irqsave(&hidg->read_spinlock, flags); } /* pick the first one */ list = list_first_entry(&hidg->completed_out_req, struct f_hidg_req_list, list); + + /* + * Remove this from list to protect it from beign free() + * while host disables our function + */ + list_del(&list->list); + req = list->req; count = min_t(unsigned int, count, req->actual - list->pos); - spin_unlock_irqrestore(&hidg->spinlock, flags); + spin_unlock_irqrestore(&hidg->read_spinlock, flags); /* copy to user outside spinlock */ count -= copy_to_user(buffer, req->buf + list->pos, count); @@ -292,15 +299,20 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer, * call, taking into account its current read position. */ if (list->pos == req->actual) { - spin_lock_irqsave(&hidg->spinlock, flags); - list_del(&list->list); kfree(list); - spin_unlock_irqrestore(&hidg->spinlock, flags); req->length = hidg->report_length; ret = usb_ep_queue(hidg->out_ep, req, GFP_KERNEL); - if (ret < 0) + if (ret < 0) { + free_ep_req(hidg->out_ep, req); return ret; + } + } else { + spin_lock_irqsave(&hidg->read_spinlock, flags); + list_add(&list->list, &hidg->completed_out_req); + spin_unlock_irqrestore(&hidg->read_spinlock, flags); + + wake_up(&hidg->read_queue); } return count; @@ -309,13 +321,16 @@ static ssize_t f_hidg_read(struct file *file, char __user *buffer, static void f_hidg_req_complete(struct usb_ep *ep, struct usb_request *req) { struct f_hidg *hidg = (struct f_hidg *)ep->driver_data; + unsigned long flags; if (req->status != 0) { ERROR(hidg->func.config->cdev, "End Point Request ERROR: %d\n", req->status); } + spin_lock_irqsave(&hidg->write_spinlock, flags); hidg->write_pending = 0; + spin_unlock_irqrestore(&hidg->write_spinlock, flags); wake_up(&hidg->write_queue); } @@ -323,18 +338,20 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer, size_t count, loff_t *offp) { struct f_hidg *hidg = file->private_data; + struct usb_request *req; + unsigned long flags; ssize_t status = -ENOMEM; if (!access_ok(VERIFY_READ, buffer, count)) return -EFAULT; - mutex_lock(&hidg->lock); + spin_lock_irqsave(&hidg->write_spinlock, flags); #define WRITE_COND (!hidg->write_pending) - +try_again: /* write queue */ while (!WRITE_COND) { - mutex_unlock(&hidg->lock); + spin_unlock_irqrestore(&hidg->write_spinlock, flags); if (file->f_flags & O_NONBLOCK) return -EAGAIN; @@ -342,37 +359,59 @@ static ssize_t f_hidg_write(struct file *file, const char __user *buffer, hidg->write_queue, WRITE_COND)) return -ERESTARTSYS; - mutex_lock(&hidg->lock); + spin_lock_irqsave(&hidg->write_spinlock, flags); } + hidg->write_pending = 1; + req = hidg->req; count = min_t(unsigned, count, hidg->report_length); + + spin_unlock_irqrestore(&hidg->write_spinlock, flags); status = copy_from_user(hidg->req->buf, buffer, count); if (status != 0) { ERROR(hidg->func.config->cdev, "copy_from_user error\n"); - mutex_unlock(&hidg->lock); - return -EINVAL; + status = -EINVAL; + goto release_write_pending; } - hidg->req->status = 0; - hidg->req->zero = 0; - hidg->req->length = count; - hidg->req->complete = f_hidg_req_complete; - hidg->req->context = hidg; - hidg->write_pending = 1; + spin_lock_irqsave(&hidg->write_spinlock, flags); + + /* we our function has been disabled by host */ + if (!hidg->req) { + free_ep_req(hidg->in_ep, hidg->req); + /* + * TODO + * Should we fail with error here? + */ + goto try_again; + } + + req->status = 0; + req->zero = 0; + req->length = count; + req->complete = f_hidg_req_complete; + req->context = hidg; status = usb_ep_queue(hidg->in_ep, hidg->req, GFP_ATOMIC); if (status < 0) { ERROR(hidg->func.config->cdev, "usb_ep_queue error on int endpoint %zd\n", status); - hidg->write_pending = 0; - wake_up(&hidg->write_queue); + goto release_write_pending_unlocked; } else { status = count; } + spin_unlock_irqrestore(&hidg->write_spinlock, flags); - mutex_unlock(&hidg->lock); + return status; +release_write_pending: + spin_lock_irqsave(&hidg->write_spinlock, flags); +release_write_pending_unlocked: + hidg->write_pending = 0; + spin_unlock_irqrestore(&hidg->write_spinlock, flags); + + wake_up(&hidg->write_queue); return status; } @@ -425,20 +464,36 @@ static inline struct usb_request *hidg_alloc_ep_req(struct usb_ep *ep, static void hidg_set_report_complete(struct usb_ep *ep, struct usb_request *req) { struct f_hidg *hidg = (struct f_hidg *) req->context; + struct usb_composite_dev *cdev = hidg->func.config->cdev; struct f_hidg_req_list *req_list; unsigned long flags; - req_list = kzalloc(sizeof(*req_list), GFP_ATOMIC); - if (!req_list) - return; + switch (req->status) { + case 0: + req_list = kzalloc(sizeof(*req_list), GFP_ATOMIC); + if (!req_list) { + ERROR(cdev, "Unable to allocate mem for req_list\n"); + goto free_req; + } - req_list->req = req; + req_list->req = req; - spin_lock_irqsave(&hidg->spinlock, flags); - list_add_tail(&req_list->list, &hidg->completed_out_req); - spin_unlock_irqrestore(&hidg->spinlock, flags); + spin_lock_irqsave(&hidg->read_spinlock, flags); + list_add_tail(&req_list->list, &hidg->completed_out_req); + spin_unlock_irqrestore(&hidg->read_spinlock, flags); - wake_up(&hidg->read_queue); + wake_up(&hidg->read_queue); + break; + default: + ERROR(cdev, "Set report failed %d\n", req->status); + /* FALLTHROUGH */ + case -ECONNABORTED: /* hardware forced ep reset */ + case -ECONNRESET: /* request dequeued */ + case -ESHUTDOWN: /* disconnect from host */ +free_req: + free_ep_req(ep, req); + return; + } } static int hidg_setup(struct usb_function *f, @@ -544,20 +599,35 @@ static void hidg_disable(struct usb_function *f) { struct f_hidg *hidg = func_to_hidg(f); struct f_hidg_req_list *list, *next; + unsigned long flags; usb_ep_disable(hidg->in_ep); usb_ep_disable(hidg->out_ep); + spin_lock_irqsave(&hidg->read_spinlock, flags); list_for_each_entry_safe(list, next, &hidg->completed_out_req, list) { + free_ep_req(hidg->out_ep, list->req); list_del(&list->list); kfree(list); } + spin_unlock_irqrestore(&hidg->read_spinlock, flags); + + spin_lock_irqsave(&hidg->write_spinlock, flags); + if (!hidg->write_pending) { + free_ep_req(hidg->in_ep, hidg->req); + hidg->write_pending = 1; + } + + hidg->req = NULL; + spin_unlock_irqrestore(&hidg->write_spinlock, flags); } static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) { struct usb_composite_dev *cdev = f->config->cdev; struct f_hidg *hidg = func_to_hidg(f); + struct usb_request *req_in = NULL; + unsigned long flags; int i, status = 0; VDBG(cdev, "hidg_set_alt intf:%d alt:%d\n", intf, alt); @@ -578,6 +648,12 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) goto fail; } hidg->in_ep->driver_data = hidg; + + req_in = hidg_alloc_ep_req(hidg->in_ep, hidg->report_length); + if (!req_in) { + status = -ENOMEM; + goto disable_ep_in; + } } @@ -589,12 +665,12 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) hidg->out_ep); if (status) { ERROR(cdev, "config_ep_by_speed FAILED!\n"); - goto fail; + goto free_req_in; } status = usb_ep_enable(hidg->out_ep); if (status < 0) { ERROR(cdev, "Enable OUT endpoint FAILED!\n"); - goto fail; + goto free_req_in; } hidg->out_ep->driver_data = hidg; @@ -610,17 +686,37 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) req->context = hidg; status = usb_ep_queue(hidg->out_ep, req, GFP_ATOMIC); - if (status) + if (status) { ERROR(cdev, "%s queue req --> %d\n", hidg->out_ep->name, status); + free_ep_req(hidg->out_ep, req); + } } else { - usb_ep_disable(hidg->out_ep); status = -ENOMEM; - goto fail; + goto disable_out_ep; } } } + if (hidg->in_ep != NULL) { + spin_lock_irqsave(&hidg->write_spinlock, flags); + hidg->req = req_in; + hidg->write_pending = 0; + spin_unlock_irqrestore(&hidg->write_spinlock, flags); + + wake_up(&hidg->write_queue); + } + return 0; +disable_out_ep: + usb_ep_disable(hidg->out_ep); +free_req_in: + if (req_in) + free_ep_req(hidg->in_ep, req_in); + +disable_ep_in: + if (hidg->in_ep) + usb_ep_disable(hidg->in_ep); + fail: return status; } @@ -669,12 +765,6 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f) goto fail; hidg->out_ep = ep; - /* preallocate request and buffer */ - status = -ENOMEM; - hidg->req = alloc_ep_req(hidg->in_ep, hidg->report_length); - if (!hidg->req) - goto fail; - /* set descriptor dynamic values */ hidg_interface_desc.bInterfaceSubClass = hidg->bInterfaceSubClass; hidg_interface_desc.bInterfaceProtocol = hidg->bInterfaceProtocol; @@ -711,8 +801,10 @@ static int hidg_bind(struct usb_configuration *c, struct usb_function *f) if (status) goto fail; - mutex_init(&hidg->lock); - spin_lock_init(&hidg->spinlock); + spin_lock_init(&hidg->write_spinlock); + hidg->write_pending = 1; + hidg->req = NULL; + spin_lock_init(&hidg->read_spinlock); init_waitqueue_head(&hidg->write_queue); init_waitqueue_head(&hidg->read_queue); INIT_LIST_HEAD(&hidg->completed_out_req); @@ -976,10 +1068,6 @@ static void hidg_unbind(struct usb_configuration *c, struct usb_function *f) device_destroy(hidg_class, MKDEV(major, hidg->minor)); cdev_del(&hidg->cdev); - /* disable/free request and end point */ - usb_ep_disable(hidg->in_ep); - free_ep_req(hidg->in_ep, hidg->req); - usb_free_all_descriptors(f); } diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c index 8054da9276dd..8df244fc9d80 100644 --- a/drivers/usb/gadget/function/f_printer.c +++ b/drivers/usb/gadget/function/f_printer.c @@ -49,7 +49,6 @@ #include "u_printer.h" -#define PNP_STRING_LEN 1024 #define PRINTER_MINORS 4 #define GET_DEVICE_ID 0 #define GET_PORT_STATUS 1 @@ -907,8 +906,7 @@ static bool gprinter_req_match(struct usb_function *f, switch (ctrl->bRequest) { case GET_DEVICE_ID: w_index >>= 8; - if (w_length <= PNP_STRING_LEN && - (USB_DIR_IN & ctrl->bRequestType)) + if (USB_DIR_IN & ctrl->bRequestType) break; return false; case GET_PORT_STATUS: @@ -937,6 +935,7 @@ static int printer_func_setup(struct usb_function *f, struct printer_dev *dev = func_to_printer(f); struct usb_composite_dev *cdev = f->config->cdev; struct usb_request *req = cdev->req; + u8 *buf = req->buf; int value = -EOPNOTSUPP; u16 wIndex = le16_to_cpu(ctrl->wIndex); u16 wValue = le16_to_cpu(ctrl->wValue); @@ -953,10 +952,16 @@ static int printer_func_setup(struct usb_function *f, if ((wIndex>>8) != dev->interface) break; - value = (dev->pnp_string[0] << 8) | dev->pnp_string[1]; - memcpy(req->buf, dev->pnp_string, value); + if (!dev->pnp_string) { + value = 0; + break; + } + value = strlen(dev->pnp_string); + buf[0] = (value >> 8) & 0xFF; + buf[1] = value & 0xFF; + memcpy(buf + 2, dev->pnp_string, value); DBG(dev, "1284 PNP String: %x %s\n", value, - &dev->pnp_string[2]); + dev->pnp_string); break; case GET_PORT_STATUS: /* Get Port Status */ @@ -964,7 +969,7 @@ static int printer_func_setup(struct usb_function *f, if (wIndex != dev->interface) break; - *(u8 *)req->buf = dev->printer_status; + buf[0] = dev->printer_status; value = min_t(u16, wLength, 1); break; @@ -1157,10 +1162,21 @@ static ssize_t f_printer_opts_pnp_string_show(struct config_item *item, char *page) { struct f_printer_opts *opts = to_f_printer_opts(item); - int result; + int result = 0; mutex_lock(&opts->lock); - result = strlcpy(page, opts->pnp_string + 2, PNP_STRING_LEN - 2); + if (!opts->pnp_string) + goto unlock; + + result = strlcpy(page, opts->pnp_string, PAGE_SIZE); + if (result >= PAGE_SIZE) { + result = PAGE_SIZE; + } else if (page[result - 1] != '\n' && result + 1 < PAGE_SIZE) { + page[result++] = '\n'; + page[result] = '\0'; + } + +unlock: mutex_unlock(&opts->lock); return result; @@ -1170,13 +1186,24 @@ static ssize_t f_printer_opts_pnp_string_store(struct config_item *item, const char *page, size_t len) { struct f_printer_opts *opts = to_f_printer_opts(item); - int result, l; + char *new_pnp; + int result; mutex_lock(&opts->lock); - result = strlcpy(opts->pnp_string + 2, page, PNP_STRING_LEN - 2); - l = strlen(opts->pnp_string + 2) + 2; - opts->pnp_string[0] = (l >> 8) & 0xFF; - opts->pnp_string[1] = l & 0xFF; + + new_pnp = kstrndup(page, len, GFP_KERNEL); + if (!new_pnp) { + result = -ENOMEM; + goto unlock; + } + + if (opts->pnp_string_allocated) + kfree(opts->pnp_string); + + opts->pnp_string_allocated = true; + opts->pnp_string = new_pnp; + result = len; +unlock: mutex_unlock(&opts->lock); return result; @@ -1270,6 +1297,8 @@ static void gprinter_free_inst(struct usb_function_instance *f) mutex_unlock(&printer_ida_lock); + if (opts->pnp_string_allocated) + kfree(opts->pnp_string); kfree(opts); } diff --git a/drivers/usb/gadget/function/f_uac2.c b/drivers/usb/gadget/function/f_uac2.c index 969cfe741380..f6a0d3a1311b 100644 --- a/drivers/usb/gadget/function/f_uac2.c +++ b/drivers/usb/gadget/function/f_uac2.c @@ -22,9 +22,6 @@ #include "u_uac2.h" -/* Keep everyone on toes */ -#define USB_XFERS 2 - /* * The driver implements a simple UAC_2 topology. * USB-OUT -> IT_1 -> OT_3 -> ALSA_Capture @@ -78,7 +75,7 @@ struct uac2_rtd_params { size_t period_size; unsigned max_psize; - struct uac2_req ureq[USB_XFERS]; + struct uac2_req *ureq; spinlock_t lock; }; @@ -269,6 +266,8 @@ static int uac2_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct snd_uac2_chip *uac2 = snd_pcm_substream_chip(substream); + struct audio_dev *agdev = uac2_to_agdev(uac2); + struct f_uac2_opts *uac2_opts = agdev_to_uac2_opts(agdev); struct uac2_rtd_params *prm; unsigned long flags; int err = 0; @@ -300,7 +299,7 @@ uac2_pcm_trigger(struct snd_pcm_substream *substream, int cmd) /* Clear buffer after Play stops */ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && !prm->ss) - memset(prm->rbuf, 0, prm->max_psize * USB_XFERS); + memset(prm->rbuf, 0, prm->max_psize * uac2_opts->req_number); return err; } @@ -943,6 +942,8 @@ static inline void free_ep(struct uac2_rtd_params *prm, struct usb_ep *ep) { struct snd_uac2_chip *uac2 = prm->uac2; + struct audio_dev *agdev = uac2_to_agdev(uac2); + struct f_uac2_opts *uac2_opts = agdev_to_uac2_opts(agdev); int i; if (!prm->ep_enabled) @@ -950,7 +951,7 @@ free_ep(struct uac2_rtd_params *prm, struct usb_ep *ep) prm->ep_enabled = false; - for (i = 0; i < USB_XFERS; i++) { + for (i = 0; i < uac2_opts->req_number; i++) { if (prm->ureq[i].req) { usb_ep_dequeue(ep, prm->ureq[i].req); usb_ep_free_request(ep, prm->ureq[i].req); @@ -1095,31 +1096,47 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn) prm = &agdev->uac2.c_prm; prm->max_psize = hs_epout_desc.wMaxPacketSize; - prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL); + prm->ureq = kcalloc(uac2_opts->req_number, sizeof(struct uac2_req), + GFP_KERNEL); + if (!prm->ureq) { + ret = -ENOMEM; + goto err_free_descs; + } + prm->rbuf = kcalloc(uac2_opts->req_number, prm->max_psize, GFP_KERNEL); if (!prm->rbuf) { prm->max_psize = 0; + ret = -ENOMEM; goto err_free_descs; } prm = &agdev->uac2.p_prm; prm->max_psize = hs_epin_desc.wMaxPacketSize; - prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL); + prm->ureq = kcalloc(uac2_opts->req_number, sizeof(struct uac2_req), + GFP_KERNEL); + if (!prm->ureq) { + ret = -ENOMEM; + goto err_free_descs; + } + prm->rbuf = kcalloc(uac2_opts->req_number, prm->max_psize, GFP_KERNEL); if (!prm->rbuf) { prm->max_psize = 0; - goto err; + ret = -ENOMEM; + goto err_no_memory; } ret = alsa_uac2_init(agdev); if (ret) - goto err; + goto err_no_memory; return 0; -err: +err_no_memory: + kfree(agdev->uac2.p_prm.ureq); + kfree(agdev->uac2.c_prm.ureq); kfree(agdev->uac2.p_prm.rbuf); kfree(agdev->uac2.c_prm.rbuf); err_free_descs: usb_free_all_descriptors(fn); - return -EINVAL; + return ret; } static int @@ -1127,6 +1144,7 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt) { struct usb_composite_dev *cdev = fn->config->cdev; struct audio_dev *agdev = func_to_agdev(fn); + struct f_uac2_opts *opts = agdev_to_uac2_opts(agdev); struct snd_uac2_chip *uac2 = &agdev->uac2; struct usb_gadget *gadget = cdev->gadget; struct device *dev = &uac2->pdev.dev; @@ -1157,7 +1175,6 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt) agdev->as_out_alt = alt; req_len = prm->max_psize; } else if (intf == agdev->as_in_intf) { - struct f_uac2_opts *opts = agdev_to_uac2_opts(agdev); unsigned int factor, rate; struct usb_endpoint_descriptor *ep_desc; @@ -1203,7 +1220,7 @@ afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt) prm->ep_enabled = true; usb_ep_enable(ep); - for (i = 0; i < USB_XFERS; i++) { + for (i = 0; i < opts->req_number; i++) { if (!prm->ureq[i].req) { req = usb_ep_alloc_request(ep, GFP_ATOMIC); if (req == NULL) @@ -1487,6 +1504,7 @@ UAC2_ATTRIBUTE(p_ssize); UAC2_ATTRIBUTE(c_chmask); UAC2_ATTRIBUTE(c_srate); UAC2_ATTRIBUTE(c_ssize); +UAC2_ATTRIBUTE(req_number); static struct configfs_attribute *f_uac2_attrs[] = { &f_uac2_opts_attr_p_chmask, @@ -1495,6 +1513,7 @@ static struct configfs_attribute *f_uac2_attrs[] = { &f_uac2_opts_attr_c_chmask, &f_uac2_opts_attr_c_srate, &f_uac2_opts_attr_c_ssize, + &f_uac2_opts_attr_req_number, NULL, }; @@ -1532,6 +1551,7 @@ static struct usb_function_instance *afunc_alloc_inst(void) opts->c_chmask = UAC2_DEF_CCHMASK; opts->c_srate = UAC2_DEF_CSRATE; opts->c_ssize = UAC2_DEF_CSSIZE; + opts->req_number = UAC2_DEF_REQ_NUM; return &opts->func_inst; } @@ -1560,6 +1580,7 @@ static void afunc_unbind(struct usb_configuration *c, struct usb_function *f) prm = &agdev->uac2.c_prm; kfree(prm->rbuf); + kfree(prm->ureq); usb_free_all_descriptors(f); } diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index b4e5d6dfd549..c3cab77181d4 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -913,9 +913,16 @@ EXPORT_SYMBOL_GPL(gether_set_dev_addr); int gether_get_dev_addr(struct net_device *net, char *dev_addr, int len) { struct eth_dev *dev; + int ret; dev = netdev_priv(net); - return get_ether_addr_str(dev->dev_mac, dev_addr, len); + ret = get_ether_addr_str(dev->dev_mac, dev_addr, len); + if (ret + 1 < len) { + dev_addr[ret++] = '\n'; + dev_addr[ret] = '\0'; + } + + return ret; } EXPORT_SYMBOL_GPL(gether_get_dev_addr); @@ -935,9 +942,16 @@ EXPORT_SYMBOL_GPL(gether_set_host_addr); int gether_get_host_addr(struct net_device *net, char *host_addr, int len) { struct eth_dev *dev; + int ret; dev = netdev_priv(net); - return get_ether_addr_str(dev->host_mac, host_addr, len); + ret = get_ether_addr_str(dev->host_mac, host_addr, len); + if (ret + 1 < len) { + host_addr[ret++] = '\n'; + host_addr[ret] = '\0'; + } + + return ret; } EXPORT_SYMBOL_GPL(gether_get_host_addr); @@ -984,10 +998,12 @@ EXPORT_SYMBOL_GPL(gether_get_qmult); int gether_get_ifname(struct net_device *net, char *name, int len) { + int ret; + rtnl_lock(); - strlcpy(name, netdev_name(net), len); + ret = snprintf(name, len, "%s\n", netdev_name(net)); rtnl_unlock(); - return strlen(name); + return ret < len ? ret : len; } EXPORT_SYMBOL_GPL(gether_get_ifname); diff --git a/drivers/usb/gadget/function/u_ether_configfs.h b/drivers/usb/gadget/function/u_ether_configfs.h index 4f47289fcf7c..c71133de17e7 100644 --- a/drivers/usb/gadget/function/u_ether_configfs.h +++ b/drivers/usb/gadget/function/u_ether_configfs.h @@ -108,7 +108,7 @@ mutex_lock(&opts->lock); \ qmult = gether_get_qmult(opts->net); \ mutex_unlock(&opts->lock); \ - return sprintf(page, "%d", qmult); \ + return sprintf(page, "%d\n", qmult); \ } \ \ static ssize_t _f_##_opts_qmult_store(struct config_item *item, \ diff --git a/drivers/usb/gadget/function/u_fs.h b/drivers/usb/gadget/function/u_fs.h index 60139854e0b1..4b6969451cdc 100644 --- a/drivers/usb/gadget/function/u_fs.h +++ b/drivers/usb/gadget/function/u_fs.h @@ -247,7 +247,8 @@ struct ffs_data { unsigned user_flags; - u8 eps_addrmap[15]; +#define FFS_MAX_EPS_COUNT 31 + u8 eps_addrmap[FFS_MAX_EPS_COUNT]; unsigned short strings_count; unsigned short interfaces_count; diff --git a/drivers/usb/gadget/function/u_printer.h b/drivers/usb/gadget/function/u_printer.h index 0e2c49d4274e..8d30b7577f87 100644 --- a/drivers/usb/gadget/function/u_printer.h +++ b/drivers/usb/gadget/function/u_printer.h @@ -18,12 +18,11 @@ #include <linux/usb/composite.h> -#define PNP_STRING_LEN 1024 - struct f_printer_opts { struct usb_function_instance func_inst; int minor; - char pnp_string[PNP_STRING_LEN]; + char *pnp_string; + bool pnp_string_allocated; unsigned q_len; /* diff --git a/drivers/usb/gadget/function/u_uac2.h b/drivers/usb/gadget/function/u_uac2.h index 78dd37279bd4..19eeb83538a5 100644 --- a/drivers/usb/gadget/function/u_uac2.h +++ b/drivers/usb/gadget/function/u_uac2.h @@ -24,6 +24,7 @@ #define UAC2_DEF_CCHMASK 0x3 #define UAC2_DEF_CSRATE 64000 #define UAC2_DEF_CSSIZE 2 +#define UAC2_DEF_REQ_NUM 2 struct f_uac2_opts { struct usb_function_instance func_inst; @@ -33,6 +34,7 @@ struct f_uac2_opts { int c_chmask; int c_srate; int c_ssize; + int req_number; bool bound; struct mutex lock; diff --git a/drivers/usb/gadget/legacy/audio.c b/drivers/usb/gadget/legacy/audio.c index 5d7b3c6a422b..8a39f42a4d56 100644 --- a/drivers/usb/gadget/legacy/audio.c +++ b/drivers/usb/gadget/legacy/audio.c @@ -229,6 +229,7 @@ static int audio_bind(struct usb_composite_dev *cdev) uac2_opts->c_chmask = c_chmask; uac2_opts->c_srate = c_srate; uac2_opts->c_ssize = c_ssize; + uac2_opts->req_number = UAC2_DEF_REQ_NUM; #else uac1_opts = container_of(fi_uac1, struct f_uac1_opts, func_inst); uac1_opts->fn_play = fn_play; diff --git a/drivers/usb/gadget/legacy/printer.c b/drivers/usb/gadget/legacy/printer.c index 6f969a86175c..4c9cfff34a03 100644 --- a/drivers/usb/gadget/legacy/printer.c +++ b/drivers/usb/gadget/legacy/printer.c @@ -88,8 +88,8 @@ static const struct usb_descriptor_header *otg_desc[2]; static char product_desc [40] = DRIVER_DESC; static char serial_num [40] = "1"; -static char pnp_string[PNP_STRING_LEN] = - "XXMFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;"; +static char *pnp_string = + "MFG:linux;MDL:g_printer;CLS:PRINTER;SN:1;"; /* static strings, in UTF-8 */ static struct usb_string strings [] = { @@ -143,23 +143,29 @@ static int printer_do_config(struct usb_configuration *c) static int printer_bind(struct usb_composite_dev *cdev) { struct f_printer_opts *opts; - int ret, len; + int ret; fi_printer = usb_get_function_instance("printer"); if (IS_ERR(fi_printer)) return PTR_ERR(fi_printer); - if (iPNPstring) - strlcpy(&pnp_string[2], iPNPstring, PNP_STRING_LEN - 2); - - len = strlen(pnp_string); - pnp_string[0] = (len >> 8) & 0xFF; - pnp_string[1] = len & 0xFF; - opts = container_of(fi_printer, struct f_printer_opts, func_inst); opts->minor = 0; - memcpy(opts->pnp_string, pnp_string, PNP_STRING_LEN); opts->q_len = QLEN; + if (iPNPstring) { + opts->pnp_string = kstrdup(iPNPstring, GFP_KERNEL); + if (!opts->pnp_string) { + ret = -ENOMEM; + goto fail_put_func_inst; + } + opts->pnp_string_allocated = true; + /* + * we don't free this memory in case of error + * as printer cleanup func will do this for us + */ + } else { + opts->pnp_string = pnp_string; + } ret = usb_string_ids_tab(cdev, strings); if (ret < 0) diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig index 658b8da60915..4b69f28a9af9 100644 --- a/drivers/usb/gadget/udc/Kconfig +++ b/drivers/usb/gadget/udc/Kconfig @@ -60,6 +60,20 @@ config USB_ATMEL_USBA USBA is the integrated high-speed USB Device controller on the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel. + The fifo_mode parameter is used to select endpoint allocation mode. + fifo_mode = 0 is used to let the driver autoconfigure the endpoints. + In this case 2 banks are allocated for isochronous endpoints and + only one bank is allocated for the rest of the endpoints. + + fifo_mode = 1 is a generic maximum fifo size (1024 bytes) configuration + allowing the usage of ep1 - ep6 + + fifo_mode = 2 is a generic performance maximum fifo size (1024 bytes) + configuration allowing the usage of ep1 - ep3 + + fifo_mode = 3 is a balanced performance configuration allowing the + the usage of ep1 - ep8 + config USB_BCM63XX_UDC tristate "Broadcom BCM63xx Peripheral Controller" depends on BCM63XX diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index 12c7687216e6..11bbce28bc23 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -20,6 +20,7 @@ #include <linux/mfd/syscon.h> #include <linux/platform_device.h> #include <linux/regmap.h> +#include <linux/ctype.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> #include <linux/usb/atmel_usba_udc.h> @@ -318,6 +319,91 @@ static inline void usba_cleanup_debugfs(struct usba_udc *udc) } #endif +static ushort fifo_mode; + +/* "modprobe ... fifo_mode=1" etc */ +module_param(fifo_mode, ushort, 0x0); +MODULE_PARM_DESC(fifo_mode, "Endpoint configuration mode"); + +/* mode 0 - uses autoconfig */ + +/* mode 1 - fits in 8KB, generic max fifo configuration */ +static struct usba_fifo_cfg mode_1_cfg[] = { +{ .hw_ep_num = 0, .fifo_size = 64, .nr_banks = 1, }, +{ .hw_ep_num = 1, .fifo_size = 1024, .nr_banks = 2, }, +{ .hw_ep_num = 2, .fifo_size = 1024, .nr_banks = 1, }, +{ .hw_ep_num = 3, .fifo_size = 1024, .nr_banks = 1, }, +{ .hw_ep_num = 4, .fifo_size = 1024, .nr_banks = 1, }, +{ .hw_ep_num = 5, .fifo_size = 1024, .nr_banks = 1, }, +{ .hw_ep_num = 6, .fifo_size = 1024, .nr_banks = 1, }, +}; + +/* mode 2 - fits in 8KB, performance max fifo configuration */ +static struct usba_fifo_cfg mode_2_cfg[] = { +{ .hw_ep_num = 0, .fifo_size = 64, .nr_banks = 1, }, +{ .hw_ep_num = 1, .fifo_size = 1024, .nr_banks = 3, }, +{ .hw_ep_num = 2, .fifo_size = 1024, .nr_banks = 2, }, +{ .hw_ep_num = 3, .fifo_size = 1024, .nr_banks = 2, }, +}; + +/* mode 3 - fits in 8KB, mixed fifo configuration */ +static struct usba_fifo_cfg mode_3_cfg[] = { +{ .hw_ep_num = 0, .fifo_size = 64, .nr_banks = 1, }, +{ .hw_ep_num = 1, .fifo_size = 1024, .nr_banks = 2, }, +{ .hw_ep_num = 2, .fifo_size = 512, .nr_banks = 2, }, +{ .hw_ep_num = 3, .fifo_size = 512, .nr_banks = 2, }, +{ .hw_ep_num = 4, .fifo_size = 512, .nr_banks = 2, }, +{ .hw_ep_num = 5, .fifo_size = 512, .nr_banks = 2, }, +{ .hw_ep_num = 6, .fifo_size = 512, .nr_banks = 2, }, +}; + +/* mode 4 - fits in 8KB, custom fifo configuration */ +static struct usba_fifo_cfg mode_4_cfg[] = { +{ .hw_ep_num = 0, .fifo_size = 64, .nr_banks = 1, }, +{ .hw_ep_num = 1, .fifo_size = 512, .nr_banks = 2, }, +{ .hw_ep_num = 2, .fifo_size = 512, .nr_banks = 2, }, +{ .hw_ep_num = 3, .fifo_size = 8, .nr_banks = 2, }, +{ .hw_ep_num = 4, .fifo_size = 512, .nr_banks = 2, }, +{ .hw_ep_num = 5, .fifo_size = 512, .nr_banks = 2, }, +{ .hw_ep_num = 6, .fifo_size = 16, .nr_banks = 2, }, +{ .hw_ep_num = 7, .fifo_size = 8, .nr_banks = 2, }, +{ .hw_ep_num = 8, .fifo_size = 8, .nr_banks = 2, }, +}; +/* Add additional configurations here */ + +int usba_config_fifo_table(struct usba_udc *udc) +{ + int n; + + switch (fifo_mode) { + default: + fifo_mode = 0; + case 0: + udc->fifo_cfg = NULL; + n = 0; + break; + case 1: + udc->fifo_cfg = mode_1_cfg; + n = ARRAY_SIZE(mode_1_cfg); + break; + case 2: + udc->fifo_cfg = mode_2_cfg; + n = ARRAY_SIZE(mode_2_cfg); + break; + case 3: + udc->fifo_cfg = mode_3_cfg; + n = ARRAY_SIZE(mode_3_cfg); + break; + case 4: + udc->fifo_cfg = mode_4_cfg; + n = ARRAY_SIZE(mode_4_cfg); + break; + } + DBG(DBG_HW, "Setup fifo_mode %d\n", fifo_mode); + + return n; +} + static inline u32 usba_int_enb_get(struct usba_udc *udc) { return udc->int_enb_cache; @@ -543,24 +629,17 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) ep->is_isoc = 0; ep->is_in = 0; - if (maxpacket <= 8) - ept_cfg = USBA_BF(EPT_SIZE, USBA_EPT_SIZE_8); - else - /* LSB is bit 1, not 0 */ - ept_cfg = USBA_BF(EPT_SIZE, fls(maxpacket - 1) - 3); - - DBG(DBG_HW, "%s: EPT_SIZE = %lu (maxpacket = %lu)\n", + DBG(DBG_ERR, "%s: EPT_CFG = 0x%lx (maxpacket = %lu)\n", ep->ep.name, ept_cfg, maxpacket); if (usb_endpoint_dir_in(desc)) { ep->is_in = 1; - ept_cfg |= USBA_EPT_DIR_IN; + ep->ept_cfg |= USBA_EPT_DIR_IN; } switch (usb_endpoint_type(desc)) { case USB_ENDPOINT_XFER_CONTROL: - ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL); - ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE); + ep->ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL); break; case USB_ENDPOINT_XFER_ISOC: if (!ep->can_isoc) { @@ -578,24 +657,15 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) return -EINVAL; ep->is_isoc = 1; - ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_ISO); + ep->ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_ISO); + ep->ept_cfg |= USBA_BF(NB_TRANS, nr_trans); - /* - * Do triple-buffering on high-bandwidth iso endpoints. - */ - if (nr_trans > 1 && ep->nr_banks == 3) - ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_TRIPLE); - else - ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE); - ept_cfg |= USBA_BF(NB_TRANS, nr_trans); break; case USB_ENDPOINT_XFER_BULK: - ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK); - ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE); + ep->ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK); break; case USB_ENDPOINT_XFER_INT: - ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_INT); - ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE); + ep->ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_INT); break; } @@ -604,7 +674,7 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) ep->ep.desc = desc; ep->ep.maxpacket = maxpacket; - usba_ep_writel(ep, CFG, ept_cfg); + usba_ep_writel(ep, CFG, ep->ept_cfg); usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE); if (ep->can_dma) { @@ -1006,12 +1076,81 @@ static int atmel_usba_start(struct usb_gadget *gadget, struct usb_gadget_driver *driver); static int atmel_usba_stop(struct usb_gadget *gadget); +static struct usb_ep *atmel_usba_match_ep( + struct usb_gadget *gadget, + struct usb_endpoint_descriptor *desc, + struct usb_ss_ep_comp_descriptor *ep_comp +) +{ + struct usb_ep *_ep; + struct usba_ep *ep; + + /* Look at endpoints until an unclaimed one looks usable */ + list_for_each_entry(_ep, &gadget->ep_list, ep_list) { + if (usb_gadget_ep_match_desc(gadget, _ep, desc, ep_comp)) + goto found_ep; + } + /* Fail */ + return NULL; + +found_ep: + + if (fifo_mode == 0) { + /* Optimize hw fifo size based on ep type and other info */ + ep = to_usba_ep(_ep); + + switch (usb_endpoint_type(desc)) { + + case USB_ENDPOINT_XFER_CONTROL: + break; + + case USB_ENDPOINT_XFER_ISOC: + ep->fifo_size = 1024; + ep->nr_banks = 2; + break; + + case USB_ENDPOINT_XFER_BULK: + ep->fifo_size = 512; + ep->nr_banks = 1; + break; + + case USB_ENDPOINT_XFER_INT: + if (desc->wMaxPacketSize == 0) + ep->fifo_size = + roundup_pow_of_two(_ep->maxpacket_limit); + else + ep->fifo_size = + roundup_pow_of_two(le16_to_cpu(desc->wMaxPacketSize)); + ep->nr_banks = 1; + break; + } + + /* It might be a little bit late to set this */ + usb_ep_set_maxpacket_limit(&ep->ep, ep->fifo_size); + + /* Generate ept_cfg basd on FIFO size and number of banks */ + if (ep->fifo_size <= 8) + ep->ept_cfg = USBA_BF(EPT_SIZE, USBA_EPT_SIZE_8); + else + /* LSB is bit 1, not 0 */ + ep->ept_cfg = + USBA_BF(EPT_SIZE, fls(ep->fifo_size - 1) - 3); + + ep->ept_cfg |= USBA_BF(BK_NUMBER, ep->nr_banks); + + ep->udc->configured_ep++; + } + +return _ep; +} + static const struct usb_gadget_ops usba_udc_ops = { .get_frame = usba_udc_get_frame, .wakeup = usba_udc_wakeup, .set_selfpowered = usba_udc_set_selfpowered, .udc_start = atmel_usba_start, .udc_stop = atmel_usba_stop, + .match_ep = atmel_usba_match_ep, }; static struct usb_endpoint_descriptor usba_ep0_desc = { @@ -1678,7 +1817,8 @@ static irqreturn_t usba_udc_irq(int irq, void *devid) } if (status & USBA_END_OF_RESET) { - struct usba_ep *ep0; + struct usba_ep *ep0, *ep; + int i, n; usba_writel(udc, INT_CLR, USBA_END_OF_RESET); generate_bias_pulse(udc); @@ -1717,6 +1857,16 @@ static irqreturn_t usba_udc_irq(int irq, void *devid) if (!(usba_ep_readl(ep0, CFG) & USBA_EPT_MAPPED)) dev_dbg(&udc->pdev->dev, "ODD: EP0 configuration is invalid!\n"); + + /* Preallocate other endpoints */ + n = fifo_mode ? udc->num_ep : udc->configured_ep; + for (i = 1; i < n; i++) { + ep = &udc->usba_ep[i]; + usba_ep_writel(ep, CFG, ep->ept_cfg); + if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) + dev_dbg(&udc->pdev->dev, + "ODD: EP%d configuration is invalid!\n", i); + } } spin_unlock(&udc->lock); @@ -1864,6 +2014,9 @@ static int atmel_usba_stop(struct usb_gadget *gadget) if (gpio_is_valid(udc->vbus_pin)) disable_irq(gpio_to_irq(udc->vbus_pin)); + if (fifo_mode == 0) + udc->configured_ep = 1; + usba_stop(udc); udc->driver = NULL; @@ -1931,9 +2084,13 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, &flags); udc->vbus_pin_inverted = (flags & OF_GPIO_ACTIVE_LOW) ? 1 : 0; - pp = NULL; - while ((pp = of_get_next_child(np, pp))) - udc->num_ep++; + if (fifo_mode == 0) { + pp = NULL; + while ((pp = of_get_next_child(np, pp))) + udc->num_ep++; + udc->configured_ep = 1; + } else + udc->num_ep = usba_config_fifo_table(udc); eps = devm_kzalloc(&pdev->dev, sizeof(struct usba_ep) * udc->num_ep, GFP_KERNEL); @@ -1946,7 +2103,7 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, pp = NULL; i = 0; - while ((pp = of_get_next_child(np, pp))) { + while ((pp = of_get_next_child(np, pp)) && i < udc->num_ep) { ep = &eps[i]; ret = of_property_read_u32(pp, "reg", &val); @@ -1954,21 +2111,21 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, dev_err(&pdev->dev, "of_probe: reg error(%d)\n", ret); goto err; } - ep->index = val; + ep->index = fifo_mode ? udc->fifo_cfg[i].hw_ep_num : val; ret = of_property_read_u32(pp, "atmel,fifo-size", &val); if (ret) { dev_err(&pdev->dev, "of_probe: fifo-size error(%d)\n", ret); goto err; } - ep->fifo_size = val; + ep->fifo_size = fifo_mode ? udc->fifo_cfg[i].fifo_size : val; ret = of_property_read_u32(pp, "atmel,nb-banks", &val); if (ret) { dev_err(&pdev->dev, "of_probe: nb-banks error(%d)\n", ret); goto err; } - ep->nr_banks = val; + ep->nr_banks = fifo_mode ? udc->fifo_cfg[i].nr_banks : val; ep->can_dma = of_property_read_bool(pp, "atmel,can-dma"); ep->can_isoc = of_property_read_bool(pp, "atmel,can-isoc"); @@ -2000,6 +2157,21 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev, ep->ep.caps.dir_in = true; ep->ep.caps.dir_out = true; + if (fifo_mode != 0) { + /* + * Generate ept_cfg based on FIFO size and + * banks number + */ + if (ep->fifo_size <= 8) + ep->ept_cfg = USBA_BF(EPT_SIZE, USBA_EPT_SIZE_8); + else + /* LSB is bit 1, not 0 */ + ep->ept_cfg = + USBA_BF(EPT_SIZE, fls(ep->fifo_size - 1) - 3); + + ep->ept_cfg |= USBA_BF(BK_NUMBER, ep->nr_banks); + } + if (i) list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.h b/drivers/usb/gadget/udc/atmel_usba_udc.h index b03b2ebfc53a..9551b704bfd3 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.h +++ b/drivers/usb/gadget/udc/atmel_usba_udc.h @@ -275,6 +275,12 @@ struct usba_dma_desc { u32 ctrl; }; +struct usba_fifo_cfg { + u8 hw_ep_num; + u16 fifo_size; + u8 nr_banks; +}; + struct usba_ep { int state; void __iomem *ep_regs; @@ -293,7 +299,7 @@ struct usba_ep { unsigned int can_isoc:1; unsigned int is_isoc:1; unsigned int is_in:1; - + unsigned long ept_cfg; #ifdef CONFIG_USB_GADGET_DEBUG_FS u32 last_dma_status; struct dentry *debugfs_dir; @@ -338,6 +344,8 @@ struct usba_udc { int vbus_pin; int vbus_pin_inverted; int num_ep; + int configured_ep; + struct usba_fifo_cfg *fifo_cfg; struct clk *pclk; struct clk *hclk; struct usba_ep *usba_ep; diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index 0402177f93cd..d685d82dcf48 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -1080,6 +1080,24 @@ static void usb_udc_nop_release(struct device *dev) dev_vdbg(dev, "%s\n", __func__); } +/* should be called with udc_lock held */ +static int check_pending_gadget_drivers(struct usb_udc *udc) +{ + struct usb_gadget_driver *driver; + int ret = 0; + + list_for_each_entry(driver, &gadget_driver_pending_list, pending) + if (!driver->udc_name || strcmp(driver->udc_name, + dev_name(&udc->dev)) == 0) { + ret = udc_bind_to_driver(udc, driver); + if (ret != -EPROBE_DEFER) + list_del(&driver->pending); + break; + } + + return ret; +} + /** * usb_add_gadget_udc_release - adds a new gadget to the udc class driver list * @parent: the parent device to this udc. Usually the controller driver's @@ -1093,7 +1111,6 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, void (*release)(struct device *dev)) { struct usb_udc *udc; - struct usb_gadget_driver *driver; int ret = -ENOMEM; udc = kzalloc(sizeof(*udc), GFP_KERNEL); @@ -1136,17 +1153,9 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget, udc->vbus = true; /* pick up one of pending gadget drivers */ - list_for_each_entry(driver, &gadget_driver_pending_list, pending) { - if (!driver->udc_name || strcmp(driver->udc_name, - dev_name(&udc->dev)) == 0) { - ret = udc_bind_to_driver(udc, driver); - if (ret != -EPROBE_DEFER) - list_del(&driver->pending); - if (ret) - goto err5; - break; - } - } + ret = check_pending_gadget_drivers(udc); + if (ret) + goto err5; mutex_unlock(&udc_lock); @@ -1356,14 +1365,22 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) return -EINVAL; mutex_lock(&udc_lock); - list_for_each_entry(udc, &udc_list, list) + list_for_each_entry(udc, &udc_list, list) { if (udc->driver == driver) { usb_gadget_remove_driver(udc); usb_gadget_set_state(udc->gadget, - USB_STATE_NOTATTACHED); + USB_STATE_NOTATTACHED); + + /* Maybe there is someone waiting for this UDC? */ + check_pending_gadget_drivers(udc); + /* + * For now we ignore bind errors as probably it's + * not a valid reason to fail other's gadget unbind + */ ret = 0; break; } + } if (ret) { list_del(&driver->pending); diff --git a/drivers/usb/gadget/udc/fotg210-udc.c b/drivers/usb/gadget/udc/fotg210-udc.c index 6ba122cc7490..78d0204e3e20 100644 --- a/drivers/usb/gadget/udc/fotg210-udc.c +++ b/drivers/usb/gadget/udc/fotg210-udc.c @@ -527,7 +527,7 @@ static void fotg210_ep_fifo_flush(struct usb_ep *_ep) { } -static struct usb_ep_ops fotg210_ep_ops = { +static const struct usb_ep_ops fotg210_ep_ops = { .enable = fotg210_ep_enable, .disable = fotg210_ep_disable, @@ -1058,7 +1058,7 @@ static int fotg210_udc_stop(struct usb_gadget *g) return 0; } -static struct usb_gadget_ops fotg210_gadget_ops = { +static const struct usb_gadget_ops fotg210_gadget_ops = { .udc_start = fotg210_udc_start, .udc_stop = fotg210_udc_stop, }; diff --git a/drivers/usb/gadget/udc/fsl_qe_udc.c b/drivers/usb/gadget/udc/fsl_qe_udc.c index 4fff51b8a18e..303328ce59ee 100644 --- a/drivers/usb/gadget/udc/fsl_qe_udc.c +++ b/drivers/usb/gadget/udc/fsl_qe_udc.c @@ -1847,7 +1847,7 @@ out: return status; } -static struct usb_ep_ops qe_ep_ops = { +static const struct usb_ep_ops qe_ep_ops = { .enable = qe_ep_enable, .disable = qe_ep_disable, diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c index 71094e479a96..2e41ef36b944 100644 --- a/drivers/usb/gadget/udc/fsl_udc_core.c +++ b/drivers/usb/gadget/udc/fsl_udc_core.c @@ -1118,7 +1118,7 @@ static void fsl_ep_fifo_flush(struct usb_ep *_ep) } while (fsl_readl(&dr_regs->endptstatus) & bits); } -static struct usb_ep_ops fsl_ep_ops = { +static const struct usb_ep_ops fsl_ep_ops = { .enable = fsl_ep_enable, .disable = fsl_ep_disable, @@ -1248,6 +1248,12 @@ static const struct usb_gadget_ops fsl_gadget_ops = { .udc_stop = fsl_udc_stop, }; +/* + * Empty complete function used by this driver to fill in the req->complete + * field when creating a request since the complete field is mandatory. + */ +static void fsl_noop_complete(struct usb_ep *ep, struct usb_request *req) { } + /* Set protocol stall on ep0, protocol stall will automatically be cleared on new transaction */ static void ep0stall(struct fsl_udc *udc) @@ -1282,7 +1288,7 @@ static int ep0_prime_status(struct fsl_udc *udc, int direction) req->req.length = 0; req->req.status = -EINPROGRESS; req->req.actual = 0; - req->req.complete = NULL; + req->req.complete = fsl_noop_complete; req->dtd_count = 0; ret = usb_gadget_map_request(&ep->udc->gadget, &req->req, ep_is_in(ep)); @@ -1365,7 +1371,7 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value, req->req.length = 2; req->req.status = -EINPROGRESS; req->req.actual = 0; - req->req.complete = NULL; + req->req.complete = fsl_noop_complete; req->dtd_count = 0; ret = usb_gadget_map_request(&ep->udc->gadget, &req->req, ep_is_in(ep)); diff --git a/drivers/usb/gadget/udc/fusb300_udc.c b/drivers/usb/gadget/udc/fusb300_udc.c index 42ff308578df..e0c1b0099265 100644 --- a/drivers/usb/gadget/udc/fusb300_udc.c +++ b/drivers/usb/gadget/udc/fusb300_udc.c @@ -518,7 +518,7 @@ static void fusb300_fifo_flush(struct usb_ep *_ep) { } -static struct usb_ep_ops fusb300_ep_ops = { +static const struct usb_ep_ops fusb300_ep_ops = { .enable = fusb300_enable, .disable = fusb300_disable, diff --git a/drivers/usb/gadget/udc/goku_udc.c b/drivers/usb/gadget/udc/goku_udc.c index 5107987bd353..8433c22900dc 100644 --- a/drivers/usb/gadget/udc/goku_udc.c +++ b/drivers/usb/gadget/udc/goku_udc.c @@ -968,7 +968,7 @@ static void goku_fifo_flush(struct usb_ep *_ep) command(regs, COMMAND_FIFO_CLEAR, ep->num); } -static struct usb_ep_ops goku_ep_ops = { +static const struct usb_ep_ops goku_ep_ops = { .enable = goku_ep_enable, .disable = goku_ep_disable, diff --git a/drivers/usb/gadget/udc/gr_udc.c b/drivers/usb/gadget/udc/gr_udc.c index b16f8af34050..1f9941145746 100644 --- a/drivers/usb/gadget/udc/gr_udc.c +++ b/drivers/usb/gadget/udc/gr_udc.c @@ -1841,7 +1841,7 @@ static void gr_fifo_flush(struct usb_ep *_ep) spin_unlock(&ep->dev->lock); } -static struct usb_ep_ops gr_ep_ops = { +static const struct usb_ep_ops gr_ep_ops = { .enable = gr_ep_enable, .disable = gr_ep_disable, diff --git a/drivers/usb/gadget/udc/m66592-udc.c b/drivers/usb/gadget/udc/m66592-udc.c index de3e03483659..46ce7bc15f2b 100644 --- a/drivers/usb/gadget/udc/m66592-udc.c +++ b/drivers/usb/gadget/udc/m66592-udc.c @@ -1436,7 +1436,7 @@ static void m66592_fifo_flush(struct usb_ep *_ep) spin_unlock_irqrestore(&ep->m66592->lock, flags); } -static struct usb_ep_ops m66592_ep_ops = { +static const struct usb_ep_ops m66592_ep_ops = { .enable = m66592_enable, .disable = m66592_disable, diff --git a/drivers/usb/gadget/udc/mv_u3d_core.c b/drivers/usb/gadget/udc/mv_u3d_core.c index 8d726bd767fd..d365449a295a 100644 --- a/drivers/usb/gadget/udc/mv_u3d_core.c +++ b/drivers/usb/gadget/udc/mv_u3d_core.c @@ -995,7 +995,7 @@ static int mv_u3d_ep_set_wedge(struct usb_ep *_ep) return mv_u3d_ep_set_halt_wedge(_ep, 1, 1); } -static struct usb_ep_ops mv_u3d_ep_ops = { +static const struct usb_ep_ops mv_u3d_ep_ops = { .enable = mv_u3d_ep_enable, .disable = mv_u3d_ep_disable, diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c index d82a91bddbd9..27ebb0d5449d 100644 --- a/drivers/usb/gadget/udc/mv_udc_core.c +++ b/drivers/usb/gadget/udc/mv_udc_core.c @@ -946,7 +946,7 @@ static int mv_ep_set_wedge(struct usb_ep *_ep) return mv_ep_set_halt_wedge(_ep, 1, 1); } -static struct usb_ep_ops mv_ep_ops = { +static const struct usb_ep_ops mv_ep_ops = { .enable = mv_ep_enable, .disable = mv_ep_disable, diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c index 078c91d546e0..7dc0102abdfe 100644 --- a/drivers/usb/gadget/udc/net2272.c +++ b/drivers/usb/gadget/udc/net2272.c @@ -181,7 +181,7 @@ static void net2272_dequeue_all(struct net2272_ep *); static int net2272_kick_dma(struct net2272_ep *, struct net2272_request *); static int net2272_fifo_status(struct usb_ep *); -static struct usb_ep_ops net2272_ep_ops; +static const struct usb_ep_ops net2272_ep_ops; /*---------------------------------------------------------------------------*/ @@ -1067,7 +1067,7 @@ net2272_fifo_flush(struct usb_ep *_ep) net2272_ep_write(ep, EP_STAT1, 1 << BUFFER_FLUSH); } -static struct usb_ep_ops net2272_ep_ops = { +static const struct usb_ep_ops net2272_ep_ops = { .enable = net2272_enable, .disable = net2272_disable, diff --git a/drivers/usb/gadget/udc/omap_udc.c b/drivers/usb/gadget/udc/omap_udc.c index a8709f9e5648..f05ba6825bfe 100644 --- a/drivers/usb/gadget/udc/omap_udc.c +++ b/drivers/usb/gadget/udc/omap_udc.c @@ -1112,7 +1112,7 @@ done: return status; } -static struct usb_ep_ops omap_ep_ops = { +static const struct usb_ep_ops omap_ep_ops = { .enable = omap_ep_enable, .disable = omap_ep_disable, diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c index 7fa60f5b7ae4..e1335ad5bce9 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.c +++ b/drivers/usb/gadget/udc/pxa27x_udc.c @@ -1473,7 +1473,7 @@ static int pxa_ep_disable(struct usb_ep *_ep) return 0; } -static struct usb_ep_ops pxa_ep_ops = { +static const struct usb_ep_ops pxa_ep_ops = { .enable = pxa_ep_enable, .disable = pxa_ep_disable, diff --git a/drivers/usb/gadget/udc/r8a66597-udc.c b/drivers/usb/gadget/udc/r8a66597-udc.c index f2c8862093a2..118ad70f1af0 100644 --- a/drivers/usb/gadget/udc/r8a66597-udc.c +++ b/drivers/usb/gadget/udc/r8a66597-udc.c @@ -1706,7 +1706,7 @@ static void r8a66597_fifo_flush(struct usb_ep *_ep) spin_unlock_irqrestore(&ep->r8a66597->lock, flags); } -static struct usb_ep_ops r8a66597_ep_ops = { +static const struct usb_ep_ops r8a66597_ep_ops = { .enable = r8a66597_enable, .disable = r8a66597_disable, diff --git a/drivers/usb/gadget/udc/s3c-hsudc.c b/drivers/usb/gadget/udc/s3c-hsudc.c index 82a9e2a3bedc..42587b738a1f 100644 --- a/drivers/usb/gadget/udc/s3c-hsudc.c +++ b/drivers/usb/gadget/udc/s3c-hsudc.c @@ -954,7 +954,7 @@ static int s3c_hsudc_dequeue(struct usb_ep *_ep, struct usb_request *_req) return 0; } -static struct usb_ep_ops s3c_hsudc_ep_ops = { +static const struct usb_ep_ops s3c_hsudc_ep_ops = { .enable = s3c_hsudc_ep_enable, .disable = s3c_hsudc_ep_disable, .alloc_request = s3c_hsudc_alloc_request, diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 6361fc739306..407d947b34ea 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -45,9 +45,9 @@ config USB_XHCI_PLATFORM If unsure, say N. config USB_XHCI_MTK - tristate "xHCI support for Mediatek MT65xx" + tristate "xHCI support for Mediatek MT65xx/MT7621" select MFD_SYSCON - depends on ARCH_MEDIATEK || COMPILE_TEST + depends on (MIPS && SOC_MT7621) || ARCH_MEDIATEK || COMPILE_TEST ---help--- Say 'Y' to enable the support for the xHCI host controller found in Mediatek MT65xx SoCs. diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c index 42e5b66353ef..7a603f66a9bc 100644 --- a/drivers/usb/host/ehci-exynos.c +++ b/drivers/usb/host/ehci-exynos.c @@ -77,10 +77,12 @@ static int exynos_ehci_get_phy(struct device *dev, if (IS_ERR(phy)) { ret = PTR_ERR(phy); if (ret == -EPROBE_DEFER) { + of_node_put(child); return ret; } else if (ret != -ENOSYS && ret != -ENODEV) { dev_err(dev, "Error retrieving usb2 phy: %d\n", ret); + of_node_put(child); return ret; } } diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index 91701cc68082..3733aab46efe 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -600,7 +600,7 @@ static int ehci_fsl_drv_restore(struct device *dev) return 0; } -static struct dev_pm_ops ehci_fsl_pm_ops = { +static const struct dev_pm_ops ehci_fsl_pm_ops = { .suspend = ehci_fsl_drv_suspend, .resume = ehci_fsl_drv_resume, .restore = ehci_fsl_drv_restore, diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c index 2cd105be7319..6865b919403f 100644 --- a/drivers/usb/host/ohci-exynos.c +++ b/drivers/usb/host/ohci-exynos.c @@ -66,10 +66,12 @@ static int exynos_ohci_get_phy(struct device *dev, if (IS_ERR(phy)) { ret = PTR_ERR(phy); if (ret == -EPROBE_DEFER) { + of_node_put(child); return ret; } else if (ret != -ENOSYS && ret != -ENODEV) { dev_err(dev, "Error retrieving usb2 phy: %d\n", ret); + of_node_put(child); return ret; } } diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index ed678c17c4ea..248eb7702463 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -17,21 +17,21 @@ ohci_dbg (hc, \ "%s roothub.portstatus [%d] " \ "= 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s\n", \ - label, num, temp, \ - (temp & RH_PS_PRSC) ? " PRSC" : "", \ - (temp & RH_PS_OCIC) ? " OCIC" : "", \ - (temp & RH_PS_PSSC) ? " PSSC" : "", \ - (temp & RH_PS_PESC) ? " PESC" : "", \ - (temp & RH_PS_CSC) ? " CSC" : "", \ + label, num, value, \ + (value & RH_PS_PRSC) ? " PRSC" : "", \ + (value & RH_PS_OCIC) ? " OCIC" : "", \ + (value & RH_PS_PSSC) ? " PSSC" : "", \ + (value & RH_PS_PESC) ? " PESC" : "", \ + (value & RH_PS_CSC) ? " CSC" : "", \ \ - (temp & RH_PS_LSDA) ? " LSDA" : "", \ - (temp & RH_PS_PPS) ? " PPS" : "", \ - (temp & RH_PS_PRS) ? " PRS" : "", \ - (temp & RH_PS_POCI) ? " POCI" : "", \ - (temp & RH_PS_PSS) ? " PSS" : "", \ + (value & RH_PS_LSDA) ? " LSDA" : "", \ + (value & RH_PS_PPS) ? " PPS" : "", \ + (value & RH_PS_PRS) ? " PRS" : "", \ + (value & RH_PS_POCI) ? " POCI" : "", \ + (value & RH_PS_PSS) ? " PSS" : "", \ \ - (temp & RH_PS_PES) ? " PES" : "", \ - (temp & RH_PS_CCS) ? " CCS" : "" \ + (value & RH_PS_PES) ? " PES" : "", \ + (value & RH_PS_CCS) ? " CCS" : "" \ ); /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index b08e385399b9..a4d814b7f380 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -227,8 +227,7 @@ static int ohci_omap_reset(struct usb_hcd *hcd) return status; } } else { - dev_err(hcd->self.controller, "can't find phy\n"); - return -ENODEV; + return -EPROBE_DEFER; } ohci->start_hnp = start_hnp; } diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index 4e4d601af35c..bcf531c44c70 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -2288,9 +2288,7 @@ restart: while (q.ptr != NULL) { union ehci_shadow temp; - int live; - live = HC_IS_RUNNING(oxu_to_hcd(oxu)->state); switch (type) { case Q_TYPE_QH: /* handle any completions */ diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c index 74c42f722678..363d125300ea 100644 --- a/drivers/usb/host/xhci-dbg.c +++ b/drivers/usb/host/xhci-dbg.c @@ -37,10 +37,8 @@ void xhci_dbg_regs(struct xhci_hcd *xhci) &xhci->cap_regs->hc_capbase, temp); xhci_dbg(xhci, "// CAPLENGTH: 0x%x\n", (unsigned int) HC_LENGTH(temp)); -#if 0 xhci_dbg(xhci, "// HCIVERSION: 0x%x\n", (unsigned int) HC_VERSION(temp)); -#endif xhci_dbg(xhci, "// xHCI operational registers at %p:\n", xhci->op_regs); @@ -177,7 +175,7 @@ static void xhci_print_ports(struct xhci_hcd *xhci) ports = HCS_MAX_PORTS(xhci->hcs_params1); addr = &xhci->op_regs->port_status_base; for (i = 0; i < ports; i++) { - for (j = 0; j < NUM_PORT_REGS; ++j) { + for (j = 0; j < NUM_PORT_REGS; j++) { xhci_dbg(xhci, "%p port %s reg = 0x%x\n", addr, names[j], (unsigned int) readl(addr)); @@ -240,7 +238,7 @@ void xhci_print_run_regs(struct xhci_hcd *xhci) xhci_dbg(xhci, " %p: Microframe index = 0x%x\n", &xhci->run_regs->microframe_index, (unsigned int) temp); - for (i = 0; i < 7; ++i) { + for (i = 0; i < 7; i++) { temp = readl(&xhci->run_regs->rsvd[i]); if (temp != XHCI_INIT_VALUE) xhci_dbg(xhci, " WARN: %p: Rsvd[%i] = 0x%x\n", @@ -259,7 +257,7 @@ void xhci_print_registers(struct xhci_hcd *xhci) void xhci_print_trb_offsets(struct xhci_hcd *xhci, union xhci_trb *trb) { int i; - for (i = 0; i < 4; ++i) + for (i = 0; i < 4; i++) xhci_dbg(xhci, "Offset 0x%x = 0x%x\n", i*4, trb->generic.field[i]); } @@ -332,7 +330,7 @@ void xhci_debug_segment(struct xhci_hcd *xhci, struct xhci_segment *seg) u64 addr = seg->dma; union xhci_trb *trb = seg->trbs; - for (i = 0; i < TRBS_PER_SEGMENT; ++i) { + for (i = 0; i < TRBS_PER_SEGMENT; i++) { trb = &seg->trbs[i]; xhci_dbg(xhci, "@%016llx %08x %08x %08x %08x\n", addr, lower_32_bits(le64_to_cpu(trb->link.segment_ptr)), @@ -413,7 +411,7 @@ void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst) int i; struct xhci_erst_entry *entry; - for (i = 0; i < erst->num_entries; ++i) { + for (i = 0; i < erst->num_entries; i++) { entry = &erst->entries[i]; xhci_dbg(xhci, "@%016llx %08x %08x %08x %08x\n", addr, @@ -440,7 +438,7 @@ void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci) static void dbg_rsvd64(struct xhci_hcd *xhci, u64 *ctx, dma_addr_t dma) { int i; - for (i = 0; i < 4; ++i) { + for (i = 0; i < 4; i++) { xhci_dbg(xhci, "@%p (virt) @%08llx " "(dma) %#08llx - rsvd64[%d]\n", &ctx[4 + i], (unsigned long long)dma, @@ -496,7 +494,7 @@ static void xhci_dbg_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx * &slot_ctx->dev_state, (unsigned long long)dma, slot_ctx->dev_state); dma += field_size; - for (i = 0; i < 4; ++i) { + for (i = 0; i < 4; i++) { xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", &slot_ctx->reserved[i], (unsigned long long)dma, slot_ctx->reserved[i], i); @@ -519,7 +517,7 @@ static void xhci_dbg_ep_ctx(struct xhci_hcd *xhci, if (last_ep < 31) last_ep_ctx = last_ep + 1; - for (i = 0; i < last_ep_ctx; ++i) { + for (i = 0; i < last_ep_ctx; i++) { unsigned int epaddr = xhci_get_endpoint_address(i); struct xhci_ep_ctx *ep_ctx = xhci_get_ep_ctx(xhci, ctx, i); dma_addr_t dma = ctx->dma + @@ -544,7 +542,7 @@ static void xhci_dbg_ep_ctx(struct xhci_hcd *xhci, &ep_ctx->tx_info, (unsigned long long)dma, ep_ctx->tx_info); dma += field_size; - for (j = 0; j < 3; ++j) { + for (j = 0; j < 3; j++) { xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n", &ep_ctx->reserved[j], (unsigned long long)dma, @@ -583,7 +581,7 @@ void xhci_dbg_ctx(struct xhci_hcd *xhci, &ctrl_ctx->add_flags, (unsigned long long)dma, ctrl_ctx->add_flags); dma += field_size; - for (i = 0; i < 6; ++i) { + for (i = 0; i < 6; i++) { xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd2[%d]\n", &ctrl_ctx->rsvd2[i], (unsigned long long)dma, ctrl_ctx->rsvd2[i], i); diff --git a/drivers/usb/host/xhci-ext-caps.h b/drivers/usb/host/xhci-ext-caps.h index e0244fb3903d..28deea584884 100644 --- a/drivers/usb/host/xhci-ext-caps.h +++ b/drivers/usb/host/xhci-ext-caps.h @@ -117,7 +117,7 @@ static inline int xhci_find_next_ext_cap(void __iomem *base, u32 start, int id) offset = XHCI_HCC_EXT_CAPS(val) << 2; if (!offset) return 0; - }; + } do { val = readl(base + offset); if (val == ~0) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 0ef16900efed..3bddeaa1e2d7 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -389,6 +389,8 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend) if (!virt_dev) return -ENODEV; + trace_xhci_stop_device(virt_dev); + cmd = xhci_alloc_command(xhci, false, true, GFP_NOIO); if (!cmd) { xhci_dbg(xhci, "Couldn't allocate command structure.\n"); @@ -418,7 +420,8 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend) /* Wait for last stop endpoint command to finish */ wait_for_completion(cmd->completion); - if (cmd->status == COMP_CMD_ABORT || cmd->status == COMP_CMD_STOP) { + if (cmd->status == COMP_COMMAND_ABORTED || + cmd->status == COMP_STOPPED) { xhci_warn(xhci, "Timeout while waiting for stop endpoint command\n"); ret = -ETIME; } @@ -458,6 +461,12 @@ static void xhci_disable_port(struct usb_hcd *hcd, struct xhci_hcd *xhci, return; } + if (xhci->quirks & XHCI_BROKEN_PORT_PED) { + xhci_dbg(xhci, + "Broken Port Enabled/Disabled, ignoring port disable request.\n"); + return; + } + /* Write 1 to disable the port */ writel(port_status | PORT_PE, addr); port_status = readl(addr); @@ -990,8 +999,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, temp = readl(port_array[wIndex]); if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) || (temp & PORT_PLS_MASK) >= XDEV_U3) { - xhci_warn(xhci, "USB core suspending device " - "not in U0/U1/U2.\n"); + xhci_warn(xhci, "USB core suspending device not in U0/U1/U2.\n"); goto error; } diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 8414ed2a02de..ba1853f4e407 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -936,6 +936,9 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) return; dev = xhci->devs[slot_id]; + + trace_xhci_free_virt_device(dev); + xhci->dcbaa->dev_context_ptrs[slot_id] = 0; if (!dev) return; @@ -943,7 +946,7 @@ void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id) if (dev->tt_info) old_active_eps = dev->tt_info->active_eps; - for (i = 0; i < 31; ++i) { + for (i = 0; i < 31; i++) { if (dev->eps[i].ring) xhci_ring_free(xhci, dev->eps[i].ring); if (dev->eps[i].stream_info) @@ -1075,6 +1078,8 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, &xhci->dcbaa->dev_context_ptrs[slot_id], le64_to_cpu(xhci->dcbaa->dev_context_ptrs[slot_id])); + trace_xhci_alloc_virt_device(dev); + return 1; fail: xhci_free_virt_device(xhci, slot_id); @@ -1249,6 +1254,8 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud ep0_ctx->deq = cpu_to_le64(dev->eps[0].ring->first_seg->dma | dev->eps[0].ring->cycle_state); + trace_xhci_setup_addressable_virt_device(dev); + /* Steps 7 and 8 were done in xhci_alloc_virt_device() */ return 0; @@ -1414,14 +1421,16 @@ static u32 xhci_get_endpoint_type(struct usb_host_endpoint *ep) in = usb_endpoint_dir_in(&ep->desc); - if (usb_endpoint_xfer_control(&ep->desc)) + switch (usb_endpoint_type(&ep->desc)) { + case USB_ENDPOINT_XFER_CONTROL: return CTRL_EP; - if (usb_endpoint_xfer_bulk(&ep->desc)) + case USB_ENDPOINT_XFER_BULK: return in ? BULK_IN_EP : BULK_OUT_EP; - if (usb_endpoint_xfer_isoc(&ep->desc)) + case USB_ENDPOINT_XFER_ISOC: return in ? ISOC_IN_EP : ISOC_OUT_EP; - if (usb_endpoint_xfer_int(&ep->desc)) + case USB_ENDPOINT_XFER_INT: return in ? INT_IN_EP : INT_OUT_EP; + } return 0; } @@ -1587,7 +1596,7 @@ void xhci_update_bw_info(struct xhci_hcd *xhci, unsigned int ep_type; int i; - for (i = 1; i < 31; ++i) { + for (i = 1; i < 31; i++) { bw_info = &virt_dev->eps[i].bw_info; /* We can't tell what endpoint type is being dropped, but @@ -1808,10 +1817,7 @@ struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci, void xhci_urb_free_priv(struct urb_priv *urb_priv) { - if (urb_priv) { - kfree(urb_priv->td[0]); - kfree(urb_priv); - } + kfree(urb_priv); } void xhci_free_command(struct xhci_hcd *xhci, @@ -2569,9 +2575,9 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) * something other than the default (~1ms minimum between interrupts). * See section 5.5.1.2. */ - for (i = 0; i < MAX_HC_SLOTS; ++i) + for (i = 0; i < MAX_HC_SLOTS; i++) xhci->devs[i] = NULL; - for (i = 0; i < USB_MAXCHILDREN; ++i) { + for (i = 0; i < USB_MAXCHILDREN; i++) { xhci->bus_state[0].resume_done[i] = 0; xhci->bus_state[1].resume_done[i] = 0; /* Only the USB 2.0 completions will ever be used. */ diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c index bac961cd24ad..9066ec9e0c2e 100644 --- a/drivers/usb/host/xhci-mtk.c +++ b/drivers/usb/host/xhci-mtk.c @@ -212,6 +212,12 @@ static int xhci_mtk_clks_enable(struct xhci_hcd_mtk *mtk) { int ret; + ret = clk_prepare_enable(mtk->ref_clk); + if (ret) { + dev_err(mtk->dev, "failed to enable ref_clk\n"); + goto ref_clk_err; + } + ret = clk_prepare_enable(mtk->sys_clk); if (ret) { dev_err(mtk->dev, "failed to enable sys_clk\n"); @@ -238,6 +244,8 @@ usb_p1_err: usb_p0_err: clk_disable_unprepare(mtk->sys_clk); sys_clk_err: + clk_disable_unprepare(mtk->ref_clk); +ref_clk_err: return -EINVAL; } @@ -248,6 +256,7 @@ static void xhci_mtk_clks_disable(struct xhci_hcd_mtk *mtk) clk_disable_unprepare(mtk->wk_deb_p0); } clk_disable_unprepare(mtk->sys_clk); + clk_disable_unprepare(mtk->ref_clk); } /* only clocks can be turn off for ip-sleep wakeup mode */ @@ -550,6 +559,19 @@ static int xhci_mtk_probe(struct platform_device *pdev) return PTR_ERR(mtk->sys_clk); } + /* + * reference clock is usually a "fixed-clock", make it optional + * for backward compatibility and ignore the error if it does + * not exist. + */ + mtk->ref_clk = devm_clk_get(dev, "ref_ck"); + if (IS_ERR(mtk->ref_clk)) { + if (PTR_ERR(mtk->ref_clk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + mtk->ref_clk = NULL; + } + mtk->lpm_support = of_property_read_bool(node, "usb3-lpm-capable"); ret = usb_wakeup_of_property_parse(mtk, node); diff --git a/drivers/usb/host/xhci-mtk.h b/drivers/usb/host/xhci-mtk.h index 2845c49efe1b..3aa5e1d25064 100644 --- a/drivers/usb/host/xhci-mtk.h +++ b/drivers/usb/host/xhci-mtk.h @@ -124,6 +124,7 @@ struct xhci_hcd_mtk { struct regulator *vusb33; struct regulator *vbus; struct clk *sys_clk; /* sys and mac clock */ + struct clk *ref_clk; struct clk *wk_deb_p0; /* port0's wakeup debounce clock */ struct clk *wk_deb_p1; struct regmap *pericfg; diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 954abfd5014d..fc99f51d12e1 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -242,11 +242,7 @@ static int xhci_pci_setup(struct usb_hcd *hcd) xhci_dbg(xhci, "Got SBRN %u\n", (unsigned int) xhci->sbrn); /* Find any debug ports */ - retval = xhci_pci_reinit(xhci, pdev); - if (!retval) - return retval; - - return retval; + return xhci_pci_reinit(xhci, pdev); } /* diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index e5834dd9bcde..6d33b42ffcf5 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -232,8 +232,8 @@ static int xhci_plat_probe(struct platform_device *pdev) if (device_property_read_bool(&pdev->dev, "usb3-lpm-capable")) xhci->quirks |= XHCI_LPM_SUPPORT; - if (HCC_MAX_PSA(xhci->hcc_params) >= 4) - xhci->shared_hcd->can_do_streams = 1; + if (device_property_read_bool(&pdev->dev, "quirk-broken-port-ped")) + xhci->quirks |= XHCI_BROKEN_PORT_PED; hcd->usb_phy = devm_usb_get_phy_by_phandle(&pdev->dev, "usb-phy", 0); if (IS_ERR(hcd->usb_phy)) { @@ -251,6 +251,9 @@ static int xhci_plat_probe(struct platform_device *pdev) if (ret) goto disable_usb_phy; + if (HCC_MAX_PSA(xhci->hcc_params) >= 4) + xhci->shared_hcd->can_do_streams = 1; + ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED); if (ret) goto dealloc_usb2_hcd; diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index e32029a31ca4..d9936c771fa0 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -119,14 +119,29 @@ static bool last_td_in_urb(struct xhci_td *td) { struct urb_priv *urb_priv = td->urb->hcpriv; - return urb_priv->td_cnt == urb_priv->length; + return urb_priv->num_tds_done == urb_priv->num_tds; } static void inc_td_cnt(struct urb *urb) { struct urb_priv *urb_priv = urb->hcpriv; - urb_priv->td_cnt++; + urb_priv->num_tds_done++; +} + +static void trb_to_noop(union xhci_trb *trb, u32 noop_type) +{ + if (trb_is_link(trb)) { + /* unchain chained link TRBs */ + trb->link.control &= cpu_to_le32(~TRB_CHAIN); + } else { + trb->generic.field[0] = 0; + trb->generic.field[1] = 0; + trb->generic.field[2] = 0; + /* Preserve only the cycle bit of this TRB */ + trb->generic.field[3] &= cpu_to_le32(TRB_CYCLE); + trb->generic.field[3] |= cpu_to_le32(TRB_TYPE(noop_type)); + } } /* Updates trb to point to the next TRB in the ring, and updates seg if the next @@ -299,27 +314,19 @@ static void xhci_handle_stopped_cmd_ring(struct xhci_hcd *xhci, struct xhci_command *cur_cmd) { struct xhci_command *i_cmd; - u32 cycle_state; /* Turn all aborted commands in list to no-ops, then restart */ list_for_each_entry(i_cmd, &xhci->cmd_list, cmd_list) { - if (i_cmd->status != COMP_CMD_ABORT) + if (i_cmd->status != COMP_COMMAND_ABORTED) continue; - i_cmd->status = COMP_CMD_STOP; + i_cmd->status = COMP_STOPPED; xhci_dbg(xhci, "Turn aborted command %p to no-op\n", i_cmd->command_trb); - /* get cycle state from the original cmd trb */ - cycle_state = le32_to_cpu( - i_cmd->command_trb->generic.field[3]) & TRB_CYCLE; - /* modify the command trb to no-op command */ - i_cmd->command_trb->generic.field[0] = 0; - i_cmd->command_trb->generic.field[1] = 0; - i_cmd->command_trb->generic.field[2] = 0; - i_cmd->command_trb->generic.field[3] = cpu_to_le32( - TRB_TYPE(TRB_CMD_NOOP) | cycle_state); + + trb_to_noop(i_cmd->command_trb, TRB_CMD_NOOP); /* * caller waiting for completion is called when command @@ -362,19 +369,11 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci, unsigned long flags) ret = xhci_handshake(&xhci->op_regs->cmd_ring, CMD_RING_RUNNING, 0, 5 * 1000 * 1000); if (ret < 0) { - /* we are about to kill xhci, give it one more chance */ - xhci_write_64(xhci, temp_64 | CMD_RING_ABORT, - &xhci->op_regs->cmd_ring); - udelay(1000); - ret = xhci_handshake(&xhci->op_regs->cmd_ring, - CMD_RING_RUNNING, 0, 3 * 1000 * 1000); - if (ret < 0) { - xhci_err(xhci, "Stopped the command ring failed, " - "maybe the host is dead\n"); - xhci->xhc_state |= XHCI_STATE_DYING; - xhci_halt(xhci); - return -ESHUTDOWN; - } + xhci_err(xhci, + "Stop command ring failed, maybe the host is dead\n"); + xhci->xhc_state |= XHCI_STATE_DYING; + xhci_halt(xhci); + return -ESHUTDOWN; } /* * Writing the CMD_RING_ABORT bit should cause a cmd completion event, @@ -410,7 +409,7 @@ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, * pointer command pending because the device can choose to start any * stream once the endpoint is on the HW schedule. */ - if ((ep_state & EP_HALT_PENDING) || (ep_state & SET_DEQ_PENDING) || + if ((ep_state & EP_STOP_CMD_PENDING) || (ep_state & SET_DEQ_PENDING) || (ep_state & EP_HALTED)) return; writel(DB_VALUE(ep_index, stream_id), db_addr); @@ -600,18 +599,8 @@ static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, union xhci_trb *trb = td->first_trb; while (1) { - if (trb_is_link(trb)) { - /* unchain chained link TRBs */ - trb->link.control &= cpu_to_le32(~TRB_CHAIN); - } else { - trb->generic.field[0] = 0; - trb->generic.field[1] = 0; - trb->generic.field[2] = 0; - /* Preserve only the cycle bit of this TRB */ - trb->generic.field[3] &= cpu_to_le32(TRB_CYCLE); - trb->generic.field[3] |= cpu_to_le32( - TRB_TYPE(TRB_TR_NOOP)); - } + trb_to_noop(trb, TRB_TR_NOOP); + /* flip cycle if asked to */ if (flip_cycle && trb != td->first_trb && trb != td->last_trb) trb->generic.field[3] ^= cpu_to_le32(TRB_CYCLE); @@ -626,13 +615,9 @@ static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, static void xhci_stop_watchdog_timer_in_irq(struct xhci_hcd *xhci, struct xhci_virt_ep *ep) { - ep->ep_state &= ~EP_HALT_PENDING; - /* Can't del_timer_sync in interrupt, so we attempt to cancel. If the - * timer is running on another CPU, we don't decrement stop_cmds_pending - * (since we didn't successfully stop the watchdog timer). - */ - if (del_timer(&ep->stop_cmd_timer)) - ep->stop_cmds_pending--; + ep->ep_state &= ~EP_STOP_CMD_PENDING; + /* Can't del_timer_sync in interrupt */ + del_timer(&ep->stop_cmd_timer); } /* @@ -657,6 +642,7 @@ static void xhci_giveback_urb_in_irq(struct xhci_hcd *xhci, usb_hcd_unlink_urb_from_ep(hcd, urb); spin_unlock(&xhci->lock); usb_hcd_giveback_urb(hcd, urb, status); + trace_xhci_urb_giveback(urb); spin_lock(&xhci->lock); } @@ -667,7 +653,7 @@ static void xhci_unmap_td_bounce_buffer(struct xhci_hcd *xhci, struct xhci_segment *seg = td->bounce_seg; struct urb *urb = td->urb; - if (!seg || !urb) + if (!ring || !seg || !urb) return; if (usb_urb_dir_out(urb)) { @@ -701,7 +687,6 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id, unsigned int ep_index; struct xhci_ring *ep_ring; struct xhci_virt_ep *ep; - struct list_head *entry; struct xhci_td *cur_td = NULL; struct xhci_td *last_unlinked_td; @@ -718,6 +703,8 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id, memset(&deq_state, 0, sizeof(deq_state)); ep_index = TRB_TO_EP_INDEX(le32_to_cpu(trb->generic.field[3])); ep = &xhci->devs[slot_id]->eps[ep_index]; + last_unlinked_td = list_last_entry(&ep->cancelled_td_list, + struct xhci_td, cancelled_td_list); if (list_empty(&ep->cancelled_td_list)) { xhci_stop_watchdog_timer_in_irq(xhci, ep); @@ -731,8 +718,7 @@ static void xhci_handle_cmd_stop_ep(struct xhci_hcd *xhci, int slot_id, * it. We're also in the event handler, so we can't get re-interrupted * if another Stop Endpoint command completes */ - list_for_each(entry, &ep->cancelled_td_list) { - cur_td = list_entry(entry, struct xhci_td, cancelled_td_list); + list_for_each_entry(cur_td, &ep->cancelled_td_list, cancelled_td_list) { xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, "Removing canceled TD starting at 0x%llx (dma).", (unsigned long long)xhci_trb_virt_to_dma( @@ -774,7 +760,7 @@ remove_finished_td: */ list_del_init(&cur_td->td_list); } - last_unlinked_td = cur_td; + xhci_stop_watchdog_timer_in_irq(xhci, ep); /* If necessary, queue a Set Transfer Ring Dequeue Pointer command */ @@ -796,7 +782,7 @@ remove_finished_td: * So stop when we've completed the URB for the last TD we unlinked. */ do { - cur_td = list_entry(ep->cancelled_td_list.next, + cur_td = list_first_entry(&ep->cancelled_td_list, struct xhci_td, cancelled_td_list); list_del_init(&cur_td->cancelled_td_list); @@ -805,8 +791,7 @@ remove_finished_td: * just overwrite it (because the URB has been unlinked). */ ep_ring = xhci_urb_to_transfer_ring(xhci, cur_td->urb); - if (ep_ring && cur_td->bounce_seg) - xhci_unmap_td_bounce_buffer(xhci, ep_ring, cur_td); + xhci_unmap_td_bounce_buffer(xhci, ep_ring, cur_td); inc_td_cnt(cur_td->urb); if (last_td_in_urb(cur_td)) xhci_giveback_urb_in_irq(xhci, cur_td, 0); @@ -824,16 +809,15 @@ remove_finished_td: static void xhci_kill_ring_urbs(struct xhci_hcd *xhci, struct xhci_ring *ring) { struct xhci_td *cur_td; + struct xhci_td *tmp; - while (!list_empty(&ring->td_list)) { - cur_td = list_first_entry(&ring->td_list, - struct xhci_td, td_list); + list_for_each_entry_safe(cur_td, tmp, &ring->td_list, td_list) { list_del_init(&cur_td->td_list); + if (!list_empty(&cur_td->cancelled_td_list)) list_del_init(&cur_td->cancelled_td_list); - if (cur_td->bounce_seg) - xhci_unmap_td_bounce_buffer(xhci, ring, cur_td); + xhci_unmap_td_bounce_buffer(xhci, ring, cur_td); inc_td_cnt(cur_td->urb); if (last_td_in_urb(cur_td)) @@ -845,6 +829,7 @@ static void xhci_kill_endpoint_urbs(struct xhci_hcd *xhci, int slot_id, int ep_index) { struct xhci_td *cur_td; + struct xhci_td *tmp; struct xhci_virt_ep *ep; struct xhci_ring *ring; @@ -870,12 +855,12 @@ static void xhci_kill_endpoint_urbs(struct xhci_hcd *xhci, slot_id, ep_index); xhci_kill_ring_urbs(xhci, ring); } - while (!list_empty(&ep->cancelled_td_list)) { - cur_td = list_first_entry(&ep->cancelled_td_list, - struct xhci_td, cancelled_td_list); - list_del_init(&cur_td->cancelled_td_list); + list_for_each_entry_safe(cur_td, tmp, &ep->cancelled_td_list, + cancelled_td_list) { + list_del_init(&cur_td->cancelled_td_list); inc_td_cnt(cur_td->urb); + if (last_td_in_urb(cur_td)) xhci_giveback_urb_in_irq(xhci, cur_td, -ESHUTDOWN); } @@ -895,10 +880,8 @@ static void xhci_kill_endpoint_urbs(struct xhci_hcd *xhci, * simple flag to say whether there is a pending stop endpoint command for a * particular endpoint. * - * Instead we use a combination of that flag and a counter for the number of - * pending stop endpoint commands. If the timer is the tail end of the last - * stop endpoint command, and the endpoint's command is still pending, we assume - * the host is dying. + * Instead we use a combination of that flag and checking if a new timer is + * pending. */ void xhci_stop_endpoint_command_watchdog(unsigned long arg) { @@ -912,12 +895,11 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg) spin_lock_irqsave(&xhci->lock, flags); - ep->stop_cmds_pending--; - if (!(ep->stop_cmds_pending == 0 && (ep->ep_state & EP_HALT_PENDING))) { - xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, - "Stop EP timer ran, but no command pending, " - "exiting."); + /* bail out if cmd completed but raced with stop ep watchdog timer.*/ + if (!(ep->ep_state & EP_STOP_CMD_PENDING) || + timer_pending(&ep->stop_cmd_timer)) { spin_unlock_irqrestore(&xhci->lock, flags); + xhci_dbg(xhci, "Stop EP timer raced with cmd completion, exit"); return; } @@ -926,7 +908,10 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg) /* Oops, HC is dead or dying or at least not responding to the stop * endpoint command. */ + xhci->xhc_state |= XHCI_STATE_DYING; + ep->ep_state &= ~EP_STOP_CMD_PENDING; + /* Disable interrupts from the host controller and start halting it */ xhci_quiesce(xhci); spin_unlock_irqrestore(&xhci->lock, flags); @@ -1050,10 +1035,10 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id, unsigned int slot_state; switch (cmd_comp_code) { - case COMP_TRB_ERR: + case COMP_TRB_ERROR: xhci_warn(xhci, "WARN Set TR Deq Ptr cmd invalid because of stream ID configuration\n"); break; - case COMP_CTX_STATE: + case COMP_CONTEXT_STATE_ERROR: xhci_warn(xhci, "WARN Set TR Deq Ptr cmd failed due to incorrect slot or ep state.\n"); ep_state = GET_EP_CTX_STATE(ep_ctx); slot_state = le32_to_cpu(slot_ctx->dev_state); @@ -1062,7 +1047,7 @@ static void xhci_handle_cmd_set_deq(struct xhci_hcd *xhci, int slot_id, "Slot state = %u, EP state = %u", slot_state, ep_state); break; - case COMP_EBADSLT: + case COMP_SLOT_NOT_ENABLED_ERROR: xhci_warn(xhci, "WARN Set TR Deq Ptr cmd failed because slot %u was not enabled.\n", slot_id); break; @@ -1259,7 +1244,7 @@ void xhci_cleanup_command_queue(struct xhci_hcd *xhci) { struct xhci_command *cur_cmd, *tmp_cmd; list_for_each_entry_safe(cur_cmd, tmp_cmd, &xhci->cmd_list, cmd_list) - xhci_complete_del_and_free_cmd(cur_cmd, COMP_CMD_ABORT); + xhci_complete_del_and_free_cmd(cur_cmd, COMP_COMMAND_ABORTED); } void xhci_handle_command_timeout(struct work_struct *work) @@ -1282,7 +1267,7 @@ void xhci_handle_command_timeout(struct work_struct *work) return; } /* mark this command to be cancelled */ - xhci->current_cmd->status = COMP_CMD_ABORT; + xhci->current_cmd->status = COMP_COMMAND_ABORTED; /* Make sure command ring is running before aborting it */ hw_ring_state = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); @@ -1335,6 +1320,9 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, cmd_dma = le64_to_cpu(event->cmd_trb); cmd_trb = xhci->cmd_ring->dequeue; + + trace_xhci_handle_command(xhci->cmd_ring, &cmd_trb->generic); + cmd_dequeue_dma = xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg, cmd_trb); /* @@ -1347,16 +1335,14 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, return; } - cmd = list_entry(xhci->cmd_list.next, struct xhci_command, cmd_list); + cmd = list_first_entry(&xhci->cmd_list, struct xhci_command, cmd_list); cancel_delayed_work(&xhci->cmd_timer); - trace_xhci_cmd_completion(cmd_trb, (struct xhci_generic_trb *) event); - cmd_comp_code = GET_COMP_CODE(le32_to_cpu(event->status)); /* If CMD ring stopped we own the trbs between enqueue and dequeue */ - if (cmd_comp_code == COMP_CMD_STOP) { + if (cmd_comp_code == COMP_STOPPED) { complete_all(&xhci->cmd_ring_stop_completion); return; } @@ -1373,9 +1359,9 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, * The command ring is stopped now, but the xHC will issue a Command * Ring Stopped event which will cause us to restart it. */ - if (cmd_comp_code == COMP_CMD_ABORT) { + if (cmd_comp_code == COMP_COMMAND_ABORTED) { xhci->cmd_ring_state = CMD_RING_STATE_STOPPED; - if (cmd->status == COMP_CMD_ABORT) { + if (cmd->status == COMP_COMMAND_ABORTED) { if (xhci->current_cmd == cmd) xhci->current_cmd = NULL; goto event_handled; @@ -1411,8 +1397,8 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, break; case TRB_CMD_NOOP: /* Is this an aborted command turned to NO-OP? */ - if (cmd->status == COMP_CMD_STOP) - cmd_comp_code = COMP_CMD_STOP; + if (cmd->status == COMP_STOPPED) + cmd_comp_code = COMP_STOPPED; break; case TRB_RESET_EP: WARN_ON(slot_id != TRB_TO_SLOT_ID( @@ -1437,9 +1423,9 @@ static void handle_cmd_completion(struct xhci_hcd *xhci, } /* restart timer if this wasn't the last command */ - if (cmd->cmd_list.next != &xhci->cmd_list) { - xhci->current_cmd = list_entry(cmd->cmd_list.next, - struct xhci_command, cmd_list); + if (!list_is_singular(&xhci->cmd_list)) { + xhci->current_cmd = list_first_entry(&cmd->cmd_list, + struct xhci_command, cmd_list); xhci_mod_cmd_timer(xhci, XHCI_CMD_DEFAULT_TIMEOUT); } else if (xhci->current_cmd == cmd) { xhci->current_cmd = NULL; @@ -1805,9 +1791,9 @@ static int xhci_requires_manual_halt_cleanup(struct xhci_hcd *xhci, unsigned int trb_comp_code) { /* TRB completion codes that may require a manual halt cleanup */ - if (trb_comp_code == COMP_TX_ERR || - trb_comp_code == COMP_BABBLE || - trb_comp_code == COMP_SPLIT_ERR) + if (trb_comp_code == COMP_USB_TRANSACTION_ERROR || + trb_comp_code == COMP_BABBLE_DETECTED_ERROR || + trb_comp_code == COMP_SPLIT_TRANSACTION_ERROR) /* The 0.95 spec says a babbling control endpoint * is not halted. The 0.96 spec says it is. Some HW * claims to be 0.95 compliant, but it halts the control @@ -1834,22 +1820,64 @@ int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code) return 0; } -/* - * Finish the td processing, remove the td from td list; - * Return 1 if the urb can be given back. - */ +static int xhci_td_cleanup(struct xhci_hcd *xhci, struct xhci_td *td, + struct xhci_ring *ep_ring, int *status) +{ + struct urb_priv *urb_priv; + struct urb *urb = NULL; + + /* Clean up the endpoint's TD list */ + urb = td->urb; + urb_priv = urb->hcpriv; + + /* if a bounce buffer was used to align this td then unmap it */ + xhci_unmap_td_bounce_buffer(xhci, ep_ring, td); + + /* Do one last check of the actual transfer length. + * If the host controller said we transferred more data than the buffer + * length, urb->actual_length will be a very big number (since it's + * unsigned). Play it safe and say we didn't transfer anything. + */ + if (urb->actual_length > urb->transfer_buffer_length) { + xhci_warn(xhci, "URB req %u and actual %u transfer length mismatch\n", + urb->transfer_buffer_length, urb->actual_length); + urb->actual_length = 0; + *status = 0; + } + list_del_init(&td->td_list); + /* Was this TD slated to be cancelled but completed anyway? */ + if (!list_empty(&td->cancelled_td_list)) + list_del_init(&td->cancelled_td_list); + + inc_td_cnt(urb); + /* Giveback the urb when all the tds are completed */ + if (last_td_in_urb(td)) { + if ((urb->actual_length != urb->transfer_buffer_length && + (urb->transfer_flags & URB_SHORT_NOT_OK)) || + (*status != 0 && !usb_endpoint_xfer_isoc(&urb->ep->desc))) + xhci_dbg(xhci, "Giveback URB %p, len = %d, expected = %d, status = %d\n", + urb, urb->actual_length, + urb->transfer_buffer_length, *status); + + /* set isoc urb status to 0 just as EHCI, UHCI, and OHCI */ + if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) + *status = 0; + xhci_giveback_urb_in_irq(xhci, td, *status); + } + + return 0; +} + static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, union xhci_trb *ep_trb, struct xhci_transfer_event *event, struct xhci_virt_ep *ep, int *status, bool skip) { struct xhci_virt_device *xdev; + struct xhci_ep_ctx *ep_ctx; struct xhci_ring *ep_ring; unsigned int slot_id; - int ep_index; - struct urb *urb = NULL; - struct xhci_ep_ctx *ep_ctx; - struct urb_priv *urb_priv; u32 trb_comp_code; + int ep_index; slot_id = TRB_TO_SLOT_ID(le32_to_cpu(event->flags)); xdev = xhci->devs[slot_id]; @@ -1861,9 +1889,9 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, if (skip) goto td_cleanup; - if (trb_comp_code == COMP_STOP_INVAL || - trb_comp_code == COMP_STOP || - trb_comp_code == COMP_STOP_SHORT) { + if (trb_comp_code == COMP_STOPPED_LENGTH_INVALID || + trb_comp_code == COMP_STOPPED || + trb_comp_code == COMP_STOPPED_SHORT_PACKET) { /* The Endpoint Stop Command completion will take care of any * stopped TDs. A stopped TD may be restarted, so don't update * the ring dequeue pointer or take this TD off any lists yet. @@ -1871,7 +1899,7 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, ep->stopped_td = td; return 0; } - if (trb_comp_code == COMP_STALL || + if (trb_comp_code == COMP_STALL_ERROR || xhci_requires_manual_halt_cleanup(xhci, ep_ctx, trb_comp_code)) { /* Issue a reset endpoint command to clear the host side @@ -1889,46 +1917,7 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, } td_cleanup: - /* Clean up the endpoint's TD list */ - urb = td->urb; - urb_priv = urb->hcpriv; - - /* if a bounce buffer was used to align this td then unmap it */ - if (td->bounce_seg) - xhci_unmap_td_bounce_buffer(xhci, ep_ring, td); - - /* Do one last check of the actual transfer length. - * If the host controller said we transferred more data than the buffer - * length, urb->actual_length will be a very big number (since it's - * unsigned). Play it safe and say we didn't transfer anything. - */ - if (urb->actual_length > urb->transfer_buffer_length) { - xhci_warn(xhci, "URB req %u and actual %u transfer length mismatch\n", - urb->transfer_buffer_length, urb->actual_length); - urb->actual_length = 0; - *status = 0; - } - list_del_init(&td->td_list); - /* Was this TD slated to be cancelled but completed anyway? */ - if (!list_empty(&td->cancelled_td_list)) - list_del_init(&td->cancelled_td_list); - - inc_td_cnt(urb); - /* Giveback the urb when all the tds are completed */ - if (last_td_in_urb(td)) { - if ((urb->actual_length != urb->transfer_buffer_length && - (urb->transfer_flags & URB_SHORT_NOT_OK)) || - (*status != 0 && !usb_endpoint_xfer_isoc(&urb->ep->desc))) - xhci_dbg(xhci, "Giveback URB %p, len = %d, expected = %d, status = %d\n", - urb, urb->actual_length, - urb->transfer_buffer_length, *status); - - /* set isoc urb status to 0 just as EHCI, UHCI, and OHCI */ - if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) - *status = 0; - xhci_giveback_urb_in_irq(xhci, td, *status); - } - return 0; + return xhci_td_cleanup(xhci, td, ep_ring, status); } /* sum trb lengths from ring dequeue up to stop_trb, _excluding_ stop_trb */ @@ -1982,16 +1971,16 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, } *status = 0; break; - case COMP_SHORT_TX: + case COMP_SHORT_PACKET: *status = 0; break; - case COMP_STOP_SHORT: + case COMP_STOPPED_SHORT_PACKET: if (trb_type == TRB_DATA || trb_type == TRB_NORMAL) td->urb->actual_length = remaining; else xhci_warn(xhci, "WARN: Stopped Short Packet on ctrl setup or status TRB\n"); goto finish_td; - case COMP_STOP: + case COMP_STOPPED: switch (trb_type) { case TRB_SETUP: td->urb->actual_length = 0; @@ -2005,7 +1994,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, trb_type); goto finish_td; } - case COMP_STOP_INVAL: + case COMP_STOPPED_LENGTH_INVALID: goto finish_td; default: if (!xhci_requires_manual_halt_cleanup(xhci, @@ -2014,7 +2003,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, xhci_dbg(xhci, "TRB error %u, halted endpoint index = %u\n", trb_comp_code, ep_index); /* else fall through */ - case COMP_STALL: + case COMP_STALL_ERROR: /* Did we transfer part of the data (middle) phase? */ if (trb_type == TRB_DATA || trb_type == TRB_NORMAL) td->urb->actual_length = requested - remaining; @@ -2066,7 +2055,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer)); trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len)); urb_priv = td->urb->hcpriv; - idx = urb_priv->td_cnt; + idx = urb_priv->num_tds_done; frame = &td->urb->iso_frame_desc[idx]; requested = frame->length; remaining = EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)); @@ -2085,35 +2074,35 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, } frame->status = 0; break; - case COMP_SHORT_TX: + case COMP_SHORT_PACKET: frame->status = short_framestatus; sum_trbs_for_length = true; break; - case COMP_BW_OVER: + case COMP_BANDWIDTH_OVERRUN_ERROR: frame->status = -ECOMM; break; - case COMP_BUFF_OVER: - case COMP_BABBLE: + case COMP_ISOCH_BUFFER_OVERRUN: + case COMP_BABBLE_DETECTED_ERROR: frame->status = -EOVERFLOW; break; - case COMP_DEV_ERR: - case COMP_STALL: + case COMP_INCOMPATIBLE_DEVICE_ERROR: + case COMP_STALL_ERROR: frame->status = -EPROTO; break; - case COMP_TX_ERR: + case COMP_USB_TRANSACTION_ERROR: frame->status = -EPROTO; if (ep_trb != td->last_trb) return 0; break; - case COMP_STOP: + case COMP_STOPPED: sum_trbs_for_length = true; break; - case COMP_STOP_SHORT: + case COMP_STOPPED_SHORT_PACKET: /* field normally containing residue now contains tranferred */ frame->status = short_framestatus; requested = remaining; break; - case COMP_STOP_INVAL: + case COMP_STOPPED_LENGTH_INVALID: requested = 0; remaining = 0; break; @@ -2145,7 +2134,7 @@ static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, ep_ring = xhci_dma_to_transfer_ring(ep, le64_to_cpu(event->buffer)); urb_priv = td->urb->hcpriv; - idx = urb_priv->td_cnt; + idx = urb_priv->num_tds_done; frame = &td->urb->iso_frame_desc[idx]; /* The transfer is partly done. */ @@ -2190,16 +2179,16 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, } *status = 0; break; - case COMP_SHORT_TX: + case COMP_SHORT_PACKET: xhci_dbg(xhci, "ep %#x - asked for %d bytes, %d bytes untransferred\n", td->urb->ep->desc.bEndpointAddress, requested, remaining); *status = 0; break; - case COMP_STOP_SHORT: + case COMP_STOPPED_SHORT_PACKET: td->urb->actual_length = remaining; goto finish_td; - case COMP_STOP_INVAL: + case COMP_STOPPED_LENGTH_INVALID: /* stopped on ep trb with invalid length, exclude it */ ep_trb_len = 0; remaining = 0; @@ -2231,8 +2220,6 @@ finish_td: */ static int handle_tx_event(struct xhci_hcd *xhci, struct xhci_transfer_event *event) - __releases(&xhci->lock) - __acquires(&xhci->lock) { struct xhci_virt_device *xdev; struct xhci_virt_ep *ep; @@ -2305,50 +2292,50 @@ static int handle_tx_event(struct xhci_hcd *xhci, if (EVENT_TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) break; if (xhci->quirks & XHCI_TRUST_TX_LENGTH) - trb_comp_code = COMP_SHORT_TX; + trb_comp_code = COMP_SHORT_PACKET; else xhci_warn_ratelimited(xhci, "WARN Successful completion on short TX: needs XHCI_TRUST_TX_LENGTH quirk?\n"); - case COMP_SHORT_TX: + case COMP_SHORT_PACKET: break; - case COMP_STOP: + case COMP_STOPPED: xhci_dbg(xhci, "Stopped on Transfer TRB\n"); break; - case COMP_STOP_INVAL: + case COMP_STOPPED_LENGTH_INVALID: xhci_dbg(xhci, "Stopped on No-op or Link TRB\n"); break; - case COMP_STOP_SHORT: + case COMP_STOPPED_SHORT_PACKET: xhci_dbg(xhci, "Stopped with short packet transfer detected\n"); break; - case COMP_STALL: + case COMP_STALL_ERROR: xhci_dbg(xhci, "Stalled endpoint\n"); ep->ep_state |= EP_HALTED; status = -EPIPE; break; - case COMP_TRB_ERR: + case COMP_TRB_ERROR: xhci_warn(xhci, "WARN: TRB error on endpoint\n"); status = -EILSEQ; break; - case COMP_SPLIT_ERR: - case COMP_TX_ERR: + case COMP_SPLIT_TRANSACTION_ERROR: + case COMP_USB_TRANSACTION_ERROR: xhci_dbg(xhci, "Transfer error on endpoint\n"); status = -EPROTO; break; - case COMP_BABBLE: + case COMP_BABBLE_DETECTED_ERROR: xhci_dbg(xhci, "Babble error on endpoint\n"); status = -EOVERFLOW; break; - case COMP_DB_ERR: + case COMP_DATA_BUFFER_ERROR: xhci_warn(xhci, "WARN: HC couldn't access mem fast enough\n"); status = -ENOSR; break; - case COMP_BW_OVER: + case COMP_BANDWIDTH_OVERRUN_ERROR: xhci_warn(xhci, "WARN: bandwidth overrun event on endpoint\n"); break; - case COMP_BUFF_OVER: + case COMP_ISOCH_BUFFER_OVERRUN: xhci_warn(xhci, "WARN: buffer overrun event on endpoint\n"); break; - case COMP_UNDERRUN: + case COMP_RING_UNDERRUN: /* * When the Isoch ring is empty, the xHC will generate * a Ring Overrun Event for IN Isoch endpoint or Ring @@ -2361,7 +2348,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, TRB_TO_SLOT_ID(le32_to_cpu(event->flags)), ep_index); goto cleanup; - case COMP_OVERRUN: + case COMP_RING_OVERRUN: xhci_dbg(xhci, "overrun event on endpoint\n"); if (!list_empty(&ep_ring->td_list)) xhci_dbg(xhci, "Overrun Event for slot %d ep %d " @@ -2369,11 +2356,11 @@ static int handle_tx_event(struct xhci_hcd *xhci, TRB_TO_SLOT_ID(le32_to_cpu(event->flags)), ep_index); goto cleanup; - case COMP_DEV_ERR: + case COMP_INCOMPATIBLE_DEVICE_ERROR: xhci_warn(xhci, "WARN: detect an incompatible device"); status = -EPROTO; break; - case COMP_MISSED_INT: + case COMP_MISSED_SERVICE_ERROR: /* * When encounter missed service error, one or more isoc tds * may be missed by xHC. @@ -2383,7 +2370,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, ep->skip = true; xhci_dbg(xhci, "Miss service interval error, set skip flag\n"); goto cleanup; - case COMP_PING_ERR: + case COMP_NO_PING_RESPONSE_ERROR: ep->skip = true; xhci_dbg(xhci, "No Ping response error, Skip one Isoc TD\n"); goto cleanup; @@ -2407,8 +2394,8 @@ static int handle_tx_event(struct xhci_hcd *xhci, * event if the device was suspended. Don't print * warnings. */ - if (!(trb_comp_code == COMP_STOP || - trb_comp_code == COMP_STOP_INVAL)) { + if (!(trb_comp_code == COMP_STOPPED || + trb_comp_code == COMP_STOPPED_LENGTH_INVALID)) { xhci_warn(xhci, "WARN Event TRB for slot %d ep %d with no TDs queued?\n", TRB_TO_SLOT_ID(le32_to_cpu(event->flags)), ep_index); @@ -2433,7 +2420,8 @@ static int handle_tx_event(struct xhci_hcd *xhci, goto cleanup; } - td = list_entry(ep_ring->td_list.next, struct xhci_td, td_list); + td = list_first_entry(&ep_ring->td_list, struct xhci_td, + td_list); if (ep->skip) td_num--; @@ -2449,8 +2437,8 @@ static int handle_tx_event(struct xhci_hcd *xhci, * last TRB of the previous TD. The command completion handle * will take care the rest. */ - if (!ep_seg && (trb_comp_code == COMP_STOP || - trb_comp_code == COMP_STOP_INVAL)) { + if (!ep_seg && (trb_comp_code == COMP_STOPPED || + trb_comp_code == COMP_STOPPED_LENGTH_INVALID)) { goto cleanup; } @@ -2481,7 +2469,7 @@ static int handle_tx_event(struct xhci_hcd *xhci, skip_isoc_td(xhci, td, event, ep, &status); goto cleanup; } - if (trb_comp_code == COMP_SHORT_TX) + if (trb_comp_code == COMP_SHORT_PACKET) ep_ring->last_td_was_short = true; else ep_ring->last_td_was_short = false; @@ -2493,6 +2481,10 @@ static int handle_tx_event(struct xhci_hcd *xhci, ep_trb = &ep_seg->trbs[(ep_trb_dma - ep_seg->dma) / sizeof(*ep_trb)]; + + trace_xhci_handle_transfer(ep_ring, + (struct xhci_generic_trb *) ep_trb); + /* * No-op TRB should not trigger interrupts. * If ep_trb is a no-op TRB, it means the @@ -2514,8 +2506,8 @@ static int handle_tx_event(struct xhci_hcd *xhci, &status); cleanup: handling_skipped_tds = ep->skip && - trb_comp_code != COMP_MISSED_INT && - trb_comp_code != COMP_PING_ERR; + trb_comp_code != COMP_MISSED_SERVICE_ERROR && + trb_comp_code != COMP_NO_PING_RESPONSE_ERROR; /* * Do not update event ring dequeue pointer if we're in a loop @@ -2559,6 +2551,8 @@ static int xhci_handle_event(struct xhci_hcd *xhci) xhci->event_ring->cycle_state) return 0; + trace_xhci_handle_event(xhci->event_ring, &event->generic); + /* * Barrier between reading the TRB_CYCLE (valid) flag above and any * speculative reads of the event's flags/data below. @@ -2617,27 +2611,28 @@ static int xhci_handle_event(struct xhci_hcd *xhci) irqreturn_t xhci_irq(struct usb_hcd *hcd) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); - u32 status; - u64 temp_64; union xhci_trb *event_ring_deq; + irqreturn_t ret = IRQ_NONE; dma_addr_t deq; + u64 temp_64; + u32 status; spin_lock(&xhci->lock); /* Check if the xHC generated the interrupt, or the irq is shared */ status = readl(&xhci->op_regs->status); - if (status == 0xffffffff) - goto hw_died; - - if (!(status & STS_EINT)) { - spin_unlock(&xhci->lock); - return IRQ_NONE; + if (status == 0xffffffff) { + ret = IRQ_HANDLED; + goto out; } + + if (!(status & STS_EINT)) + goto out; + if (status & STS_FATAL) { xhci_warn(xhci, "WARNING: Host System Error\n"); xhci_halt(xhci); -hw_died: - spin_unlock(&xhci->lock); - return IRQ_HANDLED; + ret = IRQ_HANDLED; + goto out; } /* @@ -2668,9 +2663,8 @@ hw_died: temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); xhci_write_64(xhci, temp_64 | ERST_EHB, &xhci->ir_set->erst_dequeue); - spin_unlock(&xhci->lock); - - return IRQ_HANDLED; + ret = IRQ_HANDLED; + goto out; } event_ring_deq = xhci->event_ring->dequeue; @@ -2695,10 +2689,12 @@ hw_died: /* Clear the event handler busy flag (RW1C); event ring is empty. */ temp_64 |= ERST_EHB; xhci_write_64(xhci, temp_64, &xhci->ir_set->erst_dequeue); + ret = IRQ_HANDLED; +out: spin_unlock(&xhci->lock); - return IRQ_HANDLED; + return ret; } irqreturn_t xhci_msi_irq(int irq, void *hcd) @@ -2726,6 +2722,9 @@ static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring, trb->field[1] = cpu_to_le32(field2); trb->field[2] = cpu_to_le32(field3); trb->field[3] = cpu_to_le32(field4); + + trace_xhci_queue_trb(ring, trb); + inc_enq(xhci, ring, more_trbs_coming); } @@ -2839,7 +2838,7 @@ static int prepare_transfer(struct xhci_hcd *xhci, return ret; urb_priv = urb->hcpriv; - td = urb_priv->td[td_index]; + td = &urb_priv->td[td_index]; INIT_LIST_HEAD(&td->td_list); INIT_LIST_HEAD(&td->cancelled_td_list); @@ -2856,8 +2855,6 @@ static int prepare_transfer(struct xhci_hcd *xhci, td->start_seg = ep_ring->enq_seg; td->first_trb = ep_ring->enqueue; - urb_priv->td[td_index] = td; - return 0; } @@ -3134,10 +3131,10 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, urb_priv = urb->hcpriv; /* Deal with URB_ZERO_PACKET - need one more td/trb */ - if (urb->transfer_flags & URB_ZERO_PACKET && urb_priv->length > 1) + if (urb->transfer_flags & URB_ZERO_PACKET && urb_priv->num_tds > 1) need_zero_pkt = true; - td = urb_priv->td[0]; + td = &urb_priv->td[0]; /* * Don't give the first TRB to the hardware (by toggling the cycle bit) @@ -3230,7 +3227,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index, urb->stream_id, 1, urb, 1, mem_flags); - urb_priv->td[1]->last_trb = ring->enqueue; + urb_priv->td[1].last_trb = ring->enqueue; field = TRB_TYPE(TRB_NORMAL) | ring->cycle_state | TRB_IOC; queue_trb(xhci, ring, 0, 0, 0, TRB_INTR_TARGET(0), field); } @@ -3251,7 +3248,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct usb_ctrlrequest *setup; struct xhci_generic_trb *start_trb; int start_cycle; - u32 field, length_field, remainder; + u32 field; struct urb_priv *urb_priv; struct xhci_td *td; @@ -3282,7 +3279,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, return ret; urb_priv = urb->hcpriv; - td = urb_priv->td[0]; + td = &urb_priv->td[0]; /* * Don't give the first TRB to the hardware (by toggling the cycle bit) @@ -3324,16 +3321,16 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, else field = TRB_TYPE(TRB_DATA); - remainder = xhci_td_remainder(xhci, 0, - urb->transfer_buffer_length, - urb->transfer_buffer_length, - urb, 1); - - length_field = TRB_LEN(urb->transfer_buffer_length) | - TRB_TD_SIZE(remainder) | - TRB_INTR_TARGET(0); - if (urb->transfer_buffer_length > 0) { + u32 length_field, remainder; + + remainder = xhci_td_remainder(xhci, 0, + urb->transfer_buffer_length, + urb->transfer_buffer_length, + urb, 1); + length_field = TRB_LEN(urb->transfer_buffer_length) | + TRB_TD_SIZE(remainder) | + TRB_INTR_TARGET(0); if (setup->bRequestType & USB_DIR_IN) field |= TRB_DIR_IN; queue_trb(xhci, ep_ring, true, @@ -3570,7 +3567,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags, return ret; goto cleanup; } - td = urb_priv->td[i]; + td = &urb_priv->td[i]; /* use SIA as default, if frame id is used overwrite it */ sia_frame_id = TRB_SIA; @@ -3677,20 +3674,20 @@ cleanup: /* Clean up a partially enqueued isoc transfer. */ for (i--; i >= 0; i--) - list_del_init(&urb_priv->td[i]->td_list); + list_del_init(&urb_priv->td[i].td_list); /* Use the first TD as a temporary variable to turn the TDs we've queued * into No-ops with a software-owned cycle bit. That way the hardware * won't accidentally start executing bogus TDs when we partially * overwrite them. td->first_trb and td->start_seg are already set. */ - urb_priv->td[0]->last_trb = ep_ring->enqueue; + urb_priv->td[0].last_trb = ep_ring->enqueue; /* Every TRB except the first & last will have its cycle bit flipped. */ - td_to_noop(xhci, ep_ring, urb_priv->td[0], true); + td_to_noop(xhci, ep_ring, &urb_priv->td[0], true); /* Reset the ring enqueue back to the first TRB and its cycle bit. */ - ep_ring->enqueue = urb_priv->td[0]->first_trb; - ep_ring->enq_seg = urb_priv->td[0]->start_seg; + ep_ring->enqueue = urb_priv->td[0].first_trb; + ep_ring->enq_seg = urb_priv->td[0].start_seg; ep_ring->cycle_state = start_cycle; ep_ring->num_trbs_free = ep_ring->num_trbs_free_temp; usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb); @@ -3816,15 +3813,15 @@ static int queue_command(struct xhci_hcd *xhci, struct xhci_command *cmd, } cmd->command_trb = xhci->cmd_ring->enqueue; - list_add_tail(&cmd->cmd_list, &xhci->cmd_list); /* if there are no other commands queued we start the timeout timer */ - if (xhci->cmd_list.next == &cmd->cmd_list && - !delayed_work_pending(&xhci->cmd_timer)) { + if (list_empty(&xhci->cmd_list)) { xhci->current_cmd = cmd; xhci_mod_cmd_timer(xhci, XHCI_CMD_DEFAULT_TIMEOUT); } + list_add_tail(&cmd->cmd_list, &xhci->cmd_list); + queue_trb(xhci, xhci->cmd_ring, false, field1, field2, field3, field4 | xhci->cmd_ring->cycle_state); return 0; diff --git a/drivers/usb/host/xhci-trace.h b/drivers/usb/host/xhci-trace.h index 59c05653b2ea..1ac2cdf8eece 100644 --- a/drivers/usb/host/xhci-trace.h +++ b/drivers/usb/host/xhci-trace.h @@ -103,7 +103,7 @@ DECLARE_EVENT_CLASS(xhci_log_ctx, ((HCC_64BYTE_CONTEXT(xhci->hcc_params) + 1) * 32) * ((ctx->type == XHCI_CTX_TYPE_INPUT) + ep_num + 1)); ), - TP_printk("\nctx_64=%d, ctx_type=%u, ctx_dma=@%llx, ctx_va=@%p", + TP_printk("ctx_64=%d, ctx_type=%u, ctx_dma=@%llx, ctx_va=@%p", __entry->ctx_64, __entry->ctx_type, (unsigned long long) __entry->ctx_dma, __entry->ctx_va ) @@ -115,34 +115,174 @@ DEFINE_EVENT(xhci_log_ctx, xhci_address_ctx, TP_ARGS(xhci, ctx, ep_num) ); -DECLARE_EVENT_CLASS(xhci_log_event, - TP_PROTO(void *trb_va, struct xhci_generic_trb *ev), - TP_ARGS(trb_va, ev), +DECLARE_EVENT_CLASS(xhci_log_trb, + TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb), + TP_ARGS(ring, trb), TP_STRUCT__entry( - __field(void *, va) - __field(u64, dma) - __field(u32, status) - __field(u32, flags) - __dynamic_array(u8, trb, sizeof(struct xhci_generic_trb)) + __field(u32, type) + __field(u32, field0) + __field(u32, field1) + __field(u32, field2) + __field(u32, field3) ), TP_fast_assign( - __entry->va = trb_va; - __entry->dma = ((u64)le32_to_cpu(ev->field[1])) << 32 | - le32_to_cpu(ev->field[0]); - __entry->status = le32_to_cpu(ev->field[2]); - __entry->flags = le32_to_cpu(ev->field[3]); - memcpy(__get_dynamic_array(trb), trb_va, - sizeof(struct xhci_generic_trb)); + __entry->type = ring->type; + __entry->field0 = le32_to_cpu(trb->field[0]); + __entry->field1 = le32_to_cpu(trb->field[1]); + __entry->field2 = le32_to_cpu(trb->field[2]); + __entry->field3 = le32_to_cpu(trb->field[3]); ), - TP_printk("\ntrb_dma=@%llx, trb_va=@%p, status=%08x, flags=%08x", - (unsigned long long) __entry->dma, __entry->va, - __entry->status, __entry->flags + TP_printk("%s: %s", xhci_ring_type_string(__entry->type), + xhci_decode_trb(__entry->field0, __entry->field1, + __entry->field2, __entry->field3) ) ); -DEFINE_EVENT(xhci_log_event, xhci_cmd_completion, - TP_PROTO(void *trb_va, struct xhci_generic_trb *ev), - TP_ARGS(trb_va, ev) +DEFINE_EVENT(xhci_log_trb, xhci_handle_event, + TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb), + TP_ARGS(ring, trb) +); + +DEFINE_EVENT(xhci_log_trb, xhci_handle_command, + TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb), + TP_ARGS(ring, trb) +); + +DEFINE_EVENT(xhci_log_trb, xhci_handle_transfer, + TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb), + TP_ARGS(ring, trb) +); + +DEFINE_EVENT(xhci_log_trb, xhci_queue_trb, + TP_PROTO(struct xhci_ring *ring, struct xhci_generic_trb *trb), + TP_ARGS(ring, trb) +); + +DECLARE_EVENT_CLASS(xhci_log_virt_dev, + TP_PROTO(struct xhci_virt_device *vdev), + TP_ARGS(vdev), + TP_STRUCT__entry( + __field(void *, vdev) + __field(unsigned long long, out_ctx) + __field(unsigned long long, in_ctx) + __field(int, devnum) + __field(int, state) + __field(int, speed) + __field(u8, portnum) + __field(u8, level) + __field(int, slot_id) + ), + TP_fast_assign( + __entry->vdev = vdev; + __entry->in_ctx = (unsigned long long) vdev->in_ctx->dma; + __entry->out_ctx = (unsigned long long) vdev->out_ctx->dma; + __entry->devnum = vdev->udev->devnum; + __entry->state = vdev->udev->state; + __entry->speed = vdev->udev->speed; + __entry->portnum = vdev->udev->portnum; + __entry->level = vdev->udev->level; + __entry->slot_id = vdev->udev->slot_id; + ), + TP_printk("vdev %p ctx %llx | %llx num %d state %d speed %d port %d level %d slot %d", + __entry->vdev, __entry->in_ctx, __entry->out_ctx, + __entry->devnum, __entry->state, __entry->speed, + __entry->portnum, __entry->level, __entry->slot_id + ) +); + +DEFINE_EVENT(xhci_log_virt_dev, xhci_alloc_virt_device, + TP_PROTO(struct xhci_virt_device *vdev), + TP_ARGS(vdev) +); + +DEFINE_EVENT(xhci_log_virt_dev, xhci_free_virt_device, + TP_PROTO(struct xhci_virt_device *vdev), + TP_ARGS(vdev) +); + +DEFINE_EVENT(xhci_log_virt_dev, xhci_setup_device, + TP_PROTO(struct xhci_virt_device *vdev), + TP_ARGS(vdev) +); + +DEFINE_EVENT(xhci_log_virt_dev, xhci_setup_addressable_virt_device, + TP_PROTO(struct xhci_virt_device *vdev), + TP_ARGS(vdev) +); + +DEFINE_EVENT(xhci_log_virt_dev, xhci_stop_device, + TP_PROTO(struct xhci_virt_device *vdev), + TP_ARGS(vdev) +); + +DECLARE_EVENT_CLASS(xhci_log_urb, + TP_PROTO(struct urb *urb), + TP_ARGS(urb), + TP_STRUCT__entry( + __field(void *, urb) + __field(unsigned int, pipe) + __field(unsigned int, stream) + __field(int, status) + __field(unsigned int, flags) + __field(int, num_mapped_sgs) + __field(int, num_sgs) + __field(int, length) + __field(int, actual) + __field(int, epnum) + __field(int, dir_in) + __field(int, type) + ), + TP_fast_assign( + __entry->urb = urb; + __entry->pipe = urb->pipe; + __entry->stream = urb->stream_id; + __entry->status = urb->status; + __entry->flags = urb->transfer_flags; + __entry->num_mapped_sgs = urb->num_mapped_sgs; + __entry->num_sgs = urb->num_sgs; + __entry->length = urb->transfer_buffer_length; + __entry->actual = urb->actual_length; + __entry->epnum = usb_endpoint_num(&urb->ep->desc); + __entry->dir_in = usb_endpoint_dir_in(&urb->ep->desc); + __entry->type = usb_endpoint_type(&urb->ep->desc); + ), + TP_printk("ep%d%s-%s: urb %p pipe %u length %d/%d sgs %d/%d stream %d flags %08x", + __entry->epnum, __entry->dir_in ? "in" : "out", + ({ char *s; + switch (__entry->type) { + case USB_ENDPOINT_XFER_INT: + s = "intr"; + break; + case USB_ENDPOINT_XFER_CONTROL: + s = "control"; + break; + case USB_ENDPOINT_XFER_BULK: + s = "bulk"; + break; + case USB_ENDPOINT_XFER_ISOC: + s = "isoc"; + break; + default: + s = "UNKNOWN"; + } s; }), __entry->urb, __entry->pipe, __entry->actual, + __entry->length, __entry->num_mapped_sgs, + __entry->num_sgs, __entry->stream, __entry->flags + ) +); + +DEFINE_EVENT(xhci_log_urb, xhci_urb_enqueue, + TP_PROTO(struct urb *urb), + TP_ARGS(urb) +); + +DEFINE_EVENT(xhci_log_urb, xhci_urb_giveback, + TP_PROTO(struct urb *urb), + TP_ARGS(urb) +); + +DEFINE_EVENT(xhci_log_urb, xhci_urb_dequeue, + TP_PROTO(struct urb *urb), + TP_ARGS(urb) ); #endif /* __XHCI_TRACE_H */ diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 9a0ec116654a..6d6c46000e56 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -207,7 +207,7 @@ int xhci_reset(struct xhci_hcd *xhci) ret = xhci_handshake(&xhci->op_regs->status, STS_CNR, 0, 10 * 1000 * 1000); - for (i = 0; i < 2; ++i) { + for (i = 0; i < 2; i++) { xhci->bus_state[i].port_c_suspend = 0; xhci->bus_state[i].suspended_ports = 0; xhci->bus_state[i].resuming_ports = 0; @@ -1332,12 +1332,11 @@ command_cleanup: int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); - struct xhci_td *buffer; unsigned long flags; int ret = 0; - unsigned int slot_id, ep_index; + unsigned int slot_id, ep_index, ep_state; struct urb_priv *urb_priv; - int size, i; + int num_tds; if (!urb || xhci_check_args(hcd, urb->dev, urb->ep, true, true, __func__) <= 0) @@ -1349,40 +1348,30 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) if (!HCD_HW_ACCESSIBLE(hcd)) { if (!in_interrupt()) xhci_dbg(xhci, "urb submitted during PCI suspend\n"); - ret = -ESHUTDOWN; - goto exit; + return -ESHUTDOWN; } if (usb_endpoint_xfer_isoc(&urb->ep->desc)) - size = urb->number_of_packets; + num_tds = urb->number_of_packets; else if (usb_endpoint_is_bulk_out(&urb->ep->desc) && urb->transfer_buffer_length > 0 && urb->transfer_flags & URB_ZERO_PACKET && !(urb->transfer_buffer_length % usb_endpoint_maxp(&urb->ep->desc))) - size = 2; + num_tds = 2; else - size = 1; + num_tds = 1; urb_priv = kzalloc(sizeof(struct urb_priv) + - size * sizeof(struct xhci_td *), mem_flags); + num_tds * sizeof(struct xhci_td), mem_flags); if (!urb_priv) return -ENOMEM; - buffer = kzalloc(size * sizeof(struct xhci_td), mem_flags); - if (!buffer) { - kfree(urb_priv); - return -ENOMEM; - } - - for (i = 0; i < size; i++) { - urb_priv->td[i] = buffer; - buffer++; - } - - urb_priv->length = size; - urb_priv->td_cnt = 0; + urb_priv->num_tds = num_tds; + urb_priv->num_tds_done = 0; urb->hcpriv = urb_priv; + trace_xhci_urb_enqueue(urb); + if (usb_endpoint_xfer_control(&urb->ep->desc)) { /* Check to see if the max packet size for the default control * endpoint changed during FS device enumeration @@ -1396,69 +1385,51 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags) return ret; } } + } - /* We have a spinlock and interrupts disabled, so we must pass - * atomic context to this function, which may allocate memory. - */ - spin_lock_irqsave(&xhci->lock, flags); - if (xhci->xhc_state & XHCI_STATE_DYING) - goto dying; + spin_lock_irqsave(&xhci->lock, flags); + + if (xhci->xhc_state & XHCI_STATE_DYING) { + xhci_dbg(xhci, "Ep 0x%x: URB %p submitted for non-responsive xHCI host.\n", + urb->ep->desc.bEndpointAddress, urb); + ret = -ESHUTDOWN; + goto free_priv; + } + + switch (usb_endpoint_type(&urb->ep->desc)) { + + case USB_ENDPOINT_XFER_CONTROL: ret = xhci_queue_ctrl_tx(xhci, GFP_ATOMIC, urb, - slot_id, ep_index); - if (ret) - goto free_priv; - spin_unlock_irqrestore(&xhci->lock, flags); - } else if (usb_endpoint_xfer_bulk(&urb->ep->desc)) { - spin_lock_irqsave(&xhci->lock, flags); - if (xhci->xhc_state & XHCI_STATE_DYING) - goto dying; - if (xhci->devs[slot_id]->eps[ep_index].ep_state & - EP_GETTING_STREAMS) { - xhci_warn(xhci, "WARN: Can't enqueue URB while bulk ep " - "is transitioning to using streams.\n"); - ret = -EINVAL; - } else if (xhci->devs[slot_id]->eps[ep_index].ep_state & - EP_GETTING_NO_STREAMS) { - xhci_warn(xhci, "WARN: Can't enqueue URB while bulk ep " - "is transitioning to " - "not having streams.\n"); + slot_id, ep_index); + break; + case USB_ENDPOINT_XFER_BULK: + ep_state = xhci->devs[slot_id]->eps[ep_index].ep_state; + if (ep_state & (EP_GETTING_STREAMS | EP_GETTING_NO_STREAMS)) { + xhci_warn(xhci, "WARN: Can't enqueue URB, ep in streams transition state %x\n", + ep_state); ret = -EINVAL; - } else { - ret = xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb, - slot_id, ep_index); + break; } - if (ret) - goto free_priv; - spin_unlock_irqrestore(&xhci->lock, flags); - } else if (usb_endpoint_xfer_int(&urb->ep->desc)) { - spin_lock_irqsave(&xhci->lock, flags); - if (xhci->xhc_state & XHCI_STATE_DYING) - goto dying; + ret = xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb, + slot_id, ep_index); + break; + + + case USB_ENDPOINT_XFER_INT: ret = xhci_queue_intr_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index); - if (ret) - goto free_priv; - spin_unlock_irqrestore(&xhci->lock, flags); - } else { - spin_lock_irqsave(&xhci->lock, flags); - if (xhci->xhc_state & XHCI_STATE_DYING) - goto dying; + break; + + case USB_ENDPOINT_XFER_ISOC: ret = xhci_queue_isoc_tx_prepare(xhci, GFP_ATOMIC, urb, slot_id, ep_index); - if (ret) - goto free_priv; - spin_unlock_irqrestore(&xhci->lock, flags); } -exit: - return ret; -dying: - xhci_dbg(xhci, "Ep 0x%x: URB %p submitted for " - "non-responsive xHCI host.\n", - urb->ep->desc.bEndpointAddress, urb); - ret = -ESHUTDOWN; + + if (ret) { free_priv: - xhci_urb_free_priv(urb_priv); - urb->hcpriv = NULL; + xhci_urb_free_priv(urb_priv); + urb->hcpriv = NULL; + } spin_unlock_irqrestore(&xhci->lock, flags); return ret; } @@ -1509,6 +1480,9 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) xhci = hcd_to_xhci(hcd); spin_lock_irqsave(&xhci->lock, flags); + + trace_xhci_urb_dequeue(urb); + /* Make sure the URB hasn't completed or been unlinked already */ ret = usb_hcd_check_unlink_urb(hcd, urb, status); if (ret || !urb->hcpriv) @@ -1518,10 +1492,10 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, "HW died, freeing TD."); urb_priv = urb->hcpriv; - for (i = urb_priv->td_cnt; - i < urb_priv->length && xhci->devs[urb->dev->slot_id]; + for (i = urb_priv->num_tds_done; + i < urb_priv->num_tds && xhci->devs[urb->dev->slot_id]; i++) { - td = urb_priv->td[i]; + td = &urb_priv->td[i]; if (!list_empty(&td->td_list)) list_del_init(&td->td_list); if (!list_empty(&td->cancelled_td_list)) @@ -1544,33 +1518,32 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) } urb_priv = urb->hcpriv; - i = urb_priv->td_cnt; - if (i < urb_priv->length) + i = urb_priv->num_tds_done; + if (i < urb_priv->num_tds) xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, "Cancel URB %p, dev %s, ep 0x%x, " "starting at offset 0x%llx", urb, urb->dev->devpath, urb->ep->desc.bEndpointAddress, (unsigned long long) xhci_trb_virt_to_dma( - urb_priv->td[i]->start_seg, - urb_priv->td[i]->first_trb)); + urb_priv->td[i].start_seg, + urb_priv->td[i].first_trb)); - for (; i < urb_priv->length; i++) { - td = urb_priv->td[i]; + for (; i < urb_priv->num_tds; i++) { + td = &urb_priv->td[i]; list_add_tail(&td->cancelled_td_list, &ep->cancelled_td_list); } /* Queue a stop endpoint command, but only if this is * the first cancellation to be handled. */ - if (!(ep->ep_state & EP_HALT_PENDING)) { + if (!(ep->ep_state & EP_STOP_CMD_PENDING)) { command = xhci_alloc_command(xhci, false, false, GFP_ATOMIC); if (!command) { ret = -ENOMEM; goto done; } - ep->ep_state |= EP_HALT_PENDING; - ep->stop_cmds_pending++; + ep->ep_state |= EP_STOP_CMD_PENDING; ep->stop_cmd_timer.expires = jiffies + XHCI_STOP_EP_CMD_TIMEOUT * HZ; add_timer(&ep->stop_cmd_timer); @@ -1809,7 +1782,7 @@ static void xhci_zero_in_ctx(struct xhci_hcd *xhci, struct xhci_virt_device *vir slot_ctx->dev_info &= cpu_to_le32(~LAST_CTX_MASK); /* Endpoint 0 is always valid */ slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1)); - for (i = 1; i < 31; ++i) { + for (i = 1; i < 31; i++) { ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, i); ep_ctx->ep_info = 0; ep_ctx->ep_info2 = 0; @@ -1824,32 +1797,32 @@ static int xhci_configure_endpoint_result(struct xhci_hcd *xhci, int ret; switch (*cmd_status) { - case COMP_CMD_ABORT: - case COMP_CMD_STOP: + case COMP_COMMAND_ABORTED: + case COMP_STOPPED: xhci_warn(xhci, "Timeout while waiting for configure endpoint command\n"); ret = -ETIME; break; - case COMP_ENOMEM: + case COMP_RESOURCE_ERROR: dev_warn(&udev->dev, "Not enough host controller resources for new device state.\n"); ret = -ENOMEM; /* FIXME: can we allocate more resources for the HC? */ break; - case COMP_BW_ERR: - case COMP_2ND_BW_ERR: + case COMP_BANDWIDTH_ERROR: + case COMP_SECONDARY_BANDWIDTH_ERROR: dev_warn(&udev->dev, "Not enough bandwidth for new device state.\n"); ret = -ENOSPC; /* FIXME: can we go back to the old state? */ break; - case COMP_TRB_ERR: + case COMP_TRB_ERROR: /* the HCD set up something wrong */ dev_warn(&udev->dev, "ERROR: Endpoint drop flag = 0, " "add flag = 1, " "and endpoint is not disabled.\n"); ret = -EINVAL; break; - case COMP_DEV_ERR: + case COMP_INCOMPATIBLE_DEVICE_ERROR: dev_warn(&udev->dev, "ERROR: Incompatible device for endpoint configure command.\n"); ret = -ENODEV; @@ -1875,33 +1848,33 @@ static int xhci_evaluate_context_result(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev = xhci->devs[udev->slot_id]; switch (*cmd_status) { - case COMP_CMD_ABORT: - case COMP_CMD_STOP: + case COMP_COMMAND_ABORTED: + case COMP_STOPPED: xhci_warn(xhci, "Timeout while waiting for evaluate context command\n"); ret = -ETIME; break; - case COMP_EINVAL: + case COMP_PARAMETER_ERROR: dev_warn(&udev->dev, "WARN: xHCI driver setup invalid evaluate context command.\n"); ret = -EINVAL; break; - case COMP_EBADSLT: + case COMP_SLOT_NOT_ENABLED_ERROR: dev_warn(&udev->dev, "WARN: slot not enabled for evaluate context command.\n"); ret = -EINVAL; break; - case COMP_CTX_STATE: + case COMP_CONTEXT_STATE_ERROR: dev_warn(&udev->dev, "WARN: invalid context state for evaluate context command.\n"); xhci_dbg_ctx(xhci, virt_dev->out_ctx, 1); ret = -EINVAL; break; - case COMP_DEV_ERR: + case COMP_INCOMPATIBLE_DEVICE_ERROR: dev_warn(&udev->dev, "ERROR: Incompatible device for evaluate context command.\n"); ret = -ENODEV; break; - case COMP_MEL_ERR: + case COMP_MAX_EXIT_LATENCY_TOO_LARGE_ERROR: /* Max Exit Latency too large error */ dev_warn(&udev->dev, "WARN: Max Exit Latency too large\n"); ret = -EINVAL; @@ -2781,7 +2754,7 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) LAST_CTX_TO_EP_NUM(le32_to_cpu(slot_ctx->dev_info))); /* Free any rings that were dropped, but not changed. */ - for (i = 1; i < 31; ++i) { + for (i = 1; i < 31; i++) { if ((le32_to_cpu(ctrl_ctx->drop_flags) & (1 << (i + 1))) && !(le32_to_cpu(ctrl_ctx->add_flags) & (1 << (i + 1)))) { xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i); @@ -2793,7 +2766,7 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) * Install any rings for completely new endpoints or changed endpoints, * and free or cache any old rings from changed endpoints. */ - for (i = 1; i < 31; ++i) { + for (i = 1; i < 31; i++) { if (!virt_dev->eps[i].new_ring) continue; /* Only cache or free the old ring if it exists. @@ -2827,7 +2800,7 @@ void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev) xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev); virt_dev = xhci->devs[udev->slot_id]; /* Free any rings allocated for added endpoints */ - for (i = 0; i < 31; ++i) { + for (i = 0; i < 31; i++) { if (virt_dev->eps[i].new_ring) { xhci_ring_free(xhci, virt_dev->eps[i].new_ring); virt_dev->eps[i].new_ring = NULL; @@ -3497,13 +3470,13 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev) */ ret = reset_device_cmd->status; switch (ret) { - case COMP_CMD_ABORT: - case COMP_CMD_STOP: + case COMP_COMMAND_ABORTED: + case COMP_STOPPED: xhci_warn(xhci, "Timeout waiting for reset device command\n"); ret = -ETIME; goto command_cleanup; - case COMP_EBADSLT: /* 0.95 completion code for bad slot ID */ - case COMP_CTX_STATE: /* 0.96 completion code for same thing */ + case COMP_SLOT_NOT_ENABLED_ERROR: /* 0.95 completion for bad slot ID */ + case COMP_CONTEXT_STATE_ERROR: /* 0.96 completion code for same thing */ xhci_dbg(xhci, "Can't reset device (slot ID %u) in %s state\n", slot_id, xhci_get_slot_state(xhci, virt_dev->out_ctx)); @@ -3533,7 +3506,7 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev) /* Everything but endpoint 0 is disabled, so free or cache the rings. */ last_freed_endpoint = 1; - for (i = 1; i < 31; ++i) { + for (i = 1; i < 31; i++) { struct xhci_virt_ep *ep = &virt_dev->eps[i]; if (ep->ep_state & EP_HAS_STREAMS) { @@ -3609,8 +3582,8 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev) virt_dev = xhci->devs[udev->slot_id]; /* Stop any wayward timer functions (which may grab the lock) */ - for (i = 0; i < 31; ++i) { - virt_dev->eps[i].ep_state &= ~EP_HALT_PENDING; + for (i = 0; i < 31; i++) { + virt_dev->eps[i].ep_state &= ~EP_STOP_CMD_PENDING; del_timer_sync(&virt_dev->eps[i].stop_cmd_timer); } @@ -3844,6 +3817,7 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev, le32_to_cpu(slot_ctx->dev_info) >> 27); spin_lock_irqsave(&xhci->lock, flags); + trace_xhci_setup_device(virt_dev); ret = xhci_queue_address_device(xhci, command, virt_dev->in_ctx->dma, udev->slot_id, setup); if (ret) { @@ -3863,22 +3837,22 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev, * command on a timeout. */ switch (command->status) { - case COMP_CMD_ABORT: - case COMP_CMD_STOP: + case COMP_COMMAND_ABORTED: + case COMP_STOPPED: xhci_warn(xhci, "Timeout while waiting for setup device command\n"); ret = -ETIME; break; - case COMP_CTX_STATE: - case COMP_EBADSLT: + case COMP_CONTEXT_STATE_ERROR: + case COMP_SLOT_NOT_ENABLED_ERROR: xhci_err(xhci, "Setup ERROR: setup %s command for slot %d.\n", act, udev->slot_id); ret = -EINVAL; break; - case COMP_TX_ERR: + case COMP_USB_TRANSACTION_ERROR: dev_warn(&udev->dev, "Device not responding to setup %s.\n", act); ret = -EPROTO; break; - case COMP_DEV_ERR: + case COMP_INCOMPATIBLE_DEVICE_ERROR: dev_warn(&udev->dev, "ERROR: Incompatible device for setup %s command\n", act); ret = -ENODEV; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 2d7b6374b58d..da3eb695fe54 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -912,7 +912,7 @@ struct xhci_virt_ep { unsigned int ep_state; #define SET_DEQ_PENDING (1 << 0) #define EP_HALTED (1 << 1) /* For stall handling */ -#define EP_HALT_PENDING (1 << 2) /* For URB cancellation */ +#define EP_STOP_CMD_PENDING (1 << 2) /* For URB cancellation */ /* Transitioning the endpoint to using streams, don't enqueue URBs */ #define EP_GETTING_STREAMS (1 << 3) #define EP_HAS_STREAMS (1 << 4) @@ -924,7 +924,6 @@ struct xhci_virt_ep { unsigned int stopped_stream; /* Watchdog timer for stop endpoint command to cancel URBs */ struct timer_list stop_cmd_timer; - int stop_cmds_pending; struct xhci_hcd *xhci; /* Dequeue pointer and dequeue segment for a submitted Set TR Dequeue * command. We'll need to update the ring's dequeue segment and dequeue @@ -1061,76 +1060,122 @@ struct xhci_transfer_event { /* Completion Code - only applicable for some types of TRBs */ #define COMP_CODE_MASK (0xff << 24) #define GET_COMP_CODE(p) (((p) & COMP_CODE_MASK) >> 24) -#define COMP_SUCCESS 1 -/* Data Buffer Error */ -#define COMP_DB_ERR 2 -/* Babble Detected Error */ -#define COMP_BABBLE 3 -/* USB Transaction Error */ -#define COMP_TX_ERR 4 -/* TRB Error - some TRB field is invalid */ -#define COMP_TRB_ERR 5 -/* Stall Error - USB device is stalled */ -#define COMP_STALL 6 -/* Resource Error - HC doesn't have memory for that device configuration */ -#define COMP_ENOMEM 7 -/* Bandwidth Error - not enough room in schedule for this dev config */ -#define COMP_BW_ERR 8 -/* No Slots Available Error - HC ran out of device slots */ -#define COMP_ENOSLOTS 9 -/* Invalid Stream Type Error */ -#define COMP_STREAM_ERR 10 -/* Slot Not Enabled Error - doorbell rung for disabled device slot */ -#define COMP_EBADSLT 11 -/* Endpoint Not Enabled Error */ -#define COMP_EBADEP 12 -/* Short Packet */ -#define COMP_SHORT_TX 13 -/* Ring Underrun - doorbell rung for an empty isoc OUT ep ring */ -#define COMP_UNDERRUN 14 -/* Ring Overrun - isoc IN ep ring is empty when ep is scheduled to RX */ -#define COMP_OVERRUN 15 -/* Virtual Function Event Ring Full Error */ -#define COMP_VF_FULL 16 -/* Parameter Error - Context parameter is invalid */ -#define COMP_EINVAL 17 -/* Bandwidth Overrun Error - isoc ep exceeded its allocated bandwidth */ -#define COMP_BW_OVER 18 -/* Context State Error - illegal context state transition requested */ -#define COMP_CTX_STATE 19 -/* No Ping Response Error - HC didn't get PING_RESPONSE in time to TX */ -#define COMP_PING_ERR 20 -/* Event Ring is full */ -#define COMP_ER_FULL 21 -/* Incompatible Device Error */ -#define COMP_DEV_ERR 22 -/* Missed Service Error - HC couldn't service an isoc ep within interval */ -#define COMP_MISSED_INT 23 -/* Successfully stopped command ring */ -#define COMP_CMD_STOP 24 -/* Successfully aborted current command and stopped command ring */ -#define COMP_CMD_ABORT 25 -/* Stopped - transfer was terminated by a stop endpoint command */ -#define COMP_STOP 26 -/* Same as COMP_EP_STOPPED, but the transferred length in the event is invalid */ -#define COMP_STOP_INVAL 27 -/* Same as COMP_EP_STOPPED, but a short packet detected */ -#define COMP_STOP_SHORT 28 -/* Max Exit Latency Too Large Error */ -#define COMP_MEL_ERR 29 -/* TRB type 30 reserved */ -/* Isoc Buffer Overrun - an isoc IN ep sent more data than could fit in TD */ -#define COMP_BUFF_OVER 31 -/* Event Lost Error - xHC has an "internal event overrun condition" */ -#define COMP_ISSUES 32 -/* Undefined Error - reported when other error codes don't apply */ -#define COMP_UNKNOWN 33 -/* Invalid Stream ID Error */ -#define COMP_STRID_ERR 34 -/* Secondary Bandwidth Error - may be returned by a Configure Endpoint cmd */ -#define COMP_2ND_BW_ERR 35 -/* Split Transaction Error */ -#define COMP_SPLIT_ERR 36 +#define COMP_INVALID 0 +#define COMP_SUCCESS 1 +#define COMP_DATA_BUFFER_ERROR 2 +#define COMP_BABBLE_DETECTED_ERROR 3 +#define COMP_USB_TRANSACTION_ERROR 4 +#define COMP_TRB_ERROR 5 +#define COMP_STALL_ERROR 6 +#define COMP_RESOURCE_ERROR 7 +#define COMP_BANDWIDTH_ERROR 8 +#define COMP_NO_SLOTS_AVAILABLE_ERROR 9 +#define COMP_INVALID_STREAM_TYPE_ERROR 10 +#define COMP_SLOT_NOT_ENABLED_ERROR 11 +#define COMP_ENDPOINT_NOT_ENABLED_ERROR 12 +#define COMP_SHORT_PACKET 13 +#define COMP_RING_UNDERRUN 14 +#define COMP_RING_OVERRUN 15 +#define COMP_VF_EVENT_RING_FULL_ERROR 16 +#define COMP_PARAMETER_ERROR 17 +#define COMP_BANDWIDTH_OVERRUN_ERROR 18 +#define COMP_CONTEXT_STATE_ERROR 19 +#define COMP_NO_PING_RESPONSE_ERROR 20 +#define COMP_EVENT_RING_FULL_ERROR 21 +#define COMP_INCOMPATIBLE_DEVICE_ERROR 22 +#define COMP_MISSED_SERVICE_ERROR 23 +#define COMP_COMMAND_RING_STOPPED 24 +#define COMP_COMMAND_ABORTED 25 +#define COMP_STOPPED 26 +#define COMP_STOPPED_LENGTH_INVALID 27 +#define COMP_STOPPED_SHORT_PACKET 28 +#define COMP_MAX_EXIT_LATENCY_TOO_LARGE_ERROR 29 +#define COMP_ISOCH_BUFFER_OVERRUN 31 +#define COMP_EVENT_LOST_ERROR 32 +#define COMP_UNDEFINED_ERROR 33 +#define COMP_INVALID_STREAM_ID_ERROR 34 +#define COMP_SECONDARY_BANDWIDTH_ERROR 35 +#define COMP_SPLIT_TRANSACTION_ERROR 36 + +static inline const char *xhci_trb_comp_code_string(u8 status) +{ + switch (status) { + case COMP_INVALID: + return "Invalid"; + case COMP_SUCCESS: + return "Success"; + case COMP_DATA_BUFFER_ERROR: + return "Data Buffer Error"; + case COMP_BABBLE_DETECTED_ERROR: + return "Babble Detected"; + case COMP_USB_TRANSACTION_ERROR: + return "USB Transaction Error"; + case COMP_TRB_ERROR: + return "TRB Error"; + case COMP_STALL_ERROR: + return "Stall Error"; + case COMP_RESOURCE_ERROR: + return "Resource Error"; + case COMP_BANDWIDTH_ERROR: + return "Bandwidth Error"; + case COMP_NO_SLOTS_AVAILABLE_ERROR: + return "No Slots Available Error"; + case COMP_INVALID_STREAM_TYPE_ERROR: + return "Invalid Stream Type Error"; + case COMP_SLOT_NOT_ENABLED_ERROR: + return "Slot Not Enabled Error"; + case COMP_ENDPOINT_NOT_ENABLED_ERROR: + return "Endpoint Not Enabled Error"; + case COMP_SHORT_PACKET: + return "Short Packet"; + case COMP_RING_UNDERRUN: + return "Ring Underrun"; + case COMP_RING_OVERRUN: + return "Ring Overrun"; + case COMP_VF_EVENT_RING_FULL_ERROR: + return "VF Event Ring Full Error"; + case COMP_PARAMETER_ERROR: + return "Parameter Error"; + case COMP_BANDWIDTH_OVERRUN_ERROR: + return "Bandwidth Overrun Error"; + case COMP_CONTEXT_STATE_ERROR: + return "Context State Error"; + case COMP_NO_PING_RESPONSE_ERROR: + return "No Ping Response Error"; + case COMP_EVENT_RING_FULL_ERROR: + return "Event Ring Full Error"; + case COMP_INCOMPATIBLE_DEVICE_ERROR: + return "Incompatible Device Error"; + case COMP_MISSED_SERVICE_ERROR: + return "Missed Service Error"; + case COMP_COMMAND_RING_STOPPED: + return "Command Ring Stopped"; + case COMP_COMMAND_ABORTED: + return "Command Aborted"; + case COMP_STOPPED: + return "Stopped"; + case COMP_STOPPED_LENGTH_INVALID: + return "Stopped - Length Invalid"; + case COMP_STOPPED_SHORT_PACKET: + return "Stopped - Short Packet"; + case COMP_MAX_EXIT_LATENCY_TOO_LARGE_ERROR: + return "Max Exit Latency Too Large Error"; + case COMP_ISOCH_BUFFER_OVERRUN: + return "Isoch Buffer Overrun"; + case COMP_EVENT_LOST_ERROR: + return "Event Lost Error"; + case COMP_UNDEFINED_ERROR: + return "Undefined Error"; + case COMP_INVALID_STREAM_ID_ERROR: + return "Invalid Stream ID Error"; + case COMP_SECONDARY_BANDWIDTH_ERROR: + return "Secondary Bandwidth Error"; + case COMP_SPLIT_TRANSACTION_ERROR: + return "Split Transaction Error"; + default: + return "Unknown!!"; + } +} struct xhci_link_trb { /* 64-bit segment pointer*/ @@ -1154,6 +1199,27 @@ struct xhci_event_cmd { /* Address device - disable SetAddress */ #define TRB_BSR (1<<9) + +/* Configure Endpoint - Deconfigure */ +#define TRB_DC (1<<9) + +/* Stop Ring - Transfer State Preserve */ +#define TRB_TSP (1<<9) + +/* Force Event */ +#define TRB_TO_VF_INTR_TARGET(p) (((p) & (0x3ff << 22)) >> 22) +#define TRB_TO_VF_ID(p) (((p) & (0xff << 16)) >> 16) + +/* Set Latency Tolerance Value */ +#define TRB_TO_BELT(p) (((p) & (0xfff << 16)) >> 16) + +/* Get Port Bandwidth */ +#define TRB_TO_DEV_SPEED(p) (((p) & (0xf << 16)) >> 16) + +/* Force Header */ +#define TRB_TO_PACKET_TYPE(p) ((p) & 0x1f) +#define TRB_TO_ROOTHUB_PORT(p) (((p) & (0xff << 24)) >> 24) + enum xhci_setup_dev { SETUP_CONTEXT_ONLY, SETUP_CONTEXT_ADDRESS, @@ -1177,16 +1243,21 @@ enum xhci_setup_dev { #define STREAM_ID_FOR_TRB(p) ((((p)) & 0xffff) << 16) #define SCT_FOR_TRB(p) (((p) << 1) & 0x7) +/* Link TRB specific fields */ +#define TRB_TC (1<<1) /* Port Status Change Event TRB fields */ /* Port ID - bits 31:24 */ #define GET_PORT_ID(p) (((p) & (0xff << 24)) >> 24) +#define EVENT_DATA (1 << 2) + /* Normal TRB fields */ /* transfer_len bitmasks - bits 0:16 */ #define TRB_LEN(p) ((p) & 0x1ffff) /* TD Size, packets remaining in this TD, bits 21:17 (5 bits, so max 31) */ #define TRB_TD_SIZE(p) (min((p), (u32)31) << 17) +#define GET_TD_SIZE(p) (((p) & 0x3e0000) >> 17) /* xhci 1.1 uses the TD_SIZE field for TBC if Extended TBC is enabled (ETE) */ #define TRB_TD_SIZE_TBC(p) (min((p), (u32)31) << 17) /* Interrupter Target - which MSI-X vector to target the completion event at */ @@ -1314,6 +1385,80 @@ union xhci_trb { /* Get NEC firmware revision. */ #define TRB_NEC_GET_FW 49 +static inline const char *xhci_trb_type_string(u8 type) +{ + switch (type) { + case TRB_NORMAL: + return "Normal"; + case TRB_SETUP: + return "Setup Stage"; + case TRB_DATA: + return "Data Stage"; + case TRB_STATUS: + return "Status Stage"; + case TRB_ISOC: + return "Isoch"; + case TRB_LINK: + return "Link"; + case TRB_EVENT_DATA: + return "Event Data"; + case TRB_TR_NOOP: + return "No-Op"; + case TRB_ENABLE_SLOT: + return "Enable Slot Command"; + case TRB_DISABLE_SLOT: + return "Disable Slot Command"; + case TRB_ADDR_DEV: + return "Address Device Command"; + case TRB_CONFIG_EP: + return "Configure Endpoint Command"; + case TRB_EVAL_CONTEXT: + return "Evaluate Context Command"; + case TRB_RESET_EP: + return "Reset Endpoint Command"; + case TRB_STOP_RING: + return "Stop Ring Command"; + case TRB_SET_DEQ: + return "Set TR Dequeue Pointer Command"; + case TRB_RESET_DEV: + return "Reset Device Command"; + case TRB_FORCE_EVENT: + return "Force Event Command"; + case TRB_NEG_BANDWIDTH: + return "Negotiate Bandwidth Command"; + case TRB_SET_LT: + return "Set Latency Tolerance Value Command"; + case TRB_GET_BW: + return "Get Port Bandwidth Command"; + case TRB_FORCE_HEADER: + return "Force Header Command"; + case TRB_CMD_NOOP: + return "No-Op Command"; + case TRB_TRANSFER: + return "Transfer Event"; + case TRB_COMPLETION: + return "Command Completion Event"; + case TRB_PORT_STATUS: + return "Port Status Change Event"; + case TRB_BANDWIDTH_EVENT: + return "Bandwidth Request Event"; + case TRB_DOORBELL: + return "Doorbell Event"; + case TRB_HC_EVENT: + return "Host Controller Event"; + case TRB_DEV_NOTE: + return "Device Notification Event"; + case TRB_MFINDEX_WRAP: + return "MFINDEX Wrap Event"; + case TRB_NEC_CMD_COMP: + return "NEC Command Completion Event"; + case TRB_NEC_GET_FW: + return "NET Get Firmware Revision Command"; + default: + return "UNKNOWN"; + } +} + #define TRB_TYPE_LINK(x) (((x) & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK)) /* Above, but for __le32 types -- can avoid work by swapping constants: */ #define TRB_TYPE_LINK_LE32(x) (((x) & cpu_to_le32(TRB_TYPE_BITMASK)) == \ @@ -1390,6 +1535,28 @@ enum xhci_ring_type { TYPE_EVENT, }; +static inline const char *xhci_ring_type_string(enum xhci_ring_type type) +{ + switch (type) { + case TYPE_CTRL: + return "CTRL"; + case TYPE_ISOC: + return "ISOC"; + case TYPE_BULK: + return "BULK"; + case TYPE_INTR: + return "INTR"; + case TYPE_STREAM: + return "STREAM"; + case TYPE_COMMAND: + return "CMD"; + case TYPE_EVENT: + return "EVENT"; + } + + return "UNKNOWN"; +} + struct xhci_ring { struct xhci_segment *first_seg; struct xhci_segment *last_seg; @@ -1441,9 +1608,9 @@ struct xhci_scratchpad { }; struct urb_priv { - int length; - int td_cnt; - struct xhci_td *td[0]; + int num_tds; + int num_tds_done; + struct xhci_td td[0]; }; /* @@ -1549,7 +1716,6 @@ struct xhci_hcd { u8 max_ports; u8 isoc_threshold; int event_ring_max; - int addr_64; /* 4KB min, 128MB max */ int page_size; /* Valid values are 12 to 20, inclusive */ @@ -1650,6 +1816,9 @@ struct xhci_hcd { #define XHCI_SSIC_PORT_UNUSED (1 << 22) #define XHCI_NO_64BIT_SUPPORT (1 << 23) #define XHCI_MISSING_CAS (1 << 24) +/* For controller with a broken Port Disable implementation */ +#define XHCI_BROKEN_PORT_PED (1 << 25) + unsigned int num_active_eps; unsigned int limit_active_eps; /* There are two roothubs to keep track of bus suspend info for */ @@ -1984,4 +2153,211 @@ static inline struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci, urb->stream_id); } +static inline const char *xhci_decode_trb(u32 field0, u32 field1, u32 field2, + u32 field3) +{ + static char str[256]; + int type = TRB_FIELD_TO_TYPE(field3); + + switch (type) { + case TRB_LINK: + sprintf(str, + "TRB %08x%08x status '%s' len %d slot %d ep %d type '%s' flags %c:%c", + field1, field0, + xhci_trb_comp_code_string(GET_COMP_CODE(field2)), + EVENT_TRB_LEN(field2), TRB_TO_SLOT_ID(field3), + /* Macro decrements 1, maybe it shouldn't?!? */ + TRB_TO_EP_INDEX(field3) + 1, + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + field3 & EVENT_DATA ? 'E' : 'e', + field3 & TRB_CYCLE ? 'C' : 'c'); + break; + case TRB_TRANSFER: + case TRB_COMPLETION: + case TRB_PORT_STATUS: + case TRB_BANDWIDTH_EVENT: + case TRB_DOORBELL: + case TRB_HC_EVENT: + case TRB_DEV_NOTE: + case TRB_MFINDEX_WRAP: + sprintf(str, + "TRB %08x%08x status '%s' len %d slot %d ep %d type '%s' flags %c:%c", + field1, field0, + xhci_trb_comp_code_string(GET_COMP_CODE(field2)), + EVENT_TRB_LEN(field2), TRB_TO_SLOT_ID(field3), + /* Macro decrements 1, maybe it shouldn't?!? */ + TRB_TO_EP_INDEX(field3) + 1, + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + field3 & EVENT_DATA ? 'E' : 'e', + field3 & TRB_CYCLE ? 'C' : 'c'); + + break; + case TRB_SETUP: + sprintf(str, + "bRequestType %02x bRequest %02x wValue %02x%02x wIndex %02x%02x wLength %d length %d TD size %d intr %d type '%s' flags %c:%c:%c:%c:%c:%c:%c:%c", + field0 & 0xff, + (field0 & 0xff00) >> 8, + (field0 & 0xff000000) >> 24, + (field0 & 0xff0000) >> 16, + (field1 & 0xff00) >> 8, + field1 & 0xff, + (field1 & 0xff000000) >> 16 | + (field1 & 0xff0000) >> 16, + TRB_LEN(field2), GET_TD_SIZE(field2), + GET_INTR_TARGET(field2), + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + field3 & TRB_BEI ? 'B' : 'b', + field3 & TRB_IDT ? 'I' : 'i', + field3 & TRB_IOC ? 'I' : 'i', + field3 & TRB_CHAIN ? 'C' : 'c', + field3 & TRB_NO_SNOOP ? 'S' : 's', + field3 & TRB_ISP ? 'I' : 'i', + field3 & TRB_ENT ? 'E' : 'e', + field3 & TRB_CYCLE ? 'C' : 'c'); + break; + case TRB_NORMAL: + case TRB_DATA: + case TRB_STATUS: + case TRB_ISOC: + case TRB_EVENT_DATA: + case TRB_TR_NOOP: + sprintf(str, + "Buffer %08x%08x length %d TD size %d intr %d type '%s' flags %c:%c:%c:%c:%c:%c:%c:%c", + field1, field0, TRB_LEN(field2), GET_TD_SIZE(field2), + GET_INTR_TARGET(field2), + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + field3 & TRB_BEI ? 'B' : 'b', + field3 & TRB_IDT ? 'I' : 'i', + field3 & TRB_IOC ? 'I' : 'i', + field3 & TRB_CHAIN ? 'C' : 'c', + field3 & TRB_NO_SNOOP ? 'S' : 's', + field3 & TRB_ISP ? 'I' : 'i', + field3 & TRB_ENT ? 'E' : 'e', + field3 & TRB_CYCLE ? 'C' : 'c'); + break; + + case TRB_CMD_NOOP: + case TRB_ENABLE_SLOT: + sprintf(str, + "%s: flags %c", + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + field3 & TRB_CYCLE ? 'C' : 'c'); + break; + case TRB_DISABLE_SLOT: + case TRB_NEG_BANDWIDTH: + sprintf(str, + "%s: slot %d flags %c", + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + TRB_TO_SLOT_ID(field3), + field3 & TRB_CYCLE ? 'C' : 'c'); + break; + case TRB_ADDR_DEV: + sprintf(str, + "%s: ctx %08x%08x slot %d flags %c:%c", + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + field1, field0, + TRB_TO_SLOT_ID(field3), + field3 & TRB_BSR ? 'B' : 'b', + field3 & TRB_CYCLE ? 'C' : 'c'); + break; + case TRB_CONFIG_EP: + sprintf(str, + "%s: ctx %08x%08x slot %d flags %c:%c", + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + field1, field0, + TRB_TO_SLOT_ID(field3), + field3 & TRB_DC ? 'D' : 'd', + field3 & TRB_CYCLE ? 'C' : 'c'); + break; + case TRB_EVAL_CONTEXT: + sprintf(str, + "%s: ctx %08x%08x slot %d flags %c", + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + field1, field0, + TRB_TO_SLOT_ID(field3), + field3 & TRB_CYCLE ? 'C' : 'c'); + break; + case TRB_RESET_EP: + sprintf(str, + "%s: ctx %08x%08x slot %d ep %d flags %c", + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + field1, field0, + TRB_TO_SLOT_ID(field3), + /* Macro decrements 1, maybe it shouldn't?!? */ + TRB_TO_EP_INDEX(field3) + 1, + field3 & TRB_CYCLE ? 'C' : 'c'); + break; + case TRB_STOP_RING: + sprintf(str, + "%s: slot %d sp %d ep %d flags %c", + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + TRB_TO_SLOT_ID(field3), + TRB_TO_SUSPEND_PORT(field3), + /* Macro decrements 1, maybe it shouldn't?!? */ + TRB_TO_EP_INDEX(field3) + 1, + field3 & TRB_CYCLE ? 'C' : 'c'); + break; + case TRB_SET_DEQ: + sprintf(str, + "%s: deq %08x%08x stream %d slot %d ep %d flags %c", + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + field1, field0, + TRB_TO_STREAM_ID(field2), + TRB_TO_SLOT_ID(field3), + /* Macro decrements 1, maybe it shouldn't?!? */ + TRB_TO_EP_INDEX(field3) + 1, + field3 & TRB_CYCLE ? 'C' : 'c'); + break; + case TRB_RESET_DEV: + sprintf(str, + "%s: slot %d flags %c", + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + TRB_TO_SLOT_ID(field3), + field3 & TRB_CYCLE ? 'C' : 'c'); + break; + case TRB_FORCE_EVENT: + sprintf(str, + "%s: event %08x%08x vf intr %d vf id %d flags %c", + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + field1, field0, + TRB_TO_VF_INTR_TARGET(field2), + TRB_TO_VF_ID(field3), + field3 & TRB_CYCLE ? 'C' : 'c'); + break; + case TRB_SET_LT: + sprintf(str, + "%s: belt %d flags %c", + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + TRB_TO_BELT(field3), + field3 & TRB_CYCLE ? 'C' : 'c'); + break; + case TRB_GET_BW: + sprintf(str, + "%s: ctx %08x%08x slot %d speed %d flags %c", + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + field1, field0, + TRB_TO_SLOT_ID(field3), + TRB_TO_DEV_SPEED(field3), + field3 & TRB_CYCLE ? 'C' : 'c'); + break; + case TRB_FORCE_HEADER: + sprintf(str, + "%s: info %08x%08x%08x pkt type %d roothub port %d flags %c", + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + field2, field1, field0 & 0xffffffe0, + TRB_TO_PACKET_TYPE(field0), + TRB_TO_ROOTHUB_PORT(field3), + field3 & TRB_CYCLE ? 'C' : 'c'); + break; + default: + sprintf(str, + "type '%s' -> raw %08x %08x %08x %08x", + xhci_trb_type_string(TRB_FIELD_TO_TYPE(field3)), + field0, field1, field2, field3); + } + + return str; +} + + #endif /* __LINUX_XHCI_HCD_H */ diff --git a/drivers/usb/isp1760/isp1760-udc.c b/drivers/usb/isp1760/isp1760-udc.c index 1c3d0fd658fa..69400f3da886 100644 --- a/drivers/usb/isp1760/isp1760-udc.c +++ b/drivers/usb/isp1760/isp1760-udc.c @@ -1250,7 +1250,7 @@ static int isp1760_udc_stop(struct usb_gadget *gadget) return 0; } -static struct usb_gadget_ops isp1760_udc_ops = { +static const struct usb_gadget_ops isp1760_udc_ops = { .get_frame = isp1760_udc_get_frame, .wakeup = isp1760_udc_wakeup, .set_selfpowered = isp1760_udc_set_selfpowered, diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index 47b357760afc..1d1d70d62a19 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -233,6 +233,15 @@ config USB_EZUSB_FX2 Say Y here if you need EZUSB device support. (Cypress FX/FX2/FX2LP microcontrollers) +config USB_HUB_USB251XB + tristate "USB251XB Hub Controller Configuration Driver" + depends on I2C + help + This option enables support for configuration via SMBus of the + Microchip USB251xB/xBi USB 2.0 Hub Controller series. + Configuration parameters may be set in devicetree or platform data. + Say Y or M here if you need to configure such a device via SMBus. + config USB_HSIC_USB3503 tristate "USB3503 HSIC to USB20 Driver" depends on I2C diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 3d1992750da4..f6ac6c99a6e6 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_USB_TRANCEVIBRATOR) += trancevibrator.o obj-$(CONFIG_USB_USS720) += uss720.o obj-$(CONFIG_USB_SEVSEG) += usbsevseg.o obj-$(CONFIG_USB_YUREX) += yurex.o +obj-$(CONFIG_USB_HUB_USB251XB) += usb251xb.o obj-$(CONFIG_USB_HSIC_USB3503) += usb3503.o obj-$(CONFIG_USB_HSIC_USB4604) += usb4604.o obj-$(CONFIG_USB_CHAOSKEY) += chaoskey.o diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index 564268fca07a..a540e4f206c4 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -389,10 +389,6 @@ static ssize_t adu_read(struct file *file, __user char *buffer, size_t count, dev->secondary_head += (amount - i); bytes_read += (amount - i); bytes_to_read -= (amount - i); - if (i) { - retval = bytes_read ? bytes_read : -EFAULT; - goto exit; - } } else { /* we check the primary buffer */ spin_lock_irqsave (&dev->buflock, flags); diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index 05bd39d62568..440d7fef58cc 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -1831,16 +1831,10 @@ static int sisusb_set_default_mode(struct sisusb_usb_data *sisusb, SETIREGANDOR(SISCR, 0x09, 0x5f, ((crtcdata[16] & 0x01) << 5)); SETIREG(SISCR, 0x14, 0x4f); du = (modex / 16) * (bpp * 2); /* offset/pitch */ - if (modex % 16) - du += bpp; - SETIREGANDOR(SISSR, 0x0e, 0xf0, ((du >> 8) & 0x0f)); SETIREG(SISCR, 0x13, (du & 0xff)); du <<= 5; tmp8 = du >> 8; - if (du & 0xff) - tmp8++; - SETIREG(SISSR, 0x10, tmp8); SETIREG(SISSR, 0x31, 0x00); /* VCLK */ SETIREG(SISSR, 0x2b, 0x1b); diff --git a/drivers/usb/misc/usb251xb.c b/drivers/usb/misc/usb251xb.c new file mode 100644 index 000000000000..4e18600dc9b4 --- /dev/null +++ b/drivers/usb/misc/usb251xb.c @@ -0,0 +1,605 @@ +/* + * Driver for Microchip USB251xB USB 2.0 Hi-Speed Hub Controller + * Configuration via SMBus. + * + * Copyright (c) 2017 SKIDATA AG + * + * This work is based on the USB3503 driver by Dongjin Kim and + * a not-accepted patch by Fabien Lahoudere, see: + * https://patchwork.kernel.org/patch/9257715/ + * + * 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/gpio.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/nls.h> +#include <linux/of_device.h> +#include <linux/of_gpio.h> +#include <linux/slab.h> + +/* Internal Register Set Addresses & Default Values acc. to DS00001692C */ +#define USB251XB_ADDR_VENDOR_ID_LSB 0x00 +#define USB251XB_ADDR_VENDOR_ID_MSB 0x01 +#define USB251XB_DEF_VENDOR_ID 0x0424 + +#define USB251XB_ADDR_PRODUCT_ID_LSB 0x02 +#define USB251XB_ADDR_PRODUCT_ID_MSB 0x03 +#define USB251XB_DEF_PRODUCT_ID_12 0x2512 /* USB2512B/12Bi */ +#define USB251XB_DEF_PRODUCT_ID_13 0x2513 /* USB2513B/13Bi */ +#define USB251XB_DEF_PRODUCT_ID_14 0x2514 /* USB2514B/14Bi */ + +#define USB251XB_ADDR_DEVICE_ID_LSB 0x04 +#define USB251XB_ADDR_DEVICE_ID_MSB 0x05 +#define USB251XB_DEF_DEVICE_ID 0x0BB3 + +#define USB251XB_ADDR_CONFIG_DATA_1 0x06 +#define USB251XB_DEF_CONFIG_DATA_1 0x9B +#define USB251XB_ADDR_CONFIG_DATA_2 0x07 +#define USB251XB_DEF_CONFIG_DATA_2 0x20 +#define USB251XB_ADDR_CONFIG_DATA_3 0x08 +#define USB251XB_DEF_CONFIG_DATA_3 0x02 + +#define USB251XB_ADDR_NON_REMOVABLE_DEVICES 0x09 +#define USB251XB_DEF_NON_REMOVABLE_DEVICES 0x00 + +#define USB251XB_ADDR_PORT_DISABLE_SELF 0x0A +#define USB251XB_DEF_PORT_DISABLE_SELF 0x00 +#define USB251XB_ADDR_PORT_DISABLE_BUS 0x0B +#define USB251XB_DEF_PORT_DISABLE_BUS 0x00 + +#define USB251XB_ADDR_MAX_POWER_SELF 0x0C +#define USB251XB_DEF_MAX_POWER_SELF 0x01 +#define USB251XB_ADDR_MAX_POWER_BUS 0x0D +#define USB251XB_DEF_MAX_POWER_BUS 0x32 + +#define USB251XB_ADDR_MAX_CURRENT_SELF 0x0E +#define USB251XB_DEF_MAX_CURRENT_SELF 0x01 +#define USB251XB_ADDR_MAX_CURRENT_BUS 0x0F +#define USB251XB_DEF_MAX_CURRENT_BUS 0x32 + +#define USB251XB_ADDR_POWER_ON_TIME 0x10 +#define USB251XB_DEF_POWER_ON_TIME 0x32 + +#define USB251XB_ADDR_LANGUAGE_ID_HIGH 0x11 +#define USB251XB_ADDR_LANGUAGE_ID_LOW 0x12 +#define USB251XB_DEF_LANGUAGE_ID 0x0000 + +#define USB251XB_STRING_BUFSIZE 62 +#define USB251XB_ADDR_MANUFACTURER_STRING_LEN 0x13 +#define USB251XB_ADDR_MANUFACTURER_STRING 0x16 +#define USB251XB_DEF_MANUFACTURER_STRING "Microchip" + +#define USB251XB_ADDR_PRODUCT_STRING_LEN 0x14 +#define USB251XB_ADDR_PRODUCT_STRING 0x54 +#define USB251XB_DEF_PRODUCT_STRING "USB251xB/xBi" + +#define USB251XB_ADDR_SERIAL_STRING_LEN 0x15 +#define USB251XB_ADDR_SERIAL_STRING 0x92 +#define USB251XB_DEF_SERIAL_STRING "" + +#define USB251XB_ADDR_BATTERY_CHARGING_ENABLE 0xD0 +#define USB251XB_DEF_BATTERY_CHARGING_ENABLE 0x00 + +#define USB251XB_ADDR_BOOST_UP 0xF6 +#define USB251XB_DEF_BOOST_UP 0x00 +#define USB251XB_ADDR_BOOST_X 0xF8 +#define USB251XB_DEF_BOOST_X 0x00 + +#define USB251XB_ADDR_PORT_SWAP 0xFA +#define USB251XB_DEF_PORT_SWAP 0x00 + +#define USB251XB_ADDR_PORT_MAP_12 0xFB +#define USB251XB_DEF_PORT_MAP_12 0x00 +#define USB251XB_ADDR_PORT_MAP_34 0xFC +#define USB251XB_DEF_PORT_MAP_34 0x00 /* USB2513B/i & USB2514B/i only */ + +#define USB251XB_ADDR_STATUS_COMMAND 0xFF +#define USB251XB_STATUS_COMMAND_SMBUS_DOWN 0x04 +#define USB251XB_STATUS_COMMAND_RESET 0x02 +#define USB251XB_STATUS_COMMAND_ATTACH 0x01 + +#define USB251XB_I2C_REG_SZ 0x100 +#define USB251XB_I2C_WRITE_SZ 0x10 + +#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; + struct i2c_client *i2c; + u8 skip_config; + int gpio_reset; + u16 vendor_id; + u16 product_id; + u16 device_id; + u8 conf_data1; + u8 conf_data2; + u8 conf_data3; + u8 non_rem_dev; + u8 port_disable_sp; + u8 port_disable_bp; + u8 max_power_sp; + u8 max_power_bp; + u8 max_current_sp; + u8 max_current_bp; + u8 power_on_time; + u16 lang_id; + u8 manufacturer_len; + u8 product_len; + u8 serial_len; + char manufacturer[USB251XB_STRING_BUFSIZE]; + char product[USB251XB_STRING_BUFSIZE]; + char serial[USB251XB_STRING_BUFSIZE]; + u8 bat_charge_en; + u8 boost_up; + u8 boost_x; + u8 port_swap; + u8 port_map12; + u8 port_map34; + u8 status; +}; + +struct usb251xb_data { + u16 product_id; + char product_str[USB251XB_STRING_BUFSIZE / 2]; /* ASCII string */ +}; + +static const struct usb251xb_data usb2512b_data = { + .product_id = 0x2512, + .product_str = "USB2512B", +}; + +static const struct usb251xb_data usb2512bi_data = { + .product_id = 0x2512, + .product_str = "USB2512Bi", +}; + +static const struct usb251xb_data usb2513b_data = { + .product_id = 0x2513, + .product_str = "USB2513B", +}; + +static const struct usb251xb_data usb2513bi_data = { + .product_id = 0x2513, + .product_str = "USB2513Bi", +}; + +static const struct usb251xb_data usb2514b_data = { + .product_id = 0x2514, + .product_str = "USB2514B", +}; + +static const struct usb251xb_data usb2514bi_data = { + .product_id = 0x2514, + .product_str = "USB2514Bi", +}; + +static void usb251xb_reset(struct usb251xb *hub, int state) +{ + if (!gpio_is_valid(hub->gpio_reset)) + return; + + gpio_set_value_cansleep(hub->gpio_reset, state); + + /* wait for hub recovery/stabilization */ + if (state) + usleep_range(500, 750); /* >=500us at power on */ + else + usleep_range(1, 10); /* >=1us at power down */ +} + +static int usb251xb_connect(struct usb251xb *hub) +{ + struct device *dev = hub->dev; + int err, i; + char i2c_wb[USB251XB_I2C_REG_SZ]; + + memset(i2c_wb, 0, USB251XB_I2C_REG_SZ); + + if (hub->skip_config) { + dev_info(dev, "Skip hub configuration, only attach.\n"); + i2c_wb[0] = 0x01; + i2c_wb[1] = USB251XB_STATUS_COMMAND_ATTACH; + + usb251xb_reset(hub, 1); + + err = i2c_smbus_write_i2c_block_data(hub->i2c, + USB251XB_ADDR_STATUS_COMMAND, 2, i2c_wb); + if (err) { + dev_err(dev, "attaching hub failed: %d\n", err); + return err; + } + return 0; + } + + i2c_wb[USB251XB_ADDR_VENDOR_ID_MSB] = (hub->vendor_id >> 8) & 0xFF; + i2c_wb[USB251XB_ADDR_VENDOR_ID_LSB] = hub->vendor_id & 0xFF; + i2c_wb[USB251XB_ADDR_PRODUCT_ID_MSB] = (hub->product_id >> 8) & 0xFF; + i2c_wb[USB251XB_ADDR_PRODUCT_ID_LSB] = hub->product_id & 0xFF; + i2c_wb[USB251XB_ADDR_DEVICE_ID_MSB] = (hub->device_id >> 8) & 0xFF; + i2c_wb[USB251XB_ADDR_DEVICE_ID_LSB] = hub->device_id & 0xFF; + i2c_wb[USB251XB_ADDR_CONFIG_DATA_1] = hub->conf_data1; + i2c_wb[USB251XB_ADDR_CONFIG_DATA_2] = hub->conf_data2; + i2c_wb[USB251XB_ADDR_CONFIG_DATA_3] = hub->conf_data3; + i2c_wb[USB251XB_ADDR_NON_REMOVABLE_DEVICES] = hub->non_rem_dev; + i2c_wb[USB251XB_ADDR_PORT_DISABLE_SELF] = hub->port_disable_sp; + i2c_wb[USB251XB_ADDR_PORT_DISABLE_BUS] = hub->port_disable_bp; + i2c_wb[USB251XB_ADDR_MAX_POWER_SELF] = hub->max_power_sp; + i2c_wb[USB251XB_ADDR_MAX_POWER_BUS] = hub->max_power_bp; + i2c_wb[USB251XB_ADDR_MAX_CURRENT_SELF] = hub->max_current_sp; + i2c_wb[USB251XB_ADDR_MAX_CURRENT_BUS] = hub->max_current_bp; + i2c_wb[USB251XB_ADDR_POWER_ON_TIME] = hub->power_on_time; + i2c_wb[USB251XB_ADDR_LANGUAGE_ID_HIGH] = (hub->lang_id >> 8) & 0xFF; + i2c_wb[USB251XB_ADDR_LANGUAGE_ID_LOW] = hub->lang_id & 0xFF; + i2c_wb[USB251XB_ADDR_MANUFACTURER_STRING_LEN] = hub->manufacturer_len; + i2c_wb[USB251XB_ADDR_PRODUCT_STRING_LEN] = hub->product_len; + i2c_wb[USB251XB_ADDR_SERIAL_STRING_LEN] = hub->serial_len; + memcpy(&i2c_wb[USB251XB_ADDR_MANUFACTURER_STRING], hub->manufacturer, + USB251XB_STRING_BUFSIZE); + memcpy(&i2c_wb[USB251XB_ADDR_SERIAL_STRING], hub->serial, + USB251XB_STRING_BUFSIZE); + memcpy(&i2c_wb[USB251XB_ADDR_PRODUCT_STRING], hub->product, + USB251XB_STRING_BUFSIZE); + i2c_wb[USB251XB_ADDR_BATTERY_CHARGING_ENABLE] = hub->bat_charge_en; + i2c_wb[USB251XB_ADDR_BOOST_UP] = hub->boost_up; + i2c_wb[USB251XB_ADDR_BOOST_X] = hub->boost_x; + i2c_wb[USB251XB_ADDR_PORT_SWAP] = hub->port_swap; + i2c_wb[USB251XB_ADDR_PORT_MAP_12] = hub->port_map12; + i2c_wb[USB251XB_ADDR_PORT_MAP_34] = hub->port_map34; + i2c_wb[USB251XB_ADDR_STATUS_COMMAND] = USB251XB_STATUS_COMMAND_ATTACH; + + usb251xb_reset(hub, 1); + + /* write registers */ + for (i = 0; i < (USB251XB_I2C_REG_SZ / USB251XB_I2C_WRITE_SZ); i++) { + int offset = i * USB251XB_I2C_WRITE_SZ; + char wbuf[USB251XB_I2C_WRITE_SZ + 1]; + + /* The first data byte transferred tells the hub how many data + * bytes will follow (byte count). + */ + wbuf[0] = USB251XB_I2C_WRITE_SZ; + memcpy(&wbuf[1], &i2c_wb[offset], USB251XB_I2C_WRITE_SZ); + + dev_dbg(dev, "writing %d byte block %d to 0x%02X\n", + USB251XB_I2C_WRITE_SZ, i, offset); + + err = i2c_smbus_write_i2c_block_data(hub->i2c, offset, + USB251XB_I2C_WRITE_SZ + 1, + wbuf); + if (err) + goto out_err; + } + + dev_info(dev, "Hub configuration was successful.\n"); + return 0; + +out_err: + dev_err(dev, "configuring block %d failed: %d\n", i, err); + return err; +} + +#ifdef CONFIG_OF +static int usb251xb_get_ofdata(struct usb251xb *hub, + struct usb251xb_data *data) +{ + struct device *dev = hub->dev; + struct device_node *np = dev->of_node; + int len, err, i; + u32 *property_u32 = NULL; + const u32 *cproperty_u32; + const char *cproperty_char; + char str[USB251XB_STRING_BUFSIZE / 2]; + + if (!np) { + dev_err(dev, "failed to get ofdata\n"); + return -ENODEV; + } + + if (of_get_property(np, "skip-config", NULL)) + hub->skip_config = 1; + else + hub->skip_config = 0; + + hub->gpio_reset = of_get_named_gpio(np, "reset-gpios", 0); + if (hub->gpio_reset == -EPROBE_DEFER) + return -EPROBE_DEFER; + if (gpio_is_valid(hub->gpio_reset)) { + err = devm_gpio_request_one(dev, hub->gpio_reset, + GPIOF_OUT_INIT_LOW, + "usb251xb reset"); + if (err) { + dev_err(dev, + "unable to request GPIO %d as reset pin (%d)\n", + hub->gpio_reset, err); + return err; + } + } + + if (of_property_read_u16_array(np, "vendor-id", &hub->vendor_id, 1)) + hub->vendor_id = USB251XB_DEF_VENDOR_ID; + + if (of_property_read_u16_array(np, "product-id", + &hub->product_id, 1)) + hub->product_id = data->product_id; + + if (of_property_read_u16_array(np, "device-id", &hub->device_id, 1)) + hub->device_id = USB251XB_DEF_DEVICE_ID; + + hub->conf_data1 = USB251XB_DEF_CONFIG_DATA_1; + if (of_get_property(np, "self-powered", NULL)) { + hub->conf_data1 |= BIT(7); + + /* Configure Over-Current sens when self-powered */ + hub->conf_data1 &= ~BIT(2); + if (of_get_property(np, "ganged-sensing", NULL)) + hub->conf_data1 &= ~BIT(1); + else if (of_get_property(np, "individual-sensing", NULL)) + hub->conf_data1 |= BIT(1); + } else if (of_get_property(np, "bus-powered", NULL)) { + hub->conf_data1 &= ~BIT(7); + + /* Disable Over-Current sense when bus-powered */ + hub->conf_data1 |= BIT(2); + } + + if (of_get_property(np, "disable-hi-speed", NULL)) + hub->conf_data1 |= BIT(5); + + if (of_get_property(np, "multi-tt", NULL)) + hub->conf_data1 |= BIT(4); + else if (of_get_property(np, "single-tt", NULL)) + hub->conf_data1 &= ~BIT(4); + + if (of_get_property(np, "disable-eop", NULL)) + hub->conf_data1 |= BIT(3); + + if (of_get_property(np, "individual-port-switching", NULL)) + hub->conf_data1 |= BIT(0); + else if (of_get_property(np, "ganged-port-switching", NULL)) + hub->conf_data1 &= ~BIT(0); + + hub->conf_data2 = USB251XB_DEF_CONFIG_DATA_2; + if (of_get_property(np, "dynamic-power-switching", NULL)) + hub->conf_data2 |= BIT(7); + + if (of_get_property(np, "oc-delay-100us", NULL)) { + hub->conf_data2 &= ~BIT(5); + hub->conf_data2 &= ~BIT(4); + } else if (of_get_property(np, "oc-delay-4ms", NULL)) { + hub->conf_data2 &= ~BIT(5); + hub->conf_data2 |= BIT(4); + } else if (of_get_property(np, "oc-delay-8ms", NULL)) { + hub->conf_data2 |= BIT(5); + hub->conf_data2 &= ~BIT(4); + } else if (of_get_property(np, "oc-delay-16ms", NULL)) { + hub->conf_data2 |= BIT(5); + hub->conf_data2 |= BIT(4); + } + + if (of_get_property(np, "compound-device", NULL)) + hub->conf_data2 |= BIT(3); + + hub->conf_data3 = USB251XB_DEF_CONFIG_DATA_3; + if (of_get_property(np, "port-mapping-mode", NULL)) + hub->conf_data3 |= BIT(3); + + if (of_get_property(np, "string-support", NULL)) + hub->conf_data3 |= BIT(0); + + hub->non_rem_dev = USB251XB_DEF_NON_REMOVABLE_DEVICES; + cproperty_u32 = of_get_property(np, "non-removable-ports", &len); + if (cproperty_u32 && (len / sizeof(u32)) > 0) { + for (i = 0; i < len / sizeof(u32); i++) { + u32 port = be32_to_cpu(cproperty_u32[i]); + + if ((port >= 1) && (port <= 4)) + hub->non_rem_dev |= BIT(port); + } + } + + hub->port_disable_sp = USB251XB_DEF_PORT_DISABLE_SELF; + cproperty_u32 = of_get_property(np, "sp-disabled-ports", &len); + if (cproperty_u32 && (len / sizeof(u32)) > 0) { + for (i = 0; i < len / sizeof(u32); i++) { + u32 port = be32_to_cpu(cproperty_u32[i]); + + if ((port >= 1) && (port <= 4)) + hub->port_disable_sp |= BIT(port); + } + } + + hub->port_disable_bp = USB251XB_DEF_PORT_DISABLE_BUS; + cproperty_u32 = of_get_property(np, "bp-disabled-ports", &len); + if (cproperty_u32 && (len / sizeof(u32)) > 0) { + for (i = 0; i < len / sizeof(u32); i++) { + u32 port = be32_to_cpu(cproperty_u32[i]); + + if ((port >= 1) && (port <= 4)) + hub->port_disable_bp |= BIT(port); + } + } + + hub->max_power_sp = USB251XB_DEF_MAX_POWER_SELF; + if (!of_property_read_u32(np, "max-sp-power", property_u32)) + hub->max_power_sp = min_t(u8, be32_to_cpu(*property_u32) / 2, + 250); + + hub->max_power_bp = USB251XB_DEF_MAX_POWER_BUS; + if (!of_property_read_u32(np, "max-bp-power", property_u32)) + hub->max_power_bp = min_t(u8, be32_to_cpu(*property_u32) / 2, + 250); + + hub->max_current_sp = USB251XB_DEF_MAX_CURRENT_SELF; + if (!of_property_read_u32(np, "max-sp-current", property_u32)) + hub->max_current_sp = min_t(u8, be32_to_cpu(*property_u32) / 2, + 250); + + hub->max_current_bp = USB251XB_DEF_MAX_CURRENT_BUS; + if (!of_property_read_u32(np, "max-bp-current", property_u32)) + hub->max_current_bp = min_t(u8, be32_to_cpu(*property_u32) / 2, + 250); + + hub->power_on_time = USB251XB_DEF_POWER_ON_TIME; + if (!of_property_read_u32(np, "power-on-time", property_u32)) + hub->power_on_time = min_t(u8, be32_to_cpu(*property_u32) / 2, + 255); + + if (of_property_read_u16_array(np, "language-id", &hub->lang_id, 1)) + hub->lang_id = USB251XB_DEF_LANGUAGE_ID; + + cproperty_char = of_get_property(np, "manufacturer", NULL); + strlcpy(str, cproperty_char ? : USB251XB_DEF_MANUFACTURER_STRING, + sizeof(str)); + hub->manufacturer_len = strlen(str) & 0xFF; + memset(hub->manufacturer, 0, USB251XB_STRING_BUFSIZE); + len = min_t(size_t, USB251XB_STRING_BUFSIZE / 2, strlen(str)); + len = utf8s_to_utf16s(str, len, UTF16_LITTLE_ENDIAN, + (wchar_t *)hub->manufacturer, + USB251XB_STRING_BUFSIZE); + + cproperty_char = of_get_property(np, "product", NULL); + strlcpy(str, cproperty_char ? : data->product_str, sizeof(str)); + hub->product_len = strlen(str) & 0xFF; + memset(hub->product, 0, USB251XB_STRING_BUFSIZE); + len = min_t(size_t, USB251XB_STRING_BUFSIZE / 2, strlen(str)); + len = utf8s_to_utf16s(str, len, UTF16_LITTLE_ENDIAN, + (wchar_t *)hub->product, + USB251XB_STRING_BUFSIZE); + + cproperty_char = of_get_property(np, "serial", NULL); + strlcpy(str, cproperty_char ? : USB251XB_DEF_SERIAL_STRING, + sizeof(str)); + hub->serial_len = strlen(str) & 0xFF; + memset(hub->serial, 0, USB251XB_STRING_BUFSIZE); + len = min_t(size_t, USB251XB_STRING_BUFSIZE / 2, strlen(str)); + len = utf8s_to_utf16s(str, len, UTF16_LITTLE_ENDIAN, + (wchar_t *)hub->serial, + USB251XB_STRING_BUFSIZE); + + /* The following parameters are currently not exposed to devicetree, but + * may be as soon as needed. + */ + hub->bat_charge_en = USB251XB_DEF_BATTERY_CHARGING_ENABLE; + hub->boost_up = USB251XB_DEF_BOOST_UP; + hub->boost_x = USB251XB_DEF_BOOST_X; + hub->port_swap = USB251XB_DEF_PORT_SWAP; + hub->port_map12 = USB251XB_DEF_PORT_MAP_12; + hub->port_map34 = USB251XB_DEF_PORT_MAP_34; + + return 0; +} + +static const struct of_device_id usb251xb_of_match[] = { + { + .compatible = "microchip,usb2512b", + .data = &usb2512b_data, + }, { + .compatible = "microchip,usb2512bi", + .data = &usb2512bi_data, + }, { + .compatible = "microchip,usb2513b", + .data = &usb2513b_data, + }, { + .compatible = "microchip,usb2513bi", + .data = &usb2513bi_data, + }, { + .compatible = "microchip,usb2514b", + .data = &usb2514b_data, + }, { + .compatible = "microchip,usb2514bi", + .data = &usb2514bi_data, + }, { + /* sentinel */ + } +}; +MODULE_DEVICE_TABLE(of, usb251xb_of_match); +#else /* CONFIG_OF */ +static int usb251xb_get_ofdata(struct usb251xb *hub, + struct usb251xb_data *data) +{ + return 0; +} +#endif /* CONFIG_OF */ + +static int usb251xb_probe(struct usb251xb *hub) +{ + struct device *dev = hub->dev; + struct device_node *np = dev->of_node; + const struct of_device_id *of_id = of_match_device(usb251xb_of_match, + dev); + int err; + + if (np) { + err = usb251xb_get_ofdata(hub, + (struct usb251xb_data *)of_id->data); + if (err) { + dev_err(dev, "failed to get ofdata: %d\n", err); + return err; + } + } + + err = usb251xb_connect(hub); + if (err) { + dev_err(dev, "Failed to connect hub (%d)\n", err); + return err; + } + + dev_info(dev, "Hub probed successfully\n"); + + return 0; +} + +static int usb251xb_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct usb251xb *hub; + + hub = devm_kzalloc(&i2c->dev, sizeof(struct usb251xb), GFP_KERNEL); + if (!hub) + return -ENOMEM; + + i2c_set_clientdata(i2c, hub); + hub->dev = &i2c->dev; + hub->i2c = i2c; + + return usb251xb_probe(hub); +} + +static const struct i2c_device_id usb251xb_id[] = { + { "usb2512b", 0 }, + { "usb2512bi", 0 }, + { "usb2513b", 0 }, + { "usb2513bi", 0 }, + { "usb2514b", 0 }, + { "usb2514bi", 0 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(i2c, usb251xb_id); + +static struct i2c_driver usb251xb_i2c_driver = { + .driver = { + .name = DRIVER_NAME, + .of_match_table = of_match_ptr(usb251xb_of_match), + }, + .probe = usb251xb_i2c_probe, + .id_table = usb251xb_id, +}; + +module_i2c_driver(usb251xb_i2c_driver); + +MODULE_AUTHOR("Richard Leitner <richard.leitner@skidata.com>"); +MODULE_DESCRIPTION("USB251xB/xBi USB 2.0 Hub Controller Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index 3525626bf086..17c081068257 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -992,7 +992,7 @@ static int ch9_postconfig(struct usbtest_dev *dev) dev_err(&iface->dev, "hs dev qualifier --> %d\n", retval); - return (retval < 0) ? retval : -EDOM; + return retval; } /* usb2.0 but not high-speed capable; fine */ } else if (retval != sizeof(struct usb_qualifier_descriptor)) { diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h index ba9df719f363..aa6fd6a51221 100644 --- a/drivers/usb/mtu3/mtu3.h +++ b/drivers/usb/mtu3/mtu3.h @@ -225,6 +225,7 @@ struct ssusb_mtk { /* common power & clock */ struct regulator *vusb33; struct clk *sys_clk; + struct clk *ref_clk; /* otg */ struct otg_switch_mtk otg_switch; enum usb_dr_mode dr_mode; diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c index 783367805c99..42550c7db3e7 100644 --- a/drivers/usb/mtu3/mtu3_plat.c +++ b/drivers/usb/mtu3/mtu3_plat.c @@ -123,7 +123,13 @@ static int ssusb_rscs_init(struct ssusb_mtk *ssusb) ret = clk_prepare_enable(ssusb->sys_clk); if (ret) { dev_err(ssusb->dev, "failed to enable sys_clk\n"); - goto clk_err; + goto sys_clk_err; + } + + ret = clk_prepare_enable(ssusb->ref_clk); + if (ret) { + dev_err(ssusb->dev, "failed to enable ref_clk\n"); + goto ref_clk_err; } ret = ssusb_phy_init(ssusb); @@ -143,8 +149,10 @@ static int ssusb_rscs_init(struct ssusb_mtk *ssusb) phy_err: ssusb_phy_exit(ssusb); phy_init_err: + clk_disable_unprepare(ssusb->ref_clk); +ref_clk_err: clk_disable_unprepare(ssusb->sys_clk); -clk_err: +sys_clk_err: regulator_disable(ssusb->vusb33); vusb33_err: @@ -154,6 +162,7 @@ vusb33_err: static void ssusb_rscs_exit(struct ssusb_mtk *ssusb) { clk_disable_unprepare(ssusb->sys_clk); + clk_disable_unprepare(ssusb->ref_clk); regulator_disable(ssusb->vusb33); ssusb_phy_power_off(ssusb); ssusb_phy_exit(ssusb); @@ -204,6 +213,31 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb) int i; int ret; + ssusb->vusb33 = devm_regulator_get(&pdev->dev, "vusb33"); + if (IS_ERR(ssusb->vusb33)) { + dev_err(dev, "failed to get vusb33\n"); + return PTR_ERR(ssusb->vusb33); + } + + ssusb->sys_clk = devm_clk_get(dev, "sys_ck"); + if (IS_ERR(ssusb->sys_clk)) { + dev_err(dev, "failed to get sys clock\n"); + return PTR_ERR(ssusb->sys_clk); + } + + /* + * reference clock is usually a "fixed-clock", make it optional + * for backward compatibility and ignore the error if it does + * not exist. + */ + ssusb->ref_clk = devm_clk_get(dev, "ref_ck"); + if (IS_ERR(ssusb->ref_clk)) { + if (PTR_ERR(ssusb->ref_clk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + ssusb->ref_clk = NULL; + } + ssusb->num_phys = of_count_phandle_with_args(node, "phys", "#phy-cells"); if (ssusb->num_phys > 0) { @@ -225,22 +259,8 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb) res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ippc"); ssusb->ippc_base = devm_ioremap_resource(dev, res); - if (IS_ERR(ssusb->ippc_base)) { - dev_err(dev, "failed to map memory for ippc\n"); + if (IS_ERR(ssusb->ippc_base)) return PTR_ERR(ssusb->ippc_base); - } - - ssusb->vusb33 = devm_regulator_get(&pdev->dev, "vusb33"); - if (IS_ERR(ssusb->vusb33)) { - dev_err(dev, "failed to get vusb33\n"); - return PTR_ERR(ssusb->vusb33); - } - - ssusb->sys_clk = devm_clk_get(dev, "sys_ck"); - if (IS_ERR(ssusb->sys_clk)) { - dev_err(dev, "failed to get sys clock\n"); - return PTR_ERR(ssusb->sys_clk); - } ssusb->dr_mode = usb_get_dr_mode(dev); if (ssusb->dr_mode == USB_DR_MODE_UNKNOWN) { @@ -428,6 +448,7 @@ static int __maybe_unused mtu3_suspend(struct device *dev) ssusb_host_disable(ssusb, true); ssusb_phy_power_off(ssusb); clk_disable_unprepare(ssusb->sys_clk); + clk_disable_unprepare(ssusb->ref_clk); ssusb_wakeup_enable(ssusb); return 0; @@ -445,6 +466,7 @@ static int __maybe_unused mtu3_resume(struct device *dev) ssusb_wakeup_disable(ssusb); clk_prepare_enable(ssusb->sys_clk); + clk_prepare_enable(ssusb->ref_clk); ssusb_phy_power_on(ssusb); ssusb_host_enable(ssusb); diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c index 50ca8052bc8e..02fbb4fe3745 100644 --- a/drivers/usb/musb/am35x.c +++ b/drivers/usb/musb/am35x.c @@ -121,7 +121,6 @@ static void am35x_musb_disable(struct musb *musb) musb_writel(reg_base, CORE_INTR_MASK_CLEAR_REG, AM35X_INTR_USB_MASK); musb_writel(reg_base, EP_INTR_MASK_CLEAR_REG, AM35X_TX_INTR_MASK | AM35X_RX_INTR_MASK); - musb_writeb(musb->mregs, MUSB_DEVCTL, 0); musb_writel(reg_base, USB_END_OF_INTR_REG, 0); } diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index 896798071817..4418574a36a1 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -581,8 +581,7 @@ static int bfin_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int bfin_suspend(struct device *dev) +static int __maybe_unused bfin_suspend(struct device *dev) { struct bfin_glue *glue = dev_get_drvdata(dev); struct musb *musb = glue_to_musb(glue); @@ -599,7 +598,7 @@ static int bfin_suspend(struct device *dev) return 0; } -static int bfin_resume(struct device *dev) +static int __maybe_unused bfin_resume(struct device *dev) { struct bfin_glue *glue = dev_get_drvdata(dev); struct musb *musb = glue_to_musb(glue); @@ -608,7 +607,6 @@ static int bfin_resume(struct device *dev) return 0; } -#endif static SIMPLE_DEV_PM_OPS(bfin_pm_ops, bfin_suspend, bfin_resume); diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c index 1ae48e64e975..c4fabe952ca6 100644 --- a/drivers/usb/musb/cppi_dma.c +++ b/drivers/usb/musb/cppi_dma.c @@ -224,7 +224,7 @@ static void cppi_controller_stop(struct cppi *controller) int i; struct musb *musb; - musb = controller->musb; + musb = controller->controller.musb; tibase = controller->tibase; /* DISABLE INDIVIDUAL CHANNEL Interrupts */ @@ -288,7 +288,7 @@ cppi_channel_allocate(struct dma_controller *c, controller = container_of(c, struct cppi, controller); tibase = controller->tibase; - musb = controller->musb; + musb = c->musb; /* ep0 doesn't use DMA; remember cppi indices are 0..N-1 */ index = ep->epnum - 1; @@ -336,7 +336,7 @@ static void cppi_channel_release(struct dma_channel *channel) c = container_of(channel, struct cppi_channel, channel); tibase = c->controller->tibase; if (!c->hw_ep) - musb_dbg(c->controller->musb, + musb_dbg(c->controller->controller.musb, "releasing idle DMA channel %p", c); else if (!c->transmit) core_rxirq_enable(tibase, c->index + 1); @@ -355,7 +355,7 @@ cppi_dump_rx(int level, struct cppi_channel *c, const char *tag) musb_ep_select(base, c->index + 1); - musb_dbg(c->controller->musb, + musb_dbg(c->controller->controller.musb, "RX DMA%d%s: %d left, csr %04x, " "%08x H%08x S%08x C%08x, " "B%08x L%08x %08x .. %08x", @@ -385,7 +385,7 @@ cppi_dump_tx(int level, struct cppi_channel *c, const char *tag) musb_ep_select(base, c->index + 1); - musb_dbg(c->controller->musb, + musb_dbg(c->controller->controller.musb, "TX DMA%d%s: csr %04x, " "H%08x S%08x C%08x %08x, " "F%08x L%08x .. %08x", @@ -954,7 +954,7 @@ static int cppi_channel_program(struct dma_channel *ch, cppi_ch = container_of(ch, struct cppi_channel, channel); controller = cppi_ch->controller; - musb = controller->musb; + musb = controller->controller.musb; switch (ch->status) { case MUSB_DMA_STATUS_BUS_ABORT: @@ -1009,7 +1009,7 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch) int i; dma_addr_t safe2ack; void __iomem *regs = rx->hw_ep->regs; - struct musb *musb = cppi->musb; + struct musb *musb = cppi->controller.musb; cppi_dump_rx(6, rx, "/K"); @@ -1121,7 +1121,7 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch) * setting it here "should" be racey, but seems to work */ csr = musb_readw(rx->hw_ep->regs, MUSB_RXCSR); - if (is_host_active(cppi->musb) + if (is_host_active(cppi->controller.musb) && bd && !(csr & MUSB_RXCSR_H_REQPKT)) { csr |= MUSB_RXCSR_H_REQPKT; @@ -1311,7 +1311,7 @@ cppi_dma_controller_create(struct musb *musb, void __iomem *mregs) controller->mregs = mregs; controller->tibase = mregs - DAVINCI_BASE_OFFSET; - controller->musb = musb; + controller->controller.musb = musb; controller->controller.channel_alloc = cppi_channel_allocate; controller->controller.channel_release = cppi_channel_release; controller->controller.channel_program = cppi_channel_program; @@ -1323,7 +1323,7 @@ cppi_dma_controller_create(struct musb *musb, void __iomem *mregs) /* setup BufferPool */ controller->pool = dma_pool_create("cppi", - controller->musb->controller, + controller->controller.musb->controller, sizeof(struct cppi_descriptor), CPPI_DESCRIPTOR_ALIGN, 0); if (!controller->pool) { @@ -1357,7 +1357,7 @@ void cppi_dma_controller_destroy(struct dma_controller *c) cppi_controller_stop(cppi); if (cppi->irq) - free_irq(cppi->irq, cppi->musb); + free_irq(cppi->irq, cppi->controller.musb); /* assert: caller stopped the controller first */ dma_pool_destroy(cppi->pool); @@ -1469,7 +1469,7 @@ static int cppi_channel_abort(struct dma_channel *channel) core_rxirq_disable(tibase, cppi_ch->index + 1); /* for host, ensure ReqPkt is never set again */ - if (is_host_active(cppi_ch->controller->musb)) { + if (is_host_active(cppi_ch->controller->controller.musb)) { value = musb_readl(tibase, DAVINCI_AUTOREQ_REG); value &= ~((0x3) << (cppi_ch->index * 2)); musb_writel(tibase, DAVINCI_AUTOREQ_REG, value); @@ -1478,7 +1478,7 @@ static int cppi_channel_abort(struct dma_channel *channel) csr = musb_readw(regs, MUSB_RXCSR); /* for host, clear (just) ReqPkt at end of current packet(s) */ - if (is_host_active(cppi_ch->controller->musb)) { + if (is_host_active(cppi_ch->controller->controller.musb)) { csr |= MUSB_RXCSR_H_WZC_BITS; csr &= ~MUSB_RXCSR_H_REQPKT; } else diff --git a/drivers/usb/musb/cppi_dma.h b/drivers/usb/musb/cppi_dma.h index 7fdfb71a8f09..9bb7c5e45c85 100644 --- a/drivers/usb/musb/cppi_dma.h +++ b/drivers/usb/musb/cppi_dma.h @@ -107,7 +107,6 @@ struct cppi_channel { /* CPPI DMA controller object */ struct cppi { struct dma_controller controller; - struct musb *musb; void __iomem *mregs; /* Mentor regs */ void __iomem *tibase; /* TI/CPPI regs */ diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index e89708d839e5..d79c288ccbf2 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -125,7 +125,6 @@ static void da8xx_musb_disable(struct musb *musb) musb_writel(reg_base, DA8XX_USB_INTR_MASK_CLEAR_REG, DA8XX_INTR_USB_MASK | DA8XX_INTR_TX_MASK | DA8XX_INTR_RX_MASK); - musb_writeb(musb->mregs, MUSB_DEVCTL, 0); musb_writel(reg_base, DA8XX_USB_END_OF_INTR_REG, 0); } @@ -458,15 +457,11 @@ static inline u8 get_vbus_power(struct device *dev) } static const struct musb_platform_ops da8xx_ops = { - .quirks = MUSB_DMA_CPPI | MUSB_INDEXED_EP, + .quirks = MUSB_INDEXED_EP | MUSB_PRESERVE_SESSION, .init = da8xx_musb_init, .exit = da8xx_musb_exit, .fifo_mode = 2, -#ifdef CONFIG_USB_TI_CPPI_DMA - .dma_init = cppi_dma_controller_create, - .dma_exit = cppi_dma_controller_destroy, -#endif .enable = da8xx_musb_enable, .disable = da8xx_musb_disable, @@ -578,6 +573,34 @@ static int da8xx_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int da8xx_suspend(struct device *dev) +{ + int ret; + struct da8xx_glue *glue = dev_get_drvdata(dev); + + ret = phy_power_off(glue->phy); + if (ret) + return ret; + clk_disable_unprepare(glue->clk); + + return 0; +} + +static int da8xx_resume(struct device *dev) +{ + int ret; + struct da8xx_glue *glue = dev_get_drvdata(dev); + + ret = clk_prepare_enable(glue->clk); + if (ret) + return ret; + return phy_power_on(glue->phy); +} +#endif + +static SIMPLE_DEV_PM_OPS(da8xx_pm_ops, da8xx_suspend, da8xx_resume); + #ifdef CONFIG_OF static const struct of_device_id da8xx_id_table[] = { { @@ -593,6 +616,7 @@ static struct platform_driver da8xx_driver = { .remove = da8xx_remove, .driver = { .name = "musb-da8xx", + .pm = &da8xx_pm_ops, .of_match_table = of_match_ptr(da8xx_id_table), }, }; diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index cee61a51645e..52b491d3d5d8 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -133,7 +133,6 @@ static void davinci_musb_disable(struct musb *musb) DAVINCI_USB_USBINT_MASK | DAVINCI_USB_TXINT_MASK | DAVINCI_USB_RXINT_MASK); - musb_writeb(musb->mregs, MUSB_DEVCTL, 0); musb_writel(musb->ctrl_base, DAVINCI_USB_EOI_REG, 0); if (is_dma_capable() && !dma_off) diff --git a/drivers/usb/musb/jz4740.c b/drivers/usb/musb/jz4740.c index bc8889956d17..40c68c23d553 100644 --- a/drivers/usb/musb/jz4740.c +++ b/drivers/usb/musb/jz4740.c @@ -63,7 +63,7 @@ static struct musb_fifo_cfg jz4740_musb_fifo_cfg[] = { { .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 64, }, }; -static struct musb_hdrc_config jz4740_musb_config = { +static const struct musb_hdrc_config jz4740_musb_config = { /* Silicon does not implement USB OTG. */ .multipoint = 0, /* Max EPs scanned, driver will decide which EP can be used. */ diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 772f15821242..d8bae6ca8904 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1040,16 +1040,6 @@ static void musb_enable_interrupts(struct musb *musb) } -static void musb_generic_disable(struct musb *musb) -{ - void __iomem *mbase = musb->mregs; - - musb_disable_interrupts(musb); - - /* off */ - musb_writeb(mbase, MUSB_DEVCTL, 0); -} - /* * Program the HDRC to start (enable interrupts, dma, etc.). */ @@ -1106,8 +1096,8 @@ void musb_stop(struct musb *musb) { /* stop IRQs, timers, ... */ musb_platform_disable(musb); - musb_generic_disable(musb); - musb_dbg(musb, "HDRC disabled"); + musb_disable_interrupts(musb); + musb_writeb(musb->mregs, MUSB_DEVCTL, 0); /* FIXME * - mark host and/or peripheral drivers unusable/inactive @@ -1879,6 +1869,7 @@ static void musb_pm_runtime_check_session(struct musb *musb) return; } + /* fall through */ case MUSB_QUIRK_A_DISCONNECT_19: if (musb->quirk_retries--) { musb_dbg(musb, @@ -2323,7 +2314,8 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) /* be sure interrupts are disabled before connecting ISR */ musb_platform_disable(musb); - musb_generic_disable(musb); + musb_disable_interrupts(musb); + musb_writeb(musb->mregs, MUSB_DEVCTL, 0); /* Init IRQ workqueue before request_irq */ INIT_DELAYED_WORK(&musb->irq_work, musb_irq_work); @@ -2497,11 +2489,13 @@ static int musb_remove(struct platform_device *pdev) pm_runtime_get_sync(musb->controller); musb_host_cleanup(musb); musb_gadget_cleanup(musb); + spin_lock_irqsave(&musb->lock, flags); musb_platform_disable(musb); - musb_generic_disable(musb); - spin_unlock_irqrestore(&musb->lock, flags); + musb_disable_interrupts(musb); musb_writeb(musb->mregs, MUSB_DEVCTL, 0); + spin_unlock_irqrestore(&musb->lock, flags); + pm_runtime_dont_use_autosuspend(musb->controller); pm_runtime_put_sync(musb->controller); pm_runtime_disable(musb->controller); @@ -2676,7 +2670,9 @@ static int musb_suspend(struct device *dev) unsigned long flags; musb_platform_disable(musb); - musb_generic_disable(musb); + musb_disable_interrupts(musb); + if (!(musb->io.quirks & MUSB_PRESERVE_SESSION)) + musb_writeb(musb->mregs, MUSB_DEVCTL, 0); WARN_ON(!list_empty(&musb->pending_list)); spin_lock_irqsave(&musb->lock, flags); diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index ce5a18c98c6d..5b708be6d1d1 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -172,6 +172,7 @@ struct musb_io; */ struct musb_platform_ops { +#define MUSB_PRESERVE_SESSION BIT(7) #define MUSB_DMA_UX500 BIT(6) #define MUSB_DMA_CPPI41 BIT(5) #define MUSB_DMA_CPPI BIT(4) diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c index 16363852c034..00e272bfee39 100644 --- a/drivers/usb/musb/musb_cppi41.c +++ b/drivers/usb/musb/musb_cppi41.c @@ -30,7 +30,6 @@ struct cppi41_dma_controller { struct dma_controller controller; struct cppi41_dma_channel rx_channel[MUSB_DMA_NUM_CHANNELS]; struct cppi41_dma_channel tx_channel[MUSB_DMA_NUM_CHANNELS]; - struct musb *musb; struct hrtimer early_tx; struct list_head early_tx_list; u32 rx_mode; @@ -45,7 +44,7 @@ static void save_rx_toggle(struct cppi41_dma_channel *cppi41_channel) if (cppi41_channel->is_tx) return; - if (!is_host_active(cppi41_channel->controller->musb)) + if (!is_host_active(cppi41_channel->controller->controller.musb)) return; csr = musb_readw(cppi41_channel->hw_ep->regs, MUSB_RXCSR); @@ -78,8 +77,7 @@ static void update_rx_toggle(struct cppi41_dma_channel *cppi41_channel) if (!toggle && toggle == cppi41_channel->usb_toggle) { csr |= MUSB_RXCSR_H_DATATOGGLE | MUSB_RXCSR_H_WR_DATATOGGLE; musb_writew(cppi41_channel->hw_ep->regs, MUSB_RXCSR, csr); - musb_dbg(cppi41_channel->controller->musb, - "Restoring DATA1 toggle."); + musb_dbg(musb, "Restoring DATA1 toggle."); } cppi41_channel->usb_toggle = toggle; @@ -99,7 +97,8 @@ static bool musb_is_tx_fifo_empty(struct musb_hw_ep *hw_ep) return true; } -static void cppi41_dma_callback(void *private_data); +static void cppi41_dma_callback(void *private_data, + const struct dmaengine_result *result); static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel) { @@ -154,7 +153,7 @@ static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel) if (WARN_ON(!dma_desc)) return; - dma_desc->callback = cppi41_dma_callback; + dma_desc->callback_result = cppi41_dma_callback; dma_desc->callback_param = &cppi41_channel->channel; cppi41_channel->cookie = dma_desc->tx_submit(dma_desc); trace_musb_cppi41_cont(cppi41_channel); @@ -179,7 +178,7 @@ static enum hrtimer_restart cppi41_recheck_tx_req(struct hrtimer *timer) controller = container_of(timer, struct cppi41_dma_controller, early_tx); - musb = controller->musb; + musb = controller->controller.musb; spin_lock_irqsave(&musb->lock, flags); list_for_each_entry_safe(cppi41_channel, n, &controller->early_tx_list, @@ -204,7 +203,8 @@ static enum hrtimer_restart cppi41_recheck_tx_req(struct hrtimer *timer) return ret; } -static void cppi41_dma_callback(void *private_data) +static void cppi41_dma_callback(void *private_data, + const struct dmaengine_result *result) { struct dma_channel *channel = private_data; struct cppi41_dma_channel *cppi41_channel = channel->private_data; @@ -217,6 +217,13 @@ static void cppi41_dma_callback(void *private_data) int is_hs = 0; bool empty; + controller = cppi41_channel->controller; + if (controller->controller.dma_callback) + controller->controller.dma_callback(&controller->controller); + + if (result->result == DMA_TRANS_ABORTED) + return; + spin_lock_irqsave(&musb->lock, flags); dmaengine_tx_status(cppi41_channel->dc, cppi41_channel->cookie, @@ -249,8 +256,6 @@ static void cppi41_dma_callback(void *private_data) * We spin on HS (no longer than than 25us and setup a timer on * FS to check for the bit and complete the transfer. */ - controller = cppi41_channel->controller; - if (is_host_active(musb)) { if (musb->port1_status & USB_PORT_STAT_HIGH_SPEED) is_hs = 1; @@ -302,6 +307,7 @@ static void cppi41_set_dma_mode(struct cppi41_dma_channel *cppi41_channel, unsigned mode) { struct cppi41_dma_controller *controller = cppi41_channel->controller; + struct musb *musb = controller->controller.musb; u32 port; u32 new_mode; u32 old_mode; @@ -317,12 +323,10 @@ static void cppi41_set_dma_mode(struct cppi41_dma_channel *cppi41_channel, return; if (cppi41_channel->is_tx) { controller->tx_mode = new_mode; - musb_writel(controller->musb->ctrl_base, USB_CTRL_TX_MODE, - new_mode); + musb_writel(musb->ctrl_base, USB_CTRL_TX_MODE, new_mode); } else { controller->rx_mode = new_mode; - musb_writel(controller->musb->ctrl_base, USB_CTRL_RX_MODE, - new_mode); + musb_writel(musb->ctrl_base, USB_CTRL_RX_MODE, new_mode); } } @@ -341,7 +345,8 @@ static void cppi41_set_autoreq_mode(struct cppi41_dma_channel *cppi41_channel, if (new_mode == old_mode) return; controller->auto_req = new_mode; - musb_writel(controller->musb->ctrl_base, USB_CTRL_AUTOREQ, new_mode); + musb_writel(controller->controller.musb->ctrl_base, USB_CTRL_AUTOREQ, + new_mode); } static bool cppi41_configure_channel(struct dma_channel *channel, @@ -352,7 +357,7 @@ static bool cppi41_configure_channel(struct dma_channel *channel, struct dma_chan *dc = cppi41_channel->dc; struct dma_async_tx_descriptor *dma_desc; enum dma_transfer_direction direction; - struct musb *musb = cppi41_channel->controller->musb; + struct musb *musb = cppi41_channel->controller->controller.musb; unsigned use_gen_rndis = 0; cppi41_channel->buf_addr = dma_addr; @@ -401,7 +406,7 @@ static bool cppi41_configure_channel(struct dma_channel *channel, if (!dma_desc) return false; - dma_desc->callback = cppi41_dma_callback; + dma_desc->callback_result = cppi41_dma_callback; dma_desc->callback_param = channel; cppi41_channel->cookie = dma_desc->tx_submit(dma_desc); cppi41_channel->channel.rx_packet_done = false; @@ -465,7 +470,7 @@ static int cppi41_dma_channel_program(struct dma_channel *channel, BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN || channel->status == MUSB_DMA_STATUS_BUSY); - if (is_host_active(cppi41_channel->controller->musb)) { + if (is_host_active(cppi41_channel->controller->controller.musb)) { if (cppi41_channel->is_tx) hb_mult = cppi41_channel->hw_ep->out_qh->hb_mult; else @@ -490,7 +495,7 @@ static int cppi41_is_compatible(struct dma_channel *channel, u16 maxpacket, { struct cppi41_dma_channel *cppi41_channel = channel->private_data; struct cppi41_dma_controller *controller = cppi41_channel->controller; - struct musb *musb = controller->musb; + struct musb *musb = controller->controller.musb; if (is_host_active(musb)) { WARN_ON(1); @@ -508,7 +513,7 @@ static int cppi41_dma_channel_abort(struct dma_channel *channel) { struct cppi41_dma_channel *cppi41_channel = channel->private_data; struct cppi41_dma_controller *controller = cppi41_channel->controller; - struct musb *musb = controller->musb; + struct musb *musb = controller->controller.musb; void __iomem *epio = cppi41_channel->hw_ep->regs; int tdbit; int ret; @@ -593,7 +598,7 @@ static void cppi41_dma_controller_stop(struct cppi41_dma_controller *controller) static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller) { - struct musb *musb = controller->musb; + struct musb *musb = controller->controller.musb; struct device *dev = musb->controller; struct device_node *np = dev->parent->of_node; struct cppi41_dma_channel *cppi41_channel; @@ -688,13 +693,13 @@ cppi41_dma_controller_create(struct musb *musb, void __iomem *base) hrtimer_init(&controller->early_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL); controller->early_tx.function = cppi41_recheck_tx_req; INIT_LIST_HEAD(&controller->early_tx_list); - controller->musb = musb; controller->controller.channel_alloc = cppi41_dma_channel_allocate; controller->controller.channel_release = cppi41_dma_channel_release; controller->controller.channel_program = cppi41_dma_channel_program; controller->controller.channel_abort = cppi41_dma_channel_abort; controller->controller.is_compatible = cppi41_is_compatible; + controller->controller.musb = musb; ret = cppi41_dma_controller_start(controller); if (ret) diff --git a/drivers/usb/musb/musb_debugfs.c b/drivers/usb/musb/musb_debugfs.c index dd70c88419d2..952733ceaac8 100644 --- a/drivers/usb/musb/musb_debugfs.c +++ b/drivers/usb/musb/musb_debugfs.c @@ -153,28 +153,34 @@ static int musb_test_mode_show(struct seq_file *s, void *unused) pm_runtime_mark_last_busy(musb->controller); pm_runtime_put_autosuspend(musb->controller); - if (test & MUSB_TEST_FORCE_HOST) + if (test == (MUSB_TEST_FORCE_HOST | MUSB_TEST_FORCE_FS)) + seq_printf(s, "force host full-speed\n"); + + else if (test == (MUSB_TEST_FORCE_HOST | MUSB_TEST_FORCE_HS)) + seq_printf(s, "force host high-speed\n"); + + else if (test == MUSB_TEST_FORCE_HOST) seq_printf(s, "force host\n"); - if (test & MUSB_TEST_FIFO_ACCESS) + else if (test == MUSB_TEST_FIFO_ACCESS) seq_printf(s, "fifo access\n"); - if (test & MUSB_TEST_FORCE_FS) + else if (test == MUSB_TEST_FORCE_FS) seq_printf(s, "force full-speed\n"); - if (test & MUSB_TEST_FORCE_HS) + else if (test == MUSB_TEST_FORCE_HS) seq_printf(s, "force high-speed\n"); - if (test & MUSB_TEST_PACKET) + else if (test == MUSB_TEST_PACKET) seq_printf(s, "test packet\n"); - if (test & MUSB_TEST_K) + else if (test == MUSB_TEST_K) seq_printf(s, "test K\n"); - if (test & MUSB_TEST_J) + else if (test == MUSB_TEST_J) seq_printf(s, "test J\n"); - if (test & MUSB_TEST_SE0_NAK) + else if (test == MUSB_TEST_SE0_NAK) seq_printf(s, "test SE0 NAK\n"); return 0; @@ -198,7 +204,7 @@ static ssize_t musb_test_mode_write(struct file *file, struct seq_file *s = file->private_data; struct musb *musb = s->private; u8 test; - char buf[18]; + char buf[24]; pm_runtime_get_sync(musb->controller); test = musb_readb(musb->mregs, MUSB_TESTMODE); @@ -213,30 +219,36 @@ static ssize_t musb_test_mode_write(struct file *file, if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) return -EFAULT; - if (strstarts(buf, "force host")) + if (strstarts(buf, "force host full-speed")) + test = MUSB_TEST_FORCE_HOST | MUSB_TEST_FORCE_FS; + + else if (strstarts(buf, "force host high-speed")) + test = MUSB_TEST_FORCE_HOST | MUSB_TEST_FORCE_HS; + + else if (strstarts(buf, "force host")) test = MUSB_TEST_FORCE_HOST; - if (strstarts(buf, "fifo access")) + else if (strstarts(buf, "fifo access")) test = MUSB_TEST_FIFO_ACCESS; - if (strstarts(buf, "force full-speed")) + else if (strstarts(buf, "force full-speed")) test = MUSB_TEST_FORCE_FS; - if (strstarts(buf, "force high-speed")) + else if (strstarts(buf, "force high-speed")) test = MUSB_TEST_FORCE_HS; - if (strstarts(buf, "test packet")) { + else if (strstarts(buf, "test packet")) { test = MUSB_TEST_PACKET; musb_load_testpacket(musb); } - if (strstarts(buf, "test K")) + else if (strstarts(buf, "test K")) test = MUSB_TEST_K; - if (strstarts(buf, "test J")) + else if (strstarts(buf, "test J")) test = MUSB_TEST_J; - if (strstarts(buf, "test SE0 NAK")) + else if (strstarts(buf, "test SE0 NAK")) test = MUSB_TEST_SE0_NAK; musb_writeb(musb->mregs, MUSB_TESTMODE, test); diff --git a/drivers/usb/musb/musb_dma.h b/drivers/usb/musb/musb_dma.h index 46357e183b4c..04c3bd86bd62 100644 --- a/drivers/usb/musb/musb_dma.h +++ b/drivers/usb/musb/musb_dma.h @@ -173,6 +173,7 @@ dma_channel_status(struct dma_channel *c) /** * struct dma_controller - A DMA Controller. + * @musb: the usb controller * @start: call this to start a DMA controller; * return 0 on success, else negative errno * @stop: call this to stop a DMA controller @@ -181,10 +182,13 @@ dma_channel_status(struct dma_channel *c) * @channel_release: call this to release a DMA channel * @channel_abort: call this to abort a pending DMA transaction, * returning it to FREE (but allocated) state + * @dma_callback: invoked on DMA completion, useful to run platform + * code such IRQ acknowledgment. * * Controllers manage dma channels. */ struct dma_controller { + struct musb *musb; struct dma_channel *(*channel_alloc)(struct dma_controller *, struct musb_hw_ep *, u8 is_tx); void (*channel_release)(struct dma_channel *); @@ -196,6 +200,7 @@ struct dma_controller { int (*is_compatible)(struct dma_channel *channel, u16 maxpacket, void *buf, u32 length); + void (*dma_callback)(struct dma_controller *); }; /* called after channel_program(), may indicate a fault */ diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 9f125e179acd..7c047c4a2565 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -118,9 +118,11 @@ struct dsps_glue { struct device *dev; struct platform_device *musb; /* child musb pdev */ const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */ + int vbus_irq; /* optional vbus irq */ struct timer_list timer; /* otg_workaround timer */ unsigned long last_timer; /* last timer data for each instance */ bool sw_babble_enabled; + void __iomem *usbss_base; struct dsps_context context; struct debugfs_regset32 regset; @@ -145,6 +147,36 @@ static const struct debugfs_reg32 dsps_musb_regs[] = { { "mode", 0xe8 }, }; +static void dsps_mod_timer(struct dsps_glue *glue, int wait_ms) +{ + int wait; + + if (wait_ms < 0) + wait = msecs_to_jiffies(glue->wrp->poll_timeout); + else + wait = msecs_to_jiffies(wait_ms); + + mod_timer(&glue->timer, jiffies + wait); +} + +/* + * If no vbus irq from the PMIC is configured, we need to poll VBUS status. + */ +static void dsps_mod_timer_optional(struct dsps_glue *glue) +{ + if (glue->vbus_irq) + return; + + dsps_mod_timer(glue, -1); +} + +/* USBSS / USB AM335x */ +#define USBSS_IRQ_STATUS 0x28 +#define USBSS_IRQ_ENABLER 0x2c +#define USBSS_IRQ_CLEARR 0x30 + +#define USBSS_IRQ_PD_COMP (1 << 2) + /** * dsps_musb_enable - enable interrupts */ @@ -167,8 +199,7 @@ static void dsps_musb_enable(struct musb *musb) /* start polling for ID change in dual-role idle mode */ if (musb->xceiv->otg->state == OTG_STATE_B_IDLE && musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) - mod_timer(&glue->timer, jiffies + - msecs_to_jiffies(wrp->poll_timeout)); + dsps_mod_timer(glue, -1); } /** @@ -186,7 +217,6 @@ static void dsps_musb_disable(struct musb *musb) musb_writel(reg_base, wrp->epintr_clear, wrp->txep_bitmap | wrp->rxep_bitmap); del_timer_sync(&glue->timer); - musb_writeb(musb->mregs, MUSB_DEVCTL, 0); } /* Caller must take musb->lock */ @@ -199,6 +229,9 @@ static int dsps_check_status(struct musb *musb, void *unused) u8 devctl; int skip_session = 0; + if (glue->vbus_irq) + del_timer(&glue->timer); + /* * We poll because DSPS IP's won't expose several OTG-critical * status change events (from the transceiver) otherwise. @@ -209,8 +242,7 @@ static int dsps_check_status(struct musb *musb, void *unused) switch (musb->xceiv->otg->state) { case OTG_STATE_A_WAIT_VRISE: - mod_timer(&glue->timer, jiffies + - msecs_to_jiffies(wrp->poll_timeout)); + dsps_mod_timer_optional(glue); break; case OTG_STATE_A_WAIT_BCON: musb_writeb(musb->mregs, MUSB_DEVCTL, 0); @@ -219,17 +251,19 @@ static int dsps_check_status(struct musb *musb, void *unused) case OTG_STATE_A_IDLE: case OTG_STATE_B_IDLE: - if (devctl & MUSB_DEVCTL_BDEVICE) { - musb->xceiv->otg->state = OTG_STATE_B_IDLE; - MUSB_DEV_MODE(musb); - } else { - musb->xceiv->otg->state = OTG_STATE_A_IDLE; - MUSB_HST_MODE(musb); + if (!glue->vbus_irq) { + if (devctl & MUSB_DEVCTL_BDEVICE) { + musb->xceiv->otg->state = OTG_STATE_B_IDLE; + MUSB_DEV_MODE(musb); + } else { + musb->xceiv->otg->state = OTG_STATE_A_IDLE; + MUSB_HST_MODE(musb); + } + if (!(devctl & MUSB_DEVCTL_SESSION) && !skip_session) + musb_writeb(mregs, MUSB_DEVCTL, + MUSB_DEVCTL_SESSION); } - if (!(devctl & MUSB_DEVCTL_SESSION) && !skip_session) - musb_writeb(mregs, MUSB_DEVCTL, MUSB_DEVCTL_SESSION); - mod_timer(&glue->timer, jiffies + - msecs_to_jiffies(wrp->poll_timeout)); + dsps_mod_timer_optional(glue); break; case OTG_STATE_A_WAIT_VFALL: musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; @@ -267,7 +301,7 @@ static void otg_timer(unsigned long _musb) pm_runtime_put_autosuspend(dev); } -void dsps_musb_clear_ep_rxintr(struct musb *musb, int epnum) +static void dsps_musb_clear_ep_rxintr(struct musb *musb, int epnum) { u32 epintr; struct dsps_glue *glue = dev_get_drvdata(musb->controller->parent); @@ -332,15 +366,13 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) */ musb->int_usb &= ~MUSB_INTR_VBUSERROR; musb->xceiv->otg->state = OTG_STATE_A_WAIT_VFALL; - mod_timer(&glue->timer, jiffies + - msecs_to_jiffies(wrp->poll_timeout)); + dsps_mod_timer_optional(glue); WARNING("VBUS error workaround (delay coming)\n"); } else if (drvvbus) { MUSB_HST_MODE(musb); musb->xceiv->otg->default_a = 1; musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; - mod_timer(&glue->timer, jiffies + - msecs_to_jiffies(wrp->poll_timeout)); + dsps_mod_timer_optional(glue); } else { musb->is_active = 0; MUSB_DEV_MODE(musb); @@ -364,8 +396,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) switch (musb->xceiv->otg->state) { case OTG_STATE_B_IDLE: case OTG_STATE_A_WAIT_BCON: - mod_timer(&glue->timer, jiffies + - msecs_to_jiffies(wrp->poll_timeout)); + dsps_mod_timer_optional(glue); break; default: break; @@ -469,8 +500,7 @@ static int dsps_musb_init(struct musb *musb) musb_writeb(musb->mregs, MUSB_BABBLE_CTL, val); } - mod_timer(&glue->timer, jiffies + - msecs_to_jiffies(glue->wrp->poll_timeout)); + dsps_mod_timer(glue, -1); return dsps_musb_dbg_init(musb, glue); } @@ -619,14 +649,76 @@ static void dsps_read_fifo32(struct musb_hw_ep *hw_ep, u16 len, u8 *dst) } } +#ifdef CONFIG_USB_TI_CPPI41_DMA +static void dsps_dma_controller_callback(struct dma_controller *c) +{ + struct musb *musb = c->musb; + struct dsps_glue *glue = dev_get_drvdata(musb->controller->parent); + void __iomem *usbss_base = glue->usbss_base; + u32 status; + + status = musb_readl(usbss_base, USBSS_IRQ_STATUS); + if (status & USBSS_IRQ_PD_COMP) + musb_writel(usbss_base, USBSS_IRQ_STATUS, USBSS_IRQ_PD_COMP); +} + +static struct dma_controller * +dsps_dma_controller_create(struct musb *musb, void __iomem *base) +{ + struct dma_controller *controller; + struct dsps_glue *glue = dev_get_drvdata(musb->controller->parent); + void __iomem *usbss_base = glue->usbss_base; + + controller = cppi41_dma_controller_create(musb, base); + if (IS_ERR_OR_NULL(controller)) + return controller; + + musb_writel(usbss_base, USBSS_IRQ_ENABLER, USBSS_IRQ_PD_COMP); + controller->dma_callback = dsps_dma_controller_callback; + + return controller; +} + +static void dsps_dma_controller_destroy(struct dma_controller *c) +{ + struct musb *musb = c->musb; + struct dsps_glue *glue = dev_get_drvdata(musb->controller->parent); + void __iomem *usbss_base = glue->usbss_base; + + musb_writel(usbss_base, USBSS_IRQ_CLEARR, USBSS_IRQ_PD_COMP); + cppi41_dma_controller_destroy(c); +} + +#ifdef CONFIG_PM_SLEEP +static void dsps_dma_controller_suspend(struct dsps_glue *glue) +{ + void __iomem *usbss_base = glue->usbss_base; + + musb_writel(usbss_base, USBSS_IRQ_CLEARR, USBSS_IRQ_PD_COMP); +} + +static void dsps_dma_controller_resume(struct dsps_glue *glue) +{ + void __iomem *usbss_base = glue->usbss_base; + + musb_writel(usbss_base, USBSS_IRQ_ENABLER, USBSS_IRQ_PD_COMP); +} +#endif +#else /* CONFIG_USB_TI_CPPI41_DMA */ +#ifdef CONFIG_PM_SLEEP +static void dsps_dma_controller_suspend(struct dsps_glue *glue) {} +static void dsps_dma_controller_resume(struct dsps_glue *glue) {} +#endif +#endif /* CONFIG_USB_TI_CPPI41_DMA */ + static struct musb_platform_ops dsps_ops = { .quirks = MUSB_DMA_CPPI41 | MUSB_INDEXED_EP, .init = dsps_musb_init, .exit = dsps_musb_exit, #ifdef CONFIG_USB_TI_CPPI41_DMA - .dma_init = cppi41_dma_controller_create, - .dma_exit = cppi41_dma_controller_destroy, + .dma_init = dsps_dma_controller_create, + .dma_exit = dsps_dma_controller_destroy, #endif .enable = dsps_musb_enable, .disable = dsps_musb_disable, @@ -696,7 +788,8 @@ static int dsps_create_musb_pdev(struct dsps_glue *glue, resources[1] = *res; /* allocate the child platform device */ - musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); + musb = platform_device_alloc("musb-hdrc", + (resources[0].start & 0xFFF) == 0x400 ? 0 : 1); if (!musb) { dev_err(dev, "failed to allocate musb device\n"); return -ENOMEM; @@ -765,6 +858,47 @@ err: return ret; } +static irqreturn_t dsps_vbus_threaded_irq(int irq, void *priv) +{ + struct dsps_glue *glue = priv; + struct musb *musb = platform_get_drvdata(glue->musb); + + if (!musb) + return IRQ_NONE; + + dev_dbg(glue->dev, "VBUS interrupt\n"); + dsps_mod_timer(glue, 0); + + return IRQ_HANDLED; +} + +static int dsps_setup_optional_vbus_irq(struct platform_device *pdev, + struct dsps_glue *glue) +{ + int error; + + glue->vbus_irq = platform_get_irq_byname(pdev, "vbus"); + if (glue->vbus_irq == -EPROBE_DEFER) + return -EPROBE_DEFER; + + if (glue->vbus_irq <= 0) { + glue->vbus_irq = 0; + return 0; + } + + error = devm_request_threaded_irq(glue->dev, glue->vbus_irq, + NULL, dsps_vbus_threaded_irq, + IRQF_ONESHOT, + "vbus", glue); + if (error) { + glue->vbus_irq = 0; + return error; + } + dev_dbg(glue->dev, "VBUS irq %i configured\n", glue->vbus_irq); + + return 0; +} + static int dsps_probe(struct platform_device *pdev) { const struct of_device_id *match; @@ -792,6 +926,15 @@ static int dsps_probe(struct platform_device *pdev) glue->dev = &pdev->dev; glue->wrp = wrp; + glue->usbss_base = of_iomap(pdev->dev.parent->of_node, 0); + if (!glue->usbss_base) + return -ENXIO; + + if (usb_get_dr_mode(&pdev->dev) == USB_DR_MODE_PERIPHERAL) { + ret = dsps_setup_optional_vbus_irq(pdev, glue); + if (ret) + return ret; + } platform_set_drvdata(pdev, glue); pm_runtime_enable(&pdev->dev); @@ -880,6 +1023,8 @@ static int dsps_suspend(struct device *dev) glue->context.tx_mode = musb_readl(mbase, wrp->tx_mode); glue->context.rx_mode = musb_readl(mbase, wrp->rx_mode); + dsps_dma_controller_suspend(glue); + return 0; } @@ -893,6 +1038,8 @@ static int dsps_resume(struct device *dev) if (!musb) return 0; + dsps_dma_controller_resume(glue); + mbase = musb->ctrl_base; musb_writel(mbase, wrp->control, glue->context.control); musb_writel(mbase, wrp->epintr_set, glue->context.epintr); @@ -903,8 +1050,7 @@ static int dsps_resume(struct device *dev) musb_writel(mbase, wrp->rx_mode, glue->context.rx_mode); if (musb->xceiv->otg->state == OTG_STATE_B_IDLE && musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE) - mod_timer(&glue->timer, jiffies + - msecs_to_jiffies(wrp->poll_timeout)); + dsps_mod_timer(glue, -1); return 0; } diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 8b73214a9ea3..456f3e6ecf03 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -575,7 +575,7 @@ static int omap2430_runtime_resume(struct device *dev) return 0; } -static struct dev_pm_ops omap2430_pm_ops = { +static const struct dev_pm_ops omap2430_pm_ops = { .runtime_suspend = omap2430_runtime_suspend, .runtime_resume = omap2430_runtime_resume, }; diff --git a/drivers/usb/musb/sunxi.c b/drivers/usb/musb/sunxi.c index d0be0eadd0d9..c9a09b5bb6e5 100644 --- a/drivers/usb/musb/sunxi.c +++ b/drivers/usb/musb/sunxi.c @@ -251,14 +251,14 @@ static int sunxi_musb_init(struct musb *musb) writeb(SUNXI_MUSB_VEND0_PIO_MODE, musb->mregs + SUNXI_MUSB_VEND0); /* Register notifier before calling phy_init() */ - ret = extcon_register_notifier(glue->extcon, EXTCON_USB_HOST, - &glue->host_nb); + ret = devm_extcon_register_notifier(glue->dev, glue->extcon, + EXTCON_USB_HOST, &glue->host_nb); if (ret) goto error_reset_assert; ret = phy_init(glue->phy); if (ret) - goto error_unregister_notifier; + goto error_reset_assert; musb->isr = sunxi_musb_interrupt; @@ -267,9 +267,6 @@ static int sunxi_musb_init(struct musb *musb) return 0; -error_unregister_notifier: - extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST, - &glue->host_nb); error_reset_assert: if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags)) reset_control_assert(glue->rst); @@ -293,9 +290,6 @@ static int sunxi_musb_exit(struct musb *musb) phy_exit(glue->phy); - extcon_unregister_notifier(glue->extcon, EXTCON_USB_HOST, - &glue->host_nb); - if (test_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags)) reset_control_assert(glue->rst); @@ -645,7 +639,21 @@ static struct musb_fifo_cfg sunxi_musb_mode_cfg[] = { MUSB_EP_FIFO_SINGLE(5, FIFO_RX, 512), }; -static struct musb_hdrc_config sunxi_musb_hdrc_config = { +/* H3/V3s OTG supports only 4 endpoints */ +#define SUNXI_MUSB_MAX_EP_NUM_H3 5 + +static struct musb_fifo_cfg sunxi_musb_mode_cfg_h3[] = { + MUSB_EP_FIFO_SINGLE(1, FIFO_TX, 512), + MUSB_EP_FIFO_SINGLE(1, FIFO_RX, 512), + MUSB_EP_FIFO_SINGLE(2, FIFO_TX, 512), + MUSB_EP_FIFO_SINGLE(2, FIFO_RX, 512), + MUSB_EP_FIFO_SINGLE(3, FIFO_TX, 512), + MUSB_EP_FIFO_SINGLE(3, FIFO_RX, 512), + MUSB_EP_FIFO_SINGLE(4, FIFO_TX, 512), + MUSB_EP_FIFO_SINGLE(4, FIFO_RX, 512), +}; + +static const struct musb_hdrc_config sunxi_musb_hdrc_config = { .fifo_cfg = sunxi_musb_mode_cfg, .fifo_cfg_size = ARRAY_SIZE(sunxi_musb_mode_cfg), .multipoint = true, @@ -656,6 +664,18 @@ static struct musb_hdrc_config sunxi_musb_hdrc_config = { .dma = 0, }; +static struct musb_hdrc_config sunxi_musb_hdrc_config_h3 = { + .fifo_cfg = sunxi_musb_mode_cfg_h3, + .fifo_cfg_size = ARRAY_SIZE(sunxi_musb_mode_cfg_h3), + .multipoint = true, + .dyn_fifo = true, + .soft_con = true, + .num_eps = SUNXI_MUSB_MAX_EP_NUM_H3, + .ram_bits = SUNXI_MUSB_RAM_BITS, + .dma = 0, +}; + + static int sunxi_musb_probe(struct platform_device *pdev) { struct musb_hdrc_platform_data pdata; @@ -698,7 +718,10 @@ static int sunxi_musb_probe(struct platform_device *pdev) return -EINVAL; } pdata.platform_ops = &sunxi_musb_ops; - pdata.config = &sunxi_musb_hdrc_config; + if (!of_device_is_compatible(np, "allwinner,sun8i-h3-musb")) + pdata.config = &sunxi_musb_hdrc_config; + else + pdata.config = &sunxi_musb_hdrc_config_h3; glue->dev = &pdev->dev; INIT_WORK(&glue->work, sunxi_musb_work); @@ -710,7 +733,8 @@ static int sunxi_musb_probe(struct platform_device *pdev) if (of_device_is_compatible(np, "allwinner,sun6i-a31-musb")) set_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags); - if (of_device_is_compatible(np, "allwinner,sun8i-a33-musb")) { + if (of_device_is_compatible(np, "allwinner,sun8i-a33-musb") || + of_device_is_compatible(np, "allwinner,sun8i-h3-musb")) { set_bit(SUNXI_MUSB_FL_HAS_RESET, &glue->flags); set_bit(SUNXI_MUSB_FL_NO_CONFIGDATA, &glue->flags); } @@ -804,6 +828,7 @@ static const struct of_device_id sunxi_musb_match[] = { { .compatible = "allwinner,sun4i-a10-musb", }, { .compatible = "allwinner,sun6i-a31-musb", }, { .compatible = "allwinner,sun8i-a33-musb", }, + { .compatible = "allwinner,sun8i-h3-musb", }, {} }; MODULE_DEVICE_TABLE(of, sunxi_musb_match); diff --git a/drivers/usb/musb/tusb6010_omap.c b/drivers/usb/musb/tusb6010_omap.c index e6959ccb4453..8b43c4b99f04 100644 --- a/drivers/usb/musb/tusb6010_omap.c +++ b/drivers/usb/musb/tusb6010_omap.c @@ -56,7 +56,6 @@ struct tusb_omap_dma_ch { struct tusb_omap_dma { struct dma_controller controller; - struct musb *musb; void __iomem *tbase; int ch; @@ -497,7 +496,7 @@ tusb_omap_dma_allocate(struct dma_controller *c, u32 reg; tusb_dma = container_of(c, struct tusb_omap_dma, controller); - musb = tusb_dma->musb; + musb = tusb_dma->controller.musb; tbase = musb->ctrl_base; reg = musb_readl(tbase, TUSB_DMA_INT_MASK); @@ -534,7 +533,7 @@ tusb_omap_dma_allocate(struct dma_controller *c, dev_name = "TUSB receive"; } - chdat->musb = tusb_dma->musb; + chdat->musb = tusb_dma->controller.musb; chdat->tbase = tusb_dma->tbase; chdat->hw_ep = hw_ep; chdat->epnum = hw_ep->epnum; @@ -667,7 +666,7 @@ tusb_dma_controller_create(struct musb *musb, void __iomem *base) if (!tusb_dma) goto out; - tusb_dma->musb = musb; + tusb_dma->controller.musb = musb; tusb_dma->tbase = musb->ctrl_base; tusb_dma->ch = -1; diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index 3eaa4ba6867d..5a572500c418 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -30,7 +30,7 @@ #include "musb_core.h" -static struct musb_hdrc_config ux500_musb_hdrc_config = { +static const struct musb_hdrc_config ux500_musb_hdrc_config = { .multipoint = true, .dyn_fifo = true, .num_eps = 16, diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c index a03caf4b1327..61bf2285d5b1 100644 --- a/drivers/usb/phy/phy-ab8500-usb.c +++ b/drivers/usb/phy/phy-ab8500-usb.c @@ -1023,38 +1023,6 @@ static void ab8500_usb_vbus_turn_on_event_work(struct work_struct *work) ab->enabled_charging_detection = true; } -static unsigned ab8500_eyediagram_workaroud(struct ab8500_usb *ab, unsigned mA) -{ - /* - * AB8500 V2 has eye diagram issues when drawing more than 100mA from - * VBUS. Set charging current to 100mA in case of standard host - */ - if (is_ab8500_2p0_or_earlier(ab->ab8500)) - if (mA > 100) - mA = 100; - - return mA; -} - -static int ab8500_usb_set_power(struct usb_phy *phy, unsigned mA) -{ - struct ab8500_usb *ab; - - if (!phy) - return -ENODEV; - - ab = phy_to_ab(phy); - - mA = ab8500_eyediagram_workaroud(ab, mA); - - ab->vbus_draw = mA; - - atomic_notifier_call_chain(&ab->phy.notifier, - UX500_MUSB_VBUS, &ab->vbus_draw); - - return 0; -} - static int ab8500_usb_set_suspend(struct usb_phy *x, int suspend) { /* TODO */ @@ -1392,7 +1360,6 @@ static int ab8500_usb_probe(struct platform_device *pdev) ab->phy.otg = otg; ab->phy.label = "ab8500"; ab->phy.set_suspend = ab8500_usb_set_suspend; - ab->phy.set_power = ab8500_usb_set_power; ab->phy.otg->state = OTG_STATE_UNDEFINED; otg->usb_phy = &ab->phy; diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c index 94eb2923afed..392ab422163c 100644 --- a/drivers/usb/phy/phy-fsl-usb.c +++ b/drivers/usb/phy/phy-fsl-usb.c @@ -642,17 +642,6 @@ static int fsl_otg_set_peripheral(struct usb_otg *otg, return 0; } -/* Set OTG port power, only for B-device */ -static int fsl_otg_set_power(struct usb_phy *phy, unsigned mA) -{ - if (!fsl_otg_dev) - return -ENODEV; - if (phy->otg->state == OTG_STATE_B_PERIPHERAL) - pr_info("FSL OTG: Draw %d mA\n", mA); - - return 0; -} - /* * Delayed pin detect interrupt processing. * @@ -821,7 +810,6 @@ static int fsl_otg_conf(struct platform_device *pdev) /* initialize the otg structure */ fsl_otg_tc->phy.label = DRIVER_DESC; fsl_otg_tc->phy.dev = &pdev->dev; - fsl_otg_tc->phy.set_power = fsl_otg_set_power; fsl_otg_tc->phy.otg->usb_phy = &fsl_otg_tc->phy; fsl_otg_tc->phy.otg->set_host = fsl_otg_set_host; diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 8a34759727bb..93d9aaad2994 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -842,23 +842,6 @@ static void msm_otg_notify_charger(struct msm_otg *motg, unsigned mA) motg->cur_power = mA; } -static int msm_otg_set_power(struct usb_phy *phy, unsigned mA) -{ - struct msm_otg *motg = container_of(phy, struct msm_otg, phy); - - /* - * Gadget driver uses set_power method to notify about the - * available current based on suspend/configured states. - * - * IDEV_CHG can be drawn irrespective of suspend/un-configured - * states when CDP/ACA is connected. - */ - if (motg->chg_type == USB_SDP_CHARGER) - msm_otg_notify_charger(motg, mA); - - return 0; -} - static void msm_otg_start_host(struct usb_phy *phy, int on) { struct msm_otg *motg = container_of(phy, struct msm_otg, phy); @@ -1742,14 +1725,14 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg) if (!IS_ERR(ext_vbus)) { motg->vbus.extcon = ext_vbus; motg->vbus.nb.notifier_call = msm_otg_vbus_notifier; - ret = extcon_register_notifier(ext_vbus, EXTCON_USB, - &motg->vbus.nb); + ret = devm_extcon_register_notifier(&pdev->dev, ext_vbus, + EXTCON_USB, &motg->vbus.nb); if (ret < 0) { dev_err(&pdev->dev, "register VBUS notifier failed\n"); return ret; } - ret = extcon_get_cable_state_(ext_vbus, EXTCON_USB); + ret = extcon_get_state(ext_vbus, EXTCON_USB); if (ret) set_bit(B_SESS_VLD, &motg->inputs); else @@ -1759,16 +1742,14 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg) if (!IS_ERR(ext_id)) { motg->id.extcon = ext_id; motg->id.nb.notifier_call = msm_otg_id_notifier; - ret = extcon_register_notifier(ext_id, EXTCON_USB_HOST, - &motg->id.nb); + ret = devm_extcon_register_notifier(&pdev->dev, ext_id, + EXTCON_USB_HOST, &motg->id.nb); if (ret < 0) { dev_err(&pdev->dev, "register ID notifier failed\n"); - extcon_unregister_notifier(motg->vbus.extcon, - EXTCON_USB, &motg->vbus.nb); return ret; } - ret = extcon_get_cable_state_(ext_id, EXTCON_USB_HOST); + ret = extcon_get_state(ext_id, EXTCON_USB_HOST); if (ret) clear_bit(ID, &motg->inputs); else @@ -1883,10 +1864,9 @@ static int msm_otg_probe(struct platform_device *pdev) */ if (motg->phy_number) { phy_select = devm_ioremap_nocache(&pdev->dev, USB2_PHY_SEL, 4); - if (!phy_select) { - ret = -ENOMEM; - goto unregister_extcon; - } + if (!phy_select) + return -ENOMEM; + /* Enable second PHY with the OTG port */ writel(0x1, phy_select); } @@ -1897,7 +1877,7 @@ static int msm_otg_probe(struct platform_device *pdev) if (motg->irq < 0) { dev_err(&pdev->dev, "platform_get_irq failed\n"); ret = motg->irq; - goto unregister_extcon; + return motg->irq; } regs[0].supply = "vddcx"; @@ -1906,7 +1886,7 @@ static int msm_otg_probe(struct platform_device *pdev) ret = devm_regulator_bulk_get(motg->phy.dev, ARRAY_SIZE(regs), regs); if (ret) - goto unregister_extcon; + return ret; motg->vddcx = regs[0].consumer; motg->v3p3 = regs[1].consumer; @@ -1950,7 +1930,6 @@ static int msm_otg_probe(struct platform_device *pdev) } phy->init = msm_phy_init; - phy->set_power = msm_otg_set_power; phy->notify_disconnect = msm_phy_notify_disconnect; phy->type = USB_PHY_TYPE_USB2; @@ -2003,11 +1982,6 @@ disable_clks: clk_disable_unprepare(motg->clk); if (!IS_ERR(motg->core_clk)) clk_disable_unprepare(motg->core_clk); -unregister_extcon: - extcon_unregister_notifier(motg->id.extcon, - EXTCON_USB_HOST, &motg->id.nb); - extcon_unregister_notifier(motg->vbus.extcon, - EXTCON_USB, &motg->vbus.nb); return ret; } @@ -2029,9 +2003,6 @@ static int msm_otg_remove(struct platform_device *pdev) */ gpiod_set_value_cansleep(motg->switch_gpio, 0); - extcon_unregister_notifier(motg->id.extcon, EXTCON_USB_HOST, &motg->id.nb); - extcon_unregister_notifier(motg->vbus.extcon, EXTCON_USB, &motg->vbus.nb); - msm_otg_debugfs_cleanup(); cancel_delayed_work_sync(&motg->chg_work); cancel_work_sync(&motg->sm_work); diff --git a/drivers/usb/phy/phy-omap-otg.c b/drivers/usb/phy/phy-omap-otg.c index 6523af4f8f93..800d1d90753d 100644 --- a/drivers/usb/phy/phy-omap-otg.c +++ b/drivers/usb/phy/phy-omap-otg.c @@ -118,19 +118,19 @@ static int omap_otg_probe(struct platform_device *pdev) otg_dev->id_nb.notifier_call = omap_otg_id_notifier; otg_dev->vbus_nb.notifier_call = omap_otg_vbus_notifier; - ret = extcon_register_notifier(extcon, EXTCON_USB_HOST, &otg_dev->id_nb); + ret = devm_extcon_register_notifier(&pdev->dev, extcon, + EXTCON_USB_HOST, &otg_dev->id_nb); if (ret) return ret; - ret = extcon_register_notifier(extcon, EXTCON_USB, &otg_dev->vbus_nb); + ret = devm_extcon_register_notifier(&pdev->dev, extcon, + EXTCON_USB, &otg_dev->vbus_nb); if (ret) { - extcon_unregister_notifier(extcon, EXTCON_USB_HOST, - &otg_dev->id_nb); return ret; } - otg_dev->id = extcon_get_cable_state_(extcon, EXTCON_USB_HOST); - otg_dev->vbus = extcon_get_cable_state_(extcon, EXTCON_USB); + otg_dev->id = extcon_get_state(extcon, EXTCON_USB_HOST); + otg_dev->vbus = extcon_get_state(extcon, EXTCON_USB); omap_otg_set_mode(otg_dev); rev = readl(otg_dev->base); @@ -145,20 +145,8 @@ static int omap_otg_probe(struct platform_device *pdev) return 0; } -static int omap_otg_remove(struct platform_device *pdev) -{ - struct otg_device *otg_dev = platform_get_drvdata(pdev); - struct extcon_dev *edev = otg_dev->extcon; - - extcon_unregister_notifier(edev, EXTCON_USB_HOST, &otg_dev->id_nb); - extcon_unregister_notifier(edev, EXTCON_USB, &otg_dev->vbus_nb); - - return 0; -} - static struct platform_driver omap_otg_driver = { .probe = omap_otg_probe, - .remove = omap_otg_remove, .driver = { .name = "omap_otg", }, diff --git a/drivers/usb/phy/phy-qcom-8x16-usb.c b/drivers/usb/phy/phy-qcom-8x16-usb.c index d8593adb3621..fdf686398772 100644 --- a/drivers/usb/phy/phy-qcom-8x16-usb.c +++ b/drivers/usb/phy/phy-qcom-8x16-usb.c @@ -187,7 +187,7 @@ static int phy_8x16_init(struct usb_phy *phy) val = ULPI_PWR_OTG_COMP_DISABLE; usb_phy_io_write(phy, val, ULPI_SET(ULPI_PWR_CLK_MNG_REG)); - state = extcon_get_cable_state_(qphy->vbus_edev, EXTCON_USB); + state = extcon_get_state(qphy->vbus_edev, EXTCON_USB); if (state) phy_8x16_vbus_on(qphy); else @@ -316,23 +316,20 @@ static int phy_8x16_probe(struct platform_device *pdev) goto off_clks; qphy->vbus_notify.notifier_call = phy_8x16_vbus_notify; - ret = extcon_register_notifier(qphy->vbus_edev, EXTCON_USB, - &qphy->vbus_notify); + ret = devm_extcon_register_notifier(&pdev->dev, qphy->vbus_edev, + EXTCON_USB, &qphy->vbus_notify); if (ret < 0) goto off_power; ret = usb_add_phy_dev(&qphy->phy); if (ret) - goto off_extcon; + goto off_power; qphy->reboot_notify.notifier_call = phy_8x16_reboot_notify; register_reboot_notifier(&qphy->reboot_notify); return 0; -off_extcon: - extcon_unregister_notifier(qphy->vbus_edev, EXTCON_USB, - &qphy->vbus_notify); off_power: regulator_bulk_disable(ARRAY_SIZE(qphy->regulator), qphy->regulator); off_clks: @@ -347,8 +344,6 @@ static int phy_8x16_remove(struct platform_device *pdev) struct phy_8x16 *qphy = platform_get_drvdata(pdev); unregister_reboot_notifier(&qphy->reboot_notify); - extcon_unregister_notifier(qphy->vbus_edev, EXTCON_USB, - &qphy->vbus_notify); /* * Ensure that D+/D- lines are routed to uB connector, so diff --git a/drivers/usb/phy/phy-tahvo.c b/drivers/usb/phy/phy-tahvo.c index ab5d364f6e8c..a31c8682e998 100644 --- a/drivers/usb/phy/phy-tahvo.c +++ b/drivers/usb/phy/phy-tahvo.c @@ -121,7 +121,7 @@ static void check_vbus_state(struct tahvo_usb *tu) prev_state = tu->vbus_state; tu->vbus_state = reg & TAHVO_STAT_VBUS; if (prev_state != tu->vbus_state) { - extcon_set_cable_state_(tu->extcon, EXTCON_USB, tu->vbus_state); + extcon_set_state_sync(tu->extcon, EXTCON_USB, tu->vbus_state); sysfs_notify(&tu->pt_dev->dev.kobj, NULL, "vbus_state"); } } @@ -130,7 +130,7 @@ static void tahvo_usb_become_host(struct tahvo_usb *tu) { struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent); - extcon_set_cable_state_(tu->extcon, EXTCON_USB_HOST, true); + extcon_set_state_sync(tu->extcon, EXTCON_USB_HOST, true); /* Power up the transceiver in USB host mode */ retu_write(rdev, TAHVO_REG_USBR, USBR_REGOUT | USBR_NSUSPEND | @@ -149,7 +149,7 @@ static void tahvo_usb_become_peripheral(struct tahvo_usb *tu) { struct retu_dev *rdev = dev_get_drvdata(tu->pt_dev->dev.parent); - extcon_set_cable_state_(tu->extcon, EXTCON_USB_HOST, false); + extcon_set_state_sync(tu->extcon, EXTCON_USB_HOST, false); /* Power up transceiver and set it in USB peripheral mode */ retu_write(rdev, TAHVO_REG_USBR, USBR_SLAVE_CONTROL | USBR_REGOUT | @@ -379,9 +379,9 @@ static int tahvo_usb_probe(struct platform_device *pdev) } /* Set the initial cable state. */ - extcon_set_cable_state_(tu->extcon, EXTCON_USB_HOST, + extcon_set_state_sync(tu->extcon, EXTCON_USB_HOST, tu->tahvo_mode == TAHVO_MODE_HOST); - extcon_set_cable_state_(tu->extcon, EXTCON_USB, tu->vbus_state); + extcon_set_state_sync(tu->extcon, EXTCON_USB, tu->vbus_state); /* Create OTG interface */ tahvo_usb_power_off(tu); diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 012a37aa3e0d..623c51300393 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -389,7 +389,7 @@ static void usbhsc_hotplug(struct usbhs_priv *priv) if (enable && !mod) { if (priv->edev) { - cable = extcon_get_cable_state_(priv->edev, EXTCON_USB_HOST); + cable = extcon_get_state(priv->edev, EXTCON_USB_HOST); if ((cable > 0 && id != USBHS_HOST) || (!cable && id != USBHS_GADGET)) { dev_info(&pdev->dev, diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c index 165e81bfd93a..dfb346e9bd0c 100644 --- a/drivers/usb/renesas_usbhs/mod_host.c +++ b/drivers/usb/renesas_usbhs/mod_host.c @@ -577,7 +577,7 @@ static struct usbhsh_device *usbhsh_device_attach(struct usbhsh_hpriv *hpriv, upphub = usbhsh_device_number(hpriv, parent); hubport = usbhsh_device_hubport(udev); - dev_dbg(dev, "%s connecte to Hub [%d:%d](%p)\n", __func__, + dev_dbg(dev, "%s connected to Hub [%d:%d](%p)\n", __func__, upphub, hubport, parent); } diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index d9bc8dafe000..a8d5f2e4878d 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -713,6 +713,15 @@ config USB_SERIAL_QT2 To compile this driver as a module, choose M here: the module will be called quatech-serial. +config USB_SERIAL_UPD78F0730 + tristate "USB Renesas uPD78F0730 Single Port Serial Driver" + help + Say Y here if you want to use the Renesas uPD78F0730 + serial driver. + + To compile this driver as a module, choose M here: the + module will be called upd78f0730. + config USB_SERIAL_DEBUG tristate "USB Debugging Device" help diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index 9e43b7b002eb..5a21a82390e1 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -56,6 +56,7 @@ obj-$(CONFIG_USB_SERIAL_SSU100) += ssu100.o obj-$(CONFIG_USB_SERIAL_SYMBOL) += symbolserial.o obj-$(CONFIG_USB_SERIAL_WWAN) += usb_wwan.o obj-$(CONFIG_USB_SERIAL_TI) += ti_usb_3410_5052.o +obj-$(CONFIG_USB_SERIAL_UPD78F0730) += upd78f0730.o obj-$(CONFIG_USB_SERIAL_VISOR) += visor.o obj-$(CONFIG_USB_SERIAL_WISHBONE) += wishbone-serial.o obj-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat.o diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index 1532cde8a437..2779e59c30f1 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -99,10 +99,17 @@ static int ark3116_read_reg(struct usb_serial *serial, usb_rcvctrlpipe(serial->dev, 0), 0xfe, 0xc0, 0, reg, buf, 1, ARK_TIMEOUT); - if (result < 0) + if (result < 1) { + dev_err(&serial->interface->dev, + "failed to read register %u: %d\n", + reg, result); + if (result >= 0) + result = -EIO; + return result; - else - return buf[0]; + } + + return buf[0]; } static inline int calc_divisor(int bps) @@ -118,17 +125,11 @@ static inline int calc_divisor(int bps) static int ark3116_attach(struct usb_serial *serial) { /* make sure we have our end-points */ - if ((serial->num_bulk_in == 0) || - (serial->num_bulk_out == 0) || - (serial->num_interrupt_in == 0)) { - dev_err(&serial->dev->dev, - "%s - missing endpoint - " - "bulk in: %d, bulk out: %d, int in %d\n", - KBUILD_MODNAME, - serial->num_bulk_in, - serial->num_bulk_out, - serial->num_interrupt_in); - return -EINVAL; + if (serial->num_bulk_in == 0 || + serial->num_bulk_out == 0 || + serial->num_interrupt_in == 0) { + dev_err(&serial->interface->dev, "missing endpoint\n"); + return -ENODEV; } return 0; @@ -186,10 +187,8 @@ static int ark3116_port_probe(struct usb_serial_port *port) if (priv->irda) ark3116_write_reg(serial, 0x9, 0); - dev_info(&serial->dev->dev, - "%s using %s mode\n", - KBUILD_MODNAME, - priv->irda ? "IrDA" : "RS232"); + dev_info(&port->dev, "using %s mode\n", priv->irda ? "IrDA" : "RS232"); + return 0; } @@ -325,9 +324,8 @@ static void ark3116_set_termios(struct tty_struct *tty, /* check for software flow control */ if (I_IXOFF(tty) || I_IXON(tty)) { - dev_warn(&serial->dev->dev, - "%s: don't know how to do software flow control\n", - KBUILD_MODNAME); + dev_warn(&port->dev, + "software flow control not implemented\n"); } /* Don't rewrite B0 */ @@ -346,8 +344,8 @@ static void ark3116_close(struct usb_serial_port *port) ark3116_write_reg(serial, UART_IER, 0); usb_serial_generic_close(port); - if (serial->num_interrupt_in) - usb_kill_urb(port->interrupt_in_urb); + + usb_kill_urb(port->interrupt_in_urb); } static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port) @@ -366,23 +364,29 @@ static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port) dev_dbg(&port->dev, "%s - usb_serial_generic_open failed: %d\n", __func__, result); - goto err_out; + goto err_free; } /* remove any data still left: also clears error state */ ark3116_read_reg(serial, UART_RX, buf); /* read modem status */ - priv->msr = ark3116_read_reg(serial, UART_MSR, buf); + result = ark3116_read_reg(serial, UART_MSR, buf); + if (result < 0) + goto err_close; + priv->msr = *buf; + /* read line status */ - priv->lsr = ark3116_read_reg(serial, UART_LSR, buf); + result = ark3116_read_reg(serial, UART_LSR, buf); + if (result < 0) + goto err_close; + priv->lsr = *buf; result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result) { dev_err(&port->dev, "submit irq_in urb failed %d\n", result); - ark3116_close(port); - goto err_out; + goto err_close; } /* activate interrupts */ @@ -395,8 +399,15 @@ static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port) if (tty) ark3116_set_termios(tty, port, NULL); -err_out: kfree(buf); + + return 0; + +err_close: + usb_serial_generic_close(port); +err_free: + kfree(buf); + return result; } @@ -602,9 +613,8 @@ static void ark3116_read_int_callback(struct urb *urb) result = usb_submit_urb(urb, GFP_ATOMIC); if (result) - dev_err(&urb->dev->dev, - "%s - Error %d submitting interrupt urb\n", - __func__, result); + dev_err(&port->dev, "failed to resubmit interrupt urb: %d\n", + result); } diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index 95aa5233726c..351745aec0e1 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -93,8 +93,8 @@ MODULE_DEVICE_TABLE(usb, id_table); struct ch341_private { spinlock_t lock; /* access lock */ unsigned baud_rate; /* set baud rate */ - u8 line_control; /* set line control value RTS/DTR */ - u8 line_status; /* active status of modem control inputs */ + u8 mcr; + u8 msr; u8 lcr; }; @@ -107,8 +107,8 @@ static int ch341_control_out(struct usb_device *dev, u8 request, { int r; - dev_dbg(&dev->dev, "ch341_control_out(%02x,%02x,%04x,%04x)\n", - USB_DIR_OUT|0x40, (int)request, (int)value, (int)index); + dev_dbg(&dev->dev, "%s - (%02x,%04x,%04x)\n", __func__, + request, value, index); r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, @@ -125,9 +125,8 @@ static int ch341_control_in(struct usb_device *dev, { int r; - dev_dbg(&dev->dev, "ch341_control_in(%02x,%02x,%04x,%04x,%p,%u)\n", - USB_DIR_IN|0x40, (int)request, (int)value, (int)index, buf, - (int)bufsize); + dev_dbg(&dev->dev, "%s - (%02x,%04x,%04x,%u)\n", __func__, + request, value, index, bufsize); r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, @@ -210,7 +209,7 @@ static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv) goto out; spin_lock_irqsave(&priv->lock, flags); - priv->line_status = (~(*buffer)) & CH341_BITS_MODEM_STAT; + priv->msr = (~(*buffer)) & CH341_BITS_MODEM_STAT; spin_unlock_irqrestore(&priv->lock, flags); out: kfree(buffer); @@ -239,30 +238,11 @@ static int ch341_configure(struct usb_device *dev, struct ch341_private *priv) if (r < 0) goto out; - /* expect two bytes 0x56 0x00 */ - r = ch341_control_in(dev, CH341_REQ_READ_REG, 0x2518, 0, buffer, size); - if (r < 0) - goto out; - - r = ch341_control_out(dev, CH341_REQ_WRITE_REG, 0x2518, 0x0050); - if (r < 0) - goto out; - - /* expect 0xff 0xee */ - r = ch341_get_status(dev, priv); - if (r < 0) - goto out; - r = ch341_set_baudrate_lcr(dev, priv, priv->lcr); if (r < 0) goto out; - r = ch341_set_handshake(dev, priv->line_control); - if (r < 0) - goto out; - - /* expect 0x9f 0xee */ - r = ch341_get_status(dev, priv); + r = ch341_set_handshake(dev, priv->mcr); out: kfree(buffer); return r; @@ -279,6 +259,11 @@ static int ch341_port_probe(struct usb_serial_port *port) spin_lock_init(&priv->lock); priv->baud_rate = DEFAULT_BAUD_RATE; + /* + * Some CH340 devices appear unable to change the initial LCR + * settings, so set a sane 8N1 default. + */ + priv->lcr = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX | CH341_LCR_CS8; r = ch341_configure(port->serial->dev, priv); if (r < 0) @@ -304,7 +289,7 @@ static int ch341_port_remove(struct usb_serial_port *port) static int ch341_carrier_raised(struct usb_serial_port *port) { struct ch341_private *priv = usb_get_serial_port_data(port); - if (priv->line_status & CH341_BIT_DCD) + if (priv->msr & CH341_BIT_DCD) return 1; return 0; } @@ -317,11 +302,11 @@ static void ch341_dtr_rts(struct usb_serial_port *port, int on) /* drop DTR and RTS */ spin_lock_irqsave(&priv->lock, flags); if (on) - priv->line_control |= CH341_BIT_RTS | CH341_BIT_DTR; + priv->mcr |= CH341_BIT_RTS | CH341_BIT_DTR; else - priv->line_control &= ~(CH341_BIT_RTS | CH341_BIT_DTR); + priv->mcr &= ~(CH341_BIT_RTS | CH341_BIT_DTR); spin_unlock_irqrestore(&priv->lock, flags); - ch341_set_handshake(port->serial->dev, priv->line_control); + ch341_set_handshake(port->serial->dev, priv->mcr); } static void ch341_close(struct usb_serial_port *port) @@ -334,14 +319,9 @@ static void ch341_close(struct usb_serial_port *port) /* open this device, set default parameters */ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port) { - struct usb_serial *serial = port->serial; struct ch341_private *priv = usb_get_serial_port_data(port); int r; - r = ch341_configure(serial->dev, priv); - if (r) - return r; - if (tty) ch341_set_termios(tty, port, NULL); @@ -353,6 +333,12 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port) return r; } + r = ch341_get_status(port->serial->dev, priv); + if (r < 0) { + dev_err(&port->dev, "failed to read modem status: %d\n", r); + goto err_kill_interrupt_urb; + } + r = usb_serial_generic_open(tty, port); if (r) goto err_kill_interrupt_urb; @@ -374,7 +360,7 @@ static void ch341_set_termios(struct tty_struct *tty, struct ch341_private *priv = usb_get_serial_port_data(port); unsigned baud_rate; unsigned long flags; - unsigned char ctrl; + u8 lcr; int r; /* redundant changes may cause the chip to lose bytes */ @@ -383,54 +369,54 @@ static void ch341_set_termios(struct tty_struct *tty, baud_rate = tty_get_baud_rate(tty); - ctrl = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX; + lcr = CH341_LCR_ENABLE_RX | CH341_LCR_ENABLE_TX; switch (C_CSIZE(tty)) { case CS5: - ctrl |= CH341_LCR_CS5; + lcr |= CH341_LCR_CS5; break; case CS6: - ctrl |= CH341_LCR_CS6; + lcr |= CH341_LCR_CS6; break; case CS7: - ctrl |= CH341_LCR_CS7; + lcr |= CH341_LCR_CS7; break; case CS8: - ctrl |= CH341_LCR_CS8; + lcr |= CH341_LCR_CS8; break; } if (C_PARENB(tty)) { - ctrl |= CH341_LCR_ENABLE_PAR; + lcr |= CH341_LCR_ENABLE_PAR; if (C_PARODD(tty) == 0) - ctrl |= CH341_LCR_PAR_EVEN; + lcr |= CH341_LCR_PAR_EVEN; if (C_CMSPAR(tty)) - ctrl |= CH341_LCR_MARK_SPACE; + lcr |= CH341_LCR_MARK_SPACE; } if (C_CSTOPB(tty)) - ctrl |= CH341_LCR_STOP_BITS_2; + lcr |= CH341_LCR_STOP_BITS_2; if (baud_rate) { priv->baud_rate = baud_rate; - r = ch341_set_baudrate_lcr(port->serial->dev, priv, ctrl); + r = ch341_set_baudrate_lcr(port->serial->dev, priv, lcr); if (r < 0 && old_termios) { priv->baud_rate = tty_termios_baud_rate(old_termios); tty_termios_copy_hw(&tty->termios, old_termios); } else if (r == 0) { - priv->lcr = ctrl; + priv->lcr = lcr; } } spin_lock_irqsave(&priv->lock, flags); if (C_BAUD(tty) == B0) - priv->line_control &= ~(CH341_BIT_DTR | CH341_BIT_RTS); + priv->mcr &= ~(CH341_BIT_DTR | CH341_BIT_RTS); else if (old_termios && (old_termios->c_cflag & CBAUD) == B0) - priv->line_control |= (CH341_BIT_DTR | CH341_BIT_RTS); + priv->mcr |= (CH341_BIT_DTR | CH341_BIT_RTS); spin_unlock_irqrestore(&priv->lock, flags); - ch341_set_handshake(port->serial->dev, priv->line_control); + ch341_set_handshake(port->serial->dev, priv->mcr); } static void ch341_break_ctl(struct tty_struct *tty, int break_state) @@ -486,20 +472,20 @@ static int ch341_tiocmset(struct tty_struct *tty, spin_lock_irqsave(&priv->lock, flags); if (set & TIOCM_RTS) - priv->line_control |= CH341_BIT_RTS; + priv->mcr |= CH341_BIT_RTS; if (set & TIOCM_DTR) - priv->line_control |= CH341_BIT_DTR; + priv->mcr |= CH341_BIT_DTR; if (clear & TIOCM_RTS) - priv->line_control &= ~CH341_BIT_RTS; + priv->mcr &= ~CH341_BIT_RTS; if (clear & TIOCM_DTR) - priv->line_control &= ~CH341_BIT_DTR; - control = priv->line_control; + priv->mcr &= ~CH341_BIT_DTR; + control = priv->mcr; spin_unlock_irqrestore(&priv->lock, flags); return ch341_set_handshake(port->serial->dev, control); } -static void ch341_update_line_status(struct usb_serial_port *port, +static void ch341_update_status(struct usb_serial_port *port, unsigned char *data, size_t len) { struct ch341_private *priv = usb_get_serial_port_data(port); @@ -514,8 +500,8 @@ static void ch341_update_line_status(struct usb_serial_port *port, status = ~data[2] & CH341_BITS_MODEM_STAT; spin_lock_irqsave(&priv->lock, flags); - delta = status ^ priv->line_status; - priv->line_status = status; + delta = status ^ priv->msr; + priv->msr = status; spin_unlock_irqrestore(&priv->lock, flags); if (data[1] & CH341_MULT_STAT) @@ -568,7 +554,7 @@ static void ch341_read_int_callback(struct urb *urb) } usb_serial_debug_data(&port->dev, __func__, len, data); - ch341_update_line_status(port, data, len); + ch341_update_status(port, data, len); exit: status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { @@ -587,8 +573,8 @@ static int ch341_tiocmget(struct tty_struct *tty) unsigned int result; spin_lock_irqsave(&priv->lock, flags); - mcr = priv->line_control; - status = priv->line_status; + mcr = priv->mcr; + status = priv->msr; spin_unlock_irqrestore(&priv->lock, flags); result = ((mcr & CH341_BIT_DTR) ? TIOCM_DTR : 0) @@ -619,6 +605,12 @@ static int ch341_reset_resume(struct usb_serial *serial) ret); return ret; } + + ret = ch341_get_status(port->serial->dev, priv); + if (ret < 0) { + dev_err(&port->dev, "failed to read modem status: %d\n", + ret); + } } return usb_serial_generic_resume(serial); diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c index 8967715fe6fc..fdf89800ebc3 100644 --- a/drivers/usb/serial/console.c +++ b/drivers/usb/serial/console.c @@ -143,6 +143,7 @@ static int usb_console_setup(struct console *co, char *options) tty->driver = usb_serial_tty_driver; tty->index = co->index; init_ldsem(&tty->ldisc_sem); + spin_lock_init(&tty->files_lock); INIT_LIST_HEAD(&tty->tty_files); kref_get(&tty->driver->kref); __module_get(tty->driver->owner); @@ -264,8 +265,7 @@ static struct console usbcons = { void usb_serial_console_disconnect(struct usb_serial *serial) { - if (serial && serial->port && serial->port[0] - && serial->port[0] == usbcons_info.port) { + if (serial->port[0] == usbcons_info.port) { usb_serial_console_exit(); usb_serial_put(serial); } diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index 5d61d0871f2e..0c55e7f64269 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -178,6 +178,8 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(0x1901, 0x0190) }, /* GE B850 CP2105 Recorder interface */ { USB_DEVICE(0x1901, 0x0193) }, /* GE B650 CP2104 PMC interface */ { USB_DEVICE(0x1901, 0x0194) }, /* GE Healthcare Remote Alarm Box */ + { USB_DEVICE(0x1901, 0x0195) }, /* GE B850/B650/B450 CP2104 DP UART interface */ + { USB_DEVICE(0x1901, 0x0196) }, /* GE B850 CP2105 DP UART interface */ { USB_DEVICE(0x19CF, 0x3000) }, /* Parrot NMEA GPS Flight Recorder */ { USB_DEVICE(0x1ADB, 0x0001) }, /* Schweitzer Engineering C662 Cable */ { USB_DEVICE(0x1B1C, 0x1C00) }, /* Corsair USB Dongle */ diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index bbeeb2bd55a8..90110de715e0 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -1069,7 +1069,6 @@ static void cypress_read_int_callback(struct urb *urb) unsigned char *data = urb->transfer_buffer; unsigned long flags; char tty_flag = TTY_NORMAL; - int havedata = 0; int bytes = 0; int result; int i = 0; @@ -1118,16 +1117,12 @@ static void cypress_read_int_callback(struct urb *urb) priv->current_status = data[0] & 0xF8; bytes = data[1] + 2; i = 2; - if (bytes > 2) - havedata = 1; break; case packet_format_2: /* This is for the CY7C63743... */ priv->current_status = data[0] & 0xF8; bytes = (data[0] & 0x07) + 1; i = 1; - if (bytes > 1) - havedata = 1; break; } spin_unlock_irqrestore(&priv->lock, flags); diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 6a1df9e824ca..eb433922598c 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -1398,25 +1398,30 @@ static int digi_read_inb_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; struct digi_port *priv = usb_get_serial_port_data(port); - int opcode = ((unsigned char *)urb->transfer_buffer)[0]; - int len = ((unsigned char *)urb->transfer_buffer)[1]; - int port_status = ((unsigned char *)urb->transfer_buffer)[2]; - unsigned char *data = ((unsigned char *)urb->transfer_buffer) + 3; + unsigned char *buf = urb->transfer_buffer; + int opcode; + int len; + int port_status; + unsigned char *data; int flag, throttled; - int status = urb->status; - - /* do not process callbacks on closed ports */ - /* but do continue the read chain */ - if (urb->status == -ENOENT) - return 0; /* short/multiple packet check */ + if (urb->actual_length < 2) { + dev_warn(&port->dev, "short packet received\n"); + return -1; + } + + opcode = buf[0]; + len = buf[1]; + if (urb->actual_length != len + 2) { - dev_err(&port->dev, "%s: INCOMPLETE OR MULTIPLE PACKET, " - "status=%d, port=%d, opcode=%d, len=%d, " - "actual_length=%d, status=%d\n", __func__, status, - priv->dp_port_num, opcode, len, urb->actual_length, - port_status); + dev_err(&port->dev, "malformed packet received: port=%d, opcode=%d, len=%d, actual_length=%u\n", + priv->dp_port_num, opcode, len, urb->actual_length); + return -1; + } + + if (opcode == DIGI_CMD_RECEIVE_DATA && len < 1) { + dev_err(&port->dev, "malformed data packet received\n"); return -1; } @@ -1430,6 +1435,9 @@ static int digi_read_inb_callback(struct urb *urb) /* receive data */ if (opcode == DIGI_CMD_RECEIVE_DATA) { + port_status = buf[2]; + data = &buf[3]; + /* get flag from port_status */ flag = 0; @@ -1482,16 +1490,20 @@ static int digi_read_oob_callback(struct urb *urb) struct usb_serial *serial = port->serial; struct tty_struct *tty; struct digi_port *priv = usb_get_serial_port_data(port); + unsigned char *buf = urb->transfer_buffer; int opcode, line, status, val; int i; unsigned int rts; + if (urb->actual_length < 4) + return -1; + /* handle each oob command */ - for (i = 0; i < urb->actual_length - 3;) { - opcode = ((unsigned char *)urb->transfer_buffer)[i++]; - line = ((unsigned char *)urb->transfer_buffer)[i++]; - status = ((unsigned char *)urb->transfer_buffer)[i++]; - val = ((unsigned char *)urb->transfer_buffer)[i++]; + for (i = 0; i < urb->actual_length - 4; i += 4) { + opcode = buf[i]; + line = buf[i + 1]; + status = buf[i + 2]; + val = buf[i + 3]; dev_dbg(&port->dev, "digi_read_oob_callback: opcode=%d, line=%d, status=%d, val=%d\n", opcode, line, status, val); diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 23d14b98ae2a..c540de15aad2 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1439,10 +1439,13 @@ static int read_latency_timer(struct usb_serial_port *port) FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE, 0, priv->interface, buf, 1, WDR_TIMEOUT); - if (rv < 0) + if (rv < 1) { dev_err(&port->dev, "Unable to read latency timer: %i\n", rv); - else + if (rv >= 0) + rv = -EIO; + } else { priv->latency = buf[0]; + } kfree(buf); @@ -1531,7 +1534,7 @@ check_and_exit: } static int get_lsr_info(struct usb_serial_port *port, - struct serial_struct __user *retinfo) + unsigned int __user *retinfo) { struct ftdi_private *priv = usb_get_serial_port_data(port); unsigned int result = 0; @@ -1802,8 +1805,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) mutex_init(&priv->cfg_lock); - priv->flags = ASYNC_LOW_LATENCY; - if (quirk && quirk->port_probe) quirk->port_probe(priv); @@ -2067,6 +2068,20 @@ static int ftdi_process_packet(struct usb_serial_port *port, priv->prev_status = status; } + /* save if the transmitter is empty or not */ + if (packet[1] & FTDI_RS_TEMT) + priv->transmit_empty = 1; + else + priv->transmit_empty = 0; + + len -= 2; + if (!len) + return 0; /* status only */ + + /* + * Break and error status must only be processed for packets with + * data payload to avoid over-reporting. + */ flag = TTY_NORMAL; if (packet[1] & FTDI_RS_ERR_MASK) { /* Break takes precedence over parity, which takes precedence @@ -2089,15 +2104,6 @@ static int ftdi_process_packet(struct usb_serial_port *port, } } - /* save if the transmitter is empty or not */ - if (packet[1] & FTDI_RS_TEMT) - priv->transmit_empty = 1; - else - priv->transmit_empty = 0; - - len -= 2; - if (!len) - return 0; /* status only */ port->icount.rx += len; ch = packet + 2; @@ -2428,8 +2434,12 @@ static int ftdi_get_modem_status(struct usb_serial_port *port, FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, 0, priv->interface, buf, len, WDR_TIMEOUT); - if (ret < 0) { + + /* NOTE: We allow short responses and handle that below. */ + if (ret < 1) { dev_err(&port->dev, "failed to get modem status: %d\n", ret); + if (ret >= 0) + ret = -EIO; ret = usb_translate_errors(ret); goto out; } @@ -2480,20 +2490,15 @@ static int ftdi_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct usb_serial_port *port = tty->driver_data; + void __user *argp = (void __user *)arg; - /* Based on code from acm.c and others */ switch (cmd) { - - case TIOCGSERIAL: /* gets serial port data */ - return get_serial_info(port, - (struct serial_struct __user *) arg); - - case TIOCSSERIAL: /* sets serial port data */ - return set_serial_info(tty, port, - (struct serial_struct __user *) arg); + case TIOCGSERIAL: + return get_serial_info(port, argp); + case TIOCSSERIAL: + return set_serial_info(tty, port, argp); case TIOCSERGETLSR: - return get_lsr_info(port, (struct serial_struct __user *)arg); - break; + return get_lsr_info(port, argp); default: break; } diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index d50e5773483f..bb7673e80a57 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -57,6 +57,88 @@ #define OPEN_TIMEOUT (5*HZ) /* 5 seconds */ +static const struct usb_device_id edgeport_2port_id_table[] = { + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_421) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_21) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2_DIN) }, + { } +}; + +static const struct usb_device_id edgeport_4port_id_table[] = { + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_RAPIDPORT_4) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4T) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_MT4X56USB) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8_DUAL_CPU) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4_DIN) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_22I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_4) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_COMPATIBLE) }, + { } +}; + +static const struct usb_device_id edgeport_8port_id_table[] = { + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8R) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8RR) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_8) }, + { } +}; + +static const struct usb_device_id Epic_port_id_table[] = { + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0311) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0312) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A758) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A794) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A225) }, + { } +}; + +/* Devices that this driver supports */ +static const struct usb_device_id id_table_combined[] = { + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_RAPIDPORT_4) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4T) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_MT4X56USB) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_421) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_21) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8_DUAL_CPU) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2_DIN) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4_DIN) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_22I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_4) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_COMPATIBLE) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8I) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8R) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8RR) }, + { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_8) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0311) }, + { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0312) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A758) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A794) }, + { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A225) }, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, id_table_combined); + + /* receive port state */ enum RXSTATE { EXPECT_HDR1 = 0, /* Expect header byte 1 */ @@ -217,8 +299,6 @@ static void edge_release(struct usb_serial *serial); static int edge_port_probe(struct usb_serial_port *port); static int edge_port_remove(struct usb_serial_port *port); -#include "io_tables.h" /* all of the devices that this driver supports */ - /* function prototypes for all of our local functions */ static void process_rcvd_data(struct edgeport_serial *edge_serial, @@ -492,20 +572,24 @@ static int get_epic_descriptor(struct edgeport_serial *ep) int result; struct usb_serial *serial = ep->serial; struct edgeport_product_info *product_info = &ep->product_info; - struct edge_compatibility_descriptor *epic = &ep->epic_descriptor; + struct edge_compatibility_descriptor *epic; struct edge_compatibility_bits *bits; struct device *dev = &serial->dev->dev; ep->is_epic = 0; + + epic = kmalloc(sizeof(*epic), GFP_KERNEL); + if (!epic) + return -ENOMEM; + result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), USB_REQUEST_ION_GET_EPIC_DESC, 0xC0, 0x00, 0x00, - &ep->epic_descriptor, - sizeof(struct edge_compatibility_descriptor), + epic, sizeof(*epic), 300); - - if (result > 0) { + if (result == sizeof(*epic)) { ep->is_epic = 1; + memcpy(&ep->epic_descriptor, epic, sizeof(*epic)); memset(product_info, 0, sizeof(struct edgeport_product_info)); product_info->NumPorts = epic->NumPorts; @@ -534,8 +618,16 @@ static int get_epic_descriptor(struct edgeport_serial *ep) dev_dbg(dev, " IOSPWriteLCR : %s\n", bits->IOSPWriteLCR ? "TRUE": "FALSE"); dev_dbg(dev, " IOSPSetBaudRate : %s\n", bits->IOSPSetBaudRate ? "TRUE": "FALSE"); dev_dbg(dev, " TrueEdgeport : %s\n", bits->TrueEdgeport ? "TRUE": "FALSE"); + + result = 0; + } else if (result >= 0) { + dev_warn(&serial->interface->dev, "short epic descriptor received: %d\n", + result); + result = -EIO; } + kfree(epic); + return result; } @@ -1560,7 +1652,6 @@ static int get_serial_info(struct edgeport_port *edge_port, tmp.line = edge_port->port->minor; tmp.port = edge_port->port->port_number; tmp.irq = 0; - tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; tmp.xmit_fifo_size = edge_port->maxTxCredits; tmp.baud_base = 9600; tmp.close_delay = 5*HZ; @@ -2090,8 +2181,7 @@ static int rom_write(struct usb_serial *serial, __u16 extAddr, __u16 addr, * rom_read * reads a number of bytes from the Edgeport device starting at the given * address. - * If successful returns the number of bytes read, otherwise it returns - * a negative error number of the problem. + * Returns zero on success or a negative error number. ****************************************************************************/ static int rom_read(struct usb_serial *serial, __u16 extAddr, __u16 addr, __u16 length, __u8 *data) @@ -2116,12 +2206,17 @@ static int rom_read(struct usb_serial *serial, __u16 extAddr, USB_REQUEST_ION_READ_ROM, 0xC0, addr, extAddr, transfer_buffer, current_length, 300); - if (result < 0) + if (result < current_length) { + if (result >= 0) + result = -EIO; break; + } memcpy(data, transfer_buffer, current_length); length -= current_length; addr += current_length; data += current_length; + + result = 0; } kfree(transfer_buffer); @@ -2575,9 +2670,10 @@ static void get_manufacturing_desc(struct edgeport_serial *edge_serial) EDGE_MANUF_DESC_LEN, (__u8 *)(&edge_serial->manuf_descriptor)); - if (response < 1) - dev_err(dev, "error in getting manufacturer descriptor\n"); - else { + if (response < 0) { + dev_err(dev, "error in getting manufacturer descriptor: %d\n", + response); + } else { char string[30]; dev_dbg(dev, "**Manufacturer Descriptor\n"); dev_dbg(dev, " RomSize: %dK\n", @@ -2634,9 +2730,10 @@ static void get_boot_desc(struct edgeport_serial *edge_serial) EDGE_BOOT_DESC_LEN, (__u8 *)(&edge_serial->boot_descriptor)); - if (response < 1) - dev_err(dev, "error in getting boot descriptor\n"); - else { + if (response < 0) { + dev_err(dev, "error in getting boot descriptor: %d\n", + response); + } else { dev_dbg(dev, "**Boot Descriptor:\n"); dev_dbg(dev, " BootCodeLength: %d\n", le16_to_cpu(edge_serial->boot_descriptor.BootCodeLength)); @@ -2779,7 +2876,7 @@ static int edge_startup(struct usb_serial *serial) dev_info(&serial->dev->dev, "%s detected\n", edge_serial->name); /* Read the epic descriptor */ - if (get_epic_descriptor(edge_serial) <= 0) { + if (get_epic_descriptor(edge_serial) < 0) { /* memcpy descriptor to Supports structures */ memcpy(&edge_serial->epic_descriptor.Supports, descriptor, sizeof(struct edge_compatibility_bits)); @@ -3015,6 +3112,139 @@ static int edge_port_remove(struct usb_serial_port *port) return 0; } +static struct usb_serial_driver edgeport_2port_device = { + .driver = { + .owner = THIS_MODULE, + .name = "edgeport_2", + }, + .description = "Edgeport 2 port adapter", + .id_table = edgeport_2port_id_table, + .num_ports = 2, + .open = edge_open, + .close = edge_close, + .throttle = edge_throttle, + .unthrottle = edge_unthrottle, + .attach = edge_startup, + .disconnect = edge_disconnect, + .release = edge_release, + .port_probe = edge_port_probe, + .port_remove = edge_port_remove, + .ioctl = edge_ioctl, + .set_termios = edge_set_termios, + .tiocmget = edge_tiocmget, + .tiocmset = edge_tiocmset, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, + .write = edge_write, + .write_room = edge_write_room, + .chars_in_buffer = edge_chars_in_buffer, + .break_ctl = edge_break, + .read_int_callback = edge_interrupt_callback, + .read_bulk_callback = edge_bulk_in_callback, + .write_bulk_callback = edge_bulk_out_data_callback, +}; + +static struct usb_serial_driver edgeport_4port_device = { + .driver = { + .owner = THIS_MODULE, + .name = "edgeport_4", + }, + .description = "Edgeport 4 port adapter", + .id_table = edgeport_4port_id_table, + .num_ports = 4, + .open = edge_open, + .close = edge_close, + .throttle = edge_throttle, + .unthrottle = edge_unthrottle, + .attach = edge_startup, + .disconnect = edge_disconnect, + .release = edge_release, + .port_probe = edge_port_probe, + .port_remove = edge_port_remove, + .ioctl = edge_ioctl, + .set_termios = edge_set_termios, + .tiocmget = edge_tiocmget, + .tiocmset = edge_tiocmset, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, + .write = edge_write, + .write_room = edge_write_room, + .chars_in_buffer = edge_chars_in_buffer, + .break_ctl = edge_break, + .read_int_callback = edge_interrupt_callback, + .read_bulk_callback = edge_bulk_in_callback, + .write_bulk_callback = edge_bulk_out_data_callback, +}; + +static struct usb_serial_driver edgeport_8port_device = { + .driver = { + .owner = THIS_MODULE, + .name = "edgeport_8", + }, + .description = "Edgeport 8 port adapter", + .id_table = edgeport_8port_id_table, + .num_ports = 8, + .open = edge_open, + .close = edge_close, + .throttle = edge_throttle, + .unthrottle = edge_unthrottle, + .attach = edge_startup, + .disconnect = edge_disconnect, + .release = edge_release, + .port_probe = edge_port_probe, + .port_remove = edge_port_remove, + .ioctl = edge_ioctl, + .set_termios = edge_set_termios, + .tiocmget = edge_tiocmget, + .tiocmset = edge_tiocmset, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, + .write = edge_write, + .write_room = edge_write_room, + .chars_in_buffer = edge_chars_in_buffer, + .break_ctl = edge_break, + .read_int_callback = edge_interrupt_callback, + .read_bulk_callback = edge_bulk_in_callback, + .write_bulk_callback = edge_bulk_out_data_callback, +}; + +static struct usb_serial_driver epic_device = { + .driver = { + .owner = THIS_MODULE, + .name = "epic", + }, + .description = "EPiC device", + .id_table = Epic_port_id_table, + .num_ports = 1, + .open = edge_open, + .close = edge_close, + .throttle = edge_throttle, + .unthrottle = edge_unthrottle, + .attach = edge_startup, + .disconnect = edge_disconnect, + .release = edge_release, + .port_probe = edge_port_probe, + .port_remove = edge_port_remove, + .ioctl = edge_ioctl, + .set_termios = edge_set_termios, + .tiocmget = edge_tiocmget, + .tiocmset = edge_tiocmset, + .tiocmiwait = usb_serial_generic_tiocmiwait, + .get_icount = usb_serial_generic_get_icount, + .write = edge_write, + .write_room = edge_write_room, + .chars_in_buffer = edge_chars_in_buffer, + .break_ctl = edge_break, + .read_int_callback = edge_interrupt_callback, + .read_bulk_callback = edge_bulk_in_callback, + .write_bulk_callback = edge_bulk_out_data_callback, +}; + +static struct usb_serial_driver * const serial_drivers[] = { + &edgeport_2port_device, &edgeport_4port_device, + &edgeport_8port_device, &epic_device, NULL +}; + module_usb_serial_driver(serial_drivers, id_table_combined); MODULE_AUTHOR(DRIVER_AUTHOR); diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h deleted file mode 100644 index ae5fac5656c9..000000000000 --- a/drivers/usb/serial/io_tables.h +++ /dev/null @@ -1,232 +0,0 @@ -/* - * IO Edgeport Driver tables - * - * Copyright (C) 2001 - * Greg Kroah-Hartman (greg@kroah.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. - * - */ - -#ifndef IO_TABLES_H -#define IO_TABLES_H - -static const struct usb_device_id edgeport_2port_id_table[] = { - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_421) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_21) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2_DIN) }, - { } -}; - -static const struct usb_device_id edgeport_4port_id_table[] = { - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_RAPIDPORT_4) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4T) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_MT4X56USB) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8_DUAL_CPU) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4_DIN) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_22I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_4) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_COMPATIBLE) }, - { } -}; - -static const struct usb_device_id edgeport_8port_id_table[] = { - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8R) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8RR) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_8) }, - { } -}; - -static const struct usb_device_id Epic_port_id_table[] = { - { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) }, - { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) }, - { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) }, - { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0311) }, - { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0312) }, - { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A758) }, - { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A794) }, - { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A225) }, - { } -}; - -/* Devices that this driver supports */ -static const struct usb_device_id id_table_combined[] = { - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_RAPIDPORT_4) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4T) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_MT4X56USB) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_421) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_21) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8_DUAL_CPU) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2_DIN) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4_DIN) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_22I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_4) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_COMPATIBLE) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8I) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8R) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8RR) }, - { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_8) }, - { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) }, - { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) }, - { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) }, - { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0311) }, - { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0312) }, - { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A758) }, - { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A794) }, - { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A225) }, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, id_table_combined); - -static struct usb_serial_driver edgeport_2port_device = { - .driver = { - .owner = THIS_MODULE, - .name = "edgeport_2", - }, - .description = "Edgeport 2 port adapter", - .id_table = edgeport_2port_id_table, - .num_ports = 2, - .open = edge_open, - .close = edge_close, - .throttle = edge_throttle, - .unthrottle = edge_unthrottle, - .attach = edge_startup, - .disconnect = edge_disconnect, - .release = edge_release, - .port_probe = edge_port_probe, - .port_remove = edge_port_remove, - .ioctl = edge_ioctl, - .set_termios = edge_set_termios, - .tiocmget = edge_tiocmget, - .tiocmset = edge_tiocmset, - .tiocmiwait = usb_serial_generic_tiocmiwait, - .get_icount = usb_serial_generic_get_icount, - .write = edge_write, - .write_room = edge_write_room, - .chars_in_buffer = edge_chars_in_buffer, - .break_ctl = edge_break, - .read_int_callback = edge_interrupt_callback, - .read_bulk_callback = edge_bulk_in_callback, - .write_bulk_callback = edge_bulk_out_data_callback, -}; - -static struct usb_serial_driver edgeport_4port_device = { - .driver = { - .owner = THIS_MODULE, - .name = "edgeport_4", - }, - .description = "Edgeport 4 port adapter", - .id_table = edgeport_4port_id_table, - .num_ports = 4, - .open = edge_open, - .close = edge_close, - .throttle = edge_throttle, - .unthrottle = edge_unthrottle, - .attach = edge_startup, - .disconnect = edge_disconnect, - .release = edge_release, - .port_probe = edge_port_probe, - .port_remove = edge_port_remove, - .ioctl = edge_ioctl, - .set_termios = edge_set_termios, - .tiocmget = edge_tiocmget, - .tiocmset = edge_tiocmset, - .tiocmiwait = usb_serial_generic_tiocmiwait, - .get_icount = usb_serial_generic_get_icount, - .write = edge_write, - .write_room = edge_write_room, - .chars_in_buffer = edge_chars_in_buffer, - .break_ctl = edge_break, - .read_int_callback = edge_interrupt_callback, - .read_bulk_callback = edge_bulk_in_callback, - .write_bulk_callback = edge_bulk_out_data_callback, -}; - -static struct usb_serial_driver edgeport_8port_device = { - .driver = { - .owner = THIS_MODULE, - .name = "edgeport_8", - }, - .description = "Edgeport 8 port adapter", - .id_table = edgeport_8port_id_table, - .num_ports = 8, - .open = edge_open, - .close = edge_close, - .throttle = edge_throttle, - .unthrottle = edge_unthrottle, - .attach = edge_startup, - .disconnect = edge_disconnect, - .release = edge_release, - .port_probe = edge_port_probe, - .port_remove = edge_port_remove, - .ioctl = edge_ioctl, - .set_termios = edge_set_termios, - .tiocmget = edge_tiocmget, - .tiocmset = edge_tiocmset, - .tiocmiwait = usb_serial_generic_tiocmiwait, - .get_icount = usb_serial_generic_get_icount, - .write = edge_write, - .write_room = edge_write_room, - .chars_in_buffer = edge_chars_in_buffer, - .break_ctl = edge_break, - .read_int_callback = edge_interrupt_callback, - .read_bulk_callback = edge_bulk_in_callback, - .write_bulk_callback = edge_bulk_out_data_callback, -}; - -static struct usb_serial_driver epic_device = { - .driver = { - .owner = THIS_MODULE, - .name = "epic", - }, - .description = "EPiC device", - .id_table = Epic_port_id_table, - .num_ports = 1, - .open = edge_open, - .close = edge_close, - .throttle = edge_throttle, - .unthrottle = edge_unthrottle, - .attach = edge_startup, - .disconnect = edge_disconnect, - .release = edge_release, - .port_probe = edge_port_probe, - .port_remove = edge_port_remove, - .ioctl = edge_ioctl, - .set_termios = edge_set_termios, - .tiocmget = edge_tiocmget, - .tiocmset = edge_tiocmset, - .tiocmiwait = usb_serial_generic_tiocmiwait, - .get_icount = usb_serial_generic_get_icount, - .write = edge_write, - .write_room = edge_write_room, - .chars_in_buffer = edge_chars_in_buffer, - .break_ctl = edge_break, - .read_int_callback = edge_interrupt_callback, - .read_bulk_callback = edge_bulk_in_callback, - .write_bulk_callback = edge_bulk_out_data_callback, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &edgeport_2port_device, &edgeport_4port_device, - &edgeport_8port_device, &epic_device, NULL -}; - -#endif - diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 9a0db2965fbb..ceaeebaa6f90 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -2468,7 +2468,6 @@ static int get_serial_info(struct edgeport_port *edge_port, tmp.line = edge_port->port->minor; tmp.port = edge_port->port->port_number; tmp.irq = 0; - tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; tmp.xmit_fifo_size = edge_port->port->bulk_out_size; tmp.baud_base = 9600; tmp.close_delay = 5*HZ; diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index d57fb5199218..030390f37b0a 100644 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c @@ -976,7 +976,6 @@ static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port) { struct usb_serial *serial = port->serial; struct device *dev = &port->dev; - u8 *buf; int result; int baud; u32 actual; @@ -991,20 +990,8 @@ static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port) usb_clear_halt(serial->dev, port->write_urb->pipe); usb_clear_halt(serial->dev, port->read_urb->pipe); - buf = kmalloc(10, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - priv->poll = 0; - /* initialize writebuf */ -#define FISH(a, b, c, d) do { \ - result = usb_control_msg(port->serial->dev, \ - usb_rcvctrlpipe(port->serial->dev, 0), \ - b, a, c, d, buf, 1, 1000); \ - dev_dbg(dev, "0x%x:0x%x:0x%x:0x%x %d - %x\n", a, b, c, d, result, \ - buf[0]); } while (0); - #define SOUP(a, b, c, d) do { \ result = usb_control_msg(port->serial->dev, \ usb_sndctrlpipe(port->serial->dev, 0), \ @@ -1017,7 +1004,7 @@ static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port) /* sprintf(buf ,"%c%c%c%c",0x03,0x02,0x02,0x0); */ SOUP(0x03, 0x02, 0x02, 0x0); - kfree(buf); + iuu_led(port, 0xF000, 0xF000, 0, 0xFF); iuu_uart_on(port); if (boost < 100) diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 1f9414bdd649..5662d324edd2 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -41,11 +41,508 @@ #include <linux/usb.h> #include <linux/usb/serial.h> #include <linux/usb/ezusb.h> -#include "keyspan.h" #define DRIVER_AUTHOR "Hugh Blemings <hugh@misc.nu" #define DRIVER_DESC "Keyspan USB to Serial Converter Driver" +/* Function prototypes for Keyspan serial converter */ +static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port); +static void keyspan_close(struct usb_serial_port *port); +static void keyspan_dtr_rts(struct usb_serial_port *port, int on); +static int keyspan_startup(struct usb_serial *serial); +static void keyspan_disconnect(struct usb_serial *serial); +static void keyspan_release(struct usb_serial *serial); +static int keyspan_port_probe(struct usb_serial_port *port); +static int keyspan_port_remove(struct usb_serial_port *port); +static int keyspan_write_room(struct tty_struct *tty); +static int keyspan_write(struct tty_struct *tty, struct usb_serial_port *port, + const unsigned char *buf, int count); +static void keyspan_send_setup(struct usb_serial_port *port, int reset_port); +static void keyspan_set_termios(struct tty_struct *tty, + struct usb_serial_port *port, + struct ktermios *old); +static void keyspan_break_ctl(struct tty_struct *tty, int break_state); +static int keyspan_tiocmget(struct tty_struct *tty); +static int keyspan_tiocmset(struct tty_struct *tty, unsigned int set, + unsigned int clear); +static int keyspan_fake_startup(struct usb_serial *serial); + +static int keyspan_usa19_calc_baud(struct usb_serial_port *port, + u32 baud_rate, u32 baudclk, + u8 *rate_hi, u8 *rate_low, + u8 *prescaler, int portnum); +static int keyspan_usa19w_calc_baud(struct usb_serial_port *port, + u32 baud_rate, u32 baudclk, + u8 *rate_hi, u8 *rate_low, + u8 *prescaler, int portnum); +static int keyspan_usa28_calc_baud(struct usb_serial_port *port, + u32 baud_rate, u32 baudclk, + u8 *rate_hi, u8 *rate_low, + u8 *prescaler, int portnum); +static int keyspan_usa19hs_calc_baud(struct usb_serial_port *port, + u32 baud_rate, u32 baudclk, + u8 *rate_hi, u8 *rate_low, + u8 *prescaler, int portnum); + +static int keyspan_usa28_send_setup(struct usb_serial *serial, + struct usb_serial_port *port, + int reset_port); +static int keyspan_usa26_send_setup(struct usb_serial *serial, + struct usb_serial_port *port, + int reset_port); +static int keyspan_usa49_send_setup(struct usb_serial *serial, + struct usb_serial_port *port, + int reset_port); +static int keyspan_usa90_send_setup(struct usb_serial *serial, + struct usb_serial_port *port, + int reset_port); +static int keyspan_usa67_send_setup(struct usb_serial *serial, + struct usb_serial_port *port, + int reset_port); + +/* Values used for baud rate calculation - device specific */ +#define KEYSPAN_INVALID_BAUD_RATE (-1) +#define KEYSPAN_BAUD_RATE_OK (0) +#define KEYSPAN_USA18X_BAUDCLK (12000000L) /* a guess */ +#define KEYSPAN_USA19_BAUDCLK (12000000L) +#define KEYSPAN_USA19W_BAUDCLK (24000000L) +#define KEYSPAN_USA19HS_BAUDCLK (14769231L) +#define KEYSPAN_USA28_BAUDCLK (1843200L) +#define KEYSPAN_USA28X_BAUDCLK (12000000L) +#define KEYSPAN_USA49W_BAUDCLK (48000000L) + +/* Some constants used to characterise each device. */ +#define KEYSPAN_MAX_NUM_PORTS (4) +#define KEYSPAN_MAX_FLIPS (2) + +/* + * Device info for the Keyspan serial converter, used by the overall + * usb-serial probe function. + */ +#define KEYSPAN_VENDOR_ID (0x06cd) + +/* Product IDs for the products supported, pre-renumeration */ +#define keyspan_usa18x_pre_product_id 0x0105 +#define keyspan_usa19_pre_product_id 0x0103 +#define keyspan_usa19qi_pre_product_id 0x010b +#define keyspan_mpr_pre_product_id 0x011b +#define keyspan_usa19qw_pre_product_id 0x0118 +#define keyspan_usa19w_pre_product_id 0x0106 +#define keyspan_usa28_pre_product_id 0x0101 +#define keyspan_usa28x_pre_product_id 0x0102 +#define keyspan_usa28xa_pre_product_id 0x0114 +#define keyspan_usa28xb_pre_product_id 0x0113 +#define keyspan_usa49w_pre_product_id 0x0109 +#define keyspan_usa49wlc_pre_product_id 0x011a + +/* + * Product IDs post-renumeration. Note that the 28x and 28xb have the same + * id's post-renumeration but behave identically so it's not an issue. As + * such, the 28xb is not listed in any of the device tables. + */ +#define keyspan_usa18x_product_id 0x0112 +#define keyspan_usa19_product_id 0x0107 +#define keyspan_usa19qi_product_id 0x010c +#define keyspan_usa19hs_product_id 0x0121 +#define keyspan_mpr_product_id 0x011c +#define keyspan_usa19qw_product_id 0x0119 +#define keyspan_usa19w_product_id 0x0108 +#define keyspan_usa28_product_id 0x010f +#define keyspan_usa28x_product_id 0x0110 +#define keyspan_usa28xa_product_id 0x0115 +#define keyspan_usa28xb_product_id 0x0110 +#define keyspan_usa28xg_product_id 0x0135 +#define keyspan_usa49w_product_id 0x010a +#define keyspan_usa49wlc_product_id 0x012a +#define keyspan_usa49wg_product_id 0x0131 + +struct keyspan_device_details { + /* product ID value */ + int product_id; + + enum {msg_usa26, msg_usa28, msg_usa49, msg_usa90, msg_usa67} msg_format; + + /* Number of physical ports */ + int num_ports; + + /* 1 if endpoint flipping used on input, 0 if not */ + int indat_endp_flip; + + /* 1 if endpoint flipping used on output, 0 if not */ + int outdat_endp_flip; + + /* + * Table mapping input data endpoint IDs to physical port + * number and flip if used + */ + int indat_endpoints[KEYSPAN_MAX_NUM_PORTS]; + + /* Same for output endpoints */ + int outdat_endpoints[KEYSPAN_MAX_NUM_PORTS]; + + /* Input acknowledge endpoints */ + int inack_endpoints[KEYSPAN_MAX_NUM_PORTS]; + + /* Output control endpoints */ + int outcont_endpoints[KEYSPAN_MAX_NUM_PORTS]; + + /* Endpoint used for input status */ + int instat_endpoint; + + /* Endpoint used for input data 49WG only */ + int indat_endpoint; + + /* Endpoint used for global control functions */ + int glocont_endpoint; + + int (*calculate_baud_rate)(struct usb_serial_port *port, + u32 baud_rate, u32 baudclk, + u8 *rate_hi, u8 *rate_low, u8 *prescaler, + int portnum); + u32 baudclk; +}; + +/* + * Now for each device type we setup the device detail structure with the + * appropriate information (provided in Keyspan's documentation) + */ + +static const struct keyspan_device_details usa18x_device_details = { + .product_id = keyspan_usa18x_product_id, + .msg_format = msg_usa26, + .num_ports = 1, + .indat_endp_flip = 0, + .outdat_endp_flip = 1, + .indat_endpoints = {0x81}, + .outdat_endpoints = {0x01}, + .inack_endpoints = {0x85}, + .outcont_endpoints = {0x05}, + .instat_endpoint = 0x87, + .indat_endpoint = -1, + .glocont_endpoint = 0x07, + .calculate_baud_rate = keyspan_usa19w_calc_baud, + .baudclk = KEYSPAN_USA18X_BAUDCLK, +}; + +static const struct keyspan_device_details usa19_device_details = { + .product_id = keyspan_usa19_product_id, + .msg_format = msg_usa28, + .num_ports = 1, + .indat_endp_flip = 1, + .outdat_endp_flip = 1, + .indat_endpoints = {0x81}, + .outdat_endpoints = {0x01}, + .inack_endpoints = {0x83}, + .outcont_endpoints = {0x03}, + .instat_endpoint = 0x84, + .indat_endpoint = -1, + .glocont_endpoint = -1, + .calculate_baud_rate = keyspan_usa19_calc_baud, + .baudclk = KEYSPAN_USA19_BAUDCLK, +}; + +static const struct keyspan_device_details usa19qi_device_details = { + .product_id = keyspan_usa19qi_product_id, + .msg_format = msg_usa28, + .num_ports = 1, + .indat_endp_flip = 1, + .outdat_endp_flip = 1, + .indat_endpoints = {0x81}, + .outdat_endpoints = {0x01}, + .inack_endpoints = {0x83}, + .outcont_endpoints = {0x03}, + .instat_endpoint = 0x84, + .indat_endpoint = -1, + .glocont_endpoint = -1, + .calculate_baud_rate = keyspan_usa28_calc_baud, + .baudclk = KEYSPAN_USA19_BAUDCLK, +}; + +static const struct keyspan_device_details mpr_device_details = { + .product_id = keyspan_mpr_product_id, + .msg_format = msg_usa28, + .num_ports = 1, + .indat_endp_flip = 1, + .outdat_endp_flip = 1, + .indat_endpoints = {0x81}, + .outdat_endpoints = {0x01}, + .inack_endpoints = {0x83}, + .outcont_endpoints = {0x03}, + .instat_endpoint = 0x84, + .indat_endpoint = -1, + .glocont_endpoint = -1, + .calculate_baud_rate = keyspan_usa28_calc_baud, + .baudclk = KEYSPAN_USA19_BAUDCLK, +}; + +static const struct keyspan_device_details usa19qw_device_details = { + .product_id = keyspan_usa19qw_product_id, + .msg_format = msg_usa26, + .num_ports = 1, + .indat_endp_flip = 0, + .outdat_endp_flip = 1, + .indat_endpoints = {0x81}, + .outdat_endpoints = {0x01}, + .inack_endpoints = {0x85}, + .outcont_endpoints = {0x05}, + .instat_endpoint = 0x87, + .indat_endpoint = -1, + .glocont_endpoint = 0x07, + .calculate_baud_rate = keyspan_usa19w_calc_baud, + .baudclk = KEYSPAN_USA19W_BAUDCLK, +}; + +static const struct keyspan_device_details usa19w_device_details = { + .product_id = keyspan_usa19w_product_id, + .msg_format = msg_usa26, + .num_ports = 1, + .indat_endp_flip = 0, + .outdat_endp_flip = 1, + .indat_endpoints = {0x81}, + .outdat_endpoints = {0x01}, + .inack_endpoints = {0x85}, + .outcont_endpoints = {0x05}, + .instat_endpoint = 0x87, + .indat_endpoint = -1, + .glocont_endpoint = 0x07, + .calculate_baud_rate = keyspan_usa19w_calc_baud, + .baudclk = KEYSPAN_USA19W_BAUDCLK, +}; + +static const struct keyspan_device_details usa19hs_device_details = { + .product_id = keyspan_usa19hs_product_id, + .msg_format = msg_usa90, + .num_ports = 1, + .indat_endp_flip = 0, + .outdat_endp_flip = 0, + .indat_endpoints = {0x81}, + .outdat_endpoints = {0x01}, + .inack_endpoints = {-1}, + .outcont_endpoints = {0x02}, + .instat_endpoint = 0x82, + .indat_endpoint = -1, + .glocont_endpoint = -1, + .calculate_baud_rate = keyspan_usa19hs_calc_baud, + .baudclk = KEYSPAN_USA19HS_BAUDCLK, +}; + +static const struct keyspan_device_details usa28_device_details = { + .product_id = keyspan_usa28_product_id, + .msg_format = msg_usa28, + .num_ports = 2, + .indat_endp_flip = 1, + .outdat_endp_flip = 1, + .indat_endpoints = {0x81, 0x83}, + .outdat_endpoints = {0x01, 0x03}, + .inack_endpoints = {0x85, 0x86}, + .outcont_endpoints = {0x05, 0x06}, + .instat_endpoint = 0x87, + .indat_endpoint = -1, + .glocont_endpoint = 0x07, + .calculate_baud_rate = keyspan_usa28_calc_baud, + .baudclk = KEYSPAN_USA28_BAUDCLK, +}; + +static const struct keyspan_device_details usa28x_device_details = { + .product_id = keyspan_usa28x_product_id, + .msg_format = msg_usa26, + .num_ports = 2, + .indat_endp_flip = 0, + .outdat_endp_flip = 1, + .indat_endpoints = {0x81, 0x83}, + .outdat_endpoints = {0x01, 0x03}, + .inack_endpoints = {0x85, 0x86}, + .outcont_endpoints = {0x05, 0x06}, + .instat_endpoint = 0x87, + .indat_endpoint = -1, + .glocont_endpoint = 0x07, + .calculate_baud_rate = keyspan_usa19w_calc_baud, + .baudclk = KEYSPAN_USA28X_BAUDCLK, +}; + +static const struct keyspan_device_details usa28xa_device_details = { + .product_id = keyspan_usa28xa_product_id, + .msg_format = msg_usa26, + .num_ports = 2, + .indat_endp_flip = 0, + .outdat_endp_flip = 1, + .indat_endpoints = {0x81, 0x83}, + .outdat_endpoints = {0x01, 0x03}, + .inack_endpoints = {0x85, 0x86}, + .outcont_endpoints = {0x05, 0x06}, + .instat_endpoint = 0x87, + .indat_endpoint = -1, + .glocont_endpoint = 0x07, + .calculate_baud_rate = keyspan_usa19w_calc_baud, + .baudclk = KEYSPAN_USA28X_BAUDCLK, +}; + +static const struct keyspan_device_details usa28xg_device_details = { + .product_id = keyspan_usa28xg_product_id, + .msg_format = msg_usa67, + .num_ports = 2, + .indat_endp_flip = 0, + .outdat_endp_flip = 0, + .indat_endpoints = {0x84, 0x88}, + .outdat_endpoints = {0x02, 0x06}, + .inack_endpoints = {-1, -1}, + .outcont_endpoints = {-1, -1}, + .instat_endpoint = 0x81, + .indat_endpoint = -1, + .glocont_endpoint = 0x01, + .calculate_baud_rate = keyspan_usa19w_calc_baud, + .baudclk = KEYSPAN_USA28X_BAUDCLK, +}; +/* + * We don't need a separate entry for the usa28xb as it appears as a 28x + * anyway. + */ + +static const struct keyspan_device_details usa49w_device_details = { + .product_id = keyspan_usa49w_product_id, + .msg_format = msg_usa49, + .num_ports = 4, + .indat_endp_flip = 0, + .outdat_endp_flip = 0, + .indat_endpoints = {0x81, 0x82, 0x83, 0x84}, + .outdat_endpoints = {0x01, 0x02, 0x03, 0x04}, + .inack_endpoints = {-1, -1, -1, -1}, + .outcont_endpoints = {-1, -1, -1, -1}, + .instat_endpoint = 0x87, + .indat_endpoint = -1, + .glocont_endpoint = 0x07, + .calculate_baud_rate = keyspan_usa19w_calc_baud, + .baudclk = KEYSPAN_USA49W_BAUDCLK, +}; + +static const struct keyspan_device_details usa49wlc_device_details = { + .product_id = keyspan_usa49wlc_product_id, + .msg_format = msg_usa49, + .num_ports = 4, + .indat_endp_flip = 0, + .outdat_endp_flip = 0, + .indat_endpoints = {0x81, 0x82, 0x83, 0x84}, + .outdat_endpoints = {0x01, 0x02, 0x03, 0x04}, + .inack_endpoints = {-1, -1, -1, -1}, + .outcont_endpoints = {-1, -1, -1, -1}, + .instat_endpoint = 0x87, + .indat_endpoint = -1, + .glocont_endpoint = 0x07, + .calculate_baud_rate = keyspan_usa19w_calc_baud, + .baudclk = KEYSPAN_USA19W_BAUDCLK, +}; + +static const struct keyspan_device_details usa49wg_device_details = { + .product_id = keyspan_usa49wg_product_id, + .msg_format = msg_usa49, + .num_ports = 4, + .indat_endp_flip = 0, + .outdat_endp_flip = 0, + .indat_endpoints = {-1, -1, -1, -1}, /* single 'global' data in EP */ + .outdat_endpoints = {0x01, 0x02, 0x04, 0x06}, + .inack_endpoints = {-1, -1, -1, -1}, + .outcont_endpoints = {-1, -1, -1, -1}, + .instat_endpoint = 0x81, + .indat_endpoint = 0x88, + .glocont_endpoint = 0x00, /* uses control EP */ + .calculate_baud_rate = keyspan_usa19w_calc_baud, + .baudclk = KEYSPAN_USA19W_BAUDCLK, +}; + +static const struct keyspan_device_details *keyspan_devices[] = { + &usa18x_device_details, + &usa19_device_details, + &usa19qi_device_details, + &mpr_device_details, + &usa19qw_device_details, + &usa19w_device_details, + &usa19hs_device_details, + &usa28_device_details, + &usa28x_device_details, + &usa28xa_device_details, + &usa28xg_device_details, + /* 28xb not required as it renumerates as a 28x */ + &usa49w_device_details, + &usa49wlc_device_details, + &usa49wg_device_details, + NULL, +}; + +static const struct usb_device_id keyspan_ids_combined[] = { + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19hs_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xg_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id)}, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)}, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wg_product_id)}, + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, keyspan_ids_combined); + +/* usb_device_id table for the pre-firmware download keyspan devices */ +static const struct usb_device_id keyspan_pre_ids[] = { + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_pre_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_pre_product_id) }, + { } /* Terminating entry */ +}; + +static const struct usb_device_id keyspan_1port_ids[] = { + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19hs_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_product_id) }, + { } /* Terminating entry */ +}; + +static const struct usb_device_id keyspan_2port_ids[] = { + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xg_product_id) }, + { } /* Terminating entry */ +}; + +static const struct usb_device_id keyspan_4port_ids[] = { + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id) }, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)}, + { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wg_product_id)}, + { } /* Terminating entry */ +}; + #define INSTAT_BUFLEN 32 #define GLOCONT_BUFLEN 64 #define INDAT49W_BUFLEN 512 @@ -126,8 +623,6 @@ struct keyspan_port_private { #include "keyspan_usa67msg.h" -module_usb_serial_driver(serial_drivers, keyspan_ids_combined); - static void keyspan_break_ctl(struct tty_struct *tty, int break_state) { struct usb_serial_port *port = tty->driver_data; @@ -2523,6 +3018,97 @@ static int keyspan_port_remove(struct usb_serial_port *port) return 0; } +/* Structs for the devices, pre and post renumeration. */ +static struct usb_serial_driver keyspan_pre_device = { + .driver = { + .owner = THIS_MODULE, + .name = "keyspan_no_firm", + }, + .description = "Keyspan - (without firmware)", + .id_table = keyspan_pre_ids, + .num_ports = 1, + .attach = keyspan_fake_startup, +}; + +static struct usb_serial_driver keyspan_1port_device = { + .driver = { + .owner = THIS_MODULE, + .name = "keyspan_1", + }, + .description = "Keyspan 1 port adapter", + .id_table = keyspan_1port_ids, + .num_ports = 1, + .open = keyspan_open, + .close = keyspan_close, + .dtr_rts = keyspan_dtr_rts, + .write = keyspan_write, + .write_room = keyspan_write_room, + .set_termios = keyspan_set_termios, + .break_ctl = keyspan_break_ctl, + .tiocmget = keyspan_tiocmget, + .tiocmset = keyspan_tiocmset, + .attach = keyspan_startup, + .disconnect = keyspan_disconnect, + .release = keyspan_release, + .port_probe = keyspan_port_probe, + .port_remove = keyspan_port_remove, +}; + +static struct usb_serial_driver keyspan_2port_device = { + .driver = { + .owner = THIS_MODULE, + .name = "keyspan_2", + }, + .description = "Keyspan 2 port adapter", + .id_table = keyspan_2port_ids, + .num_ports = 2, + .open = keyspan_open, + .close = keyspan_close, + .dtr_rts = keyspan_dtr_rts, + .write = keyspan_write, + .write_room = keyspan_write_room, + .set_termios = keyspan_set_termios, + .break_ctl = keyspan_break_ctl, + .tiocmget = keyspan_tiocmget, + .tiocmset = keyspan_tiocmset, + .attach = keyspan_startup, + .disconnect = keyspan_disconnect, + .release = keyspan_release, + .port_probe = keyspan_port_probe, + .port_remove = keyspan_port_remove, +}; + +static struct usb_serial_driver keyspan_4port_device = { + .driver = { + .owner = THIS_MODULE, + .name = "keyspan_4", + }, + .description = "Keyspan 4 port adapter", + .id_table = keyspan_4port_ids, + .num_ports = 4, + .open = keyspan_open, + .close = keyspan_close, + .dtr_rts = keyspan_dtr_rts, + .write = keyspan_write, + .write_room = keyspan_write_room, + .set_termios = keyspan_set_termios, + .break_ctl = keyspan_break_ctl, + .tiocmget = keyspan_tiocmget, + .tiocmset = keyspan_tiocmset, + .attach = keyspan_startup, + .disconnect = keyspan_disconnect, + .release = keyspan_release, + .port_probe = keyspan_port_probe, + .port_remove = keyspan_port_remove, +}; + +static struct usb_serial_driver * const serial_drivers[] = { + &keyspan_pre_device, &keyspan_1port_device, + &keyspan_2port_device, &keyspan_4port_device, NULL +}; + +module_usb_serial_driver(serial_drivers, keyspan_ids_combined); + MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h deleted file mode 100644 index 0273dda303a4..000000000000 --- a/drivers/usb/serial/keyspan.h +++ /dev/null @@ -1,629 +0,0 @@ -/* - Keyspan USB to Serial Converter driver - - (C) Copyright (C) 2000-2001 - Hugh Blemings <hugh@blemings.org> - - 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. - - See http://blemings.org/hugh/keyspan.html for more information. - - Code in this driver inspired by and in a number of places taken - from Brian Warner's original Keyspan-PDA driver. - - This driver has been put together with the support of Innosys, Inc. - and Keyspan, Inc the manufacturers of the Keyspan USB-serial products. - Thanks Guys :) - - Thanks to Paulus for miscellaneous tidy ups, some largish chunks - of much nicer and/or completely new code and (perhaps most uniquely) - having the patience to sit down and explain why and where he'd changed - stuff. - - Tip 'o the hat to IBM (and previously Linuxcare :) for supporting - staff in their work on open source projects. - - See keyspan.c for update history. - -*/ - -#ifndef __LINUX_USB_SERIAL_KEYSPAN_H -#define __LINUX_USB_SERIAL_KEYSPAN_H - - -/* Function prototypes for Keyspan serial converter */ -static int keyspan_open (struct tty_struct *tty, - struct usb_serial_port *port); -static void keyspan_close (struct usb_serial_port *port); -static void keyspan_dtr_rts (struct usb_serial_port *port, int on); -static int keyspan_startup (struct usb_serial *serial); -static void keyspan_disconnect (struct usb_serial *serial); -static void keyspan_release (struct usb_serial *serial); -static int keyspan_port_probe(struct usb_serial_port *port); -static int keyspan_port_remove(struct usb_serial_port *port); -static int keyspan_write_room (struct tty_struct *tty); - -static int keyspan_write (struct tty_struct *tty, - struct usb_serial_port *port, - const unsigned char *buf, - int count); - -static void keyspan_send_setup (struct usb_serial_port *port, - int reset_port); - - -static void keyspan_set_termios (struct tty_struct *tty, - struct usb_serial_port *port, - struct ktermios *old); -static void keyspan_break_ctl (struct tty_struct *tty, - int break_state); -static int keyspan_tiocmget (struct tty_struct *tty); -static int keyspan_tiocmset (struct tty_struct *tty, - unsigned int set, - unsigned int clear); -static int keyspan_fake_startup (struct usb_serial *serial); - -static int keyspan_usa19_calc_baud (struct usb_serial_port *port, - u32 baud_rate, u32 baudclk, - u8 *rate_hi, u8 *rate_low, - u8 *prescaler, int portnum); - -static int keyspan_usa19w_calc_baud (struct usb_serial_port *port, - u32 baud_rate, u32 baudclk, - u8 *rate_hi, u8 *rate_low, - u8 *prescaler, int portnum); - -static int keyspan_usa28_calc_baud (struct usb_serial_port *port, - u32 baud_rate, u32 baudclk, - u8 *rate_hi, u8 *rate_low, - u8 *prescaler, int portnum); - -static int keyspan_usa19hs_calc_baud (struct usb_serial_port *port, - u32 baud_rate, u32 baudclk, - u8 *rate_hi, u8 *rate_low, - u8 *prescaler, int portnum); - -static int keyspan_usa28_send_setup (struct usb_serial *serial, - struct usb_serial_port *port, - int reset_port); -static int keyspan_usa26_send_setup (struct usb_serial *serial, - struct usb_serial_port *port, - int reset_port); -static int keyspan_usa49_send_setup (struct usb_serial *serial, - struct usb_serial_port *port, - int reset_port); - -static int keyspan_usa90_send_setup (struct usb_serial *serial, - struct usb_serial_port *port, - int reset_port); - -static int keyspan_usa67_send_setup (struct usb_serial *serial, - struct usb_serial_port *port, - int reset_port); - -/* Values used for baud rate calculation - device specific */ -#define KEYSPAN_INVALID_BAUD_RATE (-1) -#define KEYSPAN_BAUD_RATE_OK (0) -#define KEYSPAN_USA18X_BAUDCLK (12000000L) /* a guess */ -#define KEYSPAN_USA19_BAUDCLK (12000000L) -#define KEYSPAN_USA19W_BAUDCLK (24000000L) -#define KEYSPAN_USA19HS_BAUDCLK (14769231L) -#define KEYSPAN_USA28_BAUDCLK (1843200L) -#define KEYSPAN_USA28X_BAUDCLK (12000000L) -#define KEYSPAN_USA49W_BAUDCLK (48000000L) - -/* Some constants used to characterise each device. */ -#define KEYSPAN_MAX_NUM_PORTS (4) -#define KEYSPAN_MAX_FLIPS (2) - -/* Device info for the Keyspan serial converter, used - by the overall usb-serial probe function */ -#define KEYSPAN_VENDOR_ID (0x06cd) - -/* Product IDs for the products supported, pre-renumeration */ -#define keyspan_usa18x_pre_product_id 0x0105 -#define keyspan_usa19_pre_product_id 0x0103 -#define keyspan_usa19qi_pre_product_id 0x010b -#define keyspan_mpr_pre_product_id 0x011b -#define keyspan_usa19qw_pre_product_id 0x0118 -#define keyspan_usa19w_pre_product_id 0x0106 -#define keyspan_usa28_pre_product_id 0x0101 -#define keyspan_usa28x_pre_product_id 0x0102 -#define keyspan_usa28xa_pre_product_id 0x0114 -#define keyspan_usa28xb_pre_product_id 0x0113 -#define keyspan_usa49w_pre_product_id 0x0109 -#define keyspan_usa49wlc_pre_product_id 0x011a - -/* Product IDs post-renumeration. Note that the 28x and 28xb - have the same id's post-renumeration but behave identically - so it's not an issue. As such, the 28xb is not listed in any - of the device tables. */ -#define keyspan_usa18x_product_id 0x0112 -#define keyspan_usa19_product_id 0x0107 -#define keyspan_usa19qi_product_id 0x010c -#define keyspan_usa19hs_product_id 0x0121 -#define keyspan_mpr_product_id 0x011c -#define keyspan_usa19qw_product_id 0x0119 -#define keyspan_usa19w_product_id 0x0108 -#define keyspan_usa28_product_id 0x010f -#define keyspan_usa28x_product_id 0x0110 -#define keyspan_usa28xa_product_id 0x0115 -#define keyspan_usa28xb_product_id 0x0110 -#define keyspan_usa28xg_product_id 0x0135 -#define keyspan_usa49w_product_id 0x010a -#define keyspan_usa49wlc_product_id 0x012a -#define keyspan_usa49wg_product_id 0x0131 - -struct keyspan_device_details { - /* product ID value */ - int product_id; - - enum {msg_usa26, msg_usa28, msg_usa49, msg_usa90, msg_usa67} msg_format; - - /* Number of physical ports */ - int num_ports; - - /* 1 if endpoint flipping used on input, 0 if not */ - int indat_endp_flip; - - /* 1 if endpoint flipping used on output, 0 if not */ - int outdat_endp_flip; - - /* Table mapping input data endpoint IDs to physical - port number and flip if used */ - int indat_endpoints[KEYSPAN_MAX_NUM_PORTS]; - - /* Same for output endpoints */ - int outdat_endpoints[KEYSPAN_MAX_NUM_PORTS]; - - /* Input acknowledge endpoints */ - int inack_endpoints[KEYSPAN_MAX_NUM_PORTS]; - - /* Output control endpoints */ - int outcont_endpoints[KEYSPAN_MAX_NUM_PORTS]; - - /* Endpoint used for input status */ - int instat_endpoint; - - /* Endpoint used for input data 49WG only */ - int indat_endpoint; - - /* Endpoint used for global control functions */ - int glocont_endpoint; - - int (*calculate_baud_rate) (struct usb_serial_port *port, - u32 baud_rate, u32 baudclk, - u8 *rate_hi, u8 *rate_low, u8 *prescaler, int portnum); - u32 baudclk; -}; - -/* Now for each device type we setup the device detail - structure with the appropriate information (provided - in Keyspan's documentation) */ - -static const struct keyspan_device_details usa18x_device_details = { - .product_id = keyspan_usa18x_product_id, - .msg_format = msg_usa26, - .num_ports = 1, - .indat_endp_flip = 0, - .outdat_endp_flip = 1, - .indat_endpoints = {0x81}, - .outdat_endpoints = {0x01}, - .inack_endpoints = {0x85}, - .outcont_endpoints = {0x05}, - .instat_endpoint = 0x87, - .indat_endpoint = -1, - .glocont_endpoint = 0x07, - .calculate_baud_rate = keyspan_usa19w_calc_baud, - .baudclk = KEYSPAN_USA18X_BAUDCLK, -}; - -static const struct keyspan_device_details usa19_device_details = { - .product_id = keyspan_usa19_product_id, - .msg_format = msg_usa28, - .num_ports = 1, - .indat_endp_flip = 1, - .outdat_endp_flip = 1, - .indat_endpoints = {0x81}, - .outdat_endpoints = {0x01}, - .inack_endpoints = {0x83}, - .outcont_endpoints = {0x03}, - .instat_endpoint = 0x84, - .indat_endpoint = -1, - .glocont_endpoint = -1, - .calculate_baud_rate = keyspan_usa19_calc_baud, - .baudclk = KEYSPAN_USA19_BAUDCLK, -}; - -static const struct keyspan_device_details usa19qi_device_details = { - .product_id = keyspan_usa19qi_product_id, - .msg_format = msg_usa28, - .num_ports = 1, - .indat_endp_flip = 1, - .outdat_endp_flip = 1, - .indat_endpoints = {0x81}, - .outdat_endpoints = {0x01}, - .inack_endpoints = {0x83}, - .outcont_endpoints = {0x03}, - .instat_endpoint = 0x84, - .indat_endpoint = -1, - .glocont_endpoint = -1, - .calculate_baud_rate = keyspan_usa28_calc_baud, - .baudclk = KEYSPAN_USA19_BAUDCLK, -}; - -static const struct keyspan_device_details mpr_device_details = { - .product_id = keyspan_mpr_product_id, - .msg_format = msg_usa28, - .num_ports = 1, - .indat_endp_flip = 1, - .outdat_endp_flip = 1, - .indat_endpoints = {0x81}, - .outdat_endpoints = {0x01}, - .inack_endpoints = {0x83}, - .outcont_endpoints = {0x03}, - .instat_endpoint = 0x84, - .indat_endpoint = -1, - .glocont_endpoint = -1, - .calculate_baud_rate = keyspan_usa28_calc_baud, - .baudclk = KEYSPAN_USA19_BAUDCLK, -}; - -static const struct keyspan_device_details usa19qw_device_details = { - .product_id = keyspan_usa19qw_product_id, - .msg_format = msg_usa26, - .num_ports = 1, - .indat_endp_flip = 0, - .outdat_endp_flip = 1, - .indat_endpoints = {0x81}, - .outdat_endpoints = {0x01}, - .inack_endpoints = {0x85}, - .outcont_endpoints = {0x05}, - .instat_endpoint = 0x87, - .indat_endpoint = -1, - .glocont_endpoint = 0x07, - .calculate_baud_rate = keyspan_usa19w_calc_baud, - .baudclk = KEYSPAN_USA19W_BAUDCLK, -}; - -static const struct keyspan_device_details usa19w_device_details = { - .product_id = keyspan_usa19w_product_id, - .msg_format = msg_usa26, - .num_ports = 1, - .indat_endp_flip = 0, - .outdat_endp_flip = 1, - .indat_endpoints = {0x81}, - .outdat_endpoints = {0x01}, - .inack_endpoints = {0x85}, - .outcont_endpoints = {0x05}, - .instat_endpoint = 0x87, - .indat_endpoint = -1, - .glocont_endpoint = 0x07, - .calculate_baud_rate = keyspan_usa19w_calc_baud, - .baudclk = KEYSPAN_USA19W_BAUDCLK, -}; - -static const struct keyspan_device_details usa19hs_device_details = { - .product_id = keyspan_usa19hs_product_id, - .msg_format = msg_usa90, - .num_ports = 1, - .indat_endp_flip = 0, - .outdat_endp_flip = 0, - .indat_endpoints = {0x81}, - .outdat_endpoints = {0x01}, - .inack_endpoints = {-1}, - .outcont_endpoints = {0x02}, - .instat_endpoint = 0x82, - .indat_endpoint = -1, - .glocont_endpoint = -1, - .calculate_baud_rate = keyspan_usa19hs_calc_baud, - .baudclk = KEYSPAN_USA19HS_BAUDCLK, -}; - -static const struct keyspan_device_details usa28_device_details = { - .product_id = keyspan_usa28_product_id, - .msg_format = msg_usa28, - .num_ports = 2, - .indat_endp_flip = 1, - .outdat_endp_flip = 1, - .indat_endpoints = {0x81, 0x83}, - .outdat_endpoints = {0x01, 0x03}, - .inack_endpoints = {0x85, 0x86}, - .outcont_endpoints = {0x05, 0x06}, - .instat_endpoint = 0x87, - .indat_endpoint = -1, - .glocont_endpoint = 0x07, - .calculate_baud_rate = keyspan_usa28_calc_baud, - .baudclk = KEYSPAN_USA28_BAUDCLK, -}; - -static const struct keyspan_device_details usa28x_device_details = { - .product_id = keyspan_usa28x_product_id, - .msg_format = msg_usa26, - .num_ports = 2, - .indat_endp_flip = 0, - .outdat_endp_flip = 1, - .indat_endpoints = {0x81, 0x83}, - .outdat_endpoints = {0x01, 0x03}, - .inack_endpoints = {0x85, 0x86}, - .outcont_endpoints = {0x05, 0x06}, - .instat_endpoint = 0x87, - .indat_endpoint = -1, - .glocont_endpoint = 0x07, - .calculate_baud_rate = keyspan_usa19w_calc_baud, - .baudclk = KEYSPAN_USA28X_BAUDCLK, -}; - -static const struct keyspan_device_details usa28xa_device_details = { - .product_id = keyspan_usa28xa_product_id, - .msg_format = msg_usa26, - .num_ports = 2, - .indat_endp_flip = 0, - .outdat_endp_flip = 1, - .indat_endpoints = {0x81, 0x83}, - .outdat_endpoints = {0x01, 0x03}, - .inack_endpoints = {0x85, 0x86}, - .outcont_endpoints = {0x05, 0x06}, - .instat_endpoint = 0x87, - .indat_endpoint = -1, - .glocont_endpoint = 0x07, - .calculate_baud_rate = keyspan_usa19w_calc_baud, - .baudclk = KEYSPAN_USA28X_BAUDCLK, -}; - -static const struct keyspan_device_details usa28xg_device_details = { - .product_id = keyspan_usa28xg_product_id, - .msg_format = msg_usa67, - .num_ports = 2, - .indat_endp_flip = 0, - .outdat_endp_flip = 0, - .indat_endpoints = {0x84, 0x88}, - .outdat_endpoints = {0x02, 0x06}, - .inack_endpoints = {-1, -1}, - .outcont_endpoints = {-1, -1}, - .instat_endpoint = 0x81, - .indat_endpoint = -1, - .glocont_endpoint = 0x01, - .calculate_baud_rate = keyspan_usa19w_calc_baud, - .baudclk = KEYSPAN_USA28X_BAUDCLK, -}; -/* We don't need a separate entry for the usa28xb as it appears as a 28x anyway */ - -static const struct keyspan_device_details usa49w_device_details = { - .product_id = keyspan_usa49w_product_id, - .msg_format = msg_usa49, - .num_ports = 4, - .indat_endp_flip = 0, - .outdat_endp_flip = 0, - .indat_endpoints = {0x81, 0x82, 0x83, 0x84}, - .outdat_endpoints = {0x01, 0x02, 0x03, 0x04}, - .inack_endpoints = {-1, -1, -1, -1}, - .outcont_endpoints = {-1, -1, -1, -1}, - .instat_endpoint = 0x87, - .indat_endpoint = -1, - .glocont_endpoint = 0x07, - .calculate_baud_rate = keyspan_usa19w_calc_baud, - .baudclk = KEYSPAN_USA49W_BAUDCLK, -}; - -static const struct keyspan_device_details usa49wlc_device_details = { - .product_id = keyspan_usa49wlc_product_id, - .msg_format = msg_usa49, - .num_ports = 4, - .indat_endp_flip = 0, - .outdat_endp_flip = 0, - .indat_endpoints = {0x81, 0x82, 0x83, 0x84}, - .outdat_endpoints = {0x01, 0x02, 0x03, 0x04}, - .inack_endpoints = {-1, -1, -1, -1}, - .outcont_endpoints = {-1, -1, -1, -1}, - .instat_endpoint = 0x87, - .indat_endpoint = -1, - .glocont_endpoint = 0x07, - .calculate_baud_rate = keyspan_usa19w_calc_baud, - .baudclk = KEYSPAN_USA19W_BAUDCLK, -}; - -static const struct keyspan_device_details usa49wg_device_details = { - .product_id = keyspan_usa49wg_product_id, - .msg_format = msg_usa49, - .num_ports = 4, - .indat_endp_flip = 0, - .outdat_endp_flip = 0, - .indat_endpoints = {-1, -1, -1, -1}, /* single 'global' data in EP */ - .outdat_endpoints = {0x01, 0x02, 0x04, 0x06}, - .inack_endpoints = {-1, -1, -1, -1}, - .outcont_endpoints = {-1, -1, -1, -1}, - .instat_endpoint = 0x81, - .indat_endpoint = 0x88, - .glocont_endpoint = 0x00, /* uses control EP */ - .calculate_baud_rate = keyspan_usa19w_calc_baud, - .baudclk = KEYSPAN_USA19W_BAUDCLK, -}; - -static const struct keyspan_device_details *keyspan_devices[] = { - &usa18x_device_details, - &usa19_device_details, - &usa19qi_device_details, - &mpr_device_details, - &usa19qw_device_details, - &usa19w_device_details, - &usa19hs_device_details, - &usa28_device_details, - &usa28x_device_details, - &usa28xa_device_details, - &usa28xg_device_details, - /* 28xb not required as it renumerates as a 28x */ - &usa49w_device_details, - &usa49wlc_device_details, - &usa49wg_device_details, - NULL, -}; - -static const struct usb_device_id keyspan_ids_combined[] = { - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19hs_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xg_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id)}, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)}, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wg_product_id)}, - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, keyspan_ids_combined); - -/* usb_device_id table for the pre-firmware download keyspan devices */ -static const struct usb_device_id keyspan_pre_ids[] = { - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_pre_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_pre_product_id) }, - { } /* Terminating entry */ -}; - -static const struct usb_device_id keyspan_1port_ids[] = { - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qw_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19hs_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_mpr_product_id) }, - { } /* Terminating entry */ -}; - -static const struct usb_device_id keyspan_2port_ids[] = { - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xg_product_id) }, - { } /* Terminating entry */ -}; - -static const struct usb_device_id keyspan_4port_ids[] = { - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id) }, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)}, - { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wg_product_id)}, - { } /* Terminating entry */ -}; - -/* Structs for the devices, pre and post renumeration. */ -static struct usb_serial_driver keyspan_pre_device = { - .driver = { - .owner = THIS_MODULE, - .name = "keyspan_no_firm", - }, - .description = "Keyspan - (without firmware)", - .id_table = keyspan_pre_ids, - .num_ports = 1, - .attach = keyspan_fake_startup, -}; - -static struct usb_serial_driver keyspan_1port_device = { - .driver = { - .owner = THIS_MODULE, - .name = "keyspan_1", - }, - .description = "Keyspan 1 port adapter", - .id_table = keyspan_1port_ids, - .num_ports = 1, - .open = keyspan_open, - .close = keyspan_close, - .dtr_rts = keyspan_dtr_rts, - .write = keyspan_write, - .write_room = keyspan_write_room, - .set_termios = keyspan_set_termios, - .break_ctl = keyspan_break_ctl, - .tiocmget = keyspan_tiocmget, - .tiocmset = keyspan_tiocmset, - .attach = keyspan_startup, - .disconnect = keyspan_disconnect, - .release = keyspan_release, - .port_probe = keyspan_port_probe, - .port_remove = keyspan_port_remove, -}; - -static struct usb_serial_driver keyspan_2port_device = { - .driver = { - .owner = THIS_MODULE, - .name = "keyspan_2", - }, - .description = "Keyspan 2 port adapter", - .id_table = keyspan_2port_ids, - .num_ports = 2, - .open = keyspan_open, - .close = keyspan_close, - .dtr_rts = keyspan_dtr_rts, - .write = keyspan_write, - .write_room = keyspan_write_room, - .set_termios = keyspan_set_termios, - .break_ctl = keyspan_break_ctl, - .tiocmget = keyspan_tiocmget, - .tiocmset = keyspan_tiocmset, - .attach = keyspan_startup, - .disconnect = keyspan_disconnect, - .release = keyspan_release, - .port_probe = keyspan_port_probe, - .port_remove = keyspan_port_remove, -}; - -static struct usb_serial_driver keyspan_4port_device = { - .driver = { - .owner = THIS_MODULE, - .name = "keyspan_4", - }, - .description = "Keyspan 4 port adapter", - .id_table = keyspan_4port_ids, - .num_ports = 4, - .open = keyspan_open, - .close = keyspan_close, - .dtr_rts = keyspan_dtr_rts, - .write = keyspan_write, - .write_room = keyspan_write_room, - .set_termios = keyspan_set_termios, - .break_ctl = keyspan_break_ctl, - .tiocmget = keyspan_tiocmget, - .tiocmset = keyspan_tiocmset, - .attach = keyspan_startup, - .disconnect = keyspan_disconnect, - .release = keyspan_release, - .port_probe = keyspan_port_probe, - .port_remove = keyspan_port_remove, -}; - -static struct usb_serial_driver * const serial_drivers[] = { - &keyspan_pre_device, &keyspan_1port_device, - &keyspan_2port_device, &keyspan_4port_device, NULL -}; - -#endif diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 83523fcf6fb9..d2dab2a341b8 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -139,6 +139,7 @@ static void keyspan_pda_rx_interrupt(struct urb *urb) { struct usb_serial_port *port = urb->context; unsigned char *data = urb->transfer_buffer; + unsigned int len = urb->actual_length; int retval; int status = urb->status; struct keyspan_pda_private *priv; @@ -159,18 +160,26 @@ static void keyspan_pda_rx_interrupt(struct urb *urb) goto exit; } + if (len < 1) { + dev_warn(&port->dev, "short message received\n"); + goto exit; + } + /* see if the message is data or a status interrupt */ switch (data[0]) { case 0: /* rest of message is rx data */ - if (urb->actual_length) { - tty_insert_flip_string(&port->port, data + 1, - urb->actual_length - 1); - tty_flip_buffer_push(&port->port); - } + if (len < 2) + break; + tty_insert_flip_string(&port->port, data + 1, len - 1); + tty_flip_buffer_push(&port->port); break; case 1: /* status interrupt */ + if (len < 3) { + dev_warn(&port->dev, "short interrupt message received\n"); + break; + } dev_dbg(&port->dev, "rx int, d1=%d, d2=%d\n", data[1], data[2]); switch (data[1]) { case 1: /* modemline change */ diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 6cb45757818f..595415e59d5d 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -89,7 +89,6 @@ static struct usb_serial_driver kl5kusb105d_device = { .open = klsi_105_open, .close = klsi_105_close, .set_termios = klsi_105_set_termios, - /*.break_ctl = klsi_105_break_ctl,*/ .tiocmget = klsi_105_tiocmget, .port_probe = klsi_105_port_probe, .port_remove = klsi_105_port_remove, @@ -104,16 +103,15 @@ static struct usb_serial_driver * const serial_drivers[] = { }; struct klsi_105_port_settings { - __u8 pktlen; /* always 5, it seems */ - __u8 baudrate; - __u8 databits; - __u8 unknown1; - __u8 unknown2; -} __attribute__ ((packed)); + u8 pktlen; /* always 5, it seems */ + u8 baudrate; + u8 databits; + u8 unknown1; + u8 unknown2; +}; struct klsi_105_private { struct klsi_105_port_settings cfg; - struct ktermios termios; unsigned long line_state; /* modem line settings */ spinlock_t lock; }; @@ -143,10 +141,12 @@ static int klsi_105_chg_port_settings(struct usb_serial_port *port, if (rc < 0) dev_err(&port->dev, "Change port settings failed (error = %d)\n", rc); - dev_info(&port->serial->dev->dev, - "%d byte block, baudrate %x, databits %d, u1 %d, u2 %d\n", - settings->pktlen, settings->baudrate, settings->databits, - settings->unknown1, settings->unknown2); + + dev_dbg(&port->dev, + "pktlen %u, baudrate 0x%02x, databits %u, u1 %u, u2 %u\n", + settings->pktlen, settings->baudrate, settings->databits, + settings->unknown1, settings->unknown2); + return rc; } @@ -175,8 +175,6 @@ static int klsi_105_get_line_state(struct usb_serial_port *port, u8 *status_buf; __u16 status; - dev_info(&port->serial->dev->dev, "sending SIO Poll request\n"); - status_buf = kmalloc(KLSI_STATUSBUF_LEN, GFP_KERNEL); if (!status_buf) return -ENOMEM; @@ -199,8 +197,8 @@ static int klsi_105_get_line_state(struct usb_serial_port *port, } else { status = get_unaligned_le16(status_buf); - dev_info(&port->serial->dev->dev, "read status %x %x\n", - status_buf[0], status_buf[1]); + dev_dbg(&port->dev, "read status %02x %02x\n", + status_buf[0], status_buf[1]); *line_state_p = klsi_105_status2linestate(status); } @@ -233,8 +231,6 @@ static int klsi_105_port_probe(struct usb_serial_port *port) spin_lock_init(&priv->lock); - /* priv->termios is left uninitialized until port opening */ - usb_set_serial_port_data(port, priv); return 0; @@ -255,7 +251,6 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port) struct klsi_105_private *priv = usb_get_serial_port_data(port); int retval = 0; int rc; - int i; unsigned long line_state; struct klsi_105_port_settings *cfg; unsigned long flags; @@ -278,14 +273,7 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port) cfg->unknown2 = 1; klsi_105_chg_port_settings(port, cfg); - /* set up termios structure */ spin_lock_irqsave(&priv->lock, flags); - priv->termios.c_iflag = tty->termios.c_iflag; - priv->termios.c_oflag = tty->termios.c_oflag; - priv->termios.c_cflag = tty->termios.c_cflag; - priv->termios.c_lflag = tty->termios.c_lflag; - for (i = 0; i < NCCS; i++) - priv->termios.c_cc[i] = tty->termios.c_cc[i]; priv->cfg.pktlen = cfg->pktlen; priv->cfg.baudrate = cfg->baudrate; priv->cfg.databits = cfg->databits; @@ -438,19 +426,6 @@ static void klsi_105_set_termios(struct tty_struct *tty, */ baud = tty_get_baud_rate(tty); - if ((cflag & CBAUD) != (old_cflag & CBAUD)) { - /* reassert DTR and (maybe) RTS on transition from B0 */ - if ((old_cflag & CBAUD) == B0) { - dev_dbg(dev, "%s: baud was B0\n", __func__); -#if 0 - priv->control_state |= TIOCM_DTR; - /* don't set RTS if using hardware flow control */ - if (!(old_cflag & CRTSCTS)) - priv->control_state |= TIOCM_RTS; - mct_u232_set_modem_ctrl(serial, priv->control_state); -#endif - } - } switch (baud) { case 0: /* handled below */ break; @@ -484,17 +459,14 @@ static void klsi_105_set_termios(struct tty_struct *tty, baud = 9600; break; } - if ((cflag & CBAUD) == B0) { - dev_dbg(dev, "%s: baud is B0\n", __func__); - /* Drop RTS and DTR */ - /* maybe this should be simulated by sending read - * disable and read enable messages? - */ -#if 0 - priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS); - mct_u232_set_modem_ctrl(serial, priv->control_state); -#endif - } + + /* + * FIXME: implement B0 handling + * + * Maybe this should be simulated by sending read disable and read + * enable messages? + */ + tty_encode_baud_rate(tty, baud, baud); if ((cflag & CSIZE) != (old_cflag & CSIZE)) { @@ -528,22 +500,6 @@ static void klsi_105_set_termios(struct tty_struct *tty, || (cflag & CSTOPB) != (old_cflag & CSTOPB)) { /* Not currently supported */ tty->termios.c_cflag &= ~(PARENB|PARODD|CSTOPB); -#if 0 - priv->last_lcr = 0; - - /* set the parity */ - if (cflag & PARENB) - priv->last_lcr |= (cflag & PARODD) ? - MCT_U232_PARITY_ODD : MCT_U232_PARITY_EVEN; - else - priv->last_lcr |= MCT_U232_PARITY_NONE; - - /* set the number of stop bits */ - priv->last_lcr |= (cflag & CSTOPB) ? - MCT_U232_STOP_BITS_2 : MCT_U232_STOP_BITS_1; - - mct_u232_set_line_ctrl(serial, priv->last_lcr); -#endif } /* * Set flow control: well, I do not really now how to handle DTR/RTS. @@ -554,14 +510,6 @@ static void klsi_105_set_termios(struct tty_struct *tty, || (cflag & CRTSCTS) != (old_cflag & CRTSCTS)) { /* Not currently supported */ tty->termios.c_cflag &= ~CRTSCTS; - /* Drop DTR/RTS if no flow control otherwise assert */ -#if 0 - if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS)) - priv->control_state |= TIOCM_DTR | TIOCM_RTS; - else - priv->control_state &= ~(TIOCM_DTR | TIOCM_RTS); - mct_u232_set_modem_ctrl(serial, priv->control_state); -#endif } memcpy(cfg, &priv->cfg, sizeof(*cfg)); spin_unlock_irqrestore(&priv->lock, flags); @@ -572,25 +520,6 @@ err: kfree(cfg); } -#if 0 -static void mct_u232_break_ctl(struct tty_struct *tty, int break_state) -{ - struct usb_serial_port *port = tty->driver_data; - struct usb_serial *serial = port->serial; - struct mct_u232_private *priv = - (struct mct_u232_private *)port->private; - unsigned char lcr = priv->last_lcr; - - dev_dbg(&port->dev, "%s - state=%d\n", __func__, break_state); - - /* LOCKING */ - if (break_state) - lcr |= MCT_U232_SET_BREAK; - - mct_u232_set_line_ctrl(serial, lcr); -} -#endif - static int klsi_105_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index 885655315de1..edbc81f205c2 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -322,8 +322,12 @@ static int mct_u232_get_modem_stat(struct usb_serial_port *port, MCT_U232_GET_REQUEST_TYPE, 0, 0, buf, MCT_U232_GET_MODEM_STAT_SIZE, WDR_TIMEOUT); - if (rc < 0) { + if (rc < MCT_U232_GET_MODEM_STAT_SIZE) { dev_err(&port->dev, "Get MODEM STATus failed (error = %d)\n", rc); + + if (rc >= 0) + rc = -EIO; + *msr = 0; } else { *msr = buf[0]; diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c index 39e683096e94..cc84da8dbb84 100644 --- a/drivers/usb/serial/metro-usb.c +++ b/drivers/usb/serial/metro-usb.c @@ -135,23 +135,8 @@ static void metrousb_read_int_callback(struct urb *urb) throttled = metro_priv->throttled; spin_unlock_irqrestore(&metro_priv->lock, flags); - /* Continue trying to read if set. */ - if (!throttled) { - usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev, - usb_rcvintpipe(port->serial->dev, port->interrupt_in_endpointAddress), - port->interrupt_in_urb->transfer_buffer, - port->interrupt_in_urb->transfer_buffer_length, - metrousb_read_int_callback, port, 1); - - result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); - - if (result) - dev_err(&port->dev, - "%s - failed submitting interrupt in urb, error code=%d\n", - __func__, result); - } - return; - + if (throttled) + return; exit: /* Try to resubmit the urb. */ result = usb_submit_urb(urb, GFP_ATOMIC); @@ -161,19 +146,8 @@ exit: __func__, result); } -static void metrousb_write_int_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - - dev_warn(&port->dev, "%s not implemented yet.\n", - __func__); -} - static void metrousb_cleanup(struct usb_serial_port *port) { - dev_dbg(&port->dev, "%s\n", __func__); - - usb_unlink_urb(port->interrupt_in_urb); usb_kill_urb(port->interrupt_in_urb); metrousb_send_unidirectional_cmd(UNI_CMD_CLOSE, port); @@ -186,8 +160,6 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port) unsigned long flags = 0; int result = 0; - dev_dbg(&port->dev, "%s\n", __func__); - /* Make sure the urb is initialized. */ if (!port->interrupt_in_urb) { dev_err(&port->dev, "%s - interrupt urb not initialized\n", @@ -227,8 +199,6 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port) __func__, result); goto exit; } - - dev_dbg(&port->dev, "%s - port open\n", __func__); exit: return result; } @@ -290,8 +260,6 @@ static void metrousb_throttle(struct tty_struct *tty) struct metrousb_private *metro_priv = usb_get_serial_port_data(port); unsigned long flags = 0; - dev_dbg(tty->dev, "%s\n", __func__); - /* Set the private information for the port to stop reading data. */ spin_lock_irqsave(&metro_priv->lock, flags); metro_priv->throttled = 1; @@ -305,8 +273,6 @@ static int metrousb_tiocmget(struct tty_struct *tty) struct metrousb_private *metro_priv = usb_get_serial_port_data(port); unsigned long flags = 0; - dev_dbg(tty->dev, "%s\n", __func__); - spin_lock_irqsave(&metro_priv->lock, flags); control_state = metro_priv->control_state; spin_unlock_irqrestore(&metro_priv->lock, flags); @@ -350,15 +316,12 @@ static void metrousb_unthrottle(struct tty_struct *tty) unsigned long flags = 0; int result = 0; - dev_dbg(tty->dev, "%s\n", __func__); - /* Set the private information for the port to resume reading data. */ spin_lock_irqsave(&metro_priv->lock, flags); metro_priv->throttled = 0; spin_unlock_irqrestore(&metro_priv->lock, flags); /* Submit the urb to read from the port. */ - port->interrupt_in_urb->dev = port->serial->dev; result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); if (result) dev_err(tty->dev, @@ -377,7 +340,6 @@ static struct usb_serial_driver metrousb_device = { .open = metrousb_open, .close = metrousb_cleanup, .read_int_callback = metrousb_read_int_callback, - .write_int_callback = metrousb_write_int_callback, .port_probe = metrousb_port_probe, .port_remove = metrousb_port_remove, .throttle = metrousb_throttle, diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 91bc170b408a..f075121c6e32 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -234,11 +234,16 @@ static int read_mos_reg(struct usb_serial *serial, unsigned int serial_portnum, status = usb_control_msg(usbdev, pipe, request, requesttype, value, index, buf, 1, MOS_WDR_TIMEOUT); - if (status == 1) + if (status == 1) { *data = *buf; - else if (status < 0) + } else { dev_err(&usbdev->dev, "mos7720: usb_control_msg() failed: %d\n", status); + if (status >= 0) + status = -EIO; + *data = 0; + } + kfree(buf); return status; @@ -1846,7 +1851,6 @@ static int get_serial_info(struct moschip_port *mos7720_port, tmp.line = mos7720_port->port->minor; tmp.port = mos7720_port->port->port_number; tmp.irq = 0; - tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE; tmp.baud_base = 9600; tmp.close_delay = 5*HZ; diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index ea27fb23967a..3821c53fcee9 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -284,9 +284,15 @@ static int mos7840_get_reg_sync(struct usb_serial_port *port, __u16 reg, ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ, MCS_RD_RTYPE, 0, reg, buf, VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); + if (ret < VENDOR_READ_LENGTH) { + if (ret >= 0) + ret = -EIO; + goto out; + } + *val = buf[0]; dev_dbg(&port->dev, "%s offset is %x, return val %x\n", __func__, reg, *val); - +out: kfree(buf); return ret; } @@ -352,8 +358,13 @@ static int mos7840_get_uart_reg(struct usb_serial_port *port, __u16 reg, ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ, MCS_RD_RTYPE, Wval, reg, buf, VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); + if (ret < VENDOR_READ_LENGTH) { + if (ret >= 0) + ret = -EIO; + goto out; + } *val = buf[0]; - +out: kfree(buf); return ret; } @@ -1023,6 +1034,7 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) * (can't set it up in mos7840_startup as the structures * * were not set up at that time.) */ if (port0->open_ports == 1) { + /* FIXME: Buffer never NULL, so URB is not submitted. */ if (serial->port[0]->interrupt_in_buffer == NULL) { /* set up interrupt urb */ usb_fill_int_urb(serial->port[0]->interrupt_in_urb, @@ -1479,10 +1491,10 @@ static int mos7840_tiocmget(struct tty_struct *tty) return -ENODEV; status = mos7840_get_uart_reg(port, MODEM_STATUS_REGISTER, &msr); - if (status != 1) + if (status < 0) return -EIO; status = mos7840_get_uart_reg(port, MODEM_CONTROL_REGISTER, &mcr); - if (status != 1) + if (status < 0) return -EIO; result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0) | ((mcr & MCR_RTS) ? TIOCM_RTS : 0) @@ -1952,7 +1964,6 @@ static int mos7840_get_serial_info(struct moschip_port *mos7840_port, tmp.line = mos7840_port->port->minor; tmp.port = mos7840_port->port->port_number; tmp.irq = 0; - tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE; tmp.baud_base = 9600; tmp.close_delay = 5 * HZ; @@ -2106,7 +2117,8 @@ static int mos7840_calc_num_ports(struct usb_serial *serial) static int mos7840_attach(struct usb_serial *serial) { if (serial->num_bulk_in < serial->num_ports || - serial->num_bulk_out < serial->num_ports) { + serial->num_bulk_out < serial->num_ports || + serial->num_interrupt_in < 1) { dev_err(&serial->interface->dev, "missing endpoints\n"); return -ENODEV; } diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index 5ded6f524d59..3937b9c3cc69 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -142,7 +142,7 @@ static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port) usb_clear_halt(port->serial->dev, port->read_urb->pipe); res = usb_serial_generic_open(tty, port); - if (!res) + if (res) return res; /* Request CTS line state, sometimes during opening the current @@ -343,7 +343,6 @@ static int get_serial_info(struct usb_serial_port *port, tmp.line = port->minor; tmp.port = 0; tmp.irq = 0; - tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; tmp.xmit_fifo_size = 1024; tmp.baud_base = 9600; tmp.close_delay = 5*HZ; diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 1db4b61bdf7b..ca69eb42071b 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -450,7 +450,7 @@ static int pl2303_get_line_request(struct usb_serial_port *port, if (ret != 7) { dev_err(&port->dev, "%s - failed: %d\n", __func__, ret); - if (ret > 0) + if (ret >= 0) ret = -EIO; return ret; @@ -470,12 +470,8 @@ static int pl2303_set_line_request(struct usb_serial_port *port, ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE, 0, 0, buf, 7, 100); - if (ret != 7) { + if (ret < 0) { dev_err(&port->dev, "%s - failed: %d\n", __func__, ret); - - if (ret > 0) - ret = -EIO; - return ret; } diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index 5709cc93b083..fdbb904d153f 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -188,22 +188,22 @@ static inline int qt2_setdevice(struct usb_device *dev, u8 *data) } -static inline int qt2_getdevice(struct usb_device *dev, u8 *data) -{ - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - QT_SET_GET_DEVICE, 0xc0, 0, 0, - data, 3, QT2_USB_TIMEOUT); -} - static inline int qt2_getregister(struct usb_device *dev, u8 uart, u8 reg, u8 *data) { - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - QT_SET_GET_REGISTER, 0xc0, reg, - uart, data, sizeof(*data), QT2_USB_TIMEOUT); + int ret; + + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + QT_SET_GET_REGISTER, 0xc0, reg, + uart, data, sizeof(*data), QT2_USB_TIMEOUT); + if (ret < sizeof(*data)) { + if (ret >= 0) + ret = -EIO; + } + return ret; } static inline int qt2_setregister(struct usb_device *dev, @@ -372,9 +372,11 @@ static int qt2_open(struct tty_struct *tty, struct usb_serial_port *port) 0xc0, 0, device_port, data, 2, QT2_USB_TIMEOUT); - if (status < 0) { + if (status < 2) { dev_err(&port->dev, "%s - open port failed %i\n", __func__, status); + if (status >= 0) + status = -EIO; kfree(data); return status; } @@ -463,7 +465,6 @@ static int get_serial_info(struct usb_serial_port *port, tmp.line = port->minor; tmp.port = 0; tmp.irq = 0; - tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; tmp.xmit_fifo_size = port->bulk_out_size; tmp.baud_base = 9600; tmp.close_delay = 5*HZ; diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index e1994e264cc0..465e851b2815 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -137,24 +137,9 @@ static int is_himemory(const u8 ifnum, return 0; } -static int sierra_calc_interface(struct usb_serial *serial) +static u8 sierra_interface_num(struct usb_serial *serial) { - int interface; - struct usb_interface *p_interface; - struct usb_host_interface *p_host_interface; - - /* Get the interface structure pointer from the serial struct */ - p_interface = serial->interface; - - /* Get a pointer to the host interface structure */ - p_host_interface = p_interface->cur_altsetting; - - /* read the interface descriptor for this active altsetting - * to find out the interface number we are on - */ - interface = p_host_interface->desc.bInterfaceNumber; - - return interface; + return serial->interface->cur_altsetting->desc.bInterfaceNumber; } static int sierra_probe(struct usb_serial *serial, @@ -165,7 +150,7 @@ static int sierra_probe(struct usb_serial *serial, u8 ifnum; udev = serial->dev; - ifnum = sierra_calc_interface(serial); + ifnum = sierra_interface_num(serial); /* * If this interface supports more than 1 alternate @@ -178,9 +163,6 @@ static int sierra_probe(struct usb_serial *serial, usb_set_interface(udev, ifnum, 1); } - /* ifnum could have changed - by calling usb_set_interface */ - ifnum = sierra_calc_interface(serial); - if (is_blacklisted(ifnum, (struct sierra_iface_info *)id->driver_info)) { dev_dbg(&serial->dev->dev, @@ -342,7 +324,7 @@ static int sierra_send_setup(struct usb_serial_port *port) /* If composite device then properly report interface */ if (serial->num_ports == 1) { - interface = sierra_calc_interface(serial); + interface = sierra_interface_num(serial); /* Control message is sent only to interfaces with * interrupt_in endpoints */ @@ -916,7 +898,7 @@ static int sierra_port_probe(struct usb_serial_port *port) /* Determine actual memory requirements */ if (serial->num_ports == 1) { /* Get interface number for composite device */ - ifnum = sierra_calc_interface(serial); + ifnum = sierra_interface_num(serial); himemoryp = &typeB_interface_list; } else { /* This is really the usb-serial port number of the interface diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c index 475e6c31b266..ddfd787c461c 100644 --- a/drivers/usb/serial/spcp8x5.c +++ b/drivers/usb/serial/spcp8x5.c @@ -232,11 +232,17 @@ static int spcp8x5_get_msr(struct usb_serial_port *port, u8 *status) ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), GET_UART_STATUS, GET_UART_STATUS_TYPE, 0, GET_UART_STATUS_MSR, buf, 1, 100); - if (ret < 0) + if (ret < 1) { dev_err(&port->dev, "failed to get modem status: %d\n", ret); + if (ret >= 0) + ret = -EIO; + goto out; + } dev_dbg(&port->dev, "0xc0:0x22:0:6 %d - 0x02%x\n", ret, *buf); *status = *buf; + ret = 0; +out: kfree(buf); return ret; diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index 2a156144c76c..5aa7bbbeba3d 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -80,9 +80,17 @@ static inline int ssu100_setdevice(struct usb_device *dev, u8 *data) static inline int ssu100_getdevice(struct usb_device *dev, u8 *data) { - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - QT_SET_GET_DEVICE, 0xc0, 0, 0, - data, 3, 300); + int ret; + + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + QT_SET_GET_DEVICE, 0xc0, 0, 0, + data, 3, 300); + if (ret < 3) { + if (ret >= 0) + ret = -EIO; + } + + return ret; } static inline int ssu100_getregister(struct usb_device *dev, @@ -90,10 +98,17 @@ static inline int ssu100_getregister(struct usb_device *dev, unsigned short reg, u8 *data) { - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), - QT_SET_GET_REGISTER, 0xc0, reg, - uart, data, sizeof(*data), 300); + int ret; + + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + QT_SET_GET_REGISTER, 0xc0, reg, + uart, data, sizeof(*data), 300); + if (ret < sizeof(*data)) { + if (ret >= 0) + ret = -EIO; + } + return ret; } @@ -289,8 +304,10 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port) QT_OPEN_CLOSE_CHANNEL, QT_TRANSFER_IN, 0x01, 0, data, 2, 300); - if (result < 0) { + if (result < 2) { dev_dbg(&port->dev, "%s - open failed %i\n", __func__, result); + if (result >= 0) + result = -EIO; kfree(data); return result; } @@ -322,7 +339,6 @@ static int get_serial_info(struct usb_serial_port *port, tmp.line = port->minor; tmp.port = 0; tmp.irq = 0; - tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; tmp.xmit_fifo_size = port->bulk_out_size; tmp.baud_base = 9600; tmp.close_delay = 5*HZ; diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 64b85b8dedf3..3107bf5d1c96 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -1553,13 +1553,10 @@ static int ti_command_out_sync(struct ti_device *tdev, __u8 command, (USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT), value, moduleid, data, size, 1000); - if (status == size) - status = 0; - - if (status > 0) - status = -ECOMM; + if (status < 0) + return status; - return status; + return 0; } @@ -1575,8 +1572,7 @@ static int ti_command_in_sync(struct ti_device *tdev, __u8 command, if (status == size) status = 0; - - if (status > 0) + else if (status >= 0) status = -ECOMM; return status; diff --git a/drivers/usb/serial/upd78f0730.c b/drivers/usb/serial/upd78f0730.c new file mode 100644 index 000000000000..a028dd2310c9 --- /dev/null +++ b/drivers/usb/serial/upd78f0730.c @@ -0,0 +1,441 @@ +/* + * Renesas Electronics uPD78F0730 USB to serial converter driver + * + * Copyright (C) 2014,2016 Maksim Salau <maksim.salau@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * Protocol of the adaptor is described in the application note U19660EJ1V0AN00 + * μPD78F0730 8-bit Single-Chip Microcontroller + * USB-to-Serial Conversion Software + * <https://www.renesas.com/en-eu/doc/DocumentServer/026/U19660EJ1V0AN00.pdf> + * + * The adaptor functionality is limited to the following: + * - data bits: 7 or 8 + * - stop bits: 1 or 2 + * - parity: even, odd or none + * - flow control: none + * - baud rates: 0, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 153600 + * - signals: DTR, RTS and BREAK + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/usb.h> +#include <linux/usb/serial.h> + +#define DRIVER_DESC "Renesas uPD78F0730 USB to serial converter driver" + +#define DRIVER_AUTHOR "Maksim Salau <maksim.salau@gmail.com>" + +static const struct usb_device_id id_table[] = { + { USB_DEVICE(0x0409, 0x0063) }, /* V850ESJX3-STICK */ + { USB_DEVICE(0x045B, 0x0212) }, /* YRPBRL78G13, YRPBRL78G14 */ + { USB_DEVICE(0x064B, 0x7825) }, /* Analog Devices EVAL-ADXL362Z-DB */ + {} +}; + +MODULE_DEVICE_TABLE(usb, id_table); + +/* + * Each adaptor is associated with a private structure, that holds the current + * state of control signals (DTR, RTS and BREAK). + */ +struct upd78f0730_port_private { + struct mutex lock; /* mutex to protect line_signals */ + u8 line_signals; +}; + +/* Op-codes of control commands */ +#define UPD78F0730_CMD_LINE_CONTROL 0x00 +#define UPD78F0730_CMD_SET_DTR_RTS 0x01 +#define UPD78F0730_CMD_SET_XON_XOFF_CHR 0x02 +#define UPD78F0730_CMD_OPEN_CLOSE 0x03 +#define UPD78F0730_CMD_SET_ERR_CHR 0x04 + +/* Data sizes in UPD78F0730_CMD_LINE_CONTROL command */ +#define UPD78F0730_DATA_SIZE_7_BITS 0x00 +#define UPD78F0730_DATA_SIZE_8_BITS 0x01 +#define UPD78F0730_DATA_SIZE_MASK 0x01 + +/* Stop-bit modes in UPD78F0730_CMD_LINE_CONTROL command */ +#define UPD78F0730_STOP_BIT_1_BIT 0x00 +#define UPD78F0730_STOP_BIT_2_BIT 0x02 +#define UPD78F0730_STOP_BIT_MASK 0x02 + +/* Parity modes in UPD78F0730_CMD_LINE_CONTROL command */ +#define UPD78F0730_PARITY_NONE 0x00 +#define UPD78F0730_PARITY_EVEN 0x04 +#define UPD78F0730_PARITY_ODD 0x08 +#define UPD78F0730_PARITY_MASK 0x0C + +/* Flow control modes in UPD78F0730_CMD_LINE_CONTROL command */ +#define UPD78F0730_FLOW_CONTROL_NONE 0x00 +#define UPD78F0730_FLOW_CONTROL_HW 0x10 +#define UPD78F0730_FLOW_CONTROL_SW 0x20 +#define UPD78F0730_FLOW_CONTROL_MASK 0x30 + +/* Control signal bits in UPD78F0730_CMD_SET_DTR_RTS command */ +#define UPD78F0730_RTS 0x01 +#define UPD78F0730_DTR 0x02 +#define UPD78F0730_BREAK 0x04 + +/* Port modes in UPD78F0730_CMD_OPEN_CLOSE command */ +#define UPD78F0730_PORT_CLOSE 0x00 +#define UPD78F0730_PORT_OPEN 0x01 + +/* Error character substitution modes in UPD78F0730_CMD_SET_ERR_CHR command */ +#define UPD78F0730_ERR_CHR_DISABLED 0x00 +#define UPD78F0730_ERR_CHR_ENABLED 0x01 + +/* + * Declaration of command structures + */ + +/* UPD78F0730_CMD_LINE_CONTROL command */ +struct upd78f0730_line_control { + u8 opcode; + __le32 baud_rate; + u8 params; +} __packed; + +/* UPD78F0730_CMD_SET_DTR_RTS command */ +struct upd78f0730_set_dtr_rts { + u8 opcode; + u8 params; +}; + +/* UPD78F0730_CMD_SET_XON_OFF_CHR command */ +struct upd78f0730_set_xon_xoff_chr { + u8 opcode; + u8 xon; + u8 xoff; +}; + +/* UPD78F0730_CMD_OPEN_CLOSE command */ +struct upd78f0730_open_close { + u8 opcode; + u8 state; +}; + +/* UPD78F0730_CMD_SET_ERR_CHR command */ +struct upd78f0730_set_err_chr { + u8 opcode; + u8 state; + u8 err_char; +}; + +static int upd78f0730_send_ctl(struct usb_serial_port *port, + const void *data, int size) +{ + struct usb_device *usbdev = port->serial->dev; + void *buf; + int res; + + if (size <= 0 || !data) + return -EINVAL; + + buf = kmemdup(data, size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + res = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x00, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + 0x0000, 0x0000, buf, size, USB_CTRL_SET_TIMEOUT); + + kfree(buf); + + if (res != size) { + struct device *dev = &port->dev; + + dev_err(dev, "failed to send control request %02x: %d\n", + *(u8 *)data, res); + /* The maximum expected length of a transfer is 6 bytes */ + if (res >= 0) + res = -EIO; + + return res; + } + + return 0; +} + +static int upd78f0730_port_probe(struct usb_serial_port *port) +{ + struct upd78f0730_port_private *private; + + private = kzalloc(sizeof(*private), GFP_KERNEL); + if (!private) + return -ENOMEM; + + mutex_init(&private->lock); + usb_set_serial_port_data(port, private); + + return 0; +} + +static int upd78f0730_port_remove(struct usb_serial_port *port) +{ + struct upd78f0730_port_private *private; + + private = usb_get_serial_port_data(port); + mutex_destroy(&private->lock); + kfree(private); + + return 0; +} + +static int upd78f0730_tiocmget(struct tty_struct *tty) +{ + struct device *dev = tty->dev; + struct upd78f0730_port_private *private; + struct usb_serial_port *port = tty->driver_data; + int signals; + int res; + + private = usb_get_serial_port_data(port); + + mutex_lock(&private->lock); + signals = private->line_signals; + mutex_unlock(&private->lock); + + res = ((signals & UPD78F0730_DTR) ? TIOCM_DTR : 0) | + ((signals & UPD78F0730_RTS) ? TIOCM_RTS : 0); + + dev_dbg(dev, "%s - res = %x\n", __func__, res); + + return res; +} + +static int upd78f0730_tiocmset(struct tty_struct *tty, + unsigned int set, unsigned int clear) +{ + struct device *dev = tty->dev; + struct usb_serial_port *port = tty->driver_data; + struct upd78f0730_port_private *private; + struct upd78f0730_set_dtr_rts request; + int res; + + private = usb_get_serial_port_data(port); + + mutex_lock(&private->lock); + if (set & TIOCM_DTR) { + private->line_signals |= UPD78F0730_DTR; + dev_dbg(dev, "%s - set DTR\n", __func__); + } + if (set & TIOCM_RTS) { + private->line_signals |= UPD78F0730_RTS; + dev_dbg(dev, "%s - set RTS\n", __func__); + } + if (clear & TIOCM_DTR) { + private->line_signals &= ~UPD78F0730_DTR; + dev_dbg(dev, "%s - clear DTR\n", __func__); + } + if (clear & TIOCM_RTS) { + private->line_signals &= ~UPD78F0730_RTS; + dev_dbg(dev, "%s - clear RTS\n", __func__); + } + request.opcode = UPD78F0730_CMD_SET_DTR_RTS; + request.params = private->line_signals; + + res = upd78f0730_send_ctl(port, &request, sizeof(request)); + mutex_unlock(&private->lock); + + return res; +} + +static void upd78f0730_break_ctl(struct tty_struct *tty, int break_state) +{ + struct device *dev = tty->dev; + struct upd78f0730_port_private *private; + struct usb_serial_port *port = tty->driver_data; + struct upd78f0730_set_dtr_rts request; + + private = usb_get_serial_port_data(port); + + mutex_lock(&private->lock); + if (break_state) { + private->line_signals |= UPD78F0730_BREAK; + dev_dbg(dev, "%s - set BREAK\n", __func__); + } else { + private->line_signals &= ~UPD78F0730_BREAK; + dev_dbg(dev, "%s - clear BREAK\n", __func__); + } + request.opcode = UPD78F0730_CMD_SET_DTR_RTS; + request.params = private->line_signals; + + upd78f0730_send_ctl(port, &request, sizeof(request)); + mutex_unlock(&private->lock); +} + +static void upd78f0730_dtr_rts(struct usb_serial_port *port, int on) +{ + struct tty_struct *tty = port->port.tty; + unsigned int set = 0; + unsigned int clear = 0; + + if (on) + set = TIOCM_DTR | TIOCM_RTS; + else + clear = TIOCM_DTR | TIOCM_RTS; + + upd78f0730_tiocmset(tty, set, clear); +} + +static speed_t upd78f0730_get_baud_rate(struct tty_struct *tty) +{ + const speed_t baud_rate = tty_get_baud_rate(tty); + const speed_t supported[] = { + 0, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 153600 + }; + int i; + + for (i = ARRAY_SIZE(supported) - 1; i >= 0; i--) { + if (baud_rate == supported[i]) + return baud_rate; + } + + /* If the baud rate is not supported, switch to the default one */ + tty_encode_baud_rate(tty, 9600, 9600); + + return tty_get_baud_rate(tty); +} + +static void upd78f0730_set_termios(struct tty_struct *tty, + struct usb_serial_port *port, + struct ktermios *old_termios) +{ + struct device *dev = &port->dev; + struct upd78f0730_line_control request; + speed_t baud_rate; + + if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios)) + return; + + if (C_BAUD(tty) == B0) + upd78f0730_dtr_rts(port, 0); + else if (old_termios && (old_termios->c_cflag & CBAUD) == B0) + upd78f0730_dtr_rts(port, 1); + + baud_rate = upd78f0730_get_baud_rate(tty); + request.opcode = UPD78F0730_CMD_LINE_CONTROL; + request.baud_rate = cpu_to_le32(baud_rate); + request.params = 0; + dev_dbg(dev, "%s - baud rate = %d\n", __func__, baud_rate); + + switch (C_CSIZE(tty)) { + case CS7: + request.params |= UPD78F0730_DATA_SIZE_7_BITS; + dev_dbg(dev, "%s - 7 data bits\n", __func__); + break; + default: + tty->termios.c_cflag &= ~CSIZE; + tty->termios.c_cflag |= CS8; + dev_warn(dev, "data size is not supported, using 8 bits\n"); + /* fall through */ + case CS8: + request.params |= UPD78F0730_DATA_SIZE_8_BITS; + dev_dbg(dev, "%s - 8 data bits\n", __func__); + break; + } + + if (C_PARENB(tty)) { + if (C_PARODD(tty)) { + request.params |= UPD78F0730_PARITY_ODD; + dev_dbg(dev, "%s - odd parity\n", __func__); + } else { + request.params |= UPD78F0730_PARITY_EVEN; + dev_dbg(dev, "%s - even parity\n", __func__); + } + + if (C_CMSPAR(tty)) { + tty->termios.c_cflag &= ~CMSPAR; + dev_warn(dev, "MARK/SPACE parity is not supported\n"); + } + } else { + request.params |= UPD78F0730_PARITY_NONE; + dev_dbg(dev, "%s - no parity\n", __func__); + } + + if (C_CSTOPB(tty)) { + request.params |= UPD78F0730_STOP_BIT_2_BIT; + dev_dbg(dev, "%s - 2 stop bits\n", __func__); + } else { + request.params |= UPD78F0730_STOP_BIT_1_BIT; + dev_dbg(dev, "%s - 1 stop bit\n", __func__); + } + + if (C_CRTSCTS(tty)) { + tty->termios.c_cflag &= ~CRTSCTS; + dev_warn(dev, "RTSCTS flow control is not supported\n"); + } + if (I_IXOFF(tty) || I_IXON(tty)) { + tty->termios.c_iflag &= ~(IXOFF | IXON); + dev_warn(dev, "XON/XOFF flow control is not supported\n"); + } + request.params |= UPD78F0730_FLOW_CONTROL_NONE; + dev_dbg(dev, "%s - no flow control\n", __func__); + + upd78f0730_send_ctl(port, &request, sizeof(request)); +} + +static int upd78f0730_open(struct tty_struct *tty, struct usb_serial_port *port) +{ + struct upd78f0730_open_close request = { + .opcode = UPD78F0730_CMD_OPEN_CLOSE, + .state = UPD78F0730_PORT_OPEN + }; + int res; + + res = upd78f0730_send_ctl(port, &request, sizeof(request)); + if (res) + return res; + + if (tty) + upd78f0730_set_termios(tty, port, NULL); + + return usb_serial_generic_open(tty, port); +} + +static void upd78f0730_close(struct usb_serial_port *port) +{ + struct upd78f0730_open_close request = { + .opcode = UPD78F0730_CMD_OPEN_CLOSE, + .state = UPD78F0730_PORT_CLOSE + }; + + usb_serial_generic_close(port); + upd78f0730_send_ctl(port, &request, sizeof(request)); +} + +static struct usb_serial_driver upd78f0730_device = { + .driver = { + .owner = THIS_MODULE, + .name = "upd78f0730", + }, + .id_table = id_table, + .num_ports = 1, + .port_probe = upd78f0730_port_probe, + .port_remove = upd78f0730_port_remove, + .open = upd78f0730_open, + .close = upd78f0730_close, + .set_termios = upd78f0730_set_termios, + .tiocmget = upd78f0730_tiocmget, + .tiocmset = upd78f0730_tiocmset, + .dtr_rts = upd78f0730_dtr_rts, + .break_ctl = upd78f0730_break_ctl, +}; + +static struct usb_serial_driver * const serial_drivers[] = { + &upd78f0730_device, + NULL +}; + +module_usb_serial_driver(serial_drivers, id_table); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index d3ea90bef84d..5ab65eb1dacc 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -487,7 +487,6 @@ static int whiteheat_ioctl(struct tty_struct *tty, serstruct.type = PORT_16654; serstruct.line = port->minor; serstruct.port = port->port_number; - serstruct.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; serstruct.xmit_fifo_size = kfifo_size(&port->write_fifo); serstruct.custom_divisor = 0; serstruct.baud_base = 460800; diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c index 02bdaa912164..369f3c24815a 100644 --- a/drivers/usb/storage/ene_ub6250.c +++ b/drivers/usb/storage/ene_ub6250.c @@ -1364,7 +1364,6 @@ static int ms_lib_read_extra(struct us_data *us, u32 PhyBlock, static int ms_libsearch_block_from_physical(struct us_data *us, u16 phyblk) { - u16 Newblk; u16 blk; struct ms_lib_type_extdat extdat; /* need check */ struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; @@ -1377,7 +1376,6 @@ static int ms_libsearch_block_from_physical(struct us_data *us, u16 phyblk) if ((blk & MS_PHYSICAL_BLOCKS_PER_SEGMENT_MASK) == 0) blk -= MS_PHYSICAL_BLOCKS_PER_SEGMENT; - Newblk = info->MS_Lib.Phy2LogMap[blk]; if (info->MS_Lib.Phy2LogMap[blk] == MS_LB_NOT_USED_ERASED) { return blk; } else if (info->MS_Lib.Phy2LogMap[blk] == MS_LB_NOT_USED) { diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c index 3aeaa536c44f..44f8ffccd031 100644 --- a/drivers/usb/storage/sddr09.c +++ b/drivers/usb/storage/sddr09.c @@ -870,13 +870,12 @@ sddr09_write_lba(struct us_data *us, unsigned int lba, unsigned int pagelen; unsigned char *bptr, *cptr, *xptr; unsigned char ecc[3]; - int i, result, isnew; + int i, result; lbap = ((lba % 1000) << 1) | 0x1000; if (parity[MSB_of(lbap) ^ LSB_of(lbap)]) lbap ^= 1; pba = info->lba_to_pba[lba]; - isnew = 0; if (pba == UNDEF) { pba = sddr09_find_unused_pba(info, lba); @@ -887,7 +886,6 @@ sddr09_write_lba(struct us_data *us, unsigned int lba, } info->pba_to_lba[pba] = lba; info->lba_to_pba[lba] = pba; - isnew = 1; } if (pba == 1) { diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index c4724fb3a691..e4cb9f0625e8 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c @@ -313,6 +313,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, default: break; } + break; default: usbip_dbg_vhci_rh(" ClearPortFeature: default %x\n", wValue); diff --git a/include/linux/of_device.h b/include/linux/of_device.h index cc7dd687a89d..e9afbcc8de12 100644 --- a/include/linux/of_device.h +++ b/include/linux/of_device.h @@ -37,6 +37,7 @@ extern const void *of_device_get_match_data(const struct device *dev); extern ssize_t of_device_get_modalias(struct device *dev, char *str, ssize_t len); +extern int of_device_request_module(struct device *dev); extern void of_device_uevent(struct device *dev, struct kobj_uevent_env *env); extern int of_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env); @@ -78,6 +79,11 @@ static inline int of_device_get_modalias(struct device *dev, return -ENODEV; } +static inline int of_device_request_module(struct device *dev) +{ + return -ENODEV; +} + static inline int of_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env) { diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h index 5dd75fa47dd8..c5fdfcf99828 100644 --- a/include/linux/usb/chipidea.h +++ b/include/linux/usb/chipidea.h @@ -12,16 +12,18 @@ struct ci_hdrc; /** * struct ci_hdrc_cable - structure for external connector cable state tracking - * @state: current state of the line + * @connected: true if cable is connected, false otherwise * @changed: set to true when extcon event happen + * @enabled: set to true if we've enabled the vbus or id interrupt * @edev: device which generate events * @ci: driver state of the chipidea device * @nb: hold event notification callback * @conn: used for notification registration */ struct ci_hdrc_cable { - bool state; + bool connected; bool changed; + bool enabled; struct extcon_dev *edev; struct ci_hdrc *ci; struct notifier_block nb; @@ -55,10 +57,11 @@ struct ci_hdrc_platform_data { #define CI_HDRC_OVERRIDE_AHB_BURST BIT(9) #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 */ enum usb_dr_mode dr_mode; #define CI_HDRC_CONTROLLER_RESET_EVENT 0 #define CI_HDRC_CONTROLLER_STOPPED_EVENT 1 - void (*notify_event) (struct ci_hdrc *ci, unsigned event); + int (*notify_event) (struct ci_hdrc *ci, unsigned event); struct regulator *reg_vbus; struct usb_otg_caps ci_otg_caps; bool tpl_support; diff --git a/tools/usb/ffs-test.c b/tools/usb/ffs-test.c index 88d5e71be044..95dd14648ba5 100644 --- a/tools/usb/ffs-test.c +++ b/tools/usb/ffs-test.c @@ -22,7 +22,7 @@ /* $(CROSS_COMPILE)cc -Wall -Wextra -g -o ffs-test ffs-test.c -lpthread */ -#define _BSD_SOURCE /* for endian.h */ +#define _DEFAULT_SOURCE /* for endian.h */ #include <endian.h> #include <errno.h> @@ -110,16 +110,25 @@ static const struct { struct usb_functionfs_descs_head_v2 header; __le32 fs_count; __le32 hs_count; + __le32 ss_count; struct { struct usb_interface_descriptor intf; struct usb_endpoint_descriptor_no_audio sink; struct usb_endpoint_descriptor_no_audio source; } __attribute__((packed)) fs_descs, hs_descs; + struct { + struct usb_interface_descriptor intf; + struct usb_endpoint_descriptor_no_audio sink; + struct usb_ss_ep_comp_descriptor sink_comp; + struct usb_endpoint_descriptor_no_audio source; + struct usb_ss_ep_comp_descriptor source_comp; + } ss_descs; } __attribute__((packed)) descriptors = { .header = { .magic = cpu_to_le32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2), .flags = cpu_to_le32(FUNCTIONFS_HAS_FS_DESC | - FUNCTIONFS_HAS_HS_DESC), + FUNCTIONFS_HAS_HS_DESC | + FUNCTIONFS_HAS_SS_DESC), .length = cpu_to_le32(sizeof descriptors), }, .fs_count = cpu_to_le32(3), @@ -171,6 +180,45 @@ static const struct { .bInterval = 1, /* NAK every 1 uframe */ }, }, + .ss_count = cpu_to_le32(5), + .ss_descs = { + .intf = { + .bLength = sizeof descriptors.fs_descs.intf, + .bDescriptorType = USB_DT_INTERFACE, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, + .iInterface = 1, + }, + .sink = { + .bLength = sizeof descriptors.hs_descs.sink, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 1 | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), + }, + .sink_comp = { + .bLength = USB_DT_SS_EP_COMP_SIZE, + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + .bMaxBurst = 0, + .bmAttributes = 0, + .wBytesPerInterval = 0, + }, + .source = { + .bLength = sizeof descriptors.hs_descs.source, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 2 | USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), + .bInterval = 1, /* NAK every 1 uframe */ + }, + .source_comp = { + .bLength = USB_DT_SS_EP_COMP_SIZE, + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + .bMaxBurst = 0, + .bmAttributes = 0, + .wBytesPerInterval = 0, + }, + }, }; static size_t descs_to_legacy(void **legacy, const void *descriptors_v2) diff --git a/tools/usb/usbip/README b/tools/usb/usbip/README index 831f49fea3ce..5eb2b6c7722b 100644 --- a/tools/usb/usbip/README +++ b/tools/usb/usbip/README @@ -4,10 +4,33 @@ # Copyright (C) 2011 matt mooney <mfm@muteddisk.com> # 2005-2008 Takahiro Hirofuchi +[Overview] +USB/IP protocol allows to pass USB device from server to client over the +network. Server is a machine which provides (shares) a USB device. Client is +a machine which uses USB device provided by server over the network. +The USB device may be either physical device connected to a server or +software entity created on a server using USB gadget subsystem. +Whole project consists of four parts: + + - usbip-vhci + A client side kernel module which provides a virtual USB Host Controller + and allows to import a USB device from a remote machine. + + - usbip-host (stub driver) + A server side module which provides a USB device driver which can be + bound to a physical USB device to make it exportable. + + - usbip-vudc + A server side module which provides a virtual USB Device Controller and allows + to export a USB device created using USB Gadget Subsystem. + + - usbip-utils + A set of userspace tools used to handle connection and management. + Used on both sides. [Requirements] - USB/IP device drivers - Found in the staging directory of the Linux kernel. + Found in the drivers/usb/usbip/ directory of the Linux kernel tree. - libudev >= 2.0 libudev library @@ -36,6 +59,10 @@ [Usage] +On a server side there are two entities which can be shared. +First of them is physical usb device connected to the machine. +To make it available below steps should be executed: + server:# (Physically attach your USB device.) server:# insmod usbip-core.ko @@ -52,6 +79,30 @@ - The USB device 1-2 is now exportable to other hosts! - Use `usbip unbind --busid 1-2' to stop exporting the device. +Second of shareable entities is USB Gadget created using USB Gadget Subsystem +on a server machine. To make it available below steps should be executed: + + server:# (Create your USB gadget) + - Currently the most preferable way of creating a new USB gadget + is ConfigFS Composite Gadget. Please refer to its documentation + for details. + - See vudc_server_example.sh for a short example of USB gadget creation + + server:# insmod usbip-core.ko + server:# insmod usbip-vudc.ko + - To create more than one instance of vudc use num module param + + server:# (Bind gadget to one of available vudc) + - Assign your new gadget to USB/IP UDC + - Using ConfigFS interface you may do this simply by: + server:# cd /sys/kernel/config/usb_gadget/<gadget_name> + server:# echo "usbip-vudc.0" > UDC + + server:# usbipd -D --device + - Start usbip daemon. + +To attach new device to client machine below commands should be used: + client:# insmod usbip-core.ko client:# insmod vhci-hcd.ko @@ -60,6 +111,8 @@ client:# usbip attach --remote <host> --busid 1-2 - Connect the remote USB device. + - When using vudc on a server side busid is really vudc instance name. + For example: usbip-vudc.0 client:# usbip port - Show virtual port status. @@ -192,6 +245,8 @@ Detach the imported device: - http://usbip.wiki.sourceforge.net/how-to-debug-usbip - usbip-host.ko must be bound to the target device. - See /proc/bus/usb/devices and find "Driver=..." lines of the device. + - Target USB gadget must be bound to vudc + (using USB gadget susbsys, not usbip bind command) - Shutdown firewall. - usbip now uses TCP port 3240. - Disable SELinux. diff --git a/tools/usb/usbip/vudc/vudc_server_example.sh b/tools/usb/usbip/vudc/vudc_server_example.sh new file mode 100755 index 000000000000..2736be64f203 --- /dev/null +++ b/tools/usb/usbip/vudc/vudc_server_example.sh @@ -0,0 +1,107 @@ +#!/bin/bash + +################################################################################ +# This is free and unencumbered software released into the public domain. +# +# Anyone is free to copy, modify, publish, use, compile, sell, or +# distribute this software, either in source code form or as a compiled +# binary, for any purpose, commercial or non-commercial, and by any +# means. +# +# In jurisdictions that recognize copyright laws, the author or authors +# of this software dedicate any and all copyright interest in the +# software to the public domain. We make this dedication for the benefit +# of the public at large and to the detriment of our heirs and +# successors. We intend this dedication to be an overt act of +# relinquishment in perpetuity of all present and future rights to this +# software under copyright law. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +# For more information, please refer to <http://unlicense.org/> +################################################################################ + +################################################################################ +# This is a sample script which shows how to use vUDC with ConfigFS gadgets +################################################################################ + +# Stop script on error +set -e + +################################################################################ +# Create your USB gadget +# You may use bare ConfigFS interface (as below) +# or libusbgx or gt toool +# Instead of ConfigFS gadgets you may use any of legacy gadgets. +################################################################################ +CONFIGFS_MOUNT_POINT="/sys/kernel/config" +GADGET_NAME="g1" +ID_VENDOR="0x1d6b" +ID_PRODUCT="0x0104" + +cd ${CONFIGFS_MOUNT_POINT}/usb_gadget +# Create a new USB gadget +mkdir ${GADGET_NAME} +cd ${GADGET_NAME} + +# This gadget contains one function - ACM (serial port over USB) +FUNC_DIR="functions/acm.ser0" +mkdir ${FUNC_DIR} + +# Just one configuration +mkdir configs/c.1 +ln -s ${FUNC_DIR} configs/c.1 + +# Set our gadget identity +echo ${ID_VENDOR} > idVendor +echo ${ID_PRODUCT} > idProduct + +################################################################################ +# Load vudc-module if vudc is not available +# You may change value of num param to get more than one vUDC instance +################################################################################ +[[ -d /sys/class/udc/usbip-vudc.0 ]] || modprobe usbip-vudc num=1 + +################################################################################ +# Bind gadget to our vUDC +# By default we bind to first one but you may change this if you would like +# to use more than one instance +################################################################################ +echo "usbip-vudc.0" > UDC + +################################################################################ +# Let's now run our usbip daemon in a USB device mode +################################################################################ +usbipd --device & + +################################################################################ +# Now your USB gadget is available using USB/IP protocol. +# To prepare your client, you should ensure that usbip-vhci module is inside +# your kernel. If it's not then you can load it: +# +# $ modprobe usbip-vhci +# +# To check availability of your gadget you may try to list devices exported +# on a remote server: +# +# $ modprobe usbip-vhci +# $ usbip list -r $SERVER_IP +# Exportable USB devices +# ====================== +# usbipd: info: request 0x8005(6): complete +# - 127.0.0.1 +# usbip-vudc.0: Linux Foundation : unknown product (1d6b:0104) +# : /sys/devices/platform/usbip-vudc.0 +# : (Defined at Interface level) (00/00/00) +# +# To attach this device to your client you may use: +# +# $ usbip attach -r $SERVER_IP -d usbip-vudc.0 +# +################################################################################ |