diff options
206 files changed, 12187 insertions, 3332 deletions
diff --git a/Documentation/ABI/testing/sysfs-driver-ucsi-ccg b/Documentation/ABI/testing/sysfs-driver-ucsi-ccg new file mode 100644 index 000000000000..45cf62ad89e9 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-driver-ucsi-ccg | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | What: /sys/bus/i2c/drivers/ucsi_ccg/.../do_flash | ||
| 2 | Date: May 2019 | ||
| 3 | Contact: Ajay Gupta <ajayg@nvidia.com> | ||
| 4 | Description: | ||
| 5 | Tell the driver for Cypress CCGx Type-C controller to attempt | ||
| 6 | firmware upgrade by writing [Yy1] to the file. | ||
diff --git a/Documentation/ABI/testing/usb-uevent b/Documentation/ABI/testing/usb-uevent new file mode 100644 index 000000000000..d35c3cad892c --- /dev/null +++ b/Documentation/ABI/testing/usb-uevent | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | What: Raise a uevent when a USB Host Controller has died | ||
| 2 | Date: 2019-04-17 | ||
| 3 | KernelVersion: 5.2 | ||
| 4 | Contact: linux-usb@vger.kernel.org | ||
| 5 | Description: When the USB Host Controller has entered a state where it is no | ||
| 6 | longer functional a uevent will be raised. The uevent will | ||
| 7 | contain ACTION=offline and ERROR=DEAD. | ||
| 8 | |||
| 9 | Here is an example taken using udevadm monitor -p: | ||
| 10 | |||
| 11 | KERNEL[130.428945] offline /devices/pci0000:00/0000:00:10.0/usb2 (usb) | ||
| 12 | ACTION=offline | ||
| 13 | BUSNUM=002 | ||
| 14 | DEVNAME=/dev/bus/usb/002/001 | ||
| 15 | DEVNUM=001 | ||
| 16 | DEVPATH=/devices/pci0000:00/0000:00:10.0/usb2 | ||
| 17 | DEVTYPE=usb_device | ||
| 18 | DRIVER=usb | ||
| 19 | ERROR=DEAD | ||
| 20 | MAJOR=189 | ||
| 21 | MINOR=128 | ||
| 22 | PRODUCT=1d6b/2/414 | ||
| 23 | SEQNUM=2168 | ||
| 24 | SUBSYSTEM=usb | ||
| 25 | TYPE=9/0/1 | ||
| 26 | |||
| 27 | Users: chromium-os-dev@chromium.org | ||
diff --git a/Documentation/devicetree/bindings/phy/brcm,stingray-usb-phy.txt b/Documentation/devicetree/bindings/phy/brcm,stingray-usb-phy.txt new file mode 100644 index 000000000000..4ba298966af9 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/brcm,stingray-usb-phy.txt | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | Broadcom Stingray USB PHY | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | - compatible : should be one of the listed compatibles | ||
| 5 | - "brcm,sr-usb-combo-phy" is combo PHY has two PHYs, one SS and one HS. | ||
| 6 | - "brcm,sr-usb-hs-phy" is a single HS PHY. | ||
| 7 | - reg: offset and length of the PHY blocks registers | ||
| 8 | - #phy-cells: | ||
| 9 | - Must be 1 for brcm,sr-usb-combo-phy as it expects one argument to indicate | ||
| 10 | the PHY number of two PHYs. 0 for HS PHY and 1 for SS PHY. | ||
| 11 | - Must be 0 for brcm,sr-usb-hs-phy. | ||
| 12 | |||
| 13 | Refer to phy/phy-bindings.txt for the generic PHY binding properties | ||
| 14 | |||
| 15 | Example: | ||
| 16 | usbphy0: usb-phy@0 { | ||
| 17 | compatible = "brcm,sr-usb-combo-phy"; | ||
| 18 | reg = <0x00000000 0x100>; | ||
| 19 | #phy-cells = <1>; | ||
| 20 | }; | ||
| 21 | |||
| 22 | usbphy1: usb-phy@10000 { | ||
| 23 | compatible = "brcm,sr-usb-combo-phy"; | ||
| 24 | reg = <0x00010000 0x100>, | ||
| 25 | #phy-cells = <1>; | ||
| 26 | }; | ||
| 27 | |||
| 28 | usbphy2: usb-phy@20000 { | ||
| 29 | compatible = "brcm,sr-usb-hs-phy"; | ||
| 30 | reg = <0x00020000 0x100>, | ||
| 31 | #phy-cells = <0>; | ||
| 32 | }; | ||
diff --git a/Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.txt b/Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.txt index a22e853d710c..ed47e5cd067e 100644 --- a/Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.txt +++ b/Documentation/devicetree/bindings/phy/fsl,imx8mq-usb-phy.txt | |||
| @@ -7,6 +7,9 @@ Required properties: | |||
| 7 | - clocks: phandles to the clocks for each clock listed in clock-names | 7 | - clocks: phandles to the clocks for each clock listed in clock-names |
| 8 | - clock-names: must contain "phy" | 8 | - clock-names: must contain "phy" |
| 9 | 9 | ||
| 10 | Optional properties: | ||
| 11 | - vbus-supply: A phandle to the regulator for USB VBUS. | ||
| 12 | |||
| 10 | Example: | 13 | Example: |
| 11 | usb3_phy0: phy@381f0040 { | 14 | usb3_phy0: phy@381f0040 { |
| 12 | compatible = "fsl,imx8mq-usb-phy"; | 15 | compatible = "fsl,imx8mq-usb-phy"; |
diff --git a/Documentation/devicetree/bindings/phy/meson-g12a-usb2-phy.txt b/Documentation/devicetree/bindings/phy/meson-g12a-usb2-phy.txt new file mode 100644 index 000000000000..a6ebc3dea159 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/meson-g12a-usb2-phy.txt | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | * Amlogic G12A USB2 PHY binding | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | - compatible: Should be "amlogic,meson-g12a-usb2-phy" | ||
| 5 | - reg: The base address and length of the registers | ||
| 6 | - #phys-cells: must be 0 (see phy-bindings.txt in this directory) | ||
| 7 | - clocks: a phandle to the clock of this PHY | ||
| 8 | - clock-names: must be "xtal" | ||
| 9 | - resets: a phandle to the reset line of this PHY | ||
| 10 | - reset-names: must be "phy" | ||
| 11 | - phy-supply: see phy-bindings.txt in this directory | ||
| 12 | |||
| 13 | Example: | ||
| 14 | usb2_phy0: phy@36000 { | ||
| 15 | compatible = "amlogic,g12a-usb2-phy"; | ||
| 16 | reg = <0x0 0x36000 0x0 0x2000>; | ||
| 17 | clocks = <&xtal>; | ||
| 18 | clock-names = "xtal"; | ||
| 19 | resets = <&reset RESET_USB_PHY21>; | ||
| 20 | reset-names = "phy"; | ||
| 21 | #phy-cells = <0>; | ||
| 22 | }; | ||
diff --git a/Documentation/devicetree/bindings/phy/meson-g12a-usb3-pcie-phy.txt b/Documentation/devicetree/bindings/phy/meson-g12a-usb3-pcie-phy.txt new file mode 100644 index 000000000000..7cfc17e2df31 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/meson-g12a-usb3-pcie-phy.txt | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | * Amlogic G12A USB3 + PCIE Combo PHY binding | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | - compatible: Should be "amlogic,meson-g12a-usb3-pcie-phy" | ||
| 5 | - #phys-cells: must be 1. The cell number is used to select the phy mode | ||
| 6 | as defined in <dt-bindings/phy/phy.h> between PHY_TYPE_USB3 and PHY_TYPE_PCIE | ||
| 7 | - reg: The base address and length of the registers | ||
| 8 | - clocks: a phandle to the 100MHz reference clock of this PHY | ||
| 9 | - clock-names: must be "ref_clk" | ||
| 10 | - resets: phandle to the reset lines for the PHY control | ||
| 11 | - reset-names: must be "phy" | ||
| 12 | |||
| 13 | Example: | ||
| 14 | usb3_pcie_phy: phy@46000 { | ||
| 15 | compatible = "amlogic,g12a-usb3-pcie-phy"; | ||
| 16 | reg = <0x0 0x46000 0x0 0x2000>; | ||
| 17 | clocks = <&clkc CLKID_PCIE_PLL>; | ||
| 18 | clock-names = "ref_clk"; | ||
| 19 | resets = <&reset RESET_PCIE_PHY>; | ||
| 20 | reset-names = "phy"; | ||
| 21 | #phy-cells = <1>; | ||
| 22 | }; | ||
diff --git a/Documentation/devicetree/bindings/phy/nvidia,tegra124-xusb-padctl.txt b/Documentation/devicetree/bindings/phy/nvidia,tegra124-xusb-padctl.txt index 3742c152c467..daedb15f322e 100644 --- a/Documentation/devicetree/bindings/phy/nvidia,tegra124-xusb-padctl.txt +++ b/Documentation/devicetree/bindings/phy/nvidia,tegra124-xusb-padctl.txt | |||
| @@ -36,11 +36,20 @@ Required properties: | |||
| 36 | - Tegra124: "nvidia,tegra124-xusb-padctl" | 36 | - Tegra124: "nvidia,tegra124-xusb-padctl" |
| 37 | - Tegra132: "nvidia,tegra132-xusb-padctl", "nvidia,tegra124-xusb-padctl" | 37 | - Tegra132: "nvidia,tegra132-xusb-padctl", "nvidia,tegra124-xusb-padctl" |
| 38 | - Tegra210: "nvidia,tegra210-xusb-padctl" | 38 | - Tegra210: "nvidia,tegra210-xusb-padctl" |
| 39 | - Tegra186: "nvidia,tegra186-xusb-padctl" | ||
| 39 | - reg: Physical base address and length of the controller's registers. | 40 | - reg: Physical base address and length of the controller's registers. |
| 40 | - resets: Must contain an entry for each entry in reset-names. | 41 | - resets: Must contain an entry for each entry in reset-names. |
| 41 | - reset-names: Must include the following entries: | 42 | - reset-names: Must include the following entries: |
| 42 | - "padctl" | 43 | - "padctl" |
| 43 | 44 | ||
| 45 | For Tegra186: | ||
| 46 | - avdd-pll-erefeut-supply: UPHY brick and reference clock as well as UTMI PHY | ||
| 47 | power supply. Must supply 1.8 V. | ||
| 48 | - avdd-usb-supply: USB I/Os, VBUS, ID, REXT, D+/D- power supply. Must supply | ||
| 49 | 3.3 V. | ||
| 50 | - vclamp-usb-supply: Bias rail for USB pad. Must supply 1.8 V. | ||
| 51 | - vddio-hsic-supply: HSIC PHY power supply. Must supply 1.2 V. | ||
| 52 | |||
| 44 | 53 | ||
| 45 | Pad nodes: | 54 | Pad nodes: |
| 46 | ========== | 55 | ========== |
diff --git a/Documentation/devicetree/bindings/phy/phy-hi3660-usb3.txt b/Documentation/devicetree/bindings/phy/phy-hi3660-usb3.txt new file mode 100644 index 000000000000..e88ba7d92dcb --- /dev/null +++ b/Documentation/devicetree/bindings/phy/phy-hi3660-usb3.txt | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | Hisilicon hi3660 USB PHY | ||
| 2 | ----------------------- | ||
| 3 | |||
| 4 | Required properties: | ||
| 5 | - compatible: should be "hisilicon,hi3660-usb-phy" | ||
| 6 | - #phy-cells: must be 0 | ||
| 7 | - hisilicon,pericrg-syscon: phandle of syscon used to control phy. | ||
| 8 | - hisilicon,pctrl-syscon: phandle of syscon used to control phy. | ||
| 9 | - hisilicon,eye-diagram-param: parameter set for phy | ||
| 10 | Refer to phy/phy-bindings.txt for the generic PHY binding properties | ||
| 11 | |||
| 12 | This is a subnode of usb3_otg_bc register node. | ||
| 13 | |||
| 14 | Example: | ||
| 15 | usb3_otg_bc: usb3_otg_bc@ff200000 { | ||
| 16 | compatible = "syscon", "simple-mfd"; | ||
| 17 | reg = <0x0 0xff200000 0x0 0x1000>; | ||
| 18 | |||
| 19 | usb-phy { | ||
| 20 | compatible = "hisilicon,hi3660-usb-phy"; | ||
| 21 | #phy-cells = <0>; | ||
| 22 | hisilicon,pericrg-syscon = <&crg_ctrl>; | ||
| 23 | hisilicon,pctrl-syscon = <&pctrl>; | ||
| 24 | hisilicon,eye-diagram-param = <0x22466e4>; | ||
| 25 | }; | ||
| 26 | }; | ||
diff --git a/Documentation/devicetree/bindings/phy/phy-mtk-ufs.txt b/Documentation/devicetree/bindings/phy/phy-mtk-ufs.txt new file mode 100644 index 000000000000..5789029a1d42 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/phy-mtk-ufs.txt | |||
| @@ -0,0 +1,38 @@ | |||
| 1 | MediaTek Universal Flash Storage (UFS) M-PHY binding | ||
| 2 | -------------------------------------------------------- | ||
| 3 | |||
| 4 | UFS M-PHY nodes are defined to describe on-chip UFS M-PHY hardware macro. | ||
| 5 | Each UFS M-PHY node should have its own node. | ||
| 6 | |||
| 7 | To bind UFS M-PHY with UFS host controller, the controller node should | ||
| 8 | contain a phandle reference to UFS M-PHY node. | ||
| 9 | |||
| 10 | Required properties for UFS M-PHY nodes: | ||
| 11 | - compatible : Compatible list, contains the following controller: | ||
| 12 | "mediatek,mt8183-ufsphy" for ufs phy | ||
| 13 | persent on MT81xx chipsets. | ||
| 14 | - reg : Address and length of the UFS M-PHY register set. | ||
| 15 | - #phy-cells : This property shall be set to 0. | ||
| 16 | - clocks : List of phandle and clock specifier pairs. | ||
| 17 | - clock-names : List of clock input name strings sorted in the same | ||
| 18 | order as the clocks property. Following clocks are | ||
| 19 | mandatory. | ||
| 20 | "unipro": Unipro core control clock. | ||
| 21 | "mp": M-PHY core control clock. | ||
| 22 | |||
| 23 | Example: | ||
| 24 | |||
| 25 | ufsphy: phy@11fa0000 { | ||
| 26 | compatible = "mediatek,mt8183-ufsphy"; | ||
| 27 | reg = <0 0x11fa0000 0 0xc000>; | ||
| 28 | #phy-cells = <0>; | ||
| 29 | |||
| 30 | clocks = <&infracfg_ao INFRACFG_AO_UNIPRO_SCK_CG>, | ||
| 31 | <&infracfg_ao INFRACFG_AO_UFS_MP_SAP_BCLK_CG>; | ||
| 32 | clock-names = "unipro", "mp"; | ||
| 33 | }; | ||
| 34 | |||
| 35 | ufshci@11270000 { | ||
| 36 | ... | ||
| 37 | phys = <&ufsphy>; | ||
| 38 | }; | ||
diff --git a/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt b/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt index 5d181fc3cc18..085fbd676cfc 100644 --- a/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt +++ b/Documentation/devicetree/bindings/phy/qcom-qmp-phy.txt | |||
| @@ -11,6 +11,7 @@ Required properties: | |||
| 11 | "qcom,msm8996-qmp-usb3-phy" for 14nm USB3 phy on msm8996, | 11 | "qcom,msm8996-qmp-usb3-phy" for 14nm USB3 phy on msm8996, |
| 12 | "qcom,msm8998-qmp-usb3-phy" for USB3 QMP V3 phy on msm8998, | 12 | "qcom,msm8998-qmp-usb3-phy" for USB3 QMP V3 phy on msm8998, |
| 13 | "qcom,msm8998-qmp-ufs-phy" for UFS QMP phy on msm8998, | 13 | "qcom,msm8998-qmp-ufs-phy" for UFS QMP phy on msm8998, |
| 14 | "qcom,msm8998-qmp-pcie-phy" for PCIe QMP phy on msm8998, | ||
| 14 | "qcom,sdm845-qmp-usb3-phy" for USB3 QMP V3 phy on sdm845, | 15 | "qcom,sdm845-qmp-usb3-phy" for USB3 QMP V3 phy on sdm845, |
| 15 | "qcom,sdm845-qmp-usb3-uni-phy" for USB3 QMP V3 UNI phy on sdm845, | 16 | "qcom,sdm845-qmp-usb3-uni-phy" for USB3 QMP V3 UNI phy on sdm845, |
| 16 | "qcom,sdm845-qmp-ufs-phy" for UFS QMP phy on sdm845. | 17 | "qcom,sdm845-qmp-ufs-phy" for UFS QMP phy on sdm845. |
| @@ -48,6 +49,8 @@ Required properties: | |||
| 48 | "aux", "cfg_ahb", "ref". | 49 | "aux", "cfg_ahb", "ref". |
| 49 | For "qcom,msm8998-qmp-ufs-phy" must contain: | 50 | For "qcom,msm8998-qmp-ufs-phy" must contain: |
| 50 | "ref", "ref_aux". | 51 | "ref", "ref_aux". |
| 52 | For "qcom,msm8998-qmp-pcie-phy" must contain: | ||
| 53 | "aux", "cfg_ahb", "ref". | ||
| 51 | For "qcom,sdm845-qmp-usb3-phy" must contain: | 54 | For "qcom,sdm845-qmp-usb3-phy" must contain: |
| 52 | "aux", "cfg_ahb", "ref", "com_aux". | 55 | "aux", "cfg_ahb", "ref", "com_aux". |
| 53 | For "qcom,sdm845-qmp-usb3-uni-phy" must contain: | 56 | For "qcom,sdm845-qmp-usb3-uni-phy" must contain: |
| @@ -59,7 +62,8 @@ Required properties: | |||
| 59 | one for each entry in reset-names. | 62 | one for each entry in reset-names. |
| 60 | - reset-names: "phy" for reset of phy block, | 63 | - reset-names: "phy" for reset of phy block, |
| 61 | "common" for phy common block reset, | 64 | "common" for phy common block reset, |
| 62 | "cfg" for phy's ahb cfg block reset. | 65 | "cfg" for phy's ahb cfg block reset, |
| 66 | "ufsphy" for the PHY reset in the UFS controller. | ||
| 63 | 67 | ||
| 64 | For "qcom,ipq8074-qmp-pcie-phy" must contain: | 68 | For "qcom,ipq8074-qmp-pcie-phy" must contain: |
| 65 | "phy", "common". | 69 | "phy", "common". |
| @@ -69,12 +73,16 @@ Required properties: | |||
| 69 | "phy", "common". | 73 | "phy", "common". |
| 70 | For "qcom,msm8998-qmp-usb3-phy" must contain | 74 | For "qcom,msm8998-qmp-usb3-phy" must contain |
| 71 | "phy", "common". | 75 | "phy", "common". |
| 72 | For "qcom,msm8998-qmp-ufs-phy": no resets are listed. | 76 | For "qcom,msm8998-qmp-ufs-phy": must contain: |
| 77 | "ufsphy". | ||
| 78 | For "qcom,msm8998-qmp-pcie-phy" must contain: | ||
| 79 | "phy", "common". | ||
| 73 | For "qcom,sdm845-qmp-usb3-phy" must contain: | 80 | For "qcom,sdm845-qmp-usb3-phy" must contain: |
| 74 | "phy", "common". | 81 | "phy", "common". |
| 75 | For "qcom,sdm845-qmp-usb3-uni-phy" must contain: | 82 | For "qcom,sdm845-qmp-usb3-uni-phy" must contain: |
| 76 | "phy", "common". | 83 | "phy", "common". |
| 77 | For "qcom,sdm845-qmp-ufs-phy": no resets are listed. | 84 | For "qcom,sdm845-qmp-ufs-phy": must contain: |
| 85 | "ufsphy". | ||
| 78 | 86 | ||
| 79 | - vdda-phy-supply: Phandle to a regulator supply to PHY core block. | 87 | - vdda-phy-supply: Phandle to a regulator supply to PHY core block. |
| 80 | - vdda-pll-supply: Phandle to 1.8V regulator supply to PHY refclk pll block. | 88 | - vdda-pll-supply: Phandle to 1.8V regulator supply to PHY refclk pll block. |
diff --git a/Documentation/devicetree/bindings/phy/rcar-gen2-phy.txt b/Documentation/devicetree/bindings/phy/rcar-gen2-phy.txt index 4f0879a0ca12..ac96d6481bb8 100644 --- a/Documentation/devicetree/bindings/phy/rcar-gen2-phy.txt +++ b/Documentation/devicetree/bindings/phy/rcar-gen2-phy.txt | |||
| @@ -7,6 +7,7 @@ Required properties: | |||
| 7 | - compatible: "renesas,usb-phy-r8a7743" if the device is a part of R8A7743 SoC. | 7 | - compatible: "renesas,usb-phy-r8a7743" if the device is a part of R8A7743 SoC. |
| 8 | "renesas,usb-phy-r8a7744" if the device is a part of R8A7744 SoC. | 8 | "renesas,usb-phy-r8a7744" if the device is a part of R8A7744 SoC. |
| 9 | "renesas,usb-phy-r8a7745" if the device is a part of R8A7745 SoC. | 9 | "renesas,usb-phy-r8a7745" if the device is a part of R8A7745 SoC. |
| 10 | "renesas,usb-phy-r8a77470" if the device is a part of R8A77470 SoC. | ||
| 10 | "renesas,usb-phy-r8a7790" if the device is a part of R8A7790 SoC. | 11 | "renesas,usb-phy-r8a7790" if the device is a part of R8A7790 SoC. |
| 11 | "renesas,usb-phy-r8a7791" if the device is a part of R8A7791 SoC. | 12 | "renesas,usb-phy-r8a7791" if the device is a part of R8A7791 SoC. |
| 12 | "renesas,usb-phy-r8a7794" if the device is a part of R8A7794 SoC. | 13 | "renesas,usb-phy-r8a7794" if the device is a part of R8A7794 SoC. |
| @@ -30,7 +31,7 @@ channels. These subnodes must contain the following properties: | |||
| 30 | - #phy-cells: see phy-bindings.txt in the same directory, must be <1>. | 31 | - #phy-cells: see phy-bindings.txt in the same directory, must be <1>. |
| 31 | 32 | ||
| 32 | The phandle's argument in the PHY specifier is the USB controller selector for | 33 | The phandle's argument in the PHY specifier is the USB controller selector for |
| 33 | the USB channel; see the selector meanings below: | 34 | the USB channel other than r8a77470 SoC; see the selector meanings below: |
| 34 | 35 | ||
| 35 | +-----------+---------------+---------------+ | 36 | +-----------+---------------+---------------+ |
| 36 | |\ Selector | | | | 37 | |\ Selector | | | |
| @@ -41,6 +42,16 @@ the USB channel; see the selector meanings below: | |||
| 41 | | 2 | PCI EHCI/OHCI | xHCI | | 42 | | 2 | PCI EHCI/OHCI | xHCI | |
| 42 | +-----------+---------------+---------------+ | 43 | +-----------+---------------+---------------+ |
| 43 | 44 | ||
| 45 | For r8a77470 SoC;see the selector meaning below: | ||
| 46 | |||
| 47 | +-----------+---------------+---------------+ | ||
| 48 | |\ Selector | | | | ||
| 49 | + --------- + 0 | 1 | | ||
| 50 | | Channel \| | | | ||
| 51 | +-----------+---------------+---------------+ | ||
| 52 | | 0 | EHCI/OHCI | HS-USB | | ||
| 53 | +-----------+---------------+---------------+ | ||
| 54 | |||
| 44 | Example (Lager board): | 55 | Example (Lager board): |
| 45 | 56 | ||
| 46 | usb-phy@e6590100 { | 57 | usb-phy@e6590100 { |
| @@ -48,15 +59,53 @@ Example (Lager board): | |||
| 48 | reg = <0 0xe6590100 0 0x100>; | 59 | reg = <0 0xe6590100 0 0x100>; |
| 49 | #address-cells = <1>; | 60 | #address-cells = <1>; |
| 50 | #size-cells = <0>; | 61 | #size-cells = <0>; |
| 51 | clocks = <&mstp7_clks R8A7790_CLK_HSUSB>; | 62 | clocks = <&cpg CPG_MOD 704>; |
| 52 | clock-names = "usbhs"; | 63 | clock-names = "usbhs"; |
| 64 | power-domains = <&sysc R8A7790_PD_ALWAYS_ON>; | ||
| 65 | resets = <&cpg 704>; | ||
| 53 | 66 | ||
| 54 | usb-channel@0 { | 67 | usb0: usb-channel@0 { |
| 55 | reg = <0>; | 68 | reg = <0>; |
| 56 | #phy-cells = <1>; | 69 | #phy-cells = <1>; |
| 57 | }; | 70 | }; |
| 58 | usb-channel@2 { | 71 | usb2: usb-channel@2 { |
| 59 | reg = <2>; | 72 | reg = <2>; |
| 60 | #phy-cells = <1>; | 73 | #phy-cells = <1>; |
| 61 | }; | 74 | }; |
| 62 | }; | 75 | }; |
| 76 | |||
| 77 | Example (iWave RZ/G1C sbc): | ||
| 78 | |||
| 79 | usbphy0: usb-phy0@e6590100 { | ||
| 80 | compatible = "renesas,usb-phy-r8a77470", | ||
| 81 | "renesas,rcar-gen2-usb-phy"; | ||
| 82 | reg = <0 0xe6590100 0 0x100>; | ||
| 83 | #address-cells = <1>; | ||
| 84 | #size-cells = <0>; | ||
| 85 | clocks = <&cpg CPG_MOD 704>; | ||
| 86 | clock-names = "usbhs"; | ||
| 87 | power-domains = <&sysc R8A77470_PD_ALWAYS_ON>; | ||
| 88 | resets = <&cpg 704>; | ||
| 89 | |||
| 90 | usb0: usb-channel@0 { | ||
| 91 | reg = <0>; | ||
| 92 | #phy-cells = <1>; | ||
| 93 | }; | ||
| 94 | }; | ||
| 95 | |||
| 96 | usbphy1: usb-phy@e6598100 { | ||
| 97 | compatible = "renesas,usb-phy-r8a77470", | ||
| 98 | "renesas,rcar-gen2-usb-phy"; | ||
| 99 | reg = <0 0xe6598100 0 0x100>; | ||
| 100 | #address-cells = <1>; | ||
| 101 | #size-cells = <0>; | ||
| 102 | clocks = <&cpg CPG_MOD 706>; | ||
| 103 | clock-names = "usbhs"; | ||
| 104 | power-domains = <&sysc R8A77470_PD_ALWAYS_ON>; | ||
| 105 | resets = <&cpg 706>; | ||
| 106 | |||
| 107 | usb1: usb-channel@0 { | ||
| 108 | reg = <0>; | ||
| 109 | #phy-cells = <1>; | ||
| 110 | }; | ||
| 111 | }; | ||
diff --git a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt index ad9c290d8f15..d46188f450bf 100644 --- a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt +++ b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb2.txt | |||
| @@ -1,10 +1,12 @@ | |||
| 1 | * Renesas R-Car generation 3 USB 2.0 PHY | 1 | * Renesas R-Car generation 3 USB 2.0 PHY |
| 2 | 2 | ||
| 3 | This file provides information on what the device node for the R-Car generation | 3 | This file provides information on what the device node for the R-Car generation |
| 4 | 3 and RZ/G2 USB 2.0 PHY contain. | 4 | 3, RZ/G1C and RZ/G2 USB 2.0 PHY contain. |
| 5 | 5 | ||
| 6 | Required properties: | 6 | Required properties: |
| 7 | - compatible: "renesas,usb2-phy-r8a774a1" if the device is a part of an R8A774A1 | 7 | - compatible: "renesas,usb2-phy-r8a77470" if the device is a part of an R8A77470 |
| 8 | SoC. | ||
| 9 | "renesas,usb2-phy-r8a774a1" if the device is a part of an R8A774A1 | ||
| 8 | SoC. | 10 | SoC. |
| 9 | "renesas,usb2-phy-r8a774c0" if the device is a part of an R8A774C0 | 11 | "renesas,usb2-phy-r8a774c0" if the device is a part of an R8A774C0 |
| 10 | SoC. | 12 | SoC. |
| @@ -27,7 +29,13 @@ Required properties: | |||
| 27 | 29 | ||
| 28 | - reg: offset and length of the partial USB 2.0 Host register block. | 30 | - reg: offset and length of the partial USB 2.0 Host register block. |
| 29 | - clocks: clock phandle and specifier pair(s). | 31 | - clocks: clock phandle and specifier pair(s). |
| 30 | - #phy-cells: see phy-bindings.txt in the same directory, must be <0>. | 32 | - #phy-cells: see phy-bindings.txt in the same directory, must be <1> (and |
| 33 | using <0> is deprecated). | ||
| 34 | |||
| 35 | The phandle's argument in the PHY specifier is the INT_STATUS bit of controller: | ||
| 36 | - 1 = USBH_INTA (OHCI) | ||
| 37 | - 2 = USBH_INTB (EHCI) | ||
| 38 | - 3 = UCOM_INT (OTG and BC) | ||
| 31 | 39 | ||
| 32 | Optional properties: | 40 | Optional properties: |
| 33 | To use a USB channel where USB 2.0 Host and HSUSB (USB 2.0 Peripheral) are | 41 | To use a USB channel where USB 2.0 Host and HSUSB (USB 2.0 Peripheral) are |
diff --git a/Documentation/devicetree/bindings/phy/rockchip-emmc-phy.txt b/Documentation/devicetree/bindings/phy/rockchip-emmc-phy.txt index e3ea55763b0a..e728786f21e0 100644 --- a/Documentation/devicetree/bindings/phy/rockchip-emmc-phy.txt +++ b/Documentation/devicetree/bindings/phy/rockchip-emmc-phy.txt | |||
| @@ -7,12 +7,15 @@ Required properties: | |||
| 7 | - reg: PHY register address offset and length in "general | 7 | - reg: PHY register address offset and length in "general |
| 8 | register files" | 8 | register files" |
| 9 | 9 | ||
| 10 | Optional clocks using the clock bindings (see ../clock/clock-bindings.txt), | 10 | Optional properties: |
| 11 | specified by name: | ||
| 12 | - clock-names: Should contain "emmcclk". Although this is listed as optional | 11 | - clock-names: Should contain "emmcclk". Although this is listed as optional |
| 13 | (because most boards can get basic functionality without having | 12 | (because most boards can get basic functionality without having |
| 14 | access to it), it is strongly suggested. | 13 | access to it), it is strongly suggested. |
| 14 | See ../clock/clock-bindings.txt for details. | ||
| 15 | - clocks: Should have a phandle to the card clock exported by the SDHCI driver. | 15 | - clocks: Should have a phandle to the card clock exported by the SDHCI driver. |
| 16 | - drive-impedance-ohm: Specifies the drive impedance in Ohm. | ||
| 17 | Possible values are 33, 40, 50, 66 and 100. | ||
| 18 | If not set, the default value of 50 will be applied. | ||
| 16 | 19 | ||
| 17 | Example: | 20 | Example: |
| 18 | 21 | ||
| @@ -29,6 +32,7 @@ grf: syscon@ff770000 { | |||
| 29 | reg = <0xf780 0x20>; | 32 | reg = <0xf780 0x20>; |
| 30 | clocks = <&sdhci>; | 33 | clocks = <&sdhci>; |
| 31 | clock-names = "emmcclk"; | 34 | clock-names = "emmcclk"; |
| 35 | drive-impedance-ohm = <50>; | ||
| 32 | #phy-cells = <0>; | 36 | #phy-cells = <0>; |
| 33 | }; | 37 | }; |
| 34 | }; | 38 | }; |
diff --git a/Documentation/devicetree/bindings/phy/ti,phy-am654-serdes.txt b/Documentation/devicetree/bindings/phy/ti,phy-am654-serdes.txt new file mode 100644 index 000000000000..64b286d2d398 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/ti,phy-am654-serdes.txt | |||
| @@ -0,0 +1,82 @@ | |||
| 1 | TI AM654 SERDES | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | - compatible: Should be "ti,phy-am654-serdes" | ||
| 5 | - reg : Address and length of the register set for the device. | ||
| 6 | - #phy-cells: determine the number of cells that should be given in the | ||
| 7 | phandle while referencing this phy. Should be "2". The 1st cell | ||
| 8 | corresponds to the phy type (should be one of the types specified in | ||
| 9 | include/dt-bindings/phy/phy.h) and the 2nd cell should be the serdes | ||
| 10 | lane function. | ||
| 11 | If SERDES0 is referenced 2nd cell should be: | ||
| 12 | 0 - USB3 | ||
| 13 | 1 - PCIe0 Lane0 | ||
| 14 | 2 - ICSS2 SGMII Lane0 | ||
| 15 | If SERDES1 is referenced 2nd cell should be: | ||
| 16 | 0 - PCIe1 Lane0 | ||
| 17 | 1 - PCIe0 Lane1 | ||
| 18 | 2 - ICSS2 SGMII Lane1 | ||
| 19 | - power-domains: As documented by the generic PM domain bindings in | ||
| 20 | Documentation/devicetree/bindings/power/power_domain.txt. | ||
| 21 | - clocks: List of clock-specifiers representing the input to the SERDES. | ||
| 22 | Should have 3 items representing the left input clock, external | ||
| 23 | reference clock and right input clock in that order. | ||
| 24 | - clock-output-names: List of clock names for each of the clock outputs of | ||
| 25 | SERDES. Should have 3 items for CMU reference clock, | ||
| 26 | left output clock and right output clock in that order. | ||
| 27 | - assigned-clocks: As defined in | ||
| 28 | Documentation/devicetree/bindings/clock/clock-bindings.txt | ||
| 29 | - assigned-clock-parents: As defined in | ||
| 30 | Documentation/devicetree/bindings/clock/clock-bindings.txt | ||
| 31 | - #clock-cells: Should be <1> to choose between the 3 output clocks. | ||
| 32 | Defined in Documentation/devicetree/bindings/clock/clock-bindings.txt | ||
| 33 | |||
| 34 | The following macros are defined in dt-bindings/phy/phy-am654-serdes.h | ||
| 35 | for selecting the correct reference clock. This can be used while | ||
| 36 | specifying the clocks created by SERDES. | ||
| 37 | => AM654_SERDES_CMU_REFCLK | ||
| 38 | => AM654_SERDES_LO_REFCLK | ||
| 39 | => AM654_SERDES_RO_REFCLK | ||
| 40 | |||
| 41 | - mux-controls: Phandle to the multiplexer that is used to select the lane | ||
| 42 | function. See #phy-cells above to see the multiplex values. | ||
| 43 | |||
| 44 | Example: | ||
| 45 | |||
| 46 | Example for SERDES0 is given below. It has 3 clock inputs; | ||
| 47 | left input reference clock as indicated by <&k3_clks 153 4>, external | ||
| 48 | reference clock as indicated by <&k3_clks 153 1> and right input | ||
| 49 | reference clock as indicated by <&serdes1 AM654_SERDES_LO_REFCLK>. (The | ||
| 50 | right input of SERDES0 is connected to the left output of SERDES1). | ||
| 51 | |||
| 52 | SERDES0 registers 3 clock outputs as indicated in clock-output-names. The | ||
| 53 | first refers to the CMU reference clock, second refers to the left output | ||
| 54 | reference clock and the third refers to the right output reference clock. | ||
| 55 | |||
| 56 | The assigned-clocks and assigned-clock-parents is used here to set the | ||
| 57 | parent of left input reference clock to MAINHSDIV_CLKOUT4 and parent of | ||
| 58 | CMU reference clock to left input reference clock. | ||
| 59 | |||
| 60 | serdes0: serdes@900000 { | ||
| 61 | compatible = "ti,phy-am654-serdes"; | ||
| 62 | reg = <0x0 0x900000 0x0 0x2000>; | ||
| 63 | reg-names = "serdes"; | ||
| 64 | #phy-cells = <2>; | ||
| 65 | power-domains = <&k3_pds 153>; | ||
| 66 | clocks = <&k3_clks 153 4>, <&k3_clks 153 1>, | ||
| 67 | <&serdes1 AM654_SERDES_LO_REFCLK>; | ||
| 68 | clock-output-names = "serdes0_cmu_refclk", "serdes0_lo_refclk", | ||
| 69 | "serdes0_ro_refclk"; | ||
| 70 | assigned-clocks = <&k3_clks 153 4>, <&serdes0 AM654_SERDES_CMU_REFCLK>; | ||
| 71 | assigned-clock-parents = <&k3_clks 153 8>, <&k3_clks 153 4>; | ||
| 72 | ti,serdes-clk = <&serdes0_clk>; | ||
| 73 | mux-controls = <&serdes_mux 0>; | ||
| 74 | #clock-cells = <1>; | ||
| 75 | }; | ||
| 76 | |||
| 77 | Example for PCIe consumer node using the SERDES PHY specifier is given below. | ||
| 78 | &pcie0_rc { | ||
| 79 | num-lanes = <2>; | ||
| 80 | phys = <&serdes0 PHY_TYPE_PCIE 1>, <&serdes1 PHY_TYPE_PCIE 1>; | ||
| 81 | phy-names = "pcie-phy0", "pcie-phy1"; | ||
| 82 | }; | ||
diff --git a/Documentation/devicetree/bindings/ufs/ufs-qcom.txt b/Documentation/devicetree/bindings/ufs/ufs-qcom.txt index 21d9a93db2e9..fd59f93e9556 100644 --- a/Documentation/devicetree/bindings/ufs/ufs-qcom.txt +++ b/Documentation/devicetree/bindings/ufs/ufs-qcom.txt | |||
| @@ -29,6 +29,7 @@ Optional properties: | |||
| 29 | - vdda-pll-max-microamp : specifies max. load that can be drawn from pll supply | 29 | - vdda-pll-max-microamp : specifies max. load that can be drawn from pll supply |
| 30 | - vddp-ref-clk-supply : phandle to UFS device ref_clk pad power supply | 30 | - vddp-ref-clk-supply : phandle to UFS device ref_clk pad power supply |
| 31 | - vddp-ref-clk-max-microamp : specifies max. load that can be drawn from this supply | 31 | - vddp-ref-clk-max-microamp : specifies max. load that can be drawn from this supply |
| 32 | - resets : specifies the PHY reset in the UFS controller | ||
| 32 | 33 | ||
| 33 | Example: | 34 | Example: |
| 34 | 35 | ||
| @@ -51,9 +52,11 @@ Example: | |||
| 51 | <&clock_gcc clk_ufs_phy_ldo>, | 52 | <&clock_gcc clk_ufs_phy_ldo>, |
| 52 | <&clock_gcc clk_gcc_ufs_tx_cfg_clk>, | 53 | <&clock_gcc clk_gcc_ufs_tx_cfg_clk>, |
| 53 | <&clock_gcc clk_gcc_ufs_rx_cfg_clk>; | 54 | <&clock_gcc clk_gcc_ufs_rx_cfg_clk>; |
| 55 | resets = <&ufshc 0>; | ||
| 54 | }; | 56 | }; |
| 55 | 57 | ||
| 56 | ufshc@fc598000 { | 58 | ufshc: ufshc@fc598000 { |
| 59 | #reset-cells = <1>; | ||
| 57 | ... | 60 | ... |
| 58 | phys = <&ufsphy1>; | 61 | phys = <&ufsphy1>; |
| 59 | phy-names = "ufsphy"; | 62 | phy-names = "ufsphy"; |
diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt index 5111e9130bc3..f647c09bc62a 100644 --- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt +++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt | |||
| @@ -50,6 +50,8 @@ Optional properties: | |||
| 50 | -lanes-per-direction : number of lanes available per direction - either 1 or 2. | 50 | -lanes-per-direction : number of lanes available per direction - either 1 or 2. |
| 51 | Note that it is assume same number of lanes is used both | 51 | Note that it is assume same number of lanes is used both |
| 52 | directions at once. If not specified, default is 2 lanes per direction. | 52 | directions at once. If not specified, default is 2 lanes per direction. |
| 53 | - #reset-cells : Must be <1> for Qualcomm UFS controllers that expose | ||
| 54 | PHY reset from the UFS controller. | ||
| 53 | - resets : reset node register | 55 | - resets : reset node register |
| 54 | - reset-names : describe reset node register, the "rst" corresponds to reset the whole UFS IP. | 56 | - reset-names : describe reset node register, the "rst" corresponds to reset the whole UFS IP. |
| 55 | 57 | ||
| @@ -79,4 +81,5 @@ Example: | |||
| 79 | reset-names = "rst"; | 81 | reset-names = "rst"; |
| 80 | phys = <&ufsphy1>; | 82 | phys = <&ufsphy1>; |
| 81 | phy-names = "ufsphy"; | 83 | phy-names = "ufsphy"; |
| 84 | #reset-cells = <1>; | ||
| 82 | }; | 85 | }; |
diff --git a/Documentation/devicetree/bindings/usb/amlogic,dwc3.txt b/Documentation/devicetree/bindings/usb/amlogic,dwc3.txt index 9a8b631904fd..b9f04e617eb7 100644 --- a/Documentation/devicetree/bindings/usb/amlogic,dwc3.txt +++ b/Documentation/devicetree/bindings/usb/amlogic,dwc3.txt | |||
| @@ -40,3 +40,91 @@ Example device nodes: | |||
| 40 | phy-names = "usb2-phy", "usb3-phy"; | 40 | phy-names = "usb2-phy", "usb3-phy"; |
| 41 | }; | 41 | }; |
| 42 | }; | 42 | }; |
| 43 | |||
| 44 | Amlogic Meson G12A DWC3 USB SoC Controller Glue | ||
| 45 | |||
| 46 | The Amlogic G12A embeds a DWC3 USB IP Core configured for USB2 and USB3 | ||
| 47 | in host-only mode, and a DWC2 IP Core configured for USB2 peripheral mode | ||
| 48 | only. | ||
| 49 | |||
| 50 | A glue connects the DWC3 core to USB2 PHYs and optionnaly to an USB3 PHY. | ||
| 51 | |||
| 52 | One of the USB2 PHY can be re-routed in peripheral mode to a DWC2 USB IP. | ||
| 53 | |||
| 54 | The DWC3 Glue controls the PHY routing and power, an interrupt line is | ||
| 55 | connected to the Glue to serve as OTG ID change detection. | ||
| 56 | |||
| 57 | Required properties: | ||
| 58 | - compatible: Should be "amlogic,meson-g12a-usb-ctrl" | ||
| 59 | - clocks: a handle for the "USB" clock | ||
| 60 | - resets: a handle for the shared "USB" reset line | ||
| 61 | - reg: The base address and length of the registers | ||
| 62 | - interrupts: the interrupt specifier for the OTG detection | ||
| 63 | - phys: handle to used PHYs on the system | ||
| 64 | - a <0> phandle can be used if a PHY is not used | ||
| 65 | - phy-names: names of the used PHYs on the system : | ||
| 66 | - "usb2-phy0" for USB2 PHY0 if USBHOST_A port is used | ||
| 67 | - "usb2-phy1" for USB2 PHY1 if USBOTG_B port is used | ||
| 68 | - "usb3-phy0" for USB3 PHY if USB3_0 is used | ||
| 69 | - dr_mode: should be "host", "peripheral", or "otg" depending on | ||
| 70 | the usage and configuration of the OTG Capable port. | ||
| 71 | - "host" and "peripheral" means a fixed Host or Device only connection | ||
| 72 | - "otg" means the port can be used as both Host or Device and | ||
| 73 | be switched automatically using the OTG ID pin. | ||
| 74 | |||
| 75 | Optional properties: | ||
| 76 | - vbus-supply: should be a phandle to the regulator controlling the VBUS | ||
| 77 | power supply when used in OTG switchable mode | ||
| 78 | |||
| 79 | Required child nodes: | ||
| 80 | |||
| 81 | A child node must exist to represent the core DWC3 IP block. The name of | ||
| 82 | the node is not important. The content of the node is defined in dwc3.txt. | ||
| 83 | |||
| 84 | A child node must exist to represent the core DWC2 IP block. The name of | ||
| 85 | the node is not important. The content of the node is defined in dwc2.txt. | ||
| 86 | |||
| 87 | PHY documentation is provided in the following places: | ||
| 88 | - Documentation/devicetree/bindings/phy/meson-g12a-usb2-phy.txt | ||
| 89 | - Documentation/devicetree/bindings/phy/meson-g12a-usb3-pcie-phy.txt | ||
| 90 | |||
| 91 | Example device nodes: | ||
| 92 | usb: usb@ffe09000 { | ||
| 93 | compatible = "amlogic,meson-g12a-usb-ctrl"; | ||
| 94 | reg = <0x0 0xffe09000 0x0 0xa0>; | ||
| 95 | interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>; | ||
| 96 | #address-cells = <2>; | ||
| 97 | #size-cells = <2>; | ||
| 98 | ranges; | ||
| 99 | |||
| 100 | clocks = <&clkc CLKID_USB>; | ||
| 101 | resets = <&reset RESET_USB>; | ||
| 102 | |||
| 103 | dr_mode = "otg"; | ||
| 104 | |||
| 105 | phys = <&usb2_phy0>, <&usb2_phy1>, | ||
| 106 | <&usb3_pcie_phy PHY_TYPE_USB3>; | ||
| 107 | phy-names = "usb2-phy0", "usb2-phy1", "usb3-phy0"; | ||
| 108 | |||
| 109 | dwc2: usb@ff400000 { | ||
| 110 | compatible = "amlogic,meson-g12a-usb", "snps,dwc2"; | ||
| 111 | reg = <0x0 0xff400000 0x0 0x40000>; | ||
| 112 | interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>; | ||
| 113 | clocks = <&clkc CLKID_USB1_DDR_BRIDGE>; | ||
| 114 | clock-names = "ddr"; | ||
| 115 | phys = <&usb2_phy1>; | ||
| 116 | dr_mode = "peripheral"; | ||
| 117 | g-rx-fifo-size = <192>; | ||
| 118 | g-np-tx-fifo-size = <128>; | ||
| 119 | g-tx-fifo-size = <128 128 16 16 16>; | ||
| 120 | }; | ||
| 121 | |||
| 122 | dwc3: usb@ff500000 { | ||
| 123 | compatible = "snps,dwc3"; | ||
| 124 | reg = <0x0 0xff500000 0x0 0x100000>; | ||
| 125 | interrupts = <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>; | ||
| 126 | dr_mode = "host"; | ||
| 127 | snps,dis_u2_susphy_quirk; | ||
| 128 | snps,quirk-frame-length-adjustment; | ||
| 129 | }; | ||
| 130 | }; | ||
diff --git a/Documentation/devicetree/bindings/usb/dwc2.txt b/Documentation/devicetree/bindings/usb/dwc2.txt index 6dc3c4a34483..49eac0dc86b0 100644 --- a/Documentation/devicetree/bindings/usb/dwc2.txt +++ b/Documentation/devicetree/bindings/usb/dwc2.txt | |||
| @@ -14,6 +14,7 @@ Required properties: | |||
| 14 | - "amlogic,meson8-usb": The DWC2 USB controller instance in Amlogic Meson8 SoCs; | 14 | - "amlogic,meson8-usb": The DWC2 USB controller instance in Amlogic Meson8 SoCs; |
| 15 | - "amlogic,meson8b-usb": The DWC2 USB controller instance in Amlogic Meson8b SoCs; | 15 | - "amlogic,meson8b-usb": The DWC2 USB controller instance in Amlogic Meson8b SoCs; |
| 16 | - "amlogic,meson-gxbb-usb": The DWC2 USB controller instance in Amlogic S905 SoCs; | 16 | - "amlogic,meson-gxbb-usb": The DWC2 USB controller instance in Amlogic S905 SoCs; |
| 17 | - "amlogic,meson-g12a-usb": The DWC2 USB controller instance in Amlogic G12A SoCs; | ||
| 17 | - "amcc,dwc-otg": The DWC2 USB controller instance in AMCC Canyonlands 460EX SoCs; | 18 | - "amcc,dwc-otg": The DWC2 USB controller instance in AMCC Canyonlands 460EX SoCs; |
| 18 | - snps,dwc2: A generic DWC2 USB controller with default parameters. | 19 | - snps,dwc2: A generic DWC2 USB controller with default parameters. |
| 19 | - "st,stm32f4x9-fsotg": The DWC2 USB FS/HS controller instance in STM32F4x9 SoCs | 20 | - "st,stm32f4x9-fsotg": The DWC2 USB FS/HS controller instance in STM32F4x9 SoCs |
| @@ -31,12 +32,18 @@ Refer to clk/clock-bindings.txt for generic clock consumer properties | |||
| 31 | Optional properties: | 32 | Optional properties: |
| 32 | - phys: phy provider specifier | 33 | - phys: phy provider specifier |
| 33 | - phy-names: shall be "usb2-phy" | 34 | - phy-names: shall be "usb2-phy" |
| 35 | - vbus-supply: reference to the VBUS regulator. Depending on the current mode | ||
| 36 | this is enabled (in "host" mode") or disabled (in "peripheral" mode). The | ||
| 37 | regulator is updated if the controller is configured in "otg" mode and the | ||
| 38 | status changes between "host" and "peripheral". | ||
| 34 | Refer to phy/phy-bindings.txt for generic phy consumer properties | 39 | Refer to phy/phy-bindings.txt for generic phy consumer properties |
| 35 | - dr_mode: shall be one of "host", "peripheral" and "otg" | 40 | - dr_mode: shall be one of "host", "peripheral" and "otg" |
| 36 | Refer to usb/generic.txt | 41 | Refer to usb/generic.txt |
| 37 | - g-rx-fifo-size: size of rx fifo size in gadget mode. | 42 | - g-rx-fifo-size: size of rx fifo size in gadget mode. |
| 38 | - g-np-tx-fifo-size: size of non-periodic tx fifo size in gadget mode. | 43 | - g-np-tx-fifo-size: size of non-periodic tx fifo size in gadget mode. |
| 39 | - g-tx-fifo-size: size of periodic tx fifo per endpoint (except ep0) in gadget mode. | 44 | - g-tx-fifo-size: size of periodic tx fifo per endpoint (except ep0) in gadget mode. |
| 45 | - snps,reset-phy-on-wake: If present indicates that we need to reset the PHY when | ||
| 46 | we detect a wakeup. This is due to a hardware errata. | ||
| 40 | 47 | ||
| 41 | Deprecated properties: | 48 | Deprecated properties: |
| 42 | - g-use-dma: gadget DMA mode is automatically detected | 49 | - g-use-dma: gadget DMA mode is automatically detected |
diff --git a/Documentation/devicetree/bindings/usb/generic-ehci.yaml b/Documentation/devicetree/bindings/usb/generic-ehci.yaml new file mode 100644 index 000000000000..d3b4f6415920 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/generic-ehci.yaml | |||
| @@ -0,0 +1,95 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/usb/generic-ehci.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: USB EHCI Controller Device Tree Bindings | ||
| 8 | |||
| 9 | allOf: | ||
| 10 | - $ref: "usb-hcd.yaml" | ||
| 11 | |||
| 12 | maintainers: | ||
| 13 | - Greg Kroah-Hartman <gregkh@linuxfoundation.org> | ||
| 14 | |||
| 15 | properties: | ||
| 16 | compatible: | ||
| 17 | contains: | ||
| 18 | const: generic-ehci | ||
| 19 | |||
| 20 | reg: | ||
| 21 | maxItems: 1 | ||
| 22 | |||
| 23 | interrupts: | ||
| 24 | maxItems: 1 | ||
| 25 | |||
| 26 | resets: | ||
| 27 | minItems: 1 | ||
| 28 | maxItems: 4 | ||
| 29 | |||
| 30 | clocks: | ||
| 31 | minItems: 1 | ||
| 32 | maxItems: 4 | ||
| 33 | description: | | ||
| 34 | In case the Renesas R-Car Gen3 SoCs: | ||
| 35 | - if a host only channel: first clock should be host. | ||
| 36 | - if a USB DRD channel: first clock should be host and second | ||
| 37 | one should be peripheral | ||
| 38 | |||
| 39 | big-endian: | ||
| 40 | $ref: /schemas/types.yaml#/definitions/flag | ||
| 41 | description: | ||
| 42 | Set this flag for HCDs with big endian descriptors and big | ||
| 43 | endian registers. | ||
| 44 | |||
| 45 | big-endian-desc: | ||
| 46 | $ref: /schemas/types.yaml#/definitions/flag | ||
| 47 | description: | ||
| 48 | Set this flag for HCDs with big endian descriptors. | ||
| 49 | |||
| 50 | big-endian-regs: | ||
| 51 | $ref: /schemas/types.yaml#/definitions/flag | ||
| 52 | description: | ||
| 53 | Set this flag for HCDs with big endian registers. | ||
| 54 | |||
| 55 | has-transaction-translator: | ||
| 56 | $ref: /schemas/types.yaml#/definitions/flag | ||
| 57 | description: | ||
| 58 | Set this flag if EHCI has a Transaction Translator built into | ||
| 59 | the root hub. | ||
| 60 | |||
| 61 | needs-reset-on-resume: | ||
| 62 | $ref: /schemas/types.yaml#/definitions/flag | ||
| 63 | description: | ||
| 64 | Set this flag to force EHCI reset after resume. | ||
| 65 | |||
| 66 | phys: true | ||
| 67 | |||
| 68 | required: | ||
| 69 | - compatible | ||
| 70 | - reg | ||
| 71 | - interrupts | ||
| 72 | |||
| 73 | additionalProperties: false | ||
| 74 | |||
| 75 | examples: | ||
| 76 | - | | ||
| 77 | ehci@e0000300 { | ||
| 78 | compatible = "ibm,usb-ehci-440epx", "generic-ehci"; | ||
| 79 | interrupt-parent = <&UIC0>; | ||
| 80 | interrupts = <0x1a 4>; | ||
| 81 | reg = <0 0xe0000300 90 0 0xe0000390 70>; | ||
| 82 | big-endian; | ||
| 83 | }; | ||
| 84 | |||
| 85 | - | | ||
| 86 | ehci0: usb@1c14000 { | ||
| 87 | compatible = "allwinner,sun4i-a10-ehci", "generic-ehci"; | ||
| 88 | reg = <0x01c14000 0x100>; | ||
| 89 | interrupts = <39>; | ||
| 90 | clocks = <&ahb_gates 1>; | ||
| 91 | phys = <&usbphy 1>; | ||
| 92 | phy-names = "usb"; | ||
| 93 | }; | ||
| 94 | |||
| 95 | ... | ||
diff --git a/Documentation/devicetree/bindings/usb/generic-ohci.yaml b/Documentation/devicetree/bindings/usb/generic-ohci.yaml new file mode 100644 index 000000000000..da5a14becbe5 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/generic-ohci.yaml | |||
| @@ -0,0 +1,89 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/usb/generic-ohci.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: USB OHCI Controller Device Tree Bindings | ||
| 8 | |||
| 9 | allOf: | ||
| 10 | - $ref: "usb-hcd.yaml" | ||
| 11 | |||
| 12 | maintainers: | ||
| 13 | - Greg Kroah-Hartman <gregkh@linuxfoundation.org> | ||
| 14 | |||
| 15 | properties: | ||
| 16 | compatible: | ||
| 17 | contains: | ||
| 18 | const: generic-ohci | ||
| 19 | |||
| 20 | reg: | ||
| 21 | maxItems: 1 | ||
| 22 | |||
| 23 | interrupts: | ||
| 24 | maxItems: 1 | ||
| 25 | |||
| 26 | resets: | ||
| 27 | minItems: 1 | ||
| 28 | maxItems: 2 | ||
| 29 | |||
| 30 | clocks: | ||
| 31 | minItems: 1 | ||
| 32 | maxItems: 3 | ||
| 33 | description: | | ||
| 34 | In case the Renesas R-Car Gen3 SoCs: | ||
| 35 | - if a host only channel: first clock should be host. | ||
| 36 | - if a USB DRD channel: first clock should be host and second | ||
| 37 | one should be peripheral | ||
| 38 | |||
| 39 | big-endian: | ||
| 40 | $ref: /schemas/types.yaml#/definitions/flag | ||
| 41 | description: | ||
| 42 | Set this flag for HCDs with big endian descriptors and big | ||
| 43 | endian registers. | ||
| 44 | |||
| 45 | big-endian-desc: | ||
| 46 | $ref: /schemas/types.yaml#/definitions/flag | ||
| 47 | description: | ||
| 48 | Set this flag for HCDs with big endian descriptors. | ||
| 49 | |||
| 50 | big-endian-regs: | ||
| 51 | $ref: /schemas/types.yaml#/definitions/flag | ||
| 52 | description: | ||
| 53 | Set this flag for HCDs with big endian registers. | ||
| 54 | |||
| 55 | remote-wakeup-connected: | ||
| 56 | $ref: /schemas/types.yaml#/definitions/flag | ||
| 57 | description: | ||
| 58 | Remote wakeup is wired on the platform. | ||
| 59 | |||
| 60 | no-big-frame-no: | ||
| 61 | $ref: /schemas/types.yaml#/definitions/flag | ||
| 62 | description: | ||
| 63 | Set if frame_no lives in bits [15:0] of HCCA | ||
| 64 | |||
| 65 | num-ports: | ||
| 66 | $ref: /schemas/types.yaml#/definitions/uint32 | ||
| 67 | description: | ||
| 68 | Overrides the detected port count | ||
| 69 | |||
| 70 | phys: true | ||
| 71 | |||
| 72 | required: | ||
| 73 | - compatible | ||
| 74 | - reg | ||
| 75 | - interrupts | ||
| 76 | |||
| 77 | additionalProperties: false | ||
| 78 | |||
| 79 | examples: | ||
| 80 | - | | ||
| 81 | ohci0: usb@1c14400 { | ||
| 82 | compatible = "allwinner,sun4i-a10-ohci", "generic-ohci"; | ||
| 83 | reg = <0x01c14400 0x100>; | ||
| 84 | interrupts = <64>; | ||
| 85 | clocks = <&usb_clk 6>, <&ahb_gates 2>; | ||
| 86 | phys = <&usbphy 1>; | ||
| 87 | }; | ||
| 88 | |||
| 89 | ... | ||
diff --git a/Documentation/devicetree/bindings/usb/ingenic,jz4740-musb.txt b/Documentation/devicetree/bindings/usb/ingenic,jz4740-musb.txt index 620355cee63f..16808721f3ff 100644 --- a/Documentation/devicetree/bindings/usb/ingenic,jz4740-musb.txt +++ b/Documentation/devicetree/bindings/usb/ingenic,jz4740-musb.txt | |||
| @@ -8,9 +8,15 @@ Required properties: | |||
| 8 | - interrupt-names: must be "mc" | 8 | - interrupt-names: must be "mc" |
| 9 | - clocks: phandle to the "udc" clock | 9 | - clocks: phandle to the "udc" clock |
| 10 | - clock-names: must be "udc" | 10 | - clock-names: must be "udc" |
| 11 | - phys: phandle to the USB PHY | ||
| 11 | 12 | ||
| 12 | Example: | 13 | Example: |
| 13 | 14 | ||
| 15 | usb_phy: usb-phy@0 { | ||
| 16 | compatible = "usb-nop-xceiv"; | ||
| 17 | #phy-cells = <0>; | ||
| 18 | }; | ||
| 19 | |||
| 14 | udc: usb@13040000 { | 20 | udc: usb@13040000 { |
| 15 | compatible = "ingenic,jz4740-musb"; | 21 | compatible = "ingenic,jz4740-musb"; |
| 16 | reg = <0x13040000 0x10000>; | 22 | reg = <0x13040000 0x10000>; |
| @@ -21,4 +27,6 @@ udc: usb@13040000 { | |||
| 21 | 27 | ||
| 22 | clocks = <&cgu JZ4740_CLK_UDC>; | 28 | clocks = <&cgu JZ4740_CLK_UDC>; |
| 23 | clock-names = "udc"; | 29 | clock-names = "udc"; |
| 30 | |||
| 31 | phys = <&usb_phy>; | ||
| 24 | }; | 32 | }; |
diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra124-xusb.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra124-xusb.txt index 4156c3e181c5..5bfcc0b4d6b9 100644 --- a/Documentation/devicetree/bindings/usb/nvidia,tegra124-xusb.txt +++ b/Documentation/devicetree/bindings/usb/nvidia,tegra124-xusb.txt | |||
| @@ -10,6 +10,7 @@ Required properties: | |||
| 10 | - Tegra124: "nvidia,tegra124-xusb" | 10 | - Tegra124: "nvidia,tegra124-xusb" |
| 11 | - Tegra132: "nvidia,tegra132-xusb", "nvidia,tegra124-xusb" | 11 | - Tegra132: "nvidia,tegra132-xusb", "nvidia,tegra124-xusb" |
| 12 | - Tegra210: "nvidia,tegra210-xusb" | 12 | - Tegra210: "nvidia,tegra210-xusb" |
| 13 | - Tegra186: "nvidia,tegra186-xusb" | ||
| 13 | - reg: Must contain the base and length of the xHCI host registers, XUSB FPCI | 14 | - reg: Must contain the base and length of the xHCI host registers, XUSB FPCI |
| 14 | registers and XUSB IPFS registers. | 15 | registers and XUSB IPFS registers. |
| 15 | - reg-names: Must contain the following entries: | 16 | - reg-names: Must contain the following entries: |
| @@ -59,6 +60,8 @@ For Tegra210: | |||
| 59 | - avdd-pll-uerefe-supply: PLLE reference PLL power supply. Must supply 1.05 V. | 60 | - avdd-pll-uerefe-supply: PLLE reference PLL power supply. Must supply 1.05 V. |
| 60 | - dvdd-pex-pll-supply: PCIe/USB3 PLL power supply. Must supply 1.05 V. | 61 | - dvdd-pex-pll-supply: PCIe/USB3 PLL power supply. Must supply 1.05 V. |
| 61 | - hvdd-pex-pll-e-supply: High-voltage PLLE power supply. Must supply 1.8 V. | 62 | - hvdd-pex-pll-e-supply: High-voltage PLLE power supply. Must supply 1.8 V. |
| 63 | |||
| 64 | For Tegra210 and Tegra186: | ||
| 62 | - power-domains: A list of PM domain specifiers that reference each power-domain | 65 | - power-domains: A list of PM domain specifiers that reference each power-domain |
| 63 | used by the xHCI controller. This list must comprise of a specifier for the | 66 | used by the xHCI controller. This list must comprise of a specifier for the |
| 64 | XUSBA and XUSBC power-domains. See ../power/power_domain.txt and | 67 | XUSBA and XUSBC power-domains. See ../power/power_domain.txt and |
| @@ -78,6 +81,7 @@ Optional properties: | |||
| 78 | - Tegra132: usb2-0, usb2-1, usb2-2, hsic-0, hsic-1, usb3-0, usb3-1 | 81 | - Tegra132: usb2-0, usb2-1, usb2-2, hsic-0, hsic-1, usb3-0, usb3-1 |
| 79 | - Tegra210: usb2-0, usb2-1, usb2-2, usb2-3, hsic-0, usb3-0, usb3-1, usb3-2, | 82 | - Tegra210: usb2-0, usb2-1, usb2-2, usb2-3, hsic-0, usb3-0, usb3-1, usb3-2, |
| 80 | usb3-3 | 83 | usb3-3 |
| 84 | - Tegra186: usb2-0, usb2-1, usb2-2, hsic-0, usb3-0, usb3-1, usb3-2 | ||
| 81 | 85 | ||
| 82 | Example: | 86 | Example: |
| 83 | -------- | 87 | -------- |
diff --git a/Documentation/devicetree/bindings/usb/renesas_usbhs.txt b/Documentation/devicetree/bindings/usb/renesas_usbhs.txt index d93b6a1504f2..b8acc2a994a8 100644 --- a/Documentation/devicetree/bindings/usb/renesas_usbhs.txt +++ b/Documentation/devicetree/bindings/usb/renesas_usbhs.txt | |||
| @@ -6,6 +6,7 @@ Required properties: | |||
| 6 | - "renesas,usbhs-r8a7743" for r8a7743 (RZ/G1M) compatible device | 6 | - "renesas,usbhs-r8a7743" for r8a7743 (RZ/G1M) compatible device |
| 7 | - "renesas,usbhs-r8a7744" for r8a7744 (RZ/G1N) compatible device | 7 | - "renesas,usbhs-r8a7744" for r8a7744 (RZ/G1N) compatible device |
| 8 | - "renesas,usbhs-r8a7745" for r8a7745 (RZ/G1E) compatible device | 8 | - "renesas,usbhs-r8a7745" for r8a7745 (RZ/G1E) compatible device |
| 9 | - "renesas,usbhs-r8a77470" for r8a77470 (RZ/G1C) compatible device | ||
| 9 | - "renesas,usbhs-r8a774a1" for r8a774a1 (RZ/G2M) compatible device | 10 | - "renesas,usbhs-r8a774a1" for r8a774a1 (RZ/G2M) compatible device |
| 10 | - "renesas,usbhs-r8a774c0" for r8a774c0 (RZ/G2E) compatible device | 11 | - "renesas,usbhs-r8a774c0" for r8a774c0 (RZ/G2E) compatible device |
| 11 | - "renesas,usbhs-r8a7790" for r8a7790 (R-Car H2) compatible device | 12 | - "renesas,usbhs-r8a7790" for r8a7790 (R-Car H2) compatible device |
diff --git a/Documentation/devicetree/bindings/usb/usb-ehci.txt b/Documentation/devicetree/bindings/usb/usb-ehci.txt deleted file mode 100644 index 406252d14c6b..000000000000 --- a/Documentation/devicetree/bindings/usb/usb-ehci.txt +++ /dev/null | |||
| @@ -1,46 +0,0 @@ | |||
| 1 | USB EHCI controllers | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | - compatible : should be "generic-ehci". | ||
| 5 | - reg : should contain at least address and length of the standard EHCI | ||
| 6 | register set for the device. Optional platform-dependent registers | ||
| 7 | (debug-port or other) can be also specified here, but only after | ||
| 8 | definition of standard EHCI registers. | ||
| 9 | - interrupts : one EHCI interrupt should be described here. | ||
| 10 | |||
| 11 | Optional properties: | ||
| 12 | - big-endian-regs : boolean, set this for hcds with big-endian registers | ||
| 13 | - big-endian-desc : boolean, set this for hcds with big-endian descriptors | ||
| 14 | - big-endian : boolean, for hcds with big-endian-regs + big-endian-desc | ||
| 15 | - needs-reset-on-resume : boolean, set this to force EHCI reset after resume | ||
| 16 | - has-transaction-translator : boolean, set this if EHCI have a Transaction | ||
| 17 | Translator built into the root hub. | ||
| 18 | - clocks : a list of phandle + clock specifier pairs. In case of Renesas | ||
| 19 | R-Car Gen3 SoCs: | ||
| 20 | - if a host only channel: first clock should be host. | ||
| 21 | - if a USB DRD channel: first clock should be host and second one | ||
| 22 | should be peripheral. | ||
| 23 | - phys : see usb-hcd.txt in the current directory | ||
| 24 | - resets : phandle + reset specifier pair | ||
| 25 | |||
| 26 | additionally the properties from usb-hcd.txt (in the current directory) are | ||
| 27 | supported. | ||
| 28 | |||
| 29 | Example (Sequoia 440EPx): | ||
| 30 | ehci@e0000300 { | ||
| 31 | compatible = "ibm,usb-ehci-440epx", "usb-ehci"; | ||
| 32 | interrupt-parent = <&UIC0>; | ||
| 33 | interrupts = <1a 4>; | ||
| 34 | reg = <0 e0000300 90 0 e0000390 70>; | ||
| 35 | big-endian; | ||
| 36 | }; | ||
| 37 | |||
| 38 | Example (Allwinner sun4i A10 SoC): | ||
| 39 | ehci0: usb@1c14000 { | ||
| 40 | compatible = "allwinner,sun4i-a10-ehci", "generic-ehci"; | ||
| 41 | reg = <0x01c14000 0x100>; | ||
| 42 | interrupts = <39>; | ||
| 43 | clocks = <&ahb_gates 1>; | ||
| 44 | phys = <&usbphy 1>; | ||
| 45 | phy-names = "usb"; | ||
| 46 | }; | ||
diff --git a/Documentation/devicetree/bindings/usb/usb-hcd.txt b/Documentation/devicetree/bindings/usb/usb-hcd.txt deleted file mode 100644 index 50529b838c9c..000000000000 --- a/Documentation/devicetree/bindings/usb/usb-hcd.txt +++ /dev/null | |||
| @@ -1,9 +0,0 @@ | |||
| 1 | Generic USB HCD (Host Controller Device) Properties | ||
| 2 | |||
| 3 | Optional properties: | ||
| 4 | - phys: a list of all USB PHYs on this HCD | ||
| 5 | |||
| 6 | Example: | ||
| 7 | &usb1 { | ||
| 8 | phys = <&usb2_phy1>, <&usb3_phy1>; | ||
| 9 | }; | ||
diff --git a/Documentation/devicetree/bindings/usb/usb-hcd.yaml b/Documentation/devicetree/bindings/usb/usb-hcd.yaml new file mode 100644 index 000000000000..9c8c56d3a792 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/usb-hcd.yaml | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | ||
| 2 | %YAML 1.2 | ||
| 3 | --- | ||
| 4 | $id: http://devicetree.org/schemas/usb/usb-hcd.yaml# | ||
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | ||
| 6 | |||
| 7 | title: Generic USB Host Controller Device Tree Bindings | ||
| 8 | |||
| 9 | maintainers: | ||
| 10 | - Greg Kroah-Hartman <gregkh@linuxfoundation.org> | ||
| 11 | |||
| 12 | properties: | ||
| 13 | $nodename: | ||
| 14 | pattern: "^usb(@.*)?" | ||
| 15 | |||
| 16 | phys: | ||
| 17 | $ref: /schemas/types.yaml#/definitions/phandle-array | ||
| 18 | description: | ||
| 19 | List of all the USB PHYs on this HCD | ||
| 20 | |||
| 21 | examples: | ||
| 22 | - | | ||
| 23 | usb { | ||
| 24 | phys = <&usb2_phy1>, <&usb3_phy1>; | ||
| 25 | }; | ||
diff --git a/Documentation/devicetree/bindings/usb/usb-ohci.txt b/Documentation/devicetree/bindings/usb/usb-ohci.txt deleted file mode 100644 index aaaa5255c972..000000000000 --- a/Documentation/devicetree/bindings/usb/usb-ohci.txt +++ /dev/null | |||
| @@ -1,35 +0,0 @@ | |||
| 1 | USB OHCI controllers | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | - compatible : "generic-ohci" | ||
| 5 | - reg : ohci controller register range (address and length) | ||
| 6 | - interrupts : ohci controller interrupt | ||
| 7 | |||
| 8 | Optional properties: | ||
| 9 | - big-endian-regs : boolean, set this for hcds with big-endian registers | ||
| 10 | - big-endian-desc : boolean, set this for hcds with big-endian descriptors | ||
| 11 | - big-endian : boolean, for hcds with big-endian-regs + big-endian-desc | ||
| 12 | - no-big-frame-no : boolean, set if frame_no lives in bits [15:0] of HCCA | ||
| 13 | - remote-wakeup-connected: remote wakeup is wired on the platform | ||
| 14 | - num-ports : u32, to override the detected port count | ||
| 15 | - clocks : a list of phandle + clock specifier pairs. In case of Renesas | ||
| 16 | R-Car Gen3 SoCs: | ||
| 17 | - if a host only channel: first clock should be host. | ||
| 18 | - if a USB DRD channel: first clock should be host and second one | ||
| 19 | should be peripheral. | ||
| 20 | - phys : see usb-hcd.txt in the current directory | ||
| 21 | - resets : a list of phandle + reset specifier pairs | ||
| 22 | |||
| 23 | additionally the properties from usb-hcd.txt (in the current directory) are | ||
| 24 | supported. | ||
| 25 | |||
| 26 | Example: | ||
| 27 | |||
| 28 | ohci0: usb@1c14400 { | ||
| 29 | compatible = "allwinner,sun4i-a10-ohci", "generic-ohci"; | ||
| 30 | reg = <0x01c14400 0x100>; | ||
| 31 | interrupts = <64>; | ||
| 32 | clocks = <&usb_clk 6>, <&ahb_gates 2>; | ||
| 33 | phys = <&usbphy 1>; | ||
| 34 | phy-names = "usb"; | ||
| 35 | }; | ||
diff --git a/Documentation/devicetree/bindings/usb/usb-xhci.txt b/Documentation/devicetree/bindings/usb/usb-xhci.txt index fea8b1545751..97400e8f8605 100644 --- a/Documentation/devicetree/bindings/usb/usb-xhci.txt +++ b/Documentation/devicetree/bindings/usb/usb-xhci.txt | |||
| @@ -10,6 +10,7 @@ Required properties: | |||
| 10 | - "renesas,xhci-r8a7743" for r8a7743 SoC | 10 | - "renesas,xhci-r8a7743" for r8a7743 SoC |
| 11 | - "renesas,xhci-r8a7744" for r8a7744 SoC | 11 | - "renesas,xhci-r8a7744" for r8a7744 SoC |
| 12 | - "renesas,xhci-r8a774a1" for r8a774a1 SoC | 12 | - "renesas,xhci-r8a774a1" for r8a774a1 SoC |
| 13 | - "renesas,xhci-r8a774c0" for r8a774c0 SoC | ||
| 13 | - "renesas,xhci-r8a7790" for r8a7790 SoC | 14 | - "renesas,xhci-r8a7790" for r8a7790 SoC |
| 14 | - "renesas,xhci-r8a7791" for r8a7791 SoC | 15 | - "renesas,xhci-r8a7791" for r8a7791 SoC |
| 15 | - "renesas,xhci-r8a7793" for r8a7793 SoC | 16 | - "renesas,xhci-r8a7793" for r8a7793 SoC |
diff --git a/Documentation/devicetree/bindings/usb/usb251xb.txt b/Documentation/devicetree/bindings/usb/usb251xb.txt index 17915f64b8ee..bc7945e9dbfe 100644 --- a/Documentation/devicetree/bindings/usb/usb251xb.txt +++ b/Documentation/devicetree/bindings/usb/usb251xb.txt | |||
| @@ -64,8 +64,10 @@ Optional properties : | |||
| 64 | - power-on-time-ms : Specifies the time it takes from the time the host | 64 | - power-on-time-ms : Specifies the time it takes from the time the host |
| 65 | initiates the power-on sequence to a port until the port has adequate | 65 | initiates the power-on sequence to a port until the port has adequate |
| 66 | power. The value is given in ms in a 0 - 510 range (default is 100ms). | 66 | power. The value is given in ms in a 0 - 510 range (default is 100ms). |
| 67 | - swap-dx-lanes : Specifies the ports which will swap the differential-pair | 67 | - swap-dx-lanes : Specifies the downstream ports which will swap the |
| 68 | (D+/D-), default is not-swapped. | 68 | differential-pair (D+/D-), default is not-swapped. |
| 69 | - swap-us-lanes : Selects the upstream port differential-pair (D+/D-) | ||
| 70 | swapping (boolean, default is not-swapped) | ||
| 69 | 71 | ||
| 70 | Examples: | 72 | Examples: |
| 71 | usb2512b@2c { | 73 | usb2512b@2c { |
diff --git a/Documentation/usb/WUSB-Design-overview.txt b/Documentation/usb/WUSB-Design-overview.txt index fdb47637720e..dc5e21609bb5 100644 --- a/Documentation/usb/WUSB-Design-overview.txt +++ b/Documentation/usb/WUSB-Design-overview.txt | |||
| @@ -1,7 +1,9 @@ | |||
| 1 | 1 | ================================ | |
| 2 | Linux UWB + Wireless USB + WiNET | 2 | Linux UWB + Wireless USB + WiNET |
| 3 | ================================ | ||
| 4 | |||
| 5 | Copyright (C) 2005-2006 Intel Corporation | ||
| 3 | 6 | ||
| 4 | (C) 2005-2006 Intel Corporation | ||
| 5 | Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> | 7 | Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> |
| 6 | 8 | ||
| 7 | This program is free software; you can redistribute it and/or | 9 | This program is free software; you can redistribute it and/or |
| @@ -29,6 +31,7 @@ drivers for the USB based UWB radio controllers defined in the | |||
| 29 | Wireless USB 1.0 specification (including Wireless USB host controller | 31 | Wireless USB 1.0 specification (including Wireless USB host controller |
| 30 | and an Intel WiNET controller). | 32 | and an Intel WiNET controller). |
| 31 | 33 | ||
| 34 | .. Contents | ||
| 32 | 1. Introduction | 35 | 1. Introduction |
| 33 | 1. HWA: Host Wire adapters, your Wireless USB dongle | 36 | 1. HWA: Host Wire adapters, your Wireless USB dongle |
| 34 | 37 | ||
| @@ -51,7 +54,8 @@ and an Intel WiNET controller). | |||
| 51 | 4. Glossary | 54 | 4. Glossary |
| 52 | 55 | ||
| 53 | 56 | ||
| 54 | Introduction | 57 | Introduction |
| 58 | ============ | ||
| 55 | 59 | ||
| 56 | UWB is a wide-band communication protocol that is to serve also as the | 60 | UWB is a wide-band communication protocol that is to serve also as the |
| 57 | low-level protocol for others (much like TCP sits on IP). Currently | 61 | low-level protocol for others (much like TCP sits on IP). Currently |
| @@ -93,7 +97,8 @@ The different logical parts of this driver are: | |||
| 93 | do the actual WUSB. | 97 | do the actual WUSB. |
| 94 | 98 | ||
| 95 | 99 | ||
| 96 | HWA: Host Wire adapters, your Wireless USB dongle | 100 | HWA: Host Wire adapters, your Wireless USB dongle |
| 101 | ------------------------------------------------- | ||
| 97 | 102 | ||
| 98 | WUSB also defines a device called a Host Wire Adaptor (HWA), which in | 103 | WUSB also defines a device called a Host Wire Adaptor (HWA), which in |
| 99 | mere terms is a USB dongle that enables your PC to have UWB and Wireless | 104 | mere terms is a USB dongle that enables your PC to have UWB and Wireless |
| @@ -125,7 +130,8 @@ The HWA itself is broken in two or three main interfaces: | |||
| 125 | their type and kick into gear. | 130 | their type and kick into gear. |
| 126 | 131 | ||
| 127 | 132 | ||
| 128 | DWA: Device Wired Adaptor, a Wireless USB hub for wired devices | 133 | DWA: Device Wired Adaptor, a Wireless USB hub for wired devices |
| 134 | --------------------------------------------------------------- | ||
| 129 | 135 | ||
| 130 | These are the complement to HWAs. They are a USB host for connecting | 136 | These are the complement to HWAs. They are a USB host for connecting |
| 131 | wired devices, but it is connected to your PC connected via Wireless | 137 | wired devices, but it is connected to your PC connected via Wireless |
| @@ -137,7 +143,8 @@ code with the HWA-RC driver; there is a bunch of factorization work that | |||
| 137 | has been done to support that in upcoming releases. | 143 | has been done to support that in upcoming releases. |
| 138 | 144 | ||
| 139 | 145 | ||
| 140 | WHCI: Wireless Host Controller Interface, the PCI WUSB host adapter | 146 | WHCI: Wireless Host Controller Interface, the PCI WUSB host adapter |
| 147 | ------------------------------------------------------------------- | ||
| 141 | 148 | ||
| 142 | This is your usual PCI device that implements WHCI. Similar in concept | 149 | This is your usual PCI device that implements WHCI. Similar in concept |
| 143 | to EHCI, it allows your wireless USB devices (including DWAs) to connect | 150 | to EHCI, it allows your wireless USB devices (including DWAs) to connect |
| @@ -148,7 +155,8 @@ There is still no driver support for this, but will be in upcoming | |||
| 148 | releases. | 155 | releases. |
| 149 | 156 | ||
| 150 | 157 | ||
| 151 | The UWB stack | 158 | The UWB stack |
| 159 | ============= | ||
| 152 | 160 | ||
| 153 | The main mission of the UWB stack is to keep a tally of which devices | 161 | The main mission of the UWB stack is to keep a tally of which devices |
| 154 | are in radio proximity to allow drivers to connect to them. As well, it | 162 | are in radio proximity to allow drivers to connect to them. As well, it |
| @@ -156,7 +164,8 @@ provides an API for controlling the local radio controllers (RCs from | |||
| 156 | now on), such as to start/stop beaconing, scan, allocate bandwidth, etc. | 164 | now on), such as to start/stop beaconing, scan, allocate bandwidth, etc. |
| 157 | 165 | ||
| 158 | 166 | ||
| 159 | Devices and hosts: the basic structure | 167 | Devices and hosts: the basic structure |
| 168 | -------------------------------------- | ||
| 160 | 169 | ||
| 161 | The main building block here is the UWB device (struct uwb_dev). For | 170 | The main building block here is the UWB device (struct uwb_dev). For |
| 162 | each device that pops up in radio presence (ie: the UWB host receives a | 171 | each device that pops up in radio presence (ie: the UWB host receives a |
| @@ -187,7 +196,8 @@ the USB connected HWA. Eventually, drivers/whci-rc.c will do the same | |||
| 187 | for the PCI connected WHCI controller. | 196 | for the PCI connected WHCI controller. |
| 188 | 197 | ||
| 189 | 198 | ||
| 190 | Host Controller life cycle | 199 | Host Controller life cycle |
| 200 | -------------------------- | ||
| 191 | 201 | ||
| 192 | So let's say we connect a dongle to the system: it is detected and | 202 | So let's say we connect a dongle to the system: it is detected and |
| 193 | firmware uploaded if needed [for Intel's i1480 | 203 | firmware uploaded if needed [for Intel's i1480 |
| @@ -209,7 +219,8 @@ When a dongle is disconnected, /drivers/uwb/hwa-rc.c:hwarc_disconnect()/ | |||
| 209 | takes time of tearing everything down safely (or not...). | 219 | takes time of tearing everything down safely (or not...). |
| 210 | 220 | ||
| 211 | 221 | ||
| 212 | On the air: beacons and enumerating the radio neighborhood | 222 | On the air: beacons and enumerating the radio neighborhood |
| 223 | ---------------------------------------------------------- | ||
| 213 | 224 | ||
| 214 | So assuming we have devices and we have agreed for a channel to connect | 225 | So assuming we have devices and we have agreed for a channel to connect |
| 215 | on (let's say 9), we put the new RC to beacon: | 226 | on (let's say 9), we put the new RC to beacon: |
| @@ -235,12 +246,14 @@ are received in some time, the device is considered gone and wiped out | |||
| 235 | the beacon cache of dead devices]. | 246 | the beacon cache of dead devices]. |
| 236 | 247 | ||
| 237 | 248 | ||
| 238 | Device lists | 249 | Device lists |
| 250 | ------------ | ||
| 239 | 251 | ||
| 240 | All UWB devices are kept in the list of the struct bus_type uwb_bus_type. | 252 | All UWB devices are kept in the list of the struct bus_type uwb_bus_type. |
| 241 | 253 | ||
| 242 | 254 | ||
| 243 | Bandwidth allocation | 255 | Bandwidth allocation |
| 256 | -------------------- | ||
| 244 | 257 | ||
| 245 | The UWB stack maintains a local copy of DRP availability through | 258 | The UWB stack maintains a local copy of DRP availability through |
| 246 | processing of incoming *DRP Availability Change* notifications. This | 259 | processing of incoming *DRP Availability Change* notifications. This |
| @@ -260,7 +273,8 @@ completion. [Note: The bandwidth reservation work is in progress and | |||
| 260 | subject to change.] | 273 | subject to change.] |
| 261 | 274 | ||
| 262 | 275 | ||
| 263 | Wireless USB Host Controller drivers | 276 | Wireless USB Host Controller drivers |
| 277 | ==================================== | ||
| 264 | 278 | ||
| 265 | *WARNING* This section needs a lot of work! | 279 | *WARNING* This section needs a lot of work! |
| 266 | 280 | ||
| @@ -296,7 +310,8 @@ starts sending MMCs. | |||
| 296 | 310 | ||
| 297 | Now it all depends on external stimuli. | 311 | Now it all depends on external stimuli. |
| 298 | 312 | ||
| 299 | *New device connection* | 313 | New device connection |
| 314 | --------------------- | ||
| 300 | 315 | ||
| 301 | A new device pops up, it scans the radio looking for MMCs that give out | 316 | A new device pops up, it scans the radio looking for MMCs that give out |
| 302 | the existence of Wireless USB channels. Once one (or more) are found, | 317 | the existence of Wireless USB channels. Once one (or more) are found, |
| @@ -322,7 +337,8 @@ has seen the port status changes, as we have been toggling them. It will | |||
| 322 | start enumerating and doing transfers through usb_hcd->urb_enqueue() to | 337 | start enumerating and doing transfers through usb_hcd->urb_enqueue() to |
| 323 | read descriptors and move our data. | 338 | read descriptors and move our data. |
| 324 | 339 | ||
| 325 | *Device life cycle and keep alives* | 340 | Device life cycle and keep alives |
| 341 | --------------------------------- | ||
| 326 | 342 | ||
| 327 | Every time there is a successful transfer to/from a device, we update a | 343 | Every time there is a successful transfer to/from a device, we update a |
| 328 | per-device activity timestamp. If not, every now and then we check and | 344 | per-device activity timestamp. If not, every now and then we check and |
| @@ -340,7 +356,8 @@ device list looking for whom needs refreshing. | |||
| 340 | If the device wants to disconnect, it will either die (ugly) or send a | 356 | If the device wants to disconnect, it will either die (ugly) or send a |
| 341 | /DN_Disconnect/ that will prompt a disconnection from the system. | 357 | /DN_Disconnect/ that will prompt a disconnection from the system. |
| 342 | 358 | ||
| 343 | *Sending and receiving data* | 359 | Sending and receiving data |
| 360 | -------------------------- | ||
| 344 | 361 | ||
| 345 | Data is sent and received through /Remote Pipes/ (rpipes). An rpipe is | 362 | Data is sent and received through /Remote Pipes/ (rpipes). An rpipe is |
| 346 | /aimed/ at an endpoint in a WUSB device. This is the same for HWAs and | 363 | /aimed/ at an endpoint in a WUSB device. This is the same for HWAs and |
| @@ -394,7 +411,8 @@ finalize the transfer. | |||
| 394 | For IN xfers, we only issue URBs for the segments we want to read and | 411 | For IN xfers, we only issue URBs for the segments we want to read and |
| 395 | then wait for the xfer result data. | 412 | then wait for the xfer result data. |
| 396 | 413 | ||
| 397 | *URB mapping into xfers* | 414 | URB mapping into xfers |
| 415 | ^^^^^^^^^^^^^^^^^^^^^^ | ||
| 398 | 416 | ||
| 399 | This is done by hwahc_op_urb_[en|de]queue(). In enqueue() we aim an | 417 | This is done by hwahc_op_urb_[en|de]queue(). In enqueue() we aim an |
| 400 | rpipe to the endpoint where we have to transmit, create a transfer | 418 | rpipe to the endpoint where we have to transmit, create a transfer |
| @@ -407,7 +425,8 @@ and not yet done and when all that is done, the xfer callback will be | |||
| 407 | called--this will call the URB callback. | 425 | called--this will call the URB callback. |
| 408 | 426 | ||
| 409 | 427 | ||
| 410 | Glossary | 428 | Glossary |
| 429 | ======== | ||
| 411 | 430 | ||
| 412 | *DWA* -- Device Wire Adapter | 431 | *DWA* -- Device Wire Adapter |
| 413 | 432 | ||
| @@ -436,4 +455,3 @@ the host. | |||
| 436 | 455 | ||
| 437 | Design-overview.txt-1.8 (last edited 2006-11-04 12:22:24 by | 456 | Design-overview.txt-1.8 (last edited 2006-11-04 12:22:24 by |
| 438 | InakyPerezGonzalez) | 457 | InakyPerezGonzalez) |
| 439 | |||
diff --git a/Documentation/usb/acm.txt b/Documentation/usb/acm.txt index 903abca10517..e8bda98e9b51 100644 --- a/Documentation/usb/acm.txt +++ b/Documentation/usb/acm.txt | |||
| @@ -1,127 +1,131 @@ | |||
| 1 | Linux ACM driver v0.16 | 1 | ====================== |
| 2 | (c) 1999 Vojtech Pavlik <vojtech@suse.cz> | 2 | Linux ACM driver v0.16 |
| 3 | Sponsored by SuSE | 3 | ====================== |
| 4 | ---------------------------------------------------------------------------- | 4 | |
| 5 | Copyright (c) 1999 Vojtech Pavlik <vojtech@suse.cz> | ||
| 6 | |||
| 7 | Sponsored by SuSE | ||
| 5 | 8 | ||
| 6 | 0. Disclaimer | 9 | 0. Disclaimer |
| 7 | ~~~~~~~~~~~~~ | 10 | ~~~~~~~~~~~~~ |
| 8 | This program is free software; you can redistribute it and/or modify it | 11 | This program is free software; you can redistribute it and/or modify it |
| 9 | under the terms of the GNU General Public License as published by the Free | 12 | under the terms of the GNU General Public License as published by the Free |
| 10 | Software Foundation; either version 2 of the License, or (at your option) | 13 | Software Foundation; either version 2 of the License, or (at your option) |
| 11 | any later version. | 14 | any later version. |
| 12 | 15 | ||
| 13 | This program is distributed in the hope that it will be useful, but | 16 | This program is distributed in the hope that it will be useful, but |
| 14 | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | 17 | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
| 15 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | 18 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| 16 | more details. | 19 | more details. |
| 17 | 20 | ||
| 18 | You should have received a copy of the GNU General Public License along | 21 | You should have received a copy of the GNU General Public License along |
| 19 | with this program; if not, write to the Free Software Foundation, Inc., 59 | 22 | with this program; if not, write to the Free Software Foundation, Inc., 59 |
| 20 | Temple Place, Suite 330, Boston, MA 02111-1307 USA | 23 | Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 21 | 24 | ||
| 22 | Should you need to contact me, the author, you can do so either by e-mail | 25 | Should you need to contact me, the author, you can do so either by e-mail - |
| 23 | - mail your message to <vojtech@suse.cz>, or by paper mail: Vojtech Pavlik, | 26 | mail your message to <vojtech@suse.cz>, or by paper mail: Vojtech Pavlik, |
| 24 | Ucitelska 1576, Prague 8, 182 00 Czech Republic | 27 | Ucitelska 1576, Prague 8, 182 00 Czech Republic |
| 25 | 28 | ||
| 26 | For your convenience, the GNU General Public License version 2 is included | 29 | For your convenience, the GNU General Public License version 2 is included |
| 27 | in the package: See the file COPYING. | 30 | in the package: See the file COPYING. |
| 28 | 31 | ||
| 29 | 1. Usage | 32 | 1. Usage |
| 30 | ~~~~~~~~ | 33 | ~~~~~~~~ |
| 31 | The drivers/usb/class/cdc-acm.c drivers works with USB modems and USB ISDN terminal | 34 | The drivers/usb/class/cdc-acm.c drivers works with USB modems and USB ISDN terminal |
| 32 | adapters that conform to the Universal Serial Bus Communication Device Class | 35 | adapters that conform to the Universal Serial Bus Communication Device Class |
| 33 | Abstract Control Model (USB CDC ACM) specification. | 36 | Abstract Control Model (USB CDC ACM) specification. |
| 34 | 37 | ||
| 35 | Many modems do, here is a list of those I know of: | 38 | Many modems do, here is a list of those I know of: |
| 36 | 39 | ||
| 37 | 3Com OfficeConnect 56k | 40 | - 3Com OfficeConnect 56k |
| 38 | 3Com Voice FaxModem Pro | 41 | - 3Com Voice FaxModem Pro |
| 39 | 3Com Sportster | 42 | - 3Com Sportster |
| 40 | MultiTech MultiModem 56k | 43 | - MultiTech MultiModem 56k |
| 41 | Zoom 2986L FaxModem | 44 | - Zoom 2986L FaxModem |
| 42 | Compaq 56k FaxModem | 45 | - Compaq 56k FaxModem |
| 43 | ELSA Microlink 56k | 46 | - ELSA Microlink 56k |
| 44 | 47 | ||
| 45 | I know of one ISDN TA that does work with the acm driver: | 48 | I know of one ISDN TA that does work with the acm driver: |
| 46 | 49 | ||
| 47 | 3Com USR ISDN Pro TA | 50 | - 3Com USR ISDN Pro TA |
| 48 | 51 | ||
| 49 | Some cell phones also connect via USB. I know the following phones work: | 52 | Some cell phones also connect via USB. I know the following phones work: |
| 50 | 53 | ||
| 51 | SonyEricsson K800i | 54 | - SonyEricsson K800i |
| 52 | 55 | ||
| 53 | Unfortunately many modems and most ISDN TAs use proprietary interfaces and | 56 | Unfortunately many modems and most ISDN TAs use proprietary interfaces and |
| 54 | thus won't work with this drivers. Check for ACM compliance before buying. | 57 | thus won't work with this drivers. Check for ACM compliance before buying. |
| 55 | 58 | ||
| 56 | To use the modems you need these modules loaded: | 59 | To use the modems you need these modules loaded:: |
| 57 | 60 | ||
| 58 | usbcore.ko | 61 | usbcore.ko |
| 59 | uhci-hcd.ko ohci-hcd.ko or ehci-hcd.ko | 62 | uhci-hcd.ko ohci-hcd.ko or ehci-hcd.ko |
| 60 | cdc-acm.ko | 63 | cdc-acm.ko |
| 61 | 64 | ||
| 62 | After that, the modem[s] should be accessible. You should be able to use | 65 | After that, the modem[s] should be accessible. You should be able to use |
| 63 | minicom, ppp and mgetty with them. | 66 | minicom, ppp and mgetty with them. |
| 64 | 67 | ||
| 65 | 2. Verifying that it works | 68 | 2. Verifying that it works |
| 66 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ | 69 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 67 | The first step would be to check /sys/kernel/debug/usb/devices, it should look | 70 | |
| 68 | like this: | 71 | The first step would be to check /sys/kernel/debug/usb/devices, it should look |
| 69 | 72 | like this:: | |
| 70 | T: Bus=01 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= 1 Spd=12 MxCh= 2 | 73 | |
| 71 | B: Alloc= 0/900 us ( 0%), #Int= 0, #Iso= 0 | 74 | T: Bus=01 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= 1 Spd=12 MxCh= 2 |
| 72 | D: Ver= 1.00 Cls=09(hub ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 | 75 | B: Alloc= 0/900 us ( 0%), #Int= 0, #Iso= 0 |
| 73 | P: Vendor=0000 ProdID=0000 Rev= 0.00 | 76 | D: Ver= 1.00 Cls=09(hub ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 |
| 74 | S: Product=USB UHCI Root Hub | 77 | P: Vendor=0000 ProdID=0000 Rev= 0.00 |
| 75 | S: SerialNumber=6800 | 78 | S: Product=USB UHCI Root Hub |
| 76 | C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr= 0mA | 79 | S: SerialNumber=6800 |
| 77 | I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub | 80 | C:* #Ifs= 1 Cfg#= 1 Atr=40 MxPwr= 0mA |
| 78 | E: Ad=81(I) Atr=03(Int.) MxPS= 8 Ivl=255ms | 81 | I: If#= 0 Alt= 0 #EPs= 1 Cls=09(hub ) Sub=00 Prot=00 Driver=hub |
| 79 | T: Bus=01 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#= 2 Spd=12 MxCh= 0 | 82 | E: Ad=81(I) Atr=03(Int.) MxPS= 8 Ivl=255ms |
| 80 | D: Ver= 1.00 Cls=02(comm.) Sub=00 Prot=00 MxPS= 8 #Cfgs= 2 | 83 | T: Bus=01 Lev=01 Prnt=01 Port=01 Cnt=01 Dev#= 2 Spd=12 MxCh= 0 |
| 81 | P: Vendor=04c1 ProdID=008f Rev= 2.07 | 84 | D: Ver= 1.00 Cls=02(comm.) Sub=00 Prot=00 MxPS= 8 #Cfgs= 2 |
| 82 | S: Manufacturer=3Com Inc. | 85 | P: Vendor=04c1 ProdID=008f Rev= 2.07 |
| 83 | S: Product=3Com U.S. Robotics Pro ISDN TA | 86 | S: Manufacturer=3Com Inc. |
| 84 | S: SerialNumber=UFT53A49BVT7 | 87 | S: Product=3Com U.S. Robotics Pro ISDN TA |
| 85 | C: #Ifs= 1 Cfg#= 1 Atr=60 MxPwr= 0mA | 88 | S: SerialNumber=UFT53A49BVT7 |
| 86 | I: If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=acm | 89 | C: #Ifs= 1 Cfg#= 1 Atr=60 MxPwr= 0mA |
| 87 | E: Ad=85(I) Atr=02(Bulk) MxPS= 64 Ivl= 0ms | 90 | I: If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=acm |
| 88 | E: Ad=04(O) Atr=02(Bulk) MxPS= 64 Ivl= 0ms | 91 | E: Ad=85(I) Atr=02(Bulk) MxPS= 64 Ivl= 0ms |
| 89 | E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=128ms | 92 | E: Ad=04(O) Atr=02(Bulk) MxPS= 64 Ivl= 0ms |
| 90 | C:* #Ifs= 2 Cfg#= 2 Atr=60 MxPwr= 0mA | 93 | E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=128ms |
| 91 | I: If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=02 Prot=01 Driver=acm | 94 | C:* #Ifs= 2 Cfg#= 2 Atr=60 MxPwr= 0mA |
| 92 | E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=128ms | 95 | I: If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=02 Prot=01 Driver=acm |
| 93 | I: If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=acm | 96 | E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=128ms |
| 94 | E: Ad=85(I) Atr=02(Bulk) MxPS= 64 Ivl= 0ms | 97 | I: If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=acm |
| 95 | E: Ad=04(O) Atr=02(Bulk) MxPS= 64 Ivl= 0ms | 98 | E: Ad=85(I) Atr=02(Bulk) MxPS= 64 Ivl= 0ms |
| 99 | E: Ad=04(O) Atr=02(Bulk) MxPS= 64 Ivl= 0ms | ||
| 96 | 100 | ||
| 97 | The presence of these three lines (and the Cls= 'comm' and 'data' classes) | 101 | The presence of these three lines (and the Cls= 'comm' and 'data' classes) |
| 98 | is important, it means it's an ACM device. The Driver=acm means the acm | 102 | is important, it means it's an ACM device. The Driver=acm means the acm |
| 99 | driver is used for the device. If you see only Cls=ff(vend.) then you're out | 103 | driver is used for the device. If you see only Cls=ff(vend.) then you're out |
| 100 | of luck, you have a device with vendor specific-interface. | 104 | of luck, you have a device with vendor specific-interface:: |
| 101 | 105 | ||
| 102 | D: Ver= 1.00 Cls=02(comm.) Sub=00 Prot=00 MxPS= 8 #Cfgs= 2 | 106 | D: Ver= 1.00 Cls=02(comm.) Sub=00 Prot=00 MxPS= 8 #Cfgs= 2 |
| 103 | I: If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=02 Prot=01 Driver=acm | 107 | I: If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=02 Prot=01 Driver=acm |
| 104 | I: If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=acm | 108 | I: If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=acm |
| 105 | 109 | ||
| 106 | In the system log you should see: | 110 | In the system log you should see:: |
| 107 | 111 | ||
| 108 | usb.c: USB new device connect, assigned device number 2 | 112 | usb.c: USB new device connect, assigned device number 2 |
| 109 | usb.c: kmalloc IF c7691fa0, numif 1 | 113 | usb.c: kmalloc IF c7691fa0, numif 1 |
| 110 | usb.c: kmalloc IF c7b5f3e0, numif 2 | 114 | usb.c: kmalloc IF c7b5f3e0, numif 2 |
| 111 | usb.c: skipped 4 class/vendor specific interface descriptors | 115 | usb.c: skipped 4 class/vendor specific interface descriptors |
| 112 | usb.c: new device strings: Mfr=1, Product=2, SerialNumber=3 | 116 | usb.c: new device strings: Mfr=1, Product=2, SerialNumber=3 |
| 113 | usb.c: USB device number 2 default language ID 0x409 | 117 | usb.c: USB device number 2 default language ID 0x409 |
| 114 | Manufacturer: 3Com Inc. | 118 | Manufacturer: 3Com Inc. |
| 115 | Product: 3Com U.S. Robotics Pro ISDN TA | 119 | Product: 3Com U.S. Robotics Pro ISDN TA |
| 116 | SerialNumber: UFT53A49BVT7 | 120 | SerialNumber: UFT53A49BVT7 |
| 117 | acm.c: probing config 1 | 121 | acm.c: probing config 1 |
| 118 | acm.c: probing config 2 | 122 | acm.c: probing config 2 |
| 119 | ttyACM0: USB ACM device | 123 | ttyACM0: USB ACM device |
| 120 | acm.c: acm_control_msg: rq: 0x22 val: 0x0 len: 0x0 result: 0 | 124 | acm.c: acm_control_msg: rq: 0x22 val: 0x0 len: 0x0 result: 0 |
| 121 | acm.c: acm_control_msg: rq: 0x20 val: 0x0 len: 0x7 result: 7 | 125 | acm.c: acm_control_msg: rq: 0x20 val: 0x0 len: 0x7 result: 7 |
| 122 | usb.c: acm driver claimed interface c7b5f3e0 | 126 | usb.c: acm driver claimed interface c7b5f3e0 |
| 123 | usb.c: acm driver claimed interface c7b5f3f8 | 127 | usb.c: acm driver claimed interface c7b5f3f8 |
| 124 | usb.c: acm driver claimed interface c7691fa0 | 128 | usb.c: acm driver claimed interface c7691fa0 |
| 125 | 129 | ||
| 126 | If all this seems to be OK, fire up minicom and set it to talk to the ttyACM | 130 | If all this seems to be OK, fire up minicom and set it to talk to the ttyACM |
| 127 | device and try typing 'at'. If it responds with 'OK', then everything is | 131 | device and try typing 'at'. If it responds with 'OK', then everything is |
diff --git a/Documentation/usb/authorization.txt b/Documentation/usb/authorization.txt index 9dd1dc7b1009..9e53909d04c2 100644 --- a/Documentation/usb/authorization.txt +++ b/Documentation/usb/authorization.txt | |||
| @@ -1,7 +1,8 @@ | |||
| 1 | 1 | ============================================================== | |
| 2 | Authorizing (or not) your USB devices to connect to the system | 2 | Authorizing (or not) your USB devices to connect to the system |
| 3 | ============================================================== | ||
| 3 | 4 | ||
| 4 | (C) 2007 Inaky Perez-Gonzalez <inaky@linux.intel.com> Intel Corporation | 5 | Copyright (C) 2007 Inaky Perez-Gonzalez <inaky@linux.intel.com> Intel Corporation |
| 5 | 6 | ||
| 6 | This feature allows you to control if a USB device can be used (or | 7 | This feature allows you to control if a USB device can be used (or |
| 7 | not) in a system. This feature will allow you to implement a lock-down | 8 | not) in a system. This feature will allow you to implement a lock-down |
| @@ -12,24 +13,25 @@ its interfaces are immediately made available to the users. With this | |||
| 12 | modification, only if root authorizes the device to be configured will | 13 | modification, only if root authorizes the device to be configured will |
| 13 | then it be possible to use it. | 14 | then it be possible to use it. |
| 14 | 15 | ||
| 15 | Usage: | 16 | Usage |
| 17 | ===== | ||
| 16 | 18 | ||
| 17 | Authorize a device to connect: | 19 | Authorize a device to connect:: |
| 18 | 20 | ||
| 19 | $ echo 1 > /sys/bus/usb/devices/DEVICE/authorized | 21 | $ echo 1 > /sys/bus/usb/devices/DEVICE/authorized |
| 20 | 22 | ||
| 21 | Deauthorize a device: | 23 | De-authorize a device:: |
| 22 | 24 | ||
| 23 | $ echo 0 > /sys/bus/usb/devices/DEVICE/authorized | 25 | $ echo 0 > /sys/bus/usb/devices/DEVICE/authorized |
| 24 | 26 | ||
| 25 | Set new devices connected to hostX to be deauthorized by default (ie: | 27 | Set new devices connected to hostX to be deauthorized by default (ie: |
| 26 | lock down): | 28 | lock down):: |
| 27 | 29 | ||
| 28 | $ echo 0 > /sys/bus/usb/devices/usbX/authorized_default | 30 | $ echo 0 > /sys/bus/usb/devices/usbX/authorized_default |
| 29 | 31 | ||
| 30 | Remove the lock down: | 32 | Remove the lock down:: |
| 31 | 33 | ||
| 32 | $ echo 1 > /sys/bus/usb/devices/usbX/authorized_default | 34 | $ echo 1 > /sys/bus/usb/devices/usbX/authorized_default |
| 33 | 35 | ||
| 34 | By default, Wired USB devices are authorized by default to | 36 | By default, Wired USB devices are authorized by default to |
| 35 | connect. Wireless USB hosts deauthorize by default all new connected | 37 | connect. Wireless USB hosts deauthorize by default all new connected |
| @@ -40,21 +42,21 @@ USB ports. | |||
| 40 | 42 | ||
| 41 | 43 | ||
| 42 | Example system lockdown (lame) | 44 | Example system lockdown (lame) |
| 43 | ----------------------- | 45 | ------------------------------ |
| 44 | 46 | ||
| 45 | Imagine you want to implement a lockdown so only devices of type XYZ | 47 | Imagine you want to implement a lockdown so only devices of type XYZ |
| 46 | can be connected (for example, it is a kiosk machine with a visible | 48 | can be connected (for example, it is a kiosk machine with a visible |
| 47 | USB port): | 49 | USB port):: |
| 48 | 50 | ||
| 49 | boot up | 51 | boot up |
| 50 | rc.local -> | 52 | rc.local -> |
| 51 | 53 | ||
| 52 | for host in /sys/bus/usb/devices/usb* | 54 | for host in /sys/bus/usb/devices/usb* |
| 53 | do | 55 | do |
| 54 | echo 0 > $host/authorized_default | 56 | echo 0 > $host/authorized_default |
| 55 | done | 57 | done |
| 56 | 58 | ||
| 57 | Hookup an script to udev, for new USB devices | 59 | Hookup an script to udev, for new USB devices:: |
| 58 | 60 | ||
| 59 | if device_is_my_type $DEV | 61 | if device_is_my_type $DEV |
| 60 | then | 62 | then |
| @@ -67,10 +69,10 @@ checking if the class, type and protocol match something is the worse | |||
| 67 | security verification you can make (or the best, for someone willing | 69 | security verification you can make (or the best, for someone willing |
| 68 | to break it). If you need something secure, use crypto and Certificate | 70 | to break it). If you need something secure, use crypto and Certificate |
| 69 | Authentication or stuff like that. Something simple for an storage key | 71 | Authentication or stuff like that. Something simple for an storage key |
| 70 | could be: | 72 | could be:: |
| 71 | 73 | ||
| 72 | function device_is_my_type() | 74 | function device_is_my_type() |
| 73 | { | 75 | { |
| 74 | echo 1 > authorized # temporarily authorize it | 76 | echo 1 > authorized # temporarily authorize it |
| 75 | # FIXME: make sure none can mount it | 77 | # FIXME: make sure none can mount it |
| 76 | mount DEVICENODE /mntpoint | 78 | mount DEVICENODE /mntpoint |
| @@ -83,7 +85,7 @@ function device_is_my_type() | |||
| 83 | else | 85 | else |
| 84 | echo 0 > authorized | 86 | echo 0 > authorized |
| 85 | fi | 87 | fi |
| 86 | } | 88 | } |
| 87 | 89 | ||
| 88 | 90 | ||
| 89 | Of course, this is lame, you'd want to do a real certificate | 91 | Of course, this is lame, you'd want to do a real certificate |
| @@ -95,30 +97,35 @@ welcome. | |||
| 95 | 97 | ||
| 96 | Interface authorization | 98 | Interface authorization |
| 97 | ----------------------- | 99 | ----------------------- |
| 100 | |||
| 98 | There is a similar approach to allow or deny specific USB interfaces. | 101 | There is a similar approach to allow or deny specific USB interfaces. |
| 99 | That allows to block only a subset of an USB device. | 102 | That allows to block only a subset of an USB device. |
| 100 | 103 | ||
| 101 | Authorize an interface: | 104 | Authorize an interface:: |
| 102 | $ echo 1 > /sys/bus/usb/devices/INTERFACE/authorized | ||
| 103 | 105 | ||
| 104 | Deauthorize an interface: | 106 | $ echo 1 > /sys/bus/usb/devices/INTERFACE/authorized |
| 105 | $ echo 0 > /sys/bus/usb/devices/INTERFACE/authorized | 107 | |
| 108 | Deauthorize an interface:: | ||
| 109 | |||
| 110 | $ echo 0 > /sys/bus/usb/devices/INTERFACE/authorized | ||
| 106 | 111 | ||
| 107 | The default value for new interfaces | 112 | The default value for new interfaces |
| 108 | on a particular USB bus can be changed, too. | 113 | on a particular USB bus can be changed, too. |
| 109 | 114 | ||
| 110 | Allow interfaces per default: | 115 | Allow interfaces per default:: |
| 111 | $ echo 1 > /sys/bus/usb/devices/usbX/interface_authorized_default | 116 | |
| 117 | $ echo 1 > /sys/bus/usb/devices/usbX/interface_authorized_default | ||
| 118 | |||
| 119 | Deny interfaces per default:: | ||
| 112 | 120 | ||
| 113 | Deny interfaces per default: | 121 | $ echo 0 > /sys/bus/usb/devices/usbX/interface_authorized_default |
| 114 | $ echo 0 > /sys/bus/usb/devices/usbX/interface_authorized_default | ||
| 115 | 122 | ||
| 116 | Per default the interface_authorized_default bit is 1. | 123 | Per default the interface_authorized_default bit is 1. |
| 117 | So all interfaces would authorized per default. | 124 | So all interfaces would authorized per default. |
| 118 | 125 | ||
| 119 | Note: | 126 | Note: |
| 120 | If a deauthorized interface will be authorized so the driver probing must | 127 | If a deauthorized interface will be authorized so the driver probing must |
| 121 | be triggered manually by writing INTERFACE to /sys/bus/usb/drivers_probe | 128 | be triggered manually by writing INTERFACE to /sys/bus/usb/drivers_probe |
| 122 | 129 | ||
| 123 | For drivers that need multiple interfaces all needed interfaces should be | 130 | For drivers that need multiple interfaces all needed interfaces should be |
| 124 | authorized first. After that the drivers should be probed. | 131 | authorized first. After that the drivers should be probed. |
diff --git a/Documentation/usb/chipidea.txt b/Documentation/usb/chipidea.txt index d1eedc01b00a..68473abe2823 100644 --- a/Documentation/usb/chipidea.txt +++ b/Documentation/usb/chipidea.txt | |||
| @@ -1,22 +1,37 @@ | |||
| 1 | ============================================== | ||
| 2 | ChipIdea Highspeed Dual Role Controller Driver | ||
| 3 | ============================================== | ||
| 4 | |||
| 1 | 1. How to test OTG FSM(HNP and SRP) | 5 | 1. How to test OTG FSM(HNP and SRP) |
| 2 | ----------------------------------- | 6 | ----------------------------------- |
| 7 | |||
| 3 | To show how to demo OTG HNP and SRP functions via sys input files | 8 | To show how to demo OTG HNP and SRP functions via sys input files |
| 4 | with 2 Freescale i.MX6Q sabre SD boards. | 9 | with 2 Freescale i.MX6Q sabre SD boards. |
| 5 | 10 | ||
| 6 | 1.1 How to enable OTG FSM | 11 | 1.1 How to enable OTG FSM |
| 7 | --------------------------------------- | 12 | ------------------------- |
| 13 | |||
| 8 | 1.1.1 Select CONFIG_USB_OTG_FSM in menuconfig, rebuild kernel | 14 | 1.1.1 Select CONFIG_USB_OTG_FSM in menuconfig, rebuild kernel |
| 15 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 16 | |||
| 9 | Image and modules. If you want to check some internal | 17 | Image and modules. If you want to check some internal |
| 10 | variables for otg fsm, mount debugfs, there are 2 files | 18 | variables for otg fsm, mount debugfs, there are 2 files |
| 11 | which can show otg fsm variables and some controller registers value: | 19 | which can show otg fsm variables and some controller registers value:: |
| 12 | cat /sys/kernel/debug/ci_hdrc.0/otg | 20 | |
| 13 | cat /sys/kernel/debug/ci_hdrc.0/registers | 21 | cat /sys/kernel/debug/ci_hdrc.0/otg |
| 22 | cat /sys/kernel/debug/ci_hdrc.0/registers | ||
| 23 | |||
| 14 | 1.1.2 Add below entries in your dts file for your controller node | 24 | 1.1.2 Add below entries in your dts file for your controller node |
| 25 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 26 | |||
| 27 | :: | ||
| 28 | |||
| 15 | otg-rev = <0x0200>; | 29 | otg-rev = <0x0200>; |
| 16 | adp-disable; | 30 | adp-disable; |
| 17 | 31 | ||
| 18 | 1.2 Test operations | 32 | 1.2 Test operations |
| 19 | ------------------- | 33 | ------------------- |
| 34 | |||
| 20 | 1) Power up 2 Freescale i.MX6Q sabre SD boards with gadget class driver loaded | 35 | 1) Power up 2 Freescale i.MX6Q sabre SD boards with gadget class driver loaded |
| 21 | (e.g. g_mass_storage). | 36 | (e.g. g_mass_storage). |
| 22 | 37 | ||
| @@ -26,19 +41,24 @@ cat /sys/kernel/debug/ci_hdrc.0/registers | |||
| 26 | The A-device(with micro A plug inserted) should enumerate B-device. | 41 | The A-device(with micro A plug inserted) should enumerate B-device. |
| 27 | 42 | ||
| 28 | 3) Role switch | 43 | 3) Role switch |
| 29 | On B-device: | 44 | |
| 30 | echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req | 45 | On B-device:: |
| 46 | |||
| 47 | echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req | ||
| 31 | 48 | ||
| 32 | B-device should take host role and enumerate A-device. | 49 | B-device should take host role and enumerate A-device. |
| 33 | 50 | ||
| 34 | 4) A-device switch back to host. | 51 | 4) A-device switch back to host. |
| 35 | On B-device: | 52 | |
| 36 | echo 0 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req | 53 | On B-device:: |
| 54 | |||
| 55 | echo 0 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req | ||
| 37 | 56 | ||
| 38 | or, by introducing HNP polling, B-Host can know when A-peripheral wish | 57 | or, by introducing HNP polling, B-Host can know when A-peripheral wish |
| 39 | to be host role, so this role switch also can be trigged in A-peripheral | 58 | to be host role, so this role switch also can be trigged in A-peripheral |
| 40 | side by answering the polling from B-Host, this can be done on A-device: | 59 | side by answering the polling from B-Host, this can be done on A-device:: |
| 41 | echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_req | 60 | |
| 61 | echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_req | ||
| 42 | 62 | ||
| 43 | A-device should switch back to host and enumerate B-device. | 63 | A-device should switch back to host and enumerate B-device. |
| 44 | 64 | ||
| @@ -49,23 +69,31 @@ cat /sys/kernel/debug/ci_hdrc.0/registers | |||
| 49 | A-device should NOT enumerate B-device. | 69 | A-device should NOT enumerate B-device. |
| 50 | 70 | ||
| 51 | if A-device wants to use bus: | 71 | if A-device wants to use bus: |
| 52 | On A-device: | 72 | |
| 53 | echo 0 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_drop | 73 | On A-device:: |
| 54 | echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_req | 74 | |
| 75 | echo 0 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_drop | ||
| 76 | echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_req | ||
| 55 | 77 | ||
| 56 | if B-device wants to use bus: | 78 | if B-device wants to use bus: |
| 57 | On B-device: | 79 | |
| 58 | echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req | 80 | On B-device:: |
| 81 | |||
| 82 | echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req | ||
| 59 | 83 | ||
| 60 | 7) A-device power down the bus. | 84 | 7) A-device power down the bus. |
| 61 | On A-device: | 85 | |
| 62 | echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_drop | 86 | On A-device:: |
| 87 | |||
| 88 | echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/a_bus_drop | ||
| 63 | 89 | ||
| 64 | A-device should disconnect with B-device and power down the bus. | 90 | A-device should disconnect with B-device and power down the bus. |
| 65 | 91 | ||
| 66 | 8) B-device does data pulse for SRP. | 92 | 8) B-device does data pulse for SRP. |
| 67 | On B-device: | 93 | |
| 68 | echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req | 94 | On B-device:: |
| 95 | |||
| 96 | echo 1 > /sys/bus/platform/devices/ci_hdrc.0/inputs/b_bus_req | ||
| 69 | 97 | ||
| 70 | A-device should resume usb bus and enumerate B-device. | 98 | A-device should resume usb bus and enumerate B-device. |
| 71 | 99 | ||
| @@ -75,22 +103,31 @@ cat /sys/kernel/debug/ci_hdrc.0/registers | |||
| 75 | July 27, 2012 Revision 2.0 version 1.1a" | 103 | July 27, 2012 Revision 2.0 version 1.1a" |
| 76 | 104 | ||
| 77 | 2. How to enable USB as system wakeup source | 105 | 2. How to enable USB as system wakeup source |
| 78 | ----------------------------------- | 106 | -------------------------------------------- |
| 79 | Below is the example for how to enable USB as system wakeup source | 107 | Below is the example for how to enable USB as system wakeup source |
| 80 | at imx6 platform. | 108 | at imx6 platform. |
| 81 | 109 | ||
| 82 | 2.1 Enable core's wakeup | 110 | 2.1 Enable core's wakeup:: |
| 83 | echo enabled > /sys/bus/platform/devices/ci_hdrc.0/power/wakeup | 111 | |
| 84 | 2.2 Enable glue layer's wakeup | 112 | echo enabled > /sys/bus/platform/devices/ci_hdrc.0/power/wakeup |
| 85 | echo enabled > /sys/bus/platform/devices/2184000.usb/power/wakeup | 113 | |
| 86 | 2.3 Enable PHY's wakeup (optional) | 114 | 2.2 Enable glue layer's wakeup:: |
| 87 | echo enabled > /sys/bus/platform/devices/20c9000.usbphy/power/wakeup | 115 | |
| 88 | 2.4 Enable roothub's wakeup | 116 | echo enabled > /sys/bus/platform/devices/2184000.usb/power/wakeup |
| 89 | echo enabled > /sys/bus/usb/devices/usb1/power/wakeup | 117 | |
| 90 | 2.5 Enable related device's wakeup | 118 | 2.3 Enable PHY's wakeup (optional):: |
| 91 | echo enabled > /sys/bus/usb/devices/1-1/power/wakeup | 119 | |
| 120 | echo enabled > /sys/bus/platform/devices/20c9000.usbphy/power/wakeup | ||
| 121 | |||
| 122 | 2.4 Enable roothub's wakeup:: | ||
| 123 | |||
| 124 | echo enabled > /sys/bus/usb/devices/usb1/power/wakeup | ||
| 125 | |||
| 126 | 2.5 Enable related device's wakeup:: | ||
| 127 | |||
| 128 | echo enabled > /sys/bus/usb/devices/1-1/power/wakeup | ||
| 92 | 129 | ||
| 93 | If the system has only one usb port, and you want usb wakeup at this port, you | 130 | If the system has only one usb port, and you want usb wakeup at this port, you |
| 94 | can use below script to enable usb wakeup. | 131 | can use below script to enable usb wakeup:: |
| 95 | for i in $(find /sys -name wakeup | grep usb);do echo enabled > $i;done; | ||
| 96 | 132 | ||
| 133 | for i in $(find /sys -name wakeup | grep usb);do echo enabled > $i;done; | ||
diff --git a/Documentation/usb/dwc3.txt b/Documentation/usb/dwc3.txt index 1d02c01d1c7c..f94a7ba16573 100644 --- a/Documentation/usb/dwc3.txt +++ b/Documentation/usb/dwc3.txt | |||
| @@ -1,6 +1,11 @@ | |||
| 1 | =========== | ||
| 2 | DWC3 driver | ||
| 3 | =========== | ||
| 4 | |||
| 5 | |||
| 6 | TODO | ||
| 7 | ~~~~ | ||
| 1 | 8 | ||
| 2 | TODO | ||
| 3 | ~~~~~~ | ||
| 4 | Please pick something while reading :) | 9 | Please pick something while reading :) |
| 5 | 10 | ||
| 6 | - Convert interrupt handler to per-ep-thread-irq | 11 | - Convert interrupt handler to per-ep-thread-irq |
| @@ -9,6 +14,7 @@ Please pick something while reading :) | |||
| 9 | until the command completes which is bad. | 14 | until the command completes which is bad. |
| 10 | 15 | ||
| 11 | Implementation idea: | 16 | Implementation idea: |
| 17 | |||
| 12 | - dwc core implements a demultiplexing irq chip for interrupts per | 18 | - dwc core implements a demultiplexing irq chip for interrupts per |
| 13 | endpoint. The interrupt numbers are allocated during probe and belong | 19 | endpoint. The interrupt numbers are allocated during probe and belong |
| 14 | to the device. If MSI provides per-endpoint interrupt this dummy | 20 | to the device. If MSI provides per-endpoint interrupt this dummy |
| @@ -19,6 +25,7 @@ Please pick something while reading :) | |||
| 19 | - dwc3_send_gadget_ep_cmd() will sleep in wait_for_completion_timeout() | 25 | - dwc3_send_gadget_ep_cmd() will sleep in wait_for_completion_timeout() |
| 20 | until the command completes. | 26 | until the command completes. |
| 21 | - the interrupt handler is split into the following pieces: | 27 | - the interrupt handler is split into the following pieces: |
| 28 | |||
| 22 | - primary handler of the device | 29 | - primary handler of the device |
| 23 | goes through every event and calls generic_handle_irq() for event | 30 | goes through every event and calls generic_handle_irq() for event |
| 24 | it. On return from generic_handle_irq() in acknowledges the event | 31 | it. On return from generic_handle_irq() in acknowledges the event |
| @@ -40,6 +47,7 @@ Please pick something while reading :) | |||
| 40 | for command completion. | 47 | for command completion. |
| 41 | 48 | ||
| 42 | Latency: | 49 | Latency: |
| 50 | |||
| 43 | There should be no increase in latency since the interrupt-thread has a | 51 | There should be no increase in latency since the interrupt-thread has a |
| 44 | high priority and will be run before an average task in user land | 52 | high priority and will be run before an average task in user land |
| 45 | (except the user changed priorities). | 53 | (except the user changed priorities). |
diff --git a/Documentation/usb/ehci.txt b/Documentation/usb/ehci.txt index 160bd6c3ab7b..31f650e7c1b4 100644 --- a/Documentation/usb/ehci.txt +++ b/Documentation/usb/ehci.txt | |||
| @@ -1,3 +1,7 @@ | |||
| 1 | =========== | ||
| 2 | EHCI driver | ||
| 3 | =========== | ||
| 4 | |||
| 1 | 27-Dec-2002 | 5 | 27-Dec-2002 |
| 2 | 6 | ||
| 3 | The EHCI driver is used to talk to high speed USB 2.0 devices using | 7 | The EHCI driver is used to talk to high speed USB 2.0 devices using |
| @@ -40,7 +44,8 @@ APIs exposed to USB device drivers. | |||
| 40 | <dbrownell@users.sourceforge.net> | 44 | <dbrownell@users.sourceforge.net> |
| 41 | 45 | ||
| 42 | 46 | ||
| 43 | FUNCTIONALITY | 47 | Functionality |
| 48 | ============= | ||
| 44 | 49 | ||
| 45 | This driver is regularly tested on x86 hardware, and has also been | 50 | This driver is regularly tested on x86 hardware, and has also been |
| 46 | used on PPC hardware so big/little endianness issues should be gone. | 51 | used on PPC hardware so big/little endianness issues should be gone. |
| @@ -48,6 +53,7 @@ It's believed to do all the right PCI magic so that I/O works even on | |||
| 48 | systems with interesting DMA mapping issues. | 53 | systems with interesting DMA mapping issues. |
| 49 | 54 | ||
| 50 | Transfer Types | 55 | Transfer Types |
| 56 | -------------- | ||
| 51 | 57 | ||
| 52 | At this writing the driver should comfortably handle all control, bulk, | 58 | At this writing the driver should comfortably handle all control, bulk, |
| 53 | and interrupt transfers, including requests to USB 1.1 devices through | 59 | and interrupt transfers, including requests to USB 1.1 devices through |
| @@ -63,6 +69,7 @@ since EHCI represents these with a different data structure. So for now, | |||
| 63 | most USB audio and video devices can't be connected to high speed buses. | 69 | most USB audio and video devices can't be connected to high speed buses. |
| 64 | 70 | ||
| 65 | Driver Behavior | 71 | Driver Behavior |
| 72 | --------------- | ||
| 66 | 73 | ||
| 67 | Transfers of all types can be queued. This means that control transfers | 74 | Transfers of all types can be queued. This means that control transfers |
| 68 | from a driver on one interface (or through usbfs) won't interfere with | 75 | from a driver on one interface (or through usbfs) won't interfere with |
| @@ -83,14 +90,15 @@ limits on the number of periodic transactions that can be scheduled, | |||
| 83 | and prevent use of polling intervals of less than one frame. | 90 | and prevent use of polling intervals of less than one frame. |
| 84 | 91 | ||
| 85 | 92 | ||
| 86 | USE BY | 93 | Use by |
| 94 | ====== | ||
| 87 | 95 | ||
| 88 | Assuming you have an EHCI controller (on a PCI card or motherboard) | 96 | Assuming you have an EHCI controller (on a PCI card or motherboard) |
| 89 | and have compiled this driver as a module, load this like: | 97 | and have compiled this driver as a module, load this like:: |
| 90 | 98 | ||
| 91 | # modprobe ehci-hcd | 99 | # modprobe ehci-hcd |
| 92 | 100 | ||
| 93 | and remove it by: | 101 | and remove it by:: |
| 94 | 102 | ||
| 95 | # rmmod ehci-hcd | 103 | # rmmod ehci-hcd |
| 96 | 104 | ||
| @@ -112,13 +120,16 @@ If you're using this driver on a 2.5 kernel, and you've enabled USB | |||
| 112 | debugging support, you'll see three files in the "sysfs" directory for | 120 | debugging support, you'll see three files in the "sysfs" directory for |
| 113 | any EHCI controller: | 121 | any EHCI controller: |
| 114 | 122 | ||
| 115 | "async" dumps the asynchronous schedule, used for control | 123 | "async" |
| 124 | dumps the asynchronous schedule, used for control | ||
| 116 | and bulk transfers. Shows each active qh and the qtds | 125 | and bulk transfers. Shows each active qh and the qtds |
| 117 | pending, usually one qtd per urb. (Look at it with | 126 | pending, usually one qtd per urb. (Look at it with |
| 118 | usb-storage doing disk I/O; watch the request queues!) | 127 | usb-storage doing disk I/O; watch the request queues!) |
| 119 | "periodic" dumps the periodic schedule, used for interrupt | 128 | "periodic" |
| 129 | dumps the periodic schedule, used for interrupt | ||
| 120 | and isochronous transfers. Doesn't show qtds. | 130 | and isochronous transfers. Doesn't show qtds. |
| 121 | "registers" show controller register state, and | 131 | "registers" |
| 132 | show controller register state, and | ||
| 122 | 133 | ||
| 123 | The contents of those files can help identify driver problems. | 134 | The contents of those files can help identify driver problems. |
| 124 | 135 | ||
| @@ -136,7 +147,8 @@ transaction translators are in use; some drivers have been seen to behave | |||
| 136 | badly when they see different faults than OHCI or UHCI report. | 147 | badly when they see different faults than OHCI or UHCI report. |
| 137 | 148 | ||
| 138 | 149 | ||
| 139 | PERFORMANCE | 150 | Performance |
| 151 | =========== | ||
| 140 | 152 | ||
| 141 | USB 2.0 throughput is gated by two main factors: how fast the host | 153 | USB 2.0 throughput is gated by two main factors: how fast the host |
| 142 | controller can process requests, and how fast devices can respond to | 154 | controller can process requests, and how fast devices can respond to |
| @@ -156,6 +168,7 @@ hardware and device driver software allow it. Periodic transfer modes | |||
| 156 | approach the quoted 480 MBit/sec transfer rate. | 168 | approach the quoted 480 MBit/sec transfer rate. |
| 157 | 169 | ||
| 158 | Hardware Performance | 170 | Hardware Performance |
| 171 | -------------------- | ||
| 159 | 172 | ||
| 160 | At this writing, individual USB 2.0 devices tend to max out at around | 173 | At this writing, individual USB 2.0 devices tend to max out at around |
| 161 | 20 MByte/sec transfer rates. This is of course subject to change; | 174 | 20 MByte/sec transfer rates. This is of course subject to change; |
| @@ -183,6 +196,7 @@ you issue a control or bulk request you can often expect to learn that | |||
| 183 | it completed in less than 250 usec (depending on transfer size). | 196 | it completed in less than 250 usec (depending on transfer size). |
| 184 | 197 | ||
| 185 | Software Performance | 198 | Software Performance |
| 199 | -------------------- | ||
| 186 | 200 | ||
| 187 | To get even 20 MByte/sec transfer rates, Linux-USB device drivers will | 201 | To get even 20 MByte/sec transfer rates, Linux-USB device drivers will |
| 188 | need to keep the EHCI queue full. That means issuing large requests, | 202 | need to keep the EHCI queue full. That means issuing large requests, |
| @@ -206,9 +220,11 @@ mapping (which might apply an IOMMU) and IRQ reduction, all of which will | |||
| 206 | help make high speed transfers run as fast as they can. | 220 | help make high speed transfers run as fast as they can. |
| 207 | 221 | ||
| 208 | 222 | ||
| 209 | TBD: Interrupt and ISO transfer performance issues. Those periodic | 223 | TBD: |
| 210 | transfers are fully scheduled, so the main issue is likely to be how | 224 | Interrupt and ISO transfer performance issues. Those periodic |
| 211 | to trigger "high bandwidth" modes. | 225 | transfers are fully scheduled, so the main issue is likely to be how |
| 226 | to trigger "high bandwidth" modes. | ||
| 212 | 227 | ||
| 213 | TBD: More than standard 80% periodic bandwidth allocation is possible | 228 | TBD: |
| 214 | through sysfs uframe_periodic_max parameter. Describe that. | 229 | More than standard 80% periodic bandwidth allocation is possible |
| 230 | through sysfs uframe_periodic_max parameter. Describe that. | ||
diff --git a/Documentation/usb/functionfs.txt b/Documentation/usb/functionfs.txt index eaaaea019fc7..7fdc6d840ac5 100644 --- a/Documentation/usb/functionfs.txt +++ b/Documentation/usb/functionfs.txt | |||
| @@ -1,4 +1,6 @@ | |||
| 1 | *How FunctionFS works* | 1 | ==================== |
| 2 | How FunctionFS works | ||
| 3 | ==================== | ||
| 2 | 4 | ||
| 3 | From kernel point of view it is just a composite function with some | 5 | From kernel point of view it is just a composite function with some |
| 4 | unique behaviour. It may be added to an USB configuration only after | 6 | unique behaviour. It may be added to an USB configuration only after |
| @@ -38,13 +40,13 @@ when mounting. | |||
| 38 | 40 | ||
| 39 | One can imagine a gadget that has an Ethernet, MTP and HID interfaces | 41 | One can imagine a gadget that has an Ethernet, MTP and HID interfaces |
| 40 | where the last two are implemented via FunctionFS. On user space | 42 | where the last two are implemented via FunctionFS. On user space |
| 41 | level it would look like this: | 43 | level it would look like this:: |
| 42 | 44 | ||
| 43 | $ insmod g_ffs.ko idVendor=<ID> iSerialNumber=<string> functions=mtp,hid | 45 | $ insmod g_ffs.ko idVendor=<ID> iSerialNumber=<string> functions=mtp,hid |
| 44 | $ mkdir /dev/ffs-mtp && mount -t functionfs mtp /dev/ffs-mtp | 46 | $ mkdir /dev/ffs-mtp && mount -t functionfs mtp /dev/ffs-mtp |
| 45 | $ ( cd /dev/ffs-mtp && mtp-daemon ) & | 47 | $ ( cd /dev/ffs-mtp && mtp-daemon ) & |
| 46 | $ mkdir /dev/ffs-hid && mount -t functionfs hid /dev/ffs-hid | 48 | $ mkdir /dev/ffs-hid && mount -t functionfs hid /dev/ffs-hid |
| 47 | $ ( cd /dev/ffs-hid && hid-daemon ) & | 49 | $ ( cd /dev/ffs-hid && hid-daemon ) & |
| 48 | 50 | ||
| 49 | On kernel level the gadget checks ffs_data->dev_name to identify | 51 | On kernel level the gadget checks ffs_data->dev_name to identify |
| 50 | whether it's FunctionFS designed for MTP ("mtp") or HID ("hid"). | 52 | whether it's FunctionFS designed for MTP ("mtp") or HID ("hid"). |
| @@ -64,4 +66,3 @@ have been written to their ep0's. | |||
| 64 | 66 | ||
| 65 | Conversely, the gadget is unregistered after the first USB function | 67 | Conversely, the gadget is unregistered after the first USB function |
| 66 | closes its endpoints. | 68 | closes its endpoints. |
| 67 | |||
diff --git a/Documentation/usb/gadget-testing.txt b/Documentation/usb/gadget-testing.txt index 5908a21fddb6..7d7f2340af42 100644 --- a/Documentation/usb/gadget-testing.txt +++ b/Documentation/usb/gadget-testing.txt | |||
| @@ -1,26 +1,32 @@ | |||
| 1 | ============== | ||
| 2 | Gadget Testing | ||
| 3 | ============== | ||
| 4 | |||
| 1 | This file summarizes information on basic testing of USB functions | 5 | This file summarizes information on basic testing of USB functions |
| 2 | provided by gadgets. | 6 | provided by gadgets. |
| 3 | 7 | ||
| 4 | 1. ACM function | 8 | .. contents |
| 5 | 2. ECM function | 9 | |
| 6 | 3. ECM subset function | 10 | 1. ACM function |
| 7 | 4. EEM function | 11 | 2. ECM function |
| 8 | 5. FFS function | 12 | 3. ECM subset function |
| 9 | 6. HID function | 13 | 4. EEM function |
| 10 | 7. LOOPBACK function | 14 | 5. FFS function |
| 11 | 8. MASS STORAGE function | 15 | 6. HID function |
| 12 | 9. MIDI function | 16 | 7. LOOPBACK function |
| 13 | 10. NCM function | 17 | 8. MASS STORAGE function |
| 14 | 11. OBEX function | 18 | 9. MIDI function |
| 15 | 12. PHONET function | 19 | 10. NCM function |
| 16 | 13. RNDIS function | 20 | 11. OBEX function |
| 17 | 14. SERIAL function | 21 | 12. PHONET function |
| 18 | 15. SOURCESINK function | 22 | 13. RNDIS function |
| 19 | 16. UAC1 function (legacy implementation) | 23 | 14. SERIAL function |
| 20 | 17. UAC2 function | 24 | 15. SOURCESINK function |
| 21 | 18. UVC function | 25 | 16. UAC1 function (legacy implementation) |
| 22 | 19. PRINTER function | 26 | 17. UAC2 function |
| 23 | 20. UAC1 function (new API) | 27 | 18. UVC function |
| 28 | 19. PRINTER function | ||
| 29 | 20. UAC1 function (new API) | ||
| 24 | 30 | ||
| 25 | 31 | ||
| 26 | 1. ACM function | 32 | 1. ACM function |
| @@ -44,13 +50,23 @@ There can be at most 4 ACM/generic serial/OBEX ports in the system. | |||
| 44 | Testing the ACM function | 50 | Testing the ACM function |
| 45 | ------------------------ | 51 | ------------------------ |
| 46 | 52 | ||
| 47 | On the host: cat > /dev/ttyACM<X> | 53 | On the host:: |
| 48 | On the device : cat /dev/ttyGS<Y> | 54 | |
| 55 | cat > /dev/ttyACM<X> | ||
| 56 | |||
| 57 | On the device:: | ||
| 58 | |||
| 59 | cat /dev/ttyGS<Y> | ||
| 49 | 60 | ||
| 50 | then the other way round | 61 | then the other way round |
| 51 | 62 | ||
| 52 | On the device: cat > /dev/ttyGS<Y> | 63 | On the device:: |
| 53 | On the host: cat /dev/ttyACM<X> | 64 | |
| 65 | cat > /dev/ttyGS<Y> | ||
| 66 | |||
| 67 | On the host:: | ||
| 68 | |||
| 69 | cat /dev/ttyACM<X> | ||
| 54 | 70 | ||
| 55 | 2. ECM function | 71 | 2. ECM function |
| 56 | =============== | 72 | =============== |
| @@ -63,13 +79,15 @@ Function-specific configfs interface | |||
| 63 | The function name to use when creating the function directory is "ecm". | 79 | The function name to use when creating the function directory is "ecm". |
| 64 | The ECM function provides these attributes in its function directory: | 80 | The ECM function provides these attributes in its function directory: |
| 65 | 81 | ||
| 66 | ifname - network device interface name associated with this | 82 | =============== ================================================== |
| 83 | ifname network device interface name associated with this | ||
| 67 | function instance | 84 | function instance |
| 68 | qmult - queue length multiplier for high and super speed | 85 | qmult queue length multiplier for high and super speed |
| 69 | host_addr - MAC address of host's end of this | 86 | host_addr MAC address of host's end of this |
| 70 | Ethernet over USB link | 87 | Ethernet over USB link |
| 71 | dev_addr - MAC address of device's end of this | 88 | dev_addr MAC address of device's end of this |
| 72 | Ethernet over USB link | 89 | Ethernet over USB link |
| 90 | =============== ================================================== | ||
| 73 | 91 | ||
| 74 | and after creating the functions/ecm.<instance name> they contain default | 92 | and after creating the functions/ecm.<instance name> they contain default |
| 75 | values: qmult is 5, dev_addr and host_addr are randomly selected. | 93 | values: qmult is 5, dev_addr and host_addr are randomly selected. |
| @@ -82,8 +100,13 @@ Testing the ECM function | |||
| 82 | 100 | ||
| 83 | Configure IP addresses of the device and the host. Then: | 101 | Configure IP addresses of the device and the host. Then: |
| 84 | 102 | ||
| 85 | On the device: ping <host's IP> | 103 | On the device:: |
| 86 | On the host: ping <device's IP> | 104 | |
| 105 | ping <host's IP> | ||
| 106 | |||
| 107 | On the host:: | ||
| 108 | |||
| 109 | ping <device's IP> | ||
| 87 | 110 | ||
| 88 | 3. ECM subset function | 111 | 3. ECM subset function |
| 89 | ====================== | 112 | ====================== |
| @@ -96,13 +119,15 @@ Function-specific configfs interface | |||
| 96 | The function name to use when creating the function directory is "geth". | 119 | The function name to use when creating the function directory is "geth". |
| 97 | The ECM subset function provides these attributes in its function directory: | 120 | The ECM subset function provides these attributes in its function directory: |
| 98 | 121 | ||
| 99 | ifname - network device interface name associated with this | 122 | =============== ================================================== |
| 123 | ifname network device interface name associated with this | ||
| 100 | function instance | 124 | function instance |
| 101 | qmult - queue length multiplier for high and super speed | 125 | qmult queue length multiplier for high and super speed |
| 102 | host_addr - MAC address of host's end of this | 126 | host_addr MAC address of host's end of this |
| 103 | Ethernet over USB link | 127 | Ethernet over USB link |
| 104 | dev_addr - MAC address of device's end of this | 128 | dev_addr MAC address of device's end of this |
| 105 | Ethernet over USB link | 129 | Ethernet over USB link |
| 130 | =============== ================================================== | ||
| 106 | 131 | ||
| 107 | and after creating the functions/ecm.<instance name> they contain default | 132 | and after creating the functions/ecm.<instance name> they contain default |
| 108 | values: qmult is 5, dev_addr and host_addr are randomly selected. | 133 | values: qmult is 5, dev_addr and host_addr are randomly selected. |
| @@ -115,8 +140,13 @@ Testing the ECM subset function | |||
| 115 | 140 | ||
| 116 | Configure IP addresses of the device and the host. Then: | 141 | Configure IP addresses of the device and the host. Then: |
| 117 | 142 | ||
| 118 | On the device: ping <host's IP> | 143 | On the device:: |
| 119 | On the host: ping <device's IP> | 144 | |
| 145 | ping <host's IP> | ||
| 146 | |||
| 147 | On the host:: | ||
| 148 | |||
| 149 | ping <device's IP> | ||
| 120 | 150 | ||
| 121 | 4. EEM function | 151 | 4. EEM function |
| 122 | =============== | 152 | =============== |
| @@ -129,13 +159,15 @@ Function-specific configfs interface | |||
| 129 | The function name to use when creating the function directory is "eem". | 159 | The function name to use when creating the function directory is "eem". |
| 130 | The EEM function provides these attributes in its function directory: | 160 | The EEM function provides these attributes in its function directory: |
| 131 | 161 | ||
| 132 | ifname - network device interface name associated with this | 162 | =============== ================================================== |
| 163 | ifname network device interface name associated with this | ||
| 133 | function instance | 164 | function instance |
| 134 | qmult - queue length multiplier for high and super speed | 165 | qmult queue length multiplier for high and super speed |
| 135 | host_addr - MAC address of host's end of this | 166 | host_addr MAC address of host's end of this |
| 136 | Ethernet over USB link | 167 | Ethernet over USB link |
| 137 | dev_addr - MAC address of device's end of this | 168 | dev_addr MAC address of device's end of this |
| 138 | Ethernet over USB link | 169 | Ethernet over USB link |
| 170 | =============== ================================================== | ||
| 139 | 171 | ||
| 140 | and after creating the functions/eem.<instance name> they contain default | 172 | and after creating the functions/eem.<instance name> they contain default |
| 141 | values: qmult is 5, dev_addr and host_addr are randomly selected. | 173 | values: qmult is 5, dev_addr and host_addr are randomly selected. |
| @@ -148,8 +180,13 @@ Testing the EEM function | |||
| 148 | 180 | ||
| 149 | Configure IP addresses of the device and the host. Then: | 181 | Configure IP addresses of the device and the host. Then: |
| 150 | 182 | ||
| 151 | On the device: ping <host's IP> | 183 | On the device:: |
| 152 | On the host: ping <device's IP> | 184 | |
| 185 | ping <host's IP> | ||
| 186 | |||
| 187 | On the host:: | ||
| 188 | |||
| 189 | ping <device's IP> | ||
| 153 | 190 | ||
| 154 | 5. FFS function | 191 | 5. FFS function |
| 155 | =============== | 192 | =============== |
| @@ -172,6 +209,7 @@ Testing the FFS function | |||
| 172 | ------------------------ | 209 | ------------------------ |
| 173 | 210 | ||
| 174 | On the device: start the function's userspace daemon, enable the gadget | 211 | On the device: start the function's userspace daemon, enable the gadget |
| 212 | |||
| 175 | On the host: use the USB function provided by the device | 213 | On the host: use the USB function provided by the device |
| 176 | 214 | ||
| 177 | 6. HID function | 215 | 6. HID function |
| @@ -185,39 +223,43 @@ Function-specific configfs interface | |||
| 185 | The function name to use when creating the function directory is "hid". | 223 | The function name to use when creating the function directory is "hid". |
| 186 | The HID function provides these attributes in its function directory: | 224 | The HID function provides these attributes in its function directory: |
| 187 | 225 | ||
| 188 | protocol - HID protocol to use | 226 | =============== =========================================== |
| 189 | report_desc - data to be used in HID reports, except data | 227 | protocol HID protocol to use |
| 228 | report_desc data to be used in HID reports, except data | ||
| 190 | passed with /dev/hidg<X> | 229 | passed with /dev/hidg<X> |
| 191 | report_length - HID report length | 230 | report_length HID report length |
| 192 | subclass - HID subclass to use | 231 | subclass HID subclass to use |
| 232 | =============== =========================================== | ||
| 193 | 233 | ||
| 194 | For a keyboard the protocol and the subclass are 1, the report_length is 8, | 234 | For a keyboard the protocol and the subclass are 1, the report_length is 8, |
| 195 | while the report_desc is: | 235 | while the report_desc is:: |
| 196 | 236 | ||
| 197 | $ hd my_report_desc | 237 | $ hd my_report_desc |
| 198 | 00000000 05 01 09 06 a1 01 05 07 19 e0 29 e7 15 00 25 01 |..........)...%.| | 238 | 00000000 05 01 09 06 a1 01 05 07 19 e0 29 e7 15 00 25 01 |..........)...%.| |
| 199 | 00000010 75 01 95 08 81 02 95 01 75 08 81 03 95 05 75 01 |u.......u.....u.| | 239 | 00000010 75 01 95 08 81 02 95 01 75 08 81 03 95 05 75 01 |u.......u.....u.| |
| 200 | 00000020 05 08 19 01 29 05 91 02 95 01 75 03 91 03 95 06 |....).....u.....| | 240 | 00000020 05 08 19 01 29 05 91 02 95 01 75 03 91 03 95 06 |....).....u.....| |
| 201 | 00000030 75 08 15 00 25 65 05 07 19 00 29 65 81 00 c0 |u...%e....)e...| | 241 | 00000030 75 08 15 00 25 65 05 07 19 00 29 65 81 00 c0 |u...%e....)e...| |
| 202 | 0000003f | 242 | 0000003f |
| 203 | 243 | ||
| 204 | Such a sequence of bytes can be stored to the attribute with echo: | 244 | Such a sequence of bytes can be stored to the attribute with echo:: |
| 205 | 245 | ||
| 206 | $ echo -ne \\x05\\x01\\x09\\x06\\xa1..... | 246 | $ echo -ne \\x05\\x01\\x09\\x06\\xa1..... |
| 207 | 247 | ||
| 208 | Testing the HID function | 248 | Testing the HID function |
| 209 | ------------------------ | 249 | ------------------------ |
| 210 | 250 | ||
| 211 | Device: | 251 | Device: |
| 252 | |||
| 212 | - create the gadget | 253 | - create the gadget |
| 213 | - connect the gadget to a host, preferably not the one used | 254 | - connect the gadget to a host, preferably not the one used |
| 214 | to control the gadget | 255 | to control the gadget |
| 215 | - run a program which writes to /dev/hidg<N>, e.g. | 256 | - run a program which writes to /dev/hidg<N>, e.g. |
| 216 | a userspace program found in Documentation/usb/gadget_hid.txt: | 257 | a userspace program found in Documentation/usb/gadget_hid.txt:: |
| 217 | 258 | ||
| 218 | $ ./hid_gadget_test /dev/hidg0 keyboard | 259 | $ ./hid_gadget_test /dev/hidg0 keyboard |
| 219 | 260 | ||
| 220 | Host: | 261 | Host: |
| 262 | |||
| 221 | - observe the keystrokes from the gadget | 263 | - observe the keystrokes from the gadget |
| 222 | 264 | ||
| 223 | 7. LOOPBACK function | 265 | 7. LOOPBACK function |
| @@ -231,13 +273,16 @@ Function-specific configfs interface | |||
| 231 | The function name to use when creating the function directory is "Loopback". | 273 | The function name to use when creating the function directory is "Loopback". |
| 232 | The LOOPBACK function provides these attributes in its function directory: | 274 | The LOOPBACK function provides these attributes in its function directory: |
| 233 | 275 | ||
| 234 | qlen - depth of loopback queue | 276 | =============== ======================= |
| 235 | bulk_buflen - buffer length | 277 | qlen depth of loopback queue |
| 278 | bulk_buflen buffer length | ||
| 279 | =============== ======================= | ||
| 236 | 280 | ||
| 237 | Testing the LOOPBACK function | 281 | Testing the LOOPBACK function |
| 238 | ----------------------------- | 282 | ----------------------------- |
| 239 | 283 | ||
| 240 | device: run the gadget | 284 | device: run the gadget |
| 285 | |||
| 241 | host: test-usb (tools/usb/testusb.c) | 286 | host: test-usb (tools/usb/testusb.c) |
| 242 | 287 | ||
| 243 | 8. MASS STORAGE function | 288 | 8. MASS STORAGE function |
| @@ -252,18 +297,20 @@ The function name to use when creating the function directory is "mass_storage". | |||
| 252 | The MASS STORAGE function provides these attributes in its directory: | 297 | The MASS STORAGE function provides these attributes in its directory: |
| 253 | files: | 298 | files: |
| 254 | 299 | ||
| 255 | stall - Set to permit function to halt bulk endpoints. | 300 | =============== ============================================== |
| 301 | stall Set to permit function to halt bulk endpoints. | ||
| 256 | Disabled on some USB devices known not to work | 302 | Disabled on some USB devices known not to work |
| 257 | correctly. You should set it to true. | 303 | correctly. You should set it to true. |
| 258 | num_buffers - Number of pipeline buffers. Valid numbers | 304 | num_buffers Number of pipeline buffers. Valid numbers |
| 259 | are 2..4. Available only if | 305 | are 2..4. Available only if |
| 260 | CONFIG_USB_GADGET_DEBUG_FILES is set. | 306 | CONFIG_USB_GADGET_DEBUG_FILES is set. |
| 307 | =============== ============================================== | ||
| 261 | 308 | ||
| 262 | and a default lun.0 directory corresponding to SCSI LUN #0. | 309 | and a default lun.0 directory corresponding to SCSI LUN #0. |
| 263 | 310 | ||
| 264 | A new lun can be added with mkdir: | 311 | A new lun can be added with mkdir:: |
| 265 | 312 | ||
| 266 | $ mkdir functions/mass_storage.0/partition.5 | 313 | $ mkdir functions/mass_storage.0/partition.5 |
| 267 | 314 | ||
| 268 | Lun numbering does not have to be continuous, except for lun #0 which is | 315 | Lun numbering does not have to be continuous, except for lun #0 which is |
| 269 | created by default. A maximum of 8 luns can be specified and they all must be | 316 | created by default. A maximum of 8 luns can be specified and they all must be |
| @@ -273,18 +320,20 @@ although it is not mandatory. | |||
| 273 | 320 | ||
| 274 | In each lun directory there are the following attribute files: | 321 | In each lun directory there are the following attribute files: |
| 275 | 322 | ||
| 276 | file - The path to the backing file for the LUN. | 323 | =============== ============================================== |
| 324 | file The path to the backing file for the LUN. | ||
| 277 | Required if LUN is not marked as removable. | 325 | Required if LUN is not marked as removable. |
| 278 | ro - Flag specifying access to the LUN shall be | 326 | ro Flag specifying access to the LUN shall be |
| 279 | read-only. This is implied if CD-ROM emulation | 327 | read-only. This is implied if CD-ROM emulation |
| 280 | is enabled as well as when it was impossible | 328 | is enabled as well as when it was impossible |
| 281 | to open "filename" in R/W mode. | 329 | to open "filename" in R/W mode. |
| 282 | removable - Flag specifying that LUN shall be indicated as | 330 | removable Flag specifying that LUN shall be indicated as |
| 283 | being removable. | 331 | being removable. |
| 284 | cdrom - Flag specifying that LUN shall be reported as | 332 | cdrom Flag specifying that LUN shall be reported as |
| 285 | being a CD-ROM. | 333 | being a CD-ROM. |
| 286 | nofua - Flag specifying that FUA flag | 334 | nofua Flag specifying that FUA flag |
| 287 | in SCSI WRITE(10,12) | 335 | in SCSI WRITE(10,12) |
| 336 | =============== ============================================== | ||
| 288 | 337 | ||
| 289 | Testing the MASS STORAGE function | 338 | Testing the MASS STORAGE function |
| 290 | --------------------------------- | 339 | --------------------------------- |
| @@ -304,12 +353,14 @@ Function-specific configfs interface | |||
| 304 | The function name to use when creating the function directory is "midi". | 353 | The function name to use when creating the function directory is "midi". |
| 305 | The MIDI function provides these attributes in its function directory: | 354 | The MIDI function provides these attributes in its function directory: |
| 306 | 355 | ||
| 307 | buflen - MIDI buffer length | 356 | =============== ==================================== |
| 308 | id - ID string for the USB MIDI adapter | 357 | buflen MIDI buffer length |
| 309 | in_ports - number of MIDI input ports | 358 | id ID string for the USB MIDI adapter |
| 310 | index - index value for the USB MIDI adapter | 359 | in_ports number of MIDI input ports |
| 311 | out_ports - number of MIDI output ports | 360 | index index value for the USB MIDI adapter |
| 312 | qlen - USB read request queue length | 361 | out_ports number of MIDI output ports |
| 362 | qlen USB read request queue length | ||
| 363 | =============== ==================================== | ||
| 313 | 364 | ||
| 314 | Testing the MIDI function | 365 | Testing the MIDI function |
| 315 | ------------------------- | 366 | ------------------------- |
| @@ -317,60 +368,63 @@ Testing the MIDI function | |||
| 317 | There are two cases: playing a mid from the gadget to | 368 | There are two cases: playing a mid from the gadget to |
| 318 | the host and playing a mid from the host to the gadget. | 369 | the host and playing a mid from the host to the gadget. |
| 319 | 370 | ||
| 320 | 1) Playing a mid from the gadget to the host | 371 | 1) Playing a mid from the gadget to the host: |
| 321 | host) | 372 | |
| 373 | host:: | ||
| 322 | 374 | ||
| 323 | $ arecordmidi -l | 375 | $ arecordmidi -l |
| 324 | Port Client name Port name | 376 | Port Client name Port name |
| 325 | 14:0 Midi Through Midi Through Port-0 | 377 | 14:0 Midi Through Midi Through Port-0 |
| 326 | 24:0 MIDI Gadget MIDI Gadget MIDI 1 | 378 | 24:0 MIDI Gadget MIDI Gadget MIDI 1 |
| 327 | $ arecordmidi -p 24:0 from_gadget.mid | 379 | $ arecordmidi -p 24:0 from_gadget.mid |
| 328 | 380 | ||
| 329 | gadget) | 381 | gadget:: |
| 330 | 382 | ||
| 331 | $ aplaymidi -l | 383 | $ aplaymidi -l |
| 332 | Port Client name Port name | 384 | Port Client name Port name |
| 333 | 20:0 f_midi f_midi | 385 | 20:0 f_midi f_midi |
| 334 | 386 | ||
| 335 | $ aplaymidi -p 20:0 to_host.mid | 387 | $ aplaymidi -p 20:0 to_host.mid |
| 336 | 388 | ||
| 337 | 2) Playing a mid from the host to the gadget | 389 | 2) Playing a mid from the host to the gadget |
| 338 | gadget) | ||
| 339 | 390 | ||
| 340 | $ arecordmidi -l | 391 | gadget:: |
| 341 | Port Client name Port name | 392 | |
| 342 | 20:0 f_midi f_midi | 393 | $ arecordmidi -l |
| 394 | Port Client name Port name | ||
| 395 | 20:0 f_midi f_midi | ||
| 343 | 396 | ||
| 344 | $ arecordmidi -p 20:0 from_host.mid | 397 | $ arecordmidi -p 20:0 from_host.mid |
| 345 | 398 | ||
| 346 | host) | 399 | host:: |
| 347 | 400 | ||
| 348 | $ aplaymidi -l | 401 | $ aplaymidi -l |
| 349 | Port Client name Port name | 402 | Port Client name Port name |
| 350 | 14:0 Midi Through Midi Through Port-0 | 403 | 14:0 Midi Through Midi Through Port-0 |
| 351 | 24:0 MIDI Gadget MIDI Gadget MIDI 1 | 404 | 24:0 MIDI Gadget MIDI Gadget MIDI 1 |
| 352 | 405 | ||
| 353 | $ aplaymidi -p24:0 to_gadget.mid | 406 | $ aplaymidi -p24:0 to_gadget.mid |
| 354 | 407 | ||
| 355 | The from_gadget.mid should sound identical to the to_host.mid. | 408 | The from_gadget.mid should sound identical to the to_host.mid. |
| 409 | |||
| 356 | The from_host.id should sound identical to the to_gadget.mid. | 410 | The from_host.id should sound identical to the to_gadget.mid. |
| 357 | 411 | ||
| 358 | MIDI files can be played to speakers/headphones with e.g. timidity installed | 412 | MIDI files can be played to speakers/headphones with e.g. timidity installed:: |
| 359 | 413 | ||
| 360 | $ aplaymidi -l | 414 | $ aplaymidi -l |
| 361 | Port Client name Port name | 415 | Port Client name Port name |
| 362 | 14:0 Midi Through Midi Through Port-0 | 416 | 14:0 Midi Through Midi Through Port-0 |
| 363 | 24:0 MIDI Gadget MIDI Gadget MIDI 1 | 417 | 24:0 MIDI Gadget MIDI Gadget MIDI 1 |
| 364 | 128:0 TiMidity TiMidity port 0 | 418 | 128:0 TiMidity TiMidity port 0 |
| 365 | 128:1 TiMidity TiMidity port 1 | 419 | 128:1 TiMidity TiMidity port 1 |
| 366 | 128:2 TiMidity TiMidity port 2 | 420 | 128:2 TiMidity TiMidity port 2 |
| 367 | 128:3 TiMidity TiMidity port 3 | 421 | 128:3 TiMidity TiMidity port 3 |
| 368 | 422 | ||
| 369 | $ aplaymidi -p 128:0 file.mid | 423 | $ aplaymidi -p 128:0 file.mid |
| 370 | 424 | ||
| 371 | MIDI ports can be logically connected using the aconnect utility, e.g.: | 425 | MIDI ports can be logically connected using the aconnect utility, e.g.:: |
| 372 | 426 | ||
| 373 | $ aconnect 24:0 128:0 # try it on the host | 427 | $ aconnect 24:0 128:0 # try it on the host |
| 374 | 428 | ||
| 375 | After the gadget's MIDI port is connected to timidity's MIDI port, | 429 | After the gadget's MIDI port is connected to timidity's MIDI port, |
| 376 | whatever is played at the gadget side with aplaymidi -l is audible | 430 | whatever is played at the gadget side with aplaymidi -l is audible |
| @@ -387,13 +441,15 @@ Function-specific configfs interface | |||
| 387 | The function name to use when creating the function directory is "ncm". | 441 | The function name to use when creating the function directory is "ncm". |
| 388 | The NCM function provides these attributes in its function directory: | 442 | The NCM function provides these attributes in its function directory: |
| 389 | 443 | ||
| 390 | ifname - network device interface name associated with this | 444 | =============== ================================================== |
| 445 | ifname network device interface name associated with this | ||
| 391 | function instance | 446 | function instance |
| 392 | qmult - queue length multiplier for high and super speed | 447 | qmult queue length multiplier for high and super speed |
| 393 | host_addr - MAC address of host's end of this | 448 | host_addr MAC address of host's end of this |
| 394 | Ethernet over USB link | 449 | Ethernet over USB link |
| 395 | dev_addr - MAC address of device's end of this | 450 | dev_addr MAC address of device's end of this |
| 396 | Ethernet over USB link | 451 | Ethernet over USB link |
| 452 | =============== ================================================== | ||
| 397 | 453 | ||
| 398 | and after creating the functions/ncm.<instance name> they contain default | 454 | and after creating the functions/ncm.<instance name> they contain default |
| 399 | values: qmult is 5, dev_addr and host_addr are randomly selected. | 455 | values: qmult is 5, dev_addr and host_addr are randomly selected. |
| @@ -406,8 +462,13 @@ Testing the NCM function | |||
| 406 | 462 | ||
| 407 | Configure IP addresses of the device and the host. Then: | 463 | Configure IP addresses of the device and the host. Then: |
| 408 | 464 | ||
| 409 | On the device: ping <host's IP> | 465 | On the device:: |
| 410 | On the host: ping <device's IP> | 466 | |
| 467 | ping <host's IP> | ||
| 468 | |||
| 469 | On the host:: | ||
| 470 | |||
| 471 | ping <device's IP> | ||
| 411 | 472 | ||
| 412 | 11. OBEX function | 473 | 11. OBEX function |
| 413 | ================= | 474 | ================= |
| @@ -429,13 +490,18 @@ There can be at most 4 ACM/generic serial/OBEX ports in the system. | |||
| 429 | Testing the OBEX function | 490 | Testing the OBEX function |
| 430 | ------------------------- | 491 | ------------------------- |
| 431 | 492 | ||
| 432 | On device: seriald -f /dev/ttyGS<Y> -s 1024 | 493 | On device:: |
| 433 | On host: serialc -v <vendorID> -p <productID> -i<interface#> -a1 -s1024 \ | 494 | |
| 434 | -t<out endpoint addr> -r<in endpoint addr> | 495 | seriald -f /dev/ttyGS<Y> -s 1024 |
| 496 | |||
| 497 | On host:: | ||
| 498 | |||
| 499 | serialc -v <vendorID> -p <productID> -i<interface#> -a1 -s1024 \ | ||
| 500 | -t<out endpoint addr> -r<in endpoint addr> | ||
| 435 | 501 | ||
| 436 | where seriald and serialc are Felipe's utilities found here: | 502 | where seriald and serialc are Felipe's utilities found here: |
| 437 | 503 | ||
| 438 | https://github.com/felipebalbi/usb-tools.git master | 504 | https://github.com/felipebalbi/usb-tools.git master |
| 439 | 505 | ||
| 440 | 12. PHONET function | 506 | 12. PHONET function |
| 441 | =================== | 507 | =================== |
| @@ -448,8 +514,10 @@ Function-specific configfs interface | |||
| 448 | The function name to use when creating the function directory is "phonet". | 514 | The function name to use when creating the function directory is "phonet". |
| 449 | The PHONET function provides just one attribute in its function directory: | 515 | The PHONET function provides just one attribute in its function directory: |
| 450 | 516 | ||
| 451 | ifname - network device interface name associated with this | 517 | =============== ================================================== |
| 518 | ifname network device interface name associated with this | ||
| 452 | function instance | 519 | function instance |
| 520 | =============== ================================================== | ||
| 453 | 521 | ||
| 454 | Testing the PHONET function | 522 | Testing the PHONET function |
| 455 | --------------------------- | 523 | --------------------------- |
| @@ -464,41 +532,41 @@ These tools are required: | |||
| 464 | 532 | ||
| 465 | git://git.gitorious.org/meego-cellular/phonet-utils.git | 533 | git://git.gitorious.org/meego-cellular/phonet-utils.git |
| 466 | 534 | ||
| 467 | On the host: | 535 | On the host:: |
| 468 | 536 | ||
| 469 | $ ./phonet -a 0x10 -i usbpn0 | 537 | $ ./phonet -a 0x10 -i usbpn0 |
| 470 | $ ./pnroute add 0x6c usbpn0 | 538 | $ ./pnroute add 0x6c usbpn0 |
| 471 | $./pnroute add 0x10 usbpn0 | 539 | $./pnroute add 0x10 usbpn0 |
| 472 | $ ifconfig usbpn0 up | 540 | $ ifconfig usbpn0 up |
| 473 | 541 | ||
| 474 | On the device: | 542 | On the device:: |
| 475 | 543 | ||
| 476 | $ ./phonet -a 0x6c -i upnlink0 | 544 | $ ./phonet -a 0x6c -i upnlink0 |
| 477 | $ ./pnroute add 0x10 upnlink0 | 545 | $ ./pnroute add 0x10 upnlink0 |
| 478 | $ ifconfig upnlink0 up | 546 | $ ifconfig upnlink0 up |
| 479 | 547 | ||
| 480 | Then a test program can be used: | 548 | Then a test program can be used:: |
| 481 | 549 | ||
| 482 | http://www.spinics.net/lists/linux-usb/msg85690.html | 550 | http://www.spinics.net/lists/linux-usb/msg85690.html |
| 483 | 551 | ||
| 484 | On the device: | 552 | On the device:: |
| 485 | 553 | ||
| 486 | $ ./pnxmit -a 0x6c -r | 554 | $ ./pnxmit -a 0x6c -r |
| 487 | 555 | ||
| 488 | On the host: | 556 | On the host:: |
| 489 | 557 | ||
| 490 | $ ./pnxmit -a 0x10 -s 0x6c | 558 | $ ./pnxmit -a 0x10 -s 0x6c |
| 491 | 559 | ||
| 492 | As a result some data should be sent from host to device. | 560 | As a result some data should be sent from host to device. |
| 493 | Then the other way round: | 561 | Then the other way round: |
| 494 | 562 | ||
| 495 | On the host: | 563 | On the host:: |
| 496 | 564 | ||
| 497 | $ ./pnxmit -a 0x10 -r | 565 | $ ./pnxmit -a 0x10 -r |
| 498 | 566 | ||
| 499 | On the device: | 567 | On the device:: |
| 500 | 568 | ||
| 501 | $ ./pnxmit -a 0x6c -s 0x10 | 569 | $ ./pnxmit -a 0x6c -s 0x10 |
| 502 | 570 | ||
| 503 | 13. RNDIS function | 571 | 13. RNDIS function |
| 504 | ================== | 572 | ================== |
| @@ -511,13 +579,15 @@ Function-specific configfs interface | |||
| 511 | The function name to use when creating the function directory is "rndis". | 579 | The function name to use when creating the function directory is "rndis". |
| 512 | The RNDIS function provides these attributes in its function directory: | 580 | The RNDIS function provides these attributes in its function directory: |
| 513 | 581 | ||
| 514 | ifname - network device interface name associated with this | 582 | =============== ================================================== |
| 583 | ifname network device interface name associated with this | ||
| 515 | function instance | 584 | function instance |
| 516 | qmult - queue length multiplier for high and super speed | 585 | qmult queue length multiplier for high and super speed |
| 517 | host_addr - MAC address of host's end of this | 586 | host_addr MAC address of host's end of this |
| 518 | Ethernet over USB link | 587 | Ethernet over USB link |
| 519 | dev_addr - MAC address of device's end of this | 588 | dev_addr MAC address of device's end of this |
| 520 | Ethernet over USB link | 589 | Ethernet over USB link |
| 590 | =============== ================================================== | ||
| 521 | 591 | ||
| 522 | and after creating the functions/rndis.<instance name> they contain default | 592 | and after creating the functions/rndis.<instance name> they contain default |
| 523 | values: qmult is 5, dev_addr and host_addr are randomly selected. | 593 | values: qmult is 5, dev_addr and host_addr are randomly selected. |
| @@ -530,8 +600,13 @@ Testing the RNDIS function | |||
| 530 | 600 | ||
| 531 | Configure IP addresses of the device and the host. Then: | 601 | Configure IP addresses of the device and the host. Then: |
| 532 | 602 | ||
| 533 | On the device: ping <host's IP> | 603 | On the device:: |
| 534 | On the host: ping <device's IP> | 604 | |
| 605 | ping <host's IP> | ||
| 606 | |||
| 607 | On the host:: | ||
| 608 | |||
| 609 | ping <device's IP> | ||
| 535 | 610 | ||
| 536 | 14. SERIAL function | 611 | 14. SERIAL function |
| 537 | =================== | 612 | =================== |
| @@ -553,15 +628,28 @@ There can be at most 4 ACM/generic serial/OBEX ports in the system. | |||
| 553 | Testing the SERIAL function | 628 | Testing the SERIAL function |
| 554 | --------------------------- | 629 | --------------------------- |
| 555 | 630 | ||
| 556 | On host: insmod usbserial | 631 | On host:: |
| 557 | echo VID PID >/sys/bus/usb-serial/drivers/generic/new_id | 632 | |
| 558 | On host: cat > /dev/ttyUSB<X> | 633 | insmod usbserial |
| 559 | On target: cat /dev/ttyGS<Y> | 634 | echo VID PID >/sys/bus/usb-serial/drivers/generic/new_id |
| 635 | |||
| 636 | On host:: | ||
| 637 | |||
| 638 | cat > /dev/ttyUSB<X> | ||
| 639 | |||
| 640 | On target:: | ||
| 641 | |||
| 642 | cat /dev/ttyGS<Y> | ||
| 560 | 643 | ||
| 561 | then the other way round | 644 | then the other way round |
| 562 | 645 | ||
| 563 | On target: cat > /dev/ttyGS<Y> | 646 | On target:: |
| 564 | On host: cat /dev/ttyUSB<X> | 647 | |
| 648 | cat > /dev/ttyGS<Y> | ||
| 649 | |||
| 650 | On host:: | ||
| 651 | |||
| 652 | cat /dev/ttyUSB<X> | ||
| 565 | 653 | ||
| 566 | 15. SOURCESINK function | 654 | 15. SOURCESINK function |
| 567 | ======================= | 655 | ======================= |
| @@ -574,24 +662,27 @@ Function-specific configfs interface | |||
| 574 | The function name to use when creating the function directory is "SourceSink". | 662 | The function name to use when creating the function directory is "SourceSink". |
| 575 | The SOURCESINK function provides these attributes in its function directory: | 663 | The SOURCESINK function provides these attributes in its function directory: |
| 576 | 664 | ||
| 577 | pattern - 0 (all zeros), 1 (mod63), 2 (none) | 665 | =============== ================================== |
| 578 | isoc_interval - 1..16 | 666 | pattern 0 (all zeros), 1 (mod63), 2 (none) |
| 579 | isoc_maxpacket - 0 - 1023 (fs), 0 - 1024 (hs/ss) | 667 | isoc_interval 1..16 |
| 580 | isoc_mult - 0..2 (hs/ss only) | 668 | isoc_maxpacket 0 - 1023 (fs), 0 - 1024 (hs/ss) |
| 581 | isoc_maxburst - 0..15 (ss only) | 669 | isoc_mult 0..2 (hs/ss only) |
| 582 | bulk_buflen - buffer length | 670 | isoc_maxburst 0..15 (ss only) |
| 583 | bulk_qlen - depth of queue for bulk | 671 | bulk_buflen buffer length |
| 584 | iso_qlen - depth of queue for iso | 672 | bulk_qlen depth of queue for bulk |
| 673 | iso_qlen depth of queue for iso | ||
| 674 | =============== ================================== | ||
| 585 | 675 | ||
| 586 | Testing the SOURCESINK function | 676 | Testing the SOURCESINK function |
| 587 | ------------------------------- | 677 | ------------------------------- |
| 588 | 678 | ||
| 589 | device: run the gadget | 679 | device: run the gadget |
| 680 | |||
| 590 | host: test-usb (tools/usb/testusb.c) | 681 | host: test-usb (tools/usb/testusb.c) |
| 591 | 682 | ||
| 592 | 683 | ||
| 593 | 16. UAC1 function (legacy implementation) | 684 | 16. UAC1 function (legacy implementation) |
| 594 | ================= | 685 | ========================================= |
| 595 | 686 | ||
| 596 | The function is provided by usb_f_uac1_legacy.ko module. | 687 | The function is provided by usb_f_uac1_legacy.ko module. |
| 597 | 688 | ||
| @@ -602,12 +693,14 @@ The function name to use when creating the function directory | |||
| 602 | is "uac1_legacy". | 693 | is "uac1_legacy". |
| 603 | The uac1 function provides these attributes in its function directory: | 694 | The uac1 function provides these attributes in its function directory: |
| 604 | 695 | ||
| 605 | audio_buf_size - audio buffer size | 696 | =============== ==================================== |
| 606 | fn_cap - capture pcm device file name | 697 | audio_buf_size audio buffer size |
| 607 | fn_cntl - control device file name | 698 | fn_cap capture pcm device file name |
| 608 | fn_play - playback pcm device file name | 699 | fn_cntl control device file name |
| 609 | req_buf_size - ISO OUT endpoint request buffer size | 700 | fn_play playback pcm device file name |
| 610 | req_count - ISO OUT endpoint request count | 701 | req_buf_size ISO OUT endpoint request buffer size |
| 702 | req_count ISO OUT endpoint request count | ||
| 703 | =============== ==================================== | ||
| 611 | 704 | ||
| 612 | The attributes have sane default values. | 705 | The attributes have sane default values. |
| 613 | 706 | ||
| @@ -615,7 +708,10 @@ Testing the UAC1 function | |||
| 615 | ------------------------- | 708 | ------------------------- |
| 616 | 709 | ||
| 617 | device: run the gadget | 710 | device: run the gadget |
| 618 | host: aplay -l # should list our USB Audio Gadget | 711 | |
| 712 | host:: | ||
| 713 | |||
| 714 | aplay -l # should list our USB Audio Gadget | ||
| 619 | 715 | ||
| 620 | 17. UAC2 function | 716 | 17. UAC2 function |
| 621 | ================= | 717 | ================= |
| @@ -628,14 +724,16 @@ Function-specific configfs interface | |||
| 628 | The function name to use when creating the function directory is "uac2". | 724 | The function name to use when creating the function directory is "uac2". |
| 629 | The uac2 function provides these attributes in its function directory: | 725 | The uac2 function provides these attributes in its function directory: |
| 630 | 726 | ||
| 631 | c_chmask - capture channel mask | 727 | =============== ==================================================== |
| 632 | c_srate - capture sampling rate | 728 | c_chmask capture channel mask |
| 633 | c_ssize - capture sample size (bytes) | 729 | c_srate capture sampling rate |
| 634 | p_chmask - playback channel mask | 730 | c_ssize capture sample size (bytes) |
| 635 | p_srate - playback sampling rate | 731 | p_chmask playback channel mask |
| 636 | p_ssize - playback sample size (bytes) | 732 | p_srate playback sampling rate |
| 637 | req_number - the number of pre-allocated request for both capture | 733 | p_ssize playback sample size (bytes) |
| 638 | and playback | 734 | req_number the number of pre-allocated request for both capture |
| 735 | and playback | ||
| 736 | =============== ==================================================== | ||
| 639 | 737 | ||
| 640 | The attributes have sane default values. | 738 | The attributes have sane default values. |
| 641 | 739 | ||
| @@ -648,14 +746,14 @@ host: aplay -l # should list our USB Audio Gadget | |||
| 648 | This function does not require real hardware support, it just | 746 | This function does not require real hardware support, it just |
| 649 | sends a stream of audio data to/from the host. In order to | 747 | sends a stream of audio data to/from the host. In order to |
| 650 | actually hear something at the device side, a command similar | 748 | actually hear something at the device side, a command similar |
| 651 | to this must be used at the device side: | 749 | to this must be used at the device side:: |
| 652 | 750 | ||
| 653 | $ arecord -f dat -t wav -D hw:2,0 | aplay -D hw:0,0 & | 751 | $ arecord -f dat -t wav -D hw:2,0 | aplay -D hw:0,0 & |
| 654 | 752 | ||
| 655 | e.g.: | 753 | e.g.:: |
| 656 | 754 | ||
| 657 | $ arecord -f dat -t wav -D hw:CARD=UAC2Gadget,DEV=0 | \ | 755 | $ arecord -f dat -t wav -D hw:CARD=UAC2Gadget,DEV=0 | \ |
| 658 | aplay -D default:CARD=OdroidU3 | 756 | aplay -D default:CARD=OdroidU3 |
| 659 | 757 | ||
| 660 | 18. UVC function | 758 | 18. UVC function |
| 661 | ================ | 759 | ================ |
| @@ -668,66 +766,73 @@ Function-specific configfs interface | |||
| 668 | The function name to use when creating the function directory is "uvc". | 766 | The function name to use when creating the function directory is "uvc". |
| 669 | The uvc function provides these attributes in its function directory: | 767 | The uvc function provides these attributes in its function directory: |
| 670 | 768 | ||
| 671 | streaming_interval - interval for polling endpoint for data transfers | 769 | =================== ================================================ |
| 672 | streaming_maxburst - bMaxBurst for super speed companion descriptor | 770 | streaming_interval interval for polling endpoint for data transfers |
| 673 | streaming_maxpacket - maximum packet size this endpoint is capable of | 771 | streaming_maxburst bMaxBurst for super speed companion descriptor |
| 674 | sending or receiving when this configuration is | 772 | streaming_maxpacket maximum packet size this endpoint is capable of |
| 675 | selected | 773 | sending or receiving when this configuration is |
| 774 | selected | ||
| 775 | =================== ================================================ | ||
| 676 | 776 | ||
| 677 | There are also "control" and "streaming" subdirectories, each of which contain | 777 | There are also "control" and "streaming" subdirectories, each of which contain |
| 678 | a number of their subdirectories. There are some sane defaults provided, but | 778 | a number of their subdirectories. There are some sane defaults provided, but |
| 679 | the user must provide the following: | 779 | the user must provide the following: |
| 680 | 780 | ||
| 681 | control header - create in control/header, link from control/class/fs | 781 | ================== ==================================================== |
| 682 | and/or control/class/ss | 782 | control header create in control/header, link from control/class/fs |
| 683 | streaming header - create in streaming/header, link from | 783 | and/or control/class/ss |
| 684 | streaming/class/fs and/or streaming/class/hs and/or | 784 | streaming header create in streaming/header, link from |
| 685 | streaming/class/ss | 785 | streaming/class/fs and/or streaming/class/hs and/or |
| 686 | format description - create in streaming/mjpeg and/or | 786 | streaming/class/ss |
| 687 | streaming/uncompressed | 787 | format description create in streaming/mjpeg and/or |
| 688 | frame description - create in streaming/mjpeg/<format> and/or in | 788 | streaming/uncompressed |
| 689 | streaming/uncompressed/<format> | 789 | frame description create in streaming/mjpeg/<format> and/or in |
| 790 | streaming/uncompressed/<format> | ||
| 791 | ================== ==================================================== | ||
| 690 | 792 | ||
| 691 | Each frame description contains frame interval specification, and each | 793 | Each frame description contains frame interval specification, and each |
| 692 | such specification consists of a number of lines with an inverval value | 794 | such specification consists of a number of lines with an inverval value |
| 693 | in each line. The rules stated above are best illustrated with an example: | 795 | in each line. The rules stated above are best illustrated with an example:: |
| 694 | 796 | ||
| 695 | # mkdir functions/uvc.usb0/control/header/h | 797 | # mkdir functions/uvc.usb0/control/header/h |
| 696 | # cd functions/uvc.usb0/control/ | 798 | # cd functions/uvc.usb0/control/ |
| 697 | # ln -s header/h class/fs | 799 | # ln -s header/h class/fs |
| 698 | # ln -s header/h class/ss | 800 | # ln -s header/h class/ss |
| 699 | # mkdir -p functions/uvc.usb0/streaming/uncompressed/u/360p | 801 | # mkdir -p functions/uvc.usb0/streaming/uncompressed/u/360p |
| 700 | # cat <<EOF > functions/uvc.usb0/streaming/uncompressed/u/360p/dwFrameInterval | 802 | # cat <<EOF > functions/uvc.usb0/streaming/uncompressed/u/360p/dwFrameInterval |
| 701 | 666666 | 803 | 666666 |
| 702 | 1000000 | 804 | 1000000 |
| 703 | 5000000 | 805 | 5000000 |
| 704 | EOF | 806 | EOF |
| 705 | # cd $GADGET_CONFIGFS_ROOT | 807 | # cd $GADGET_CONFIGFS_ROOT |
| 706 | # mkdir functions/uvc.usb0/streaming/header/h | 808 | # mkdir functions/uvc.usb0/streaming/header/h |
| 707 | # cd functions/uvc.usb0/streaming/header/h | 809 | # cd functions/uvc.usb0/streaming/header/h |
| 708 | # ln -s ../../uncompressed/u | 810 | # ln -s ../../uncompressed/u |
| 709 | # cd ../../class/fs | 811 | # cd ../../class/fs |
| 710 | # ln -s ../../header/h | 812 | # ln -s ../../header/h |
| 711 | # cd ../../class/hs | 813 | # cd ../../class/hs |
| 712 | # ln -s ../../header/h | 814 | # ln -s ../../header/h |
| 713 | # cd ../../class/ss | 815 | # cd ../../class/ss |
| 714 | # ln -s ../../header/h | 816 | # ln -s ../../header/h |
| 715 | 817 | ||
| 716 | 818 | ||
| 717 | Testing the UVC function | 819 | Testing the UVC function |
| 718 | ------------------------ | 820 | ------------------------ |
| 719 | 821 | ||
| 720 | device: run the gadget, modprobe vivid | 822 | device: run the gadget, modprobe vivid:: |
| 721 | 823 | ||
| 722 | # uvc-gadget -u /dev/video<uvc video node #> -v /dev/video<vivid video node #> | 824 | # uvc-gadget -u /dev/video<uvc video node #> -v /dev/video<vivid video node #> |
| 723 | 825 | ||
| 724 | where uvc-gadget is this program: | 826 | where uvc-gadget is this program: |
| 725 | http://git.ideasonboard.org/uvc-gadget.git | 827 | http://git.ideasonboard.org/uvc-gadget.git |
| 726 | 828 | ||
| 727 | with these patches: | 829 | with these patches: |
| 728 | http://www.spinics.net/lists/linux-usb/msg99220.html | ||
| 729 | 830 | ||
| 730 | host: luvcview -f yuv | 831 | http://www.spinics.net/lists/linux-usb/msg99220.html |
| 832 | |||
| 833 | host:: | ||
| 834 | |||
| 835 | luvcview -f yuv | ||
| 731 | 836 | ||
| 732 | 19. PRINTER function | 837 | 19. PRINTER function |
| 733 | ==================== | 838 | ==================== |
| @@ -740,16 +845,19 @@ Function-specific configfs interface | |||
| 740 | The function name to use when creating the function directory is "printer". | 845 | The function name to use when creating the function directory is "printer". |
| 741 | The printer function provides these attributes in its function directory: | 846 | The printer function provides these attributes in its function directory: |
| 742 | 847 | ||
| 743 | pnp_string - Data to be passed to the host in pnp string | 848 | ========== =========================================== |
| 744 | q_len - Number of requests per endpoint | 849 | pnp_string Data to be passed to the host in pnp string |
| 850 | q_len Number of requests per endpoint | ||
| 851 | ========== =========================================== | ||
| 745 | 852 | ||
| 746 | Testing the PRINTER function | 853 | Testing the PRINTER function |
| 747 | ---------------------------- | 854 | ---------------------------- |
| 748 | 855 | ||
| 749 | The most basic testing: | 856 | The most basic testing: |
| 750 | 857 | ||
| 751 | device: run the gadget | 858 | device: run the gadget:: |
| 752 | # ls -l /devices/virtual/usb_printer_gadget/ | 859 | |
| 860 | # ls -l /devices/virtual/usb_printer_gadget/ | ||
| 753 | 861 | ||
| 754 | should show g_printer<number>. | 862 | should show g_printer<number>. |
| 755 | 863 | ||
| @@ -761,23 +869,28 @@ If udev is active, then e.g. /dev/usb/lp0 should appear. | |||
| 761 | 869 | ||
| 762 | host->device transmission: | 870 | host->device transmission: |
| 763 | 871 | ||
| 764 | device: | 872 | device:: |
| 765 | # cat /dev/g_printer<number> | ||
| 766 | host: | ||
| 767 | # cat > /dev/usb/lp0 | ||
| 768 | 873 | ||
| 769 | device->host transmission: | 874 | # cat /dev/g_printer<number> |
| 770 | 875 | ||
| 771 | # cat > /dev/g_printer<number> | 876 | host:: |
| 772 | host: | 877 | |
| 773 | # cat /dev/usb/lp0 | 878 | # cat > /dev/usb/lp0 |
| 879 | |||
| 880 | device->host transmission:: | ||
| 881 | |||
| 882 | # cat > /dev/g_printer<number> | ||
| 883 | |||
| 884 | host:: | ||
| 885 | |||
| 886 | # cat /dev/usb/lp0 | ||
| 774 | 887 | ||
| 775 | More advanced testing can be done with the prn_example | 888 | More advanced testing can be done with the prn_example |
| 776 | described in Documentation/usb/gadget_printer.txt. | 889 | described in Documentation/usb/gadget_printer.txt. |
| 777 | 890 | ||
| 778 | 891 | ||
| 779 | 20. UAC1 function (virtual ALSA card, using u_audio API) | 892 | 20. UAC1 function (virtual ALSA card, using u_audio API) |
| 780 | ================= | 893 | ======================================================== |
| 781 | 894 | ||
| 782 | The function is provided by usb_f_uac1.ko module. | 895 | The function is provided by usb_f_uac1.ko module. |
| 783 | It will create a virtual ALSA card and the audio streams are simply | 896 | It will create a virtual ALSA card and the audio streams are simply |
| @@ -789,14 +902,16 @@ Function-specific configfs interface | |||
| 789 | The function name to use when creating the function directory is "uac1". | 902 | The function name to use when creating the function directory is "uac1". |
| 790 | The uac1 function provides these attributes in its function directory: | 903 | The uac1 function provides these attributes in its function directory: |
| 791 | 904 | ||
| 792 | c_chmask - capture channel mask | 905 | ========== ==================================================== |
| 793 | c_srate - capture sampling rate | 906 | c_chmask capture channel mask |
| 794 | c_ssize - capture sample size (bytes) | 907 | c_srate capture sampling rate |
| 795 | p_chmask - playback channel mask | 908 | c_ssize capture sample size (bytes) |
| 796 | p_srate - playback sampling rate | 909 | p_chmask playback channel mask |
| 797 | p_ssize - playback sample size (bytes) | 910 | p_srate playback sampling rate |
| 798 | req_number - the number of pre-allocated request for both capture | 911 | p_ssize playback sample size (bytes) |
| 799 | and playback | 912 | req_number the number of pre-allocated request for both capture |
| 913 | and playback | ||
| 914 | ========== ==================================================== | ||
| 800 | 915 | ||
| 801 | The attributes have sane default values. | 916 | The attributes have sane default values. |
| 802 | 917 | ||
| @@ -809,11 +924,11 @@ host: aplay -l # should list our USB Audio Gadget | |||
| 809 | This function does not require real hardware support, it just | 924 | This function does not require real hardware support, it just |
| 810 | sends a stream of audio data to/from the host. In order to | 925 | sends a stream of audio data to/from the host. In order to |
| 811 | actually hear something at the device side, a command similar | 926 | actually hear something at the device side, a command similar |
| 812 | to this must be used at the device side: | 927 | to this must be used at the device side:: |
| 813 | 928 | ||
| 814 | $ arecord -f dat -t wav -D hw:2,0 | aplay -D hw:0,0 & | 929 | $ arecord -f dat -t wav -D hw:2,0 | aplay -D hw:0,0 & |
| 815 | 930 | ||
| 816 | e.g.: | 931 | e.g.:: |
| 817 | 932 | ||
| 818 | $ arecord -f dat -t wav -D hw:CARD=UAC1Gadget,DEV=0 | \ | 933 | $ arecord -f dat -t wav -D hw:CARD=UAC1Gadget,DEV=0 | \ |
| 819 | aplay -D default:CARD=OdroidU3 | 934 | aplay -D default:CARD=OdroidU3 |
diff --git a/Documentation/usb/gadget_configfs.txt b/Documentation/usb/gadget_configfs.txt index b8cb38a98c19..54fb08baae22 100644 --- a/Documentation/usb/gadget_configfs.txt +++ b/Documentation/usb/gadget_configfs.txt | |||
| @@ -1,11 +1,9 @@ | |||
| 1 | ============================================ | ||
| 2 | Linux USB gadget configured through configfs | ||
| 3 | ============================================ | ||
| 1 | 4 | ||
| 2 | 5 | ||
| 3 | 6 | 25th April 2013 | |
| 4 | |||
| 5 | Linux USB gadget configured through configfs | ||
| 6 | |||
| 7 | |||
| 8 | 25th April 2013 | ||
| 9 | 7 | ||
| 10 | 8 | ||
| 11 | 9 | ||
| @@ -26,7 +24,7 @@ Linux provides a number of functions for gadgets to use. | |||
| 26 | Creating a gadget means deciding what configurations there will be | 24 | Creating a gadget means deciding what configurations there will be |
| 27 | and which functions each configuration will provide. | 25 | and which functions each configuration will provide. |
| 28 | 26 | ||
| 29 | Configfs (please see Documentation/filesystems/configfs/*) lends itself nicely | 27 | Configfs (please see `Documentation/filesystems/configfs/*`) lends itself nicely |
| 30 | for the purpose of telling the kernel about the above mentioned decision. | 28 | for the purpose of telling the kernel about the above mentioned decision. |
| 31 | This document is about how to do it. | 29 | This document is about how to do it. |
| 32 | 30 | ||
| @@ -51,44 +49,46 @@ Usage | |||
| 51 | made available through configfs can be seen here: | 49 | made available through configfs can be seen here: |
| 52 | http://www.spinics.net/lists/linux-usb/msg76388.html) | 50 | http://www.spinics.net/lists/linux-usb/msg76388.html) |
| 53 | 51 | ||
| 54 | $ modprobe libcomposite | 52 | :: |
| 55 | $ mount none $CONFIGFS_HOME -t configfs | 53 | |
| 54 | $ modprobe libcomposite | ||
| 55 | $ mount none $CONFIGFS_HOME -t configfs | ||
| 56 | 56 | ||
| 57 | where CONFIGFS_HOME is the mount point for configfs | 57 | where CONFIGFS_HOME is the mount point for configfs |
| 58 | 58 | ||
| 59 | 1. Creating the gadgets | 59 | 1. Creating the gadgets |
| 60 | ----------------------- | 60 | ----------------------- |
| 61 | 61 | ||
| 62 | For each gadget to be created its corresponding directory must be created: | 62 | For each gadget to be created its corresponding directory must be created:: |
| 63 | 63 | ||
| 64 | $ mkdir $CONFIGFS_HOME/usb_gadget/<gadget name> | 64 | $ mkdir $CONFIGFS_HOME/usb_gadget/<gadget name> |
| 65 | 65 | ||
| 66 | e.g.: | 66 | e.g.:: |
| 67 | 67 | ||
| 68 | $ mkdir $CONFIGFS_HOME/usb_gadget/g1 | 68 | $ mkdir $CONFIGFS_HOME/usb_gadget/g1 |
| 69 | 69 | ||
| 70 | ... | 70 | ... |
| 71 | ... | 71 | ... |
| 72 | ... | 72 | ... |
| 73 | 73 | ||
| 74 | $ cd $CONFIGFS_HOME/usb_gadget/g1 | 74 | $ cd $CONFIGFS_HOME/usb_gadget/g1 |
| 75 | 75 | ||
| 76 | Each gadget needs to have its vendor id <VID> and product id <PID> specified: | 76 | Each gadget needs to have its vendor id <VID> and product id <PID> specified:: |
| 77 | 77 | ||
| 78 | $ echo <VID> > idVendor | 78 | $ echo <VID> > idVendor |
| 79 | $ echo <PID> > idProduct | 79 | $ echo <PID> > idProduct |
| 80 | 80 | ||
| 81 | A gadget also needs its serial number, manufacturer and product strings. | 81 | A gadget also needs its serial number, manufacturer and product strings. |
| 82 | In order to have a place to store them, a strings subdirectory must be created | 82 | In order to have a place to store them, a strings subdirectory must be created |
| 83 | for each language, e.g.: | 83 | for each language, e.g.:: |
| 84 | 84 | ||
| 85 | $ mkdir strings/0x409 | 85 | $ mkdir strings/0x409 |
| 86 | 86 | ||
| 87 | Then the strings can be specified: | 87 | Then the strings can be specified:: |
| 88 | 88 | ||
| 89 | $ echo <serial number> > strings/0x409/serialnumber | 89 | $ echo <serial number> > strings/0x409/serialnumber |
| 90 | $ echo <manufacturer> > strings/0x409/manufacturer | 90 | $ echo <manufacturer> > strings/0x409/manufacturer |
| 91 | $ echo <product> > strings/0x409/product | 91 | $ echo <product> > strings/0x409/product |
| 92 | 92 | ||
| 93 | 2. Creating the configurations | 93 | 2. Creating the configurations |
| 94 | ------------------------------ | 94 | ------------------------------ |
| @@ -99,43 +99,43 @@ directories must be created: | |||
| 99 | $ mkdir configs/<name>.<number> | 99 | $ mkdir configs/<name>.<number> |
| 100 | 100 | ||
| 101 | where <name> can be any string which is legal in a filesystem and the | 101 | where <name> can be any string which is legal in a filesystem and the |
| 102 | <number> is the configuration's number, e.g.: | 102 | <number> is the configuration's number, e.g.:: |
| 103 | 103 | ||
| 104 | $ mkdir configs/c.1 | 104 | $ mkdir configs/c.1 |
| 105 | 105 | ||
| 106 | ... | 106 | ... |
| 107 | ... | 107 | ... |
| 108 | ... | 108 | ... |
| 109 | 109 | ||
| 110 | Each configuration also needs its strings, so a subdirectory must be created | 110 | Each configuration also needs its strings, so a subdirectory must be created |
| 111 | for each language, e.g.: | 111 | for each language, e.g.:: |
| 112 | 112 | ||
| 113 | $ mkdir configs/c.1/strings/0x409 | 113 | $ mkdir configs/c.1/strings/0x409 |
| 114 | 114 | ||
| 115 | Then the configuration string can be specified: | 115 | Then the configuration string can be specified:: |
| 116 | 116 | ||
| 117 | $ echo <configuration> > configs/c.1/strings/0x409/configuration | 117 | $ echo <configuration> > configs/c.1/strings/0x409/configuration |
| 118 | 118 | ||
| 119 | Some attributes can also be set for a configuration, e.g.: | 119 | Some attributes can also be set for a configuration, e.g.:: |
| 120 | 120 | ||
| 121 | $ echo 120 > configs/c.1/MaxPower | 121 | $ echo 120 > configs/c.1/MaxPower |
| 122 | 122 | ||
| 123 | 3. Creating the functions | 123 | 3. Creating the functions |
| 124 | ------------------------- | 124 | ------------------------- |
| 125 | 125 | ||
| 126 | The gadget will provide some functions, for each function its corresponding | 126 | The gadget will provide some functions, for each function its corresponding |
| 127 | directory must be created: | 127 | directory must be created:: |
| 128 | 128 | ||
| 129 | $ mkdir functions/<name>.<instance name> | 129 | $ mkdir functions/<name>.<instance name> |
| 130 | 130 | ||
| 131 | where <name> corresponds to one of allowed function names and instance name | 131 | where <name> corresponds to one of allowed function names and instance name |
| 132 | is an arbitrary string allowed in a filesystem, e.g.: | 132 | is an arbitrary string allowed in a filesystem, e.g.:: |
| 133 | 133 | ||
| 134 | $ mkdir functions/ncm.usb0 # usb_f_ncm.ko gets loaded with request_module() | 134 | $ mkdir functions/ncm.usb0 # usb_f_ncm.ko gets loaded with request_module() |
| 135 | 135 | ||
| 136 | ... | 136 | ... |
| 137 | ... | 137 | ... |
| 138 | ... | 138 | ... |
| 139 | 139 | ||
| 140 | Each function provides its specific set of attributes, with either read-only | 140 | Each function provides its specific set of attributes, with either read-only |
| 141 | or read-write access. Where applicable they need to be written to as | 141 | or read-write access. Where applicable they need to be written to as |
| @@ -149,17 +149,17 @@ At this moment a number of gadgets is created, each of which has a number of | |||
| 149 | configurations specified and a number of functions available. What remains | 149 | configurations specified and a number of functions available. What remains |
| 150 | is specifying which function is available in which configuration (the same | 150 | is specifying which function is available in which configuration (the same |
| 151 | function can be used in multiple configurations). This is achieved with | 151 | function can be used in multiple configurations). This is achieved with |
| 152 | creating symbolic links: | 152 | creating symbolic links:: |
| 153 | 153 | ||
| 154 | $ ln -s functions/<name>.<instance name> configs/<name>.<number> | 154 | $ ln -s functions/<name>.<instance name> configs/<name>.<number> |
| 155 | 155 | ||
| 156 | e.g.: | 156 | e.g.:: |
| 157 | 157 | ||
| 158 | $ ln -s functions/ncm.usb0 configs/c.1 | 158 | $ ln -s functions/ncm.usb0 configs/c.1 |
| 159 | 159 | ||
| 160 | ... | 160 | ... |
| 161 | ... | 161 | ... |
| 162 | ... | 162 | ... |
| 163 | 163 | ||
| 164 | 5. Enabling the gadget | 164 | 5. Enabling the gadget |
| 165 | ---------------------- | 165 | ---------------------- |
| @@ -167,123 +167,127 @@ $ ln -s functions/ncm.usb0 configs/c.1 | |||
| 167 | All the above steps serve the purpose of composing the gadget of | 167 | All the above steps serve the purpose of composing the gadget of |
| 168 | configurations and functions. | 168 | configurations and functions. |
| 169 | 169 | ||
| 170 | An example directory structure might look like this: | 170 | An example directory structure might look like this:: |
| 171 | 171 | ||
| 172 | . | 172 | . |
| 173 | ./strings | 173 | ./strings |
| 174 | ./strings/0x409 | 174 | ./strings/0x409 |
| 175 | ./strings/0x409/serialnumber | 175 | ./strings/0x409/serialnumber |
| 176 | ./strings/0x409/product | 176 | ./strings/0x409/product |
| 177 | ./strings/0x409/manufacturer | 177 | ./strings/0x409/manufacturer |
| 178 | ./configs | 178 | ./configs |
| 179 | ./configs/c.1 | 179 | ./configs/c.1 |
| 180 | ./configs/c.1/ncm.usb0 -> ../../../../usb_gadget/g1/functions/ncm.usb0 | 180 | ./configs/c.1/ncm.usb0 -> ../../../../usb_gadget/g1/functions/ncm.usb0 |
| 181 | ./configs/c.1/strings | 181 | ./configs/c.1/strings |
| 182 | ./configs/c.1/strings/0x409 | 182 | ./configs/c.1/strings/0x409 |
| 183 | ./configs/c.1/strings/0x409/configuration | 183 | ./configs/c.1/strings/0x409/configuration |
| 184 | ./configs/c.1/bmAttributes | 184 | ./configs/c.1/bmAttributes |
| 185 | ./configs/c.1/MaxPower | 185 | ./configs/c.1/MaxPower |
| 186 | ./functions | 186 | ./functions |
| 187 | ./functions/ncm.usb0 | 187 | ./functions/ncm.usb0 |
| 188 | ./functions/ncm.usb0/ifname | 188 | ./functions/ncm.usb0/ifname |
| 189 | ./functions/ncm.usb0/qmult | 189 | ./functions/ncm.usb0/qmult |
| 190 | ./functions/ncm.usb0/host_addr | 190 | ./functions/ncm.usb0/host_addr |
| 191 | ./functions/ncm.usb0/dev_addr | 191 | ./functions/ncm.usb0/dev_addr |
| 192 | ./UDC | 192 | ./UDC |
| 193 | ./bcdUSB | 193 | ./bcdUSB |
| 194 | ./bcdDevice | 194 | ./bcdDevice |
| 195 | ./idProduct | 195 | ./idProduct |
| 196 | ./idVendor | 196 | ./idVendor |
| 197 | ./bMaxPacketSize0 | 197 | ./bMaxPacketSize0 |
| 198 | ./bDeviceProtocol | 198 | ./bDeviceProtocol |
| 199 | ./bDeviceSubClass | 199 | ./bDeviceSubClass |
| 200 | ./bDeviceClass | 200 | ./bDeviceClass |
| 201 | 201 | ||
| 202 | 202 | ||
| 203 | Such a gadget must be finally enabled so that the USB host can enumerate it. | 203 | Such a gadget must be finally enabled so that the USB host can enumerate it. |
| 204 | In order to enable the gadget it must be bound to a UDC (USB Device Controller). | ||
| 205 | 204 | ||
| 206 | $ echo <udc name> > UDC | 205 | In order to enable the gadget it must be bound to a UDC (USB Device |
| 206 | Controller):: | ||
| 207 | |||
| 208 | $ echo <udc name> > UDC | ||
| 207 | 209 | ||
| 208 | where <udc name> is one of those found in /sys/class/udc/* | 210 | where <udc name> is one of those found in /sys/class/udc/* |
| 209 | e.g.: | 211 | e.g.:: |
| 210 | 212 | ||
| 211 | $ echo s3c-hsotg > UDC | 213 | $ echo s3c-hsotg > UDC |
| 212 | 214 | ||
| 213 | 215 | ||
| 214 | 6. Disabling the gadget | 216 | 6. Disabling the gadget |
| 215 | ----------------------- | 217 | ----------------------- |
| 216 | 218 | ||
| 217 | $ echo "" > UDC | 219 | :: |
| 220 | |||
| 221 | $ echo "" > UDC | ||
| 218 | 222 | ||
| 219 | 7. Cleaning up | 223 | 7. Cleaning up |
| 220 | -------------- | 224 | -------------- |
| 221 | 225 | ||
| 222 | Remove functions from configurations: | 226 | Remove functions from configurations:: |
| 223 | 227 | ||
| 224 | $ rm configs/<config name>.<number>/<function> | 228 | $ rm configs/<config name>.<number>/<function> |
| 225 | 229 | ||
| 226 | where <config name>.<number> specify the configuration and <function> is | 230 | where <config name>.<number> specify the configuration and <function> is |
| 227 | a symlink to a function being removed from the configuration, e.g.: | 231 | a symlink to a function being removed from the configuration, e.g.:: |
| 228 | 232 | ||
| 229 | $ rm configs/c.1/ncm.usb0 | 233 | $ rm configs/c.1/ncm.usb0 |
| 230 | 234 | ||
| 231 | ... | 235 | ... |
| 232 | ... | 236 | ... |
| 233 | ... | 237 | ... |
| 234 | 238 | ||
| 235 | Remove strings directories in configurations | 239 | Remove strings directories in configurations: |
| 236 | 240 | ||
| 237 | $ rmdir configs/<config name>.<number>/strings/<lang> | 241 | $ rmdir configs/<config name>.<number>/strings/<lang> |
| 238 | 242 | ||
| 239 | e.g.: | 243 | e.g.:: |
| 240 | 244 | ||
| 241 | $ rmdir configs/c.1/strings/0x409 | 245 | $ rmdir configs/c.1/strings/0x409 |
| 242 | 246 | ||
| 243 | ... | 247 | ... |
| 244 | ... | 248 | ... |
| 245 | ... | 249 | ... |
| 246 | 250 | ||
| 247 | and remove the configurations | 251 | and remove the configurations:: |
| 248 | 252 | ||
| 249 | $ rmdir configs/<config name>.<number> | 253 | $ rmdir configs/<config name>.<number> |
| 250 | 254 | ||
| 251 | e.g.: | 255 | e.g.:: |
| 252 | 256 | ||
| 253 | rmdir configs/c.1 | 257 | rmdir configs/c.1 |
| 254 | 258 | ||
| 255 | ... | 259 | ... |
| 256 | ... | 260 | ... |
| 257 | ... | 261 | ... |
| 258 | 262 | ||
| 259 | Remove functions (function modules are not unloaded, though) | 263 | Remove functions (function modules are not unloaded, though): |
| 260 | 264 | ||
| 261 | $ rmdir functions/<name>.<instance name> | 265 | $ rmdir functions/<name>.<instance name> |
| 262 | 266 | ||
| 263 | e.g.: | 267 | e.g.:: |
| 264 | 268 | ||
| 265 | $ rmdir functions/ncm.usb0 | 269 | $ rmdir functions/ncm.usb0 |
| 266 | 270 | ||
| 267 | ... | 271 | ... |
| 268 | ... | 272 | ... |
| 269 | ... | 273 | ... |
| 270 | 274 | ||
| 271 | Remove strings directories in the gadget | 275 | Remove strings directories in the gadget:: |
| 272 | 276 | ||
| 273 | $ rmdir strings/<lang> | 277 | $ rmdir strings/<lang> |
| 274 | 278 | ||
| 275 | e.g.: | 279 | e.g.:: |
| 276 | 280 | ||
| 277 | $ rmdir strings/0x409 | 281 | $ rmdir strings/0x409 |
| 278 | 282 | ||
| 279 | and finally remove the gadget: | 283 | and finally remove the gadget:: |
| 280 | 284 | ||
| 281 | $ cd .. | 285 | $ cd .. |
| 282 | $ rmdir <gadget name> | 286 | $ rmdir <gadget name> |
| 283 | 287 | ||
| 284 | e.g.: | 288 | e.g.:: |
| 285 | 289 | ||
| 286 | $ rmdir g1 | 290 | $ rmdir g1 |
| 287 | 291 | ||
| 288 | 292 | ||
| 289 | 293 | ||
| @@ -305,16 +309,16 @@ configured elements. However, they are embedded in usage-specific | |||
| 305 | larger structures. In the picture below there is a "cs" which contains | 309 | larger structures. In the picture below there is a "cs" which contains |
| 306 | a config_item and an "sa" which contains a configfs_attribute. | 310 | a config_item and an "sa" which contains a configfs_attribute. |
| 307 | 311 | ||
| 308 | The filesystem view would be like this: | 312 | The filesystem view would be like this:: |
| 309 | 313 | ||
| 310 | ./ | 314 | ./ |
| 311 | ./cs (directory) | 315 | ./cs (directory) |
| 312 | | | 316 | | |
| 313 | +--sa (file) | 317 | +--sa (file) |
| 314 | | | 318 | | |
| 315 | . | 319 | . |
| 316 | . | 320 | . |
| 317 | . | 321 | . |
| 318 | 322 | ||
| 319 | Whenever a user reads/writes the "sa" file, a function is called | 323 | Whenever a user reads/writes the "sa" file, a function is called |
| 320 | which accepts a struct config_item and a struct configfs_attribute. | 324 | which accepts a struct config_item and a struct configfs_attribute. |
| @@ -326,29 +330,31 @@ buffer), while the "store" is for modifying the file's contents (copy data | |||
| 326 | from the buffer to the cs), but it is up to the implementer of the | 330 | from the buffer to the cs), but it is up to the implementer of the |
| 327 | two functions to decide what they actually do. | 331 | two functions to decide what they actually do. |
| 328 | 332 | ||
| 329 | typedef struct configured_structure cs; | 333 | :: |
| 330 | typedef struct specific_attribute sa; | 334 | |
| 331 | 335 | typedef struct configured_structure cs; | |
| 332 | sa | 336 | typedef struct specific_attribute sa; |
| 333 | +----------------------------------+ | 337 | |
| 334 | cs | (*show)(cs *, buffer); | | 338 | sa |
| 335 | +-----------------+ | (*store)(cs *, buffer, length); | | 339 | +----------------------------------+ |
| 336 | | | | | | 340 | cs | (*show)(cs *, buffer); | |
| 337 | | +-------------+ | | +------------------+ | | 341 | +-----------------+ | (*store)(cs *, buffer, length); | |
| 338 | | | struct |-|----|------>|struct | | | 342 | | | | | |
| 339 | | | config_item | | | |configfs_attribute| | | 343 | | +-------------+ | | +------------------+ | |
| 340 | | +-------------+ | | +------------------+ | | 344 | | | struct |-|----|------>|struct | | |
| 341 | | | +----------------------------------+ | 345 | | | config_item | | | |configfs_attribute| | |
| 342 | | data to be set | . | 346 | | +-------------+ | | +------------------+ | |
| 343 | | | . | 347 | | | +----------------------------------+ |
| 344 | +-----------------+ . | 348 | | data to be set | . |
| 349 | | | . | ||
| 350 | +-----------------+ . | ||
| 345 | 351 | ||
| 346 | The file names are decided by the config item/group designer, while | 352 | The file names are decided by the config item/group designer, while |
| 347 | the directories in general can be named at will. A group can have | 353 | the directories in general can be named at will. A group can have |
| 348 | a number of its default sub-groups created automatically. | 354 | a number of its default sub-groups created automatically. |
| 349 | 355 | ||
| 350 | For more information on configfs please see | 356 | For more information on configfs please see |
| 351 | Documentation/filesystems/configfs/*. | 357 | `Documentation/filesystems/configfs/*`. |
| 352 | 358 | ||
| 353 | The concepts described above translate to USB gadgets like this: | 359 | The concepts described above translate to USB gadgets like this: |
| 354 | 360 | ||
diff --git a/Documentation/usb/gadget_hid.txt b/Documentation/usb/gadget_hid.txt index 7a0fb8e16e27..098d563040cc 100644 --- a/Documentation/usb/gadget_hid.txt +++ b/Documentation/usb/gadget_hid.txt | |||
| @@ -1,28 +1,31 @@ | |||
| 1 | 1 | =========================== | |
| 2 | Linux USB HID gadget driver | 2 | Linux USB HID gadget driver |
| 3 | =========================== | ||
| 3 | 4 | ||
| 4 | Introduction | 5 | Introduction |
| 6 | ============ | ||
| 5 | 7 | ||
| 6 | The HID Gadget driver provides emulation of USB Human Interface | 8 | The HID Gadget driver provides emulation of USB Human Interface |
| 7 | Devices (HID). The basic HID handling is done in the kernel, | 9 | Devices (HID). The basic HID handling is done in the kernel, |
| 8 | and HID reports can be sent/received through I/O on the | 10 | and HID reports can be sent/received through I/O on the |
| 9 | /dev/hidgX character devices. | 11 | /dev/hidgX character devices. |
| 10 | 12 | ||
| 11 | For more details about HID, see the developer page on | 13 | For more details about HID, see the developer page on |
| 12 | http://www.usb.org/developers/hidpage/ | 14 | http://www.usb.org/developers/hidpage/ |
| 13 | 15 | ||
| 14 | Configuration | 16 | Configuration |
| 17 | ============= | ||
| 15 | 18 | ||
| 16 | g_hid is a platform driver, so to use it you need to add | 19 | g_hid is a platform driver, so to use it you need to add |
| 17 | struct platform_device(s) to your platform code defining the | 20 | struct platform_device(s) to your platform code defining the |
| 18 | HID function descriptors you want to use - E.G. something | 21 | HID function descriptors you want to use - E.G. something |
| 19 | like: | 22 | like:: |
| 20 | 23 | ||
| 21 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
| 22 | #include <linux/usb/g_hid.h> | 25 | #include <linux/usb/g_hid.h> |
| 23 | 26 | ||
| 24 | /* hid descriptor for a keyboard */ | 27 | /* hid descriptor for a keyboard */ |
| 25 | static struct hidg_func_descriptor my_hid_data = { | 28 | static struct hidg_func_descriptor my_hid_data = { |
| 26 | .subclass = 0, /* No subclass */ | 29 | .subclass = 0, /* No subclass */ |
| 27 | .protocol = 1, /* Keyboard */ | 30 | .protocol = 1, /* Keyboard */ |
| 28 | .report_length = 8, | 31 | .report_length = 8, |
| @@ -61,85 +64,87 @@ static struct hidg_func_descriptor my_hid_data = { | |||
| 61 | 0x81, 0x00, /* INPUT (Data,Ary,Abs) */ | 64 | 0x81, 0x00, /* INPUT (Data,Ary,Abs) */ |
| 62 | 0xc0 /* END_COLLECTION */ | 65 | 0xc0 /* END_COLLECTION */ |
| 63 | } | 66 | } |
| 64 | }; | 67 | }; |
| 65 | 68 | ||
| 66 | static struct platform_device my_hid = { | 69 | static struct platform_device my_hid = { |
| 67 | .name = "hidg", | 70 | .name = "hidg", |
| 68 | .id = 0, | 71 | .id = 0, |
| 69 | .num_resources = 0, | 72 | .num_resources = 0, |
| 70 | .resource = 0, | 73 | .resource = 0, |
| 71 | .dev.platform_data = &my_hid_data, | 74 | .dev.platform_data = &my_hid_data, |
| 72 | }; | 75 | }; |
| 73 | 76 | ||
| 74 | You can add as many HID functions as you want, only limited by | 77 | You can add as many HID functions as you want, only limited by |
| 75 | the amount of interrupt endpoints your gadget driver supports. | 78 | the amount of interrupt endpoints your gadget driver supports. |
| 76 | 79 | ||
| 77 | Configuration with configfs | 80 | Configuration with configfs |
| 81 | =========================== | ||
| 78 | 82 | ||
| 79 | Instead of adding fake platform devices and drivers in order to pass | 83 | Instead of adding fake platform devices and drivers in order to pass |
| 80 | some data to the kernel, if HID is a part of a gadget composed with | 84 | some data to the kernel, if HID is a part of a gadget composed with |
| 81 | configfs the hidg_func_descriptor.report_desc is passed to the kernel | 85 | configfs the hidg_func_descriptor.report_desc is passed to the kernel |
| 82 | by writing the appropriate stream of bytes to a configfs attribute. | 86 | by writing the appropriate stream of bytes to a configfs attribute. |
| 83 | 87 | ||
| 84 | Send and receive HID reports | 88 | Send and receive HID reports |
| 89 | ============================ | ||
| 85 | 90 | ||
| 86 | HID reports can be sent/received using read/write on the | 91 | HID reports can be sent/received using read/write on the |
| 87 | /dev/hidgX character devices. See below for an example program | 92 | /dev/hidgX character devices. See below for an example program |
| 88 | to do this. | 93 | to do this. |
| 89 | 94 | ||
| 90 | hid_gadget_test is a small interactive program to test the HID | 95 | hid_gadget_test is a small interactive program to test the HID |
| 91 | gadget driver. To use, point it at a hidg device and set the | 96 | gadget driver. To use, point it at a hidg device and set the |
| 92 | device type (keyboard / mouse / joystick) - E.G.: | 97 | device type (keyboard / mouse / joystick) - E.G.:: |
| 93 | 98 | ||
| 94 | # hid_gadget_test /dev/hidg0 keyboard | 99 | # hid_gadget_test /dev/hidg0 keyboard |
| 95 | 100 | ||
| 96 | You are now in the prompt of hid_gadget_test. You can type any | 101 | You are now in the prompt of hid_gadget_test. You can type any |
| 97 | combination of options and values. Available options and | 102 | combination of options and values. Available options and |
| 98 | values are listed at program start. In keyboard mode you can | 103 | values are listed at program start. In keyboard mode you can |
| 99 | send up to six values. | 104 | send up to six values. |
| 100 | 105 | ||
| 101 | For example type: g i s t r --left-shift | 106 | For example type: g i s t r --left-shift |
| 102 | 107 | ||
| 103 | Hit return and the corresponding report will be sent by the | 108 | Hit return and the corresponding report will be sent by the |
| 104 | HID gadget. | 109 | HID gadget. |
| 105 | 110 | ||
| 106 | Another interesting example is the caps lock test. Type | 111 | Another interesting example is the caps lock test. Type |
| 107 | --caps-lock and hit return. A report is then sent by the | 112 | --caps-lock and hit return. A report is then sent by the |
| 108 | gadget and you should receive the host answer, corresponding | 113 | gadget and you should receive the host answer, corresponding |
| 109 | to the caps lock LED status. | 114 | to the caps lock LED status:: |
| 110 | 115 | ||
| 111 | --caps-lock | 116 | --caps-lock |
| 112 | recv report:2 | 117 | recv report:2 |
| 113 | 118 | ||
| 114 | With this command: | 119 | With this command:: |
| 115 | 120 | ||
| 116 | # hid_gadget_test /dev/hidg1 mouse | 121 | # hid_gadget_test /dev/hidg1 mouse |
| 117 | 122 | ||
| 118 | You can test the mouse emulation. Values are two signed numbers. | 123 | You can test the mouse emulation. Values are two signed numbers. |
| 119 | 124 | ||
| 120 | 125 | ||
| 121 | Sample code | 126 | Sample code:: |
| 122 | 127 | ||
| 123 | /* hid_gadget_test */ | 128 | /* hid_gadget_test */ |
| 124 | 129 | ||
| 125 | #include <pthread.h> | 130 | #include <pthread.h> |
| 126 | #include <string.h> | 131 | #include <string.h> |
| 127 | #include <stdio.h> | 132 | #include <stdio.h> |
| 128 | #include <ctype.h> | 133 | #include <ctype.h> |
| 129 | #include <fcntl.h> | 134 | #include <fcntl.h> |
| 130 | #include <errno.h> | 135 | #include <errno.h> |
| 131 | #include <stdio.h> | 136 | #include <stdio.h> |
| 132 | #include <stdlib.h> | 137 | #include <stdlib.h> |
| 133 | #include <unistd.h> | 138 | #include <unistd.h> |
| 134 | 139 | ||
| 135 | #define BUF_LEN 512 | 140 | #define BUF_LEN 512 |
| 136 | 141 | ||
| 137 | struct options { | 142 | struct options { |
| 138 | const char *opt; | 143 | const char *opt; |
| 139 | unsigned char val; | 144 | unsigned char val; |
| 140 | }; | 145 | }; |
| 141 | 146 | ||
| 142 | static struct options kmod[] = { | 147 | static struct options kmod[] = { |
| 143 | {.opt = "--left-ctrl", .val = 0x01}, | 148 | {.opt = "--left-ctrl", .val = 0x01}, |
| 144 | {.opt = "--right-ctrl", .val = 0x10}, | 149 | {.opt = "--right-ctrl", .val = 0x10}, |
| 145 | {.opt = "--left-shift", .val = 0x02}, | 150 | {.opt = "--left-shift", .val = 0x02}, |
| @@ -149,9 +154,9 @@ static struct options kmod[] = { | |||
| 149 | {.opt = "--left-meta", .val = 0x08}, | 154 | {.opt = "--left-meta", .val = 0x08}, |
| 150 | {.opt = "--right-meta", .val = 0x80}, | 155 | {.opt = "--right-meta", .val = 0x80}, |
| 151 | {.opt = NULL} | 156 | {.opt = NULL} |
| 152 | }; | 157 | }; |
| 153 | 158 | ||
| 154 | static struct options kval[] = { | 159 | static struct options kval[] = { |
| 155 | {.opt = "--return", .val = 0x28}, | 160 | {.opt = "--return", .val = 0x28}, |
| 156 | {.opt = "--esc", .val = 0x29}, | 161 | {.opt = "--esc", .val = 0x29}, |
| 157 | {.opt = "--bckspc", .val = 0x2a}, | 162 | {.opt = "--bckspc", .val = 0x2a}, |
| @@ -183,10 +188,10 @@ static struct options kval[] = { | |||
| 183 | {.opt = "--up", .val = 0x52}, | 188 | {.opt = "--up", .val = 0x52}, |
| 184 | {.opt = "--num-lock", .val = 0x53}, | 189 | {.opt = "--num-lock", .val = 0x53}, |
| 185 | {.opt = NULL} | 190 | {.opt = NULL} |
| 186 | }; | 191 | }; |
| 187 | 192 | ||
| 188 | int keyboard_fill_report(char report[8], char buf[BUF_LEN], int *hold) | 193 | int keyboard_fill_report(char report[8], char buf[BUF_LEN], int *hold) |
| 189 | { | 194 | { |
| 190 | char *tok = strtok(buf, " "); | 195 | char *tok = strtok(buf, " "); |
| 191 | int key = 0; | 196 | int key = 0; |
| 192 | int i = 0; | 197 | int i = 0; |
| @@ -229,17 +234,17 @@ int keyboard_fill_report(char report[8], char buf[BUF_LEN], int *hold) | |||
| 229 | fprintf(stderr, "unknown option: %s\n", tok); | 234 | fprintf(stderr, "unknown option: %s\n", tok); |
| 230 | } | 235 | } |
| 231 | return 8; | 236 | return 8; |
| 232 | } | 237 | } |
| 233 | 238 | ||
| 234 | static struct options mmod[] = { | 239 | static struct options mmod[] = { |
| 235 | {.opt = "--b1", .val = 0x01}, | 240 | {.opt = "--b1", .val = 0x01}, |
| 236 | {.opt = "--b2", .val = 0x02}, | 241 | {.opt = "--b2", .val = 0x02}, |
| 237 | {.opt = "--b3", .val = 0x04}, | 242 | {.opt = "--b3", .val = 0x04}, |
| 238 | {.opt = NULL} | 243 | {.opt = NULL} |
| 239 | }; | 244 | }; |
| 240 | 245 | ||
| 241 | int mouse_fill_report(char report[8], char buf[BUF_LEN], int *hold) | 246 | int mouse_fill_report(char report[8], char buf[BUF_LEN], int *hold) |
| 242 | { | 247 | { |
| 243 | char *tok = strtok(buf, " "); | 248 | char *tok = strtok(buf, " "); |
| 244 | int mvt = 0; | 249 | int mvt = 0; |
| 245 | int i = 0; | 250 | int i = 0; |
| @@ -274,9 +279,9 @@ int mouse_fill_report(char report[8], char buf[BUF_LEN], int *hold) | |||
| 274 | fprintf(stderr, "unknown option: %s\n", tok); | 279 | fprintf(stderr, "unknown option: %s\n", tok); |
| 275 | } | 280 | } |
| 276 | return 3; | 281 | return 3; |
| 277 | } | 282 | } |
| 278 | 283 | ||
| 279 | static struct options jmod[] = { | 284 | static struct options jmod[] = { |
| 280 | {.opt = "--b1", .val = 0x10}, | 285 | {.opt = "--b1", .val = 0x10}, |
| 281 | {.opt = "--b2", .val = 0x20}, | 286 | {.opt = "--b2", .val = 0x20}, |
| 282 | {.opt = "--b3", .val = 0x40}, | 287 | {.opt = "--b3", .val = 0x40}, |
| @@ -287,10 +292,10 @@ static struct options jmod[] = { | |||
| 287 | {.opt = "--hat4", .val = 0x03}, | 292 | {.opt = "--hat4", .val = 0x03}, |
| 288 | {.opt = "--hatneutral", .val = 0x04}, | 293 | {.opt = "--hatneutral", .val = 0x04}, |
| 289 | {.opt = NULL} | 294 | {.opt = NULL} |
| 290 | }; | 295 | }; |
| 291 | 296 | ||
| 292 | int joystick_fill_report(char report[8], char buf[BUF_LEN], int *hold) | 297 | int joystick_fill_report(char report[8], char buf[BUF_LEN], int *hold) |
| 293 | { | 298 | { |
| 294 | char *tok = strtok(buf, " "); | 299 | char *tok = strtok(buf, " "); |
| 295 | int mvt = 0; | 300 | int mvt = 0; |
| 296 | int i = 0; | 301 | int i = 0; |
| @@ -326,10 +331,10 @@ int joystick_fill_report(char report[8], char buf[BUF_LEN], int *hold) | |||
| 326 | fprintf(stderr, "unknown option: %s\n", tok); | 331 | fprintf(stderr, "unknown option: %s\n", tok); |
| 327 | } | 332 | } |
| 328 | return 4; | 333 | return 4; |
| 329 | } | 334 | } |
| 330 | 335 | ||
| 331 | void print_options(char c) | 336 | void print_options(char c) |
| 332 | { | 337 | { |
| 333 | int i = 0; | 338 | int i = 0; |
| 334 | 339 | ||
| 335 | if (c == 'k') { | 340 | if (c == 'k') { |
| @@ -358,10 +363,10 @@ void print_options(char c) | |||
| 358 | " three signed numbers\n" | 363 | " three signed numbers\n" |
| 359 | "--quit to close\n"); | 364 | "--quit to close\n"); |
| 360 | } | 365 | } |
| 361 | } | 366 | } |
| 362 | 367 | ||
| 363 | int main(int argc, const char *argv[]) | 368 | int main(int argc, const char *argv[]) |
| 364 | { | 369 | { |
| 365 | const char *filename = NULL; | 370 | const char *filename = NULL; |
| 366 | int fd = 0; | 371 | int fd = 0; |
| 367 | char buf[BUF_LEN]; | 372 | char buf[BUF_LEN]; |
| @@ -449,4 +454,4 @@ int main(int argc, const char *argv[]) | |||
| 449 | 454 | ||
| 450 | close(fd); | 455 | close(fd); |
| 451 | return 0; | 456 | return 0; |
| 452 | } | 457 | } |
diff --git a/Documentation/usb/gadget_multi.txt b/Documentation/usb/gadget_multi.txt index b3146dd7aa43..9806b55af301 100644 --- a/Documentation/usb/gadget_multi.txt +++ b/Documentation/usb/gadget_multi.txt | |||
| @@ -1,6 +1,9 @@ | |||
| 1 | -*- org -*- | 1 | ============================== |
| 2 | Multifunction Composite Gadget | ||
| 3 | ============================== | ||
| 2 | 4 | ||
| 3 | * Overview | 5 | Overview |
| 6 | ======== | ||
| 4 | 7 | ||
| 5 | The Multifunction Composite Gadget (or g_multi) is a composite gadget | 8 | The Multifunction Composite Gadget (or g_multi) is a composite gadget |
| 6 | that makes extensive use of the composite framework to provide | 9 | that makes extensive use of the composite framework to provide |
| @@ -17,13 +20,15 @@ have two configurations -- one with RNDIS and another with CDC ECM[3]. | |||
| 17 | Please note that if you use non-standard configuration (that is enable | 20 | Please note that if you use non-standard configuration (that is enable |
| 18 | CDC ECM) you may need to change vendor and/or product ID. | 21 | CDC ECM) you may need to change vendor and/or product ID. |
| 19 | 22 | ||
| 20 | * Host drivers | 23 | Host drivers |
| 24 | ============ | ||
| 21 | 25 | ||
| 22 | To make use of the gadget one needs to make it work on host side -- | 26 | To make use of the gadget one needs to make it work on host side -- |
| 23 | without that there's no hope of achieving anything with the gadget. | 27 | without that there's no hope of achieving anything with the gadget. |
| 24 | As one might expect, things one need to do very from system to system. | 28 | As one might expect, things one need to do very from system to system. |
| 25 | 29 | ||
| 26 | ** Linux host drivers | 30 | Linux host drivers |
| 31 | ------------------ | ||
| 27 | 32 | ||
| 28 | Since the gadget uses standard composite framework and appears as such | 33 | Since the gadget uses standard composite framework and appears as such |
| 29 | to Linux host it does not need any additional drivers on Linux host | 34 | to Linux host it does not need any additional drivers on Linux host |
| @@ -34,11 +39,13 @@ This is also true for two configuration set-up with RNDIS | |||
| 34 | configuration being the first one. Linux host will use the second | 39 | configuration being the first one. Linux host will use the second |
| 35 | configuration with CDC ECM which should work better under Linux. | 40 | configuration with CDC ECM which should work better under Linux. |
| 36 | 41 | ||
| 37 | ** Windows host drivers | 42 | Windows host drivers |
| 43 | -------------------- | ||
| 38 | 44 | ||
| 39 | For the gadget to work under Windows two conditions have to be met: | 45 | For the gadget to work under Windows two conditions have to be met: |
| 40 | 46 | ||
| 41 | *** Detecting as composite gadget | 47 | Detecting as composite gadget |
| 48 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 42 | 49 | ||
| 43 | First of all, Windows need to detect the gadget as an USB composite | 50 | First of all, Windows need to detect the gadget as an USB composite |
| 44 | gadget which on its own have some conditions[4]. If they are met, | 51 | gadget which on its own have some conditions[4]. If they are met, |
| @@ -53,7 +60,8 @@ The only thing to worry is that the gadget has to have a single | |||
| 53 | configuration so a dual RNDIS and CDC ECM gadget won't work unless you | 60 | configuration so a dual RNDIS and CDC ECM gadget won't work unless you |
| 54 | create a proper INF -- and of course, if you do submit it! | 61 | create a proper INF -- and of course, if you do submit it! |
| 55 | 62 | ||
| 56 | *** Installing drivers for each function | 63 | Installing drivers for each function |
| 64 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| 57 | 65 | ||
| 58 | The other, trickier thing is making Windows install drivers for each | 66 | The other, trickier thing is making Windows install drivers for each |
| 59 | individual function. | 67 | individual function. |
| @@ -63,7 +71,8 @@ implementing USB Mass Storage class and selects appropriate driver. | |||
| 63 | 71 | ||
| 64 | Things are harder with RDNIS and CDC ACM. | 72 | Things are harder with RDNIS and CDC ACM. |
| 65 | 73 | ||
| 66 | **** RNDIS | 74 | RNDIS |
| 75 | ..... | ||
| 67 | 76 | ||
| 68 | To make Windows select RNDIS drivers for the first function in the | 77 | To make Windows select RNDIS drivers for the first function in the |
| 69 | gadget, one needs to use the [[file:linux.inf]] file provided with this | 78 | gadget, one needs to use the [[file:linux.inf]] file provided with this |
| @@ -75,11 +84,13 @@ RNDIS was not the first interface. You do not need to worry abut it | |||
| 75 | unless you are trying to develop your own gadget in which case watch | 84 | unless you are trying to develop your own gadget in which case watch |
| 76 | out for this bug. | 85 | out for this bug. |
| 77 | 86 | ||
| 78 | **** CDC ACM | 87 | CDC ACM |
| 88 | ....... | ||
| 79 | 89 | ||
| 80 | Similarly, [[file:linux-cdc-acm.inf]] is provided for CDC ACM. | 90 | Similarly, [[file:linux-cdc-acm.inf]] is provided for CDC ACM. |
| 81 | 91 | ||
| 82 | **** Customising the gadget | 92 | Customising the gadget |
| 93 | ...................... | ||
| 83 | 94 | ||
| 84 | If you intend to hack the g_multi gadget be advised that rearranging | 95 | If you intend to hack the g_multi gadget be advised that rearranging |
| 85 | functions will obviously change interface numbers for each of the | 96 | functions will obviously change interface numbers for each of the |
| @@ -97,14 +108,16 @@ things don't work as intended before realising Windows have cached | |||
| 97 | some drivers information (changing USB port may sometimes help plus | 108 | some drivers information (changing USB port may sometimes help plus |
| 98 | you might try using USBDeview[8] to remove the phantom device). | 109 | you might try using USBDeview[8] to remove the phantom device). |
| 99 | 110 | ||
| 100 | **** INF testing | 111 | INF testing |
| 112 | ........... | ||
| 101 | 113 | ||
| 102 | Provided INF files have been tested on Windows XP SP3, Windows Vista | 114 | Provided INF files have been tested on Windows XP SP3, Windows Vista |
| 103 | and Windows 7, all 32-bit versions. It should work on 64-bit versions | 115 | and Windows 7, all 32-bit versions. It should work on 64-bit versions |
| 104 | as well. It most likely won't work on Windows prior to Windows XP | 116 | as well. It most likely won't work on Windows prior to Windows XP |
| 105 | SP2. | 117 | SP2. |
| 106 | 118 | ||
| 107 | ** Other systems | 119 | Other systems |
| 120 | ------------- | ||
| 108 | 121 | ||
| 109 | At this moment, drivers for any other systems have not been tested. | 122 | At this moment, drivers for any other systems have not been tested. |
| 110 | Knowing how MacOS is based on BSD and BSD is an Open Source it is | 123 | Knowing how MacOS is based on BSD and BSD is an Open Source it is |
| @@ -115,7 +128,8 @@ For more exotic systems I have even less to say... | |||
| 115 | 128 | ||
| 116 | Any testing and drivers *are* *welcome*! | 129 | Any testing and drivers *are* *welcome*! |
| 117 | 130 | ||
| 118 | * Authors | 131 | Authors |
| 132 | ======= | ||
| 119 | 133 | ||
| 120 | This document has been written by Michal Nazarewicz | 134 | This document has been written by Michal Nazarewicz |
| 121 | ([[mailto:mina86@mina86.com]]). INF files have been hacked with | 135 | ([[mailto:mina86@mina86.com]]). INF files have been hacked with |
| @@ -124,7 +138,8 @@ Xiaofan Chen ([[mailto:xiaofanc@gmail.com]]) basing on the MS RNDIS | |||
| 124 | template[9], Microchip's CDC ACM INF file and David Brownell's | 138 | template[9], Microchip's CDC ACM INF file and David Brownell's |
| 125 | ([[mailto:dbrownell@users.sourceforge.net]]) original INF files. | 139 | ([[mailto:dbrownell@users.sourceforge.net]]) original INF files. |
| 126 | 140 | ||
| 127 | * Footnotes | 141 | Footnotes |
| 142 | ========= | ||
| 128 | 143 | ||
| 129 | [1] Remote Network Driver Interface Specification, | 144 | [1] Remote Network Driver Interface Specification, |
| 130 | [[http://msdn.microsoft.com/en-us/library/ee484414.aspx]]. | 145 | [[http://msdn.microsoft.com/en-us/library/ee484414.aspx]]. |
diff --git a/Documentation/usb/gadget_printer.txt b/Documentation/usb/gadget_printer.txt index ad995bf0db41..5e5516c69075 100644 --- a/Documentation/usb/gadget_printer.txt +++ b/Documentation/usb/gadget_printer.txt | |||
| @@ -1,12 +1,14 @@ | |||
| 1 | =============================== | ||
| 2 | Linux USB Printer Gadget Driver | ||
| 3 | =============================== | ||
| 1 | 4 | ||
| 2 | Linux USB Printer Gadget Driver | 5 | 06/04/2007 |
| 3 | 06/04/2007 | ||
| 4 | 6 | ||
| 5 | Copyright (C) 2007 Craig W. Nadler <craig@nadler.us> | 7 | Copyright (C) 2007 Craig W. Nadler <craig@nadler.us> |
| 6 | 8 | ||
| 7 | 9 | ||
| 8 | 10 | ||
| 9 | GENERAL | 11 | General |
| 10 | ======= | 12 | ======= |
| 11 | 13 | ||
| 12 | This driver may be used if you are writing printer firmware using Linux as | 14 | This driver may be used if you are writing printer firmware using Linux as |
| @@ -29,52 +31,60 @@ user space firmware can read or write this status byte using a device file | |||
| 29 | 31 | ||
| 30 | 32 | ||
| 31 | 33 | ||
| 32 | HOWTO USE THIS DRIVER | 34 | Howto Use This Driver |
| 33 | ===================== | 35 | ===================== |
| 34 | 36 | ||
| 35 | To load the USB device controller driver and the printer gadget driver. The | 37 | To load the USB device controller driver and the printer gadget driver. The |
| 36 | following example uses the Netchip 2280 USB device controller driver: | 38 | following example uses the Netchip 2280 USB device controller driver:: |
| 37 | 39 | ||
| 38 | modprobe net2280 | 40 | modprobe net2280 |
| 39 | modprobe g_printer | 41 | modprobe g_printer |
| 40 | 42 | ||
| 41 | 43 | ||
| 42 | The follow command line parameter can be used when loading the printer gadget | 44 | The follow command line parameter can be used when loading the printer gadget |
| 43 | (ex: modprobe g_printer idVendor=0x0525 idProduct=0xa4a8 ): | 45 | (ex: modprobe g_printer idVendor=0x0525 idProduct=0xa4a8 ): |
| 44 | 46 | ||
| 45 | idVendor - This is the Vendor ID used in the device descriptor. The default is | 47 | idVendor |
| 48 | This is the Vendor ID used in the device descriptor. The default is | ||
| 46 | the Netchip vendor id 0x0525. YOU MUST CHANGE TO YOUR OWN VENDOR ID | 49 | the Netchip vendor id 0x0525. YOU MUST CHANGE TO YOUR OWN VENDOR ID |
| 47 | BEFORE RELEASING A PRODUCT. If you plan to release a product and don't | 50 | BEFORE RELEASING A PRODUCT. If you plan to release a product and don't |
| 48 | already have a Vendor ID please see www.usb.org for details on how to | 51 | already have a Vendor ID please see www.usb.org for details on how to |
| 49 | get one. | 52 | get one. |
| 50 | 53 | ||
| 51 | idProduct - This is the Product ID used in the device descriptor. The default | 54 | idProduct |
| 55 | This is the Product ID used in the device descriptor. The default | ||
| 52 | is 0xa4a8, you should change this to an ID that's not used by any of | 56 | is 0xa4a8, you should change this to an ID that's not used by any of |
| 53 | your other USB products if you have any. It would be a good idea to | 57 | your other USB products if you have any. It would be a good idea to |
| 54 | start numbering your products starting with say 0x0001. | 58 | start numbering your products starting with say 0x0001. |
| 55 | 59 | ||
| 56 | bcdDevice - This is the version number of your product. It would be a good idea | 60 | bcdDevice |
| 61 | This is the version number of your product. It would be a good idea | ||
| 57 | to put your firmware version here. | 62 | to put your firmware version here. |
| 58 | 63 | ||
| 59 | iManufacturer - A string containing the name of the Vendor. | 64 | iManufacturer |
| 65 | A string containing the name of the Vendor. | ||
| 60 | 66 | ||
| 61 | iProduct - A string containing the Product Name. | 67 | iProduct |
| 68 | A string containing the Product Name. | ||
| 62 | 69 | ||
| 63 | iSerialNum - A string containing the Serial Number. This should be changed for | 70 | iSerialNum |
| 71 | A string containing the Serial Number. This should be changed for | ||
| 64 | each unit of your product. | 72 | each unit of your product. |
| 65 | 73 | ||
| 66 | iPNPstring - The PNP ID string used for this printer. You will want to set | 74 | iPNPstring |
| 75 | The PNP ID string used for this printer. You will want to set | ||
| 67 | either on the command line or hard code the PNP ID string used for | 76 | either on the command line or hard code the PNP ID string used for |
| 68 | your printer product. | 77 | your printer product. |
| 69 | 78 | ||
| 70 | qlen - The number of 8k buffers to use per endpoint. The default is 10, you | 79 | qlen |
| 80 | The number of 8k buffers to use per endpoint. The default is 10, you | ||
| 71 | should tune this for your product. You may also want to tune the | 81 | should tune this for your product. You may also want to tune the |
| 72 | size of each buffer for your product. | 82 | size of each buffer for your product. |
| 73 | 83 | ||
| 74 | 84 | ||
| 75 | 85 | ||
| 76 | 86 | ||
| 77 | USING THE EXAMPLE CODE | 87 | Using The Example Code |
| 78 | ====================== | 88 | ====================== |
| 79 | 89 | ||
| 80 | This example code talks to stdout, instead of a print engine. | 90 | This example code talks to stdout, instead of a print engine. |
| @@ -82,22 +92,23 @@ This example code talks to stdout, instead of a print engine. | |||
| 82 | To compile the test code below: | 92 | To compile the test code below: |
| 83 | 93 | ||
| 84 | 1) save it to a file called prn_example.c | 94 | 1) save it to a file called prn_example.c |
| 85 | 2) compile the code with the follow command: | 95 | 2) compile the code with the follow command:: |
| 96 | |||
| 86 | gcc prn_example.c -o prn_example | 97 | gcc prn_example.c -o prn_example |
| 87 | 98 | ||
| 88 | 99 | ||
| 89 | 100 | ||
| 90 | To read printer data from the host to stdout: | 101 | To read printer data from the host to stdout:: |
| 91 | 102 | ||
| 92 | # prn_example -read_data | 103 | # prn_example -read_data |
| 93 | 104 | ||
| 94 | 105 | ||
| 95 | To write printer data from a file (data_file) to the host: | 106 | To write printer data from a file (data_file) to the host:: |
| 96 | 107 | ||
| 97 | # cat data_file | prn_example -write_data | 108 | # cat data_file | prn_example -write_data |
| 98 | 109 | ||
| 99 | 110 | ||
| 100 | To get the current printer status for the gadget driver: | 111 | To get the current printer status for the gadget driver::: |
| 101 | 112 | ||
| 102 | # prn_example -get_status | 113 | # prn_example -get_status |
| 103 | 114 | ||
| @@ -107,60 +118,62 @@ To get the current printer status for the gadget driver: | |||
| 107 | Printer OK | 118 | Printer OK |
| 108 | 119 | ||
| 109 | 120 | ||
| 110 | To set printer to Selected/On-line: | 121 | To set printer to Selected/On-line:: |
| 111 | 122 | ||
| 112 | # prn_example -selected | 123 | # prn_example -selected |
| 113 | 124 | ||
| 114 | 125 | ||
| 115 | To set printer to Not Selected/Off-line: | 126 | To set printer to Not Selected/Off-line:: |
| 116 | 127 | ||
| 117 | # prn_example -not_selected | 128 | # prn_example -not_selected |
| 118 | 129 | ||
| 119 | 130 | ||
| 120 | To set paper status to paper out: | 131 | To set paper status to paper out:: |
| 121 | 132 | ||
| 122 | # prn_example -paper_out | 133 | # prn_example -paper_out |
| 123 | 134 | ||
| 124 | 135 | ||
| 125 | To set paper status to paper loaded: | 136 | To set paper status to paper loaded:: |
| 126 | 137 | ||
| 127 | # prn_example -paper_loaded | 138 | # prn_example -paper_loaded |
| 128 | 139 | ||
| 129 | 140 | ||
| 130 | To set error status to printer OK: | 141 | To set error status to printer OK:: |
| 131 | 142 | ||
| 132 | # prn_example -no_error | 143 | # prn_example -no_error |
| 133 | 144 | ||
| 134 | 145 | ||
| 135 | To set error status to ERROR: | 146 | To set error status to ERROR:: |
| 136 | 147 | ||
| 137 | # prn_example -error | 148 | # prn_example -error |
| 138 | 149 | ||
| 139 | 150 | ||
| 140 | 151 | ||
| 141 | 152 | ||
| 142 | EXAMPLE CODE | 153 | Example Code |
| 143 | ============ | 154 | ============ |
| 144 | 155 | ||
| 156 | :: | ||
| 157 | |||
| 145 | 158 | ||
| 146 | #include <stdio.h> | 159 | #include <stdio.h> |
| 147 | #include <stdlib.h> | 160 | #include <stdlib.h> |
| 148 | #include <fcntl.h> | 161 | #include <fcntl.h> |
| 149 | #include <linux/poll.h> | 162 | #include <linux/poll.h> |
| 150 | #include <sys/ioctl.h> | 163 | #include <sys/ioctl.h> |
| 151 | #include <linux/usb/g_printer.h> | 164 | #include <linux/usb/g_printer.h> |
| 152 | 165 | ||
| 153 | #define PRINTER_FILE "/dev/g_printer" | 166 | #define PRINTER_FILE "/dev/g_printer" |
| 154 | #define BUF_SIZE 512 | 167 | #define BUF_SIZE 512 |
| 155 | 168 | ||
| 156 | 169 | ||
| 157 | /* | 170 | /* |
| 158 | * 'usage()' - Show program usage. | 171 | * 'usage()' - Show program usage. |
| 159 | */ | 172 | */ |
| 160 | 173 | ||
| 161 | static void | 174 | static void |
| 162 | usage(const char *option) /* I - Option string or NULL */ | 175 | usage(const char *option) /* I - Option string or NULL */ |
| 163 | { | 176 | { |
| 164 | if (option) { | 177 | if (option) { |
| 165 | fprintf(stderr,"prn_example: Unknown option \"%s\"!\n", | 178 | fprintf(stderr,"prn_example: Unknown option \"%s\"!\n", |
| 166 | option); | 179 | option); |
| @@ -186,12 +199,12 @@ usage(const char *option) /* I - Option string or NULL */ | |||
| 186 | fputs("\n\n", stderr); | 199 | fputs("\n\n", stderr); |
| 187 | 200 | ||
| 188 | exit(1); | 201 | exit(1); |
| 189 | } | 202 | } |
| 190 | 203 | ||
| 191 | 204 | ||
| 192 | static int | 205 | static int |
| 193 | read_printer_data() | 206 | read_printer_data() |
| 194 | { | 207 | { |
| 195 | struct pollfd fd[1]; | 208 | struct pollfd fd[1]; |
| 196 | 209 | ||
| 197 | /* Open device file for printer gadget. */ | 210 | /* Open device file for printer gadget. */ |
| @@ -236,12 +249,12 @@ read_printer_data() | |||
| 236 | close(fd[0].fd); | 249 | close(fd[0].fd); |
| 237 | 250 | ||
| 238 | return 0; | 251 | return 0; |
| 239 | } | 252 | } |
| 240 | 253 | ||
| 241 | 254 | ||
| 242 | static int | 255 | static int |
| 243 | write_printer_data() | 256 | write_printer_data() |
| 244 | { | 257 | { |
| 245 | struct pollfd fd[1]; | 258 | struct pollfd fd[1]; |
| 246 | 259 | ||
| 247 | /* Open device file for printer gadget. */ | 260 | /* Open device file for printer gadget. */ |
| @@ -295,12 +308,12 @@ write_printer_data() | |||
| 295 | close(fd[0].fd); | 308 | close(fd[0].fd); |
| 296 | 309 | ||
| 297 | return 0; | 310 | return 0; |
| 298 | } | 311 | } |
| 299 | 312 | ||
| 300 | 313 | ||
| 301 | static int | 314 | static int |
| 302 | read_NB_printer_data() | 315 | read_NB_printer_data() |
| 303 | { | 316 | { |
| 304 | int fd; | 317 | int fd; |
| 305 | static char buf[BUF_SIZE]; | 318 | static char buf[BUF_SIZE]; |
| 306 | int bytes_read; | 319 | int bytes_read; |
| @@ -329,12 +342,12 @@ read_NB_printer_data() | |||
| 329 | close(fd); | 342 | close(fd); |
| 330 | 343 | ||
| 331 | return 0; | 344 | return 0; |
| 332 | } | 345 | } |
| 333 | 346 | ||
| 334 | 347 | ||
| 335 | static int | 348 | static int |
| 336 | get_printer_status() | 349 | get_printer_status() |
| 337 | { | 350 | { |
| 338 | int retval; | 351 | int retval; |
| 339 | int fd; | 352 | int fd; |
| 340 | 353 | ||
| @@ -357,12 +370,12 @@ get_printer_status() | |||
| 357 | close(fd); | 370 | close(fd); |
| 358 | 371 | ||
| 359 | return(retval); | 372 | return(retval); |
| 360 | } | 373 | } |
| 361 | 374 | ||
| 362 | 375 | ||
| 363 | static int | 376 | static int |
| 364 | set_printer_status(unsigned char buf, int clear_printer_status_bit) | 377 | set_printer_status(unsigned char buf, int clear_printer_status_bit) |
| 365 | { | 378 | { |
| 366 | int retval; | 379 | int retval; |
| 367 | int fd; | 380 | int fd; |
| 368 | 381 | ||
| @@ -397,12 +410,12 @@ set_printer_status(unsigned char buf, int clear_printer_status_bit) | |||
| 397 | close(fd); | 410 | close(fd); |
| 398 | 411 | ||
| 399 | return 0; | 412 | return 0; |
| 400 | } | 413 | } |
| 401 | 414 | ||
| 402 | 415 | ||
| 403 | static int | 416 | static int |
| 404 | display_printer_status() | 417 | display_printer_status() |
| 405 | { | 418 | { |
| 406 | char printer_status; | 419 | char printer_status; |
| 407 | 420 | ||
| 408 | printer_status = get_printer_status(); | 421 | printer_status = get_printer_status(); |
| @@ -429,12 +442,12 @@ display_printer_status() | |||
| 429 | } | 442 | } |
| 430 | 443 | ||
| 431 | return(0); | 444 | return(0); |
| 432 | } | 445 | } |
| 433 | 446 | ||
| 434 | 447 | ||
| 435 | int | 448 | int |
| 436 | main(int argc, char *argv[]) | 449 | main(int argc, char *argv[]) |
| 437 | { | 450 | { |
| 438 | int i; /* Looping var */ | 451 | int i; /* Looping var */ |
| 439 | int retval = 0; | 452 | int retval = 0; |
| 440 | 453 | ||
| @@ -507,4 +520,4 @@ main(int argc, char *argv[]) | |||
| 507 | } | 520 | } |
| 508 | 521 | ||
| 509 | exit(retval); | 522 | exit(retval); |
| 510 | } | 523 | } |
diff --git a/Documentation/usb/gadget_serial.txt b/Documentation/usb/gadget_serial.txt index d1def3186782..dce8bc1fb1f2 100644 --- a/Documentation/usb/gadget_serial.txt +++ b/Documentation/usb/gadget_serial.txt | |||
| @@ -1,7 +1,10 @@ | |||
| 1 | =============================== | ||
| 2 | Linux Gadget Serial Driver v2.0 | ||
| 3 | =============================== | ||
| 1 | 4 | ||
| 2 | Linux Gadget Serial Driver v2.0 | 5 | 11/20/2004 |
| 3 | 11/20/2004 | 6 | |
| 4 | (updated 8-May-2008 for v2.3) | 7 | (updated 8-May-2008 for v2.3) |
| 5 | 8 | ||
| 6 | 9 | ||
| 7 | License and Disclaimer | 10 | License and Disclaimer |
| @@ -56,7 +59,7 @@ hardware; for example, a PDA, an embedded Linux system, or a PC | |||
| 56 | with a USB development card. | 59 | with a USB development card. |
| 57 | 60 | ||
| 58 | The gadget serial driver talks over USB to either a CDC ACM driver | 61 | The gadget serial driver talks over USB to either a CDC ACM driver |
| 59 | or a generic USB serial driver running on a host PC. | 62 | or a generic USB serial driver running on a host PC:: |
| 60 | 63 | ||
| 61 | Host | 64 | Host |
| 62 | -------------------------------------- | 65 | -------------------------------------- |
| @@ -112,11 +115,11 @@ configuring the kernel. Then rebuild and install the kernel or | |||
| 112 | modules. | 115 | modules. |
| 113 | 116 | ||
| 114 | Then you must load the gadget serial driver. To load it as an | 117 | Then you must load the gadget serial driver. To load it as an |
| 115 | ACM device (recommended for interoperability), do this: | 118 | ACM device (recommended for interoperability), do this:: |
| 116 | 119 | ||
| 117 | modprobe g_serial | 120 | modprobe g_serial |
| 118 | 121 | ||
| 119 | To load it as a vendor specific bulk in/out device, do this: | 122 | To load it as a vendor specific bulk in/out device, do this:: |
| 120 | 123 | ||
| 121 | modprobe g_serial use_acm=0 | 124 | modprobe g_serial use_acm=0 |
| 122 | 125 | ||
| @@ -127,7 +130,7 @@ desired. | |||
| 127 | 130 | ||
| 128 | Your system should use mdev (from busybox) or udev to make the | 131 | Your system should use mdev (from busybox) or udev to make the |
| 129 | device nodes. After this gadget driver has been set up you should | 132 | device nodes. After this gadget driver has been set up you should |
| 130 | then see a /dev/ttyGS0 node: | 133 | then see a /dev/ttyGS0 node:: |
| 131 | 134 | ||
| 132 | # ls -l /dev/ttyGS0 | cat | 135 | # ls -l /dev/ttyGS0 | cat |
| 133 | crw-rw---- 1 root root 253, 0 May 8 14:10 /dev/ttyGS0 | 136 | crw-rw---- 1 root root 253, 0 May 8 14:10 /dev/ttyGS0 |
| @@ -187,24 +190,24 @@ support". | |||
| 187 | 190 | ||
| 188 | Once the gadget serial driver is loaded and the USB device connected | 191 | Once the gadget serial driver is loaded and the USB device connected |
| 189 | to the Linux host with a USB cable, the host system should recognize | 192 | to the Linux host with a USB cable, the host system should recognize |
| 190 | the gadget serial device. For example, the command | 193 | the gadget serial device. For example, the command:: |
| 191 | 194 | ||
| 192 | cat /sys/kernel/debug/usb/devices | 195 | cat /sys/kernel/debug/usb/devices |
| 193 | 196 | ||
| 194 | should show something like this: | 197 | should show something like this::: |
| 195 | 198 | ||
| 196 | T: Bus=01 Lev=01 Prnt=01 Port=01 Cnt=02 Dev#= 5 Spd=480 MxCh= 0 | 199 | T: Bus=01 Lev=01 Prnt=01 Port=01 Cnt=02 Dev#= 5 Spd=480 MxCh= 0 |
| 197 | D: Ver= 2.00 Cls=02(comm.) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 | 200 | D: Ver= 2.00 Cls=02(comm.) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 |
| 198 | P: Vendor=0525 ProdID=a4a7 Rev= 2.01 | 201 | P: Vendor=0525 ProdID=a4a7 Rev= 2.01 |
| 199 | S: Manufacturer=Linux 2.6.8.1 with net2280 | 202 | S: Manufacturer=Linux 2.6.8.1 with net2280 |
| 200 | S: Product=Gadget Serial | 203 | S: Product=Gadget Serial |
| 201 | S: SerialNumber=0 | 204 | S: SerialNumber=0 |
| 202 | C:* #Ifs= 2 Cfg#= 2 Atr=c0 MxPwr= 2mA | 205 | C:* #Ifs= 2 Cfg#= 2 Atr=c0 MxPwr= 2mA |
| 203 | I: If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=02 Prot=01 Driver=acm | 206 | I: If#= 0 Alt= 0 #EPs= 1 Cls=02(comm.) Sub=02 Prot=01 Driver=acm |
| 204 | E: Ad=83(I) Atr=03(Int.) MxPS= 8 Ivl=32ms | 207 | E: Ad=83(I) Atr=03(Int.) MxPS= 8 Ivl=32ms |
| 205 | I: If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=acm | 208 | I: If#= 1 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=acm |
| 206 | E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms | 209 | E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms |
| 207 | E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms | 210 | E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms |
| 208 | 211 | ||
| 209 | If the host side Linux system is configured properly, the ACM driver | 212 | If the host side Linux system is configured properly, the ACM driver |
| 210 | should be loaded automatically. The command "lsmod" should show the | 213 | should be loaded automatically. The command "lsmod" should show the |
| @@ -219,29 +222,29 @@ Serial Converter support", and for the "USB Generic Serial Driver". | |||
| 219 | 222 | ||
| 220 | Once the gadget serial driver is loaded and the USB device connected | 223 | Once the gadget serial driver is loaded and the USB device connected |
| 221 | to the Linux host with a USB cable, the host system should recognize | 224 | to the Linux host with a USB cable, the host system should recognize |
| 222 | the gadget serial device. For example, the command | 225 | the gadget serial device. For example, the command:: |
| 223 | 226 | ||
| 224 | cat /sys/kernel/debug/usb/devices | 227 | cat /sys/kernel/debug/usb/devices |
| 225 | 228 | ||
| 226 | should show something like this: | 229 | should show something like this::: |
| 227 | 230 | ||
| 228 | T: Bus=01 Lev=01 Prnt=01 Port=01 Cnt=02 Dev#= 6 Spd=480 MxCh= 0 | 231 | T: Bus=01 Lev=01 Prnt=01 Port=01 Cnt=02 Dev#= 6 Spd=480 MxCh= 0 |
| 229 | D: Ver= 2.00 Cls=ff(vend.) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 | 232 | D: Ver= 2.00 Cls=ff(vend.) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 |
| 230 | P: Vendor=0525 ProdID=a4a6 Rev= 2.01 | 233 | P: Vendor=0525 ProdID=a4a6 Rev= 2.01 |
| 231 | S: Manufacturer=Linux 2.6.8.1 with net2280 | 234 | S: Manufacturer=Linux 2.6.8.1 with net2280 |
| 232 | S: Product=Gadget Serial | 235 | S: Product=Gadget Serial |
| 233 | S: SerialNumber=0 | 236 | S: SerialNumber=0 |
| 234 | C:* #Ifs= 1 Cfg#= 1 Atr=c0 MxPwr= 2mA | 237 | C:* #Ifs= 1 Cfg#= 1 Atr=c0 MxPwr= 2mA |
| 235 | I: If#= 0 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=serial | 238 | I: If#= 0 Alt= 0 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=serial |
| 236 | E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms | 239 | E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms |
| 237 | E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms | 240 | E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms |
| 238 | 241 | ||
| 239 | You must load the usbserial driver and explicitly set its parameters | 242 | You must load the usbserial driver and explicitly set its parameters |
| 240 | to configure it to recognize the gadget serial device, like this: | 243 | to configure it to recognize the gadget serial device, like this:: |
| 241 | 244 | ||
| 242 | echo 0x0525 0xA4A6 >/sys/bus/usb-serial/drivers/generic/new_id | 245 | echo 0x0525 0xA4A6 >/sys/bus/usb-serial/drivers/generic/new_id |
| 243 | 246 | ||
| 244 | The legacy way is to use module parameters: | 247 | The legacy way is to use module parameters:: |
| 245 | 248 | ||
| 246 | modprobe usbserial vendor=0x0525 product=0xA4A6 | 249 | modprobe usbserial vendor=0x0525 product=0xA4A6 |
| 247 | 250 | ||
diff --git a/Documentation/usb/iuu_phoenix.txt b/Documentation/usb/iuu_phoenix.txt index e5f048067da4..b76268728450 100644 --- a/Documentation/usb/iuu_phoenix.txt +++ b/Documentation/usb/iuu_phoenix.txt | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | ============================= | ||
| 1 | Infinity Usb Unlimited Readme | 2 | Infinity Usb Unlimited Readme |
| 2 | ----------------------------- | 3 | ============================= |
| 3 | 4 | ||
| 4 | Hi all, | 5 | Hi all, |
| 5 | 6 | ||
| @@ -19,7 +20,8 @@ have his own device file(/dev/ttyUSB0,/dev/ttyUSB1,...) | |||
| 19 | 20 | ||
| 20 | 21 | ||
| 21 | 22 | ||
| 22 | How to tune the reader speed ? | 23 | How to tune the reader speed? |
| 24 | ============================= | ||
| 23 | 25 | ||
| 24 | A few parameters can be used at load time | 26 | A few parameters can be used at load time |
| 25 | To use parameters, just unload the module if it is | 27 | To use parameters, just unload the module if it is |
| @@ -27,26 +29,33 @@ How to tune the reader speed ? | |||
| 27 | In case of prebuilt module, use the command | 29 | In case of prebuilt module, use the command |
| 28 | insmod iuu_phoenix param=value. | 30 | insmod iuu_phoenix param=value. |
| 29 | 31 | ||
| 30 | Example: | 32 | Example:: |
| 31 | 33 | ||
| 32 | modprobe iuu_phoenix clockmode=3 | 34 | modprobe iuu_phoenix clockmode=3 |
| 33 | 35 | ||
| 34 | The parameters are: | 36 | The parameters are: |
| 35 | 37 | ||
| 36 | parm: clockmode:1=3Mhz579,2=3Mhz680,3=6Mhz (int) | 38 | clockmode: |
| 37 | parm: boost:overclock boost percent 100 to 500 (int) | 39 | 1=3Mhz579,2=3Mhz680,3=6Mhz (int) |
| 38 | parm: cdmode:Card detect mode 0=none, 1=CD, 2=!CD, 3=DSR, 4=!DSR, 5=CTS, 6=!CTS, 7=RING, 8=!RING (int) | 40 | boost: |
| 39 | parm: xmas:xmas color enabled or not (bool) | 41 | overclock boost percent 100 to 500 (int) |
| 40 | parm: debug:Debug enabled or not (bool) | 42 | cdmode: |
| 43 | Card detect mode | ||
| 44 | 0=none, 1=CD, 2=!CD, 3=DSR, 4=!DSR, 5=CTS, 6=!CTS, 7=RING, 8=!RING (int) | ||
| 45 | xmas: | ||
| 46 | xmas color enabled or not (bool) | ||
| 47 | debug: | ||
| 48 | Debug enabled or not (bool) | ||
| 41 | 49 | ||
| 42 | - clockmode will provide 3 different base settings commonly adopted by | 50 | - clockmode will provide 3 different base settings commonly adopted by |
| 43 | different software: | 51 | different software: |
| 44 | 1. 3Mhz579 | 52 | |
| 53 | 1. 3Mhz579 | ||
| 45 | 2. 3Mhz680 | 54 | 2. 3Mhz680 |
| 46 | 3. 6Mhz | 55 | 3. 6Mhz |
| 47 | 56 | ||
| 48 | - boost provide a way to overclock the reader ( my favorite :-) ) | 57 | - boost provide a way to overclock the reader ( my favorite :-) ) |
| 49 | For example to have best performance than a simple clockmode=3, try this: | 58 | For example to have best performance than a simple clockmode=3, try this:: |
| 50 | 59 | ||
| 51 | modprobe boost=195 | 60 | modprobe boost=195 |
| 52 | 61 | ||
| @@ -66,7 +75,8 @@ How to tune the reader speed ? | |||
| 66 | - debug will produce a lot of debugging messages... | 75 | - debug will produce a lot of debugging messages... |
| 67 | 76 | ||
| 68 | 77 | ||
| 69 | Last notes: | 78 | Last notes |
| 79 | ========== | ||
| 70 | 80 | ||
| 71 | Don't worry about the serial settings, the serial emulation | 81 | Don't worry about the serial settings, the serial emulation |
| 72 | is an abstraction, so use any speed or parity setting will | 82 | is an abstraction, so use any speed or parity setting will |
diff --git a/Documentation/usb/mass-storage.txt b/Documentation/usb/mass-storage.txt index e89803a5a960..d181b47c3cb6 100644 --- a/Documentation/usb/mass-storage.txt +++ b/Documentation/usb/mass-storage.txt | |||
| @@ -1,4 +1,9 @@ | |||
| 1 | * Overview | 1 | ========================= |
| 2 | Mass Storage Gadget (MSG) | ||
| 3 | ========================= | ||
| 4 | |||
| 5 | Overview | ||
| 6 | ======== | ||
| 2 | 7 | ||
| 3 | Mass Storage Gadget (or MSG) acts as a USB Mass Storage device, | 8 | Mass Storage Gadget (or MSG) acts as a USB Mass Storage device, |
| 4 | appearing to the host as a disk or a CD-ROM drive. It supports | 9 | appearing to the host as a disk or a CD-ROM drive. It supports |
| @@ -24,7 +29,8 @@ | |||
| 24 | (which is no longer included in Linux). It will talk only briefly | 29 | (which is no longer included in Linux). It will talk only briefly |
| 25 | about how to use MSF within composite gadgets. | 30 | about how to use MSF within composite gadgets. |
| 26 | 31 | ||
| 27 | * Module parameters | 32 | Module parameters |
| 33 | ================= | ||
| 28 | 34 | ||
| 29 | The mass storage gadget accepts the following mass storage specific | 35 | The mass storage gadget accepts the following mass storage specific |
| 30 | module parameters: | 36 | module parameters: |
| @@ -146,7 +152,8 @@ | |||
| 146 | - iProduct -- USB Product string (string) | 152 | - iProduct -- USB Product string (string) |
| 147 | - iSerialNumber -- SerialNumber string (sting) | 153 | - iSerialNumber -- SerialNumber string (sting) |
| 148 | 154 | ||
| 149 | * sysfs entries | 155 | sysfs entries |
| 156 | ============= | ||
| 150 | 157 | ||
| 151 | For each logical unit, the gadget creates a directory in the sysfs | 158 | For each logical unit, the gadget creates a directory in the sysfs |
| 152 | hierarchy. Inside of it the following three files are created: | 159 | hierarchy. Inside of it the following three files are created: |
| @@ -177,7 +184,8 @@ | |||
| 177 | Other then those, as usual, the values of module parameters can be | 184 | Other then those, as usual, the values of module parameters can be |
| 178 | read from /sys/module/g_mass_storage/parameters/* files. | 185 | read from /sys/module/g_mass_storage/parameters/* files. |
| 179 | 186 | ||
| 180 | * Other gadgets using mass storage function | 187 | Other gadgets using mass storage function |
| 188 | ========================================= | ||
| 181 | 189 | ||
| 182 | The Mass Storage Gadget uses the Mass Storage Function to handle | 190 | The Mass Storage Gadget uses the Mass Storage Function to handle |
| 183 | mass storage protocol. As a composite function, MSF may be used by | 191 | mass storage protocol. As a composite function, MSF may be used by |
| @@ -193,7 +201,8 @@ | |||
| 193 | may take a look at mass_storage.c, acm_ms.c and multi.c (sorted by | 201 | may take a look at mass_storage.c, acm_ms.c and multi.c (sorted by |
| 194 | complexity). | 202 | complexity). |
| 195 | 203 | ||
| 196 | * Relation to file storage gadget | 204 | Relation to file storage gadget |
| 205 | =============================== | ||
| 197 | 206 | ||
| 198 | The Mass Storage Function and thus the Mass Storage Gadget has been | 207 | The Mass Storage Function and thus the Mass Storage Gadget has been |
| 199 | based on the File Storage Gadget. The difference between the two is | 208 | based on the File Storage Gadget. The difference between the two is |
diff --git a/Documentation/usb/misc_usbsevseg.txt b/Documentation/usb/misc_usbsevseg.txt index 0f6be4f9930b..6274aee083ed 100644 --- a/Documentation/usb/misc_usbsevseg.txt +++ b/Documentation/usb/misc_usbsevseg.txt | |||
| @@ -1,4 +1,7 @@ | |||
| 1 | ============================= | ||
| 1 | USB 7-Segment Numeric Display | 2 | USB 7-Segment Numeric Display |
| 3 | ============================= | ||
| 4 | |||
| 2 | Manufactured by Delcom Engineering | 5 | Manufactured by Delcom Engineering |
| 3 | 6 | ||
| 4 | Device Information | 7 | Device Information |
| @@ -13,9 +16,13 @@ Device Modes | |||
| 13 | ------------ | 16 | ------------ |
| 14 | By default, the driver assumes the display is only 6 characters | 17 | By default, the driver assumes the display is only 6 characters |
| 15 | The mode for 6 characters is: | 18 | The mode for 6 characters is: |
| 19 | |||
| 16 | MSB 0x06; LSB 0x3f | 20 | MSB 0x06; LSB 0x3f |
| 21 | |||
| 17 | For the 8 character display: | 22 | For the 8 character display: |
| 23 | |||
| 18 | MSB 0x08; LSB 0xff | 24 | MSB 0x08; LSB 0xff |
| 25 | |||
| 19 | The device can accept "text" either in raw, hex, or ascii textmode. | 26 | The device can accept "text" either in raw, hex, or ascii textmode. |
| 20 | raw controls each segment manually, | 27 | raw controls each segment manually, |
| 21 | hex expects a value between 0-15 per character, | 28 | hex expects a value between 0-15 per character, |
| @@ -42,5 +49,3 @@ Device Operation | |||
| 42 | To set multiple decimals points sum up each power. | 49 | To set multiple decimals points sum up each power. |
| 43 | For example, to set the 0th and 3rd decimal place | 50 | For example, to set the 0th and 3rd decimal place |
| 44 | echo 1001 > /sys/bus/usb/.../decimals | 51 | echo 1001 > /sys/bus/usb/.../decimals |
| 45 | |||
| 46 | |||
diff --git a/Documentation/usb/mtouchusb.txt b/Documentation/usb/mtouchusb.txt index a91adb26ea7b..d1111b74bf75 100644 --- a/Documentation/usb/mtouchusb.txt +++ b/Documentation/usb/mtouchusb.txt | |||
| @@ -1,19 +1,27 @@ | |||
| 1 | CHANGES | 1 | ================ |
| 2 | mtouchusb driver | ||
| 3 | ================ | ||
| 4 | |||
| 5 | Changes | ||
| 6 | ======= | ||
| 2 | 7 | ||
| 3 | - 0.3 - Created based off of scanner & INSTALL from the original touchscreen | 8 | - 0.3 - Created based off of scanner & INSTALL from the original touchscreen |
| 4 | driver on freecode (http://freecode.com/projects/3mtouchscreendriver) | 9 | driver on freecode (http://freecode.com/projects/3mtouchscreendriver) |
| 5 | - Amended for linux-2.4.18, then 2.4.19 | 10 | - Amended for linux-2.4.18, then 2.4.19 |
| 6 | 11 | ||
| 7 | - 0.5 - Complete rewrite using Linux Input in 2.6.3 | 12 | - 0.5 - Complete rewrite using Linux Input in 2.6.3 |
| 8 | Unfortunately no calibration support at this time | 13 | Unfortunately no calibration support at this time |
| 9 | 14 | ||
| 10 | - 1.4 - Multiple changes to support the EXII 5000UC and house cleaning | 15 | - 1.4 - Multiple changes to support the EXII 5000UC and house cleaning |
| 11 | Changed reset from standard USB dev reset to vendor reset | 16 | Changed reset from standard USB dev reset to vendor reset |
| 12 | Changed data sent to host from compensated to raw coordinates | 17 | Changed data sent to host from compensated to raw coordinates |
| 13 | Eliminated vendor/product module params | 18 | Eliminated vendor/product module params |
| 14 | Performed multiple successful tests with an EXII-5010UC | 19 | Performed multiple successful tests with an EXII-5010UC |
| 20 | |||
| 21 | Supported Hardware | ||
| 22 | ================== | ||
| 15 | 23 | ||
| 16 | SUPPORTED HARDWARE: | 24 | :: |
| 17 | 25 | ||
| 18 | All controllers have the Vendor: 0x0596 & Product: 0x0001 | 26 | All controllers have the Vendor: 0x0596 & Product: 0x0001 |
| 19 | 27 | ||
| @@ -29,9 +37,10 @@ SUPPORTED HARDWARE: | |||
| 29 | USB Capacitive - Black Case EXII-5030UC | 37 | USB Capacitive - Black Case EXII-5030UC |
| 30 | USB Capacitive - No Case EXII-5050UC | 38 | USB Capacitive - No Case EXII-5050UC |
| 31 | 39 | ||
| 32 | DRIVER NOTES: | 40 | Driver Notes |
| 41 | ============ | ||
| 33 | 42 | ||
| 34 | Installation is simple, you only need to add Linux Input, Linux USB, and the | 43 | Installation is simple, you only need to add Linux Input, Linux USB, and the |
| 35 | driver to the kernel. The driver can also be optionally built as a module. | 44 | driver to the kernel. The driver can also be optionally built as a module. |
| 36 | 45 | ||
| 37 | This driver appears to be one of possible 2 Linux USB Input Touchscreen | 46 | This driver appears to be one of possible 2 Linux USB Input Touchscreen |
| @@ -49,24 +58,27 @@ The controller screen resolution is now 0 to 16384 for both X and Y reporting | |||
| 49 | the raw touch data. This is the same for the old and new capacitive USB | 58 | the raw touch data. This is the same for the old and new capacitive USB |
| 50 | controllers. | 59 | controllers. |
| 51 | 60 | ||
| 52 | Perhaps at some point an abstract function will be placed into evdev so | 61 | Perhaps at some point an abstract function will be placed into evdev so |
| 53 | generic functions like calibrations, resets, and vendor information can be | 62 | generic functions like calibrations, resets, and vendor information can be |
| 54 | requested from the userspace (And the drivers would handle the vendor specific | 63 | requested from the userspace (And the drivers would handle the vendor specific |
| 55 | tasks). | 64 | tasks). |
| 56 | 65 | ||
| 57 | TODO: | 66 | TODO |
| 67 | ==== | ||
| 58 | 68 | ||
| 59 | Implement a control urb again to handle requests to and from the device | 69 | Implement a control urb again to handle requests to and from the device |
| 60 | such as calibration, etc once/if it becomes available. | 70 | such as calibration, etc once/if it becomes available. |
| 61 | 71 | ||
| 62 | DISCLAIMER: | 72 | Disclaimer |
| 73 | ========== | ||
| 63 | 74 | ||
| 64 | I am not a MicroTouch/3M employee, nor have I ever been. 3M does not support | 75 | I am not a MicroTouch/3M employee, nor have I ever been. 3M does not support |
| 65 | this driver! If you want touch drivers only supported within X, please go to: | 76 | this driver! If you want touch drivers only supported within X, please go to: |
| 66 | 77 | ||
| 67 | http://www.3m.com/3MTouchSystems/ | 78 | http://www.3m.com/3MTouchSystems/ |
| 68 | 79 | ||
| 69 | THANKS: | 80 | Thanks |
| 81 | ====== | ||
| 70 | 82 | ||
| 71 | A huge thank you to 3M Touch Systems for the EXII-5010UC controllers for | 83 | A huge thank you to 3M Touch Systems for the EXII-5010UC controllers for |
| 72 | testing! | 84 | testing! |
diff --git a/Documentation/usb/ohci.txt b/Documentation/usb/ohci.txt index 99320d9fa523..bb3c49719e6b 100644 --- a/Documentation/usb/ohci.txt +++ b/Documentation/usb/ohci.txt | |||
| @@ -1,3 +1,7 @@ | |||
| 1 | ==== | ||
| 2 | OHCI | ||
| 3 | ==== | ||
| 4 | |||
| 1 | 23-Aug-2002 | 5 | 23-Aug-2002 |
| 2 | 6 | ||
| 3 | The "ohci-hcd" driver is a USB Host Controller Driver (HCD) that is derived | 7 | The "ohci-hcd" driver is a USB Host Controller Driver (HCD) that is derived |
| @@ -29,4 +33,3 @@ work on while the OS is getting around to the relevant IRQ processing. | |||
| 29 | 33 | ||
| 30 | - David Brownell | 34 | - David Brownell |
| 31 | <dbrownell@users.sourceforge.net> | 35 | <dbrownell@users.sourceforge.net> |
| 32 | |||
diff --git a/Documentation/usb/rio.txt b/Documentation/usb/rio.txt index aee715af7db7..ca9adcf56355 100644 --- a/Documentation/usb/rio.txt +++ b/Documentation/usb/rio.txt | |||
| @@ -1,72 +1,80 @@ | |||
| 1 | ============ | ||
| 2 | Diamonds Rio | ||
| 3 | ============ | ||
| 4 | |||
| 1 | Copyright (C) 1999, 2000 Bruce Tenison | 5 | Copyright (C) 1999, 2000 Bruce Tenison |
| 6 | |||
| 2 | Portions Copyright (C) 1999, 2000 David Nelson | 7 | Portions Copyright (C) 1999, 2000 David Nelson |
| 8 | |||
| 3 | Thanks to David Nelson for guidance and the usage of the scanner.txt | 9 | Thanks to David Nelson for guidance and the usage of the scanner.txt |
| 4 | and scanner.c files to model our driver and this informative file. | 10 | and scanner.c files to model our driver and this informative file. |
| 5 | 11 | ||
| 6 | Mar. 2, 2000 | 12 | Mar. 2, 2000 |
| 7 | 13 | ||
| 8 | CHANGES | 14 | Changes |
| 15 | ======= | ||
| 9 | 16 | ||
| 10 | - Initial Revision | 17 | - Initial Revision |
| 11 | 18 | ||
| 12 | 19 | ||
| 13 | OVERVIEW | 20 | Overview |
| 21 | ======== | ||
| 14 | 22 | ||
| 15 | This README will address issues regarding how to configure the kernel | 23 | This README will address issues regarding how to configure the kernel |
| 16 | to access a RIO 500 mp3 player. | 24 | to access a RIO 500 mp3 player. |
| 17 | Before I explain how to use this to access the Rio500 please be warned: | 25 | Before I explain how to use this to access the Rio500 please be warned: |
| 18 | 26 | ||
| 19 | W A R N I N G: | 27 | .. warning:: |
| 20 | -------------- | ||
| 21 | 28 | ||
| 22 | Please note that this software is still under development. The authors | 29 | Please note that this software is still under development. The authors |
| 23 | are in no way responsible for any damage that may occur, no matter how | 30 | are in no way responsible for any damage that may occur, no matter how |
| 24 | inconsequential. | 31 | inconsequential. |
| 25 | 32 | ||
| 26 | It seems that the Rio has a problem when sending .mp3 with low batteries. | 33 | It seems that the Rio has a problem when sending .mp3 with low batteries. |
| 27 | I suggest when the batteries are low and you want to transfer stuff that you | 34 | I suggest when the batteries are low and you want to transfer stuff that you |
| 28 | replace it with a fresh one. In my case, what happened is I lost two 16kb | 35 | replace it with a fresh one. In my case, what happened is I lost two 16kb |
| 29 | blocks (they are no longer usable to store information to it). But I don't | 36 | blocks (they are no longer usable to store information to it). But I don't |
| 30 | know if that's normal or not; it could simply be a problem with the flash | 37 | know if that's normal or not; it could simply be a problem with the flash |
| 31 | memory. | 38 | memory. |
| 32 | 39 | ||
| 33 | In an extreme case, I left my Rio playing overnight and the batteries wore | 40 | In an extreme case, I left my Rio playing overnight and the batteries wore |
| 34 | down to nothing and appear to have corrupted the flash memory. My RIO | 41 | down to nothing and appear to have corrupted the flash memory. My RIO |
| 35 | needed to be replaced as a result. Diamond tech support is aware of the | 42 | needed to be replaced as a result. Diamond tech support is aware of the |
| 36 | problem. Do NOT allow your batteries to wear down to nothing before | 43 | problem. Do NOT allow your batteries to wear down to nothing before |
| 37 | changing them. It appears RIO 500 firmware does not handle low battery | 44 | changing them. It appears RIO 500 firmware does not handle low battery |
| 38 | power well at all. | 45 | power well at all. |
| 39 | 46 | ||
| 40 | On systems with OHCI controllers, the kernel OHCI code appears to have | 47 | On systems with OHCI controllers, the kernel OHCI code appears to have |
| 41 | power on problems with some chipsets. If you are having problems | 48 | power on problems with some chipsets. If you are having problems |
| 42 | connecting to your RIO 500, try turning it on first and then plugging it | 49 | connecting to your RIO 500, try turning it on first and then plugging it |
| 43 | into the USB cable. | 50 | into the USB cable. |
| 44 | 51 | ||
| 45 | Contact information: | 52 | Contact Information |
| 46 | -------------------- | 53 | ------------------- |
| 47 | 54 | ||
| 48 | The main page for the project is hosted at sourceforge.net in the following | 55 | The main page for the project is hosted at sourceforge.net in the following |
| 49 | URL: <http://rio500.sourceforge.net>. You can also go to the project's | 56 | URL: <http://rio500.sourceforge.net>. You can also go to the project's |
| 50 | sourceforge home page at: <http://sourceforge.net/projects/rio500/>. | 57 | sourceforge home page at: <http://sourceforge.net/projects/rio500/>. |
| 51 | There is also a mailing list: rio500-users@lists.sourceforge.net | 58 | There is also a mailing list: rio500-users@lists.sourceforge.net |
| 52 | 59 | ||
| 53 | Authors: | 60 | Authors |
| 54 | ------- | 61 | ------- |
| 55 | 62 | ||
| 56 | Most of the code was written by Cesar Miquel <miquel@df.uba.ar>. Keith | 63 | Most of the code was written by Cesar Miquel <miquel@df.uba.ar>. Keith |
| 57 | Clayton <kclayton@jps.net> is incharge of the PPC port and making sure | 64 | Clayton <kclayton@jps.net> is incharge of the PPC port and making sure |
| 58 | things work there. Bruce Tenison <btenison@dibbs.net> is adding support | 65 | things work there. Bruce Tenison <btenison@dibbs.net> is adding support |
| 59 | for .fon files and also does testing. The program will mostly sure be | 66 | for .fon files and also does testing. The program will mostly sure be |
| 60 | re-written and Pete Ikusz along with the rest will re-design it. I would | 67 | re-written and Pete Ikusz along with the rest will re-design it. I would |
| 61 | also like to thank Tri Nguyen <tmn_3022000@hotmail.com> who provided use | 68 | also like to thank Tri Nguyen <tmn_3022000@hotmail.com> who provided use |
| 62 | with some important information regarding the communication with the Rio. | 69 | with some important information regarding the communication with the Rio. |
| 63 | 70 | ||
| 64 | ADDITIONAL INFORMATION and Userspace tools | 71 | Additional Information and userspace tools |
| 65 | 72 | ||
| 66 | http://rio500.sourceforge.net/ | 73 | http://rio500.sourceforge.net/ |
| 67 | 74 | ||
| 68 | 75 | ||
| 69 | REQUIREMENTS | 76 | Requirements |
| 77 | ============ | ||
| 70 | 78 | ||
| 71 | A host with a USB port. Ideally, either a UHCI (Intel) or OHCI | 79 | A host with a USB port. Ideally, either a UHCI (Intel) or OHCI |
| 72 | (Compaq and others) hardware port should work. | 80 | (Compaq and others) hardware port should work. |
| @@ -80,11 +88,11 @@ A Linux kernel with RIO 500 support enabled. | |||
| 80 | 'lspci' which is only needed to determine the type of USB hardware | 88 | 'lspci' which is only needed to determine the type of USB hardware |
| 81 | available in your machine. | 89 | available in your machine. |
| 82 | 90 | ||
| 83 | CONFIGURATION | 91 | Configuration |
| 84 | 92 | ||
| 85 | Using `lspci -v`, determine the type of USB hardware available. | 93 | Using `lspci -v`, determine the type of USB hardware available. |
| 86 | 94 | ||
| 87 | If you see something like: | 95 | If you see something like:: |
| 88 | 96 | ||
| 89 | USB Controller: ...... | 97 | USB Controller: ...... |
| 90 | Flags: ..... | 98 | Flags: ..... |
| @@ -92,7 +100,7 @@ Using `lspci -v`, determine the type of USB hardware available. | |||
| 92 | 100 | ||
| 93 | Then you have a UHCI based controller. | 101 | Then you have a UHCI based controller. |
| 94 | 102 | ||
| 95 | If you see something like: | 103 | If you see something like:: |
| 96 | 104 | ||
| 97 | USB Controller: ..... | 105 | USB Controller: ..... |
| 98 | Flags: .... | 106 | Flags: .... |
| @@ -107,8 +115,9 @@ hardware (determined from the steps above), 'USB Diamond Rio500 support', and | |||
| 107 | (you may need to execute `depmod -a` to update the module | 115 | (you may need to execute `depmod -a` to update the module |
| 108 | dependencies). | 116 | dependencies). |
| 109 | 117 | ||
| 110 | Add a device for the USB rio500: | 118 | Add a device for the USB rio500:: |
| 111 | `mknod /dev/usb/rio500 c 180 64` | 119 | |
| 120 | mknod /dev/usb/rio500 c 180 64 | ||
| 112 | 121 | ||
| 113 | Set appropriate permissions for /dev/usb/rio500 (don't forget about | 122 | Set appropriate permissions for /dev/usb/rio500 (don't forget about |
| 114 | group and world permissions). Both read and write permissions are | 123 | group and world permissions). Both read and write permissions are |
| @@ -116,12 +125,14 @@ required for proper operation. | |||
| 116 | 125 | ||
| 117 | Load the appropriate modules (if compiled as modules): | 126 | Load the appropriate modules (if compiled as modules): |
| 118 | 127 | ||
| 119 | OHCI: | 128 | OHCI:: |
| 129 | |||
| 120 | modprobe usbcore | 130 | modprobe usbcore |
| 121 | modprobe usb-ohci | 131 | modprobe usb-ohci |
| 122 | modprobe rio500 | 132 | modprobe rio500 |
| 123 | 133 | ||
| 124 | UHCI: | 134 | UHCI:: |
| 135 | |||
| 125 | modprobe usbcore | 136 | modprobe usbcore |
| 126 | modprobe usb-uhci (or uhci) | 137 | modprobe usb-uhci (or uhci) |
| 127 | modprobe rio500 | 138 | modprobe rio500 |
| @@ -129,10 +140,10 @@ Load the appropriate modules (if compiled as modules): | |||
| 129 | That's it. The Rio500 Utils at: http://rio500.sourceforge.net should | 140 | That's it. The Rio500 Utils at: http://rio500.sourceforge.net should |
| 130 | be able to access the rio500. | 141 | be able to access the rio500. |
| 131 | 142 | ||
| 132 | BUGS | 143 | Bugs |
| 144 | ==== | ||
| 133 | 145 | ||
| 134 | If you encounter any problems feel free to drop me an email. | 146 | If you encounter any problems feel free to drop me an email. |
| 135 | 147 | ||
| 136 | Bruce Tenison | 148 | Bruce Tenison |
| 137 | btenison@dibbs.net | 149 | btenison@dibbs.net |
| 138 | |||
diff --git a/Documentation/usb/usb-help.txt b/Documentation/usb/usb-help.txt index 4273ca2b86ba..dc23ecd4d802 100644 --- a/Documentation/usb/usb-help.txt +++ b/Documentation/usb/usb-help.txt | |||
| @@ -1,16 +1,17 @@ | |||
| 1 | usb-help.txt | 1 | ============== |
| 2 | USB references | ||
| 3 | ============== | ||
| 4 | |||
| 2 | 2008-Mar-7 | 5 | 2008-Mar-7 |
| 3 | 6 | ||
| 4 | For USB help other than the readme files that are located in | 7 | For USB help other than the readme files that are located in |
| 5 | Documentation/usb/*, see the following: | 8 | `Documentation/usb/*`, see the following: |
| 6 | 9 | ||
| 7 | Linux-USB project: http://www.linux-usb.org | 10 | - Linux-USB project: http://www.linux-usb.org |
| 8 | mirrors at http://usb.in.tum.de/linux-usb/ | 11 | mirrors at http://usb.in.tum.de/linux-usb/ |
| 9 | and http://it.linux-usb.org | 12 | and http://it.linux-usb.org |
| 10 | Linux USB Guide: http://linux-usb.sourceforge.net | 13 | - Linux USB Guide: http://linux-usb.sourceforge.net |
| 11 | Linux-USB device overview (working devices and drivers): | 14 | - Linux-USB device overview (working devices and drivers): |
| 12 | http://www.qbik.ch/usb/devices/ | 15 | http://www.qbik.ch/usb/devices/ |
| 13 | 16 | ||
| 14 | The Linux-USB mailing list is at linux-usb@vger.kernel.org | 17 | The Linux-USB mailing list is at linux-usb@vger.kernel.org |
| 15 | |||
| 16 | ### | ||
diff --git a/Documentation/usb/usb-serial.txt b/Documentation/usb/usb-serial.txt index ab100d6ee436..8fa7dbd3da9a 100644 --- a/Documentation/usb/usb-serial.txt +++ b/Documentation/usb/usb-serial.txt | |||
| @@ -1,4 +1,9 @@ | |||
| 1 | INTRODUCTION | 1 | ========== |
| 2 | USB serial | ||
| 3 | ========== | ||
| 4 | |||
| 5 | Introduction | ||
| 6 | ============ | ||
| 2 | 7 | ||
| 3 | The USB serial driver currently supports a number of different USB to | 8 | The USB serial driver currently supports a number of different USB to |
| 4 | serial converter products, as well as some devices that use a serial | 9 | serial converter products, as well as some devices that use a serial |
| @@ -8,13 +13,15 @@ INTRODUCTION | |||
| 8 | the different devices. | 13 | the different devices. |
| 9 | 14 | ||
| 10 | 15 | ||
| 11 | CONFIGURATION | 16 | Configuration |
| 17 | ============= | ||
| 12 | 18 | ||
| 13 | Currently the driver can handle up to 256 different serial interfaces at | 19 | Currently the driver can handle up to 256 different serial interfaces at |
| 14 | one time. | 20 | one time. |
| 15 | 21 | ||
| 16 | The major number that the driver uses is 188 so to use the driver, | 22 | The major number that the driver uses is 188 so to use the driver, |
| 17 | create the following nodes: | 23 | create the following nodes:: |
| 24 | |||
| 18 | mknod /dev/ttyUSB0 c 188 0 | 25 | mknod /dev/ttyUSB0 c 188 0 |
| 19 | mknod /dev/ttyUSB1 c 188 1 | 26 | mknod /dev/ttyUSB1 c 188 1 |
| 20 | mknod /dev/ttyUSB2 c 188 2 | 27 | mknod /dev/ttyUSB2 c 188 2 |
| @@ -28,12 +35,14 @@ CONFIGURATION | |||
| 28 | When the device is connected and recognized by the driver, the driver | 35 | When the device is connected and recognized by the driver, the driver |
| 29 | will print to the system log, which node(s) the device has been bound | 36 | will print to the system log, which node(s) the device has been bound |
| 30 | to. | 37 | to. |
| 31 | |||
| 32 | 38 | ||
| 33 | SPECIFIC DEVICES SUPPORTED | 39 | |
| 40 | Specific Devices Supported | ||
| 41 | ========================== | ||
| 34 | 42 | ||
| 35 | 43 | ||
| 36 | ConnectTech WhiteHEAT 4 port converter | 44 | ConnectTech WhiteHEAT 4 port converter |
| 45 | -------------------------------------- | ||
| 37 | 46 | ||
| 38 | ConnectTech has been very forthcoming with information about their | 47 | ConnectTech has been very forthcoming with information about their |
| 39 | device, including providing a unit to test with. | 48 | device, including providing a unit to test with. |
| @@ -46,6 +55,7 @@ ConnectTech WhiteHEAT 4 port converter | |||
| 46 | 55 | ||
| 47 | 56 | ||
| 48 | HandSpring Visor, Palm USB, and Clié USB driver | 57 | HandSpring Visor, Palm USB, and Clié USB driver |
| 58 | ----------------------------------------------- | ||
| 49 | 59 | ||
| 50 | This driver works with all HandSpring USB, Palm USB, and Sony Clié USB | 60 | This driver works with all HandSpring USB, Palm USB, and Sony Clié USB |
| 51 | devices. | 61 | devices. |
| @@ -62,7 +72,7 @@ HandSpring Visor, Palm USB, and Clié USB driver | |||
| 62 | This goes against the current documentation for pilot-xfer and other | 72 | This goes against the current documentation for pilot-xfer and other |
| 63 | packages, but is the only way that it will work due to the hardware | 73 | packages, but is the only way that it will work due to the hardware |
| 64 | in the device. | 74 | in the device. |
| 65 | 75 | ||
| 66 | When the device is connected, try talking to it on the second port | 76 | When the device is connected, try talking to it on the second port |
| 67 | (this is usually /dev/ttyUSB1 if you do not have any other usb-serial | 77 | (this is usually /dev/ttyUSB1 if you do not have any other usb-serial |
| 68 | devices in the system.) The system log should tell you which port is | 78 | devices in the system.) The system log should tell you which port is |
| @@ -78,10 +88,10 @@ HandSpring Visor, Palm USB, and Clié USB driver | |||
| 78 | try resetting the device, first a hot reset, and then a cold reset if | 88 | try resetting the device, first a hot reset, and then a cold reset if |
| 79 | necessary. Some devices need this before they can talk to the USB port | 89 | necessary. Some devices need this before they can talk to the USB port |
| 80 | properly. | 90 | properly. |
| 81 | 91 | ||
| 82 | Devices that are not compiled into the kernel can be specified with module | 92 | Devices that are not compiled into the kernel can be specified with module |
| 83 | parameters. e.g. modprobe visor vendor=0x54c product=0x66 | 93 | parameters. e.g. modprobe visor vendor=0x54c product=0x66 |
| 84 | 94 | ||
| 85 | There is a webpage and mailing lists for this portion of the driver at: | 95 | There is a webpage and mailing lists for this portion of the driver at: |
| 86 | http://sourceforge.net/projects/usbvisor/ | 96 | http://sourceforge.net/projects/usbvisor/ |
| 87 | 97 | ||
| @@ -90,6 +100,7 @@ HandSpring Visor, Palm USB, and Clié USB driver | |||
| 90 | 100 | ||
| 91 | 101 | ||
| 92 | PocketPC PDA Driver | 102 | PocketPC PDA Driver |
| 103 | ------------------- | ||
| 93 | 104 | ||
| 94 | This driver can be used to connect to Compaq iPAQ, HP Jornada, Casio EM500 | 105 | This driver can be used to connect to Compaq iPAQ, HP Jornada, Casio EM500 |
| 95 | and other PDAs running Windows CE 3.0 or PocketPC 2002 using a USB | 106 | and other PDAs running Windows CE 3.0 or PocketPC 2002 using a USB |
| @@ -135,12 +146,13 @@ PocketPC PDA Driver | |||
| 135 | be used to flash the ROM, as well as the microP code.. so much for needing | 146 | be used to flash the ROM, as well as the microP code.. so much for needing |
| 136 | Toshiba's $350 serial cable for flashing!! :D | 147 | Toshiba's $350 serial cable for flashing!! :D |
| 137 | NOTE: This has NOT been tested. Use at your own risk. | 148 | NOTE: This has NOT been tested. Use at your own risk. |
| 138 | 149 | ||
| 139 | For any questions or problems with the driver, please contact Ganesh | 150 | For any questions or problems with the driver, please contact Ganesh |
| 140 | Varadarajan <ganesh@veritas.com> | 151 | Varadarajan <ganesh@veritas.com> |
| 141 | 152 | ||
| 142 | 153 | ||
| 143 | Keyspan PDA Serial Adapter | 154 | Keyspan PDA Serial Adapter |
| 155 | -------------------------- | ||
| 144 | 156 | ||
| 145 | Single port DB-9 serial adapter, pushed as a PDA adapter for iMacs (mostly | 157 | Single port DB-9 serial adapter, pushed as a PDA adapter for iMacs (mostly |
| 146 | sold in Macintosh catalogs, comes in a translucent white/green dongle). | 158 | sold in Macintosh catalogs, comes in a translucent white/green dongle). |
| @@ -148,32 +160,37 @@ Keyspan PDA Serial Adapter | |||
| 148 | This driver also works for the Xircom/Entrega single port serial adapter. | 160 | This driver also works for the Xircom/Entrega single port serial adapter. |
| 149 | 161 | ||
| 150 | Current status: | 162 | Current status: |
| 163 | |||
| 151 | Things that work: | 164 | Things that work: |
| 152 | basic input/output (tested with 'cu') | 165 | - basic input/output (tested with 'cu') |
| 153 | blocking write when serial line can't keep up | 166 | - blocking write when serial line can't keep up |
| 154 | changing baud rates (up to 115200) | 167 | - changing baud rates (up to 115200) |
| 155 | getting/setting modem control pins (TIOCM{GET,SET,BIS,BIC}) | 168 | - getting/setting modem control pins (TIOCM{GET,SET,BIS,BIC}) |
| 156 | sending break (although duration looks suspect) | 169 | - sending break (although duration looks suspect) |
| 170 | |||
| 157 | Things that don't: | 171 | Things that don't: |
| 158 | device strings (as logged by kernel) have trailing binary garbage | 172 | - device strings (as logged by kernel) have trailing binary garbage |
| 159 | device ID isn't right, might collide with other Keyspan products | 173 | - device ID isn't right, might collide with other Keyspan products |
| 160 | changing baud rates ought to flush tx/rx to avoid mangled half characters | 174 | - changing baud rates ought to flush tx/rx to avoid mangled half characters |
| 175 | |||
| 161 | Big Things on the todo list: | 176 | Big Things on the todo list: |
| 162 | parity, 7 vs 8 bits per char, 1 or 2 stop bits | 177 | - parity, 7 vs 8 bits per char, 1 or 2 stop bits |
| 163 | HW flow control | 178 | - HW flow control |
| 164 | not all of the standard USB descriptors are handled: Get_Status, Set_Feature | 179 | - not all of the standard USB descriptors are handled: |
| 165 | O_NONBLOCK, select() | 180 | Get_Status, Set_Feature, O_NONBLOCK, select() |
| 166 | 181 | ||
| 167 | For any questions or problems with this driver, please contact Brian | 182 | For any questions or problems with this driver, please contact Brian |
| 168 | Warner at warner@lothar.com | 183 | Warner at warner@lothar.com |
| 169 | 184 | ||
| 170 | 185 | ||
| 171 | Keyspan USA-series Serial Adapters | 186 | Keyspan USA-series Serial Adapters |
| 187 | ---------------------------------- | ||
| 172 | 188 | ||
| 173 | Single, Dual and Quad port adapters - driver uses Keyspan supplied | 189 | Single, Dual and Quad port adapters - driver uses Keyspan supplied |
| 174 | firmware and is being developed with their support. | 190 | firmware and is being developed with their support. |
| 175 | 191 | ||
| 176 | Current status: | 192 | Current status: |
| 193 | |||
| 177 | The USA-18X, USA-28X, USA-19, USA-19W and USA-49W are supported and | 194 | The USA-18X, USA-28X, USA-19, USA-19W and USA-49W are supported and |
| 178 | have been pretty thoroughly tested at various baud rates with 8-N-1 | 195 | have been pretty thoroughly tested at various baud rates with 8-N-1 |
| 179 | character settings. Other character lengths and parity setups are | 196 | character settings. Other character lengths and parity setups are |
| @@ -182,32 +199,37 @@ Keyspan USA-series Serial Adapters | |||
| 182 | The USA-28 isn't yet supported though doing so should be pretty | 199 | The USA-28 isn't yet supported though doing so should be pretty |
| 183 | straightforward. Contact the maintainer if you require this | 200 | straightforward. Contact the maintainer if you require this |
| 184 | functionality. | 201 | functionality. |
| 185 | 202 | ||
| 186 | More information is available at: | 203 | More information is available at: |
| 204 | |||
| 187 | http://www.carnationsoftware.com/carnation/Keyspan.html | 205 | http://www.carnationsoftware.com/carnation/Keyspan.html |
| 188 | 206 | ||
| 189 | For any questions or problems with this driver, please contact Hugh | 207 | For any questions or problems with this driver, please contact Hugh |
| 190 | Blemings at hugh@misc.nu | 208 | Blemings at hugh@misc.nu |
| 191 | 209 | ||
| 192 | 210 | ||
| 193 | FTDI Single Port Serial Driver | 211 | FTDI Single Port Serial Driver |
| 212 | ------------------------------ | ||
| 194 | 213 | ||
| 195 | This is a single port DB-25 serial adapter. | 214 | This is a single port DB-25 serial adapter. |
| 196 | 215 | ||
| 197 | Devices supported include: | 216 | Devices supported include: |
| 198 | -TripNav TN-200 USB GPS | 217 | |
| 199 | -Navis Engineering Bureau CH-4711 USB GPS | 218 | - TripNav TN-200 USB GPS |
| 219 | - Navis Engineering Bureau CH-4711 USB GPS | ||
| 200 | 220 | ||
| 201 | For any questions or problems with this driver, please contact Bill Ryder. | 221 | For any questions or problems with this driver, please contact Bill Ryder. |
| 202 | 222 | ||
| 203 | 223 | ||
| 204 | ZyXEL omni.net lcd plus ISDN TA | 224 | ZyXEL omni.net lcd plus ISDN TA |
| 225 | ------------------------------- | ||
| 205 | 226 | ||
| 206 | This is an ISDN TA. Please report both successes and troubles to | 227 | This is an ISDN TA. Please report both successes and troubles to |
| 207 | azummo@towertech.it | 228 | azummo@towertech.it |
| 208 | 229 | ||
| 209 | 230 | ||
| 210 | Cypress M8 CY4601 Family Serial Driver | 231 | Cypress M8 CY4601 Family Serial Driver |
| 232 | -------------------------------------- | ||
| 211 | 233 | ||
| 212 | This driver was in most part developed by Neil "koyama" Whelchel. It | 234 | This driver was in most part developed by Neil "koyama" Whelchel. It |
| 213 | has been improved since that previous form to support dynamic serial | 235 | has been improved since that previous form to support dynamic serial |
| @@ -215,18 +237,19 @@ Cypress M8 CY4601 Family Serial Driver | |||
| 215 | part stable and has been tested on an smp machine. (dual p2) | 237 | part stable and has been tested on an smp machine. (dual p2) |
| 216 | 238 | ||
| 217 | Chipsets supported under CY4601 family: | 239 | Chipsets supported under CY4601 family: |
| 218 | 240 | ||
| 219 | CY7C63723, CY7C63742, CY7C63743, CY7C64013 | 241 | CY7C63723, CY7C63742, CY7C63743, CY7C64013 |
| 220 | 242 | ||
| 221 | Devices supported: | 243 | Devices supported: |
| 222 | 244 | ||
| 223 | -DeLorme's USB Earthmate GPS (SiRF Star II lp arch) | 245 | - DeLorme's USB Earthmate GPS (SiRF Star II lp arch) |
| 224 | -Cypress HID->COM RS232 adapter | 246 | - Cypress HID->COM RS232 adapter |
| 225 | 247 | ||
| 226 | Note: Cypress Semiconductor claims no affiliation with the | 248 | Note: |
| 249 | Cypress Semiconductor claims no affiliation with the | ||
| 227 | hid->com device. | 250 | hid->com device. |
| 228 | 251 | ||
| 229 | Most devices using chipsets under the CY4601 family should | 252 | Most devices using chipsets under the CY4601 family should |
| 230 | work with the driver. As long as they stay true to the CY4601 | 253 | work with the driver. As long as they stay true to the CY4601 |
| 231 | usbserial specification. | 254 | usbserial specification. |
| 232 | 255 | ||
| @@ -236,8 +259,9 @@ Cypress M8 CY4601 Family Serial Driver | |||
| 236 | upon start init to this setting. usbserial core provides the rest | 259 | upon start init to this setting. usbserial core provides the rest |
| 237 | of the termios settings, along with some custom termios so that the | 260 | of the termios settings, along with some custom termios so that the |
| 238 | output is in proper format and parsable. | 261 | output is in proper format and parsable. |
| 239 | 262 | ||
| 240 | The device can be put into sirf mode by issuing NMEA command: | 263 | The device can be put into sirf mode by issuing NMEA command:: |
| 264 | |||
| 241 | $PSRF100,<protocol>,<baud>,<databits>,<stopbits>,<parity>*CHECKSUM | 265 | $PSRF100,<protocol>,<baud>,<databits>,<stopbits>,<parity>*CHECKSUM |
| 242 | $PSRF100,0,9600,8,1,0*0C | 266 | $PSRF100,0,9600,8,1,0*0C |
| 243 | 267 | ||
| @@ -259,11 +283,14 @@ Cypress M8 CY4601 Family Serial Driver | |||
| 259 | 283 | ||
| 260 | If you have any questions, problems, patches, feature requests, etc. you can | 284 | If you have any questions, problems, patches, feature requests, etc. you can |
| 261 | contact me here via email: | 285 | contact me here via email: |
| 286 | |||
| 262 | dignome@gmail.com | 287 | dignome@gmail.com |
| 288 | |||
| 263 | (your problems/patches can alternately be submitted to usb-devel) | 289 | (your problems/patches can alternately be submitted to usb-devel) |
| 264 | 290 | ||
| 265 | 291 | ||
| 266 | Digi AccelePort Driver | 292 | Digi AccelePort Driver |
| 293 | ---------------------- | ||
| 267 | 294 | ||
| 268 | This driver supports the Digi AccelePort USB 2 and 4 devices, 2 port | 295 | This driver supports the Digi AccelePort USB 2 and 4 devices, 2 port |
| 269 | (plus a parallel port) and 4 port USB serial converters. The driver | 296 | (plus a parallel port) and 4 port USB serial converters. The driver |
| @@ -285,42 +312,49 @@ Digi AccelePort Driver | |||
| 285 | 312 | ||
| 286 | 313 | ||
| 287 | Belkin USB Serial Adapter F5U103 | 314 | Belkin USB Serial Adapter F5U103 |
| 315 | -------------------------------- | ||
| 288 | 316 | ||
| 289 | Single port DB-9/PS-2 serial adapter from Belkin with firmware by eTEK Labs. | 317 | Single port DB-9/PS-2 serial adapter from Belkin with firmware by eTEK Labs. |
| 290 | The Peracom single port serial adapter also works with this driver, as | 318 | The Peracom single port serial adapter also works with this driver, as |
| 291 | well as the GoHubs adapter. | 319 | well as the GoHubs adapter. |
| 292 | 320 | ||
| 293 | Current status: | 321 | Current status: |
| 322 | |||
| 294 | The following have been tested and work: | 323 | The following have been tested and work: |
| 295 | Baud rate 300-230400 | 324 | |
| 296 | Data bits 5-8 | 325 | - Baud rate 300-230400 |
| 297 | Stop bits 1-2 | 326 | - Data bits 5-8 |
| 298 | Parity N,E,O,M,S | 327 | - Stop bits 1-2 |
| 299 | Handshake None, Software (XON/XOFF), Hardware (CTSRTS,CTSDTR)* | 328 | - Parity N,E,O,M,S |
| 300 | Break Set and clear | 329 | - Handshake None, Software (XON/XOFF), Hardware (CTSRTS,CTSDTR) [1]_ |
| 301 | Line control Input/Output query and control ** | 330 | - Break Set and clear |
| 302 | 331 | - Line control Input/Output query and control [2]_ | |
| 303 | * Hardware input flow control is only enabled for firmware | 332 | |
| 333 | .. [1] | ||
| 334 | Hardware input flow control is only enabled for firmware | ||
| 304 | levels above 2.06. Read source code comments describing Belkin | 335 | levels above 2.06. Read source code comments describing Belkin |
| 305 | firmware errata. Hardware output flow control is working for all | 336 | firmware errata. Hardware output flow control is working for all |
| 306 | firmware versions. | 337 | firmware versions. |
| 307 | ** Queries of inputs (CTS,DSR,CD,RI) show the last | 338 | |
| 339 | .. [2] | ||
| 340 | Queries of inputs (CTS,DSR,CD,RI) show the last | ||
| 308 | reported state. Queries of outputs (DTR,RTS) show the last | 341 | reported state. Queries of outputs (DTR,RTS) show the last |
| 309 | requested state and may not reflect current state as set by | 342 | requested state and may not reflect current state as set by |
| 310 | automatic hardware flow control. | 343 | automatic hardware flow control. |
| 311 | 344 | ||
| 312 | TO DO List: | 345 | TO DO List: |
| 313 | -- Add true modem control line query capability. Currently tracks the | 346 | - Add true modem control line query capability. Currently tracks the |
| 314 | states reported by the interrupt and the states requested. | 347 | states reported by the interrupt and the states requested. |
| 315 | -- Add error reporting back to application for UART error conditions. | 348 | - Add error reporting back to application for UART error conditions. |
| 316 | -- Add support for flush ioctls. | 349 | - Add support for flush ioctls. |
| 317 | -- Add everything else that is missing :) | 350 | - Add everything else that is missing :) |
| 318 | 351 | ||
| 319 | For any questions or problems with this driver, please contact William | 352 | For any questions or problems with this driver, please contact William |
| 320 | Greathouse at wgreathouse@smva.com | 353 | Greathouse at wgreathouse@smva.com |
| 321 | 354 | ||
| 322 | 355 | ||
| 323 | Empeg empeg-car Mark I/II Driver | 356 | Empeg empeg-car Mark I/II Driver |
| 357 | -------------------------------- | ||
| 324 | 358 | ||
| 325 | This is an experimental driver to provide connectivity support for the | 359 | This is an experimental driver to provide connectivity support for the |
| 326 | client synchronization tools for an Empeg empeg-car mp3 player. | 360 | client synchronization tools for an Empeg empeg-car mp3 player. |
| @@ -335,6 +369,7 @@ Empeg empeg-car Mark I/II Driver | |||
| 335 | 369 | ||
| 336 | 370 | ||
| 337 | MCT USB Single Port Serial Adapter U232 | 371 | MCT USB Single Port Serial Adapter U232 |
| 372 | --------------------------------------- | ||
| 338 | 373 | ||
| 339 | This driver is for the MCT USB-RS232 Converter (25 pin, Model No. | 374 | This driver is for the MCT USB-RS232 Converter (25 pin, Model No. |
| 340 | U232-P25) from Magic Control Technology Corp. (there is also a 9 pin | 375 | U232-P25) from Magic Control Technology Corp. (there is also a 9 pin |
| @@ -355,35 +390,39 @@ MCT USB Single Port Serial Adapter U232 | |||
| 355 | 390 | ||
| 356 | 391 | ||
| 357 | Inside Out Networks Edgeport Driver | 392 | Inside Out Networks Edgeport Driver |
| 393 | ----------------------------------- | ||
| 358 | 394 | ||
| 359 | This driver supports all devices made by Inside Out Networks, specifically | 395 | This driver supports all devices made by Inside Out Networks, specifically |
| 360 | the following models: | 396 | the following models: |
| 361 | Edgeport/4 | 397 | |
| 362 | Rapidport/4 | 398 | - Edgeport/4 |
| 363 | Edgeport/4t | 399 | - Rapidport/4 |
| 364 | Edgeport/2 | 400 | - Edgeport/4t |
| 365 | Edgeport/4i | 401 | - Edgeport/2 |
| 366 | Edgeport/2i | 402 | - Edgeport/4i |
| 367 | Edgeport/421 | 403 | - Edgeport/2i |
| 368 | Edgeport/21 | 404 | - Edgeport/421 |
| 369 | Edgeport/8 | 405 | - Edgeport/21 |
| 370 | Edgeport/8 Dual | 406 | - Edgeport/8 |
| 371 | Edgeport/2D8 | 407 | - Edgeport/8 Dual |
| 372 | Edgeport/4D8 | 408 | - Edgeport/2D8 |
| 373 | Edgeport/8i | 409 | - Edgeport/4D8 |
| 374 | Edgeport/2 DIN | 410 | - Edgeport/8i |
| 375 | Edgeport/4 DIN | 411 | - Edgeport/2 DIN |
| 376 | Edgeport/16 Dual | 412 | - Edgeport/4 DIN |
| 413 | - Edgeport/16 Dual | ||
| 377 | 414 | ||
| 378 | For any questions or problems with this driver, please contact Greg | 415 | For any questions or problems with this driver, please contact Greg |
| 379 | Kroah-Hartman at greg@kroah.com | 416 | Kroah-Hartman at greg@kroah.com |
| 380 | 417 | ||
| 381 | 418 | ||
| 382 | REINER SCT cyberJack pinpad/e-com USB chipcard reader | 419 | REINER SCT cyberJack pinpad/e-com USB chipcard reader |
| 383 | 420 | ----------------------------------------------------- | |
| 421 | |||
| 384 | Interface to ISO 7816 compatible contactbased chipcards, e.g. GSM SIMs. | 422 | Interface to ISO 7816 compatible contactbased chipcards, e.g. GSM SIMs. |
| 385 | 423 | ||
| 386 | Current status: | 424 | Current status: |
| 425 | |||
| 387 | This is the kernel part of the driver for this USB card reader. | 426 | This is the kernel part of the driver for this USB card reader. |
| 388 | There is also a user part for a CT-API driver available. A site | 427 | There is also a user part for a CT-API driver available. A site |
| 389 | for downloading is TBA. For now, you can request it from the | 428 | for downloading is TBA. For now, you can request it from the |
| @@ -394,6 +433,7 @@ REINER SCT cyberJack pinpad/e-com USB chipcard reader | |||
| 394 | 433 | ||
| 395 | 434 | ||
| 396 | Prolific PL2303 Driver | 435 | Prolific PL2303 Driver |
| 436 | ---------------------- | ||
| 397 | 437 | ||
| 398 | This driver supports any device that has the PL2303 chip from Prolific | 438 | This driver supports any device that has the PL2303 chip from Prolific |
| 399 | in it. This includes a number of single port USB to serial converters, | 439 | in it. This includes a number of single port USB to serial converters, |
| @@ -403,11 +443,13 @@ Prolific PL2303 Driver | |||
| 403 | 443 | ||
| 404 | For any questions or problems with this driver, please contact Greg | 444 | For any questions or problems with this driver, please contact Greg |
| 405 | Kroah-Hartman at greg@kroah.com | 445 | Kroah-Hartman at greg@kroah.com |
| 406 | 446 | ||
| 407 | 447 | ||
| 408 | KL5KUSB105 chipset / PalmConnect USB single-port adapter | 448 | KL5KUSB105 chipset / PalmConnect USB single-port adapter |
| 409 | 449 | -------------------------------------------------------- | |
| 450 | |||
| 410 | Current status: | 451 | Current status: |
| 452 | |||
| 411 | The driver was put together by looking at the usb bus transactions | 453 | The driver was put together by looking at the usb bus transactions |
| 412 | done by Palm's driver under Windows, so a lot of functionality is | 454 | done by Palm's driver under Windows, so a lot of functionality is |
| 413 | still missing. Notably, serial ioctls are sometimes faked or not yet | 455 | still missing. Notably, serial ioctls are sometimes faked or not yet |
| @@ -417,21 +459,25 @@ Current status: | |||
| 417 | are supported, but handshaking (software or hardware) is not, which is | 459 | are supported, but handshaking (software or hardware) is not, which is |
| 418 | why it is wise to cut down on the rate used is wise for large | 460 | why it is wise to cut down on the rate used is wise for large |
| 419 | transfers until this is settled. | 461 | transfers until this is settled. |
| 420 | 462 | ||
| 421 | See http://www.uuhaus.de/linux/palmconnect.html for up-to-date | 463 | See http://www.uuhaus.de/linux/palmconnect.html for up-to-date |
| 422 | information on this driver. | 464 | information on this driver. |
| 423 | 465 | ||
| 424 | Winchiphead CH341 Driver | 466 | Winchiphead CH341 Driver |
| 467 | ------------------------ | ||
| 425 | 468 | ||
| 426 | This driver is for the Winchiphead CH341 USB-RS232 Converter. This chip | 469 | This driver is for the Winchiphead CH341 USB-RS232 Converter. This chip |
| 427 | also implements an IEEE 1284 parallel port, I2C and SPI, but that is not | 470 | also implements an IEEE 1284 parallel port, I2C and SPI, but that is not |
| 428 | supported by the driver. The protocol was analyzed from the behaviour | 471 | supported by the driver. The protocol was analyzed from the behaviour |
| 429 | of the Windows driver, no datasheet is available at present. | 472 | of the Windows driver, no datasheet is available at present. |
| 473 | |||
| 430 | The manufacturer's website: http://www.winchiphead.com/. | 474 | The manufacturer's website: http://www.winchiphead.com/. |
| 475 | |||
| 431 | For any questions or problems with this driver, please contact | 476 | For any questions or problems with this driver, please contact |
| 432 | frank@kingswood-consulting.co.uk. | 477 | frank@kingswood-consulting.co.uk. |
| 433 | 478 | ||
| 434 | Moschip MCS7720, MCS7715 driver | 479 | Moschip MCS7720, MCS7715 driver |
| 480 | ------------------------------- | ||
| 435 | 481 | ||
| 436 | These chips are present in devices sold by various manufacturers, such as Syba | 482 | These chips are present in devices sold by various manufacturers, such as Syba |
| 437 | and Cables Unlimited. There may be others. The 7720 provides two serial | 483 | and Cables Unlimited. There may be others. The 7720 provides two serial |
| @@ -449,20 +495,24 @@ Moschip MCS7720, MCS7715 driver | |||
| 449 | don't have one of these devices, so I can't say for sure. | 495 | don't have one of these devices, so I can't say for sure. |
| 450 | 496 | ||
| 451 | Generic Serial driver | 497 | Generic Serial driver |
| 498 | --------------------- | ||
| 452 | 499 | ||
| 453 | If your device is not one of the above listed devices, compatible with | 500 | If your device is not one of the above listed devices, compatible with |
| 454 | the above models, you can try out the "generic" interface. This | 501 | the above models, you can try out the "generic" interface. This |
| 455 | interface does not provide any type of control messages sent to the | 502 | interface does not provide any type of control messages sent to the |
| 456 | device, and does not support any kind of device flow control. All that | 503 | device, and does not support any kind of device flow control. All that |
| 457 | is required of your device is that it has at least one bulk in endpoint, | 504 | is required of your device is that it has at least one bulk in endpoint, |
| 458 | or one bulk out endpoint. | 505 | or one bulk out endpoint. |
| 506 | |||
| 507 | To enable the generic driver to recognize your device, provide:: | ||
| 459 | 508 | ||
| 460 | To enable the generic driver to recognize your device, provide | ||
| 461 | echo <vid> <pid> >/sys/bus/usb-serial/drivers/generic/new_id | 509 | echo <vid> <pid> >/sys/bus/usb-serial/drivers/generic/new_id |
| 510 | |||
| 462 | where the <vid> and <pid> is replaced with the hex representation of your | 511 | where the <vid> and <pid> is replaced with the hex representation of your |
| 463 | device's vendor id and product id. | 512 | device's vendor id and product id. |
| 464 | If the driver is compiled as a module you can also provide one id when | 513 | If the driver is compiled as a module you can also provide one id when |
| 465 | loading the module | 514 | loading the module:: |
| 515 | |||
| 466 | insmod usbserial vendor=0x#### product=0x#### | 516 | insmod usbserial vendor=0x#### product=0x#### |
| 467 | 517 | ||
| 468 | This driver has been successfully used to connect to the NetChip USB | 518 | This driver has been successfully used to connect to the NetChip USB |
| @@ -473,7 +523,8 @@ Generic Serial driver | |||
| 473 | Kroah-Hartman at greg@kroah.com | 523 | Kroah-Hartman at greg@kroah.com |
| 474 | 524 | ||
| 475 | 525 | ||
| 476 | CONTACT: | 526 | Contact |
| 527 | ======= | ||
| 477 | 528 | ||
| 478 | If anyone has any problems using these drivers, with any of the above | 529 | If anyone has any problems using these drivers, with any of the above |
| 479 | specified products, please contact the specific driver's author listed | 530 | specified products, please contact the specific driver's author listed |
diff --git a/Documentation/usb/usbip_protocol.txt b/Documentation/usb/usbip_protocol.txt index c7a0f4c7e7f1..988c832166cd 100644 --- a/Documentation/usb/usbip_protocol.txt +++ b/Documentation/usb/usbip_protocol.txt | |||
| @@ -1,3 +1,7 @@ | |||
| 1 | =============== | ||
| 2 | USB/IP protocol | ||
| 3 | =============== | ||
| 4 | |||
| 1 | PRELIMINARY DRAFT, MAY CONTAIN MISTAKES! | 5 | PRELIMINARY DRAFT, MAY CONTAIN MISTAKES! |
| 2 | 28 Jun 2011 | 6 | 28 Jun 2011 |
| 3 | 7 | ||
| @@ -12,6 +16,8 @@ in one or more pieces at the low level transport layer). The server sends back | |||
| 12 | the OP_REP_DEVLIST packet which lists the exported USB devices. Finally the | 16 | the OP_REP_DEVLIST packet which lists the exported USB devices. Finally the |
| 13 | TCP/IP connection is closed. | 17 | TCP/IP connection is closed. |
| 14 | 18 | ||
| 19 | :: | ||
| 20 | |||
| 15 | virtual host controller usb host | 21 | virtual host controller usb host |
| 16 | "client" "server" | 22 | "client" "server" |
| 17 | (imports USB devices) (exports USB devices) | 23 | (imports USB devices) (exports USB devices) |
| @@ -32,6 +38,8 @@ send two types of packets: the USBIP_CMD_SUBMIT to submit an URB, and | |||
| 32 | USBIP_CMD_UNLINK to unlink a previously submitted URB. The answers of the | 38 | USBIP_CMD_UNLINK to unlink a previously submitted URB. The answers of the |
| 33 | server may be USBIP_RET_SUBMIT and USBIP_RET_UNLINK respectively. | 39 | server may be USBIP_RET_SUBMIT and USBIP_RET_UNLINK respectively. |
| 34 | 40 | ||
| 41 | :: | ||
| 42 | |||
| 35 | virtual host controller usb host | 43 | virtual host controller usb host |
| 36 | "client" "server" | 44 | "client" "server" |
| 37 | (imports USB devices) (exports USB devices) | 45 | (imports USB devices) (exports USB devices) |
| @@ -88,270 +96,316 @@ The fields are in network (big endian) byte order meaning that the most signific | |||
| 88 | byte (MSB) is stored at the lowest address. | 96 | byte (MSB) is stored at the lowest address. |
| 89 | 97 | ||
| 90 | 98 | ||
| 91 | OP_REQ_DEVLIST: Retrieve the list of exported USB devices. | 99 | OP_REQ_DEVLIST: |
| 100 | Retrieve the list of exported USB devices. | ||
| 92 | 101 | ||
| 93 | Offset | Length | Value | Description | 102 | +-----------+--------+------------+---------------------------------------------------+ |
| 94 | -----------+--------+------------+--------------------------------------------------- | 103 | | Offset | Length | Value | Description | |
| 95 | 0 | 2 | 0x0100 | Binary-coded decimal USBIP version number: v1.0.0 | 104 | +===========+========+============+===================================================+ |
| 96 | -----------+--------+------------+--------------------------------------------------- | 105 | | 0 | 2 | 0x0100 | Binary-coded decimal USBIP version number: v1.0.0 | |
| 97 | 2 | 2 | 0x8005 | Command code: Retrieve the list of exported USB | 106 | +-----------+--------+------------+---------------------------------------------------+ |
| 98 | | | | devices. | 107 | | 2 | 2 | 0x8005 | Command code: Retrieve the list of exported USB | |
| 99 | -----------+--------+------------+--------------------------------------------------- | 108 | | | | | devices. | |
| 100 | 4 | 4 | 0x00000000 | Status: unused, shall be set to 0 | 109 | +-----------+--------+------------+---------------------------------------------------+ |
| 110 | | 4 | 4 | 0x00000000 | Status: unused, shall be set to 0 | | ||
| 111 | +-----------+--------+------------+---------------------------------------------------+ | ||
| 101 | 112 | ||
| 102 | OP_REP_DEVLIST: Reply with the list of exported USB devices. | 113 | OP_REP_DEVLIST: |
| 114 | Reply with the list of exported USB devices. | ||
| 103 | 115 | ||
| 104 | Offset | Length | Value | Description | 116 | +-----------+--------+------------+---------------------------------------------------+ |
| 105 | -----------+--------+------------+--------------------------------------------------- | 117 | | Offset | Length | Value | Description | |
| 106 | 0 | 2 | 0x0100 | Binary-coded decimal USBIP version number: v1.0.0. | 118 | +===========+========+============+===================================================+ |
| 107 | -----------+--------+------------+--------------------------------------------------- | 119 | | 0 | 2 | 0x0100 | Binary-coded decimal USBIP version number: v1.0.0.| |
| 108 | 2 | 2 | 0x0005 | Reply code: The list of exported USB devices. | 120 | +-----------+--------+------------+---------------------------------------------------+ |
| 109 | -----------+--------+------------+--------------------------------------------------- | 121 | | 2 | 2 | 0x0005 | Reply code: The list of exported USB devices. | |
| 110 | 4 | 4 | 0x00000000 | Status: 0 for OK | 122 | +-----------+--------+------------+---------------------------------------------------+ |
| 111 | -----------+--------+------------+--------------------------------------------------- | 123 | | 4 | 4 | 0x00000000 | Status: 0 for OK | |
| 112 | 8 | 4 | n | Number of exported devices: 0 means no exported | 124 | +-----------+--------+------------+---------------------------------------------------+ |
| 113 | | | | devices. | 125 | | 8 | 4 | n | Number of exported devices: 0 means no exported | |
| 114 | -----------+--------+------------+--------------------------------------------------- | 126 | | | | | devices. | |
| 115 | 0x0C | | | From now on the exported n devices are described, | 127 | +-----------+--------+------------+---------------------------------------------------+ |
| 116 | | | | if any. If no devices are exported the message | 128 | | 0x0C | | | From now on the exported n devices are described, | |
| 117 | | | | ends with the previous "number of exported | 129 | | | | | if any. If no devices are exported the message | |
| 118 | | | | devices" field. | 130 | | | | | ends with the previous "number of exported | |
| 119 | -----------+--------+------------+--------------------------------------------------- | 131 | | | | | devices" field. | |
| 120 | | 256 | | path: Path of the device on the host exporting the | 132 | +-----------+--------+------------+---------------------------------------------------+ |
| 121 | | | | USB device, string closed with zero byte, e.g. | 133 | | | 256 | | path: Path of the device on the host exporting the| |
| 122 | | | | "/sys/devices/pci0000:00/0000:00:1d.1/usb3/3-2" | 134 | | | | | USB device, string closed with zero byte, e.g. | |
| 123 | | | | The unused bytes shall be filled with zero | 135 | | | | | "/sys/devices/pci0000:00/0000:00:1d.1/usb3/3-2" | |
| 124 | | | | bytes. | 136 | | | | | The unused bytes shall be filled with zero | |
| 125 | -----------+--------+------------+--------------------------------------------------- | 137 | | | | | bytes. | |
| 126 | 0x10C | 32 | | busid: Bus ID of the exported device, string | 138 | +-----------+--------+------------+---------------------------------------------------+ |
| 127 | | | | closed with zero byte, e.g. "3-2". The unused | 139 | | 0x10C | 32 | | busid: Bus ID of the exported device, string | |
| 128 | | | | bytes shall be filled with zero bytes. | 140 | | | | | closed with zero byte, e.g. "3-2". The unused | |
| 129 | -----------+--------+------------+--------------------------------------------------- | 141 | | | | | bytes shall be filled with zero bytes. | |
| 130 | 0x12C | 4 | | busnum | 142 | +-----------+--------+------------+---------------------------------------------------+ |
| 131 | -----------+--------+------------+--------------------------------------------------- | 143 | | 0x12C | 4 | | busnum | |
| 132 | 0x130 | 4 | | devnum | 144 | +-----------+--------+------------+---------------------------------------------------+ |
| 133 | -----------+--------+------------+--------------------------------------------------- | 145 | | 0x130 | 4 | | devnum | |
| 134 | 0x134 | 4 | | speed | 146 | +-----------+--------+------------+---------------------------------------------------+ |
| 135 | -----------+--------+------------+--------------------------------------------------- | 147 | | 0x134 | 4 | | speed | |
| 136 | 0x138 | 2 | | idVendor | 148 | +-----------+--------+------------+---------------------------------------------------+ |
| 137 | -----------+--------+------------+--------------------------------------------------- | 149 | | 0x138 | 2 | | idVendor | |
| 138 | 0x13A | 2 | | idProduct | 150 | +-----------+--------+------------+---------------------------------------------------+ |
| 139 | -----------+--------+------------+--------------------------------------------------- | 151 | | 0x13A | 2 | | idProduct | |
| 140 | 0x13C | 2 | | bcdDevice | 152 | +-----------+--------+------------+---------------------------------------------------+ |
| 141 | -----------+--------+------------+--------------------------------------------------- | 153 | | 0x13C | 2 | | bcdDevice | |
| 142 | 0x13E | 1 | | bDeviceClass | 154 | +-----------+--------+------------+---------------------------------------------------+ |
| 143 | -----------+--------+------------+--------------------------------------------------- | 155 | | 0x13E | 1 | | bDeviceClass | |
| 144 | 0x13F | 1 | | bDeviceSubClass | 156 | +-----------+--------+------------+---------------------------------------------------+ |
| 145 | -----------+--------+------------+--------------------------------------------------- | 157 | | 0x13F | 1 | | bDeviceSubClass | |
| 146 | 0x140 | 1 | | bDeviceProtocol | 158 | +-----------+--------+------------+---------------------------------------------------+ |
| 147 | -----------+--------+------------+--------------------------------------------------- | 159 | | 0x140 | 1 | | bDeviceProtocol | |
| 148 | 0x141 | 1 | | bConfigurationValue | 160 | +-----------+--------+------------+---------------------------------------------------+ |
| 149 | -----------+--------+------------+--------------------------------------------------- | 161 | | 0x141 | 1 | | bConfigurationValue | |
| 150 | 0x142 | 1 | | bNumConfigurations | 162 | +-----------+--------+------------+---------------------------------------------------+ |
| 151 | -----------+--------+------------+--------------------------------------------------- | 163 | | 0x142 | 1 | | bNumConfigurations | |
| 152 | 0x143 | 1 | | bNumInterfaces | 164 | +-----------+--------+------------+---------------------------------------------------+ |
| 153 | -----------+--------+------------+--------------------------------------------------- | 165 | | 0x143 | 1 | | bNumInterfaces | |
| 154 | 0x144 | | m_0 | From now on each interface is described, all | 166 | +-----------+--------+------------+---------------------------------------------------+ |
| 155 | | | | together bNumInterfaces times, with the | 167 | | 0x144 | | m_0 | From now on each interface is described, all | |
| 156 | | | | the following 4 fields: | 168 | | | | | together bNumInterfaces times, with the | |
| 157 | -----------+--------+------------+--------------------------------------------------- | 169 | | | | | the following 4 fields: | |
| 158 | | 1 | | bInterfaceClass | 170 | +-----------+--------+------------+---------------------------------------------------+ |
| 159 | -----------+--------+------------+--------------------------------------------------- | 171 | | | 1 | | bInterfaceClass | |
| 160 | 0x145 | 1 | | bInterfaceSubClass | 172 | +-----------+--------+------------+---------------------------------------------------+ |
| 161 | -----------+--------+------------+--------------------------------------------------- | 173 | | 0x145 | 1 | | bInterfaceSubClass | |
| 162 | 0x146 | 1 | | bInterfaceProtocol | 174 | +-----------+--------+------------+---------------------------------------------------+ |
| 163 | -----------+--------+------------+--------------------------------------------------- | 175 | | 0x146 | 1 | | bInterfaceProtocol | |
| 164 | 0x147 | 1 | | padding byte for alignment, shall be set to zero | 176 | +-----------+--------+------------+---------------------------------------------------+ |
| 165 | -----------+--------+------------+--------------------------------------------------- | 177 | | 0x147 | 1 | | padding byte for alignment, shall be set to zero | |
| 166 | 0xC + | | | The second exported USB device starts at i=1 | 178 | +-----------+--------+------------+---------------------------------------------------+ |
| 167 | i*0x138 + | | | with the busid field. | 179 | | 0xC + | | | The second exported USB device starts at i=1 | |
| 168 | m_(i-1)*4 | | | | 180 | | i*0x138 + | | | with the busid field. | |
| 181 | | m_(i-1)*4 | | | | | ||
| 182 | +-----------+--------+------------+---------------------------------------------------+ | ||
| 169 | 183 | ||
| 170 | OP_REQ_IMPORT: Request to import (attach) a remote USB device. | 184 | OP_REQ_IMPORT: |
| 185 | Request to import (attach) a remote USB device. | ||
| 171 | 186 | ||
| 172 | Offset | Length | Value | Description | 187 | +-----------+--------+------------+---------------------------------------------------+ |
| 173 | -----------+--------+------------+--------------------------------------------------- | 188 | | Offset | Length | Value | Description | |
| 174 | 0 | 2 | 0x0100 | Binary-coded decimal USBIP version number: v1.0.0 | 189 | +===========+========+============+===================================================+ |
| 175 | -----------+--------+------------+--------------------------------------------------- | 190 | | 0 | 2 | 0x0100 | Binary-coded decimal USBIP version number: v1.0.0 | |
| 176 | 2 | 2 | 0x8003 | Command code: import a remote USB device. | 191 | +-----------+--------+------------+---------------------------------------------------+ |
| 177 | -----------+--------+------------+--------------------------------------------------- | 192 | | 2 | 2 | 0x8003 | Command code: import a remote USB device. | |
| 178 | 4 | 4 | 0x00000000 | Status: unused, shall be set to 0 | 193 | +-----------+--------+------------+---------------------------------------------------+ |
| 179 | -----------+--------+------------+--------------------------------------------------- | 194 | | 4 | 4 | 0x00000000 | Status: unused, shall be set to 0 | |
| 180 | 8 | 32 | | busid: the busid of the exported device on the | 195 | +-----------+--------+------------+---------------------------------------------------+ |
| 181 | | | | remote host. The possible values are taken | 196 | | 8 | 32 | | busid: the busid of the exported device on the | |
| 182 | | | | from the message field OP_REP_DEVLIST.busid. | 197 | | | | | remote host. The possible values are taken | |
| 183 | | | | A string closed with zero, the unused bytes | 198 | | | | | from the message field OP_REP_DEVLIST.busid. | |
| 184 | | | | shall be filled with zeros. | 199 | | | | | A string closed with zero, the unused bytes | |
| 185 | -----------+--------+------------+--------------------------------------------------- | 200 | | | | | shall be filled with zeros. | |
| 201 | +-----------+--------+------------+---------------------------------------------------+ | ||
| 186 | 202 | ||
| 187 | OP_REP_IMPORT: Reply to import (attach) a remote USB device. | 203 | OP_REP_IMPORT: |
| 204 | Reply to import (attach) a remote USB device. | ||
| 188 | 205 | ||
| 189 | Offset | Length | Value | Description | 206 | +-----------+--------+------------+---------------------------------------------------+ |
| 190 | -----------+--------+------------+--------------------------------------------------- | 207 | | Offset | Length | Value | Description | |
| 191 | 0 | 2 | 0x0100 | Binary-coded decimal USBIP version number: v1.0.0 | 208 | +===========+========+============+===================================================+ |
| 192 | -----------+--------+------------+--------------------------------------------------- | 209 | | 0 | 2 | 0x0100 | Binary-coded decimal USBIP version number: v1.0.0 | |
| 193 | 2 | 2 | 0x0003 | Reply code: Reply to import. | 210 | +-----------+--------+------------+---------------------------------------------------+ |
| 194 | -----------+--------+------------+--------------------------------------------------- | 211 | | 2 | 2 | 0x0003 | Reply code: Reply to import. | |
| 195 | 4 | 4 | 0x00000000 | Status: 0 for OK | 212 | +-----------+--------+------------+---------------------------------------------------+ |
| 196 | | | | 1 for error | 213 | | 4 | 4 | 0x00000000 | Status: | |
| 197 | -----------+--------+------------+--------------------------------------------------- | 214 | | | | | | |
| 198 | 8 | | | From now on comes the details of the imported | 215 | | | | | - 0 for OK | |
| 199 | | | | device, if the previous status field was OK (0), | 216 | | | | | - 1 for error | |
| 200 | | | | otherwise the reply ends with the status field. | 217 | +-----------+--------+------------+---------------------------------------------------+ |
| 201 | -----------+--------+------------+--------------------------------------------------- | 218 | | 8 | | | From now on comes the details of the imported | |
| 202 | | 256 | | path: Path of the device on the host exporting the | 219 | | | | | device, if the previous status field was OK (0), | |
| 203 | | | | USB device, string closed with zero byte, e.g. | 220 | | | | | otherwise the reply ends with the status field. | |
| 204 | | | | "/sys/devices/pci0000:00/0000:00:1d.1/usb3/3-2" | 221 | +-----------+--------+------------+---------------------------------------------------+ |
| 205 | | | | The unused bytes shall be filled with zero | 222 | | | 256 | | path: Path of the device on the host exporting the| |
| 206 | | | | bytes. | 223 | | | | | USB device, string closed with zero byte, e.g. | |
| 207 | -----------+--------+------------+--------------------------------------------------- | 224 | | | | | "/sys/devices/pci0000:00/0000:00:1d.1/usb3/3-2" | |
| 208 | 0x108 | 32 | | busid: Bus ID of the exported device, string | 225 | | | | | The unused bytes shall be filled with zero | |
| 209 | | | | closed with zero byte, e.g. "3-2". The unused | 226 | | | | | bytes. | |
| 210 | | | | bytes shall be filled with zero bytes. | 227 | +-----------+--------+------------+---------------------------------------------------+ |
| 211 | -----------+--------+------------+--------------------------------------------------- | 228 | | 0x108 | 32 | | busid: Bus ID of the exported device, string | |
| 212 | 0x128 | 4 | | busnum | 229 | | | | | closed with zero byte, e.g. "3-2". The unused | |
| 213 | -----------+--------+------------+--------------------------------------------------- | 230 | | | | | bytes shall be filled with zero bytes. | |
| 214 | 0x12C | 4 | | devnum | 231 | +-----------+--------+------------+---------------------------------------------------+ |
| 215 | -----------+--------+------------+--------------------------------------------------- | 232 | | 0x128 | 4 | | busnum | |
| 216 | 0x130 | 4 | | speed | 233 | +-----------+--------+------------+---------------------------------------------------+ |
| 217 | -----------+--------+------------+--------------------------------------------------- | 234 | | 0x12C | 4 | | devnum | |
| 218 | 0x134 | 2 | | idVendor | 235 | +-----------+--------+------------+---------------------------------------------------+ |
| 219 | -----------+--------+------------+--------------------------------------------------- | 236 | | 0x130 | 4 | | speed | |
| 220 | 0x136 | 2 | | idProduct | 237 | +-----------+--------+------------+---------------------------------------------------+ |
| 221 | -----------+--------+------------+--------------------------------------------------- | 238 | | 0x134 | 2 | | idVendor | |
| 222 | 0x138 | 2 | | bcdDevice | 239 | +-----------+--------+------------+---------------------------------------------------+ |
| 223 | -----------+--------+------------+--------------------------------------------------- | 240 | | 0x136 | 2 | | idProduct | |
| 224 | 0x139 | 1 | | bDeviceClass | 241 | +-----------+--------+------------+---------------------------------------------------+ |
| 225 | -----------+--------+------------+--------------------------------------------------- | 242 | | 0x138 | 2 | | bcdDevice | |
| 226 | 0x13A | 1 | | bDeviceSubClass | 243 | +-----------+--------+------------+---------------------------------------------------+ |
| 227 | -----------+--------+------------+--------------------------------------------------- | 244 | | 0x139 | 1 | | bDeviceClass | |
| 228 | 0x13B | 1 | | bDeviceProtocol | 245 | +-----------+--------+------------+---------------------------------------------------+ |
| 229 | -----------+--------+------------+--------------------------------------------------- | 246 | | 0x13A | 1 | | bDeviceSubClass | |
| 230 | 0x13C | 1 | | bConfigurationValue | 247 | +-----------+--------+------------+---------------------------------------------------+ |
| 231 | -----------+--------+------------+--------------------------------------------------- | 248 | | 0x13B | 1 | | bDeviceProtocol | |
| 232 | 0x13D | 1 | | bNumConfigurations | 249 | +-----------+--------+------------+---------------------------------------------------+ |
| 233 | -----------+--------+------------+--------------------------------------------------- | 250 | | 0x13C | 1 | | bConfigurationValue | |
| 234 | 0x13E | 1 | | bNumInterfaces | 251 | +-----------+--------+------------+---------------------------------------------------+ |
| 252 | | 0x13D | 1 | | bNumConfigurations | | ||
| 253 | +-----------+--------+------------+---------------------------------------------------+ | ||
| 254 | | 0x13E | 1 | | bNumInterfaces | | ||
| 255 | +-----------+--------+------------+---------------------------------------------------+ | ||
| 235 | 256 | ||
| 236 | USBIP_CMD_SUBMIT: Submit an URB | 257 | USBIP_CMD_SUBMIT: |
| 258 | Submit an URB | ||
| 237 | 259 | ||
| 238 | Offset | Length | Value | Description | 260 | +-----------+--------+------------+---------------------------------------------------+ |
| 239 | -----------+--------+------------+--------------------------------------------------- | 261 | | Offset | Length | Value | Description | |
| 240 | 0 | 4 | 0x00000001 | command: Submit an URB | 262 | +===========+========+============+===================================================+ |
| 241 | -----------+--------+------------+--------------------------------------------------- | 263 | | 0 | 4 | 0x00000001 | command: Submit an URB | |
| 242 | 4 | 4 | | seqnum: the sequence number of the URB to submit | 264 | +-----------+--------+------------+---------------------------------------------------+ |
| 243 | -----------+--------+------------+--------------------------------------------------- | 265 | | 4 | 4 | | seqnum: the sequence number of the URB to submit | |
| 244 | 8 | 4 | | devid | 266 | +-----------+--------+------------+---------------------------------------------------+ |
| 245 | -----------+--------+------------+--------------------------------------------------- | 267 | | 8 | 4 | | devid | |
| 246 | 0xC | 4 | | direction: 0: USBIP_DIR_OUT | 268 | +-----------+--------+------------+---------------------------------------------------+ |
| 247 | | | | 1: USBIP_DIR_IN | 269 | | 0xC | 4 | | direction: | |
| 248 | -----------+--------+------------+--------------------------------------------------- | 270 | | | | | | |
| 249 | 0x10 | 4 | | ep: endpoint number, possible values are: 0...15 | 271 | | | | | - 0: USBIP_DIR_OUT | |
| 250 | -----------+--------+------------+--------------------------------------------------- | 272 | | | | | - 1: USBIP_DIR_IN | |
| 251 | 0x14 | 4 | | transfer_flags: possible values depend on the | 273 | +-----------+--------+------------+---------------------------------------------------+ |
| 252 | | | | URB transfer type, see below | 274 | | 0x10 | 4 | | ep: endpoint number, possible values are: 0...15 | |
| 253 | -----------+--------+------------+--------------------------------------------------- | 275 | +-----------+--------+------------+---------------------------------------------------+ |
| 254 | 0x18 | 4 | | transfer_buffer_length | 276 | | 0x14 | 4 | | transfer_flags: possible values depend on the | |
| 255 | -----------+--------+------------+--------------------------------------------------- | 277 | | | | | URB transfer type, see below | |
| 256 | 0x1C | 4 | | start_frame: specify the selected frame to | 278 | +-----------+--------+------------+---------------------------------------------------+ |
| 257 | | | | transmit an ISO frame, ignored if URB_ISO_ASAP | 279 | | 0x18 | 4 | | transfer_buffer_length | |
| 258 | | | | is specified at transfer_flags | 280 | +-----------+--------+------------+---------------------------------------------------+ |
| 259 | -----------+--------+------------+--------------------------------------------------- | 281 | | 0x1C | 4 | | start_frame: specify the selected frame to | |
| 260 | 0x20 | 4 | | number_of_packets: number of ISO packets | 282 | | | | | transmit an ISO frame, ignored if URB_ISO_ASAP | |
| 261 | -----------+--------+------------+--------------------------------------------------- | 283 | | | | | is specified at transfer_flags | |
| 262 | 0x24 | 4 | | interval: maximum time for the request on the | 284 | +-----------+--------+------------+---------------------------------------------------+ |
| 263 | | | | server-side host controller | 285 | | 0x20 | 4 | | number_of_packets: number of ISO packets | |
| 264 | -----------+--------+------------+--------------------------------------------------- | 286 | +-----------+--------+------------+---------------------------------------------------+ |
| 265 | 0x28 | 8 | | setup: data bytes for USB setup, filled with | 287 | | 0x24 | 4 | | interval: maximum time for the request on the | |
| 266 | | | | zeros if not used | 288 | | | | | server-side host controller | |
| 267 | -----------+--------+------------+--------------------------------------------------- | 289 | +-----------+--------+------------+---------------------------------------------------+ |
| 268 | 0x30 | | | URB data. For ISO transfers the padding between | 290 | | 0x28 | 8 | | setup: data bytes for USB setup, filled with | |
| 269 | | | | each ISO packets is not transmitted. | 291 | | | | | zeros if not used | |
| 292 | +-----------+--------+------------+---------------------------------------------------+ | ||
| 293 | | 0x30 | | | URB data. For ISO transfers the padding between | | ||
| 294 | | | | | each ISO packets is not transmitted. | | ||
| 295 | +-----------+--------+------------+---------------------------------------------------+ | ||
| 270 | 296 | ||
| 271 | 297 | ||
| 272 | Allowed transfer_flags | value | control | interrupt | bulk | isochronous | 298 | +-------------------------+------------+---------+-----------+----------+-------------+ |
| 273 | -------------------------+------------+---------+-----------+----------+------------- | 299 | | Allowed transfer_flags | value | control | interrupt | bulk | isochronous | |
| 274 | URB_SHORT_NOT_OK | 0x00000001 | only in | only in | only in | no | 300 | +=========================+============+=========+===========+==========+=============+ |
| 275 | URB_ISO_ASAP | 0x00000002 | no | no | no | yes | 301 | | URB_SHORT_NOT_OK | 0x00000001 | only in | only in | only in | no | |
| 276 | URB_NO_TRANSFER_DMA_MAP | 0x00000004 | yes | yes | yes | yes | 302 | +-------------------------+------------+---------+-----------+----------+-------------+ |
| 277 | URB_ZERO_PACKET | 0x00000040 | no | no | only out | no | 303 | | URB_ISO_ASAP | 0x00000002 | no | no | no | yes | |
| 278 | URB_NO_INTERRUPT | 0x00000080 | yes | yes | yes | yes | 304 | +-------------------------+------------+---------+-----------+----------+-------------+ |
| 279 | URB_FREE_BUFFER | 0x00000100 | yes | yes | yes | yes | 305 | | URB_NO_TRANSFER_DMA_MAP | 0x00000004 | yes | yes | yes | yes | |
| 280 | URB_DIR_MASK | 0x00000200 | yes | yes | yes | yes | 306 | +-------------------------+------------+---------+-----------+----------+-------------+ |
| 307 | | URB_ZERO_PACKET | 0x00000040 | no | no | only out | no | | ||
| 308 | +-------------------------+------------+---------+-----------+----------+-------------+ | ||
| 309 | | URB_NO_INTERRUPT | 0x00000080 | yes | yes | yes | yes | | ||
| 310 | +-------------------------+------------+---------+-----------+----------+-------------+ | ||
| 311 | | URB_FREE_BUFFER | 0x00000100 | yes | yes | yes | yes | | ||
| 312 | +-------------------------+------------+---------+-----------+----------+-------------+ | ||
| 313 | | URB_DIR_MASK | 0x00000200 | yes | yes | yes | yes | | ||
| 314 | +-------------------------+------------+---------+-----------+----------+-------------+ | ||
| 281 | 315 | ||
| 282 | 316 | ||
| 283 | USBIP_RET_SUBMIT: Reply for submitting an URB | 317 | USBIP_RET_SUBMIT: |
| 318 | Reply for submitting an URB | ||
| 284 | 319 | ||
| 285 | Offset | Length | Value | Description | 320 | +-----------+--------+------------+---------------------------------------------------+ |
| 286 | -----------+--------+------------+--------------------------------------------------- | 321 | | Offset | Length | Value | Description | |
| 287 | 0 | 4 | 0x00000003 | command | 322 | +===========+========+============+===================================================+ |
| 288 | -----------+--------+------------+--------------------------------------------------- | 323 | | 0 | 4 | 0x00000003 | command | |
| 289 | 4 | 4 | | seqnum: URB sequence number | 324 | +-----------+--------+------------+---------------------------------------------------+ |
| 290 | -----------+--------+------------+--------------------------------------------------- | 325 | | 4 | 4 | | seqnum: URB sequence number | |
| 291 | 8 | 4 | | devid | 326 | +-----------+--------+------------+---------------------------------------------------+ |
| 292 | -----------+--------+------------+--------------------------------------------------- | 327 | | 8 | 4 | | devid | |
| 293 | 0xC | 4 | | direction: 0: USBIP_DIR_OUT | 328 | +-----------+--------+------------+---------------------------------------------------+ |
| 294 | | | | 1: USBIP_DIR_IN | 329 | | 0xC | 4 | | direction: | |
| 295 | -----------+--------+------------+--------------------------------------------------- | 330 | | | | | | |
| 296 | 0x10 | 4 | | ep: endpoint number | 331 | | | | | - 0: USBIP_DIR_OUT | |
| 297 | -----------+--------+------------+--------------------------------------------------- | 332 | | | | | - 1: USBIP_DIR_IN | |
| 298 | 0x14 | 4 | | status: zero for successful URB transaction, | 333 | +-----------+--------+------------+---------------------------------------------------+ |
| 299 | | | | otherwise some kind of error happened. | 334 | | 0x10 | 4 | | ep: endpoint number | |
| 300 | -----------+--------+------------+--------------------------------------------------- | 335 | +-----------+--------+------------+---------------------------------------------------+ |
| 301 | 0x18 | 4 | n | actual_length: number of URB data bytes | 336 | | 0x14 | 4 | | status: zero for successful URB transaction, | |
| 302 | -----------+--------+------------+--------------------------------------------------- | 337 | | | | | otherwise some kind of error happened. | |
| 303 | 0x1C | 4 | | start_frame: for an ISO frame the actually | 338 | +-----------+--------+------------+---------------------------------------------------+ |
| 304 | | | | selected frame for transmit. | 339 | | 0x18 | 4 | n | actual_length: number of URB data bytes | |
| 305 | -----------+--------+------------+--------------------------------------------------- | 340 | +-----------+--------+------------+---------------------------------------------------+ |
| 306 | 0x20 | 4 | | number_of_packets | 341 | | 0x1C | 4 | | start_frame: for an ISO frame the actually | |
| 307 | -----------+--------+------------+--------------------------------------------------- | 342 | | | | | selected frame for transmit. | |
| 308 | 0x24 | 4 | | error_count | 343 | +-----------+--------+------------+---------------------------------------------------+ |
| 309 | -----------+--------+------------+--------------------------------------------------- | 344 | | 0x20 | 4 | | number_of_packets | |
| 310 | 0x28 | 8 | | setup: data bytes for USB setup, filled with | 345 | +-----------+--------+------------+---------------------------------------------------+ |
| 311 | | | | zeros if not used | 346 | | 0x24 | 4 | | error_count | |
| 312 | -----------+--------+------------+--------------------------------------------------- | 347 | +-----------+--------+------------+---------------------------------------------------+ |
| 313 | 0x30 | n | | URB data bytes. For ISO transfers the padding | 348 | | 0x28 | 8 | | setup: data bytes for USB setup, filled with | |
| 314 | | | | between each ISO packets is not transmitted. | 349 | | | | | zeros if not used | |
| 350 | +-----------+--------+------------+---------------------------------------------------+ | ||
| 351 | | 0x30 | n | | URB data bytes. For ISO transfers the padding | | ||
| 352 | | | | | between each ISO packets is not transmitted. | | ||
| 353 | +-----------+--------+------------+---------------------------------------------------+ | ||
| 315 | 354 | ||
| 316 | USBIP_CMD_UNLINK: Unlink an URB | 355 | USBIP_CMD_UNLINK: |
| 356 | Unlink an URB | ||
| 317 | 357 | ||
| 318 | Offset | Length | Value | Description | 358 | +-----------+--------+------------+---------------------------------------------------+ |
| 319 | -----------+--------+------------+--------------------------------------------------- | 359 | | Offset | Length | Value | Description | |
| 320 | 0 | 4 | 0x00000002 | command: URB unlink command | 360 | +===========+========+============+===================================================+ |
| 321 | -----------+--------+------------+--------------------------------------------------- | 361 | | 0 | 4 | 0x00000002 | command: URB unlink command | |
| 322 | 4 | 4 | | seqnum: URB sequence number to unlink: FIXME: is this so? | 362 | +-----------+--------+------------+---------------------------------------------------+ |
| 323 | -----------+--------+------------+--------------------------------------------------- | 363 | | 4 | 4 | | seqnum: URB sequence number to unlink: | |
| 324 | 8 | 4 | | devid | 364 | | | | | | |
| 325 | -----------+--------+------------+--------------------------------------------------- | 365 | | | | | FIXME: | |
| 326 | 0xC | 4 | | direction: 0: USBIP_DIR_OUT | 366 | | | | | is this so? | |
| 327 | | | | 1: USBIP_DIR_IN | 367 | +-----------+--------+------------+---------------------------------------------------+ |
| 328 | -----------+--------+------------+--------------------------------------------------- | 368 | | 8 | 4 | | devid | |
| 329 | 0x10 | 4 | | ep: endpoint number: zero | 369 | +-----------+--------+------------+---------------------------------------------------+ |
| 330 | -----------+--------+------------+--------------------------------------------------- | 370 | | 0xC | 4 | | direction: | |
| 331 | 0x14 | 4 | | seqnum: the URB sequence number given previously | 371 | | | | | | |
| 332 | | | | at USBIP_CMD_SUBMIT.seqnum field | 372 | | | | | - 0: USBIP_DIR_OUT | |
| 333 | -----------+--------+------------+--------------------------------------------------- | 373 | | | | | - 1: USBIP_DIR_IN | |
| 334 | 0x30 | n | | URB data bytes. For ISO transfers the padding | 374 | +-----------+--------+------------+---------------------------------------------------+ |
| 335 | | | | between each ISO packets is not transmitted. | 375 | | 0x10 | 4 | | ep: endpoint number: zero | |
| 376 | +-----------+--------+------------+---------------------------------------------------+ | ||
| 377 | | 0x14 | 4 | | seqnum: the URB sequence number given previously | | ||
| 378 | | | | | at USBIP_CMD_SUBMIT.seqnum field | | ||
| 379 | +-----------+--------+------------+---------------------------------------------------+ | ||
| 380 | | 0x30 | n | | URB data bytes. For ISO transfers the padding | | ||
| 381 | | | | | between each ISO packets is not transmitted. | | ||
| 382 | +-----------+--------+------------+---------------------------------------------------+ | ||
| 336 | 383 | ||
| 337 | USBIP_RET_UNLINK: Reply for URB unlink | 384 | USBIP_RET_UNLINK: |
| 385 | Reply for URB unlink | ||
| 338 | 386 | ||
| 339 | Offset | Length | Value | Description | 387 | +-----------+--------+------------+---------------------------------------------------+ |
| 340 | -----------+--------+------------+--------------------------------------------------- | 388 | | Offset | Length | Value | Description | |
| 341 | 0 | 4 | 0x00000004 | command: reply for the URB unlink command | 389 | +===========+========+============+===================================================+ |
| 342 | -----------+--------+------------+--------------------------------------------------- | 390 | | 0 | 4 | 0x00000004 | command: reply for the URB unlink command | |
| 343 | 4 | 4 | | seqnum: the unlinked URB sequence number | 391 | +-----------+--------+------------+---------------------------------------------------+ |
| 344 | -----------+--------+------------+--------------------------------------------------- | 392 | | 4 | 4 | | seqnum: the unlinked URB sequence number | |
| 345 | 8 | 4 | | devid | 393 | +-----------+--------+------------+---------------------------------------------------+ |
| 346 | -----------+--------+------------+--------------------------------------------------- | 394 | | 8 | 4 | | devid | |
| 347 | 0xC | 4 | | direction: 0: USBIP_DIR_OUT | 395 | +-----------+--------+------------+---------------------------------------------------+ |
| 348 | | | | 1: USBIP_DIR_IN | 396 | | 0xC | 4 | | direction: | |
| 349 | -----------+--------+------------+--------------------------------------------------- | 397 | | | | | | |
| 350 | 0x10 | 4 | | ep: endpoint number | 398 | | | | | - 0: USBIP_DIR_OUT | |
| 351 | -----------+--------+------------+--------------------------------------------------- | 399 | | | | | - 1: USBIP_DIR_IN | |
| 352 | 0x14 | 4 | | status: This is the value contained in the | 400 | +-----------+--------+------------+---------------------------------------------------+ |
| 353 | | | | urb->status in the URB completition handler. | 401 | | 0x10 | 4 | | ep: endpoint number | |
| 354 | | | | FIXME: a better explanation needed. | 402 | +-----------+--------+------------+---------------------------------------------------+ |
| 355 | -----------+--------+------------+--------------------------------------------------- | 403 | | 0x14 | 4 | | status: This is the value contained in the | |
| 356 | 0x30 | n | | URB data bytes. For ISO transfers the padding | 404 | | | | | urb->status in the URB completition handler. | |
| 357 | | | | between each ISO packets is not transmitted. | 405 | | | | | | |
| 406 | | | | | FIXME: | | ||
| 407 | | | | | a better explanation needed. | | ||
| 408 | +-----------+--------+------------+---------------------------------------------------+ | ||
| 409 | | 0x30 | n | | URB data bytes. For ISO transfers the padding | | ||
| 410 | | | | | between each ISO packets is not transmitted. | | ||
| 411 | +-----------+--------+------------+---------------------------------------------------+ | ||
diff --git a/Documentation/usb/usbmon.txt b/Documentation/usb/usbmon.txt index 28425f736756..b0bd51080799 100644 --- a/Documentation/usb/usbmon.txt +++ b/Documentation/usb/usbmon.txt | |||
| @@ -1,4 +1,9 @@ | |||
| 1 | * Introduction | 1 | ====== |
| 2 | usbmon | ||
| 3 | ====== | ||
| 4 | |||
| 5 | Introduction | ||
| 6 | ============ | ||
| 2 | 7 | ||
| 3 | The name "usbmon" in lowercase refers to a facility in kernel which is | 8 | The name "usbmon" in lowercase refers to a facility in kernel which is |
| 4 | used to collect traces of I/O on the USB bus. This function is analogous | 9 | used to collect traces of I/O on the USB bus. This function is analogous |
| @@ -16,7 +21,8 @@ Two APIs are currently implemented: "text" and "binary". The binary API | |||
| 16 | is available through a character device in /dev namespace and is an ABI. | 21 | is available through a character device in /dev namespace and is an ABI. |
| 17 | The text API is deprecated since 2.6.35, but available for convenience. | 22 | The text API is deprecated since 2.6.35, but available for convenience. |
| 18 | 23 | ||
| 19 | * How to use usbmon to collect raw text traces | 24 | How to use usbmon to collect raw text traces |
| 25 | ============================================ | ||
| 20 | 26 | ||
| 21 | Unlike the packet socket, usbmon has an interface which provides traces | 27 | Unlike the packet socket, usbmon has an interface which provides traces |
| 22 | in a text format. This is used for two purposes. First, it serves as a | 28 | in a text format. This is used for two purposes. First, it serves as a |
| @@ -26,38 +32,41 @@ are finalized. Second, humans can read it in case tools are not available. | |||
| 26 | To collect a raw text trace, execute following steps. | 32 | To collect a raw text trace, execute following steps. |
| 27 | 33 | ||
| 28 | 1. Prepare | 34 | 1. Prepare |
| 35 | ---------- | ||
| 29 | 36 | ||
| 30 | Mount debugfs (it has to be enabled in your kernel configuration), and | 37 | Mount debugfs (it has to be enabled in your kernel configuration), and |
| 31 | load the usbmon module (if built as module). The second step is skipped | 38 | load the usbmon module (if built as module). The second step is skipped |
| 32 | if usbmon is built into the kernel. | 39 | if usbmon is built into the kernel:: |
| 33 | 40 | ||
| 34 | # mount -t debugfs none_debugs /sys/kernel/debug | 41 | # mount -t debugfs none_debugs /sys/kernel/debug |
| 35 | # modprobe usbmon | 42 | # modprobe usbmon |
| 36 | # | 43 | # |
| 37 | 44 | ||
| 38 | Verify that bus sockets are present. | 45 | Verify that bus sockets are present: |
| 39 | 46 | ||
| 40 | # ls /sys/kernel/debug/usb/usbmon | 47 | # ls /sys/kernel/debug/usb/usbmon |
| 41 | 0s 0u 1s 1t 1u 2s 2t 2u 3s 3t 3u 4s 4t 4u | 48 | 0s 0u 1s 1t 1u 2s 2t 2u 3s 3t 3u 4s 4t 4u |
| 42 | # | 49 | # |
| 43 | 50 | ||
| 44 | Now you can choose to either use the socket '0u' (to capture packets on all | 51 | Now you can choose to either use the socket '0u' (to capture packets on all |
| 45 | buses), and skip to step #3, or find the bus used by your device with step #2. | 52 | buses), and skip to step #3, or find the bus used by your device with step #2. |
| 46 | This allows to filter away annoying devices that talk continuously. | 53 | This allows to filter away annoying devices that talk continuously. |
| 47 | 54 | ||
| 48 | 2. Find which bus connects to the desired device | 55 | 2. Find which bus connects to the desired device |
| 56 | ------------------------------------------------ | ||
| 49 | 57 | ||
| 50 | Run "cat /sys/kernel/debug/usb/devices", and find the T-line which corresponds | 58 | Run "cat /sys/kernel/debug/usb/devices", and find the T-line which corresponds |
| 51 | to the device. Usually you do it by looking for the vendor string. If you have | 59 | to the device. Usually you do it by looking for the vendor string. If you have |
| 52 | many similar devices, unplug one and compare the two | 60 | many similar devices, unplug one and compare the two |
| 53 | /sys/kernel/debug/usb/devices outputs. The T-line will have a bus number. | 61 | /sys/kernel/debug/usb/devices outputs. The T-line will have a bus number. |
| 54 | Example: | ||
| 55 | 62 | ||
| 56 | T: Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=12 MxCh= 0 | 63 | Example:: |
| 57 | D: Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 | 64 | |
| 58 | P: Vendor=0557 ProdID=2004 Rev= 1.00 | 65 | T: Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=12 MxCh= 0 |
| 59 | S: Manufacturer=ATEN | 66 | D: Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 |
| 60 | S: Product=UC100KM V2.00 | 67 | P: Vendor=0557 ProdID=2004 Rev= 1.00 |
| 68 | S: Manufacturer=ATEN | ||
| 69 | S: Product=UC100KM V2.00 | ||
| 61 | 70 | ||
| 62 | "Bus=03" means it's bus 3. Alternatively, you can look at the output from | 71 | "Bus=03" means it's bus 3. Alternatively, you can look at the output from |
| 63 | "lsusb" and get the bus number from the appropriate line. Example: | 72 | "lsusb" and get the bus number from the appropriate line. Example: |
| @@ -65,23 +74,28 @@ S: Product=UC100KM V2.00 | |||
| 65 | Bus 003 Device 002: ID 0557:2004 ATEN UC100KM V2.00 | 74 | Bus 003 Device 002: ID 0557:2004 ATEN UC100KM V2.00 |
| 66 | 75 | ||
| 67 | 3. Start 'cat' | 76 | 3. Start 'cat' |
| 77 | -------------- | ||
| 78 | |||
| 79 | :: | ||
| 68 | 80 | ||
| 69 | # cat /sys/kernel/debug/usb/usbmon/3u > /tmp/1.mon.out | 81 | # cat /sys/kernel/debug/usb/usbmon/3u > /tmp/1.mon.out |
| 70 | 82 | ||
| 71 | to listen on a single bus, otherwise, to listen on all buses, type: | 83 | to listen on a single bus, otherwise, to listen on all buses, type:: |
| 72 | 84 | ||
| 73 | # cat /sys/kernel/debug/usb/usbmon/0u > /tmp/1.mon.out | 85 | # cat /sys/kernel/debug/usb/usbmon/0u > /tmp/1.mon.out |
| 74 | 86 | ||
| 75 | This process will read until it is killed. Naturally, the output can be | 87 | This process will read until it is killed. Naturally, the output can be |
| 76 | redirected to a desirable location. This is preferred, because it is going | 88 | redirected to a desirable location. This is preferred, because it is going |
| 77 | to be quite long. | 89 | to be quite long. |
| 78 | 90 | ||
| 79 | 4. Perform the desired operation on the USB bus | 91 | 4. Perform the desired operation on the USB bus |
| 92 | ----------------------------------------------- | ||
| 80 | 93 | ||
| 81 | This is where you do something that creates the traffic: plug in a flash key, | 94 | This is where you do something that creates the traffic: plug in a flash key, |
| 82 | copy files, control a webcam, etc. | 95 | copy files, control a webcam, etc. |
| 83 | 96 | ||
| 84 | 5. Kill cat | 97 | 5. Kill cat |
| 98 | ----------- | ||
| 85 | 99 | ||
| 86 | Usually it's done with a keyboard interrupt (Control-C). | 100 | Usually it's done with a keyboard interrupt (Control-C). |
| 87 | 101 | ||
| @@ -89,7 +103,8 @@ At this point the output file (/tmp/1.mon.out in this example) can be saved, | |||
| 89 | sent by e-mail, or inspected with a text editor. In the last case make sure | 103 | sent by e-mail, or inspected with a text editor. In the last case make sure |
| 90 | that the file size is not excessive for your favourite editor. | 104 | that the file size is not excessive for your favourite editor. |
| 91 | 105 | ||
| 92 | * Raw text data format | 106 | Raw text data format |
| 107 | ==================== | ||
| 93 | 108 | ||
| 94 | Two formats are supported currently: the original, or '1t' format, and | 109 | Two formats are supported currently: the original, or '1t' format, and |
| 95 | the '1u' format. The '1t' format is deprecated in kernel 2.6.21. The '1u' | 110 | the '1u' format. The '1t' format is deprecated in kernel 2.6.21. The '1u' |
| @@ -122,10 +137,14 @@ Here is the list of words, from left to right: | |||
| 122 | - "Address" word (formerly a "pipe"). It consists of four fields, separated by | 137 | - "Address" word (formerly a "pipe"). It consists of four fields, separated by |
| 123 | colons: URB type and direction, Bus number, Device address, Endpoint number. | 138 | colons: URB type and direction, Bus number, Device address, Endpoint number. |
| 124 | Type and direction are encoded with two bytes in the following manner: | 139 | Type and direction are encoded with two bytes in the following manner: |
| 140 | |||
| 141 | == == ============================= | ||
| 125 | Ci Co Control input and output | 142 | Ci Co Control input and output |
| 126 | Zi Zo Isochronous input and output | 143 | Zi Zo Isochronous input and output |
| 127 | Ii Io Interrupt input and output | 144 | Ii Io Interrupt input and output |
| 128 | Bi Bo Bulk input and output | 145 | Bi Bo Bulk input and output |
| 146 | == == ============================= | ||
| 147 | |||
| 129 | Bus number, Device address, and Endpoint are decimal numbers, but they may | 148 | Bus number, Device address, and Endpoint are decimal numbers, but they may |
| 130 | have leading zeros, for the sake of human readers. | 149 | have leading zeros, for the sake of human readers. |
| 131 | 150 | ||
| @@ -178,24 +197,25 @@ Here is the list of words, from left to right: | |||
| 178 | 197 | ||
| 179 | Examples: | 198 | Examples: |
| 180 | 199 | ||
| 181 | An input control transfer to get a port status. | 200 | An input control transfer to get a port status:: |
| 182 | 201 | ||
| 183 | d5ea89a0 3575914555 S Ci:1:001:0 s a3 00 0000 0003 0004 4 < | 202 | d5ea89a0 3575914555 S Ci:1:001:0 s a3 00 0000 0003 0004 4 < |
| 184 | d5ea89a0 3575914560 C Ci:1:001:0 0 4 = 01050000 | 203 | d5ea89a0 3575914560 C Ci:1:001:0 0 4 = 01050000 |
| 185 | 204 | ||
| 186 | An output bulk transfer to send a SCSI command 0x28 (READ_10) in a 31-byte | 205 | An output bulk transfer to send a SCSI command 0x28 (READ_10) in a 31-byte |
| 187 | Bulk wrapper to a storage device at address 5: | 206 | Bulk wrapper to a storage device at address 5:: |
| 188 | 207 | ||
| 189 | dd65f0e8 4128379752 S Bo:1:005:2 -115 31 = 55534243 ad000000 00800000 80010a28 20000000 20000040 00000000 000000 | 208 | dd65f0e8 4128379752 S Bo:1:005:2 -115 31 = 55534243 ad000000 00800000 80010a28 20000000 20000040 00000000 000000 |
| 190 | dd65f0e8 4128379808 C Bo:1:005:2 0 31 > | 209 | dd65f0e8 4128379808 C Bo:1:005:2 0 31 > |
| 191 | 210 | ||
| 192 | * Raw binary format and API | 211 | Raw binary format and API |
| 212 | ========================= | ||
| 193 | 213 | ||
| 194 | The overall architecture of the API is about the same as the one above, | 214 | The overall architecture of the API is about the same as the one above, |
| 195 | only the events are delivered in binary format. Each event is sent in | 215 | only the events are delivered in binary format. Each event is sent in |
| 196 | the following structure (its name is made up, so that we can refer to it): | 216 | the following structure (its name is made up, so that we can refer to it):: |
| 197 | 217 | ||
| 198 | struct usbmon_packet { | 218 | struct usbmon_packet { |
| 199 | u64 id; /* 0: URB ID - from submission to callback */ | 219 | u64 id; /* 0: URB ID - from submission to callback */ |
| 200 | unsigned char type; /* 8: Same as text; extensible. */ | 220 | unsigned char type; /* 8: Same as text; extensible. */ |
| 201 | unsigned char xfer_type; /* ISO (0), Intr, Control, Bulk (3) */ | 221 | unsigned char xfer_type; /* ISO (0), Intr, Control, Bulk (3) */ |
| @@ -220,7 +240,7 @@ struct usbmon_packet { | |||
| 220 | int start_frame; /* 52: For ISO */ | 240 | int start_frame; /* 52: For ISO */ |
| 221 | unsigned int xfer_flags; /* 56: copy of URB's transfer_flags */ | 241 | unsigned int xfer_flags; /* 56: copy of URB's transfer_flags */ |
| 222 | unsigned int ndesc; /* 60: Actual number of ISO descriptors */ | 242 | unsigned int ndesc; /* 60: Actual number of ISO descriptors */ |
| 223 | }; /* 64 total length */ | 243 | }; /* 64 total length */ |
| 224 | 244 | ||
| 225 | These events can be received from a character device by reading with read(2), | 245 | These events can be received from a character device by reading with read(2), |
| 226 | with an ioctl(2), or by accessing the buffer with mmap. However, read(2) | 246 | with an ioctl(2), or by accessing the buffer with mmap. However, read(2) |
| @@ -244,12 +264,12 @@ no events are available. | |||
| 244 | 264 | ||
| 245 | MON_IOCG_STATS, defined as _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats) | 265 | MON_IOCG_STATS, defined as _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats) |
| 246 | 266 | ||
| 247 | The argument is a pointer to the following structure: | 267 | The argument is a pointer to the following structure:: |
| 248 | 268 | ||
| 249 | struct mon_bin_stats { | 269 | struct mon_bin_stats { |
| 250 | u32 queued; | 270 | u32 queued; |
| 251 | u32 dropped; | 271 | u32 dropped; |
| 252 | }; | 272 | }; |
| 253 | 273 | ||
| 254 | The member "queued" refers to the number of events currently queued in the | 274 | The member "queued" refers to the number of events currently queued in the |
| 255 | buffer (and not to the number of events processed since the last reset). | 275 | buffer (and not to the number of events processed since the last reset). |
| @@ -273,13 +293,13 @@ This call returns the current size of the buffer in bytes. | |||
| 273 | 293 | ||
| 274 | These calls wait for events to arrive if none were in the kernel buffer, | 294 | These calls wait for events to arrive if none were in the kernel buffer, |
| 275 | then return the first event. The argument is a pointer to the following | 295 | then return the first event. The argument is a pointer to the following |
| 276 | structure: | 296 | structure:: |
| 277 | 297 | ||
| 278 | struct mon_get_arg { | 298 | struct mon_get_arg { |
| 279 | struct usbmon_packet *hdr; | 299 | struct usbmon_packet *hdr; |
| 280 | void *data; | 300 | void *data; |
| 281 | size_t alloc; /* Length of data (can be zero) */ | 301 | size_t alloc; /* Length of data (can be zero) */ |
| 282 | }; | 302 | }; |
| 283 | 303 | ||
| 284 | Before the call, hdr, data, and alloc should be filled. Upon return, the area | 304 | Before the call, hdr, data, and alloc should be filled. Upon return, the area |
| 285 | pointed by hdr contains the next event structure, and the data buffer contains | 305 | pointed by hdr contains the next event structure, and the data buffer contains |
| @@ -290,13 +310,13 @@ The MON_IOCX_GET copies 48 bytes to hdr area, MON_IOCX_GETX copies 64 bytes. | |||
| 290 | MON_IOCX_MFETCH, defined as _IOWR(MON_IOC_MAGIC, 7, struct mon_mfetch_arg) | 310 | MON_IOCX_MFETCH, defined as _IOWR(MON_IOC_MAGIC, 7, struct mon_mfetch_arg) |
| 291 | 311 | ||
| 292 | This ioctl is primarily used when the application accesses the buffer | 312 | This ioctl is primarily used when the application accesses the buffer |
| 293 | with mmap(2). Its argument is a pointer to the following structure: | 313 | with mmap(2). Its argument is a pointer to the following structure:: |
| 294 | 314 | ||
| 295 | struct mon_mfetch_arg { | 315 | struct mon_mfetch_arg { |
| 296 | uint32_t *offvec; /* Vector of events fetched */ | 316 | uint32_t *offvec; /* Vector of events fetched */ |
| 297 | uint32_t nfetch; /* Number of events to fetch (out: fetched) */ | 317 | uint32_t nfetch; /* Number of events to fetch (out: fetched) */ |
| 298 | uint32_t nflush; /* Number of events to flush */ | 318 | uint32_t nflush; /* Number of events to flush */ |
| 299 | }; | 319 | }; |
| 300 | 320 | ||
| 301 | The ioctl operates in 3 stages. | 321 | The ioctl operates in 3 stages. |
| 302 | 322 | ||
| @@ -329,7 +349,7 @@ be polled with select(2) and poll(2). But lseek(2) does not work. | |||
| 329 | The basic idea is simple: | 349 | The basic idea is simple: |
| 330 | 350 | ||
| 331 | To prepare, map the buffer by getting the current size, then using mmap(2). | 351 | To prepare, map the buffer by getting the current size, then using mmap(2). |
| 332 | Then, execute a loop similar to the one written in pseudo-code below: | 352 | Then, execute a loop similar to the one written in pseudo-code below:: |
| 333 | 353 | ||
| 334 | struct mon_mfetch_arg fetch; | 354 | struct mon_mfetch_arg fetch; |
| 335 | struct usbmon_packet *hdr; | 355 | struct usbmon_packet *hdr; |
diff --git a/MAINTAINERS b/MAINTAINERS index 920a0a1545b7..3f4ccfd793eb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
| @@ -15377,6 +15377,11 @@ M: Laxman Dewangan <ldewangan@nvidia.com> | |||
| 15377 | S: Supported | 15377 | S: Supported |
| 15378 | F: drivers/spi/spi-tegra* | 15378 | F: drivers/spi/spi-tegra* |
| 15379 | 15379 | ||
| 15380 | TEGRA XUSB PADCTL DRIVER | ||
| 15381 | M: JC Kuo <jckuo@nvidia.com> | ||
| 15382 | S: Supported | ||
| 15383 | F: drivers/phy/tegra/xusb* | ||
| 15384 | |||
| 15380 | TEHUTI ETHERNET DRIVER | 15385 | TEHUTI ETHERNET DRIVER |
| 15381 | M: Andy Gospodarek <andy@greyhouse.net> | 15386 | M: Andy Gospodarek <andy@greyhouse.net> |
| 15382 | L: netdev@vger.kernel.org | 15387 | L: netdev@vger.kernel.org |
| @@ -16155,6 +16160,14 @@ L: linux-usb@vger.kernel.org | |||
| 16155 | S: Maintained | 16160 | S: Maintained |
| 16156 | F: drivers/usb/roles/intel-xhci-usb-role-switch.c | 16161 | F: drivers/usb/roles/intel-xhci-usb-role-switch.c |
| 16157 | 16162 | ||
| 16163 | USB IP DRIVER FOR HISILICON KIRIN | ||
| 16164 | M: Yu Chen <chenyu56@huawei.com> | ||
| 16165 | M: Binghui Wang <wangbinghui@hisilicon.com> | ||
| 16166 | L: linux-usb@vger.kernel.org | ||
| 16167 | S: Maintained | ||
| 16168 | F: Documentation/devicetree/bindings/phy/phy-hi3660-usb3.txt | ||
| 16169 | F: drivers/phy/hisilicon/phy-hi3660-usb3.c | ||
| 16170 | |||
| 16158 | USB ISP116X DRIVER | 16171 | USB ISP116X DRIVER |
| 16159 | M: Olav Kongas <ok@artecdesign.ee> | 16172 | M: Olav Kongas <ok@artecdesign.ee> |
| 16160 | L: linux-usb@vger.kernel.org | 16173 | L: linux-usb@vger.kernel.org |
diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi index a024d1e7e74c..8ce3dd2264b1 100644 --- a/arch/arm/boot/dts/rk3288.dtsi +++ b/arch/arm/boot/dts/rk3288.dtsi | |||
| @@ -616,6 +616,7 @@ | |||
| 616 | dr_mode = "host"; | 616 | dr_mode = "host"; |
| 617 | phys = <&usbphy2>; | 617 | phys = <&usbphy2>; |
| 618 | phy-names = "usb2-phy"; | 618 | phy-names = "usb2-phy"; |
| 619 | snps,reset-phy-on-wake; | ||
| 619 | status = "disabled"; | 620 | status = "disabled"; |
| 620 | }; | 621 | }; |
| 621 | 622 | ||
| @@ -904,6 +905,8 @@ | |||
| 904 | clocks = <&cru SCLK_OTGPHY0>; | 905 | clocks = <&cru SCLK_OTGPHY0>; |
| 905 | clock-names = "phyclk"; | 906 | clock-names = "phyclk"; |
| 906 | #clock-cells = <0>; | 907 | #clock-cells = <0>; |
| 908 | resets = <&cru SRST_USBOTG_PHY>; | ||
| 909 | reset-names = "phy-reset"; | ||
| 907 | }; | 910 | }; |
| 908 | 911 | ||
| 909 | usbphy1: usb-phy@334 { | 912 | usbphy1: usb-phy@334 { |
| @@ -912,6 +915,8 @@ | |||
| 912 | clocks = <&cru SCLK_OTGPHY1>; | 915 | clocks = <&cru SCLK_OTGPHY1>; |
| 913 | clock-names = "phyclk"; | 916 | clock-names = "phyclk"; |
| 914 | #clock-cells = <0>; | 917 | #clock-cells = <0>; |
| 918 | resets = <&cru SRST_USBHOST0_PHY>; | ||
| 919 | reset-names = "phy-reset"; | ||
| 915 | }; | 920 | }; |
| 916 | 921 | ||
| 917 | usbphy2: usb-phy@348 { | 922 | usbphy2: usb-phy@348 { |
| @@ -920,6 +925,8 @@ | |||
| 920 | clocks = <&cru SCLK_OTGPHY2>; | 925 | clocks = <&cru SCLK_OTGPHY2>; |
| 921 | clock-names = "phyclk"; | 926 | clock-names = "phyclk"; |
| 922 | #clock-cells = <0>; | 927 | #clock-cells = <0>; |
| 928 | resets = <&cru SRST_USBHOST1_PHY>; | ||
| 929 | reset-names = "phy-reset"; | ||
| 923 | }; | 930 | }; |
| 924 | }; | 931 | }; |
| 925 | }; | 932 | }; |
diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c b/drivers/i2c/busses/i2c-nvidia-gpu.c index 4e67d5ed480e..1c8f708f212b 100644 --- a/drivers/i2c/busses/i2c-nvidia-gpu.c +++ b/drivers/i2c/busses/i2c-nvidia-gpu.c | |||
| @@ -253,6 +253,12 @@ static const struct pci_device_id gpu_i2c_ids[] = { | |||
| 253 | }; | 253 | }; |
| 254 | MODULE_DEVICE_TABLE(pci, gpu_i2c_ids); | 254 | MODULE_DEVICE_TABLE(pci, gpu_i2c_ids); |
| 255 | 255 | ||
| 256 | static const struct property_entry ccgx_props[] = { | ||
| 257 | /* Use FW built for NVIDIA (nv) only */ | ||
| 258 | PROPERTY_ENTRY_U16("ccgx,firmware-build", ('n' << 8) | 'v'), | ||
| 259 | { } | ||
| 260 | }; | ||
| 261 | |||
| 256 | static int gpu_populate_client(struct gpu_i2c_dev *i2cd, int irq) | 262 | static int gpu_populate_client(struct gpu_i2c_dev *i2cd, int irq) |
| 257 | { | 263 | { |
| 258 | struct i2c_client *ccgx_client; | 264 | struct i2c_client *ccgx_client; |
| @@ -267,6 +273,7 @@ static int gpu_populate_client(struct gpu_i2c_dev *i2cd, int irq) | |||
| 267 | sizeof(i2cd->gpu_ccgx_ucsi->type)); | 273 | sizeof(i2cd->gpu_ccgx_ucsi->type)); |
| 268 | i2cd->gpu_ccgx_ucsi->addr = 0x8; | 274 | i2cd->gpu_ccgx_ucsi->addr = 0x8; |
| 269 | i2cd->gpu_ccgx_ucsi->irq = irq; | 275 | i2cd->gpu_ccgx_ucsi->irq = irq; |
| 276 | i2cd->gpu_ccgx_ucsi->properties = ccgx_props; | ||
| 270 | ccgx_client = i2c_new_device(&i2cd->adapter, i2cd->gpu_ccgx_ucsi); | 277 | ccgx_client = i2c_new_device(&i2cd->adapter, i2cd->gpu_ccgx_ucsi); |
| 271 | if (!ccgx_client) | 278 | if (!ccgx_client) |
| 272 | return -ENODEV; | 279 | return -ENODEV; |
diff --git a/drivers/phy/amlogic/Kconfig b/drivers/phy/amlogic/Kconfig index 23fe1cda2f70..4c08c1ccdd04 100644 --- a/drivers/phy/amlogic/Kconfig +++ b/drivers/phy/amlogic/Kconfig | |||
| @@ -36,3 +36,25 @@ config PHY_MESON_GXL_USB3 | |||
| 36 | Enable this to support the Meson USB3 PHY and OTG detection | 36 | Enable this to support the Meson USB3 PHY and OTG detection |
| 37 | IP block found in Meson GXL and GXM SoCs. | 37 | IP block found in Meson GXL and GXM SoCs. |
| 38 | If unsure, say N. | 38 | If unsure, say N. |
| 39 | |||
| 40 | config PHY_MESON_G12A_USB2 | ||
| 41 | tristate "Meson G12A USB2 PHY driver" | ||
| 42 | default ARCH_MESON | ||
| 43 | depends on OF && (ARCH_MESON || COMPILE_TEST) | ||
| 44 | select GENERIC_PHY | ||
| 45 | select REGMAP_MMIO | ||
| 46 | help | ||
| 47 | Enable this to support the Meson USB2 PHYs found in Meson | ||
| 48 | G12A SoCs. | ||
| 49 | If unsure, say N. | ||
| 50 | |||
| 51 | config PHY_MESON_G12A_USB3_PCIE | ||
| 52 | tristate "Meson G12A USB3+PCIE Combo PHY driver" | ||
| 53 | default ARCH_MESON | ||
| 54 | depends on OF && (ARCH_MESON || COMPILE_TEST) | ||
| 55 | select GENERIC_PHY | ||
| 56 | select REGMAP_MMIO | ||
| 57 | help | ||
| 58 | Enable this to support the Meson USB3 + PCIE Combo PHY found | ||
| 59 | in Meson G12A SoCs. | ||
| 60 | If unsure, say N. | ||
diff --git a/drivers/phy/amlogic/Makefile b/drivers/phy/amlogic/Makefile index 4fd8848c194d..fdd008e1b19b 100644 --- a/drivers/phy/amlogic/Makefile +++ b/drivers/phy/amlogic/Makefile | |||
| @@ -1,3 +1,5 @@ | |||
| 1 | obj-$(CONFIG_PHY_MESON8B_USB2) += phy-meson8b-usb2.o | 1 | obj-$(CONFIG_PHY_MESON8B_USB2) += phy-meson8b-usb2.o |
| 2 | obj-$(CONFIG_PHY_MESON_GXL_USB2) += phy-meson-gxl-usb2.o | 2 | obj-$(CONFIG_PHY_MESON_GXL_USB2) += phy-meson-gxl-usb2.o |
| 3 | obj-$(CONFIG_PHY_MESON_G12A_USB2) += phy-meson-g12a-usb2.o | ||
| 3 | obj-$(CONFIG_PHY_MESON_GXL_USB3) += phy-meson-gxl-usb3.o | 4 | obj-$(CONFIG_PHY_MESON_GXL_USB3) += phy-meson-gxl-usb3.o |
| 5 | obj-$(CONFIG_PHY_MESON_G12A_USB3_PCIE) += phy-meson-g12a-usb3-pcie.o | ||
diff --git a/drivers/phy/amlogic/phy-meson-g12a-usb2.c b/drivers/phy/amlogic/phy-meson-g12a-usb2.c new file mode 100644 index 000000000000..9065ffc85eb4 --- /dev/null +++ b/drivers/phy/amlogic/phy-meson-g12a-usb2.c | |||
| @@ -0,0 +1,341 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * Meson G12A USB2 PHY driver | ||
| 4 | * | ||
| 5 | * Copyright (C) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com> | ||
| 6 | * Copyright (C) 2017 Amlogic, Inc. All rights reserved | ||
| 7 | * Copyright (C) 2019 BayLibre, SAS | ||
| 8 | * Author: Neil Armstrong <narmstrong@baylibre.com> | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/bitfield.h> | ||
| 12 | #include <linux/bitops.h> | ||
| 13 | #include <linux/clk.h> | ||
| 14 | #include <linux/delay.h> | ||
| 15 | #include <linux/io.h> | ||
| 16 | #include <linux/module.h> | ||
| 17 | #include <linux/of_device.h> | ||
| 18 | #include <linux/regmap.h> | ||
| 19 | #include <linux/reset.h> | ||
| 20 | #include <linux/phy/phy.h> | ||
| 21 | #include <linux/platform_device.h> | ||
| 22 | |||
| 23 | #define PHY_CTRL_R0 0x0 | ||
| 24 | #define PHY_CTRL_R1 0x4 | ||
| 25 | #define PHY_CTRL_R2 0x8 | ||
| 26 | #define PHY_CTRL_R3 0xc | ||
| 27 | #define PHY_CTRL_R3_SQUELCH_REF GENMASK(1, 0) | ||
| 28 | #define PHY_CTRL_R3_HSDIC_REF GENMASK(3, 2) | ||
| 29 | #define PHY_CTRL_R3_DISC_THRESH GENMASK(7, 4) | ||
| 30 | |||
| 31 | #define PHY_CTRL_R4 0x10 | ||
| 32 | #define PHY_CTRL_R4_CALIB_CODE_7_0 GENMASK(7, 0) | ||
| 33 | #define PHY_CTRL_R4_CALIB_CODE_15_8 GENMASK(15, 8) | ||
| 34 | #define PHY_CTRL_R4_CALIB_CODE_23_16 GENMASK(23, 16) | ||
| 35 | #define PHY_CTRL_R4_I_C2L_CAL_EN BIT(24) | ||
| 36 | #define PHY_CTRL_R4_I_C2L_CAL_RESET_N BIT(25) | ||
| 37 | #define PHY_CTRL_R4_I_C2L_CAL_DONE BIT(26) | ||
| 38 | #define PHY_CTRL_R4_TEST_BYPASS_MODE_EN BIT(27) | ||
| 39 | #define PHY_CTRL_R4_I_C2L_BIAS_TRIM_1_0 GENMASK(29, 28) | ||
| 40 | #define PHY_CTRL_R4_I_C2L_BIAS_TRIM_3_2 GENMASK(31, 30) | ||
| 41 | |||
| 42 | #define PHY_CTRL_R5 0x14 | ||
| 43 | #define PHY_CTRL_R6 0x18 | ||
| 44 | #define PHY_CTRL_R7 0x1c | ||
| 45 | #define PHY_CTRL_R8 0x20 | ||
| 46 | #define PHY_CTRL_R9 0x24 | ||
| 47 | #define PHY_CTRL_R10 0x28 | ||
| 48 | #define PHY_CTRL_R11 0x2c | ||
| 49 | #define PHY_CTRL_R12 0x30 | ||
| 50 | #define PHY_CTRL_R13 0x34 | ||
| 51 | #define PHY_CTRL_R13_CUSTOM_PATTERN_19 GENMASK(7, 0) | ||
| 52 | #define PHY_CTRL_R13_LOAD_STAT BIT(14) | ||
| 53 | #define PHY_CTRL_R13_UPDATE_PMA_SIGNALS BIT(15) | ||
| 54 | #define PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET GENMASK(20, 16) | ||
| 55 | #define PHY_CTRL_R13_CLEAR_HOLD_HS_DISCONNECT BIT(21) | ||
| 56 | #define PHY_CTRL_R13_BYPASS_HOST_DISCONNECT_VAL BIT(22) | ||
| 57 | #define PHY_CTRL_R13_BYPASS_HOST_DISCONNECT_EN BIT(23) | ||
| 58 | #define PHY_CTRL_R13_I_C2L_HS_EN BIT(24) | ||
| 59 | #define PHY_CTRL_R13_I_C2L_FS_EN BIT(25) | ||
| 60 | #define PHY_CTRL_R13_I_C2L_LS_EN BIT(26) | ||
| 61 | #define PHY_CTRL_R13_I_C2L_HS_OE BIT(27) | ||
| 62 | #define PHY_CTRL_R13_I_C2L_FS_OE BIT(28) | ||
| 63 | #define PHY_CTRL_R13_I_C2L_HS_RX_EN BIT(29) | ||
| 64 | #define PHY_CTRL_R13_I_C2L_FSLS_RX_EN BIT(30) | ||
| 65 | |||
| 66 | #define PHY_CTRL_R14 0x38 | ||
| 67 | #define PHY_CTRL_R14_I_RDP_EN BIT(0) | ||
| 68 | #define PHY_CTRL_R14_I_RPU_SW1_EN BIT(1) | ||
| 69 | #define PHY_CTRL_R14_I_RPU_SW2_EN GENMASK(2, 3) | ||
| 70 | #define PHY_CTRL_R14_PG_RSTN BIT(4) | ||
| 71 | #define PHY_CTRL_R14_I_C2L_DATA_16_8 BIT(5) | ||
| 72 | #define PHY_CTRL_R14_I_C2L_ASSERT_SINGLE_EN_ZERO BIT(6) | ||
| 73 | #define PHY_CTRL_R14_BYPASS_CTRL_7_0 GENMASK(15, 8) | ||
| 74 | #define PHY_CTRL_R14_BYPASS_CTRL_15_8 GENMASK(23, 16) | ||
| 75 | |||
| 76 | #define PHY_CTRL_R15 0x3c | ||
| 77 | #define PHY_CTRL_R16 0x40 | ||
| 78 | #define PHY_CTRL_R16_MPLL_M GENMASK(8, 0) | ||
| 79 | #define PHY_CTRL_R16_MPLL_N GENMASK(14, 10) | ||
| 80 | #define PHY_CTRL_R16_MPLL_TDC_MODE BIT(20) | ||
| 81 | #define PHY_CTRL_R16_MPLL_SDM_EN BIT(21) | ||
| 82 | #define PHY_CTRL_R16_MPLL_LOAD BIT(22) | ||
| 83 | #define PHY_CTRL_R16_MPLL_DCO_SDM_EN BIT(23) | ||
| 84 | #define PHY_CTRL_R16_MPLL_LOCK_LONG GENMASK(25, 24) | ||
| 85 | #define PHY_CTRL_R16_MPLL_LOCK_F BIT(26) | ||
| 86 | #define PHY_CTRL_R16_MPLL_FAST_LOCK BIT(27) | ||
| 87 | #define PHY_CTRL_R16_MPLL_EN BIT(28) | ||
| 88 | #define PHY_CTRL_R16_MPLL_RESET BIT(29) | ||
| 89 | #define PHY_CTRL_R16_MPLL_LOCK BIT(30) | ||
| 90 | #define PHY_CTRL_R16_MPLL_LOCK_DIG BIT(31) | ||
| 91 | |||
| 92 | #define PHY_CTRL_R17 0x44 | ||
| 93 | #define PHY_CTRL_R17_MPLL_FRAC_IN GENMASK(13, 0) | ||
| 94 | #define PHY_CTRL_R17_MPLL_FIX_EN BIT(16) | ||
| 95 | #define PHY_CTRL_R17_MPLL_LAMBDA1 GENMASK(19, 17) | ||
| 96 | #define PHY_CTRL_R17_MPLL_LAMBDA0 GENMASK(22, 20) | ||
| 97 | #define PHY_CTRL_R17_MPLL_FILTER_MODE BIT(23) | ||
| 98 | #define PHY_CTRL_R17_MPLL_FILTER_PVT2 GENMASK(27, 24) | ||
| 99 | #define PHY_CTRL_R17_MPLL_FILTER_PVT1 GENMASK(31, 28) | ||
| 100 | |||
| 101 | #define PHY_CTRL_R18 0x48 | ||
| 102 | #define PHY_CTRL_R18_MPLL_LKW_SEL GENMASK(1, 0) | ||
| 103 | #define PHY_CTRL_R18_MPLL_LK_W GENMASK(5, 2) | ||
| 104 | #define PHY_CTRL_R18_MPLL_LK_S GENMASK(11, 6) | ||
| 105 | #define PHY_CTRL_R18_MPLL_DCO_M_EN BIT(12) | ||
| 106 | #define PHY_CTRL_R18_MPLL_DCO_CLK_SEL BIT(13) | ||
| 107 | #define PHY_CTRL_R18_MPLL_PFD_GAIN GENMASK(15, 14) | ||
| 108 | #define PHY_CTRL_R18_MPLL_ROU GENMASK(18, 16) | ||
| 109 | #define PHY_CTRL_R18_MPLL_DATA_SEL GENMASK(21, 19) | ||
| 110 | #define PHY_CTRL_R18_MPLL_BIAS_ADJ GENMASK(23, 22) | ||
| 111 | #define PHY_CTRL_R18_MPLL_BB_MODE GENMASK(25, 24) | ||
| 112 | #define PHY_CTRL_R18_MPLL_ALPHA GENMASK(28, 26) | ||
| 113 | #define PHY_CTRL_R18_MPLL_ADJ_LDO GENMASK(30, 29) | ||
| 114 | #define PHY_CTRL_R18_MPLL_ACG_RANGE BIT(31) | ||
| 115 | |||
| 116 | #define PHY_CTRL_R19 0x4c | ||
| 117 | #define PHY_CTRL_R20 0x50 | ||
| 118 | #define PHY_CTRL_R20_USB2_IDDET_EN BIT(0) | ||
| 119 | #define PHY_CTRL_R20_USB2_OTG_VBUS_TRIM_2_0 GENMASK(3, 1) | ||
| 120 | #define PHY_CTRL_R20_USB2_OTG_VBUSDET_EN BIT(4) | ||
| 121 | #define PHY_CTRL_R20_USB2_AMON_EN BIT(5) | ||
| 122 | #define PHY_CTRL_R20_USB2_CAL_CODE_R5 BIT(6) | ||
| 123 | #define PHY_CTRL_R20_BYPASS_OTG_DET BIT(7) | ||
| 124 | #define PHY_CTRL_R20_USB2_DMON_EN BIT(8) | ||
| 125 | #define PHY_CTRL_R20_USB2_DMON_SEL_3_0 GENMASK(12, 9) | ||
| 126 | #define PHY_CTRL_R20_USB2_EDGE_DRV_EN BIT(13) | ||
| 127 | #define PHY_CTRL_R20_USB2_EDGE_DRV_TRIM_1_0 GENMASK(15, 14) | ||
| 128 | #define PHY_CTRL_R20_USB2_BGR_ADJ_4_0 GENMASK(20, 16) | ||
| 129 | #define PHY_CTRL_R20_USB2_BGR_START BIT(21) | ||
| 130 | #define PHY_CTRL_R20_USB2_BGR_VREF_4_0 GENMASK(28, 24) | ||
| 131 | #define PHY_CTRL_R20_USB2_BGR_DBG_1_0 GENMASK(30, 29) | ||
| 132 | #define PHY_CTRL_R20_BYPASS_CAL_DONE_R5 BIT(31) | ||
| 133 | |||
| 134 | #define PHY_CTRL_R21 0x54 | ||
| 135 | #define PHY_CTRL_R21_USB2_BGR_FORCE BIT(0) | ||
| 136 | #define PHY_CTRL_R21_USB2_CAL_ACK_EN BIT(1) | ||
| 137 | #define PHY_CTRL_R21_USB2_OTG_ACA_EN BIT(2) | ||
| 138 | #define PHY_CTRL_R21_USB2_TX_STRG_PD BIT(3) | ||
| 139 | #define PHY_CTRL_R21_USB2_OTG_ACA_TRIM_1_0 GENMASK(5, 4) | ||
| 140 | #define PHY_CTRL_R21_BYPASS_UTMI_CNTR GENMASK(15, 6) | ||
| 141 | #define PHY_CTRL_R21_BYPASS_UTMI_REG GENMASK(25, 20) | ||
| 142 | |||
| 143 | #define PHY_CTRL_R22 0x58 | ||
| 144 | #define PHY_CTRL_R23 0x5c | ||
| 145 | |||
| 146 | #define RESET_COMPLETE_TIME 1000 | ||
| 147 | #define PLL_RESET_COMPLETE_TIME 100 | ||
| 148 | |||
| 149 | struct phy_meson_g12a_usb2_priv { | ||
| 150 | struct device *dev; | ||
| 151 | struct regmap *regmap; | ||
| 152 | struct clk *clk; | ||
| 153 | struct reset_control *reset; | ||
| 154 | }; | ||
| 155 | |||
| 156 | static const struct regmap_config phy_meson_g12a_usb2_regmap_conf = { | ||
| 157 | .reg_bits = 8, | ||
| 158 | .val_bits = 32, | ||
| 159 | .reg_stride = 4, | ||
| 160 | .max_register = PHY_CTRL_R23, | ||
| 161 | }; | ||
| 162 | |||
| 163 | static int phy_meson_g12a_usb2_init(struct phy *phy) | ||
| 164 | { | ||
| 165 | struct phy_meson_g12a_usb2_priv *priv = phy_get_drvdata(phy); | ||
| 166 | int ret; | ||
| 167 | |||
| 168 | ret = reset_control_reset(priv->reset); | ||
| 169 | if (ret) | ||
| 170 | return ret; | ||
| 171 | |||
| 172 | udelay(RESET_COMPLETE_TIME); | ||
| 173 | |||
| 174 | /* usb2_otg_aca_en == 0 */ | ||
| 175 | regmap_update_bits(priv->regmap, PHY_CTRL_R21, | ||
| 176 | PHY_CTRL_R21_USB2_OTG_ACA_EN, 0); | ||
| 177 | |||
| 178 | /* PLL Setup : 24MHz * 20 / 1 = 480MHz */ | ||
| 179 | regmap_write(priv->regmap, PHY_CTRL_R16, | ||
| 180 | FIELD_PREP(PHY_CTRL_R16_MPLL_M, 20) | | ||
| 181 | FIELD_PREP(PHY_CTRL_R16_MPLL_N, 1) | | ||
| 182 | PHY_CTRL_R16_MPLL_LOAD | | ||
| 183 | FIELD_PREP(PHY_CTRL_R16_MPLL_LOCK_LONG, 1) | | ||
| 184 | PHY_CTRL_R16_MPLL_FAST_LOCK | | ||
| 185 | PHY_CTRL_R16_MPLL_EN | | ||
| 186 | PHY_CTRL_R16_MPLL_RESET); | ||
| 187 | |||
| 188 | regmap_write(priv->regmap, PHY_CTRL_R17, | ||
| 189 | FIELD_PREP(PHY_CTRL_R17_MPLL_FRAC_IN, 0) | | ||
| 190 | FIELD_PREP(PHY_CTRL_R17_MPLL_LAMBDA1, 7) | | ||
| 191 | FIELD_PREP(PHY_CTRL_R17_MPLL_LAMBDA0, 7) | | ||
| 192 | FIELD_PREP(PHY_CTRL_R17_MPLL_FILTER_PVT2, 2) | | ||
| 193 | FIELD_PREP(PHY_CTRL_R17_MPLL_FILTER_PVT1, 9)); | ||
| 194 | |||
| 195 | regmap_write(priv->regmap, PHY_CTRL_R18, | ||
| 196 | FIELD_PREP(PHY_CTRL_R18_MPLL_LKW_SEL, 1) | | ||
| 197 | FIELD_PREP(PHY_CTRL_R18_MPLL_LK_W, 9) | | ||
| 198 | FIELD_PREP(PHY_CTRL_R18_MPLL_LK_S, 0x27) | | ||
| 199 | FIELD_PREP(PHY_CTRL_R18_MPLL_PFD_GAIN, 1) | | ||
| 200 | FIELD_PREP(PHY_CTRL_R18_MPLL_ROU, 7) | | ||
| 201 | FIELD_PREP(PHY_CTRL_R18_MPLL_DATA_SEL, 3) | | ||
| 202 | FIELD_PREP(PHY_CTRL_R18_MPLL_BIAS_ADJ, 1) | | ||
| 203 | FIELD_PREP(PHY_CTRL_R18_MPLL_BB_MODE, 0) | | ||
| 204 | FIELD_PREP(PHY_CTRL_R18_MPLL_ALPHA, 3) | | ||
| 205 | FIELD_PREP(PHY_CTRL_R18_MPLL_ADJ_LDO, 1) | | ||
| 206 | PHY_CTRL_R18_MPLL_ACG_RANGE); | ||
| 207 | |||
| 208 | udelay(PLL_RESET_COMPLETE_TIME); | ||
| 209 | |||
| 210 | /* UnReset PLL */ | ||
| 211 | regmap_write(priv->regmap, PHY_CTRL_R16, | ||
| 212 | FIELD_PREP(PHY_CTRL_R16_MPLL_M, 20) | | ||
| 213 | FIELD_PREP(PHY_CTRL_R16_MPLL_N, 1) | | ||
| 214 | PHY_CTRL_R16_MPLL_LOAD | | ||
| 215 | FIELD_PREP(PHY_CTRL_R16_MPLL_LOCK_LONG, 1) | | ||
| 216 | PHY_CTRL_R16_MPLL_FAST_LOCK | | ||
| 217 | PHY_CTRL_R16_MPLL_EN); | ||
| 218 | |||
| 219 | /* PHY Tuning */ | ||
| 220 | regmap_write(priv->regmap, PHY_CTRL_R20, | ||
| 221 | FIELD_PREP(PHY_CTRL_R20_USB2_OTG_VBUS_TRIM_2_0, 4) | | ||
| 222 | PHY_CTRL_R20_USB2_OTG_VBUSDET_EN | | ||
| 223 | FIELD_PREP(PHY_CTRL_R20_USB2_DMON_SEL_3_0, 15) | | ||
| 224 | PHY_CTRL_R20_USB2_EDGE_DRV_EN | | ||
| 225 | FIELD_PREP(PHY_CTRL_R20_USB2_EDGE_DRV_TRIM_1_0, 3) | | ||
| 226 | FIELD_PREP(PHY_CTRL_R20_USB2_BGR_ADJ_4_0, 0) | | ||
| 227 | FIELD_PREP(PHY_CTRL_R20_USB2_BGR_VREF_4_0, 0) | | ||
| 228 | FIELD_PREP(PHY_CTRL_R20_USB2_BGR_DBG_1_0, 0)); | ||
| 229 | |||
| 230 | regmap_write(priv->regmap, PHY_CTRL_R4, | ||
| 231 | FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_7_0, 0xf) | | ||
| 232 | FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_15_8, 0xf) | | ||
| 233 | FIELD_PREP(PHY_CTRL_R4_CALIB_CODE_23_16, 0xf) | | ||
| 234 | PHY_CTRL_R4_TEST_BYPASS_MODE_EN | | ||
| 235 | FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_1_0, 0) | | ||
| 236 | FIELD_PREP(PHY_CTRL_R4_I_C2L_BIAS_TRIM_3_2, 0)); | ||
| 237 | |||
| 238 | /* Tuning Disconnect Threshold */ | ||
| 239 | regmap_write(priv->regmap, PHY_CTRL_R3, | ||
| 240 | FIELD_PREP(PHY_CTRL_R3_SQUELCH_REF, 0) | | ||
| 241 | FIELD_PREP(PHY_CTRL_R3_HSDIC_REF, 1) | | ||
| 242 | FIELD_PREP(PHY_CTRL_R3_DISC_THRESH, 3)); | ||
| 243 | |||
| 244 | /* Analog Settings */ | ||
| 245 | regmap_write(priv->regmap, PHY_CTRL_R14, 0); | ||
| 246 | regmap_write(priv->regmap, PHY_CTRL_R13, | ||
| 247 | PHY_CTRL_R13_UPDATE_PMA_SIGNALS | | ||
| 248 | FIELD_PREP(PHY_CTRL_R13_MIN_COUNT_FOR_SYNC_DET, 7)); | ||
| 249 | |||
| 250 | return 0; | ||
| 251 | } | ||
| 252 | |||
| 253 | static int phy_meson_g12a_usb2_exit(struct phy *phy) | ||
| 254 | { | ||
| 255 | struct phy_meson_g12a_usb2_priv *priv = phy_get_drvdata(phy); | ||
| 256 | |||
| 257 | return reset_control_reset(priv->reset); | ||
| 258 | } | ||
| 259 | |||
| 260 | /* set_mode is not needed, mode setting is handled via the UTMI bus */ | ||
| 261 | static const struct phy_ops phy_meson_g12a_usb2_ops = { | ||
| 262 | .init = phy_meson_g12a_usb2_init, | ||
| 263 | .exit = phy_meson_g12a_usb2_exit, | ||
| 264 | .owner = THIS_MODULE, | ||
| 265 | }; | ||
| 266 | |||
| 267 | static int phy_meson_g12a_usb2_probe(struct platform_device *pdev) | ||
| 268 | { | ||
| 269 | struct device *dev = &pdev->dev; | ||
| 270 | struct phy_provider *phy_provider; | ||
| 271 | struct resource *res; | ||
| 272 | struct phy_meson_g12a_usb2_priv *priv; | ||
| 273 | struct phy *phy; | ||
| 274 | void __iomem *base; | ||
| 275 | int ret; | ||
| 276 | |||
| 277 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
| 278 | if (!priv) | ||
| 279 | return -ENOMEM; | ||
| 280 | |||
| 281 | priv->dev = dev; | ||
| 282 | platform_set_drvdata(pdev, priv); | ||
| 283 | |||
| 284 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 285 | base = devm_ioremap_resource(dev, res); | ||
| 286 | if (IS_ERR(base)) | ||
| 287 | return PTR_ERR(base); | ||
| 288 | |||
| 289 | priv->regmap = devm_regmap_init_mmio(dev, base, | ||
| 290 | &phy_meson_g12a_usb2_regmap_conf); | ||
| 291 | if (IS_ERR(priv->regmap)) | ||
| 292 | return PTR_ERR(priv->regmap); | ||
| 293 | |||
| 294 | priv->clk = devm_clk_get(dev, "xtal"); | ||
| 295 | if (IS_ERR(priv->clk)) | ||
| 296 | return PTR_ERR(priv->clk); | ||
| 297 | |||
| 298 | priv->reset = devm_reset_control_get(dev, "phy"); | ||
| 299 | if (IS_ERR(priv->reset)) | ||
| 300 | return PTR_ERR(priv->reset); | ||
| 301 | |||
| 302 | ret = reset_control_deassert(priv->reset); | ||
| 303 | if (ret) | ||
| 304 | return ret; | ||
| 305 | |||
| 306 | phy = devm_phy_create(dev, NULL, &phy_meson_g12a_usb2_ops); | ||
| 307 | if (IS_ERR(phy)) { | ||
| 308 | ret = PTR_ERR(phy); | ||
| 309 | if (ret != -EPROBE_DEFER) | ||
| 310 | dev_err(dev, "failed to create PHY\n"); | ||
| 311 | |||
| 312 | return ret; | ||
| 313 | } | ||
| 314 | |||
| 315 | phy_set_bus_width(phy, 8); | ||
| 316 | phy_set_drvdata(phy, priv); | ||
| 317 | |||
| 318 | phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); | ||
| 319 | |||
| 320 | return PTR_ERR_OR_ZERO(phy_provider); | ||
| 321 | } | ||
| 322 | |||
| 323 | static const struct of_device_id phy_meson_g12a_usb2_of_match[] = { | ||
| 324 | { .compatible = "amlogic,g12a-usb2-phy", }, | ||
| 325 | { }, | ||
| 326 | }; | ||
| 327 | MODULE_DEVICE_TABLE(of, phy_meson_g12a_usb2_of_match); | ||
| 328 | |||
| 329 | static struct platform_driver phy_meson_g12a_usb2_driver = { | ||
| 330 | .probe = phy_meson_g12a_usb2_probe, | ||
| 331 | .driver = { | ||
| 332 | .name = "phy-meson-g12a-usb2", | ||
| 333 | .of_match_table = phy_meson_g12a_usb2_of_match, | ||
| 334 | }, | ||
| 335 | }; | ||
| 336 | module_platform_driver(phy_meson_g12a_usb2_driver); | ||
| 337 | |||
| 338 | MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>"); | ||
| 339 | MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>"); | ||
| 340 | MODULE_DESCRIPTION("Meson G12A USB2 PHY driver"); | ||
| 341 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c b/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c new file mode 100644 index 000000000000..6233a7979a93 --- /dev/null +++ b/drivers/phy/amlogic/phy-meson-g12a-usb3-pcie.c | |||
| @@ -0,0 +1,413 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * Amlogic G12A USB3 + PCIE Combo PHY driver | ||
| 4 | * | ||
| 5 | * Copyright (C) 2017 Amlogic, Inc. All rights reserved | ||
| 6 | * Copyright (C) 2019 BayLibre, SAS | ||
| 7 | * Author: Neil Armstrong <narmstrong@baylibre.com> | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <linux/bitfield.h> | ||
| 11 | #include <linux/bitops.h> | ||
| 12 | #include <linux/clk.h> | ||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/of_device.h> | ||
| 15 | #include <linux/phy/phy.h> | ||
| 16 | #include <linux/regmap.h> | ||
| 17 | #include <linux/reset.h> | ||
| 18 | #include <linux/platform_device.h> | ||
| 19 | #include <dt-bindings/phy/phy.h> | ||
| 20 | |||
| 21 | #define PHY_R0 0x00 | ||
| 22 | #define PHY_R0_PCIE_POWER_STATE GENMASK(4, 0) | ||
| 23 | #define PHY_R0_PCIE_USB3_SWITCH GENMASK(6, 5) | ||
| 24 | |||
| 25 | #define PHY_R1 0x04 | ||
| 26 | #define PHY_R1_PHY_TX1_TERM_OFFSET GENMASK(4, 0) | ||
| 27 | #define PHY_R1_PHY_TX0_TERM_OFFSET GENMASK(9, 5) | ||
| 28 | #define PHY_R1_PHY_RX1_EQ GENMASK(12, 10) | ||
| 29 | #define PHY_R1_PHY_RX0_EQ GENMASK(15, 13) | ||
| 30 | #define PHY_R1_PHY_LOS_LEVEL GENMASK(20, 16) | ||
| 31 | #define PHY_R1_PHY_LOS_BIAS GENMASK(23, 21) | ||
| 32 | #define PHY_R1_PHY_REF_CLKDIV2 BIT(24) | ||
| 33 | #define PHY_R1_PHY_MPLL_MULTIPLIER GENMASK(31, 25) | ||
| 34 | |||
| 35 | #define PHY_R2 0x08 | ||
| 36 | #define PHY_R2_PCS_TX_DEEMPH_GEN2_6DB GENMASK(5, 0) | ||
| 37 | #define PHY_R2_PCS_TX_DEEMPH_GEN2_3P5DB GENMASK(11, 6) | ||
| 38 | #define PHY_R2_PCS_TX_DEEMPH_GEN1 GENMASK(17, 12) | ||
| 39 | #define PHY_R2_PHY_TX_VBOOST_LVL GENMASK(20, 18) | ||
| 40 | |||
| 41 | #define PHY_R4 0x10 | ||
| 42 | #define PHY_R4_PHY_CR_WRITE BIT(0) | ||
| 43 | #define PHY_R4_PHY_CR_READ BIT(1) | ||
| 44 | #define PHY_R4_PHY_CR_DATA_IN GENMASK(17, 2) | ||
| 45 | #define PHY_R4_PHY_CR_CAP_DATA BIT(18) | ||
| 46 | #define PHY_R4_PHY_CR_CAP_ADDR BIT(19) | ||
| 47 | |||
| 48 | #define PHY_R5 0x14 | ||
| 49 | #define PHY_R5_PHY_CR_DATA_OUT GENMASK(15, 0) | ||
| 50 | #define PHY_R5_PHY_CR_ACK BIT(16) | ||
| 51 | #define PHY_R5_PHY_BS_OUT BIT(17) | ||
| 52 | |||
| 53 | struct phy_g12a_usb3_pcie_priv { | ||
| 54 | struct regmap *regmap; | ||
| 55 | struct regmap *regmap_cr; | ||
| 56 | struct clk *clk_ref; | ||
| 57 | struct reset_control *reset; | ||
| 58 | struct phy *phy; | ||
| 59 | unsigned int mode; | ||
| 60 | }; | ||
| 61 | |||
| 62 | static const struct regmap_config phy_g12a_usb3_pcie_regmap_conf = { | ||
| 63 | .reg_bits = 8, | ||
| 64 | .val_bits = 32, | ||
| 65 | .reg_stride = 4, | ||
| 66 | .max_register = PHY_R5, | ||
| 67 | }; | ||
| 68 | |||
| 69 | static int phy_g12a_usb3_pcie_cr_bus_addr(struct phy_g12a_usb3_pcie_priv *priv, | ||
| 70 | unsigned int addr) | ||
| 71 | { | ||
| 72 | unsigned int val, reg; | ||
| 73 | int ret; | ||
| 74 | |||
| 75 | reg = FIELD_PREP(PHY_R4_PHY_CR_DATA_IN, addr); | ||
| 76 | |||
| 77 | regmap_write(priv->regmap, PHY_R4, reg); | ||
| 78 | regmap_write(priv->regmap, PHY_R4, reg); | ||
| 79 | |||
| 80 | regmap_write(priv->regmap, PHY_R4, reg | PHY_R4_PHY_CR_CAP_ADDR); | ||
| 81 | |||
| 82 | ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, | ||
| 83 | (val & PHY_R5_PHY_CR_ACK), | ||
| 84 | 5, 1000); | ||
| 85 | if (ret) | ||
| 86 | return ret; | ||
| 87 | |||
| 88 | regmap_write(priv->regmap, PHY_R4, reg); | ||
| 89 | |||
| 90 | ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, | ||
| 91 | !(val & PHY_R5_PHY_CR_ACK), | ||
| 92 | 5, 1000); | ||
| 93 | if (ret) | ||
| 94 | return ret; | ||
| 95 | |||
| 96 | return 0; | ||
| 97 | } | ||
| 98 | |||
| 99 | static int phy_g12a_usb3_pcie_cr_bus_read(void *context, unsigned int addr, | ||
| 100 | unsigned int *data) | ||
| 101 | { | ||
| 102 | struct phy_g12a_usb3_pcie_priv *priv = context; | ||
| 103 | unsigned int val; | ||
| 104 | int ret; | ||
| 105 | |||
| 106 | ret = phy_g12a_usb3_pcie_cr_bus_addr(priv, addr); | ||
| 107 | if (ret) | ||
| 108 | return ret; | ||
| 109 | |||
| 110 | regmap_write(priv->regmap, PHY_R4, 0); | ||
| 111 | regmap_write(priv->regmap, PHY_R4, PHY_R4_PHY_CR_READ); | ||
| 112 | |||
| 113 | ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, | ||
| 114 | (val & PHY_R5_PHY_CR_ACK), | ||
| 115 | 5, 1000); | ||
| 116 | if (ret) | ||
| 117 | return ret; | ||
| 118 | |||
| 119 | *data = FIELD_GET(PHY_R5_PHY_CR_DATA_OUT, val); | ||
| 120 | |||
| 121 | regmap_write(priv->regmap, PHY_R4, 0); | ||
| 122 | |||
| 123 | ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, | ||
| 124 | !(val & PHY_R5_PHY_CR_ACK), | ||
| 125 | 5, 1000); | ||
| 126 | if (ret) | ||
| 127 | return ret; | ||
| 128 | |||
| 129 | return 0; | ||
| 130 | } | ||
| 131 | |||
| 132 | static int phy_g12a_usb3_pcie_cr_bus_write(void *context, unsigned int addr, | ||
| 133 | unsigned int data) | ||
| 134 | { | ||
| 135 | struct phy_g12a_usb3_pcie_priv *priv = context; | ||
| 136 | unsigned int val, reg; | ||
| 137 | int ret; | ||
| 138 | |||
| 139 | ret = phy_g12a_usb3_pcie_cr_bus_addr(priv, addr); | ||
| 140 | if (ret) | ||
| 141 | return ret; | ||
| 142 | |||
| 143 | reg = FIELD_PREP(PHY_R4_PHY_CR_DATA_IN, data); | ||
| 144 | |||
| 145 | regmap_write(priv->regmap, PHY_R4, reg); | ||
| 146 | regmap_write(priv->regmap, PHY_R4, reg); | ||
| 147 | |||
| 148 | regmap_write(priv->regmap, PHY_R4, reg | PHY_R4_PHY_CR_CAP_DATA); | ||
| 149 | |||
| 150 | ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, | ||
| 151 | (val & PHY_R5_PHY_CR_ACK), | ||
| 152 | 5, 1000); | ||
| 153 | if (ret) | ||
| 154 | return ret; | ||
| 155 | |||
| 156 | regmap_write(priv->regmap, PHY_R4, reg); | ||
| 157 | |||
| 158 | ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, | ||
| 159 | (val & PHY_R5_PHY_CR_ACK) == 0, | ||
| 160 | 5, 1000); | ||
| 161 | if (ret) | ||
| 162 | return ret; | ||
| 163 | |||
| 164 | regmap_write(priv->regmap, PHY_R4, reg); | ||
| 165 | |||
| 166 | regmap_write(priv->regmap, PHY_R4, reg | PHY_R4_PHY_CR_WRITE); | ||
| 167 | |||
| 168 | ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, | ||
| 169 | (val & PHY_R5_PHY_CR_ACK), | ||
| 170 | 5, 1000); | ||
| 171 | if (ret) | ||
| 172 | return ret; | ||
| 173 | |||
| 174 | regmap_write(priv->regmap, PHY_R4, reg); | ||
| 175 | |||
| 176 | ret = regmap_read_poll_timeout(priv->regmap, PHY_R5, val, | ||
| 177 | (val & PHY_R5_PHY_CR_ACK) == 0, | ||
| 178 | 5, 1000); | ||
| 179 | if (ret) | ||
| 180 | return ret; | ||
| 181 | |||
| 182 | return 0; | ||
| 183 | } | ||
| 184 | |||
| 185 | static const struct regmap_config phy_g12a_usb3_pcie_cr_regmap_conf = { | ||
| 186 | .reg_bits = 16, | ||
| 187 | .val_bits = 16, | ||
| 188 | .reg_read = phy_g12a_usb3_pcie_cr_bus_read, | ||
| 189 | .reg_write = phy_g12a_usb3_pcie_cr_bus_write, | ||
| 190 | .max_register = 0xffff, | ||
| 191 | .fast_io = true, | ||
| 192 | }; | ||
| 193 | |||
| 194 | static int phy_g12a_usb3_init(struct phy *phy) | ||
| 195 | { | ||
| 196 | struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); | ||
| 197 | int data, ret; | ||
| 198 | |||
| 199 | /* Switch PHY to USB3 */ | ||
| 200 | /* TODO figure out how to handle when PCIe was set in the bootloader */ | ||
| 201 | regmap_update_bits(priv->regmap, PHY_R0, | ||
| 202 | PHY_R0_PCIE_USB3_SWITCH, | ||
| 203 | PHY_R0_PCIE_USB3_SWITCH); | ||
| 204 | |||
| 205 | /* | ||
| 206 | * WORKAROUND: There is SSPHY suspend bug due to | ||
| 207 | * which USB enumerates | ||
| 208 | * in HS mode instead of SS mode. Workaround it by asserting | ||
| 209 | * LANE0.TX_ALT_BLOCK.EN_ALT_BUS to enable TX to use alt bus | ||
| 210 | * mode | ||
| 211 | */ | ||
| 212 | ret = regmap_update_bits(priv->regmap_cr, 0x102d, BIT(7), BIT(7)); | ||
| 213 | if (ret) | ||
| 214 | return ret; | ||
| 215 | |||
| 216 | ret = regmap_update_bits(priv->regmap_cr, 0x1010, 0xff0, 20); | ||
| 217 | if (ret) | ||
| 218 | return ret; | ||
| 219 | |||
| 220 | /* | ||
| 221 | * Fix RX Equalization setting as follows | ||
| 222 | * LANE0.RX_OVRD_IN_HI. RX_EQ_EN set to 0 | ||
| 223 | * LANE0.RX_OVRD_IN_HI.RX_EQ_EN_OVRD set to 1 | ||
| 224 | * LANE0.RX_OVRD_IN_HI.RX_EQ set to 3 | ||
| 225 | * LANE0.RX_OVRD_IN_HI.RX_EQ_OVRD set to 1 | ||
| 226 | */ | ||
| 227 | ret = regmap_read(priv->regmap_cr, 0x1006, &data); | ||
| 228 | if (ret) | ||
| 229 | return ret; | ||
| 230 | |||
| 231 | data &= ~BIT(6); | ||
| 232 | data |= BIT(7); | ||
| 233 | data &= ~(0x7 << 8); | ||
| 234 | data |= (0x3 << 8); | ||
| 235 | data |= (1 << 11); | ||
| 236 | ret = regmap_write(priv->regmap_cr, 0x1006, data); | ||
| 237 | if (ret) | ||
| 238 | return ret; | ||
| 239 | |||
| 240 | /* | ||
| 241 | * Set EQ and TX launch amplitudes as follows | ||
| 242 | * LANE0.TX_OVRD_DRV_LO.PREEMPH set to 22 | ||
| 243 | * LANE0.TX_OVRD_DRV_LO.AMPLITUDE set to 127 | ||
| 244 | * LANE0.TX_OVRD_DRV_LO.EN set to 1. | ||
| 245 | */ | ||
| 246 | ret = regmap_read(priv->regmap_cr, 0x1002, &data); | ||
| 247 | if (ret) | ||
| 248 | return ret; | ||
| 249 | |||
| 250 | data &= ~0x3f80; | ||
| 251 | data |= (0x16 << 7); | ||
| 252 | data &= ~0x7f; | ||
| 253 | data |= (0x7f | BIT(14)); | ||
| 254 | ret = regmap_write(priv->regmap_cr, 0x1002, data); | ||
| 255 | if (ret) | ||
| 256 | return ret; | ||
| 257 | |||
| 258 | /* MPLL_LOOP_CTL.PROP_CNTRL = 8 */ | ||
| 259 | ret = regmap_update_bits(priv->regmap_cr, 0x30, 0xf << 4, 8 << 4); | ||
| 260 | if (ret) | ||
| 261 | return ret; | ||
| 262 | |||
| 263 | regmap_update_bits(priv->regmap, PHY_R2, | ||
| 264 | PHY_R2_PHY_TX_VBOOST_LVL, | ||
| 265 | FIELD_PREP(PHY_R2_PHY_TX_VBOOST_LVL, 0x4)); | ||
| 266 | |||
| 267 | regmap_update_bits(priv->regmap, PHY_R1, | ||
| 268 | PHY_R1_PHY_LOS_BIAS | PHY_R1_PHY_LOS_LEVEL, | ||
| 269 | FIELD_PREP(PHY_R1_PHY_LOS_BIAS, 4) | | ||
| 270 | FIELD_PREP(PHY_R1_PHY_LOS_LEVEL, 9)); | ||
| 271 | |||
| 272 | return 0; | ||
| 273 | } | ||
| 274 | |||
| 275 | static int phy_g12a_usb3_pcie_init(struct phy *phy) | ||
| 276 | { | ||
| 277 | struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); | ||
| 278 | int ret; | ||
| 279 | |||
| 280 | ret = reset_control_reset(priv->reset); | ||
| 281 | if (ret) | ||
| 282 | return ret; | ||
| 283 | |||
| 284 | if (priv->mode == PHY_TYPE_USB3) | ||
| 285 | return phy_g12a_usb3_init(phy); | ||
| 286 | |||
| 287 | /* Power UP PCIE */ | ||
| 288 | /* TODO figure out when the bootloader has set USB3 mode before */ | ||
| 289 | regmap_update_bits(priv->regmap, PHY_R0, | ||
| 290 | PHY_R0_PCIE_POWER_STATE, | ||
| 291 | FIELD_PREP(PHY_R0_PCIE_POWER_STATE, 0x1c)); | ||
| 292 | |||
| 293 | return 0; | ||
| 294 | } | ||
| 295 | |||
| 296 | static int phy_g12a_usb3_pcie_exit(struct phy *phy) | ||
| 297 | { | ||
| 298 | struct phy_g12a_usb3_pcie_priv *priv = phy_get_drvdata(phy); | ||
| 299 | |||
| 300 | return reset_control_reset(priv->reset); | ||
| 301 | } | ||
| 302 | |||
| 303 | static struct phy *phy_g12a_usb3_pcie_xlate(struct device *dev, | ||
| 304 | struct of_phandle_args *args) | ||
| 305 | { | ||
| 306 | struct phy_g12a_usb3_pcie_priv *priv = dev_get_drvdata(dev); | ||
| 307 | unsigned int mode; | ||
| 308 | |||
| 309 | if (args->args_count < 1) { | ||
| 310 | dev_err(dev, "invalid number of arguments\n"); | ||
| 311 | return ERR_PTR(-EINVAL); | ||
| 312 | } | ||
| 313 | |||
| 314 | mode = args->args[0]; | ||
| 315 | |||
| 316 | if (mode != PHY_TYPE_USB3 && mode != PHY_TYPE_PCIE) { | ||
| 317 | dev_err(dev, "invalid phy mode select argument\n"); | ||
| 318 | return ERR_PTR(-EINVAL); | ||
| 319 | } | ||
| 320 | |||
| 321 | priv->mode = mode; | ||
| 322 | |||
| 323 | return priv->phy; | ||
| 324 | } | ||
| 325 | |||
| 326 | static const struct phy_ops phy_g12a_usb3_pcie_ops = { | ||
| 327 | .init = phy_g12a_usb3_pcie_init, | ||
| 328 | .exit = phy_g12a_usb3_pcie_exit, | ||
| 329 | .owner = THIS_MODULE, | ||
| 330 | }; | ||
| 331 | |||
| 332 | static int phy_g12a_usb3_pcie_probe(struct platform_device *pdev) | ||
| 333 | { | ||
| 334 | struct device *dev = &pdev->dev; | ||
| 335 | struct device_node *np = dev->of_node; | ||
| 336 | struct phy_g12a_usb3_pcie_priv *priv; | ||
| 337 | struct resource *res; | ||
| 338 | struct phy_provider *phy_provider; | ||
| 339 | void __iomem *base; | ||
| 340 | int ret; | ||
| 341 | |||
| 342 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
| 343 | if (!priv) | ||
| 344 | return -ENOMEM; | ||
| 345 | |||
| 346 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 347 | base = devm_ioremap_resource(dev, res); | ||
| 348 | if (IS_ERR(base)) | ||
| 349 | return PTR_ERR(base); | ||
| 350 | |||
| 351 | priv->regmap = devm_regmap_init_mmio(dev, base, | ||
| 352 | &phy_g12a_usb3_pcie_regmap_conf); | ||
| 353 | if (IS_ERR(priv->regmap)) | ||
| 354 | return PTR_ERR(priv->regmap); | ||
| 355 | |||
| 356 | priv->regmap_cr = devm_regmap_init(dev, NULL, priv, | ||
| 357 | &phy_g12a_usb3_pcie_cr_regmap_conf); | ||
| 358 | if (IS_ERR(priv->regmap_cr)) | ||
| 359 | return PTR_ERR(priv->regmap_cr); | ||
| 360 | |||
| 361 | priv->clk_ref = devm_clk_get(dev, "ref_clk"); | ||
| 362 | if (IS_ERR(priv->clk_ref)) | ||
| 363 | return PTR_ERR(priv->clk_ref); | ||
| 364 | |||
| 365 | ret = clk_prepare_enable(priv->clk_ref); | ||
| 366 | if (ret) | ||
| 367 | goto err_disable_clk_ref; | ||
| 368 | |||
| 369 | priv->reset = devm_reset_control_array_get(dev, false, false); | ||
| 370 | if (IS_ERR(priv->reset)) | ||
| 371 | return PTR_ERR(priv->reset); | ||
| 372 | |||
| 373 | priv->phy = devm_phy_create(dev, np, &phy_g12a_usb3_pcie_ops); | ||
| 374 | if (IS_ERR(priv->phy)) { | ||
| 375 | ret = PTR_ERR(priv->phy); | ||
| 376 | if (ret != -EPROBE_DEFER) | ||
| 377 | dev_err(dev, "failed to create PHY\n"); | ||
| 378 | |||
| 379 | return ret; | ||
| 380 | } | ||
| 381 | |||
| 382 | phy_set_drvdata(priv->phy, priv); | ||
| 383 | dev_set_drvdata(dev, priv); | ||
| 384 | |||
| 385 | phy_provider = devm_of_phy_provider_register(dev, | ||
| 386 | phy_g12a_usb3_pcie_xlate); | ||
| 387 | |||
| 388 | return PTR_ERR_OR_ZERO(phy_provider); | ||
| 389 | |||
| 390 | err_disable_clk_ref: | ||
| 391 | clk_disable_unprepare(priv->clk_ref); | ||
| 392 | |||
| 393 | return ret; | ||
| 394 | } | ||
| 395 | |||
| 396 | static const struct of_device_id phy_g12a_usb3_pcie_of_match[] = { | ||
| 397 | { .compatible = "amlogic,g12a-usb3-pcie-phy", }, | ||
| 398 | { }, | ||
| 399 | }; | ||
| 400 | MODULE_DEVICE_TABLE(of, phy_g12a_usb3_pcie_of_match); | ||
| 401 | |||
| 402 | static struct platform_driver phy_g12a_usb3_pcie_driver = { | ||
| 403 | .probe = phy_g12a_usb3_pcie_probe, | ||
| 404 | .driver = { | ||
| 405 | .name = "phy-g12a-usb3-pcie", | ||
| 406 | .of_match_table = phy_g12a_usb3_pcie_of_match, | ||
| 407 | }, | ||
| 408 | }; | ||
| 409 | module_platform_driver(phy_g12a_usb3_pcie_driver); | ||
| 410 | |||
| 411 | MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>"); | ||
| 412 | MODULE_DESCRIPTION("Amlogic G12A USB3 + PCIE Combo PHY driver"); | ||
| 413 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/phy/amlogic/phy-meson-gxl-usb2.c b/drivers/phy/amlogic/phy-meson-gxl-usb2.c index 148ef0bdb9c1..4cbee412f2b0 100644 --- a/drivers/phy/amlogic/phy-meson-gxl-usb2.c +++ b/drivers/phy/amlogic/phy-meson-gxl-usb2.c | |||
| @@ -261,14 +261,9 @@ static int phy_meson_gxl_usb2_probe(struct platform_device *pdev) | |||
| 261 | if (IS_ERR(priv->regmap)) | 261 | if (IS_ERR(priv->regmap)) |
| 262 | return PTR_ERR(priv->regmap); | 262 | return PTR_ERR(priv->regmap); |
| 263 | 263 | ||
| 264 | priv->clk = devm_clk_get(dev, "phy"); | 264 | priv->clk = devm_clk_get_optional(dev, "phy"); |
| 265 | if (IS_ERR(priv->clk)) { | 265 | if (IS_ERR(priv->clk)) |
| 266 | ret = PTR_ERR(priv->clk); | 266 | return PTR_ERR(priv->clk); |
| 267 | if (ret == -ENOENT) | ||
| 268 | priv->clk = NULL; | ||
| 269 | else | ||
| 270 | return ret; | ||
| 271 | } | ||
| 272 | 267 | ||
| 273 | priv->reset = devm_reset_control_get_optional_shared(dev, "phy"); | 268 | priv->reset = devm_reset_control_get_optional_shared(dev, "phy"); |
| 274 | if (IS_ERR(priv->reset)) | 269 | if (IS_ERR(priv->reset)) |
diff --git a/drivers/phy/broadcom/Kconfig b/drivers/phy/broadcom/Kconfig index aa917a61071d..f30f4819c3bb 100644 --- a/drivers/phy/broadcom/Kconfig +++ b/drivers/phy/broadcom/Kconfig | |||
| @@ -10,6 +10,17 @@ config PHY_CYGNUS_PCIE | |||
| 10 | Enable this to support the Broadcom Cygnus PCIe PHY. | 10 | Enable this to support the Broadcom Cygnus PCIe PHY. |
| 11 | If unsure, say N. | 11 | If unsure, say N. |
| 12 | 12 | ||
| 13 | config PHY_BCM_SR_USB | ||
| 14 | tristate "Broadcom Stingray USB PHY driver" | ||
| 15 | depends on OF && (ARCH_BCM_IPROC || COMPILE_TEST) | ||
| 16 | select GENERIC_PHY | ||
| 17 | default ARCH_BCM_IPROC | ||
| 18 | help | ||
| 19 | Enable this to support the Broadcom Stingray USB PHY | ||
| 20 | driver. It supports all versions of Superspeed and | ||
| 21 | Highspeed PHYs. | ||
| 22 | If unsure, say N. | ||
| 23 | |||
| 13 | config BCM_KONA_USB2_PHY | 24 | config BCM_KONA_USB2_PHY |
| 14 | tristate "Broadcom Kona USB2 PHY Driver" | 25 | tristate "Broadcom Kona USB2 PHY Driver" |
| 15 | depends on HAS_IOMEM | 26 | depends on HAS_IOMEM |
diff --git a/drivers/phy/broadcom/Makefile b/drivers/phy/broadcom/Makefile index 0f60184e6662..f453c7d3ffff 100644 --- a/drivers/phy/broadcom/Makefile +++ b/drivers/phy/broadcom/Makefile | |||
| @@ -11,3 +11,4 @@ obj-$(CONFIG_PHY_BRCM_USB) += phy-brcm-usb-dvr.o | |||
| 11 | phy-brcm-usb-dvr-objs := phy-brcm-usb.o phy-brcm-usb-init.o | 11 | phy-brcm-usb-dvr-objs := phy-brcm-usb.o phy-brcm-usb-init.o |
| 12 | 12 | ||
| 13 | obj-$(CONFIG_PHY_BCM_SR_PCIE) += phy-bcm-sr-pcie.o | 13 | obj-$(CONFIG_PHY_BCM_SR_PCIE) += phy-bcm-sr-pcie.o |
| 14 | obj-$(CONFIG_PHY_BCM_SR_USB) += phy-bcm-sr-usb.o | ||
diff --git a/drivers/phy/broadcom/phy-bcm-sr-usb.c b/drivers/phy/broadcom/phy-bcm-sr-usb.c new file mode 100644 index 000000000000..fe6c58910e4c --- /dev/null +++ b/drivers/phy/broadcom/phy-bcm-sr-usb.c | |||
| @@ -0,0 +1,394 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * Copyright (C) 2016-2018 Broadcom | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <linux/delay.h> | ||
| 7 | #include <linux/io.h> | ||
| 8 | #include <linux/module.h> | ||
| 9 | #include <linux/of.h> | ||
| 10 | #include <linux/phy/phy.h> | ||
| 11 | #include <linux/platform_device.h> | ||
| 12 | |||
| 13 | enum bcm_usb_phy_version { | ||
| 14 | BCM_SR_USB_COMBO_PHY, | ||
| 15 | BCM_SR_USB_HS_PHY, | ||
| 16 | }; | ||
| 17 | |||
| 18 | enum bcm_usb_phy_reg { | ||
| 19 | PLL_NDIV_FRAC, | ||
| 20 | PLL_NDIV_INT, | ||
| 21 | PLL_CTRL, | ||
| 22 | PHY_CTRL, | ||
| 23 | PHY_PLL_CTRL, | ||
| 24 | }; | ||
| 25 | |||
| 26 | /* USB PHY registers */ | ||
| 27 | |||
| 28 | static const u8 bcm_usb_combo_phy_ss[] = { | ||
| 29 | [PLL_CTRL] = 0x18, | ||
| 30 | [PHY_CTRL] = 0x14, | ||
| 31 | }; | ||
| 32 | |||
| 33 | static const u8 bcm_usb_combo_phy_hs[] = { | ||
| 34 | [PLL_NDIV_FRAC] = 0x04, | ||
| 35 | [PLL_NDIV_INT] = 0x08, | ||
| 36 | [PLL_CTRL] = 0x0c, | ||
| 37 | [PHY_CTRL] = 0x10, | ||
| 38 | }; | ||
| 39 | |||
| 40 | #define HSPLL_NDIV_INT_VAL 0x13 | ||
| 41 | #define HSPLL_NDIV_FRAC_VAL 0x1005 | ||
| 42 | |||
| 43 | static const u8 bcm_usb_hs_phy[] = { | ||
| 44 | [PLL_NDIV_FRAC] = 0x0, | ||
| 45 | [PLL_NDIV_INT] = 0x4, | ||
| 46 | [PLL_CTRL] = 0x8, | ||
| 47 | [PHY_CTRL] = 0xc, | ||
| 48 | }; | ||
| 49 | |||
| 50 | enum pll_ctrl_bits { | ||
| 51 | PLL_RESETB, | ||
| 52 | SSPLL_SUSPEND_EN, | ||
| 53 | PLL_SEQ_START, | ||
| 54 | PLL_LOCK, | ||
| 55 | PLL_PDIV, | ||
| 56 | }; | ||
| 57 | |||
| 58 | static const u8 u3pll_ctrl[] = { | ||
| 59 | [PLL_RESETB] = 0, | ||
| 60 | [SSPLL_SUSPEND_EN] = 1, | ||
| 61 | [PLL_SEQ_START] = 2, | ||
| 62 | [PLL_LOCK] = 3, | ||
| 63 | }; | ||
| 64 | |||
| 65 | #define HSPLL_PDIV_MASK 0xF | ||
| 66 | #define HSPLL_PDIV_VAL 0x1 | ||
| 67 | |||
| 68 | static const u8 u2pll_ctrl[] = { | ||
| 69 | [PLL_PDIV] = 1, | ||
| 70 | [PLL_RESETB] = 5, | ||
| 71 | [PLL_LOCK] = 6, | ||
| 72 | }; | ||
| 73 | |||
| 74 | enum bcm_usb_phy_ctrl_bits { | ||
| 75 | CORERDY, | ||
| 76 | AFE_LDO_PWRDWNB, | ||
| 77 | AFE_PLL_PWRDWNB, | ||
| 78 | AFE_BG_PWRDWNB, | ||
| 79 | PHY_ISO, | ||
| 80 | PHY_RESETB, | ||
| 81 | PHY_PCTL, | ||
| 82 | }; | ||
| 83 | |||
| 84 | #define PHY_PCTL_MASK 0xffff | ||
| 85 | /* | ||
| 86 | * 0x0806 of PCTL_VAL has below bits set | ||
| 87 | * BIT-8 : refclk divider 1 | ||
| 88 | * BIT-3:2: device mode; mode is not effect | ||
| 89 | * BIT-1: soft reset active low | ||
| 90 | */ | ||
| 91 | #define HSPHY_PCTL_VAL 0x0806 | ||
| 92 | #define SSPHY_PCTL_VAL 0x0006 | ||
| 93 | |||
| 94 | static const u8 u3phy_ctrl[] = { | ||
| 95 | [PHY_RESETB] = 1, | ||
| 96 | [PHY_PCTL] = 2, | ||
| 97 | }; | ||
| 98 | |||
| 99 | static const u8 u2phy_ctrl[] = { | ||
| 100 | [CORERDY] = 0, | ||
| 101 | [AFE_LDO_PWRDWNB] = 1, | ||
| 102 | [AFE_PLL_PWRDWNB] = 2, | ||
| 103 | [AFE_BG_PWRDWNB] = 3, | ||
| 104 | [PHY_ISO] = 4, | ||
| 105 | [PHY_RESETB] = 5, | ||
| 106 | [PHY_PCTL] = 6, | ||
| 107 | }; | ||
| 108 | |||
| 109 | struct bcm_usb_phy_cfg { | ||
| 110 | uint32_t type; | ||
| 111 | uint32_t version; | ||
| 112 | void __iomem *regs; | ||
| 113 | struct phy *phy; | ||
| 114 | const u8 *offset; | ||
| 115 | }; | ||
| 116 | |||
| 117 | #define PLL_LOCK_RETRY_COUNT 1000 | ||
| 118 | |||
| 119 | enum bcm_usb_phy_type { | ||
| 120 | USB_HS_PHY, | ||
| 121 | USB_SS_PHY, | ||
| 122 | }; | ||
| 123 | |||
| 124 | #define NUM_BCM_SR_USB_COMBO_PHYS 2 | ||
| 125 | |||
| 126 | static inline void bcm_usb_reg32_clrbits(void __iomem *addr, uint32_t clear) | ||
| 127 | { | ||
| 128 | writel(readl(addr) & ~clear, addr); | ||
| 129 | } | ||
| 130 | |||
| 131 | static inline void bcm_usb_reg32_setbits(void __iomem *addr, uint32_t set) | ||
| 132 | { | ||
| 133 | writel(readl(addr) | set, addr); | ||
| 134 | } | ||
| 135 | |||
| 136 | static int bcm_usb_pll_lock_check(void __iomem *addr, u32 bit) | ||
| 137 | { | ||
| 138 | int retry; | ||
| 139 | u32 rd_data; | ||
| 140 | |||
| 141 | retry = PLL_LOCK_RETRY_COUNT; | ||
| 142 | do { | ||
| 143 | rd_data = readl(addr); | ||
| 144 | if (rd_data & bit) | ||
| 145 | return 0; | ||
| 146 | udelay(1); | ||
| 147 | } while (--retry > 0); | ||
| 148 | |||
| 149 | pr_err("%s: FAIL\n", __func__); | ||
| 150 | return -ETIMEDOUT; | ||
| 151 | } | ||
| 152 | |||
| 153 | static int bcm_usb_ss_phy_init(struct bcm_usb_phy_cfg *phy_cfg) | ||
| 154 | { | ||
| 155 | int ret = 0; | ||
| 156 | void __iomem *regs = phy_cfg->regs; | ||
| 157 | const u8 *offset; | ||
| 158 | u32 rd_data; | ||
| 159 | |||
| 160 | offset = phy_cfg->offset; | ||
| 161 | |||
| 162 | /* Set pctl with mode and soft reset */ | ||
| 163 | rd_data = readl(regs + offset[PHY_CTRL]); | ||
| 164 | rd_data &= ~(PHY_PCTL_MASK << u3phy_ctrl[PHY_PCTL]); | ||
| 165 | rd_data |= (SSPHY_PCTL_VAL << u3phy_ctrl[PHY_PCTL]); | ||
| 166 | writel(rd_data, regs + offset[PHY_CTRL]); | ||
| 167 | |||
| 168 | bcm_usb_reg32_clrbits(regs + offset[PLL_CTRL], | ||
| 169 | BIT(u3pll_ctrl[SSPLL_SUSPEND_EN])); | ||
| 170 | bcm_usb_reg32_setbits(regs + offset[PLL_CTRL], | ||
| 171 | BIT(u3pll_ctrl[PLL_SEQ_START])); | ||
| 172 | bcm_usb_reg32_setbits(regs + offset[PLL_CTRL], | ||
| 173 | BIT(u3pll_ctrl[PLL_RESETB])); | ||
| 174 | |||
| 175 | /* Maximum timeout for PLL reset done */ | ||
| 176 | msleep(30); | ||
| 177 | |||
| 178 | ret = bcm_usb_pll_lock_check(regs + offset[PLL_CTRL], | ||
| 179 | BIT(u3pll_ctrl[PLL_LOCK])); | ||
| 180 | |||
| 181 | return ret; | ||
| 182 | } | ||
| 183 | |||
| 184 | static int bcm_usb_hs_phy_init(struct bcm_usb_phy_cfg *phy_cfg) | ||
| 185 | { | ||
| 186 | int ret = 0; | ||
| 187 | void __iomem *regs = phy_cfg->regs; | ||
| 188 | const u8 *offset; | ||
| 189 | u32 rd_data; | ||
| 190 | |||
| 191 | offset = phy_cfg->offset; | ||
| 192 | |||
| 193 | writel(HSPLL_NDIV_INT_VAL, regs + offset[PLL_NDIV_INT]); | ||
| 194 | writel(HSPLL_NDIV_FRAC_VAL, regs + offset[PLL_NDIV_FRAC]); | ||
| 195 | |||
| 196 | rd_data = readl(regs + offset[PLL_CTRL]); | ||
| 197 | rd_data &= ~(HSPLL_PDIV_MASK << u2pll_ctrl[PLL_PDIV]); | ||
| 198 | rd_data |= (HSPLL_PDIV_VAL << u2pll_ctrl[PLL_PDIV]); | ||
| 199 | writel(rd_data, regs + offset[PLL_CTRL]); | ||
| 200 | |||
| 201 | /* Set Core Ready high */ | ||
| 202 | bcm_usb_reg32_setbits(regs + offset[PHY_CTRL], | ||
| 203 | BIT(u2phy_ctrl[CORERDY])); | ||
| 204 | |||
| 205 | /* Maximum timeout for Core Ready done */ | ||
| 206 | msleep(30); | ||
| 207 | |||
| 208 | bcm_usb_reg32_setbits(regs + offset[PLL_CTRL], | ||
| 209 | BIT(u2pll_ctrl[PLL_RESETB])); | ||
| 210 | bcm_usb_reg32_setbits(regs + offset[PHY_CTRL], | ||
| 211 | BIT(u2phy_ctrl[PHY_RESETB])); | ||
| 212 | |||
| 213 | |||
| 214 | rd_data = readl(regs + offset[PHY_CTRL]); | ||
| 215 | rd_data &= ~(PHY_PCTL_MASK << u2phy_ctrl[PHY_PCTL]); | ||
| 216 | rd_data |= (HSPHY_PCTL_VAL << u2phy_ctrl[PHY_PCTL]); | ||
| 217 | writel(rd_data, regs + offset[PHY_CTRL]); | ||
| 218 | |||
| 219 | /* Maximum timeout for PLL reset done */ | ||
| 220 | msleep(30); | ||
| 221 | |||
| 222 | ret = bcm_usb_pll_lock_check(regs + offset[PLL_CTRL], | ||
| 223 | BIT(u2pll_ctrl[PLL_LOCK])); | ||
| 224 | |||
| 225 | return ret; | ||
| 226 | } | ||
| 227 | |||
| 228 | static int bcm_usb_phy_reset(struct phy *phy) | ||
| 229 | { | ||
| 230 | struct bcm_usb_phy_cfg *phy_cfg = phy_get_drvdata(phy); | ||
| 231 | void __iomem *regs = phy_cfg->regs; | ||
| 232 | const u8 *offset; | ||
| 233 | |||
| 234 | offset = phy_cfg->offset; | ||
| 235 | |||
| 236 | if (phy_cfg->type == USB_HS_PHY) { | ||
| 237 | bcm_usb_reg32_clrbits(regs + offset[PHY_CTRL], | ||
| 238 | BIT(u2phy_ctrl[CORERDY])); | ||
| 239 | bcm_usb_reg32_setbits(regs + offset[PHY_CTRL], | ||
| 240 | BIT(u2phy_ctrl[CORERDY])); | ||
| 241 | } | ||
| 242 | |||
| 243 | return 0; | ||
| 244 | } | ||
| 245 | |||
| 246 | static int bcm_usb_phy_init(struct phy *phy) | ||
| 247 | { | ||
| 248 | struct bcm_usb_phy_cfg *phy_cfg = phy_get_drvdata(phy); | ||
| 249 | int ret = -EINVAL; | ||
| 250 | |||
| 251 | if (phy_cfg->type == USB_SS_PHY) | ||
| 252 | ret = bcm_usb_ss_phy_init(phy_cfg); | ||
| 253 | else if (phy_cfg->type == USB_HS_PHY) | ||
| 254 | ret = bcm_usb_hs_phy_init(phy_cfg); | ||
| 255 | |||
| 256 | return ret; | ||
| 257 | } | ||
| 258 | |||
| 259 | static struct phy_ops sr_phy_ops = { | ||
| 260 | .init = bcm_usb_phy_init, | ||
| 261 | .reset = bcm_usb_phy_reset, | ||
| 262 | .owner = THIS_MODULE, | ||
| 263 | }; | ||
| 264 | |||
| 265 | static struct phy *bcm_usb_phy_xlate(struct device *dev, | ||
| 266 | struct of_phandle_args *args) | ||
| 267 | { | ||
| 268 | struct bcm_usb_phy_cfg *phy_cfg; | ||
| 269 | int phy_idx; | ||
| 270 | |||
| 271 | phy_cfg = dev_get_drvdata(dev); | ||
| 272 | if (!phy_cfg) | ||
| 273 | return ERR_PTR(-EINVAL); | ||
| 274 | |||
| 275 | if (phy_cfg->version == BCM_SR_USB_COMBO_PHY) { | ||
| 276 | phy_idx = args->args[0]; | ||
| 277 | |||
| 278 | if (WARN_ON(phy_idx > 1)) | ||
| 279 | return ERR_PTR(-ENODEV); | ||
| 280 | |||
| 281 | return phy_cfg[phy_idx].phy; | ||
| 282 | } else | ||
| 283 | return phy_cfg->phy; | ||
| 284 | } | ||
| 285 | |||
| 286 | static int bcm_usb_phy_create(struct device *dev, struct device_node *node, | ||
| 287 | void __iomem *regs, uint32_t version) | ||
| 288 | { | ||
| 289 | struct bcm_usb_phy_cfg *phy_cfg; | ||
| 290 | int idx; | ||
| 291 | |||
| 292 | if (version == BCM_SR_USB_COMBO_PHY) { | ||
| 293 | phy_cfg = devm_kzalloc(dev, NUM_BCM_SR_USB_COMBO_PHYS * | ||
| 294 | sizeof(struct bcm_usb_phy_cfg), | ||
| 295 | GFP_KERNEL); | ||
| 296 | if (!phy_cfg) | ||
| 297 | return -ENOMEM; | ||
| 298 | |||
| 299 | for (idx = 0; idx < NUM_BCM_SR_USB_COMBO_PHYS; idx++) { | ||
| 300 | phy_cfg[idx].regs = regs; | ||
| 301 | phy_cfg[idx].version = version; | ||
| 302 | if (idx == 0) { | ||
| 303 | phy_cfg[idx].offset = bcm_usb_combo_phy_hs; | ||
| 304 | phy_cfg[idx].type = USB_HS_PHY; | ||
| 305 | } else { | ||
| 306 | phy_cfg[idx].offset = bcm_usb_combo_phy_ss; | ||
| 307 | phy_cfg[idx].type = USB_SS_PHY; | ||
| 308 | } | ||
| 309 | phy_cfg[idx].phy = devm_phy_create(dev, node, | ||
| 310 | &sr_phy_ops); | ||
| 311 | if (IS_ERR(phy_cfg[idx].phy)) | ||
| 312 | return PTR_ERR(phy_cfg[idx].phy); | ||
| 313 | |||
| 314 | phy_set_drvdata(phy_cfg[idx].phy, &phy_cfg[idx]); | ||
| 315 | } | ||
| 316 | } else if (version == BCM_SR_USB_HS_PHY) { | ||
| 317 | phy_cfg = devm_kzalloc(dev, sizeof(struct bcm_usb_phy_cfg), | ||
| 318 | GFP_KERNEL); | ||
| 319 | if (!phy_cfg) | ||
| 320 | return -ENOMEM; | ||
| 321 | |||
| 322 | phy_cfg->regs = regs; | ||
| 323 | phy_cfg->version = version; | ||
| 324 | phy_cfg->offset = bcm_usb_hs_phy; | ||
| 325 | phy_cfg->type = USB_HS_PHY; | ||
| 326 | phy_cfg->phy = devm_phy_create(dev, node, &sr_phy_ops); | ||
| 327 | if (IS_ERR(phy_cfg->phy)) | ||
| 328 | return PTR_ERR(phy_cfg->phy); | ||
| 329 | |||
| 330 | phy_set_drvdata(phy_cfg->phy, phy_cfg); | ||
| 331 | } else | ||
| 332 | return -ENODEV; | ||
| 333 | |||
| 334 | dev_set_drvdata(dev, phy_cfg); | ||
| 335 | |||
| 336 | return 0; | ||
| 337 | } | ||
| 338 | |||
| 339 | static const struct of_device_id bcm_usb_phy_of_match[] = { | ||
| 340 | { | ||
| 341 | .compatible = "brcm,sr-usb-combo-phy", | ||
| 342 | .data = (void *)BCM_SR_USB_COMBO_PHY, | ||
| 343 | }, | ||
| 344 | { | ||
| 345 | .compatible = "brcm,sr-usb-hs-phy", | ||
| 346 | .data = (void *)BCM_SR_USB_HS_PHY, | ||
| 347 | }, | ||
| 348 | { /* sentinel */ }, | ||
| 349 | }; | ||
| 350 | MODULE_DEVICE_TABLE(of, bcm_usb_phy_of_match); | ||
| 351 | |||
| 352 | static int bcm_usb_phy_probe(struct platform_device *pdev) | ||
| 353 | { | ||
| 354 | struct device *dev = &pdev->dev; | ||
| 355 | struct device_node *dn = dev->of_node; | ||
| 356 | const struct of_device_id *of_id; | ||
| 357 | struct resource *res; | ||
| 358 | void __iomem *regs; | ||
| 359 | int ret; | ||
| 360 | enum bcm_usb_phy_version version; | ||
| 361 | struct phy_provider *phy_provider; | ||
| 362 | |||
| 363 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 364 | regs = devm_ioremap_resource(dev, res); | ||
| 365 | if (IS_ERR(regs)) | ||
| 366 | return PTR_ERR(regs); | ||
| 367 | |||
| 368 | of_id = of_match_node(bcm_usb_phy_of_match, dn); | ||
| 369 | if (of_id) | ||
| 370 | version = (enum bcm_usb_phy_version)of_id->data; | ||
| 371 | else | ||
| 372 | return -ENODEV; | ||
| 373 | |||
| 374 | ret = bcm_usb_phy_create(dev, dn, regs, version); | ||
| 375 | if (ret) | ||
| 376 | return ret; | ||
| 377 | |||
| 378 | phy_provider = devm_of_phy_provider_register(dev, bcm_usb_phy_xlate); | ||
| 379 | |||
| 380 | return PTR_ERR_OR_ZERO(phy_provider); | ||
| 381 | } | ||
| 382 | |||
| 383 | static struct platform_driver bcm_usb_phy_driver = { | ||
| 384 | .driver = { | ||
| 385 | .name = "phy-bcm-sr-usb", | ||
| 386 | .of_match_table = bcm_usb_phy_of_match, | ||
| 387 | }, | ||
| 388 | .probe = bcm_usb_phy_probe, | ||
| 389 | }; | ||
| 390 | module_platform_driver(bcm_usb_phy_driver); | ||
| 391 | |||
| 392 | MODULE_AUTHOR("Broadcom"); | ||
| 393 | MODULE_DESCRIPTION("Broadcom stingray USB Phy driver"); | ||
| 394 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c index d6ea5ce8afa5..0c4833da7be0 100644 --- a/drivers/phy/freescale/phy-fsl-imx8mq-usb.c +++ b/drivers/phy/freescale/phy-fsl-imx8mq-usb.c | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | #include <linux/module.h> | 6 | #include <linux/module.h> |
| 7 | #include <linux/phy/phy.h> | 7 | #include <linux/phy/phy.h> |
| 8 | #include <linux/platform_device.h> | 8 | #include <linux/platform_device.h> |
| 9 | #include <linux/regulator/consumer.h> | ||
| 9 | 10 | ||
| 10 | #define PHY_CTRL0 0x0 | 11 | #define PHY_CTRL0 0x0 |
| 11 | #define PHY_CTRL0_REF_SSP_EN BIT(2) | 12 | #define PHY_CTRL0_REF_SSP_EN BIT(2) |
| @@ -24,6 +25,7 @@ struct imx8mq_usb_phy { | |||
| 24 | struct phy *phy; | 25 | struct phy *phy; |
| 25 | struct clk *clk; | 26 | struct clk *clk; |
| 26 | void __iomem *base; | 27 | void __iomem *base; |
| 28 | struct regulator *vbus; | ||
| 27 | }; | 29 | }; |
| 28 | 30 | ||
| 29 | static int imx8mq_usb_phy_init(struct phy *phy) | 31 | static int imx8mq_usb_phy_init(struct phy *phy) |
| @@ -55,6 +57,11 @@ static int imx8mq_usb_phy_init(struct phy *phy) | |||
| 55 | static int imx8mq_phy_power_on(struct phy *phy) | 57 | static int imx8mq_phy_power_on(struct phy *phy) |
| 56 | { | 58 | { |
| 57 | struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy); | 59 | struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy); |
| 60 | int ret; | ||
| 61 | |||
| 62 | ret = regulator_enable(imx_phy->vbus); | ||
| 63 | if (ret) | ||
| 64 | return ret; | ||
| 58 | 65 | ||
| 59 | return clk_prepare_enable(imx_phy->clk); | 66 | return clk_prepare_enable(imx_phy->clk); |
| 60 | } | 67 | } |
| @@ -64,6 +71,7 @@ static int imx8mq_phy_power_off(struct phy *phy) | |||
| 64 | struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy); | 71 | struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy); |
| 65 | 72 | ||
| 66 | clk_disable_unprepare(imx_phy->clk); | 73 | clk_disable_unprepare(imx_phy->clk); |
| 74 | regulator_disable(imx_phy->vbus); | ||
| 67 | 75 | ||
| 68 | return 0; | 76 | return 0; |
| 69 | } | 77 | } |
| @@ -101,6 +109,10 @@ static int imx8mq_usb_phy_probe(struct platform_device *pdev) | |||
| 101 | if (IS_ERR(imx_phy->phy)) | 109 | if (IS_ERR(imx_phy->phy)) |
| 102 | return PTR_ERR(imx_phy->phy); | 110 | return PTR_ERR(imx_phy->phy); |
| 103 | 111 | ||
| 112 | imx_phy->vbus = devm_regulator_get(dev, "vbus"); | ||
| 113 | if (IS_ERR(imx_phy->vbus)) | ||
| 114 | return PTR_ERR(imx_phy->vbus); | ||
| 115 | |||
| 104 | phy_set_drvdata(imx_phy->phy, imx_phy); | 116 | phy_set_drvdata(imx_phy->phy, imx_phy); |
| 105 | 117 | ||
| 106 | phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); | 118 | phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); |
diff --git a/drivers/phy/hisilicon/Kconfig b/drivers/phy/hisilicon/Kconfig index b40ee54a1a50..3c142f08987c 100644 --- a/drivers/phy/hisilicon/Kconfig +++ b/drivers/phy/hisilicon/Kconfig | |||
| @@ -12,6 +12,16 @@ config PHY_HI6220_USB | |||
| 12 | 12 | ||
| 13 | To compile this driver as a module, choose M here. | 13 | To compile this driver as a module, choose M here. |
| 14 | 14 | ||
| 15 | config PHY_HI3660_USB | ||
| 16 | tristate "hi3660 USB PHY support" | ||
| 17 | depends on (ARCH_HISI && ARM64) || COMPILE_TEST | ||
| 18 | select GENERIC_PHY | ||
| 19 | select MFD_SYSCON | ||
| 20 | help | ||
| 21 | Enable this to support the HISILICON HI3660 USB PHY. | ||
| 22 | |||
| 23 | To compile this driver as a module, choose M here. | ||
| 24 | |||
| 15 | config PHY_HISTB_COMBPHY | 25 | config PHY_HISTB_COMBPHY |
| 16 | tristate "HiSilicon STB SoCs COMBPHY support" | 26 | tristate "HiSilicon STB SoCs COMBPHY support" |
| 17 | depends on (ARCH_HISI && ARM64) || COMPILE_TEST | 27 | depends on (ARCH_HISI && ARM64) || COMPILE_TEST |
diff --git a/drivers/phy/hisilicon/Makefile b/drivers/phy/hisilicon/Makefile index f662a4fe18d8..75ba64e2faf8 100644 --- a/drivers/phy/hisilicon/Makefile +++ b/drivers/phy/hisilicon/Makefile | |||
| @@ -1,4 +1,5 @@ | |||
| 1 | obj-$(CONFIG_PHY_HI6220_USB) += phy-hi6220-usb.o | 1 | obj-$(CONFIG_PHY_HI6220_USB) += phy-hi6220-usb.o |
| 2 | obj-$(CONFIG_PHY_HI3660_USB) += phy-hi3660-usb3.o | ||
| 2 | obj-$(CONFIG_PHY_HISTB_COMBPHY) += phy-histb-combphy.o | 3 | obj-$(CONFIG_PHY_HISTB_COMBPHY) += phy-histb-combphy.o |
| 3 | obj-$(CONFIG_PHY_HISI_INNO_USB2) += phy-hisi-inno-usb2.o | 4 | obj-$(CONFIG_PHY_HISI_INNO_USB2) += phy-hisi-inno-usb2.o |
| 4 | obj-$(CONFIG_PHY_HIX5HD2_SATA) += phy-hix5hd2-sata.o | 5 | obj-$(CONFIG_PHY_HIX5HD2_SATA) += phy-hix5hd2-sata.o |
diff --git a/drivers/phy/hisilicon/phy-hi3660-usb3.c b/drivers/phy/hisilicon/phy-hi3660-usb3.c new file mode 100644 index 000000000000..cc0af2c044d0 --- /dev/null +++ b/drivers/phy/hisilicon/phy-hi3660-usb3.c | |||
| @@ -0,0 +1,233 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * Phy provider for USB 3.0 controller on HiSilicon 3660 platform | ||
| 4 | * | ||
| 5 | * Copyright (C) 2017-2018 Hilisicon Electronics Co., Ltd. | ||
| 6 | * http://www.huawei.com | ||
| 7 | * | ||
| 8 | * Authors: Yu Chen <chenyu56@huawei.com> | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/kernel.h> | ||
| 12 | #include <linux/mfd/syscon.h> | ||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/phy/phy.h> | ||
| 15 | #include <linux/platform_device.h> | ||
| 16 | #include <linux/regmap.h> | ||
| 17 | |||
| 18 | #define PERI_CRG_CLK_EN4 0x40 | ||
| 19 | #define PERI_CRG_CLK_DIS4 0x44 | ||
| 20 | #define GT_CLK_USB3OTG_REF BIT(0) | ||
| 21 | #define GT_ACLK_USB3OTG BIT(1) | ||
| 22 | |||
| 23 | #define PERI_CRG_RSTEN4 0x90 | ||
| 24 | #define PERI_CRG_RSTDIS4 0x94 | ||
| 25 | #define IP_RST_USB3OTGPHY_POR BIT(3) | ||
| 26 | #define IP_RST_USB3OTG BIT(5) | ||
| 27 | |||
| 28 | #define PERI_CRG_ISODIS 0x148 | ||
| 29 | #define USB_REFCLK_ISO_EN BIT(25) | ||
| 30 | |||
| 31 | #define PCTRL_PERI_CTRL3 0x10 | ||
| 32 | #define PCTRL_PERI_CTRL3_MSK_START 16 | ||
| 33 | #define USB_TCXO_EN BIT(1) | ||
| 34 | |||
| 35 | #define PCTRL_PERI_CTRL24 0x64 | ||
| 36 | #define SC_CLK_USB3PHY_3MUX1_SEL BIT(25) | ||
| 37 | |||
| 38 | #define USBOTG3_CTRL0 0x00 | ||
| 39 | #define SC_USB3PHY_ABB_GT_EN BIT(15) | ||
| 40 | |||
| 41 | #define USBOTG3_CTRL2 0x08 | ||
| 42 | #define USBOTG3CTRL2_POWERDOWN_HSP BIT(0) | ||
| 43 | #define USBOTG3CTRL2_POWERDOWN_SSP BIT(1) | ||
| 44 | |||
| 45 | #define USBOTG3_CTRL3 0x0C | ||
| 46 | #define USBOTG3_CTRL3_VBUSVLDEXT BIT(6) | ||
| 47 | #define USBOTG3_CTRL3_VBUSVLDEXTSEL BIT(5) | ||
| 48 | |||
| 49 | #define USBOTG3_CTRL4 0x10 | ||
| 50 | |||
| 51 | #define USBOTG3_CTRL7 0x1c | ||
| 52 | #define REF_SSP_EN BIT(16) | ||
| 53 | |||
| 54 | /* This value config the default txtune parameter of the usb 2.0 phy */ | ||
| 55 | #define HI3660_USB_DEFAULT_PHY_PARAM 0x1c466e3 | ||
| 56 | |||
| 57 | struct hi3660_priv { | ||
| 58 | struct device *dev; | ||
| 59 | struct regmap *peri_crg; | ||
| 60 | struct regmap *pctrl; | ||
| 61 | struct regmap *otg_bc; | ||
| 62 | u32 eye_diagram_param; | ||
| 63 | }; | ||
| 64 | |||
| 65 | static int hi3660_phy_init(struct phy *phy) | ||
| 66 | { | ||
| 67 | struct hi3660_priv *priv = phy_get_drvdata(phy); | ||
| 68 | u32 val, mask; | ||
| 69 | int ret; | ||
| 70 | |||
| 71 | /* usb refclk iso disable */ | ||
| 72 | ret = regmap_write(priv->peri_crg, PERI_CRG_ISODIS, USB_REFCLK_ISO_EN); | ||
| 73 | if (ret) | ||
| 74 | goto out; | ||
| 75 | |||
| 76 | /* enable usb_tcxo_en */ | ||
| 77 | val = USB_TCXO_EN | (USB_TCXO_EN << PCTRL_PERI_CTRL3_MSK_START); | ||
| 78 | ret = regmap_write(priv->pctrl, PCTRL_PERI_CTRL3, val); | ||
| 79 | if (ret) | ||
| 80 | goto out; | ||
| 81 | |||
| 82 | /* assert phy */ | ||
| 83 | val = IP_RST_USB3OTGPHY_POR | IP_RST_USB3OTG; | ||
| 84 | ret = regmap_write(priv->peri_crg, PERI_CRG_RSTEN4, val); | ||
| 85 | if (ret) | ||
| 86 | goto out; | ||
| 87 | |||
| 88 | /* enable phy ref clk */ | ||
| 89 | val = SC_USB3PHY_ABB_GT_EN; | ||
| 90 | mask = val; | ||
| 91 | ret = regmap_update_bits(priv->otg_bc, USBOTG3_CTRL0, mask, val); | ||
| 92 | if (ret) | ||
| 93 | goto out; | ||
| 94 | |||
| 95 | val = REF_SSP_EN; | ||
| 96 | mask = val; | ||
| 97 | ret = regmap_update_bits(priv->otg_bc, USBOTG3_CTRL7, mask, val); | ||
| 98 | if (ret) | ||
| 99 | goto out; | ||
| 100 | |||
| 101 | /* exit from IDDQ mode */ | ||
| 102 | mask = USBOTG3CTRL2_POWERDOWN_HSP | USBOTG3CTRL2_POWERDOWN_SSP; | ||
| 103 | ret = regmap_update_bits(priv->otg_bc, USBOTG3_CTRL2, mask, 0); | ||
| 104 | if (ret) | ||
| 105 | goto out; | ||
| 106 | |||
| 107 | /* delay for exit from IDDQ mode */ | ||
| 108 | usleep_range(100, 120); | ||
| 109 | |||
| 110 | /* deassert phy */ | ||
| 111 | val = IP_RST_USB3OTGPHY_POR | IP_RST_USB3OTG; | ||
| 112 | ret = regmap_write(priv->peri_crg, PERI_CRG_RSTDIS4, val); | ||
| 113 | if (ret) | ||
| 114 | goto out; | ||
| 115 | |||
| 116 | /* delay for phy deasserted */ | ||
| 117 | usleep_range(10000, 15000); | ||
| 118 | |||
| 119 | /* fake vbus valid signal */ | ||
| 120 | val = USBOTG3_CTRL3_VBUSVLDEXT | USBOTG3_CTRL3_VBUSVLDEXTSEL; | ||
| 121 | mask = val; | ||
| 122 | ret = regmap_update_bits(priv->otg_bc, USBOTG3_CTRL3, mask, val); | ||
| 123 | if (ret) | ||
| 124 | goto out; | ||
| 125 | |||
| 126 | /* delay for vbus valid */ | ||
| 127 | usleep_range(100, 120); | ||
| 128 | |||
| 129 | ret = regmap_write(priv->otg_bc, USBOTG3_CTRL4, | ||
| 130 | priv->eye_diagram_param); | ||
| 131 | if (ret) | ||
| 132 | goto out; | ||
| 133 | |||
| 134 | return 0; | ||
| 135 | out: | ||
| 136 | dev_err(priv->dev, "failed to init phy ret: %d\n", ret); | ||
| 137 | return ret; | ||
| 138 | } | ||
| 139 | |||
| 140 | static int hi3660_phy_exit(struct phy *phy) | ||
| 141 | { | ||
| 142 | struct hi3660_priv *priv = phy_get_drvdata(phy); | ||
| 143 | u32 val; | ||
| 144 | int ret; | ||
| 145 | |||
| 146 | /* assert phy */ | ||
| 147 | val = IP_RST_USB3OTGPHY_POR; | ||
| 148 | ret = regmap_write(priv->peri_crg, PERI_CRG_RSTEN4, val); | ||
| 149 | if (ret) | ||
| 150 | goto out; | ||
| 151 | |||
| 152 | /* disable usb_tcxo_en */ | ||
| 153 | val = USB_TCXO_EN << PCTRL_PERI_CTRL3_MSK_START; | ||
| 154 | ret = regmap_write(priv->pctrl, PCTRL_PERI_CTRL3, val); | ||
| 155 | if (ret) | ||
| 156 | goto out; | ||
| 157 | |||
| 158 | return 0; | ||
| 159 | out: | ||
| 160 | dev_err(priv->dev, "failed to exit phy ret: %d\n", ret); | ||
| 161 | return ret; | ||
| 162 | } | ||
| 163 | |||
| 164 | static struct phy_ops hi3660_phy_ops = { | ||
| 165 | .init = hi3660_phy_init, | ||
| 166 | .exit = hi3660_phy_exit, | ||
| 167 | .owner = THIS_MODULE, | ||
| 168 | }; | ||
| 169 | |||
| 170 | static int hi3660_phy_probe(struct platform_device *pdev) | ||
| 171 | { | ||
| 172 | struct phy_provider *phy_provider; | ||
| 173 | struct device *dev = &pdev->dev; | ||
| 174 | struct phy *phy; | ||
| 175 | struct hi3660_priv *priv; | ||
| 176 | |||
| 177 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
| 178 | if (!priv) | ||
| 179 | return -ENOMEM; | ||
| 180 | |||
| 181 | priv->dev = dev; | ||
| 182 | priv->peri_crg = syscon_regmap_lookup_by_phandle(dev->of_node, | ||
| 183 | "hisilicon,pericrg-syscon"); | ||
| 184 | if (IS_ERR(priv->peri_crg)) { | ||
| 185 | dev_err(dev, "no hisilicon,pericrg-syscon\n"); | ||
| 186 | return PTR_ERR(priv->peri_crg); | ||
| 187 | } | ||
| 188 | |||
| 189 | priv->pctrl = syscon_regmap_lookup_by_phandle(dev->of_node, | ||
| 190 | "hisilicon,pctrl-syscon"); | ||
| 191 | if (IS_ERR(priv->pctrl)) { | ||
| 192 | dev_err(dev, "no hisilicon,pctrl-syscon\n"); | ||
| 193 | return PTR_ERR(priv->pctrl); | ||
| 194 | } | ||
| 195 | |||
| 196 | /* node of hi3660 phy is a sub-node of usb3_otg_bc */ | ||
| 197 | priv->otg_bc = syscon_node_to_regmap(dev->parent->of_node); | ||
| 198 | if (IS_ERR(priv->otg_bc)) { | ||
| 199 | dev_err(dev, "no hisilicon,usb3-otg-bc-syscon\n"); | ||
| 200 | return PTR_ERR(priv->otg_bc); | ||
| 201 | } | ||
| 202 | |||
| 203 | if (of_property_read_u32(dev->of_node, "hisilicon,eye-diagram-param", | ||
| 204 | &(priv->eye_diagram_param))) | ||
| 205 | priv->eye_diagram_param = HI3660_USB_DEFAULT_PHY_PARAM; | ||
| 206 | |||
| 207 | phy = devm_phy_create(dev, NULL, &hi3660_phy_ops); | ||
| 208 | if (IS_ERR(phy)) | ||
| 209 | return PTR_ERR(phy); | ||
| 210 | |||
| 211 | phy_set_drvdata(phy, priv); | ||
| 212 | phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); | ||
| 213 | return PTR_ERR_OR_ZERO(phy_provider); | ||
| 214 | } | ||
| 215 | |||
| 216 | static const struct of_device_id hi3660_phy_of_match[] = { | ||
| 217 | {.compatible = "hisilicon,hi3660-usb-phy",}, | ||
| 218 | { } | ||
| 219 | }; | ||
| 220 | MODULE_DEVICE_TABLE(of, hi3660_phy_of_match); | ||
| 221 | |||
| 222 | static struct platform_driver hi3660_phy_driver = { | ||
| 223 | .probe = hi3660_phy_probe, | ||
| 224 | .driver = { | ||
| 225 | .name = "hi3660-usb-phy", | ||
| 226 | .of_match_table = hi3660_phy_of_match, | ||
| 227 | } | ||
| 228 | }; | ||
| 229 | module_platform_driver(hi3660_phy_driver); | ||
| 230 | |||
| 231 | MODULE_AUTHOR("Yu Chen <chenyu56@huawei.com>"); | ||
| 232 | MODULE_LICENSE("GPL v2"); | ||
| 233 | MODULE_DESCRIPTION("Hilisicon Hi3660 USB3 PHY Driver"); | ||
diff --git a/drivers/phy/mediatek/Kconfig b/drivers/phy/mediatek/Kconfig index 8857d00b3c65..b5a89dbd3fe7 100644 --- a/drivers/phy/mediatek/Kconfig +++ b/drivers/phy/mediatek/Kconfig | |||
| @@ -13,6 +13,16 @@ config PHY_MTK_TPHY | |||
| 13 | multi-ports is first version, otherwise is second veriosn, | 13 | multi-ports is first version, otherwise is second veriosn, |
| 14 | so you can easily distinguish them by banks layout. | 14 | so you can easily distinguish them by banks layout. |
| 15 | 15 | ||
| 16 | config PHY_MTK_UFS | ||
| 17 | tristate "MediaTek UFS M-PHY driver" | ||
| 18 | depends on ARCH_MEDIATEK && OF | ||
| 19 | select GENERIC_PHY | ||
| 20 | help | ||
| 21 | Support for UFS M-PHY on MediaTek chipsets. | ||
| 22 | Enable this to provide vendor-specific probing, | ||
| 23 | initialization, power on and power off flow of | ||
| 24 | specified M-PHYs. | ||
| 25 | |||
| 16 | config PHY_MTK_XSPHY | 26 | config PHY_MTK_XSPHY |
| 17 | tristate "MediaTek XS-PHY Driver" | 27 | tristate "MediaTek XS-PHY Driver" |
| 18 | depends on ARCH_MEDIATEK && OF | 28 | depends on ARCH_MEDIATEK && OF |
diff --git a/drivers/phy/mediatek/Makefile b/drivers/phy/mediatek/Makefile index ee49edc97ee9..08a8e6a97b1e 100644 --- a/drivers/phy/mediatek/Makefile +++ b/drivers/phy/mediatek/Makefile | |||
| @@ -4,4 +4,5 @@ | |||
| 4 | # | 4 | # |
| 5 | 5 | ||
| 6 | obj-$(CONFIG_PHY_MTK_TPHY) += phy-mtk-tphy.o | 6 | obj-$(CONFIG_PHY_MTK_TPHY) += phy-mtk-tphy.o |
| 7 | obj-$(CONFIG_PHY_MTK_UFS) += phy-mtk-ufs.o | ||
| 7 | obj-$(CONFIG_PHY_MTK_XSPHY) += phy-mtk-xsphy.o | 8 | obj-$(CONFIG_PHY_MTK_XSPHY) += phy-mtk-xsphy.o |
diff --git a/drivers/phy/mediatek/phy-mtk-tphy.c b/drivers/phy/mediatek/phy-mtk-tphy.c index 5b6a470ca145..cb2ed3b25068 100644 --- a/drivers/phy/mediatek/phy-mtk-tphy.c +++ b/drivers/phy/mediatek/phy-mtk-tphy.c | |||
| @@ -1103,13 +1103,9 @@ static int mtk_tphy_probe(struct platform_device *pdev) | |||
| 1103 | } | 1103 | } |
| 1104 | 1104 | ||
| 1105 | /* it's deprecated, make it optional for backward compatibility */ | 1105 | /* it's deprecated, make it optional for backward compatibility */ |
| 1106 | tphy->u3phya_ref = devm_clk_get(dev, "u3phya_ref"); | 1106 | tphy->u3phya_ref = devm_clk_get_optional(dev, "u3phya_ref"); |
| 1107 | if (IS_ERR(tphy->u3phya_ref)) { | 1107 | if (IS_ERR(tphy->u3phya_ref)) |
| 1108 | if (PTR_ERR(tphy->u3phya_ref) == -EPROBE_DEFER) | 1108 | return PTR_ERR(tphy->u3phya_ref); |
| 1109 | return -EPROBE_DEFER; | ||
| 1110 | |||
| 1111 | tphy->u3phya_ref = NULL; | ||
| 1112 | } | ||
| 1113 | 1109 | ||
| 1114 | tphy->src_ref_clk = U3P_REF_CLK; | 1110 | tphy->src_ref_clk = U3P_REF_CLK; |
| 1115 | tphy->src_coef = U3P_SLEW_RATE_COEF; | 1111 | tphy->src_coef = U3P_SLEW_RATE_COEF; |
diff --git a/drivers/phy/mediatek/phy-mtk-ufs.c b/drivers/phy/mediatek/phy-mtk-ufs.c new file mode 100644 index 000000000000..cf94f5c35dc5 --- /dev/null +++ b/drivers/phy/mediatek/phy-mtk-ufs.c | |||
| @@ -0,0 +1,245 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * Copyright (C) 2019 MediaTek Inc. | ||
| 4 | * Author: Stanley Chu <stanley.chu@mediatek.com> | ||
| 5 | */ | ||
| 6 | |||
| 7 | #include <linux/clk.h> | ||
| 8 | #include <linux/delay.h> | ||
| 9 | #include <linux/io.h> | ||
| 10 | #include <linux/module.h> | ||
| 11 | #include <linux/phy/phy.h> | ||
| 12 | #include <linux/platform_device.h> | ||
| 13 | |||
| 14 | /* mphy register and offsets */ | ||
| 15 | #define MP_GLB_DIG_8C 0x008C | ||
| 16 | #define FRC_PLL_ISO_EN BIT(8) | ||
| 17 | #define PLL_ISO_EN BIT(9) | ||
| 18 | #define FRC_FRC_PWR_ON BIT(10) | ||
| 19 | #define PLL_PWR_ON BIT(11) | ||
| 20 | |||
| 21 | #define MP_LN_DIG_RX_9C 0xA09C | ||
| 22 | #define FSM_DIFZ_FRC BIT(18) | ||
| 23 | |||
| 24 | #define MP_LN_DIG_RX_AC 0xA0AC | ||
| 25 | #define FRC_RX_SQ_EN BIT(0) | ||
| 26 | #define RX_SQ_EN BIT(1) | ||
| 27 | |||
| 28 | #define MP_LN_RX_44 0xB044 | ||
| 29 | #define FRC_CDR_PWR_ON BIT(17) | ||
| 30 | #define CDR_PWR_ON BIT(18) | ||
| 31 | #define FRC_CDR_ISO_EN BIT(19) | ||
| 32 | #define CDR_ISO_EN BIT(20) | ||
| 33 | |||
| 34 | struct ufs_mtk_phy { | ||
| 35 | struct device *dev; | ||
| 36 | void __iomem *mmio; | ||
| 37 | struct clk *mp_clk; | ||
| 38 | struct clk *unipro_clk; | ||
| 39 | }; | ||
| 40 | |||
| 41 | static inline u32 mphy_readl(struct ufs_mtk_phy *phy, u32 reg) | ||
| 42 | { | ||
| 43 | return readl(phy->mmio + reg); | ||
| 44 | } | ||
| 45 | |||
| 46 | static inline void mphy_writel(struct ufs_mtk_phy *phy, u32 val, u32 reg) | ||
| 47 | { | ||
| 48 | writel(val, phy->mmio + reg); | ||
| 49 | } | ||
| 50 | |||
| 51 | static void mphy_set_bit(struct ufs_mtk_phy *phy, u32 reg, u32 bit) | ||
| 52 | { | ||
| 53 | u32 val; | ||
| 54 | |||
| 55 | val = mphy_readl(phy, reg); | ||
| 56 | val |= bit; | ||
| 57 | mphy_writel(phy, val, reg); | ||
| 58 | } | ||
| 59 | |||
| 60 | static void mphy_clr_bit(struct ufs_mtk_phy *phy, u32 reg, u32 bit) | ||
| 61 | { | ||
| 62 | u32 val; | ||
| 63 | |||
| 64 | val = mphy_readl(phy, reg); | ||
| 65 | val &= ~bit; | ||
| 66 | mphy_writel(phy, val, reg); | ||
| 67 | } | ||
| 68 | |||
| 69 | static struct ufs_mtk_phy *get_ufs_mtk_phy(struct phy *generic_phy) | ||
| 70 | { | ||
| 71 | return (struct ufs_mtk_phy *)phy_get_drvdata(generic_phy); | ||
| 72 | } | ||
| 73 | |||
| 74 | static int ufs_mtk_phy_clk_init(struct ufs_mtk_phy *phy) | ||
| 75 | { | ||
| 76 | struct device *dev = phy->dev; | ||
| 77 | |||
| 78 | phy->unipro_clk = devm_clk_get(dev, "unipro"); | ||
| 79 | if (IS_ERR(phy->unipro_clk)) { | ||
| 80 | dev_err(dev, "failed to get clock: unipro"); | ||
| 81 | return PTR_ERR(phy->unipro_clk); | ||
| 82 | } | ||
| 83 | |||
| 84 | phy->mp_clk = devm_clk_get(dev, "mp"); | ||
| 85 | if (IS_ERR(phy->mp_clk)) { | ||
| 86 | dev_err(dev, "failed to get clock: mp"); | ||
| 87 | return PTR_ERR(phy->mp_clk); | ||
| 88 | } | ||
| 89 | |||
| 90 | return 0; | ||
| 91 | } | ||
| 92 | |||
| 93 | static void ufs_mtk_phy_set_active(struct ufs_mtk_phy *phy) | ||
| 94 | { | ||
| 95 | /* release DA_MP_PLL_PWR_ON */ | ||
| 96 | mphy_set_bit(phy, MP_GLB_DIG_8C, PLL_PWR_ON); | ||
| 97 | mphy_clr_bit(phy, MP_GLB_DIG_8C, FRC_FRC_PWR_ON); | ||
| 98 | |||
| 99 | /* release DA_MP_PLL_ISO_EN */ | ||
| 100 | mphy_clr_bit(phy, MP_GLB_DIG_8C, PLL_ISO_EN); | ||
| 101 | mphy_clr_bit(phy, MP_GLB_DIG_8C, FRC_PLL_ISO_EN); | ||
| 102 | |||
| 103 | /* release DA_MP_CDR_PWR_ON */ | ||
| 104 | mphy_set_bit(phy, MP_LN_RX_44, CDR_PWR_ON); | ||
| 105 | mphy_clr_bit(phy, MP_LN_RX_44, FRC_CDR_PWR_ON); | ||
| 106 | |||
| 107 | /* release DA_MP_CDR_ISO_EN */ | ||
| 108 | mphy_clr_bit(phy, MP_LN_RX_44, CDR_ISO_EN); | ||
| 109 | mphy_clr_bit(phy, MP_LN_RX_44, FRC_CDR_ISO_EN); | ||
| 110 | |||
| 111 | /* release DA_MP_RX0_SQ_EN */ | ||
| 112 | mphy_set_bit(phy, MP_LN_DIG_RX_AC, RX_SQ_EN); | ||
| 113 | mphy_clr_bit(phy, MP_LN_DIG_RX_AC, FRC_RX_SQ_EN); | ||
| 114 | |||
| 115 | /* delay 1us to wait DIFZ stable */ | ||
| 116 | udelay(1); | ||
| 117 | |||
| 118 | /* release DIFZ */ | ||
| 119 | mphy_clr_bit(phy, MP_LN_DIG_RX_9C, FSM_DIFZ_FRC); | ||
| 120 | } | ||
| 121 | |||
| 122 | static void ufs_mtk_phy_set_deep_hibern(struct ufs_mtk_phy *phy) | ||
| 123 | { | ||
| 124 | /* force DIFZ */ | ||
| 125 | mphy_set_bit(phy, MP_LN_DIG_RX_9C, FSM_DIFZ_FRC); | ||
| 126 | |||
| 127 | /* force DA_MP_RX0_SQ_EN */ | ||
| 128 | mphy_set_bit(phy, MP_LN_DIG_RX_AC, FRC_RX_SQ_EN); | ||
| 129 | mphy_clr_bit(phy, MP_LN_DIG_RX_AC, RX_SQ_EN); | ||
| 130 | |||
| 131 | /* force DA_MP_CDR_ISO_EN */ | ||
| 132 | mphy_set_bit(phy, MP_LN_RX_44, FRC_CDR_ISO_EN); | ||
| 133 | mphy_set_bit(phy, MP_LN_RX_44, CDR_ISO_EN); | ||
| 134 | |||
| 135 | /* force DA_MP_CDR_PWR_ON */ | ||
| 136 | mphy_set_bit(phy, MP_LN_RX_44, FRC_CDR_PWR_ON); | ||
| 137 | mphy_clr_bit(phy, MP_LN_RX_44, CDR_PWR_ON); | ||
| 138 | |||
| 139 | /* force DA_MP_PLL_ISO_EN */ | ||
| 140 | mphy_set_bit(phy, MP_GLB_DIG_8C, FRC_PLL_ISO_EN); | ||
| 141 | mphy_set_bit(phy, MP_GLB_DIG_8C, PLL_ISO_EN); | ||
| 142 | |||
| 143 | /* force DA_MP_PLL_PWR_ON */ | ||
| 144 | mphy_set_bit(phy, MP_GLB_DIG_8C, FRC_FRC_PWR_ON); | ||
| 145 | mphy_clr_bit(phy, MP_GLB_DIG_8C, PLL_PWR_ON); | ||
| 146 | } | ||
| 147 | |||
| 148 | static int ufs_mtk_phy_power_on(struct phy *generic_phy) | ||
| 149 | { | ||
| 150 | struct ufs_mtk_phy *phy = get_ufs_mtk_phy(generic_phy); | ||
| 151 | int ret; | ||
| 152 | |||
| 153 | ret = clk_prepare_enable(phy->unipro_clk); | ||
| 154 | if (ret) { | ||
| 155 | dev_err(phy->dev, "unipro_clk enable failed %d\n", ret); | ||
| 156 | goto out; | ||
| 157 | } | ||
| 158 | |||
| 159 | ret = clk_prepare_enable(phy->mp_clk); | ||
| 160 | if (ret) { | ||
| 161 | dev_err(phy->dev, "mp_clk enable failed %d\n", ret); | ||
| 162 | goto out_unprepare_unipro_clk; | ||
| 163 | } | ||
| 164 | |||
| 165 | ufs_mtk_phy_set_active(phy); | ||
| 166 | |||
| 167 | return 0; | ||
| 168 | |||
| 169 | out_unprepare_unipro_clk: | ||
| 170 | clk_disable_unprepare(phy->unipro_clk); | ||
| 171 | out: | ||
| 172 | return ret; | ||
| 173 | } | ||
| 174 | |||
| 175 | static int ufs_mtk_phy_power_off(struct phy *generic_phy) | ||
| 176 | { | ||
| 177 | struct ufs_mtk_phy *phy = get_ufs_mtk_phy(generic_phy); | ||
| 178 | |||
| 179 | ufs_mtk_phy_set_deep_hibern(phy); | ||
| 180 | |||
| 181 | clk_disable_unprepare(phy->unipro_clk); | ||
| 182 | clk_disable_unprepare(phy->mp_clk); | ||
| 183 | |||
| 184 | return 0; | ||
| 185 | } | ||
| 186 | |||
| 187 | static const struct phy_ops ufs_mtk_phy_ops = { | ||
| 188 | .power_on = ufs_mtk_phy_power_on, | ||
| 189 | .power_off = ufs_mtk_phy_power_off, | ||
| 190 | .owner = THIS_MODULE, | ||
| 191 | }; | ||
| 192 | |||
| 193 | static int ufs_mtk_phy_probe(struct platform_device *pdev) | ||
| 194 | { | ||
| 195 | struct device *dev = &pdev->dev; | ||
| 196 | struct phy *generic_phy; | ||
| 197 | struct phy_provider *phy_provider; | ||
| 198 | struct resource *res; | ||
| 199 | struct ufs_mtk_phy *phy; | ||
| 200 | int ret; | ||
| 201 | |||
| 202 | phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); | ||
| 203 | if (!phy) | ||
| 204 | return -ENOMEM; | ||
| 205 | |||
| 206 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 207 | phy->mmio = devm_ioremap_resource(dev, res); | ||
| 208 | if (IS_ERR(phy->mmio)) | ||
| 209 | return PTR_ERR(phy->mmio); | ||
| 210 | |||
| 211 | phy->dev = dev; | ||
| 212 | |||
| 213 | ret = ufs_mtk_phy_clk_init(phy); | ||
| 214 | if (ret) | ||
| 215 | return ret; | ||
| 216 | |||
| 217 | generic_phy = devm_phy_create(dev, NULL, &ufs_mtk_phy_ops); | ||
| 218 | if (IS_ERR(generic_phy)) | ||
| 219 | return PTR_ERR(generic_phy); | ||
| 220 | |||
| 221 | phy_set_drvdata(generic_phy, phy); | ||
| 222 | |||
| 223 | phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); | ||
| 224 | |||
| 225 | return PTR_ERR_OR_ZERO(phy_provider); | ||
| 226 | } | ||
| 227 | |||
| 228 | static const struct of_device_id ufs_mtk_phy_of_match[] = { | ||
| 229 | {.compatible = "mediatek,mt8183-ufsphy"}, | ||
| 230 | {}, | ||
| 231 | }; | ||
| 232 | MODULE_DEVICE_TABLE(of, ufs_mtk_phy_of_match); | ||
| 233 | |||
| 234 | static struct platform_driver ufs_mtk_phy_driver = { | ||
| 235 | .probe = ufs_mtk_phy_probe, | ||
| 236 | .driver = { | ||
| 237 | .of_match_table = ufs_mtk_phy_of_match, | ||
| 238 | .name = "ufs_mtk_phy", | ||
| 239 | }, | ||
| 240 | }; | ||
| 241 | module_platform_driver(ufs_mtk_phy_driver); | ||
| 242 | |||
| 243 | MODULE_DESCRIPTION("Universal Flash Storage (UFS) MediaTek MPHY"); | ||
| 244 | MODULE_AUTHOR("Stanley Chu <stanley.chu@mediatek.com>"); | ||
| 245 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/phy/mscc/phy-ocelot-serdes.c b/drivers/phy/mscc/phy-ocelot-serdes.c index 77c46f639fbf..76f596365176 100644 --- a/drivers/phy/mscc/phy-ocelot-serdes.c +++ b/drivers/phy/mscc/phy-ocelot-serdes.c | |||
| @@ -31,6 +31,238 @@ struct serdes_macro { | |||
| 31 | struct serdes_ctrl *ctrl; | 31 | struct serdes_ctrl *ctrl; |
| 32 | }; | 32 | }; |
| 33 | 33 | ||
| 34 | #define MCB_S6G_CFG_TIMEOUT 50 | ||
| 35 | |||
| 36 | static int __serdes_write_mcb_s6g(struct regmap *regmap, u8 macro, u32 op) | ||
| 37 | { | ||
| 38 | unsigned int regval = 0; | ||
| 39 | |||
| 40 | regmap_write(regmap, HSIO_MCB_S6G_ADDR_CFG, op | | ||
| 41 | HSIO_MCB_S6G_ADDR_CFG_SERDES6G_ADDR(BIT(macro))); | ||
| 42 | |||
| 43 | return regmap_read_poll_timeout(regmap, HSIO_MCB_S6G_ADDR_CFG, regval, | ||
| 44 | (regval & op) != op, 100, | ||
| 45 | MCB_S6G_CFG_TIMEOUT * 1000); | ||
| 46 | } | ||
| 47 | |||
| 48 | static int serdes_commit_mcb_s6g(struct regmap *regmap, u8 macro) | ||
| 49 | { | ||
| 50 | return __serdes_write_mcb_s6g(regmap, macro, | ||
| 51 | HSIO_MCB_S6G_ADDR_CFG_SERDES6G_WR_ONE_SHOT); | ||
| 52 | } | ||
| 53 | |||
| 54 | static int serdes_update_mcb_s6g(struct regmap *regmap, u8 macro) | ||
| 55 | { | ||
| 56 | return __serdes_write_mcb_s6g(regmap, macro, | ||
| 57 | HSIO_MCB_S6G_ADDR_CFG_SERDES6G_RD_ONE_SHOT); | ||
| 58 | } | ||
| 59 | |||
| 60 | static int serdes_init_s6g(struct regmap *regmap, u8 serdes, int mode) | ||
| 61 | { | ||
| 62 | u32 pll_fsm_ctrl_data; | ||
| 63 | u32 ob_ena1v_mode; | ||
| 64 | u32 des_bw_ana; | ||
| 65 | u32 ob_ena_cas; | ||
| 66 | u32 if_mode; | ||
| 67 | u32 ob_lev; | ||
| 68 | u32 qrate; | ||
| 69 | int ret; | ||
| 70 | |||
| 71 | if (mode == PHY_INTERFACE_MODE_QSGMII) { | ||
| 72 | pll_fsm_ctrl_data = 120; | ||
| 73 | ob_ena1v_mode = 0; | ||
| 74 | ob_ena_cas = 0; | ||
| 75 | des_bw_ana = 5; | ||
| 76 | ob_lev = 24; | ||
| 77 | if_mode = 3; | ||
| 78 | qrate = 0; | ||
| 79 | } else { | ||
| 80 | pll_fsm_ctrl_data = 60; | ||
| 81 | ob_ena1v_mode = 1; | ||
| 82 | ob_ena_cas = 2; | ||
| 83 | des_bw_ana = 3; | ||
| 84 | ob_lev = 48; | ||
| 85 | if_mode = 1; | ||
| 86 | qrate = 1; | ||
| 87 | } | ||
| 88 | |||
| 89 | ret = serdes_update_mcb_s6g(regmap, serdes); | ||
| 90 | if (ret) | ||
| 91 | return ret; | ||
| 92 | |||
| 93 | /* Test pattern */ | ||
| 94 | |||
| 95 | regmap_update_bits(regmap, HSIO_S6G_COMMON_CFG, | ||
| 96 | HSIO_S6G_COMMON_CFG_SYS_RST, 0); | ||
| 97 | |||
| 98 | regmap_update_bits(regmap, HSIO_S6G_PLL_CFG, | ||
| 99 | HSIO_S6G_PLL_CFG_PLL_FSM_ENA, 0); | ||
| 100 | |||
| 101 | regmap_update_bits(regmap, HSIO_S6G_IB_CFG, | ||
| 102 | HSIO_S6G_IB_CFG_IB_SIG_DET_ENA | | ||
| 103 | HSIO_S6G_IB_CFG_IB_REG_ENA | | ||
| 104 | HSIO_S6G_IB_CFG_IB_SAM_ENA | | ||
| 105 | HSIO_S6G_IB_CFG_IB_EQZ_ENA | | ||
| 106 | HSIO_S6G_IB_CFG_IB_CONCUR | | ||
| 107 | HSIO_S6G_IB_CFG_IB_CAL_ENA, | ||
| 108 | HSIO_S6G_IB_CFG_IB_SIG_DET_ENA | | ||
| 109 | HSIO_S6G_IB_CFG_IB_REG_ENA | | ||
| 110 | HSIO_S6G_IB_CFG_IB_SAM_ENA | | ||
| 111 | HSIO_S6G_IB_CFG_IB_EQZ_ENA | | ||
| 112 | HSIO_S6G_IB_CFG_IB_CONCUR); | ||
| 113 | |||
| 114 | regmap_update_bits(regmap, HSIO_S6G_IB_CFG1, | ||
| 115 | HSIO_S6G_IB_CFG1_IB_FRC_OFFSET | | ||
| 116 | HSIO_S6G_IB_CFG1_IB_FRC_LP | | ||
| 117 | HSIO_S6G_IB_CFG1_IB_FRC_MID | | ||
| 118 | HSIO_S6G_IB_CFG1_IB_FRC_HP | | ||
| 119 | HSIO_S6G_IB_CFG1_IB_FILT_OFFSET | | ||
| 120 | HSIO_S6G_IB_CFG1_IB_FILT_LP | | ||
| 121 | HSIO_S6G_IB_CFG1_IB_FILT_MID | | ||
| 122 | HSIO_S6G_IB_CFG1_IB_FILT_HP, | ||
| 123 | HSIO_S6G_IB_CFG1_IB_FILT_OFFSET | | ||
| 124 | HSIO_S6G_IB_CFG1_IB_FILT_HP | | ||
| 125 | HSIO_S6G_IB_CFG1_IB_FILT_LP | | ||
| 126 | HSIO_S6G_IB_CFG1_IB_FILT_MID); | ||
| 127 | |||
| 128 | regmap_update_bits(regmap, HSIO_S6G_IB_CFG2, | ||
| 129 | HSIO_S6G_IB_CFG2_IB_UREG_M, | ||
| 130 | HSIO_S6G_IB_CFG2_IB_UREG(4)); | ||
| 131 | |||
| 132 | regmap_update_bits(regmap, HSIO_S6G_IB_CFG3, | ||
| 133 | HSIO_S6G_IB_CFG3_IB_INI_OFFSET_M | | ||
| 134 | HSIO_S6G_IB_CFG3_IB_INI_LP_M | | ||
| 135 | HSIO_S6G_IB_CFG3_IB_INI_MID_M | | ||
| 136 | HSIO_S6G_IB_CFG3_IB_INI_HP_M, | ||
| 137 | HSIO_S6G_IB_CFG3_IB_INI_OFFSET(31) | | ||
| 138 | HSIO_S6G_IB_CFG3_IB_INI_LP(1) | | ||
| 139 | HSIO_S6G_IB_CFG3_IB_INI_MID(31) | | ||
| 140 | HSIO_S6G_IB_CFG3_IB_INI_HP(0)); | ||
| 141 | |||
| 142 | regmap_update_bits(regmap, HSIO_S6G_MISC_CFG, | ||
| 143 | HSIO_S6G_MISC_CFG_LANE_RST, | ||
| 144 | HSIO_S6G_MISC_CFG_LANE_RST); | ||
| 145 | |||
| 146 | ret = serdes_commit_mcb_s6g(regmap, serdes); | ||
| 147 | if (ret) | ||
| 148 | return ret; | ||
| 149 | |||
| 150 | /* OB + DES + IB + SER CFG */ | ||
| 151 | regmap_update_bits(regmap, HSIO_S6G_OB_CFG, | ||
| 152 | HSIO_S6G_OB_CFG_OB_IDLE | | ||
| 153 | HSIO_S6G_OB_CFG_OB_ENA1V_MODE | | ||
| 154 | HSIO_S6G_OB_CFG_OB_POST0_M | | ||
| 155 | HSIO_S6G_OB_CFG_OB_PREC_M, | ||
| 156 | (ob_ena1v_mode ? HSIO_S6G_OB_CFG_OB_ENA1V_MODE : 0) | | ||
| 157 | HSIO_S6G_OB_CFG_OB_POST0(0) | | ||
| 158 | HSIO_S6G_OB_CFG_OB_PREC(0)); | ||
| 159 | |||
| 160 | regmap_update_bits(regmap, HSIO_S6G_OB_CFG1, | ||
| 161 | HSIO_S6G_OB_CFG1_OB_ENA_CAS_M | | ||
| 162 | HSIO_S6G_OB_CFG1_OB_LEV_M, | ||
| 163 | HSIO_S6G_OB_CFG1_OB_LEV(ob_lev) | | ||
| 164 | HSIO_S6G_OB_CFG1_OB_ENA_CAS(ob_ena_cas)); | ||
| 165 | |||
| 166 | regmap_update_bits(regmap, HSIO_S6G_DES_CFG, | ||
| 167 | HSIO_S6G_DES_CFG_DES_PHS_CTRL_M | | ||
| 168 | HSIO_S6G_DES_CFG_DES_CPMD_SEL_M | | ||
| 169 | HSIO_S6G_DES_CFG_DES_BW_ANA_M, | ||
| 170 | HSIO_S6G_DES_CFG_DES_PHS_CTRL(2) | | ||
| 171 | HSIO_S6G_DES_CFG_DES_CPMD_SEL(0) | | ||
| 172 | HSIO_S6G_DES_CFG_DES_BW_ANA(des_bw_ana)); | ||
| 173 | |||
| 174 | regmap_update_bits(regmap, HSIO_S6G_IB_CFG, | ||
| 175 | HSIO_S6G_IB_CFG_IB_SIG_DET_CLK_SEL_M | | ||
| 176 | HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_OFFSET_M, | ||
| 177 | HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_OFFSET(0) | | ||
| 178 | HSIO_S6G_IB_CFG_IB_SIG_DET_CLK_SEL(0)); | ||
| 179 | |||
| 180 | regmap_update_bits(regmap, HSIO_S6G_IB_CFG1, | ||
| 181 | HSIO_S6G_IB_CFG1_IB_TSDET_M, | ||
| 182 | HSIO_S6G_IB_CFG1_IB_TSDET(16)); | ||
| 183 | |||
| 184 | regmap_update_bits(regmap, HSIO_S6G_SER_CFG, | ||
| 185 | HSIO_S6G_SER_CFG_SER_ALISEL_M | | ||
| 186 | HSIO_S6G_SER_CFG_SER_ENALI, | ||
| 187 | HSIO_S6G_SER_CFG_SER_ALISEL(0)); | ||
| 188 | |||
| 189 | regmap_update_bits(regmap, HSIO_S6G_PLL_CFG, | ||
| 190 | HSIO_S6G_PLL_CFG_PLL_DIV4 | | ||
| 191 | HSIO_S6G_PLL_CFG_PLL_ENA_ROT | | ||
| 192 | HSIO_S6G_PLL_CFG_PLL_FSM_CTRL_DATA_M | | ||
| 193 | HSIO_S6G_PLL_CFG_PLL_ROT_DIR | | ||
| 194 | HSIO_S6G_PLL_CFG_PLL_ROT_FRQ, | ||
| 195 | HSIO_S6G_PLL_CFG_PLL_FSM_CTRL_DATA | ||
| 196 | (pll_fsm_ctrl_data)); | ||
| 197 | |||
| 198 | regmap_update_bits(regmap, HSIO_S6G_COMMON_CFG, | ||
| 199 | HSIO_S6G_COMMON_CFG_SYS_RST | | ||
| 200 | HSIO_S6G_COMMON_CFG_ENA_LANE | | ||
| 201 | HSIO_S6G_COMMON_CFG_PWD_RX | | ||
| 202 | HSIO_S6G_COMMON_CFG_PWD_TX | | ||
| 203 | HSIO_S6G_COMMON_CFG_HRATE | | ||
| 204 | HSIO_S6G_COMMON_CFG_QRATE | | ||
| 205 | HSIO_S6G_COMMON_CFG_ENA_ELOOP | | ||
| 206 | HSIO_S6G_COMMON_CFG_ENA_FLOOP | | ||
| 207 | HSIO_S6G_COMMON_CFG_IF_MODE_M, | ||
| 208 | HSIO_S6G_COMMON_CFG_SYS_RST | | ||
| 209 | HSIO_S6G_COMMON_CFG_ENA_LANE | | ||
| 210 | (qrate ? HSIO_S6G_COMMON_CFG_QRATE : 0) | | ||
| 211 | HSIO_S6G_COMMON_CFG_IF_MODE(if_mode)); | ||
| 212 | |||
| 213 | regmap_update_bits(regmap, HSIO_S6G_MISC_CFG, | ||
| 214 | HSIO_S6G_MISC_CFG_LANE_RST | | ||
| 215 | HSIO_S6G_MISC_CFG_DES_100FX_CPMD_ENA | | ||
| 216 | HSIO_S6G_MISC_CFG_RX_LPI_MODE_ENA | | ||
| 217 | HSIO_S6G_MISC_CFG_TX_LPI_MODE_ENA, | ||
| 218 | HSIO_S6G_MISC_CFG_LANE_RST | | ||
| 219 | HSIO_S6G_MISC_CFG_RX_LPI_MODE_ENA); | ||
| 220 | |||
| 221 | |||
| 222 | ret = serdes_commit_mcb_s6g(regmap, serdes); | ||
| 223 | if (ret) | ||
| 224 | return ret; | ||
| 225 | |||
| 226 | regmap_update_bits(regmap, HSIO_S6G_PLL_CFG, | ||
| 227 | HSIO_S6G_PLL_CFG_PLL_FSM_ENA, | ||
| 228 | HSIO_S6G_PLL_CFG_PLL_FSM_ENA); | ||
| 229 | |||
| 230 | ret = serdes_commit_mcb_s6g(regmap, serdes); | ||
| 231 | if (ret) | ||
| 232 | return ret; | ||
| 233 | |||
| 234 | /* Wait for PLL bringup */ | ||
| 235 | msleep(20); | ||
| 236 | |||
| 237 | regmap_update_bits(regmap, HSIO_S6G_IB_CFG, | ||
| 238 | HSIO_S6G_IB_CFG_IB_CAL_ENA, | ||
| 239 | HSIO_S6G_IB_CFG_IB_CAL_ENA); | ||
| 240 | |||
| 241 | regmap_update_bits(regmap, HSIO_S6G_MISC_CFG, | ||
| 242 | HSIO_S6G_MISC_CFG_LANE_RST, 0); | ||
| 243 | |||
| 244 | ret = serdes_commit_mcb_s6g(regmap, serdes); | ||
| 245 | if (ret) | ||
| 246 | return ret; | ||
| 247 | |||
| 248 | /* Wait for calibration */ | ||
| 249 | msleep(60); | ||
| 250 | |||
| 251 | regmap_update_bits(regmap, HSIO_S6G_IB_CFG, | ||
| 252 | HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_OFFSET_M | | ||
| 253 | HSIO_S6G_IB_CFG_IB_SIG_DET_CLK_SEL_M, | ||
| 254 | HSIO_S6G_IB_CFG_IB_REG_PAT_SEL_OFFSET(0) | | ||
| 255 | HSIO_S6G_IB_CFG_IB_SIG_DET_CLK_SEL(7)); | ||
| 256 | |||
| 257 | regmap_update_bits(regmap, HSIO_S6G_IB_CFG1, | ||
| 258 | HSIO_S6G_IB_CFG1_IB_TSDET_M, | ||
| 259 | HSIO_S6G_IB_CFG1_IB_TSDET(3)); | ||
| 260 | |||
| 261 | /* IB CFG */ | ||
| 262 | |||
| 263 | return 0; | ||
| 264 | } | ||
| 265 | |||
| 34 | #define MCB_S1G_CFG_TIMEOUT 50 | 266 | #define MCB_S1G_CFG_TIMEOUT 50 |
| 35 | 267 | ||
| 36 | static int __serdes_write_mcb_s1g(struct regmap *regmap, u8 macro, u32 op) | 268 | static int __serdes_write_mcb_s1g(struct regmap *regmap, u8 macro, u32 op) |
| @@ -110,7 +342,7 @@ struct serdes_mux { | |||
| 110 | u32 mux; | 342 | u32 mux; |
| 111 | }; | 343 | }; |
| 112 | 344 | ||
| 113 | #define SERDES_MUX(_idx, _port, _mode, _submode, _mask, _mux) { \ | 345 | #define SERDES_MUX(_idx, _port, _mode, _submode, _mask, _mux) { \ |
| 114 | .idx = _idx, \ | 346 | .idx = _idx, \ |
| 115 | .port = _port, \ | 347 | .port = _port, \ |
| 116 | .mode = _mode, \ | 348 | .mode = _mode, \ |
| @@ -191,8 +423,12 @@ static int serdes_set_mode(struct phy *phy, enum phy_mode mode, int submode) | |||
| 191 | 423 | ||
| 192 | if (macro->idx <= SERDES1G_MAX) | 424 | if (macro->idx <= SERDES1G_MAX) |
| 193 | return serdes_init_s1g(macro->ctrl->regs, macro->idx); | 425 | return serdes_init_s1g(macro->ctrl->regs, macro->idx); |
| 426 | else if (macro->idx <= SERDES6G_MAX) | ||
| 427 | return serdes_init_s6g(macro->ctrl->regs, | ||
| 428 | macro->idx - (SERDES1G_MAX + 1), | ||
| 429 | ocelot_serdes_muxes[i].submode); | ||
| 194 | 430 | ||
| 195 | /* SERDES6G and PCIe not supported yet */ | 431 | /* PCIe not supported yet */ |
| 196 | return -EOPNOTSUPP; | 432 | return -EOPNOTSUPP; |
| 197 | } | 433 | } |
| 198 | 434 | ||
diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index cb38f6e8614c..c147ba843f0b 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c | |||
| @@ -384,10 +384,16 @@ int phy_reset(struct phy *phy) | |||
| 384 | if (!phy || !phy->ops->reset) | 384 | if (!phy || !phy->ops->reset) |
| 385 | return 0; | 385 | return 0; |
| 386 | 386 | ||
| 387 | ret = phy_pm_runtime_get_sync(phy); | ||
| 388 | if (ret < 0 && ret != -ENOTSUPP) | ||
| 389 | return ret; | ||
| 390 | |||
| 387 | mutex_lock(&phy->mutex); | 391 | mutex_lock(&phy->mutex); |
| 388 | ret = phy->ops->reset(phy); | 392 | ret = phy->ops->reset(phy); |
| 389 | mutex_unlock(&phy->mutex); | 393 | mutex_unlock(&phy->mutex); |
| 390 | 394 | ||
| 395 | phy_pm_runtime_put(phy); | ||
| 396 | |||
| 391 | return ret; | 397 | return ret; |
| 392 | } | 398 | } |
| 393 | EXPORT_SYMBOL_GPL(phy_reset); | 399 | EXPORT_SYMBOL_GPL(phy_reset); |
| @@ -564,6 +570,11 @@ void phy_put(struct phy *phy) | |||
| 564 | if (!phy || IS_ERR(phy)) | 570 | if (!phy || IS_ERR(phy)) |
| 565 | return; | 571 | return; |
| 566 | 572 | ||
| 573 | mutex_lock(&phy->mutex); | ||
| 574 | if (phy->ops->release) | ||
| 575 | phy->ops->release(phy); | ||
| 576 | mutex_unlock(&phy->mutex); | ||
| 577 | |||
| 567 | module_put(phy->ops->owner); | 578 | module_put(phy->ops->owner); |
| 568 | put_device(&phy->dev); | 579 | put_device(&phy->dev); |
| 569 | } | 580 | } |
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c index 08d6f6f7f039..cd91b4179b10 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.c +++ b/drivers/phy/qualcomm/phy-qcom-qmp.c | |||
| @@ -242,6 +242,88 @@ static const struct qmp_phy_init_tbl msm8996_pcie_pcs_tbl[] = { | |||
| 242 | QMP_PHY_INIT_CFG(QPHY_TXDEEMPH_M3P5DB_V0, 0x0e), | 242 | QMP_PHY_INIT_CFG(QPHY_TXDEEMPH_M3P5DB_V0, 0x0e), |
| 243 | }; | 243 | }; |
| 244 | 244 | ||
| 245 | static const struct qmp_phy_init_tbl msm8998_pcie_serdes_tbl[] = { | ||
| 246 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_BIAS_EN_CLKBUFLR_EN, 0x14), | ||
| 247 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x30), | ||
| 248 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_IVCO, 0x0f), | ||
| 249 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_CONFIG, 0x06), | ||
| 250 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP_EN, 0x01), | ||
| 251 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_RESETSM_CNTRL, 0x20), | ||
| 252 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_MAP, 0x00), | ||
| 253 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE2_MODE0, 0x01), | ||
| 254 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE1_MODE0, 0xc9), | ||
| 255 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_TIMER1, 0xff), | ||
| 256 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_VCO_TUNE_TIMER2, 0x3f), | ||
| 257 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_SVS_MODE_CLK_SEL, 0x01), | ||
| 258 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORE_CLK_EN, 0x00), | ||
| 259 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_CORECLK_DIV_MODE0, 0x0a), | ||
| 260 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_EP_DIV, 0x19), | ||
| 261 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_ENABLE1, 0x90), | ||
| 262 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_DEC_START_MODE0, 0x82), | ||
| 263 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START3_MODE0, 0x03), | ||
| 264 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START2_MODE0, 0x55), | ||
| 265 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_DIV_FRAC_START1_MODE0, 0x55), | ||
| 266 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP3_MODE0, 0x00), | ||
| 267 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP2_MODE0, 0x0d), | ||
| 268 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_LOCK_CMP1_MODE0, 0x04), | ||
| 269 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_HSCLK_SEL, 0x00), | ||
| 270 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_CP_CTRL_MODE0, 0x08), | ||
| 271 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_RCTRL_MODE0, 0x16), | ||
| 272 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_PLL_CCTRL_MODE0, 0x34), | ||
| 273 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_CMN_CONFIG, 0x06), | ||
| 274 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_CLK_SELECT, 0x33), | ||
| 275 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYS_CLK_CTRL, 0x02), | ||
| 276 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_BUF_ENABLE, 0x07), | ||
| 277 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_SYSCLK_EN_SEL, 0x04), | ||
| 278 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN1_MODE0, 0x00), | ||
| 279 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_INTEGLOOP_GAIN0_MODE0, 0x3f), | ||
| 280 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_BG_TIMER, 0x09), | ||
| 281 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_EN_CENTER, 0x01), | ||
| 282 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER1, 0x40), | ||
| 283 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_PER2, 0x01), | ||
| 284 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER1, 0x02), | ||
| 285 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_ADJ_PER2, 0x00), | ||
| 286 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE1, 0x7e), | ||
| 287 | QMP_PHY_INIT_CFG(QSERDES_V3_COM_SSC_STEP_SIZE2, 0x15), | ||
| 288 | }; | ||
| 289 | |||
| 290 | static const struct qmp_phy_init_tbl msm8998_pcie_tx_tbl[] = { | ||
| 291 | QMP_PHY_INIT_CFG(QSERDES_V3_TX_RES_CODE_LANE_OFFSET_TX, 0x02), | ||
| 292 | QMP_PHY_INIT_CFG(QSERDES_V3_TX_RCV_DETECT_LVL_2, 0x12), | ||
| 293 | QMP_PHY_INIT_CFG(QSERDES_V3_TX_HIGHZ_DRVR_EN, 0x10), | ||
| 294 | QMP_PHY_INIT_CFG(QSERDES_V3_TX_LANE_MODE_1, 0x06), | ||
| 295 | }; | ||
| 296 | |||
| 297 | static const struct qmp_phy_init_tbl msm8998_pcie_rx_tbl[] = { | ||
| 298 | QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_CNTRL, 0x03), | ||
| 299 | QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_ENABLES, 0x1c), | ||
| 300 | QMP_PHY_INIT_CFG(QSERDES_V3_RX_SIGDET_DEGLITCH_CNTRL, 0x14), | ||
| 301 | QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0a), | ||
| 302 | QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL3, 0x04), | ||
| 303 | QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQU_ADAPTOR_CNTRL4, 0x1a), | ||
| 304 | QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_SATURATION_AND_ENABLE, 0x4b), | ||
| 305 | QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_GAIN, 0x04), | ||
| 306 | QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_SO_GAIN_HALF, 0x04), | ||
| 307 | QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_EQ_OFFSET_ADAPTOR_CNTRL1, 0x00), | ||
| 308 | QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_OFFSET_ADAPTOR_CNTRL2, 0x80), | ||
| 309 | QMP_PHY_INIT_CFG(QSERDES_V3_RX_RX_INTERFACE_MODE, 0x40), | ||
| 310 | QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_PI_CONTROLS, 0x71), | ||
| 311 | QMP_PHY_INIT_CFG(QSERDES_V3_RX_UCDR_FASTLOCK_COUNT_LOW, 0x40), | ||
| 312 | }; | ||
| 313 | |||
| 314 | static const struct qmp_phy_init_tbl msm8998_pcie_pcs_tbl[] = { | ||
| 315 | QMP_PHY_INIT_CFG(QPHY_V3_PCS_ENDPOINT_REFCLK_DRIVE, 0x04), | ||
| 316 | QMP_PHY_INIT_CFG(QPHY_V3_PCS_OSC_DTCT_ACTIONS, 0x00), | ||
| 317 | QMP_PHY_INIT_CFG(QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK, 0x01), | ||
| 318 | QMP_PHY_INIT_CFG(QPHY_V3_PCS_L1SS_WAKEUP_DLY_TIME_AUXCLK_MSB, 0x00), | ||
| 319 | QMP_PHY_INIT_CFG(QPHY_V3_PCS_L1SS_WAKEUP_DLY_TIME_AUXCLK_LSB, 0x20), | ||
| 320 | QMP_PHY_INIT_CFG(QPHY_V3_PCS_LP_WAKEUP_DLY_TIME_AUXCLK_MSB, 0x00), | ||
| 321 | QMP_PHY_INIT_CFG(QPHY_V3_PCS_LP_WAKEUP_DLY_TIME_AUXCLK, 0x01), | ||
| 322 | QMP_PHY_INIT_CFG(QPHY_V3_PCS_PLL_LOCK_CHK_DLY_TIME, 0x73), | ||
| 323 | QMP_PHY_INIT_CFG(QPHY_V3_PCS_RX_SIGDET_LVL, 0x99), | ||
| 324 | QMP_PHY_INIT_CFG(QPHY_V3_PCS_SIGDET_CNTRL, 0x03), | ||
| 325 | }; | ||
| 326 | |||
| 245 | static const struct qmp_phy_init_tbl msm8996_usb3_serdes_tbl[] = { | 327 | static const struct qmp_phy_init_tbl msm8996_usb3_serdes_tbl[] = { |
| 246 | QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x14), | 328 | QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x14), |
| 247 | QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08), | 329 | QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08), |
| @@ -897,6 +979,7 @@ struct qmp_phy { | |||
| 897 | * @init_count: phy common block initialization count | 979 | * @init_count: phy common block initialization count |
| 898 | * @phy_initialized: indicate if PHY has been initialized | 980 | * @phy_initialized: indicate if PHY has been initialized |
| 899 | * @mode: current PHY mode | 981 | * @mode: current PHY mode |
| 982 | * @ufs_reset: optional UFS PHY reset handle | ||
| 900 | */ | 983 | */ |
| 901 | struct qcom_qmp { | 984 | struct qcom_qmp { |
| 902 | struct device *dev; | 985 | struct device *dev; |
| @@ -914,6 +997,8 @@ struct qcom_qmp { | |||
| 914 | int init_count; | 997 | int init_count; |
| 915 | bool phy_initialized; | 998 | bool phy_initialized; |
| 916 | enum phy_mode mode; | 999 | enum phy_mode mode; |
| 1000 | |||
| 1001 | struct reset_control *ufs_reset; | ||
| 917 | }; | 1002 | }; |
| 918 | 1003 | ||
| 919 | static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val) | 1004 | static inline void qphy_setbits(void __iomem *base, u32 offset, u32 val) |
| @@ -1146,6 +1231,31 @@ static const struct qmp_phy_cfg sdm845_ufsphy_cfg = { | |||
| 1146 | .no_pcs_sw_reset = true, | 1231 | .no_pcs_sw_reset = true, |
| 1147 | }; | 1232 | }; |
| 1148 | 1233 | ||
| 1234 | static const struct qmp_phy_cfg msm8998_pciephy_cfg = { | ||
| 1235 | .type = PHY_TYPE_PCIE, | ||
| 1236 | .nlanes = 1, | ||
| 1237 | |||
| 1238 | .serdes_tbl = msm8998_pcie_serdes_tbl, | ||
| 1239 | .serdes_tbl_num = ARRAY_SIZE(msm8998_pcie_serdes_tbl), | ||
| 1240 | .tx_tbl = msm8998_pcie_tx_tbl, | ||
| 1241 | .tx_tbl_num = ARRAY_SIZE(msm8998_pcie_tx_tbl), | ||
| 1242 | .rx_tbl = msm8998_pcie_rx_tbl, | ||
| 1243 | .rx_tbl_num = ARRAY_SIZE(msm8998_pcie_rx_tbl), | ||
| 1244 | .pcs_tbl = msm8998_pcie_pcs_tbl, | ||
| 1245 | .pcs_tbl_num = ARRAY_SIZE(msm8998_pcie_pcs_tbl), | ||
| 1246 | .clk_list = msm8996_phy_clk_l, | ||
| 1247 | .num_clks = ARRAY_SIZE(msm8996_phy_clk_l), | ||
| 1248 | .reset_list = ipq8074_pciephy_reset_l, | ||
| 1249 | .num_resets = ARRAY_SIZE(ipq8074_pciephy_reset_l), | ||
| 1250 | .vreg_list = qmp_phy_vreg_l, | ||
| 1251 | .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l), | ||
| 1252 | .regs = pciephy_regs_layout, | ||
| 1253 | |||
| 1254 | .start_ctrl = SERDES_START | PCS_START, | ||
| 1255 | .pwrdn_ctrl = SW_PWRDN | REFCLK_DRV_DSBL, | ||
| 1256 | .mask_com_pcs_ready = PCS_READY, | ||
| 1257 | }; | ||
| 1258 | |||
| 1149 | static const struct qmp_phy_cfg msm8998_usb3phy_cfg = { | 1259 | static const struct qmp_phy_cfg msm8998_usb3phy_cfg = { |
| 1150 | .type = PHY_TYPE_USB3, | 1260 | .type = PHY_TYPE_USB3, |
| 1151 | .nlanes = 1, | 1261 | .nlanes = 1, |
| @@ -1314,6 +1424,7 @@ static int qcom_qmp_phy_com_exit(struct qcom_qmp *qmp) | |||
| 1314 | return 0; | 1424 | return 0; |
| 1315 | } | 1425 | } |
| 1316 | 1426 | ||
| 1427 | reset_control_assert(qmp->ufs_reset); | ||
| 1317 | if (cfg->has_phy_com_ctrl) { | 1428 | if (cfg->has_phy_com_ctrl) { |
| 1318 | qphy_setbits(serdes, cfg->regs[QPHY_COM_START_CONTROL], | 1429 | qphy_setbits(serdes, cfg->regs[QPHY_COM_START_CONTROL], |
| 1319 | SERDES_START | PCS_START); | 1430 | SERDES_START | PCS_START); |
| @@ -1335,8 +1446,7 @@ static int qcom_qmp_phy_com_exit(struct qcom_qmp *qmp) | |||
| 1335 | return 0; | 1446 | return 0; |
| 1336 | } | 1447 | } |
| 1337 | 1448 | ||
| 1338 | /* PHY Initialization */ | 1449 | static int qcom_qmp_phy_enable(struct phy *phy) |
| 1339 | static int qcom_qmp_phy_init(struct phy *phy) | ||
| 1340 | { | 1450 | { |
| 1341 | struct qmp_phy *qphy = phy_get_drvdata(phy); | 1451 | struct qmp_phy *qphy = phy_get_drvdata(phy); |
| 1342 | struct qcom_qmp *qmp = qphy->qmp; | 1452 | struct qcom_qmp *qmp = qphy->qmp; |
| @@ -1351,6 +1461,33 @@ static int qcom_qmp_phy_init(struct phy *phy) | |||
| 1351 | 1461 | ||
| 1352 | dev_vdbg(qmp->dev, "Initializing QMP phy\n"); | 1462 | dev_vdbg(qmp->dev, "Initializing QMP phy\n"); |
| 1353 | 1463 | ||
| 1464 | if (cfg->no_pcs_sw_reset) { | ||
| 1465 | /* | ||
| 1466 | * Get UFS reset, which is delayed until now to avoid a | ||
| 1467 | * circular dependency where UFS needs its PHY, but the PHY | ||
| 1468 | * needs this UFS reset. | ||
| 1469 | */ | ||
| 1470 | if (!qmp->ufs_reset) { | ||
| 1471 | qmp->ufs_reset = | ||
| 1472 | devm_reset_control_get_exclusive(qmp->dev, | ||
| 1473 | "ufsphy"); | ||
| 1474 | |||
| 1475 | if (IS_ERR(qmp->ufs_reset)) { | ||
| 1476 | ret = PTR_ERR(qmp->ufs_reset); | ||
| 1477 | dev_err(qmp->dev, | ||
| 1478 | "failed to get UFS reset: %d\n", | ||
| 1479 | ret); | ||
| 1480 | |||
| 1481 | qmp->ufs_reset = NULL; | ||
| 1482 | return ret; | ||
| 1483 | } | ||
| 1484 | } | ||
| 1485 | |||
| 1486 | ret = reset_control_assert(qmp->ufs_reset); | ||
| 1487 | if (ret) | ||
| 1488 | goto err_lane_rst; | ||
| 1489 | } | ||
| 1490 | |||
| 1354 | ret = qcom_qmp_phy_com_init(qphy); | 1491 | ret = qcom_qmp_phy_com_init(qphy); |
| 1355 | if (ret) | 1492 | if (ret) |
| 1356 | return ret; | 1493 | return ret; |
| @@ -1383,14 +1520,9 @@ static int qcom_qmp_phy_init(struct phy *phy) | |||
| 1383 | cfg->rx_tbl, cfg->rx_tbl_num); | 1520 | cfg->rx_tbl, cfg->rx_tbl_num); |
| 1384 | 1521 | ||
| 1385 | qcom_qmp_phy_configure(pcs, cfg->regs, cfg->pcs_tbl, cfg->pcs_tbl_num); | 1522 | qcom_qmp_phy_configure(pcs, cfg->regs, cfg->pcs_tbl, cfg->pcs_tbl_num); |
| 1386 | 1523 | ret = reset_control_deassert(qmp->ufs_reset); | |
| 1387 | /* | 1524 | if (ret) |
| 1388 | * UFS PHY requires the deassert of software reset before serdes start. | 1525 | goto err_lane_rst; |
| 1389 | * For UFS PHYs that do not have software reset control bits, defer | ||
| 1390 | * starting serdes until the power on callback. | ||
| 1391 | */ | ||
| 1392 | if ((cfg->type == PHY_TYPE_UFS) && cfg->no_pcs_sw_reset) | ||
| 1393 | goto out; | ||
| 1394 | 1526 | ||
| 1395 | /* | 1527 | /* |
| 1396 | * Pull out PHY from POWER DOWN state. | 1528 | * Pull out PHY from POWER DOWN state. |
| @@ -1403,7 +1535,9 @@ static int qcom_qmp_phy_init(struct phy *phy) | |||
| 1403 | usleep_range(cfg->pwrdn_delay_min, cfg->pwrdn_delay_max); | 1535 | usleep_range(cfg->pwrdn_delay_min, cfg->pwrdn_delay_max); |
| 1404 | 1536 | ||
| 1405 | /* Pull PHY out of reset state */ | 1537 | /* Pull PHY out of reset state */ |
| 1406 | qphy_clrbits(pcs, cfg->regs[QPHY_SW_RESET], SW_RESET); | 1538 | if (!cfg->no_pcs_sw_reset) |
| 1539 | qphy_clrbits(pcs, cfg->regs[QPHY_SW_RESET], SW_RESET); | ||
| 1540 | |||
| 1407 | if (cfg->has_phy_dp_com_ctrl) | 1541 | if (cfg->has_phy_dp_com_ctrl) |
| 1408 | qphy_clrbits(dp_com, QPHY_V3_DP_COM_SW_RESET, SW_RESET); | 1542 | qphy_clrbits(dp_com, QPHY_V3_DP_COM_SW_RESET, SW_RESET); |
| 1409 | 1543 | ||
| @@ -1420,11 +1554,10 @@ static int qcom_qmp_phy_init(struct phy *phy) | |||
| 1420 | goto err_pcs_ready; | 1554 | goto err_pcs_ready; |
| 1421 | } | 1555 | } |
| 1422 | qmp->phy_initialized = true; | 1556 | qmp->phy_initialized = true; |
| 1423 | 1557 | return 0; | |
| 1424 | out: | ||
| 1425 | return ret; | ||
| 1426 | 1558 | ||
| 1427 | err_pcs_ready: | 1559 | err_pcs_ready: |
| 1560 | reset_control_assert(qmp->ufs_reset); | ||
| 1428 | clk_disable_unprepare(qphy->pipe_clk); | 1561 | clk_disable_unprepare(qphy->pipe_clk); |
| 1429 | err_clk_enable: | 1562 | err_clk_enable: |
| 1430 | if (cfg->has_lane_rst) | 1563 | if (cfg->has_lane_rst) |
| @@ -1435,7 +1568,7 @@ err_lane_rst: | |||
| 1435 | return ret; | 1568 | return ret; |
| 1436 | } | 1569 | } |
| 1437 | 1570 | ||
| 1438 | static int qcom_qmp_phy_exit(struct phy *phy) | 1571 | static int qcom_qmp_phy_disable(struct phy *phy) |
| 1439 | { | 1572 | { |
| 1440 | struct qmp_phy *qphy = phy_get_drvdata(phy); | 1573 | struct qmp_phy *qphy = phy_get_drvdata(phy); |
| 1441 | struct qcom_qmp *qmp = qphy->qmp; | 1574 | struct qcom_qmp *qmp = qphy->qmp; |
| @@ -1463,44 +1596,6 @@ static int qcom_qmp_phy_exit(struct phy *phy) | |||
| 1463 | return 0; | 1596 | return 0; |
| 1464 | } | 1597 | } |
| 1465 | 1598 | ||
| 1466 | static int qcom_qmp_phy_poweron(struct phy *phy) | ||
| 1467 | { | ||
| 1468 | struct qmp_phy *qphy = phy_get_drvdata(phy); | ||
| 1469 | struct qcom_qmp *qmp = qphy->qmp; | ||
| 1470 | const struct qmp_phy_cfg *cfg = qmp->cfg; | ||
| 1471 | void __iomem *pcs = qphy->pcs; | ||
| 1472 | void __iomem *status; | ||
| 1473 | unsigned int mask, val; | ||
| 1474 | int ret = 0; | ||
| 1475 | |||
| 1476 | if (cfg->type != PHY_TYPE_UFS) | ||
| 1477 | return 0; | ||
| 1478 | |||
| 1479 | /* | ||
| 1480 | * For UFS PHY that has not software reset control, serdes start | ||
| 1481 | * should only happen when UFS driver explicitly calls phy_power_on | ||
| 1482 | * after it deasserts software reset. | ||
| 1483 | */ | ||
| 1484 | if (cfg->no_pcs_sw_reset && !qmp->phy_initialized && | ||
| 1485 | (qmp->init_count != 0)) { | ||
| 1486 | /* start SerDes and Phy-Coding-Sublayer */ | ||
| 1487 | qphy_setbits(pcs, cfg->regs[QPHY_START_CTRL], cfg->start_ctrl); | ||
| 1488 | |||
| 1489 | status = pcs + cfg->regs[QPHY_PCS_READY_STATUS]; | ||
| 1490 | mask = cfg->mask_pcs_ready; | ||
| 1491 | |||
| 1492 | ret = readl_poll_timeout(status, val, !(val & mask), 1, | ||
| 1493 | PHY_INIT_COMPLETE_TIMEOUT); | ||
| 1494 | if (ret) { | ||
| 1495 | dev_err(qmp->dev, "phy initialization timed-out\n"); | ||
| 1496 | return ret; | ||
| 1497 | } | ||
| 1498 | qmp->phy_initialized = true; | ||
| 1499 | } | ||
| 1500 | |||
| 1501 | return ret; | ||
| 1502 | } | ||
| 1503 | |||
| 1504 | static int qcom_qmp_phy_set_mode(struct phy *phy, | 1599 | static int qcom_qmp_phy_set_mode(struct phy *phy, |
| 1505 | enum phy_mode mode, int submode) | 1600 | enum phy_mode mode, int submode) |
| 1506 | { | 1601 | { |
| @@ -1750,9 +1845,15 @@ static int phy_pipe_clk_register(struct qcom_qmp *qmp, struct device_node *np) | |||
| 1750 | } | 1845 | } |
| 1751 | 1846 | ||
| 1752 | static const struct phy_ops qcom_qmp_phy_gen_ops = { | 1847 | static const struct phy_ops qcom_qmp_phy_gen_ops = { |
| 1753 | .init = qcom_qmp_phy_init, | 1848 | .init = qcom_qmp_phy_enable, |
| 1754 | .exit = qcom_qmp_phy_exit, | 1849 | .exit = qcom_qmp_phy_disable, |
| 1755 | .power_on = qcom_qmp_phy_poweron, | 1850 | .set_mode = qcom_qmp_phy_set_mode, |
| 1851 | .owner = THIS_MODULE, | ||
| 1852 | }; | ||
| 1853 | |||
| 1854 | static const struct phy_ops qcom_qmp_ufs_ops = { | ||
| 1855 | .power_on = qcom_qmp_phy_enable, | ||
| 1856 | .power_off = qcom_qmp_phy_disable, | ||
| 1756 | .set_mode = qcom_qmp_phy_set_mode, | 1857 | .set_mode = qcom_qmp_phy_set_mode, |
| 1757 | .owner = THIS_MODULE, | 1858 | .owner = THIS_MODULE, |
| 1758 | }; | 1859 | }; |
| @@ -1763,6 +1864,7 @@ int qcom_qmp_phy_create(struct device *dev, struct device_node *np, int id) | |||
| 1763 | struct qcom_qmp *qmp = dev_get_drvdata(dev); | 1864 | struct qcom_qmp *qmp = dev_get_drvdata(dev); |
| 1764 | struct phy *generic_phy; | 1865 | struct phy *generic_phy; |
| 1765 | struct qmp_phy *qphy; | 1866 | struct qmp_phy *qphy; |
| 1867 | const struct phy_ops *ops = &qcom_qmp_phy_gen_ops; | ||
| 1766 | char prop_name[MAX_PROP_NAME]; | 1868 | char prop_name[MAX_PROP_NAME]; |
| 1767 | int ret; | 1869 | int ret; |
| 1768 | 1870 | ||
| @@ -1849,7 +1951,10 @@ int qcom_qmp_phy_create(struct device *dev, struct device_node *np, int id) | |||
| 1849 | } | 1951 | } |
| 1850 | } | 1952 | } |
| 1851 | 1953 | ||
| 1852 | generic_phy = devm_phy_create(dev, np, &qcom_qmp_phy_gen_ops); | 1954 | if (qmp->cfg->type == PHY_TYPE_UFS) |
| 1955 | ops = &qcom_qmp_ufs_ops; | ||
| 1956 | |||
| 1957 | generic_phy = devm_phy_create(dev, np, ops); | ||
| 1853 | if (IS_ERR(generic_phy)) { | 1958 | if (IS_ERR(generic_phy)) { |
| 1854 | ret = PTR_ERR(generic_phy); | 1959 | ret = PTR_ERR(generic_phy); |
| 1855 | dev_err(dev, "failed to create qphy %d\n", ret); | 1960 | dev_err(dev, "failed to create qphy %d\n", ret); |
| @@ -1873,6 +1978,9 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = { | |||
| 1873 | .compatible = "qcom,msm8996-qmp-usb3-phy", | 1978 | .compatible = "qcom,msm8996-qmp-usb3-phy", |
| 1874 | .data = &msm8996_usb3phy_cfg, | 1979 | .data = &msm8996_usb3phy_cfg, |
| 1875 | }, { | 1980 | }, { |
| 1981 | .compatible = "qcom,msm8998-qmp-pcie-phy", | ||
| 1982 | .data = &msm8998_pciephy_cfg, | ||
| 1983 | }, { | ||
| 1876 | .compatible = "qcom,msm8998-qmp-ufs-phy", | 1984 | .compatible = "qcom,msm8998-qmp-ufs-phy", |
| 1877 | .data = &sdm845_ufsphy_cfg, | 1985 | .data = &sdm845_ufsphy_cfg, |
| 1878 | }, { | 1986 | }, { |
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp.h b/drivers/phy/qualcomm/phy-qcom-qmp.h index a1b6cdee9a08..335ea5d7ef40 100644 --- a/drivers/phy/qualcomm/phy-qcom-qmp.h +++ b/drivers/phy/qualcomm/phy-qcom-qmp.h | |||
| @@ -241,6 +241,7 @@ | |||
| 241 | #define QSERDES_V3_RX_RX_BAND 0x110 | 241 | #define QSERDES_V3_RX_RX_BAND 0x110 |
| 242 | #define QSERDES_V3_RX_RX_INTERFACE_MODE 0x11c | 242 | #define QSERDES_V3_RX_RX_INTERFACE_MODE 0x11c |
| 243 | #define QSERDES_V3_RX_RX_MODE_00 0x164 | 243 | #define QSERDES_V3_RX_RX_MODE_00 0x164 |
| 244 | #define QSERDES_V3_RX_RX_MODE_01 0x168 | ||
| 244 | 245 | ||
| 245 | /* Only for QMP V3 PHY - PCS registers */ | 246 | /* Only for QMP V3 PHY - PCS registers */ |
| 246 | #define QPHY_V3_PCS_POWER_DOWN_CONTROL 0x004 | 247 | #define QPHY_V3_PCS_POWER_DOWN_CONTROL 0x004 |
| @@ -280,6 +281,7 @@ | |||
| 280 | #define QPHY_V3_PCS_TSYNC_RSYNC_TIME 0x08c | 281 | #define QPHY_V3_PCS_TSYNC_RSYNC_TIME 0x08c |
| 281 | #define QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK 0x0a0 | 282 | #define QPHY_V3_PCS_PWRUP_RESET_DLY_TIME_AUXCLK 0x0a0 |
| 282 | #define QPHY_V3_PCS_LP_WAKEUP_DLY_TIME_AUXCLK 0x0a4 | 283 | #define QPHY_V3_PCS_LP_WAKEUP_DLY_TIME_AUXCLK 0x0a4 |
| 284 | #define QPHY_V3_PCS_PLL_LOCK_CHK_DLY_TIME 0x0a8 | ||
| 283 | #define QPHY_V3_PCS_LFPS_TX_ECSTART_EQTLOCK 0x0b0 | 285 | #define QPHY_V3_PCS_LFPS_TX_ECSTART_EQTLOCK 0x0b0 |
| 284 | #define QPHY_V3_PCS_RXEQTRAINING_WAIT_TIME 0x0b8 | 286 | #define QPHY_V3_PCS_RXEQTRAINING_WAIT_TIME 0x0b8 |
| 285 | #define QPHY_V3_PCS_RXEQTRAINING_RUN_TIME 0x0bc | 287 | #define QPHY_V3_PCS_RXEQTRAINING_RUN_TIME 0x0bc |
| @@ -292,13 +294,23 @@ | |||
| 292 | #define QPHY_V3_PCS_RX_MIN_HIBERN8_TIME 0x138 | 294 | #define QPHY_V3_PCS_RX_MIN_HIBERN8_TIME 0x138 |
| 293 | #define QPHY_V3_PCS_RX_SIGDET_CTRL1 0x13c | 295 | #define QPHY_V3_PCS_RX_SIGDET_CTRL1 0x13c |
| 294 | #define QPHY_V3_PCS_RX_SIGDET_CTRL2 0x140 | 296 | #define QPHY_V3_PCS_RX_SIGDET_CTRL2 0x140 |
| 297 | #define QPHY_V3_PCS_LP_WAKEUP_DLY_TIME_AUXCLK_MSB 0x1a8 | ||
| 298 | #define QPHY_V3_PCS_OSC_DTCT_ACTIONS 0x1ac | ||
| 299 | #define QPHY_V3_PCS_SIGDET_CNTRL 0x1b0 | ||
| 295 | #define QPHY_V3_PCS_TX_MID_TERM_CTRL1 0x1bc | 300 | #define QPHY_V3_PCS_TX_MID_TERM_CTRL1 0x1bc |
| 296 | #define QPHY_V3_PCS_MULTI_LANE_CTRL1 0x1c4 | 301 | #define QPHY_V3_PCS_MULTI_LANE_CTRL1 0x1c4 |
| 297 | #define QPHY_V3_PCS_RX_SIGDET_LVL 0x1d8 | 302 | #define QPHY_V3_PCS_RX_SIGDET_LVL 0x1d8 |
| 303 | #define QPHY_V3_PCS_L1SS_WAKEUP_DLY_TIME_AUXCLK_LSB 0x1dc | ||
| 304 | #define QPHY_V3_PCS_L1SS_WAKEUP_DLY_TIME_AUXCLK_MSB 0x1e0 | ||
| 298 | #define QPHY_V3_PCS_REFGEN_REQ_CONFIG1 0x20c | 305 | #define QPHY_V3_PCS_REFGEN_REQ_CONFIG1 0x20c |
| 299 | #define QPHY_V3_PCS_REFGEN_REQ_CONFIG2 0x210 | 306 | #define QPHY_V3_PCS_REFGEN_REQ_CONFIG2 0x210 |
| 300 | 307 | ||
| 301 | /* Only for QMP V3 PHY - PCS_MISC registers */ | 308 | /* Only for QMP V3 PHY - PCS_MISC registers */ |
| 302 | #define QPHY_V3_PCS_MISC_CLAMP_ENABLE 0x0c | 309 | #define QPHY_V3_PCS_MISC_CLAMP_ENABLE 0x0c |
| 310 | #define QPHY_V3_PCS_MISC_OSC_DTCT_CONFIG2 0x2c | ||
| 311 | #define QPHY_V3_PCS_MISC_PCIE_INT_AUX_CLK_CONFIG1 0x44 | ||
| 312 | #define QPHY_V3_PCS_MISC_OSC_DTCT_MODE2_CONFIG2 0x54 | ||
| 313 | #define QPHY_V3_PCS_MISC_OSC_DTCT_MODE2_CONFIG4 0x5c | ||
| 314 | #define QPHY_V3_PCS_MISC_OSC_DTCT_MODE2_CONFIG5 0x60 | ||
| 303 | 315 | ||
| 304 | #endif | 316 | #endif |
diff --git a/drivers/phy/qualcomm/phy-qcom-qusb2.c b/drivers/phy/qualcomm/phy-qcom-qusb2.c index 8fd7ce139772..1cbf1d6f28ce 100644 --- a/drivers/phy/qualcomm/phy-qcom-qusb2.c +++ b/drivers/phy/qualcomm/phy-qcom-qusb2.c | |||
| @@ -822,14 +822,9 @@ static int qusb2_phy_probe(struct platform_device *pdev) | |||
| 822 | return ret; | 822 | return ret; |
| 823 | } | 823 | } |
| 824 | 824 | ||
| 825 | qphy->iface_clk = devm_clk_get(dev, "iface"); | 825 | qphy->iface_clk = devm_clk_get_optional(dev, "iface"); |
| 826 | if (IS_ERR(qphy->iface_clk)) { | 826 | if (IS_ERR(qphy->iface_clk)) |
| 827 | ret = PTR_ERR(qphy->iface_clk); | 827 | return PTR_ERR(qphy->iface_clk); |
| 828 | if (ret == -EPROBE_DEFER) | ||
| 829 | return ret; | ||
| 830 | qphy->iface_clk = NULL; | ||
| 831 | dev_dbg(dev, "failed to get iface clk, %d\n", ret); | ||
| 832 | } | ||
| 833 | 828 | ||
| 834 | qphy->phy_reset = devm_reset_control_get_by_index(&pdev->dev, 0); | 829 | qphy->phy_reset = devm_reset_control_get_by_index(&pdev->dev, 0); |
| 835 | if (IS_ERR(qphy->phy_reset)) { | 830 | if (IS_ERR(qphy->phy_reset)) { |
diff --git a/drivers/phy/qualcomm/phy-qcom-ufs-i.h b/drivers/phy/qualcomm/phy-qcom-ufs-i.h index f798fb64de94..109ddd67be82 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs-i.h +++ b/drivers/phy/qualcomm/phy-qcom-ufs-i.h | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include <linux/clk.h> | 19 | #include <linux/clk.h> |
| 20 | #include <linux/phy/phy.h> | 20 | #include <linux/phy/phy.h> |
| 21 | #include <linux/regulator/consumer.h> | 21 | #include <linux/regulator/consumer.h> |
| 22 | #include <linux/reset.h> | ||
| 22 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
| 23 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
| 24 | #include <linux/io.h> | 25 | #include <linux/io.h> |
| @@ -96,11 +97,10 @@ struct ufs_qcom_phy { | |||
| 96 | char name[UFS_QCOM_PHY_NAME_LEN]; | 97 | char name[UFS_QCOM_PHY_NAME_LEN]; |
| 97 | struct ufs_qcom_phy_calibration *cached_regs; | 98 | struct ufs_qcom_phy_calibration *cached_regs; |
| 98 | int cached_regs_table_size; | 99 | int cached_regs_table_size; |
| 99 | bool is_powered_on; | ||
| 100 | bool is_started; | ||
| 101 | struct ufs_qcom_phy_specific_ops *phy_spec_ops; | 100 | struct ufs_qcom_phy_specific_ops *phy_spec_ops; |
| 102 | 101 | ||
| 103 | enum phy_mode mode; | 102 | enum phy_mode mode; |
| 103 | struct reset_control *ufs_reset; | ||
| 104 | }; | 104 | }; |
| 105 | 105 | ||
| 106 | /** | 106 | /** |
| @@ -115,6 +115,7 @@ struct ufs_qcom_phy { | |||
| 115 | * and writes to QSERDES_RX_SIGDET_CNTRL attribute | 115 | * and writes to QSERDES_RX_SIGDET_CNTRL attribute |
| 116 | */ | 116 | */ |
| 117 | struct ufs_qcom_phy_specific_ops { | 117 | struct ufs_qcom_phy_specific_ops { |
| 118 | int (*calibrate)(struct ufs_qcom_phy *ufs_qcom_phy, bool is_rate_B); | ||
| 118 | void (*start_serdes)(struct ufs_qcom_phy *phy); | 119 | void (*start_serdes)(struct ufs_qcom_phy *phy); |
| 119 | int (*is_physical_coding_sublayer_ready)(struct ufs_qcom_phy *phy); | 120 | int (*is_physical_coding_sublayer_ready)(struct ufs_qcom_phy *phy); |
| 120 | void (*set_tx_lane_enable)(struct ufs_qcom_phy *phy, u32 val); | 121 | void (*set_tx_lane_enable)(struct ufs_qcom_phy *phy, u32 val); |
diff --git a/drivers/phy/qualcomm/phy-qcom-ufs-qmp-14nm.c b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-14nm.c index 1e0d4f2046a4..4815546f228c 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs-qmp-14nm.c +++ b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-14nm.c | |||
| @@ -42,28 +42,6 @@ void ufs_qcom_phy_qmp_14nm_advertise_quirks(struct ufs_qcom_phy *phy_common) | |||
| 42 | UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE; | 42 | UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE; |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | static int ufs_qcom_phy_qmp_14nm_init(struct phy *generic_phy) | ||
| 46 | { | ||
| 47 | struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy); | ||
| 48 | bool is_rate_B = false; | ||
| 49 | int ret; | ||
| 50 | |||
| 51 | if (phy_common->mode == PHY_MODE_UFS_HS_B) | ||
| 52 | is_rate_B = true; | ||
| 53 | |||
| 54 | ret = ufs_qcom_phy_qmp_14nm_phy_calibrate(phy_common, is_rate_B); | ||
| 55 | if (!ret) | ||
| 56 | /* phy calibrated, but yet to be started */ | ||
| 57 | phy_common->is_started = false; | ||
| 58 | |||
| 59 | return ret; | ||
| 60 | } | ||
| 61 | |||
| 62 | static int ufs_qcom_phy_qmp_14nm_exit(struct phy *generic_phy) | ||
| 63 | { | ||
| 64 | return 0; | ||
| 65 | } | ||
| 66 | |||
| 67 | static | 45 | static |
| 68 | int ufs_qcom_phy_qmp_14nm_set_mode(struct phy *generic_phy, | 46 | int ufs_qcom_phy_qmp_14nm_set_mode(struct phy *generic_phy, |
| 69 | enum phy_mode mode, int submode) | 47 | enum phy_mode mode, int submode) |
| @@ -124,8 +102,6 @@ static int ufs_qcom_phy_qmp_14nm_is_pcs_ready(struct ufs_qcom_phy *phy_common) | |||
| 124 | } | 102 | } |
| 125 | 103 | ||
| 126 | static const struct phy_ops ufs_qcom_phy_qmp_14nm_phy_ops = { | 104 | static const struct phy_ops ufs_qcom_phy_qmp_14nm_phy_ops = { |
| 127 | .init = ufs_qcom_phy_qmp_14nm_init, | ||
| 128 | .exit = ufs_qcom_phy_qmp_14nm_exit, | ||
| 129 | .power_on = ufs_qcom_phy_power_on, | 105 | .power_on = ufs_qcom_phy_power_on, |
| 130 | .power_off = ufs_qcom_phy_power_off, | 106 | .power_off = ufs_qcom_phy_power_off, |
| 131 | .set_mode = ufs_qcom_phy_qmp_14nm_set_mode, | 107 | .set_mode = ufs_qcom_phy_qmp_14nm_set_mode, |
| @@ -133,6 +109,7 @@ static const struct phy_ops ufs_qcom_phy_qmp_14nm_phy_ops = { | |||
| 133 | }; | 109 | }; |
| 134 | 110 | ||
| 135 | static struct ufs_qcom_phy_specific_ops phy_14nm_ops = { | 111 | static struct ufs_qcom_phy_specific_ops phy_14nm_ops = { |
| 112 | .calibrate = ufs_qcom_phy_qmp_14nm_phy_calibrate, | ||
| 136 | .start_serdes = ufs_qcom_phy_qmp_14nm_start_serdes, | 113 | .start_serdes = ufs_qcom_phy_qmp_14nm_start_serdes, |
| 137 | .is_physical_coding_sublayer_ready = ufs_qcom_phy_qmp_14nm_is_pcs_ready, | 114 | .is_physical_coding_sublayer_ready = ufs_qcom_phy_qmp_14nm_is_pcs_ready, |
| 138 | .set_tx_lane_enable = ufs_qcom_phy_qmp_14nm_set_tx_lane_enable, | 115 | .set_tx_lane_enable = ufs_qcom_phy_qmp_14nm_set_tx_lane_enable, |
diff --git a/drivers/phy/qualcomm/phy-qcom-ufs-qmp-20nm.c b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-20nm.c index aef40f7a41d4..f1cf819e12ea 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs-qmp-20nm.c +++ b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-20nm.c | |||
| @@ -61,28 +61,6 @@ void ufs_qcom_phy_qmp_20nm_advertise_quirks(struct ufs_qcom_phy *phy_common) | |||
| 61 | UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE; | 61 | UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE; |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | static int ufs_qcom_phy_qmp_20nm_init(struct phy *generic_phy) | ||
| 65 | { | ||
| 66 | struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy); | ||
| 67 | bool is_rate_B = false; | ||
| 68 | int ret; | ||
| 69 | |||
| 70 | if (phy_common->mode == PHY_MODE_UFS_HS_B) | ||
| 71 | is_rate_B = true; | ||
| 72 | |||
| 73 | ret = ufs_qcom_phy_qmp_20nm_phy_calibrate(phy_common, is_rate_B); | ||
| 74 | if (!ret) | ||
| 75 | /* phy calibrated, but yet to be started */ | ||
| 76 | phy_common->is_started = false; | ||
| 77 | |||
| 78 | return ret; | ||
| 79 | } | ||
| 80 | |||
| 81 | static int ufs_qcom_phy_qmp_20nm_exit(struct phy *generic_phy) | ||
| 82 | { | ||
| 83 | return 0; | ||
| 84 | } | ||
| 85 | |||
| 86 | static | 64 | static |
| 87 | int ufs_qcom_phy_qmp_20nm_set_mode(struct phy *generic_phy, | 65 | int ufs_qcom_phy_qmp_20nm_set_mode(struct phy *generic_phy, |
| 88 | enum phy_mode mode, int submode) | 66 | enum phy_mode mode, int submode) |
| @@ -182,8 +160,6 @@ static int ufs_qcom_phy_qmp_20nm_is_pcs_ready(struct ufs_qcom_phy *phy_common) | |||
| 182 | } | 160 | } |
| 183 | 161 | ||
| 184 | static const struct phy_ops ufs_qcom_phy_qmp_20nm_phy_ops = { | 162 | static const struct phy_ops ufs_qcom_phy_qmp_20nm_phy_ops = { |
| 185 | .init = ufs_qcom_phy_qmp_20nm_init, | ||
| 186 | .exit = ufs_qcom_phy_qmp_20nm_exit, | ||
| 187 | .power_on = ufs_qcom_phy_power_on, | 163 | .power_on = ufs_qcom_phy_power_on, |
| 188 | .power_off = ufs_qcom_phy_power_off, | 164 | .power_off = ufs_qcom_phy_power_off, |
| 189 | .set_mode = ufs_qcom_phy_qmp_20nm_set_mode, | 165 | .set_mode = ufs_qcom_phy_qmp_20nm_set_mode, |
| @@ -191,6 +167,7 @@ static const struct phy_ops ufs_qcom_phy_qmp_20nm_phy_ops = { | |||
| 191 | }; | 167 | }; |
| 192 | 168 | ||
| 193 | static struct ufs_qcom_phy_specific_ops phy_20nm_ops = { | 169 | static struct ufs_qcom_phy_specific_ops phy_20nm_ops = { |
| 170 | .calibrate = ufs_qcom_phy_qmp_20nm_phy_calibrate, | ||
| 194 | .start_serdes = ufs_qcom_phy_qmp_20nm_start_serdes, | 171 | .start_serdes = ufs_qcom_phy_qmp_20nm_start_serdes, |
| 195 | .is_physical_coding_sublayer_ready = ufs_qcom_phy_qmp_20nm_is_pcs_ready, | 172 | .is_physical_coding_sublayer_ready = ufs_qcom_phy_qmp_20nm_is_pcs_ready, |
| 196 | .set_tx_lane_enable = ufs_qcom_phy_qmp_20nm_set_tx_lane_enable, | 173 | .set_tx_lane_enable = ufs_qcom_phy_qmp_20nm_set_tx_lane_enable, |
diff --git a/drivers/phy/qualcomm/phy-qcom-ufs.c b/drivers/phy/qualcomm/phy-qcom-ufs.c index 78c339b2fc8b..45404e31e672 100644 --- a/drivers/phy/qualcomm/phy-qcom-ufs.c +++ b/drivers/phy/qualcomm/phy-qcom-ufs.c | |||
| @@ -147,6 +147,21 @@ out: | |||
| 147 | } | 147 | } |
| 148 | EXPORT_SYMBOL_GPL(ufs_qcom_phy_generic_probe); | 148 | EXPORT_SYMBOL_GPL(ufs_qcom_phy_generic_probe); |
| 149 | 149 | ||
| 150 | static int ufs_qcom_phy_get_reset(struct ufs_qcom_phy *phy_common) | ||
| 151 | { | ||
| 152 | struct reset_control *reset; | ||
| 153 | |||
| 154 | if (phy_common->ufs_reset) | ||
| 155 | return 0; | ||
| 156 | |||
| 157 | reset = devm_reset_control_get_exclusive_by_index(phy_common->dev, 0); | ||
| 158 | if (IS_ERR(reset)) | ||
| 159 | return PTR_ERR(reset); | ||
| 160 | |||
| 161 | phy_common->ufs_reset = reset; | ||
| 162 | return 0; | ||
| 163 | } | ||
| 164 | |||
| 150 | static int __ufs_qcom_phy_clk_get(struct device *dev, | 165 | static int __ufs_qcom_phy_clk_get(struct device *dev, |
| 151 | const char *name, struct clk **clk_out, bool err_print) | 166 | const char *name, struct clk **clk_out, bool err_print) |
| 152 | { | 167 | { |
| @@ -528,23 +543,38 @@ int ufs_qcom_phy_power_on(struct phy *generic_phy) | |||
| 528 | { | 543 | { |
| 529 | struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy); | 544 | struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy); |
| 530 | struct device *dev = phy_common->dev; | 545 | struct device *dev = phy_common->dev; |
| 546 | bool is_rate_B = false; | ||
| 531 | int err; | 547 | int err; |
| 532 | 548 | ||
| 533 | if (phy_common->is_powered_on) | 549 | err = ufs_qcom_phy_get_reset(phy_common); |
| 534 | return 0; | 550 | if (err) |
| 551 | return err; | ||
| 535 | 552 | ||
| 536 | if (!phy_common->is_started) { | 553 | err = reset_control_assert(phy_common->ufs_reset); |
| 537 | err = ufs_qcom_phy_start_serdes(phy_common); | 554 | if (err) |
| 538 | if (err) | 555 | return err; |
| 539 | return err; | ||
| 540 | 556 | ||
| 541 | err = ufs_qcom_phy_is_pcs_ready(phy_common); | 557 | if (phy_common->mode == PHY_MODE_UFS_HS_B) |
| 542 | if (err) | 558 | is_rate_B = true; |
| 543 | return err; | ||
| 544 | 559 | ||
| 545 | phy_common->is_started = true; | 560 | err = phy_common->phy_spec_ops->calibrate(phy_common, is_rate_B); |
| 561 | if (err) | ||
| 562 | return err; | ||
| 563 | |||
| 564 | err = reset_control_deassert(phy_common->ufs_reset); | ||
| 565 | if (err) { | ||
| 566 | dev_err(dev, "Failed to assert UFS PHY reset"); | ||
| 567 | return err; | ||
| 546 | } | 568 | } |
| 547 | 569 | ||
| 570 | err = ufs_qcom_phy_start_serdes(phy_common); | ||
| 571 | if (err) | ||
| 572 | return err; | ||
| 573 | |||
| 574 | err = ufs_qcom_phy_is_pcs_ready(phy_common); | ||
| 575 | if (err) | ||
| 576 | return err; | ||
| 577 | |||
| 548 | err = ufs_qcom_phy_enable_vreg(dev, &phy_common->vdda_phy); | 578 | err = ufs_qcom_phy_enable_vreg(dev, &phy_common->vdda_phy); |
| 549 | if (err) { | 579 | if (err) { |
| 550 | dev_err(dev, "%s enable vdda_phy failed, err=%d\n", | 580 | dev_err(dev, "%s enable vdda_phy failed, err=%d\n", |
| @@ -587,7 +617,6 @@ int ufs_qcom_phy_power_on(struct phy *generic_phy) | |||
| 587 | } | 617 | } |
| 588 | } | 618 | } |
| 589 | 619 | ||
| 590 | phy_common->is_powered_on = true; | ||
| 591 | goto out; | 620 | goto out; |
| 592 | 621 | ||
| 593 | out_disable_ref_clk: | 622 | out_disable_ref_clk: |
| @@ -607,9 +636,6 @@ int ufs_qcom_phy_power_off(struct phy *generic_phy) | |||
| 607 | { | 636 | { |
| 608 | struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy); | 637 | struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy); |
| 609 | 638 | ||
| 610 | if (!phy_common->is_powered_on) | ||
| 611 | return 0; | ||
| 612 | |||
| 613 | phy_common->phy_spec_ops->power_control(phy_common, false); | 639 | phy_common->phy_spec_ops->power_control(phy_common, false); |
| 614 | 640 | ||
| 615 | if (phy_common->vddp_ref_clk.reg) | 641 | if (phy_common->vddp_ref_clk.reg) |
| @@ -620,8 +646,7 @@ int ufs_qcom_phy_power_off(struct phy *generic_phy) | |||
| 620 | 646 | ||
| 621 | ufs_qcom_phy_disable_vreg(phy_common->dev, &phy_common->vdda_pll); | 647 | ufs_qcom_phy_disable_vreg(phy_common->dev, &phy_common->vdda_pll); |
| 622 | ufs_qcom_phy_disable_vreg(phy_common->dev, &phy_common->vdda_phy); | 648 | ufs_qcom_phy_disable_vreg(phy_common->dev, &phy_common->vdda_phy); |
| 623 | phy_common->is_powered_on = false; | 649 | reset_control_assert(phy_common->ufs_reset); |
| 624 | |||
| 625 | return 0; | 650 | return 0; |
| 626 | } | 651 | } |
| 627 | EXPORT_SYMBOL_GPL(ufs_qcom_phy_power_off); | 652 | EXPORT_SYMBOL_GPL(ufs_qcom_phy_power_off); |
diff --git a/drivers/phy/renesas/Kconfig b/drivers/phy/renesas/Kconfig index e340a925bbb1..111bdcae775c 100644 --- a/drivers/phy/renesas/Kconfig +++ b/drivers/phy/renesas/Kconfig | |||
| @@ -19,7 +19,7 @@ config PHY_RCAR_GEN3_PCIE | |||
| 19 | config PHY_RCAR_GEN3_USB2 | 19 | config PHY_RCAR_GEN3_USB2 |
| 20 | tristate "Renesas R-Car generation 3 USB 2.0 PHY driver" | 20 | tristate "Renesas R-Car generation 3 USB 2.0 PHY driver" |
| 21 | depends on ARCH_RENESAS | 21 | depends on ARCH_RENESAS |
| 22 | depends on EXTCON | 22 | depends on EXTCON || !EXTCON # if EXTCON=m, this cannot be built-in |
| 23 | depends on USB_SUPPORT | 23 | depends on USB_SUPPORT |
| 24 | select GENERIC_PHY | 24 | select GENERIC_PHY |
| 25 | select USB_COMMON | 25 | select USB_COMMON |
diff --git a/drivers/phy/renesas/phy-rcar-gen2.c b/drivers/phy/renesas/phy-rcar-gen2.c index 72eeb066912d..8dc5710d9c98 100644 --- a/drivers/phy/renesas/phy-rcar-gen2.c +++ b/drivers/phy/renesas/phy-rcar-gen2.c | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | * | 4 | * |
| 5 | * Copyright (C) 2014 Renesas Solutions Corp. | 5 | * Copyright (C) 2014 Renesas Solutions Corp. |
| 6 | * Copyright (C) 2014 Cogent Embedded, Inc. | 6 | * Copyright (C) 2014 Cogent Embedded, Inc. |
| 7 | * Copyright (C) 2019 Renesas Electronics Corp. | ||
| 7 | */ | 8 | */ |
| 8 | 9 | ||
| 9 | #include <linux/clk.h> | 10 | #include <linux/clk.h> |
| @@ -15,6 +16,7 @@ | |||
| 15 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
| 16 | #include <linux/spinlock.h> | 17 | #include <linux/spinlock.h> |
| 17 | #include <linux/atomic.h> | 18 | #include <linux/atomic.h> |
| 19 | #include <linux/of_device.h> | ||
| 18 | 20 | ||
| 19 | #define USBHS_LPSTS 0x02 | 21 | #define USBHS_LPSTS 0x02 |
| 20 | #define USBHS_UGCTRL 0x80 | 22 | #define USBHS_UGCTRL 0x80 |
| @@ -35,6 +37,8 @@ | |||
| 35 | #define USBHS_UGCTRL2_USB0SEL 0x00000030 | 37 | #define USBHS_UGCTRL2_USB0SEL 0x00000030 |
| 36 | #define USBHS_UGCTRL2_USB0SEL_PCI 0x00000010 | 38 | #define USBHS_UGCTRL2_USB0SEL_PCI 0x00000010 |
| 37 | #define USBHS_UGCTRL2_USB0SEL_HS_USB 0x00000030 | 39 | #define USBHS_UGCTRL2_USB0SEL_HS_USB 0x00000030 |
| 40 | #define USBHS_UGCTRL2_USB0SEL_USB20 0x00000010 | ||
| 41 | #define USBHS_UGCTRL2_USB0SEL_HS_USB20 0x00000020 | ||
| 38 | 42 | ||
| 39 | /* USB General status register (UGSTS) */ | 43 | /* USB General status register (UGSTS) */ |
| 40 | #define USBHS_UGSTS_LOCK 0x00000100 /* From technical update */ | 44 | #define USBHS_UGSTS_LOCK 0x00000100 /* From technical update */ |
| @@ -64,6 +68,11 @@ struct rcar_gen2_phy_driver { | |||
| 64 | struct rcar_gen2_channel *channels; | 68 | struct rcar_gen2_channel *channels; |
| 65 | }; | 69 | }; |
| 66 | 70 | ||
| 71 | struct rcar_gen2_phy_data { | ||
| 72 | const struct phy_ops *gen2_phy_ops; | ||
| 73 | const u32 (*select_value)[PHYS_PER_CHANNEL]; | ||
| 74 | }; | ||
| 75 | |||
| 67 | static int rcar_gen2_phy_init(struct phy *p) | 76 | static int rcar_gen2_phy_init(struct phy *p) |
| 68 | { | 77 | { |
| 69 | struct rcar_gen2_phy *phy = phy_get_drvdata(p); | 78 | struct rcar_gen2_phy *phy = phy_get_drvdata(p); |
| @@ -180,6 +189,60 @@ static int rcar_gen2_phy_power_off(struct phy *p) | |||
| 180 | return 0; | 189 | return 0; |
| 181 | } | 190 | } |
| 182 | 191 | ||
| 192 | static int rz_g1c_phy_power_on(struct phy *p) | ||
| 193 | { | ||
| 194 | struct rcar_gen2_phy *phy = phy_get_drvdata(p); | ||
| 195 | struct rcar_gen2_phy_driver *drv = phy->channel->drv; | ||
| 196 | void __iomem *base = drv->base; | ||
| 197 | unsigned long flags; | ||
| 198 | u32 value; | ||
| 199 | |||
| 200 | spin_lock_irqsave(&drv->lock, flags); | ||
| 201 | |||
| 202 | /* Power on USBHS PHY */ | ||
| 203 | value = readl(base + USBHS_UGCTRL); | ||
| 204 | value &= ~USBHS_UGCTRL_PLLRESET; | ||
| 205 | writel(value, base + USBHS_UGCTRL); | ||
| 206 | |||
| 207 | /* As per the data sheet wait 340 micro sec for power stable */ | ||
| 208 | udelay(340); | ||
| 209 | |||
| 210 | if (phy->select_value == USBHS_UGCTRL2_USB0SEL_HS_USB20) { | ||
| 211 | value = readw(base + USBHS_LPSTS); | ||
| 212 | value |= USBHS_LPSTS_SUSPM; | ||
| 213 | writew(value, base + USBHS_LPSTS); | ||
| 214 | } | ||
| 215 | |||
| 216 | spin_unlock_irqrestore(&drv->lock, flags); | ||
| 217 | |||
| 218 | return 0; | ||
| 219 | } | ||
| 220 | |||
| 221 | static int rz_g1c_phy_power_off(struct phy *p) | ||
| 222 | { | ||
| 223 | struct rcar_gen2_phy *phy = phy_get_drvdata(p); | ||
| 224 | struct rcar_gen2_phy_driver *drv = phy->channel->drv; | ||
| 225 | void __iomem *base = drv->base; | ||
| 226 | unsigned long flags; | ||
| 227 | u32 value; | ||
| 228 | |||
| 229 | spin_lock_irqsave(&drv->lock, flags); | ||
| 230 | /* Power off USBHS PHY */ | ||
| 231 | if (phy->select_value == USBHS_UGCTRL2_USB0SEL_HS_USB20) { | ||
| 232 | value = readw(base + USBHS_LPSTS); | ||
| 233 | value &= ~USBHS_LPSTS_SUSPM; | ||
| 234 | writew(value, base + USBHS_LPSTS); | ||
| 235 | } | ||
| 236 | |||
| 237 | value = readl(base + USBHS_UGCTRL); | ||
| 238 | value |= USBHS_UGCTRL_PLLRESET; | ||
| 239 | writel(value, base + USBHS_UGCTRL); | ||
| 240 | |||
| 241 | spin_unlock_irqrestore(&drv->lock, flags); | ||
| 242 | |||
| 243 | return 0; | ||
| 244 | } | ||
| 245 | |||
| 183 | static const struct phy_ops rcar_gen2_phy_ops = { | 246 | static const struct phy_ops rcar_gen2_phy_ops = { |
| 184 | .init = rcar_gen2_phy_init, | 247 | .init = rcar_gen2_phy_init, |
| 185 | .exit = rcar_gen2_phy_exit, | 248 | .exit = rcar_gen2_phy_exit, |
| @@ -188,12 +251,55 @@ static const struct phy_ops rcar_gen2_phy_ops = { | |||
| 188 | .owner = THIS_MODULE, | 251 | .owner = THIS_MODULE, |
| 189 | }; | 252 | }; |
| 190 | 253 | ||
| 254 | static const struct phy_ops rz_g1c_phy_ops = { | ||
| 255 | .init = rcar_gen2_phy_init, | ||
| 256 | .exit = rcar_gen2_phy_exit, | ||
| 257 | .power_on = rz_g1c_phy_power_on, | ||
| 258 | .power_off = rz_g1c_phy_power_off, | ||
| 259 | .owner = THIS_MODULE, | ||
| 260 | }; | ||
| 261 | |||
| 262 | static const u32 pci_select_value[][PHYS_PER_CHANNEL] = { | ||
| 263 | [0] = { USBHS_UGCTRL2_USB0SEL_PCI, USBHS_UGCTRL2_USB0SEL_HS_USB }, | ||
| 264 | [2] = { USBHS_UGCTRL2_USB2SEL_PCI, USBHS_UGCTRL2_USB2SEL_USB30 }, | ||
| 265 | }; | ||
| 266 | |||
| 267 | static const u32 usb20_select_value[][PHYS_PER_CHANNEL] = { | ||
| 268 | { USBHS_UGCTRL2_USB0SEL_USB20, USBHS_UGCTRL2_USB0SEL_HS_USB20 }, | ||
| 269 | }; | ||
| 270 | |||
| 271 | static const struct rcar_gen2_phy_data rcar_gen2_usb_phy_data = { | ||
| 272 | .gen2_phy_ops = &rcar_gen2_phy_ops, | ||
| 273 | .select_value = pci_select_value, | ||
| 274 | }; | ||
| 275 | |||
| 276 | static const struct rcar_gen2_phy_data rz_g1c_usb_phy_data = { | ||
| 277 | .gen2_phy_ops = &rz_g1c_phy_ops, | ||
| 278 | .select_value = usb20_select_value, | ||
| 279 | }; | ||
| 280 | |||
| 191 | static const struct of_device_id rcar_gen2_phy_match_table[] = { | 281 | static const struct of_device_id rcar_gen2_phy_match_table[] = { |
| 192 | { .compatible = "renesas,usb-phy-r8a7790" }, | 282 | { |
| 193 | { .compatible = "renesas,usb-phy-r8a7791" }, | 283 | .compatible = "renesas,usb-phy-r8a77470", |
| 194 | { .compatible = "renesas,usb-phy-r8a7794" }, | 284 | .data = &rz_g1c_usb_phy_data, |
| 195 | { .compatible = "renesas,rcar-gen2-usb-phy" }, | 285 | }, |
| 196 | { } | 286 | { |
| 287 | .compatible = "renesas,usb-phy-r8a7790", | ||
| 288 | .data = &rcar_gen2_usb_phy_data, | ||
| 289 | }, | ||
| 290 | { | ||
| 291 | .compatible = "renesas,usb-phy-r8a7791", | ||
| 292 | .data = &rcar_gen2_usb_phy_data, | ||
| 293 | }, | ||
| 294 | { | ||
| 295 | .compatible = "renesas,usb-phy-r8a7794", | ||
| 296 | .data = &rcar_gen2_usb_phy_data, | ||
| 297 | }, | ||
| 298 | { | ||
| 299 | .compatible = "renesas,rcar-gen2-usb-phy", | ||
| 300 | .data = &rcar_gen2_usb_phy_data, | ||
| 301 | }, | ||
| 302 | { /* sentinel */ }, | ||
| 197 | }; | 303 | }; |
| 198 | MODULE_DEVICE_TABLE(of, rcar_gen2_phy_match_table); | 304 | MODULE_DEVICE_TABLE(of, rcar_gen2_phy_match_table); |
| 199 | 305 | ||
| @@ -224,11 +330,6 @@ static const u32 select_mask[] = { | |||
| 224 | [2] = USBHS_UGCTRL2_USB2SEL, | 330 | [2] = USBHS_UGCTRL2_USB2SEL, |
| 225 | }; | 331 | }; |
| 226 | 332 | ||
| 227 | static const u32 select_value[][PHYS_PER_CHANNEL] = { | ||
| 228 | [0] = { USBHS_UGCTRL2_USB0SEL_PCI, USBHS_UGCTRL2_USB0SEL_HS_USB }, | ||
| 229 | [2] = { USBHS_UGCTRL2_USB2SEL_PCI, USBHS_UGCTRL2_USB2SEL_USB30 }, | ||
| 230 | }; | ||
| 231 | |||
| 232 | static int rcar_gen2_phy_probe(struct platform_device *pdev) | 333 | static int rcar_gen2_phy_probe(struct platform_device *pdev) |
| 233 | { | 334 | { |
| 234 | struct device *dev = &pdev->dev; | 335 | struct device *dev = &pdev->dev; |
| @@ -238,6 +339,7 @@ static int rcar_gen2_phy_probe(struct platform_device *pdev) | |||
| 238 | struct resource *res; | 339 | struct resource *res; |
| 239 | void __iomem *base; | 340 | void __iomem *base; |
| 240 | struct clk *clk; | 341 | struct clk *clk; |
| 342 | const struct rcar_gen2_phy_data *data; | ||
| 241 | int i = 0; | 343 | int i = 0; |
| 242 | 344 | ||
| 243 | if (!dev->of_node) { | 345 | if (!dev->of_node) { |
| @@ -266,6 +368,10 @@ static int rcar_gen2_phy_probe(struct platform_device *pdev) | |||
| 266 | drv->clk = clk; | 368 | drv->clk = clk; |
| 267 | drv->base = base; | 369 | drv->base = base; |
| 268 | 370 | ||
| 371 | data = of_device_get_match_data(dev); | ||
| 372 | if (!data) | ||
| 373 | return -EINVAL; | ||
| 374 | |||
| 269 | drv->num_channels = of_get_child_count(dev->of_node); | 375 | drv->num_channels = of_get_child_count(dev->of_node); |
| 270 | drv->channels = devm_kcalloc(dev, drv->num_channels, | 376 | drv->channels = devm_kcalloc(dev, drv->num_channels, |
| 271 | sizeof(struct rcar_gen2_channel), | 377 | sizeof(struct rcar_gen2_channel), |
| @@ -294,10 +400,10 @@ static int rcar_gen2_phy_probe(struct platform_device *pdev) | |||
| 294 | 400 | ||
| 295 | phy->channel = channel; | 401 | phy->channel = channel; |
| 296 | phy->number = n; | 402 | phy->number = n; |
| 297 | phy->select_value = select_value[channel_num][n]; | 403 | phy->select_value = data->select_value[channel_num][n]; |
| 298 | 404 | ||
| 299 | phy->phy = devm_phy_create(dev, NULL, | 405 | phy->phy = devm_phy_create(dev, NULL, |
| 300 | &rcar_gen2_phy_ops); | 406 | data->gen2_phy_ops); |
| 301 | if (IS_ERR(phy->phy)) { | 407 | if (IS_ERR(phy->phy)) { |
| 302 | dev_err(dev, "Failed to create PHY\n"); | 408 | dev_err(dev, "Failed to create PHY\n"); |
| 303 | return PTR_ERR(phy->phy); | 409 | return PTR_ERR(phy->phy); |
diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c index 0a34782aaaa2..1322185a00a2 100644 --- a/drivers/phy/renesas/phy-rcar-gen3-usb2.c +++ b/drivers/phy/renesas/phy-rcar-gen3-usb2.c | |||
| @@ -37,11 +37,8 @@ | |||
| 37 | 37 | ||
| 38 | /* INT_ENABLE */ | 38 | /* INT_ENABLE */ |
| 39 | #define USB2_INT_ENABLE_UCOM_INTEN BIT(3) | 39 | #define USB2_INT_ENABLE_UCOM_INTEN BIT(3) |
| 40 | #define USB2_INT_ENABLE_USBH_INTB_EN BIT(2) | 40 | #define USB2_INT_ENABLE_USBH_INTB_EN BIT(2) /* For EHCI */ |
| 41 | #define USB2_INT_ENABLE_USBH_INTA_EN BIT(1) | 41 | #define USB2_INT_ENABLE_USBH_INTA_EN BIT(1) /* For OHCI */ |
| 42 | #define USB2_INT_ENABLE_INIT (USB2_INT_ENABLE_UCOM_INTEN | \ | ||
| 43 | USB2_INT_ENABLE_USBH_INTB_EN | \ | ||
| 44 | USB2_INT_ENABLE_USBH_INTA_EN) | ||
| 45 | 42 | ||
| 46 | /* USBCTR */ | 43 | /* USBCTR */ |
| 47 | #define USB2_USBCTR_DIRPD BIT(2) | 44 | #define USB2_USBCTR_DIRPD BIT(2) |
| @@ -78,10 +75,35 @@ | |||
| 78 | #define USB2_ADPCTRL_IDPULLUP BIT(5) /* 1 = ID sampling is enabled */ | 75 | #define USB2_ADPCTRL_IDPULLUP BIT(5) /* 1 = ID sampling is enabled */ |
| 79 | #define USB2_ADPCTRL_DRVVBUS BIT(4) | 76 | #define USB2_ADPCTRL_DRVVBUS BIT(4) |
| 80 | 77 | ||
| 78 | #define NUM_OF_PHYS 4 | ||
| 79 | enum rcar_gen3_phy_index { | ||
| 80 | PHY_INDEX_BOTH_HC, | ||
| 81 | PHY_INDEX_OHCI, | ||
| 82 | PHY_INDEX_EHCI, | ||
| 83 | PHY_INDEX_HSUSB | ||
| 84 | }; | ||
| 85 | |||
| 86 | static const u32 rcar_gen3_int_enable[NUM_OF_PHYS] = { | ||
| 87 | USB2_INT_ENABLE_USBH_INTB_EN | USB2_INT_ENABLE_USBH_INTA_EN, | ||
| 88 | USB2_INT_ENABLE_USBH_INTA_EN, | ||
| 89 | USB2_INT_ENABLE_USBH_INTB_EN, | ||
| 90 | 0 | ||
| 91 | }; | ||
| 92 | |||
| 93 | struct rcar_gen3_phy { | ||
| 94 | struct phy *phy; | ||
| 95 | struct rcar_gen3_chan *ch; | ||
| 96 | u32 int_enable_bits; | ||
| 97 | bool initialized; | ||
| 98 | bool otg_initialized; | ||
| 99 | bool powered; | ||
| 100 | }; | ||
| 101 | |||
| 81 | struct rcar_gen3_chan { | 102 | struct rcar_gen3_chan { |
| 82 | void __iomem *base; | 103 | void __iomem *base; |
| 104 | struct device *dev; /* platform_device's device */ | ||
| 83 | struct extcon_dev *extcon; | 105 | struct extcon_dev *extcon; |
| 84 | struct phy *phy; | 106 | struct rcar_gen3_phy rphys[NUM_OF_PHYS]; |
| 85 | struct regulator *vbus; | 107 | struct regulator *vbus; |
| 86 | struct work_struct work; | 108 | struct work_struct work; |
| 87 | enum usb_dr_mode dr_mode; | 109 | enum usb_dr_mode dr_mode; |
| @@ -120,7 +142,7 @@ static void rcar_gen3_set_host_mode(struct rcar_gen3_chan *ch, int host) | |||
| 120 | void __iomem *usb2_base = ch->base; | 142 | void __iomem *usb2_base = ch->base; |
| 121 | u32 val = readl(usb2_base + USB2_COMMCTRL); | 143 | u32 val = readl(usb2_base + USB2_COMMCTRL); |
| 122 | 144 | ||
| 123 | dev_vdbg(&ch->phy->dev, "%s: %08x, %d\n", __func__, val, host); | 145 | dev_vdbg(ch->dev, "%s: %08x, %d\n", __func__, val, host); |
| 124 | if (host) | 146 | if (host) |
| 125 | val &= ~USB2_COMMCTRL_OTG_PERI; | 147 | val &= ~USB2_COMMCTRL_OTG_PERI; |
| 126 | else | 148 | else |
| @@ -133,7 +155,7 @@ static void rcar_gen3_set_linectrl(struct rcar_gen3_chan *ch, int dp, int dm) | |||
| 133 | void __iomem *usb2_base = ch->base; | 155 | void __iomem *usb2_base = ch->base; |
| 134 | u32 val = readl(usb2_base + USB2_LINECTRL1); | 156 | u32 val = readl(usb2_base + USB2_LINECTRL1); |
| 135 | 157 | ||
| 136 | dev_vdbg(&ch->phy->dev, "%s: %08x, %d, %d\n", __func__, val, dp, dm); | 158 | dev_vdbg(ch->dev, "%s: %08x, %d, %d\n", __func__, val, dp, dm); |
| 137 | val &= ~(USB2_LINECTRL1_DP_RPD | USB2_LINECTRL1_DM_RPD); | 159 | val &= ~(USB2_LINECTRL1_DP_RPD | USB2_LINECTRL1_DM_RPD); |
| 138 | if (dp) | 160 | if (dp) |
| 139 | val |= USB2_LINECTRL1_DP_RPD; | 161 | val |= USB2_LINECTRL1_DP_RPD; |
| @@ -147,7 +169,7 @@ static void rcar_gen3_enable_vbus_ctrl(struct rcar_gen3_chan *ch, int vbus) | |||
| 147 | void __iomem *usb2_base = ch->base; | 169 | void __iomem *usb2_base = ch->base; |
| 148 | u32 val = readl(usb2_base + USB2_ADPCTRL); | 170 | u32 val = readl(usb2_base + USB2_ADPCTRL); |
| 149 | 171 | ||
| 150 | dev_vdbg(&ch->phy->dev, "%s: %08x, %d\n", __func__, val, vbus); | 172 | dev_vdbg(ch->dev, "%s: %08x, %d\n", __func__, val, vbus); |
| 151 | if (vbus) | 173 | if (vbus) |
| 152 | val |= USB2_ADPCTRL_DRVVBUS; | 174 | val |= USB2_ADPCTRL_DRVVBUS; |
| 153 | else | 175 | else |
| @@ -249,6 +271,42 @@ static enum phy_mode rcar_gen3_get_phy_mode(struct rcar_gen3_chan *ch) | |||
| 249 | return PHY_MODE_USB_DEVICE; | 271 | return PHY_MODE_USB_DEVICE; |
| 250 | } | 272 | } |
| 251 | 273 | ||
| 274 | static bool rcar_gen3_is_any_rphy_initialized(struct rcar_gen3_chan *ch) | ||
| 275 | { | ||
| 276 | int i; | ||
| 277 | |||
| 278 | for (i = 0; i < NUM_OF_PHYS; i++) { | ||
| 279 | if (ch->rphys[i].initialized) | ||
| 280 | return true; | ||
| 281 | } | ||
| 282 | |||
| 283 | return false; | ||
| 284 | } | ||
| 285 | |||
| 286 | static bool rcar_gen3_needs_init_otg(struct rcar_gen3_chan *ch) | ||
| 287 | { | ||
| 288 | int i; | ||
| 289 | |||
| 290 | for (i = 0; i < NUM_OF_PHYS; i++) { | ||
| 291 | if (ch->rphys[i].otg_initialized) | ||
| 292 | return false; | ||
| 293 | } | ||
| 294 | |||
| 295 | return true; | ||
| 296 | } | ||
| 297 | |||
| 298 | static bool rcar_gen3_are_all_rphys_power_off(struct rcar_gen3_chan *ch) | ||
| 299 | { | ||
| 300 | int i; | ||
| 301 | |||
| 302 | for (i = 0; i < NUM_OF_PHYS; i++) { | ||
| 303 | if (ch->rphys[i].powered) | ||
| 304 | return false; | ||
| 305 | } | ||
| 306 | |||
| 307 | return true; | ||
| 308 | } | ||
| 309 | |||
| 252 | static ssize_t role_store(struct device *dev, struct device_attribute *attr, | 310 | static ssize_t role_store(struct device *dev, struct device_attribute *attr, |
| 253 | const char *buf, size_t count) | 311 | const char *buf, size_t count) |
| 254 | { | 312 | { |
| @@ -256,7 +314,7 @@ static ssize_t role_store(struct device *dev, struct device_attribute *attr, | |||
| 256 | bool is_b_device; | 314 | bool is_b_device; |
| 257 | enum phy_mode cur_mode, new_mode; | 315 | enum phy_mode cur_mode, new_mode; |
| 258 | 316 | ||
| 259 | if (!ch->is_otg_channel || !ch->phy->init_count) | 317 | if (!ch->is_otg_channel || !rcar_gen3_is_any_rphy_initialized(ch)) |
| 260 | return -EIO; | 318 | return -EIO; |
| 261 | 319 | ||
| 262 | if (!strncmp(buf, "host", strlen("host"))) | 320 | if (!strncmp(buf, "host", strlen("host"))) |
| @@ -294,7 +352,7 @@ static ssize_t role_show(struct device *dev, struct device_attribute *attr, | |||
| 294 | { | 352 | { |
| 295 | struct rcar_gen3_chan *ch = dev_get_drvdata(dev); | 353 | struct rcar_gen3_chan *ch = dev_get_drvdata(dev); |
| 296 | 354 | ||
| 297 | if (!ch->is_otg_channel || !ch->phy->init_count) | 355 | if (!ch->is_otg_channel || !rcar_gen3_is_any_rphy_initialized(ch)) |
| 298 | return -EIO; | 356 | return -EIO; |
| 299 | 357 | ||
| 300 | return sprintf(buf, "%s\n", rcar_gen3_is_host(ch) ? "host" : | 358 | return sprintf(buf, "%s\n", rcar_gen3_is_host(ch) ? "host" : |
| @@ -328,37 +386,62 @@ static void rcar_gen3_init_otg(struct rcar_gen3_chan *ch) | |||
| 328 | 386 | ||
| 329 | static int rcar_gen3_phy_usb2_init(struct phy *p) | 387 | static int rcar_gen3_phy_usb2_init(struct phy *p) |
| 330 | { | 388 | { |
| 331 | struct rcar_gen3_chan *channel = phy_get_drvdata(p); | 389 | struct rcar_gen3_phy *rphy = phy_get_drvdata(p); |
| 390 | struct rcar_gen3_chan *channel = rphy->ch; | ||
| 332 | void __iomem *usb2_base = channel->base; | 391 | void __iomem *usb2_base = channel->base; |
| 392 | u32 val; | ||
| 333 | 393 | ||
| 334 | /* Initialize USB2 part */ | 394 | /* Initialize USB2 part */ |
| 335 | writel(USB2_INT_ENABLE_INIT, usb2_base + USB2_INT_ENABLE); | 395 | val = readl(usb2_base + USB2_INT_ENABLE); |
| 396 | val |= USB2_INT_ENABLE_UCOM_INTEN | rphy->int_enable_bits; | ||
| 397 | writel(val, usb2_base + USB2_INT_ENABLE); | ||
| 336 | writel(USB2_SPD_RSM_TIMSET_INIT, usb2_base + USB2_SPD_RSM_TIMSET); | 398 | writel(USB2_SPD_RSM_TIMSET_INIT, usb2_base + USB2_SPD_RSM_TIMSET); |
| 337 | writel(USB2_OC_TIMSET_INIT, usb2_base + USB2_OC_TIMSET); | 399 | writel(USB2_OC_TIMSET_INIT, usb2_base + USB2_OC_TIMSET); |
| 338 | 400 | ||
| 339 | /* Initialize otg part */ | 401 | /* Initialize otg part */ |
| 340 | if (channel->is_otg_channel) | 402 | if (channel->is_otg_channel) { |
| 341 | rcar_gen3_init_otg(channel); | 403 | if (rcar_gen3_needs_init_otg(channel)) |
| 404 | rcar_gen3_init_otg(channel); | ||
| 405 | rphy->otg_initialized = true; | ||
| 406 | } | ||
| 407 | |||
| 408 | rphy->initialized = true; | ||
| 342 | 409 | ||
| 343 | return 0; | 410 | return 0; |
| 344 | } | 411 | } |
| 345 | 412 | ||
| 346 | static int rcar_gen3_phy_usb2_exit(struct phy *p) | 413 | static int rcar_gen3_phy_usb2_exit(struct phy *p) |
| 347 | { | 414 | { |
| 348 | struct rcar_gen3_chan *channel = phy_get_drvdata(p); | 415 | struct rcar_gen3_phy *rphy = phy_get_drvdata(p); |
| 416 | struct rcar_gen3_chan *channel = rphy->ch; | ||
| 417 | void __iomem *usb2_base = channel->base; | ||
| 418 | u32 val; | ||
| 419 | |||
| 420 | rphy->initialized = false; | ||
| 421 | |||
| 422 | if (channel->is_otg_channel) | ||
| 423 | rphy->otg_initialized = false; | ||
| 349 | 424 | ||
| 350 | writel(0, channel->base + USB2_INT_ENABLE); | 425 | val = readl(usb2_base + USB2_INT_ENABLE); |
| 426 | val &= ~rphy->int_enable_bits; | ||
| 427 | if (!rcar_gen3_is_any_rphy_initialized(channel)) | ||
| 428 | val &= ~USB2_INT_ENABLE_UCOM_INTEN; | ||
| 429 | writel(val, usb2_base + USB2_INT_ENABLE); | ||
| 351 | 430 | ||
| 352 | return 0; | 431 | return 0; |
| 353 | } | 432 | } |
| 354 | 433 | ||
| 355 | static int rcar_gen3_phy_usb2_power_on(struct phy *p) | 434 | static int rcar_gen3_phy_usb2_power_on(struct phy *p) |
| 356 | { | 435 | { |
| 357 | struct rcar_gen3_chan *channel = phy_get_drvdata(p); | 436 | struct rcar_gen3_phy *rphy = phy_get_drvdata(p); |
| 437 | struct rcar_gen3_chan *channel = rphy->ch; | ||
| 358 | void __iomem *usb2_base = channel->base; | 438 | void __iomem *usb2_base = channel->base; |
| 359 | u32 val; | 439 | u32 val; |
| 360 | int ret; | 440 | int ret; |
| 361 | 441 | ||
| 442 | if (!rcar_gen3_are_all_rphys_power_off(channel)) | ||
| 443 | return 0; | ||
| 444 | |||
| 362 | if (channel->vbus) { | 445 | if (channel->vbus) { |
| 363 | ret = regulator_enable(channel->vbus); | 446 | ret = regulator_enable(channel->vbus); |
| 364 | if (ret) | 447 | if (ret) |
| @@ -371,14 +454,22 @@ static int rcar_gen3_phy_usb2_power_on(struct phy *p) | |||
| 371 | val &= ~USB2_USBCTR_PLL_RST; | 454 | val &= ~USB2_USBCTR_PLL_RST; |
| 372 | writel(val, usb2_base + USB2_USBCTR); | 455 | writel(val, usb2_base + USB2_USBCTR); |
| 373 | 456 | ||
| 457 | rphy->powered = true; | ||
| 458 | |||
| 374 | return 0; | 459 | return 0; |
| 375 | } | 460 | } |
| 376 | 461 | ||
| 377 | static int rcar_gen3_phy_usb2_power_off(struct phy *p) | 462 | static int rcar_gen3_phy_usb2_power_off(struct phy *p) |
| 378 | { | 463 | { |
| 379 | struct rcar_gen3_chan *channel = phy_get_drvdata(p); | 464 | struct rcar_gen3_phy *rphy = phy_get_drvdata(p); |
| 465 | struct rcar_gen3_chan *channel = rphy->ch; | ||
| 380 | int ret = 0; | 466 | int ret = 0; |
| 381 | 467 | ||
| 468 | rphy->powered = false; | ||
| 469 | |||
| 470 | if (!rcar_gen3_are_all_rphys_power_off(channel)) | ||
| 471 | return 0; | ||
| 472 | |||
| 382 | if (channel->vbus) | 473 | if (channel->vbus) |
| 383 | ret = regulator_disable(channel->vbus); | 474 | ret = regulator_disable(channel->vbus); |
| 384 | 475 | ||
| @@ -393,6 +484,12 @@ static const struct phy_ops rcar_gen3_phy_usb2_ops = { | |||
| 393 | .owner = THIS_MODULE, | 484 | .owner = THIS_MODULE, |
| 394 | }; | 485 | }; |
| 395 | 486 | ||
| 487 | static const struct phy_ops rz_g1c_phy_usb2_ops = { | ||
| 488 | .init = rcar_gen3_phy_usb2_init, | ||
| 489 | .exit = rcar_gen3_phy_usb2_exit, | ||
| 490 | .owner = THIS_MODULE, | ||
| 491 | }; | ||
| 492 | |||
| 396 | static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) | 493 | static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) |
| 397 | { | 494 | { |
| 398 | struct rcar_gen3_chan *ch = _ch; | 495 | struct rcar_gen3_chan *ch = _ch; |
| @@ -401,7 +498,7 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) | |||
| 401 | irqreturn_t ret = IRQ_NONE; | 498 | irqreturn_t ret = IRQ_NONE; |
| 402 | 499 | ||
| 403 | if (status & USB2_OBINT_BITS) { | 500 | if (status & USB2_OBINT_BITS) { |
| 404 | dev_vdbg(&ch->phy->dev, "%s: %08x\n", __func__, status); | 501 | dev_vdbg(ch->dev, "%s: %08x\n", __func__, status); |
| 405 | writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTSTA); | 502 | writel(USB2_OBINT_BITS, usb2_base + USB2_OBINTSTA); |
| 406 | rcar_gen3_device_recognition(ch); | 503 | rcar_gen3_device_recognition(ch); |
| 407 | ret = IRQ_HANDLED; | 504 | ret = IRQ_HANDLED; |
| @@ -411,11 +508,27 @@ static irqreturn_t rcar_gen3_phy_usb2_irq(int irq, void *_ch) | |||
| 411 | } | 508 | } |
| 412 | 509 | ||
| 413 | static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = { | 510 | static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = { |
| 414 | { .compatible = "renesas,usb2-phy-r8a7795" }, | 511 | { |
| 415 | { .compatible = "renesas,usb2-phy-r8a7796" }, | 512 | .compatible = "renesas,usb2-phy-r8a77470", |
| 416 | { .compatible = "renesas,usb2-phy-r8a77965" }, | 513 | .data = &rz_g1c_phy_usb2_ops, |
| 417 | { .compatible = "renesas,rcar-gen3-usb2-phy" }, | 514 | }, |
| 418 | { } | 515 | { |
| 516 | .compatible = "renesas,usb2-phy-r8a7795", | ||
| 517 | .data = &rcar_gen3_phy_usb2_ops, | ||
| 518 | }, | ||
| 519 | { | ||
| 520 | .compatible = "renesas,usb2-phy-r8a7796", | ||
| 521 | .data = &rcar_gen3_phy_usb2_ops, | ||
| 522 | }, | ||
| 523 | { | ||
| 524 | .compatible = "renesas,usb2-phy-r8a77965", | ||
| 525 | .data = &rcar_gen3_phy_usb2_ops, | ||
| 526 | }, | ||
| 527 | { | ||
| 528 | .compatible = "renesas,rcar-gen3-usb2-phy", | ||
| 529 | .data = &rcar_gen3_phy_usb2_ops, | ||
| 530 | }, | ||
| 531 | { /* sentinel */ }, | ||
| 419 | }; | 532 | }; |
| 420 | MODULE_DEVICE_TABLE(of, rcar_gen3_phy_usb2_match_table); | 533 | MODULE_DEVICE_TABLE(of, rcar_gen3_phy_usb2_match_table); |
| 421 | 534 | ||
| @@ -425,13 +538,54 @@ static const unsigned int rcar_gen3_phy_cable[] = { | |||
| 425 | EXTCON_NONE, | 538 | EXTCON_NONE, |
| 426 | }; | 539 | }; |
| 427 | 540 | ||
| 541 | static struct phy *rcar_gen3_phy_usb2_xlate(struct device *dev, | ||
| 542 | struct of_phandle_args *args) | ||
| 543 | { | ||
| 544 | struct rcar_gen3_chan *ch = dev_get_drvdata(dev); | ||
| 545 | |||
| 546 | if (args->args_count == 0) /* For old version dts */ | ||
| 547 | return ch->rphys[PHY_INDEX_BOTH_HC].phy; | ||
| 548 | else if (args->args_count > 1) /* Prevent invalid args count */ | ||
| 549 | return ERR_PTR(-ENODEV); | ||
| 550 | |||
| 551 | if (args->args[0] >= NUM_OF_PHYS) | ||
| 552 | return ERR_PTR(-ENODEV); | ||
| 553 | |||
| 554 | return ch->rphys[args->args[0]].phy; | ||
| 555 | } | ||
| 556 | |||
| 557 | static enum usb_dr_mode rcar_gen3_get_dr_mode(struct device_node *np) | ||
| 558 | { | ||
| 559 | enum usb_dr_mode candidate = USB_DR_MODE_UNKNOWN; | ||
| 560 | int i; | ||
| 561 | |||
| 562 | /* | ||
| 563 | * If one of device nodes has other dr_mode except UNKNOWN, | ||
| 564 | * this function returns UNKNOWN. To achieve backward compatibility, | ||
| 565 | * this loop starts the index as 0. | ||
| 566 | */ | ||
| 567 | for (i = 0; i < NUM_OF_PHYS; i++) { | ||
| 568 | enum usb_dr_mode mode = of_usb_get_dr_mode_by_phy(np, i); | ||
| 569 | |||
| 570 | if (mode != USB_DR_MODE_UNKNOWN) { | ||
| 571 | if (candidate == USB_DR_MODE_UNKNOWN) | ||
| 572 | candidate = mode; | ||
| 573 | else if (candidate != mode) | ||
| 574 | return USB_DR_MODE_UNKNOWN; | ||
| 575 | } | ||
| 576 | } | ||
| 577 | |||
| 578 | return candidate; | ||
| 579 | } | ||
| 580 | |||
| 428 | static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) | 581 | static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) |
| 429 | { | 582 | { |
| 430 | struct device *dev = &pdev->dev; | 583 | struct device *dev = &pdev->dev; |
| 431 | struct rcar_gen3_chan *channel; | 584 | struct rcar_gen3_chan *channel; |
| 432 | struct phy_provider *provider; | 585 | struct phy_provider *provider; |
| 433 | struct resource *res; | 586 | struct resource *res; |
| 434 | int irq, ret = 0; | 587 | const struct phy_ops *phy_usb2_ops; |
| 588 | int irq, ret = 0, i; | ||
| 435 | 589 | ||
| 436 | if (!dev->of_node) { | 590 | if (!dev->of_node) { |
| 437 | dev_err(dev, "This driver needs device tree\n"); | 591 | dev_err(dev, "This driver needs device tree\n"); |
| @@ -457,7 +611,7 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) | |||
| 457 | dev_err(dev, "No irq handler (%d)\n", irq); | 611 | dev_err(dev, "No irq handler (%d)\n", irq); |
| 458 | } | 612 | } |
| 459 | 613 | ||
| 460 | channel->dr_mode = of_usb_get_dr_mode_by_phy(dev->of_node, 0); | 614 | channel->dr_mode = rcar_gen3_get_dr_mode(dev->of_node); |
| 461 | if (channel->dr_mode != USB_DR_MODE_UNKNOWN) { | 615 | if (channel->dr_mode != USB_DR_MODE_UNKNOWN) { |
| 462 | int ret; | 616 | int ret; |
| 463 | 617 | ||
| @@ -481,11 +635,21 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) | |||
| 481 | * And then, phy-core will manage runtime pm for this device. | 635 | * And then, phy-core will manage runtime pm for this device. |
| 482 | */ | 636 | */ |
| 483 | pm_runtime_enable(dev); | 637 | pm_runtime_enable(dev); |
| 484 | channel->phy = devm_phy_create(dev, NULL, &rcar_gen3_phy_usb2_ops); | 638 | phy_usb2_ops = of_device_get_match_data(dev); |
| 485 | if (IS_ERR(channel->phy)) { | 639 | if (!phy_usb2_ops) |
| 486 | dev_err(dev, "Failed to create USB2 PHY\n"); | 640 | return -EINVAL; |
| 487 | ret = PTR_ERR(channel->phy); | 641 | |
| 488 | goto error; | 642 | for (i = 0; i < NUM_OF_PHYS; i++) { |
| 643 | channel->rphys[i].phy = devm_phy_create(dev, NULL, | ||
| 644 | phy_usb2_ops); | ||
| 645 | if (IS_ERR(channel->rphys[i].phy)) { | ||
| 646 | dev_err(dev, "Failed to create USB2 PHY\n"); | ||
| 647 | ret = PTR_ERR(channel->rphys[i].phy); | ||
| 648 | goto error; | ||
| 649 | } | ||
| 650 | channel->rphys[i].ch = channel; | ||
| 651 | channel->rphys[i].int_enable_bits = rcar_gen3_int_enable[i]; | ||
| 652 | phy_set_drvdata(channel->rphys[i].phy, &channel->rphys[i]); | ||
| 489 | } | 653 | } |
| 490 | 654 | ||
| 491 | channel->vbus = devm_regulator_get_optional(dev, "vbus"); | 655 | channel->vbus = devm_regulator_get_optional(dev, "vbus"); |
| @@ -498,9 +662,9 @@ static int rcar_gen3_phy_usb2_probe(struct platform_device *pdev) | |||
| 498 | } | 662 | } |
| 499 | 663 | ||
| 500 | platform_set_drvdata(pdev, channel); | 664 | platform_set_drvdata(pdev, channel); |
| 501 | phy_set_drvdata(channel->phy, channel); | 665 | channel->dev = dev; |
| 502 | 666 | ||
| 503 | provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); | 667 | provider = devm_of_phy_provider_register(dev, rcar_gen3_phy_usb2_xlate); |
| 504 | if (IS_ERR(provider)) { | 668 | if (IS_ERR(provider)) { |
| 505 | dev_err(dev, "Failed to register PHY provider\n"); | 669 | dev_err(dev, "Failed to register PHY provider\n"); |
| 506 | ret = PTR_ERR(provider); | 670 | ret = PTR_ERR(provider); |
diff --git a/drivers/phy/rockchip/phy-rockchip-emmc.c b/drivers/phy/rockchip/phy-rockchip-emmc.c index 19bf84f0bc67..b804c6bf4b55 100644 --- a/drivers/phy/rockchip/phy-rockchip-emmc.c +++ b/drivers/phy/rockchip/phy-rockchip-emmc.c | |||
| @@ -87,6 +87,7 @@ struct rockchip_emmc_phy { | |||
| 87 | unsigned int reg_offset; | 87 | unsigned int reg_offset; |
| 88 | struct regmap *reg_base; | 88 | struct regmap *reg_base; |
| 89 | struct clk *emmcclk; | 89 | struct clk *emmcclk; |
| 90 | unsigned int drive_impedance; | ||
| 90 | }; | 91 | }; |
| 91 | 92 | ||
| 92 | static int rockchip_emmc_phy_power(struct phy *phy, bool on_off) | 93 | static int rockchip_emmc_phy_power(struct phy *phy, bool on_off) |
| @@ -281,10 +282,10 @@ static int rockchip_emmc_phy_power_on(struct phy *phy) | |||
| 281 | { | 282 | { |
| 282 | struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy); | 283 | struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy); |
| 283 | 284 | ||
| 284 | /* Drive impedance: 50 Ohm */ | 285 | /* Drive impedance: from DTS */ |
| 285 | regmap_write(rk_phy->reg_base, | 286 | regmap_write(rk_phy->reg_base, |
| 286 | rk_phy->reg_offset + GRF_EMMCPHY_CON6, | 287 | rk_phy->reg_offset + GRF_EMMCPHY_CON6, |
| 287 | HIWORD_UPDATE(PHYCTRL_DR_50OHM, | 288 | HIWORD_UPDATE(rk_phy->drive_impedance, |
| 288 | PHYCTRL_DR_MASK, | 289 | PHYCTRL_DR_MASK, |
| 289 | PHYCTRL_DR_SHIFT)); | 290 | PHYCTRL_DR_SHIFT)); |
| 290 | 291 | ||
| @@ -314,6 +315,26 @@ static const struct phy_ops ops = { | |||
| 314 | .owner = THIS_MODULE, | 315 | .owner = THIS_MODULE, |
| 315 | }; | 316 | }; |
| 316 | 317 | ||
| 318 | static u32 convert_drive_impedance_ohm(struct platform_device *pdev, u32 dr_ohm) | ||
| 319 | { | ||
| 320 | switch (dr_ohm) { | ||
| 321 | case 100: | ||
| 322 | return PHYCTRL_DR_100OHM; | ||
| 323 | case 66: | ||
| 324 | return PHYCTRL_DR_66OHM; | ||
| 325 | case 50: | ||
| 326 | return PHYCTRL_DR_50OHM; | ||
| 327 | case 40: | ||
| 328 | return PHYCTRL_DR_40OHM; | ||
| 329 | case 33: | ||
| 330 | return PHYCTRL_DR_33OHM; | ||
| 331 | } | ||
| 332 | |||
| 333 | dev_warn(&pdev->dev, "Invalid value %u for drive-impedance-ohm.\n", | ||
| 334 | dr_ohm); | ||
| 335 | return PHYCTRL_DR_50OHM; | ||
| 336 | } | ||
| 337 | |||
| 317 | static int rockchip_emmc_phy_probe(struct platform_device *pdev) | 338 | static int rockchip_emmc_phy_probe(struct platform_device *pdev) |
| 318 | { | 339 | { |
| 319 | struct device *dev = &pdev->dev; | 340 | struct device *dev = &pdev->dev; |
| @@ -322,6 +343,7 @@ static int rockchip_emmc_phy_probe(struct platform_device *pdev) | |||
| 322 | struct phy_provider *phy_provider; | 343 | struct phy_provider *phy_provider; |
| 323 | struct regmap *grf; | 344 | struct regmap *grf; |
| 324 | unsigned int reg_offset; | 345 | unsigned int reg_offset; |
| 346 | u32 val; | ||
| 325 | 347 | ||
| 326 | if (!dev->parent || !dev->parent->of_node) | 348 | if (!dev->parent || !dev->parent->of_node) |
| 327 | return -ENODEV; | 349 | return -ENODEV; |
| @@ -344,6 +366,10 @@ static int rockchip_emmc_phy_probe(struct platform_device *pdev) | |||
| 344 | 366 | ||
| 345 | rk_phy->reg_offset = reg_offset; | 367 | rk_phy->reg_offset = reg_offset; |
| 346 | rk_phy->reg_base = grf; | 368 | rk_phy->reg_base = grf; |
| 369 | rk_phy->drive_impedance = PHYCTRL_DR_50OHM; | ||
| 370 | |||
| 371 | if (!of_property_read_u32(dev->of_node, "drive-impedance-ohm", &val)) | ||
| 372 | rk_phy->drive_impedance = convert_drive_impedance_ohm(pdev, val); | ||
| 347 | 373 | ||
| 348 | generic_phy = devm_phy_create(dev, dev->of_node, &ops); | 374 | generic_phy = devm_phy_create(dev, dev->of_node, &ops); |
| 349 | if (IS_ERR(generic_phy)) { | 375 | if (IS_ERR(generic_phy)) { |
diff --git a/drivers/phy/socionext/phy-uniphier-usb3hs.c b/drivers/phy/socionext/phy-uniphier-usb3hs.c index b1b048be6166..50f379fc4e06 100644 --- a/drivers/phy/socionext/phy-uniphier-usb3hs.c +++ b/drivers/phy/socionext/phy-uniphier-usb3hs.c | |||
| @@ -335,13 +335,9 @@ static int uniphier_u3hsphy_probe(struct platform_device *pdev) | |||
| 335 | if (IS_ERR(priv->clk_parent)) | 335 | if (IS_ERR(priv->clk_parent)) |
| 336 | return PTR_ERR(priv->clk_parent); | 336 | return PTR_ERR(priv->clk_parent); |
| 337 | 337 | ||
| 338 | priv->clk_ext = devm_clk_get(dev, "phy-ext"); | 338 | priv->clk_ext = devm_clk_get_optional(dev, "phy-ext"); |
| 339 | if (IS_ERR(priv->clk_ext)) { | 339 | if (IS_ERR(priv->clk_ext)) |
| 340 | if (PTR_ERR(priv->clk_ext) == -ENOENT) | 340 | return PTR_ERR(priv->clk_ext); |
| 341 | priv->clk_ext = NULL; | ||
| 342 | else | ||
| 343 | return PTR_ERR(priv->clk_ext); | ||
| 344 | } | ||
| 345 | 341 | ||
| 346 | priv->rst = devm_reset_control_get_shared(dev, "phy"); | 342 | priv->rst = devm_reset_control_get_shared(dev, "phy"); |
| 347 | if (IS_ERR(priv->rst)) | 343 | if (IS_ERR(priv->rst)) |
diff --git a/drivers/phy/socionext/phy-uniphier-usb3ss.c b/drivers/phy/socionext/phy-uniphier-usb3ss.c index 4be95679c7d8..ec231e40ef2a 100644 --- a/drivers/phy/socionext/phy-uniphier-usb3ss.c +++ b/drivers/phy/socionext/phy-uniphier-usb3ss.c | |||
| @@ -238,13 +238,9 @@ static int uniphier_u3ssphy_probe(struct platform_device *pdev) | |||
| 238 | if (IS_ERR(priv->clk)) | 238 | if (IS_ERR(priv->clk)) |
| 239 | return PTR_ERR(priv->clk); | 239 | return PTR_ERR(priv->clk); |
| 240 | 240 | ||
| 241 | priv->clk_ext = devm_clk_get(dev, "phy-ext"); | 241 | priv->clk_ext = devm_clk_get_optional(dev, "phy-ext"); |
| 242 | if (IS_ERR(priv->clk_ext)) { | 242 | if (IS_ERR(priv->clk_ext)) |
| 243 | if (PTR_ERR(priv->clk_ext) == -ENOENT) | 243 | return PTR_ERR(priv->clk_ext); |
| 244 | priv->clk_ext = NULL; | ||
| 245 | else | ||
| 246 | return PTR_ERR(priv->clk_ext); | ||
| 247 | } | ||
| 248 | 244 | ||
| 249 | priv->rst = devm_reset_control_get_shared(dev, "phy"); | 245 | priv->rst = devm_reset_control_get_shared(dev, "phy"); |
| 250 | if (IS_ERR(priv->rst)) | 246 | if (IS_ERR(priv->rst)) |
diff --git a/drivers/phy/tegra/Makefile b/drivers/phy/tegra/Makefile index 898589238fd9..a93cd9a499b2 100644 --- a/drivers/phy/tegra/Makefile +++ b/drivers/phy/tegra/Makefile | |||
| @@ -4,3 +4,4 @@ phy-tegra-xusb-y += xusb.o | |||
| 4 | phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_124_SOC) += xusb-tegra124.o | 4 | phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_124_SOC) += xusb-tegra124.o |
| 5 | phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_132_SOC) += xusb-tegra124.o | 5 | phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_132_SOC) += xusb-tegra124.o |
| 6 | phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_210_SOC) += xusb-tegra210.o | 6 | phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_210_SOC) += xusb-tegra210.o |
| 7 | phy-tegra-xusb-$(CONFIG_ARCH_TEGRA_186_SOC) += xusb-tegra186.o | ||
diff --git a/drivers/phy/tegra/xusb-tegra186.c b/drivers/phy/tegra/xusb-tegra186.c new file mode 100644 index 000000000000..6f3afaf9398f --- /dev/null +++ b/drivers/phy/tegra/xusb-tegra186.c | |||
| @@ -0,0 +1,899 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * Copyright (c) 2016-2019, NVIDIA CORPORATION. All rights reserved. | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <linux/delay.h> | ||
| 7 | #include <linux/io.h> | ||
| 8 | #include <linux/module.h> | ||
| 9 | #include <linux/of.h> | ||
| 10 | #include <linux/phy/phy.h> | ||
| 11 | #include <linux/regulator/consumer.h> | ||
| 12 | #include <linux/platform_device.h> | ||
| 13 | #include <linux/clk.h> | ||
| 14 | #include <linux/slab.h> | ||
| 15 | |||
| 16 | #include <soc/tegra/fuse.h> | ||
| 17 | |||
| 18 | #include "xusb.h" | ||
| 19 | |||
| 20 | /* FUSE USB_CALIB registers */ | ||
| 21 | #define HS_CURR_LEVEL_PADX_SHIFT(x) ((x) ? (11 + (x - 1) * 6) : 0) | ||
| 22 | #define HS_CURR_LEVEL_PAD_MASK 0x3f | ||
| 23 | #define HS_TERM_RANGE_ADJ_SHIFT 7 | ||
| 24 | #define HS_TERM_RANGE_ADJ_MASK 0xf | ||
| 25 | #define HS_SQUELCH_SHIFT 29 | ||
| 26 | #define HS_SQUELCH_MASK 0x7 | ||
| 27 | |||
| 28 | #define RPD_CTRL_SHIFT 0 | ||
| 29 | #define RPD_CTRL_MASK 0x1f | ||
| 30 | |||
| 31 | /* XUSB PADCTL registers */ | ||
| 32 | #define XUSB_PADCTL_USB2_PAD_MUX 0x4 | ||
| 33 | #define USB2_PORT_SHIFT(x) ((x) * 2) | ||
| 34 | #define USB2_PORT_MASK 0x3 | ||
| 35 | #define PORT_XUSB 1 | ||
| 36 | #define HSIC_PORT_SHIFT(x) ((x) + 20) | ||
| 37 | #define HSIC_PORT_MASK 0x1 | ||
| 38 | #define PORT_HSIC 0 | ||
| 39 | |||
| 40 | #define XUSB_PADCTL_USB2_PORT_CAP 0x8 | ||
| 41 | #define XUSB_PADCTL_SS_PORT_CAP 0xc | ||
| 42 | #define PORTX_CAP_SHIFT(x) ((x) * 4) | ||
| 43 | #define PORT_CAP_MASK 0x3 | ||
| 44 | #define PORT_CAP_DISABLED 0x0 | ||
| 45 | #define PORT_CAP_HOST 0x1 | ||
| 46 | #define PORT_CAP_DEVICE 0x2 | ||
| 47 | #define PORT_CAP_OTG 0x3 | ||
| 48 | |||
| 49 | #define XUSB_PADCTL_ELPG_PROGRAM 0x20 | ||
| 50 | #define USB2_PORT_WAKE_INTERRUPT_ENABLE(x) BIT(x) | ||
| 51 | #define USB2_PORT_WAKEUP_EVENT(x) BIT((x) + 7) | ||
| 52 | #define SS_PORT_WAKE_INTERRUPT_ENABLE(x) BIT((x) + 14) | ||
| 53 | #define SS_PORT_WAKEUP_EVENT(x) BIT((x) + 21) | ||
| 54 | #define USB2_HSIC_PORT_WAKE_INTERRUPT_ENABLE(x) BIT((x) + 28) | ||
| 55 | #define USB2_HSIC_PORT_WAKEUP_EVENT(x) BIT((x) + 30) | ||
| 56 | #define ALL_WAKE_EVENTS \ | ||
| 57 | (USB2_PORT_WAKEUP_EVENT(0) | USB2_PORT_WAKEUP_EVENT(1) | \ | ||
| 58 | USB2_PORT_WAKEUP_EVENT(2) | SS_PORT_WAKEUP_EVENT(0) | \ | ||
| 59 | SS_PORT_WAKEUP_EVENT(1) | SS_PORT_WAKEUP_EVENT(2) | \ | ||
| 60 | USB2_HSIC_PORT_WAKEUP_EVENT(0)) | ||
| 61 | |||
| 62 | #define XUSB_PADCTL_ELPG_PROGRAM_1 0x24 | ||
| 63 | #define SSPX_ELPG_CLAMP_EN(x) BIT(0 + (x) * 3) | ||
| 64 | #define SSPX_ELPG_CLAMP_EN_EARLY(x) BIT(1 + (x) * 3) | ||
| 65 | #define SSPX_ELPG_VCORE_DOWN(x) BIT(2 + (x) * 3) | ||
| 66 | |||
| 67 | #define XUSB_PADCTL_USB2_OTG_PADX_CTL0(x) (0x88 + (x) * 0x40) | ||
| 68 | #define HS_CURR_LEVEL(x) ((x) & 0x3f) | ||
| 69 | #define TERM_SEL BIT(25) | ||
| 70 | #define USB2_OTG_PD BIT(26) | ||
| 71 | #define USB2_OTG_PD2 BIT(27) | ||
| 72 | #define USB2_OTG_PD2_OVRD_EN BIT(28) | ||
| 73 | #define USB2_OTG_PD_ZI BIT(29) | ||
| 74 | |||
| 75 | #define XUSB_PADCTL_USB2_OTG_PADX_CTL1(x) (0x8c + (x) * 0x40) | ||
| 76 | #define USB2_OTG_PD_DR BIT(2) | ||
| 77 | #define TERM_RANGE_ADJ(x) (((x) & 0xf) << 3) | ||
| 78 | #define RPD_CTRL(x) (((x) & 0x1f) << 26) | ||
| 79 | |||
| 80 | #define XUSB_PADCTL_USB2_BIAS_PAD_CTL0 0x284 | ||
| 81 | #define BIAS_PAD_PD BIT(11) | ||
| 82 | #define HS_SQUELCH_LEVEL(x) (((x) & 0x7) << 0) | ||
| 83 | |||
| 84 | #define XUSB_PADCTL_USB2_BIAS_PAD_CTL1 0x288 | ||
| 85 | #define USB2_TRK_START_TIMER(x) (((x) & 0x7f) << 12) | ||
| 86 | #define USB2_TRK_DONE_RESET_TIMER(x) (((x) & 0x7f) << 19) | ||
| 87 | #define USB2_PD_TRK BIT(26) | ||
| 88 | |||
| 89 | #define XUSB_PADCTL_HSIC_PADX_CTL0(x) (0x300 + (x) * 0x20) | ||
| 90 | #define HSIC_PD_TX_DATA0 BIT(1) | ||
| 91 | #define HSIC_PD_TX_STROBE BIT(3) | ||
| 92 | #define HSIC_PD_RX_DATA0 BIT(4) | ||
| 93 | #define HSIC_PD_RX_STROBE BIT(6) | ||
| 94 | #define HSIC_PD_ZI_DATA0 BIT(7) | ||
| 95 | #define HSIC_PD_ZI_STROBE BIT(9) | ||
| 96 | #define HSIC_RPD_DATA0 BIT(13) | ||
| 97 | #define HSIC_RPD_STROBE BIT(15) | ||
| 98 | #define HSIC_RPU_DATA0 BIT(16) | ||
| 99 | #define HSIC_RPU_STROBE BIT(18) | ||
| 100 | |||
| 101 | #define XUSB_PADCTL_HSIC_PAD_TRK_CTL0 0x340 | ||
| 102 | #define HSIC_TRK_START_TIMER(x) (((x) & 0x7f) << 5) | ||
| 103 | #define HSIC_TRK_DONE_RESET_TIMER(x) (((x) & 0x7f) << 12) | ||
| 104 | #define HSIC_PD_TRK BIT(19) | ||
| 105 | |||
| 106 | #define USB2_VBUS_ID 0x360 | ||
| 107 | #define VBUS_OVERRIDE BIT(14) | ||
| 108 | #define ID_OVERRIDE(x) (((x) & 0xf) << 18) | ||
| 109 | #define ID_OVERRIDE_FLOATING ID_OVERRIDE(8) | ||
| 110 | #define ID_OVERRIDE_GROUNDED ID_OVERRIDE(0) | ||
| 111 | |||
| 112 | #define TEGRA186_LANE(_name, _offset, _shift, _mask, _type) \ | ||
| 113 | { \ | ||
| 114 | .name = _name, \ | ||
| 115 | .offset = _offset, \ | ||
| 116 | .shift = _shift, \ | ||
| 117 | .mask = _mask, \ | ||
| 118 | .num_funcs = ARRAY_SIZE(tegra186_##_type##_functions), \ | ||
| 119 | .funcs = tegra186_##_type##_functions, \ | ||
| 120 | } | ||
| 121 | |||
| 122 | struct tegra_xusb_fuse_calibration { | ||
| 123 | u32 *hs_curr_level; | ||
| 124 | u32 hs_squelch; | ||
| 125 | u32 hs_term_range_adj; | ||
| 126 | u32 rpd_ctrl; | ||
| 127 | }; | ||
| 128 | |||
| 129 | struct tegra186_xusb_padctl { | ||
| 130 | struct tegra_xusb_padctl base; | ||
| 131 | |||
| 132 | struct tegra_xusb_fuse_calibration calib; | ||
| 133 | |||
| 134 | /* UTMI bias and tracking */ | ||
| 135 | struct clk *usb2_trk_clk; | ||
| 136 | unsigned int bias_pad_enable; | ||
| 137 | }; | ||
| 138 | |||
| 139 | static inline struct tegra186_xusb_padctl * | ||
| 140 | to_tegra186_xusb_padctl(struct tegra_xusb_padctl *padctl) | ||
| 141 | { | ||
| 142 | return container_of(padctl, struct tegra186_xusb_padctl, base); | ||
| 143 | } | ||
| 144 | |||
| 145 | /* USB 2.0 UTMI PHY support */ | ||
| 146 | static struct tegra_xusb_lane * | ||
| 147 | tegra186_usb2_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np, | ||
| 148 | unsigned int index) | ||
| 149 | { | ||
| 150 | struct tegra_xusb_usb2_lane *usb2; | ||
| 151 | int err; | ||
| 152 | |||
| 153 | usb2 = kzalloc(sizeof(*usb2), GFP_KERNEL); | ||
| 154 | if (!usb2) | ||
| 155 | return ERR_PTR(-ENOMEM); | ||
| 156 | |||
| 157 | INIT_LIST_HEAD(&usb2->base.list); | ||
| 158 | usb2->base.soc = &pad->soc->lanes[index]; | ||
| 159 | usb2->base.index = index; | ||
| 160 | usb2->base.pad = pad; | ||
| 161 | usb2->base.np = np; | ||
| 162 | |||
| 163 | err = tegra_xusb_lane_parse_dt(&usb2->base, np); | ||
| 164 | if (err < 0) { | ||
| 165 | kfree(usb2); | ||
| 166 | return ERR_PTR(err); | ||
| 167 | } | ||
| 168 | |||
| 169 | return &usb2->base; | ||
| 170 | } | ||
| 171 | |||
| 172 | static void tegra186_usb2_lane_remove(struct tegra_xusb_lane *lane) | ||
| 173 | { | ||
| 174 | struct tegra_xusb_usb2_lane *usb2 = to_usb2_lane(lane); | ||
| 175 | |||
| 176 | kfree(usb2); | ||
| 177 | } | ||
| 178 | |||
| 179 | static const struct tegra_xusb_lane_ops tegra186_usb2_lane_ops = { | ||
| 180 | .probe = tegra186_usb2_lane_probe, | ||
| 181 | .remove = tegra186_usb2_lane_remove, | ||
| 182 | }; | ||
| 183 | |||
| 184 | static void tegra186_utmi_bias_pad_power_on(struct tegra_xusb_padctl *padctl) | ||
| 185 | { | ||
| 186 | struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl); | ||
| 187 | struct device *dev = padctl->dev; | ||
| 188 | u32 value; | ||
| 189 | int err; | ||
| 190 | |||
| 191 | mutex_lock(&padctl->lock); | ||
| 192 | |||
| 193 | if (priv->bias_pad_enable++ > 0) { | ||
| 194 | mutex_unlock(&padctl->lock); | ||
| 195 | return; | ||
| 196 | } | ||
| 197 | |||
| 198 | err = clk_prepare_enable(priv->usb2_trk_clk); | ||
| 199 | if (err < 0) | ||
| 200 | dev_warn(dev, "failed to enable USB2 trk clock: %d\n", err); | ||
| 201 | |||
| 202 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); | ||
| 203 | value &= ~USB2_TRK_START_TIMER(~0); | ||
| 204 | value |= USB2_TRK_START_TIMER(0x1e); | ||
| 205 | value &= ~USB2_TRK_DONE_RESET_TIMER(~0); | ||
| 206 | value |= USB2_TRK_DONE_RESET_TIMER(0xa); | ||
| 207 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); | ||
| 208 | |||
| 209 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); | ||
| 210 | value &= ~BIAS_PAD_PD; | ||
| 211 | value &= ~HS_SQUELCH_LEVEL(~0); | ||
| 212 | value |= HS_SQUELCH_LEVEL(priv->calib.hs_squelch); | ||
| 213 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL0); | ||
| 214 | |||
| 215 | udelay(1); | ||
| 216 | |||
| 217 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); | ||
| 218 | value &= ~USB2_PD_TRK; | ||
| 219 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); | ||
| 220 | |||
| 221 | mutex_unlock(&padctl->lock); | ||
| 222 | } | ||
| 223 | |||
| 224 | static void tegra186_utmi_bias_pad_power_off(struct tegra_xusb_padctl *padctl) | ||
| 225 | { | ||
| 226 | struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl); | ||
| 227 | u32 value; | ||
| 228 | |||
| 229 | mutex_lock(&padctl->lock); | ||
| 230 | |||
| 231 | if (WARN_ON(priv->bias_pad_enable == 0)) { | ||
| 232 | mutex_unlock(&padctl->lock); | ||
| 233 | return; | ||
| 234 | } | ||
| 235 | |||
| 236 | if (--priv->bias_pad_enable > 0) { | ||
| 237 | mutex_unlock(&padctl->lock); | ||
| 238 | return; | ||
| 239 | } | ||
| 240 | |||
| 241 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); | ||
| 242 | value |= USB2_PD_TRK; | ||
| 243 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_BIAS_PAD_CTL1); | ||
| 244 | |||
| 245 | clk_disable_unprepare(priv->usb2_trk_clk); | ||
| 246 | |||
| 247 | mutex_unlock(&padctl->lock); | ||
| 248 | } | ||
| 249 | |||
| 250 | static void tegra_phy_xusb_utmi_pad_power_on(struct phy *phy) | ||
| 251 | { | ||
| 252 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
| 253 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
| 254 | struct tegra_xusb_usb2_port *port; | ||
| 255 | struct device *dev = padctl->dev; | ||
| 256 | unsigned int index = lane->index; | ||
| 257 | u32 value; | ||
| 258 | |||
| 259 | if (!phy) | ||
| 260 | return; | ||
| 261 | |||
| 262 | port = tegra_xusb_find_usb2_port(padctl, index); | ||
| 263 | if (!port) { | ||
| 264 | dev_err(dev, "no port found for USB2 lane %u\n", index); | ||
| 265 | return; | ||
| 266 | } | ||
| 267 | |||
| 268 | tegra186_utmi_bias_pad_power_on(padctl); | ||
| 269 | |||
| 270 | udelay(2); | ||
| 271 | |||
| 272 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index)); | ||
| 273 | value &= ~USB2_OTG_PD; | ||
| 274 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index)); | ||
| 275 | |||
| 276 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); | ||
| 277 | value &= ~USB2_OTG_PD_DR; | ||
| 278 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); | ||
| 279 | } | ||
| 280 | |||
| 281 | static void tegra_phy_xusb_utmi_pad_power_down(struct phy *phy) | ||
| 282 | { | ||
| 283 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
| 284 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
| 285 | unsigned int index = lane->index; | ||
| 286 | u32 value; | ||
| 287 | |||
| 288 | if (!phy) | ||
| 289 | return; | ||
| 290 | |||
| 291 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index)); | ||
| 292 | value |= USB2_OTG_PD; | ||
| 293 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index)); | ||
| 294 | |||
| 295 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); | ||
| 296 | value |= USB2_OTG_PD_DR; | ||
| 297 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); | ||
| 298 | |||
| 299 | udelay(2); | ||
| 300 | |||
| 301 | tegra186_utmi_bias_pad_power_off(padctl); | ||
| 302 | } | ||
| 303 | |||
| 304 | static int tegra186_utmi_phy_power_on(struct phy *phy) | ||
| 305 | { | ||
| 306 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
| 307 | struct tegra_xusb_usb2_lane *usb2 = to_usb2_lane(lane); | ||
| 308 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
| 309 | struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl); | ||
| 310 | struct tegra_xusb_usb2_port *port; | ||
| 311 | unsigned int index = lane->index; | ||
| 312 | struct device *dev = padctl->dev; | ||
| 313 | u32 value; | ||
| 314 | |||
| 315 | port = tegra_xusb_find_usb2_port(padctl, index); | ||
| 316 | if (!port) { | ||
| 317 | dev_err(dev, "no port found for USB2 lane %u\n", index); | ||
| 318 | return -ENODEV; | ||
| 319 | } | ||
| 320 | |||
| 321 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_PAD_MUX); | ||
| 322 | value &= ~(USB2_PORT_MASK << USB2_PORT_SHIFT(index)); | ||
| 323 | value |= (PORT_XUSB << USB2_PORT_SHIFT(index)); | ||
| 324 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_PAD_MUX); | ||
| 325 | |||
| 326 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_PORT_CAP); | ||
| 327 | value &= ~(PORT_CAP_MASK << PORTX_CAP_SHIFT(index)); | ||
| 328 | |||
| 329 | if (port->mode == USB_DR_MODE_UNKNOWN) | ||
| 330 | value |= (PORT_CAP_DISABLED << PORTX_CAP_SHIFT(index)); | ||
| 331 | else if (port->mode == USB_DR_MODE_PERIPHERAL) | ||
| 332 | value |= (PORT_CAP_DEVICE << PORTX_CAP_SHIFT(index)); | ||
| 333 | else if (port->mode == USB_DR_MODE_HOST) | ||
| 334 | value |= (PORT_CAP_HOST << PORTX_CAP_SHIFT(index)); | ||
| 335 | else if (port->mode == USB_DR_MODE_OTG) | ||
| 336 | value |= (PORT_CAP_OTG << PORTX_CAP_SHIFT(index)); | ||
| 337 | |||
| 338 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_PORT_CAP); | ||
| 339 | |||
| 340 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index)); | ||
| 341 | value &= ~USB2_OTG_PD_ZI; | ||
| 342 | value |= TERM_SEL; | ||
| 343 | value &= ~HS_CURR_LEVEL(~0); | ||
| 344 | |||
| 345 | if (usb2->hs_curr_level_offset) { | ||
| 346 | int hs_current_level; | ||
| 347 | |||
| 348 | hs_current_level = (int)priv->calib.hs_curr_level[index] + | ||
| 349 | usb2->hs_curr_level_offset; | ||
| 350 | |||
| 351 | if (hs_current_level < 0) | ||
| 352 | hs_current_level = 0; | ||
| 353 | if (hs_current_level > 0x3f) | ||
| 354 | hs_current_level = 0x3f; | ||
| 355 | |||
| 356 | value |= HS_CURR_LEVEL(hs_current_level); | ||
| 357 | } else { | ||
| 358 | value |= HS_CURR_LEVEL(priv->calib.hs_curr_level[index]); | ||
| 359 | } | ||
| 360 | |||
| 361 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index)); | ||
| 362 | |||
| 363 | value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); | ||
| 364 | value &= ~TERM_RANGE_ADJ(~0); | ||
| 365 | value |= TERM_RANGE_ADJ(priv->calib.hs_term_range_adj); | ||
| 366 | value &= ~RPD_CTRL(~0); | ||
| 367 | value |= RPD_CTRL(priv->calib.rpd_ctrl); | ||
| 368 | padctl_writel(padctl, value, XUSB_PADCTL_USB2_OTG_PADX_CTL1(index)); | ||
| 369 | |||
| 370 | /* TODO: pad power saving */ | ||
| 371 | tegra_phy_xusb_utmi_pad_power_on(phy); | ||
| 372 | return 0; | ||
| 373 | } | ||
| 374 | |||
| 375 | static int tegra186_utmi_phy_power_off(struct phy *phy) | ||
| 376 | { | ||
| 377 | /* TODO: pad power saving */ | ||
| 378 | tegra_phy_xusb_utmi_pad_power_down(phy); | ||
| 379 | |||
| 380 | return 0; | ||
| 381 | } | ||
| 382 | |||
| 383 | static int tegra186_utmi_phy_init(struct phy *phy) | ||
| 384 | { | ||
| 385 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
| 386 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
| 387 | struct tegra_xusb_usb2_port *port; | ||
| 388 | unsigned int index = lane->index; | ||
| 389 | struct device *dev = padctl->dev; | ||
| 390 | int err; | ||
| 391 | |||
| 392 | port = tegra_xusb_find_usb2_port(padctl, index); | ||
| 393 | if (!port) { | ||
| 394 | dev_err(dev, "no port found for USB2 lane %u\n", index); | ||
| 395 | return -ENODEV; | ||
| 396 | } | ||
| 397 | |||
| 398 | if (port->supply && port->mode == USB_DR_MODE_HOST) { | ||
| 399 | err = regulator_enable(port->supply); | ||
| 400 | if (err) { | ||
| 401 | dev_err(dev, "failed to enable port %u VBUS: %d\n", | ||
| 402 | index, err); | ||
| 403 | return err; | ||
| 404 | } | ||
| 405 | } | ||
| 406 | |||
| 407 | return 0; | ||
| 408 | } | ||
| 409 | |||
| 410 | static int tegra186_utmi_phy_exit(struct phy *phy) | ||
| 411 | { | ||
| 412 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
| 413 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
| 414 | struct tegra_xusb_usb2_port *port; | ||
| 415 | unsigned int index = lane->index; | ||
| 416 | struct device *dev = padctl->dev; | ||
| 417 | int err; | ||
| 418 | |||
| 419 | port = tegra_xusb_find_usb2_port(padctl, index); | ||
| 420 | if (!port) { | ||
| 421 | dev_err(dev, "no port found for USB2 lane %u\n", index); | ||
| 422 | return -ENODEV; | ||
| 423 | } | ||
| 424 | |||
| 425 | if (port->supply && port->mode == USB_DR_MODE_HOST) { | ||
| 426 | err = regulator_disable(port->supply); | ||
| 427 | if (err) { | ||
| 428 | dev_err(dev, "failed to disable port %u VBUS: %d\n", | ||
| 429 | index, err); | ||
| 430 | return err; | ||
| 431 | } | ||
| 432 | } | ||
| 433 | |||
| 434 | return 0; | ||
| 435 | } | ||
| 436 | |||
| 437 | static const struct phy_ops utmi_phy_ops = { | ||
| 438 | .init = tegra186_utmi_phy_init, | ||
| 439 | .exit = tegra186_utmi_phy_exit, | ||
| 440 | .power_on = tegra186_utmi_phy_power_on, | ||
| 441 | .power_off = tegra186_utmi_phy_power_off, | ||
| 442 | .owner = THIS_MODULE, | ||
| 443 | }; | ||
| 444 | |||
| 445 | static struct tegra_xusb_pad * | ||
| 446 | tegra186_usb2_pad_probe(struct tegra_xusb_padctl *padctl, | ||
| 447 | const struct tegra_xusb_pad_soc *soc, | ||
| 448 | struct device_node *np) | ||
| 449 | { | ||
| 450 | struct tegra186_xusb_padctl *priv = to_tegra186_xusb_padctl(padctl); | ||
| 451 | struct tegra_xusb_usb2_pad *usb2; | ||
| 452 | struct tegra_xusb_pad *pad; | ||
| 453 | int err; | ||
| 454 | |||
| 455 | usb2 = kzalloc(sizeof(*usb2), GFP_KERNEL); | ||
| 456 | if (!usb2) | ||
| 457 | return ERR_PTR(-ENOMEM); | ||
| 458 | |||
| 459 | pad = &usb2->base; | ||
| 460 | pad->ops = &tegra186_usb2_lane_ops; | ||
| 461 | pad->soc = soc; | ||
| 462 | |||
| 463 | err = tegra_xusb_pad_init(pad, padctl, np); | ||
| 464 | if (err < 0) { | ||
| 465 | kfree(usb2); | ||
| 466 | goto out; | ||
| 467 | } | ||
| 468 | |||
| 469 | priv->usb2_trk_clk = devm_clk_get(&pad->dev, "trk"); | ||
| 470 | if (IS_ERR(priv->usb2_trk_clk)) { | ||
| 471 | err = PTR_ERR(priv->usb2_trk_clk); | ||
| 472 | dev_dbg(&pad->dev, "failed to get usb2 trk clock: %d\n", err); | ||
| 473 | goto unregister; | ||
| 474 | } | ||
| 475 | |||
| 476 | err = tegra_xusb_pad_register(pad, &utmi_phy_ops); | ||
| 477 | if (err < 0) | ||
| 478 | goto unregister; | ||
| 479 | |||
| 480 | dev_set_drvdata(&pad->dev, pad); | ||
| 481 | |||
| 482 | return pad; | ||
| 483 | |||
| 484 | unregister: | ||
| 485 | device_unregister(&pad->dev); | ||
| 486 | out: | ||
| 487 | return ERR_PTR(err); | ||
| 488 | } | ||
| 489 | |||
| 490 | static void tegra186_usb2_pad_remove(struct tegra_xusb_pad *pad) | ||
| 491 | { | ||
| 492 | struct tegra_xusb_usb2_pad *usb2 = to_usb2_pad(pad); | ||
| 493 | |||
| 494 | kfree(usb2); | ||
| 495 | } | ||
| 496 | |||
| 497 | static const struct tegra_xusb_pad_ops tegra186_usb2_pad_ops = { | ||
| 498 | .probe = tegra186_usb2_pad_probe, | ||
| 499 | .remove = tegra186_usb2_pad_remove, | ||
| 500 | }; | ||
| 501 | |||
| 502 | static const char * const tegra186_usb2_functions[] = { | ||
| 503 | "xusb", | ||
| 504 | }; | ||
| 505 | |||
| 506 | static const struct tegra_xusb_lane_soc tegra186_usb2_lanes[] = { | ||
| 507 | TEGRA186_LANE("usb2-0", 0, 0, 0, usb2), | ||
| 508 | TEGRA186_LANE("usb2-1", 0, 0, 0, usb2), | ||
| 509 | TEGRA186_LANE("usb2-2", 0, 0, 0, usb2), | ||
| 510 | }; | ||
| 511 | |||
| 512 | static const struct tegra_xusb_pad_soc tegra186_usb2_pad = { | ||
| 513 | .name = "usb2", | ||
| 514 | .num_lanes = ARRAY_SIZE(tegra186_usb2_lanes), | ||
| 515 | .lanes = tegra186_usb2_lanes, | ||
| 516 | .ops = &tegra186_usb2_pad_ops, | ||
| 517 | }; | ||
| 518 | |||
| 519 | static int tegra186_usb2_port_enable(struct tegra_xusb_port *port) | ||
| 520 | { | ||
| 521 | return 0; | ||
| 522 | } | ||
| 523 | |||
| 524 | static void tegra186_usb2_port_disable(struct tegra_xusb_port *port) | ||
| 525 | { | ||
| 526 | } | ||
| 527 | |||
| 528 | static struct tegra_xusb_lane * | ||
| 529 | tegra186_usb2_port_map(struct tegra_xusb_port *port) | ||
| 530 | { | ||
| 531 | return tegra_xusb_find_lane(port->padctl, "usb2", port->index); | ||
| 532 | } | ||
| 533 | |||
| 534 | static const struct tegra_xusb_port_ops tegra186_usb2_port_ops = { | ||
| 535 | .enable = tegra186_usb2_port_enable, | ||
| 536 | .disable = tegra186_usb2_port_disable, | ||
| 537 | .map = tegra186_usb2_port_map, | ||
| 538 | }; | ||
| 539 | |||
| 540 | /* SuperSpeed PHY support */ | ||
| 541 | static struct tegra_xusb_lane * | ||
| 542 | tegra186_usb3_lane_probe(struct tegra_xusb_pad *pad, struct device_node *np, | ||
| 543 | unsigned int index) | ||
| 544 | { | ||
| 545 | struct tegra_xusb_usb3_lane *usb3; | ||
| 546 | int err; | ||
| 547 | |||
| 548 | usb3 = kzalloc(sizeof(*usb3), GFP_KERNEL); | ||
| 549 | if (!usb3) | ||
| 550 | return ERR_PTR(-ENOMEM); | ||
| 551 | |||
| 552 | INIT_LIST_HEAD(&usb3->base.list); | ||
| 553 | usb3->base.soc = &pad->soc->lanes[index]; | ||
| 554 | usb3->base.index = index; | ||
| 555 | usb3->base.pad = pad; | ||
| 556 | usb3->base.np = np; | ||
| 557 | |||
| 558 | err = tegra_xusb_lane_parse_dt(&usb3->base, np); | ||
| 559 | if (err < 0) { | ||
| 560 | kfree(usb3); | ||
| 561 | return ERR_PTR(err); | ||
| 562 | } | ||
| 563 | |||
| 564 | return &usb3->base; | ||
| 565 | } | ||
| 566 | |||
| 567 | static void tegra186_usb3_lane_remove(struct tegra_xusb_lane *lane) | ||
| 568 | { | ||
| 569 | struct tegra_xusb_usb3_lane *usb3 = to_usb3_lane(lane); | ||
| 570 | |||
| 571 | kfree(usb3); | ||
| 572 | } | ||
| 573 | |||
| 574 | static const struct tegra_xusb_lane_ops tegra186_usb3_lane_ops = { | ||
| 575 | .probe = tegra186_usb3_lane_probe, | ||
| 576 | .remove = tegra186_usb3_lane_remove, | ||
| 577 | }; | ||
| 578 | static int tegra186_usb3_port_enable(struct tegra_xusb_port *port) | ||
| 579 | { | ||
| 580 | return 0; | ||
| 581 | } | ||
| 582 | |||
| 583 | static void tegra186_usb3_port_disable(struct tegra_xusb_port *port) | ||
| 584 | { | ||
| 585 | } | ||
| 586 | |||
| 587 | static struct tegra_xusb_lane * | ||
| 588 | tegra186_usb3_port_map(struct tegra_xusb_port *port) | ||
| 589 | { | ||
| 590 | return tegra_xusb_find_lane(port->padctl, "usb3", port->index); | ||
| 591 | } | ||
| 592 | |||
| 593 | static const struct tegra_xusb_port_ops tegra186_usb3_port_ops = { | ||
| 594 | .enable = tegra186_usb3_port_enable, | ||
| 595 | .disable = tegra186_usb3_port_disable, | ||
| 596 | .map = tegra186_usb3_port_map, | ||
| 597 | }; | ||
| 598 | |||
| 599 | static int tegra186_usb3_phy_power_on(struct phy *phy) | ||
| 600 | { | ||
| 601 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
| 602 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
| 603 | struct tegra_xusb_usb3_port *port; | ||
| 604 | struct tegra_xusb_usb2_port *usb2; | ||
| 605 | unsigned int index = lane->index; | ||
| 606 | struct device *dev = padctl->dev; | ||
| 607 | u32 value; | ||
| 608 | |||
| 609 | port = tegra_xusb_find_usb3_port(padctl, index); | ||
| 610 | if (!port) { | ||
| 611 | dev_err(dev, "no port found for USB3 lane %u\n", index); | ||
| 612 | return -ENODEV; | ||
| 613 | } | ||
| 614 | |||
| 615 | usb2 = tegra_xusb_find_usb2_port(padctl, port->port); | ||
| 616 | if (!usb2) { | ||
| 617 | dev_err(dev, "no companion port found for USB3 lane %u\n", | ||
| 618 | index); | ||
| 619 | return -ENODEV; | ||
| 620 | } | ||
| 621 | |||
| 622 | mutex_lock(&padctl->lock); | ||
| 623 | |||
| 624 | value = padctl_readl(padctl, XUSB_PADCTL_SS_PORT_CAP); | ||
| 625 | value &= ~(PORT_CAP_MASK << PORTX_CAP_SHIFT(index)); | ||
| 626 | |||
| 627 | if (usb2->mode == USB_DR_MODE_UNKNOWN) | ||
| 628 | value |= (PORT_CAP_DISABLED << PORTX_CAP_SHIFT(index)); | ||
| 629 | else if (usb2->mode == USB_DR_MODE_PERIPHERAL) | ||
| 630 | value |= (PORT_CAP_DEVICE << PORTX_CAP_SHIFT(index)); | ||
| 631 | else if (usb2->mode == USB_DR_MODE_HOST) | ||
| 632 | value |= (PORT_CAP_HOST << PORTX_CAP_SHIFT(index)); | ||
| 633 | else if (usb2->mode == USB_DR_MODE_OTG) | ||
| 634 | value |= (PORT_CAP_OTG << PORTX_CAP_SHIFT(index)); | ||
| 635 | |||
| 636 | padctl_writel(padctl, value, XUSB_PADCTL_SS_PORT_CAP); | ||
| 637 | |||
| 638 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1); | ||
| 639 | value &= ~SSPX_ELPG_VCORE_DOWN(index); | ||
| 640 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1); | ||
| 641 | |||
| 642 | usleep_range(100, 200); | ||
| 643 | |||
| 644 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1); | ||
| 645 | value &= ~SSPX_ELPG_CLAMP_EN_EARLY(index); | ||
| 646 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1); | ||
| 647 | |||
| 648 | usleep_range(100, 200); | ||
| 649 | |||
| 650 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1); | ||
| 651 | value &= ~SSPX_ELPG_CLAMP_EN(index); | ||
| 652 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1); | ||
| 653 | |||
| 654 | mutex_unlock(&padctl->lock); | ||
| 655 | |||
| 656 | return 0; | ||
| 657 | } | ||
| 658 | |||
| 659 | static int tegra186_usb3_phy_power_off(struct phy *phy) | ||
| 660 | { | ||
| 661 | struct tegra_xusb_lane *lane = phy_get_drvdata(phy); | ||
| 662 | struct tegra_xusb_padctl *padctl = lane->pad->padctl; | ||
| 663 | struct tegra_xusb_usb3_port *port; | ||
| 664 | unsigned int index = lane->index; | ||
| 665 | struct device *dev = padctl->dev; | ||
| 666 | u32 value; | ||
| 667 | |||
| 668 | port = tegra_xusb_find_usb3_port(padctl, index); | ||
| 669 | if (!port) { | ||
| 670 | dev_err(dev, "no port found for USB3 lane %u\n", index); | ||
| 671 | return -ENODEV; | ||
| 672 | } | ||
| 673 | |||
| 674 | mutex_lock(&padctl->lock); | ||
| 675 | |||
| 676 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1); | ||
| 677 | value |= SSPX_ELPG_CLAMP_EN_EARLY(index); | ||
| 678 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1); | ||
| 679 | |||
| 680 | usleep_range(100, 200); | ||
| 681 | |||
| 682 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1); | ||
| 683 | value |= SSPX_ELPG_CLAMP_EN(index); | ||
| 684 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1); | ||
| 685 | |||
| 686 | usleep_range(250, 350); | ||
| 687 | |||
| 688 | value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM_1); | ||
| 689 | value |= SSPX_ELPG_VCORE_DOWN(index); | ||
| 690 | padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM_1); | ||
| 691 | |||
| 692 | mutex_unlock(&padctl->lock); | ||
| 693 | |||
| 694 | return 0; | ||
| 695 | } | ||
| 696 | |||
| 697 | static int tegra186_usb3_phy_init(struct phy *phy) | ||
| 698 | { | ||
| 699 | return 0; | ||
| 700 | } | ||
| 701 | |||
| 702 | static int tegra186_usb3_phy_exit(struct phy *phy) | ||
| 703 | { | ||
| 704 | return 0; | ||
| 705 | } | ||
| 706 | |||
| 707 | static const struct phy_ops usb3_phy_ops = { | ||
| 708 | .init = tegra186_usb3_phy_init, | ||
| 709 | .exit = tegra186_usb3_phy_exit, | ||
| 710 | .power_on = tegra186_usb3_phy_power_on, | ||
| 711 | .power_off = tegra186_usb3_phy_power_off, | ||
| 712 | .owner = THIS_MODULE, | ||
| 713 | }; | ||
| 714 | |||
| 715 | static struct tegra_xusb_pad * | ||
| 716 | tegra186_usb3_pad_probe(struct tegra_xusb_padctl *padctl, | ||
| 717 | const struct tegra_xusb_pad_soc *soc, | ||
| 718 | struct device_node *np) | ||
| 719 | { | ||
| 720 | struct tegra_xusb_usb3_pad *usb3; | ||
| 721 | struct tegra_xusb_pad *pad; | ||
| 722 | int err; | ||
| 723 | |||
| 724 | usb3 = kzalloc(sizeof(*usb3), GFP_KERNEL); | ||
| 725 | if (!usb3) | ||
| 726 | return ERR_PTR(-ENOMEM); | ||
| 727 | |||
| 728 | pad = &usb3->base; | ||
| 729 | pad->ops = &tegra186_usb3_lane_ops; | ||
| 730 | pad->soc = soc; | ||
| 731 | |||
| 732 | err = tegra_xusb_pad_init(pad, padctl, np); | ||
| 733 | if (err < 0) { | ||
| 734 | kfree(usb3); | ||
| 735 | goto out; | ||
| 736 | } | ||
| 737 | |||
| 738 | err = tegra_xusb_pad_register(pad, &usb3_phy_ops); | ||
| 739 | if (err < 0) | ||
| 740 | goto unregister; | ||
| 741 | |||
| 742 | dev_set_drvdata(&pad->dev, pad); | ||
| 743 | |||
| 744 | return pad; | ||
| 745 | |||
| 746 | unregister: | ||
| 747 | device_unregister(&pad->dev); | ||
| 748 | out: | ||
| 749 | return ERR_PTR(err); | ||
| 750 | } | ||
| 751 | |||
| 752 | static void tegra186_usb3_pad_remove(struct tegra_xusb_pad *pad) | ||
| 753 | { | ||
| 754 | struct tegra_xusb_usb2_pad *usb2 = to_usb2_pad(pad); | ||
| 755 | |||
| 756 | kfree(usb2); | ||
| 757 | } | ||
| 758 | |||
| 759 | static const struct tegra_xusb_pad_ops tegra186_usb3_pad_ops = { | ||
| 760 | .probe = tegra186_usb3_pad_probe, | ||
| 761 | .remove = tegra186_usb3_pad_remove, | ||
| 762 | }; | ||
| 763 | |||
| 764 | static const char * const tegra186_usb3_functions[] = { | ||
| 765 | "xusb", | ||
| 766 | }; | ||
| 767 | |||
| 768 | static const struct tegra_xusb_lane_soc tegra186_usb3_lanes[] = { | ||
| 769 | TEGRA186_LANE("usb3-0", 0, 0, 0, usb3), | ||
| 770 | TEGRA186_LANE("usb3-1", 0, 0, 0, usb3), | ||
| 771 | TEGRA186_LANE("usb3-2", 0, 0, 0, usb3), | ||
| 772 | }; | ||
| 773 | |||
| 774 | static const struct tegra_xusb_pad_soc tegra186_usb3_pad = { | ||
| 775 | .name = "usb3", | ||
| 776 | .num_lanes = ARRAY_SIZE(tegra186_usb3_lanes), | ||
| 777 | .lanes = tegra186_usb3_lanes, | ||
| 778 | .ops = &tegra186_usb3_pad_ops, | ||
| 779 | }; | ||
| 780 | |||
| 781 | static const struct tegra_xusb_pad_soc * const tegra186_pads[] = { | ||
| 782 | &tegra186_usb2_pad, | ||
| 783 | &tegra186_usb3_pad, | ||
| 784 | #if 0 /* TODO implement */ | ||
| 785 | &tegra186_hsic_pad, | ||
| 786 | #endif | ||
| 787 | }; | ||
| 788 | |||
| 789 | static int | ||
| 790 | tegra186_xusb_read_fuse_calibration(struct tegra186_xusb_padctl *padctl) | ||
| 791 | { | ||
| 792 | struct device *dev = padctl->base.dev; | ||
| 793 | unsigned int i, count; | ||
| 794 | u32 value, *level; | ||
| 795 | int err; | ||
| 796 | |||
| 797 | count = padctl->base.soc->ports.usb2.count; | ||
| 798 | |||
| 799 | level = devm_kcalloc(dev, count, sizeof(u32), GFP_KERNEL); | ||
| 800 | if (!level) | ||
| 801 | return -ENOMEM; | ||
| 802 | |||
| 803 | err = tegra_fuse_readl(TEGRA_FUSE_SKU_CALIB_0, &value); | ||
| 804 | if (err) { | ||
| 805 | dev_err(dev, "failed to read calibration fuse: %d\n", err); | ||
| 806 | return err; | ||
| 807 | } | ||
| 808 | |||
| 809 | dev_dbg(dev, "FUSE_USB_CALIB_0 %#x\n", value); | ||
| 810 | |||
| 811 | for (i = 0; i < count; i++) | ||
| 812 | level[i] = (value >> HS_CURR_LEVEL_PADX_SHIFT(i)) & | ||
| 813 | HS_CURR_LEVEL_PAD_MASK; | ||
| 814 | |||
| 815 | padctl->calib.hs_curr_level = level; | ||
| 816 | |||
| 817 | padctl->calib.hs_squelch = (value >> HS_SQUELCH_SHIFT) & | ||
| 818 | HS_SQUELCH_MASK; | ||
| 819 | padctl->calib.hs_term_range_adj = (value >> HS_TERM_RANGE_ADJ_SHIFT) & | ||
| 820 | HS_TERM_RANGE_ADJ_MASK; | ||
| 821 | |||
| 822 | err = tegra_fuse_readl(TEGRA_FUSE_USB_CALIB_EXT_0, &value); | ||
| 823 | if (err) { | ||
| 824 | dev_err(dev, "failed to read calibration fuse: %d\n", err); | ||
| 825 | return err; | ||
| 826 | } | ||
| 827 | |||
| 828 | dev_dbg(dev, "FUSE_USB_CALIB_EXT_0 %#x\n", value); | ||
| 829 | |||
| 830 | padctl->calib.rpd_ctrl = (value >> RPD_CTRL_SHIFT) & RPD_CTRL_MASK; | ||
| 831 | |||
| 832 | return 0; | ||
| 833 | } | ||
| 834 | |||
| 835 | static struct tegra_xusb_padctl * | ||
| 836 | tegra186_xusb_padctl_probe(struct device *dev, | ||
| 837 | const struct tegra_xusb_padctl_soc *soc) | ||
| 838 | { | ||
| 839 | struct tegra186_xusb_padctl *priv; | ||
| 840 | int err; | ||
| 841 | |||
| 842 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
| 843 | if (!priv) | ||
| 844 | return ERR_PTR(-ENOMEM); | ||
| 845 | |||
| 846 | priv->base.dev = dev; | ||
| 847 | priv->base.soc = soc; | ||
| 848 | |||
| 849 | err = tegra186_xusb_read_fuse_calibration(priv); | ||
| 850 | if (err < 0) | ||
| 851 | return ERR_PTR(err); | ||
| 852 | |||
| 853 | return &priv->base; | ||
| 854 | } | ||
| 855 | |||
| 856 | static void tegra186_xusb_padctl_remove(struct tegra_xusb_padctl *padctl) | ||
| 857 | { | ||
| 858 | } | ||
| 859 | |||
| 860 | static const struct tegra_xusb_padctl_ops tegra186_xusb_padctl_ops = { | ||
| 861 | .probe = tegra186_xusb_padctl_probe, | ||
| 862 | .remove = tegra186_xusb_padctl_remove, | ||
| 863 | }; | ||
| 864 | |||
| 865 | static const char * const tegra186_xusb_padctl_supply_names[] = { | ||
| 866 | "avdd-pll-erefeut", | ||
| 867 | "avdd-usb", | ||
| 868 | "vclamp-usb", | ||
| 869 | "vddio-hsic", | ||
| 870 | }; | ||
| 871 | |||
| 872 | const struct tegra_xusb_padctl_soc tegra186_xusb_padctl_soc = { | ||
| 873 | .num_pads = ARRAY_SIZE(tegra186_pads), | ||
| 874 | .pads = tegra186_pads, | ||
| 875 | .ports = { | ||
| 876 | .usb2 = { | ||
| 877 | .ops = &tegra186_usb2_port_ops, | ||
| 878 | .count = 3, | ||
| 879 | }, | ||
| 880 | #if 0 /* TODO implement */ | ||
| 881 | .hsic = { | ||
| 882 | .ops = &tegra186_hsic_port_ops, | ||
| 883 | .count = 1, | ||
| 884 | }, | ||
| 885 | #endif | ||
| 886 | .usb3 = { | ||
| 887 | .ops = &tegra186_usb3_port_ops, | ||
| 888 | .count = 3, | ||
| 889 | }, | ||
| 890 | }, | ||
| 891 | .ops = &tegra186_xusb_padctl_ops, | ||
| 892 | .supply_names = tegra186_xusb_padctl_supply_names, | ||
| 893 | .num_supplies = ARRAY_SIZE(tegra186_xusb_padctl_supply_names), | ||
| 894 | }; | ||
| 895 | EXPORT_SYMBOL_GPL(tegra186_xusb_padctl_soc); | ||
| 896 | |||
| 897 | MODULE_AUTHOR("JC Kuo <jckuo@nvidia.com>"); | ||
| 898 | MODULE_DESCRIPTION("NVIDIA Tegra186 XUSB Pad Controller driver"); | ||
| 899 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c index 5b3b8863363e..0417213ed68b 100644 --- a/drivers/phy/tegra/xusb.c +++ b/drivers/phy/tegra/xusb.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved. | 2 | * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved. |
| 3 | * | 3 | * |
| 4 | * This program is free software; you can redistribute it and/or modify it | 4 | * This program is free software; you can redistribute it and/or modify it |
| 5 | * under the terms and conditions of the GNU General Public License, | 5 | * under the terms and conditions of the GNU General Public License, |
| @@ -68,6 +68,12 @@ static const struct of_device_id tegra_xusb_padctl_of_match[] = { | |||
| 68 | .data = &tegra210_xusb_padctl_soc, | 68 | .data = &tegra210_xusb_padctl_soc, |
| 69 | }, | 69 | }, |
| 70 | #endif | 70 | #endif |
| 71 | #if defined(CONFIG_ARCH_TEGRA_186_SOC) | ||
| 72 | { | ||
| 73 | .compatible = "nvidia,tegra186-xusb-padctl", | ||
| 74 | .data = &tegra186_xusb_padctl_soc, | ||
| 75 | }, | ||
| 76 | #endif | ||
| 71 | { } | 77 | { } |
| 72 | }; | 78 | }; |
| 73 | MODULE_DEVICE_TABLE(of, tegra_xusb_padctl_of_match); | 79 | MODULE_DEVICE_TABLE(of, tegra_xusb_padctl_of_match); |
| @@ -313,6 +319,10 @@ static void tegra_xusb_lane_program(struct tegra_xusb_lane *lane) | |||
| 313 | const struct tegra_xusb_lane_soc *soc = lane->soc; | 319 | const struct tegra_xusb_lane_soc *soc = lane->soc; |
| 314 | u32 value; | 320 | u32 value; |
| 315 | 321 | ||
| 322 | /* skip single function lanes */ | ||
| 323 | if (soc->num_funcs < 2) | ||
| 324 | return; | ||
| 325 | |||
| 316 | /* choose function */ | 326 | /* choose function */ |
| 317 | value = padctl_readl(padctl, soc->offset); | 327 | value = padctl_readl(padctl, soc->offset); |
| 318 | value &= ~(soc->mask << soc->shift); | 328 | value &= ~(soc->mask << soc->shift); |
| @@ -542,13 +552,34 @@ static void tegra_xusb_port_unregister(struct tegra_xusb_port *port) | |||
| 542 | device_unregister(&port->dev); | 552 | device_unregister(&port->dev); |
| 543 | } | 553 | } |
| 544 | 554 | ||
| 555 | static const char *const modes[] = { | ||
| 556 | [USB_DR_MODE_UNKNOWN] = "", | ||
| 557 | [USB_DR_MODE_HOST] = "host", | ||
| 558 | [USB_DR_MODE_PERIPHERAL] = "peripheral", | ||
| 559 | [USB_DR_MODE_OTG] = "otg", | ||
| 560 | }; | ||
| 561 | |||
| 545 | static int tegra_xusb_usb2_port_parse_dt(struct tegra_xusb_usb2_port *usb2) | 562 | static int tegra_xusb_usb2_port_parse_dt(struct tegra_xusb_usb2_port *usb2) |
| 546 | { | 563 | { |
| 547 | struct tegra_xusb_port *port = &usb2->base; | 564 | struct tegra_xusb_port *port = &usb2->base; |
| 548 | struct device_node *np = port->dev.of_node; | 565 | struct device_node *np = port->dev.of_node; |
| 566 | const char *mode; | ||
| 549 | 567 | ||
| 550 | usb2->internal = of_property_read_bool(np, "nvidia,internal"); | 568 | usb2->internal = of_property_read_bool(np, "nvidia,internal"); |
| 551 | 569 | ||
| 570 | if (!of_property_read_string(np, "mode", &mode)) { | ||
| 571 | int err = match_string(modes, ARRAY_SIZE(modes), mode); | ||
| 572 | if (err < 0) { | ||
| 573 | dev_err(&port->dev, "invalid value %s for \"mode\"\n", | ||
| 574 | mode); | ||
| 575 | usb2->mode = USB_DR_MODE_UNKNOWN; | ||
| 576 | } else { | ||
| 577 | usb2->mode = err; | ||
| 578 | } | ||
| 579 | } else { | ||
| 580 | usb2->mode = USB_DR_MODE_HOST; | ||
| 581 | } | ||
| 582 | |||
| 552 | usb2->supply = devm_regulator_get(&port->dev, "vbus"); | 583 | usb2->supply = devm_regulator_get(&port->dev, "vbus"); |
| 553 | return PTR_ERR_OR_ZERO(usb2->supply); | 584 | return PTR_ERR_OR_ZERO(usb2->supply); |
| 554 | } | 585 | } |
| @@ -839,6 +870,7 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev) | |||
| 839 | struct tegra_xusb_padctl *padctl; | 870 | struct tegra_xusb_padctl *padctl; |
| 840 | const struct of_device_id *match; | 871 | const struct of_device_id *match; |
| 841 | struct resource *res; | 872 | struct resource *res; |
| 873 | unsigned int i; | ||
| 842 | int err; | 874 | int err; |
| 843 | 875 | ||
| 844 | /* for backwards compatibility with old device trees */ | 876 | /* for backwards compatibility with old device trees */ |
| @@ -876,14 +908,38 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev) | |||
| 876 | goto remove; | 908 | goto remove; |
| 877 | } | 909 | } |
| 878 | 910 | ||
| 911 | padctl->supplies = devm_kcalloc(&pdev->dev, padctl->soc->num_supplies, | ||
| 912 | sizeof(*padctl->supplies), GFP_KERNEL); | ||
| 913 | if (!padctl->supplies) { | ||
| 914 | err = -ENOMEM; | ||
| 915 | goto remove; | ||
| 916 | } | ||
| 917 | |||
| 918 | for (i = 0; i < padctl->soc->num_supplies; i++) | ||
| 919 | padctl->supplies[i].supply = padctl->soc->supply_names[i]; | ||
| 920 | |||
| 921 | err = devm_regulator_bulk_get(&pdev->dev, padctl->soc->num_supplies, | ||
| 922 | padctl->supplies); | ||
| 923 | if (err < 0) { | ||
| 924 | dev_err(&pdev->dev, "failed to get regulators: %d\n", err); | ||
| 925 | goto remove; | ||
| 926 | } | ||
| 927 | |||
| 879 | err = reset_control_deassert(padctl->rst); | 928 | err = reset_control_deassert(padctl->rst); |
| 880 | if (err < 0) | 929 | if (err < 0) |
| 881 | goto remove; | 930 | goto remove; |
| 882 | 931 | ||
| 932 | err = regulator_bulk_enable(padctl->soc->num_supplies, | ||
| 933 | padctl->supplies); | ||
| 934 | if (err < 0) { | ||
| 935 | dev_err(&pdev->dev, "failed to enable supplies: %d\n", err); | ||
| 936 | goto reset; | ||
| 937 | } | ||
| 938 | |||
| 883 | err = tegra_xusb_setup_pads(padctl); | 939 | err = tegra_xusb_setup_pads(padctl); |
| 884 | if (err < 0) { | 940 | if (err < 0) { |
| 885 | dev_err(&pdev->dev, "failed to setup pads: %d\n", err); | 941 | dev_err(&pdev->dev, "failed to setup pads: %d\n", err); |
| 886 | goto reset; | 942 | goto power_down; |
| 887 | } | 943 | } |
| 888 | 944 | ||
| 889 | err = tegra_xusb_setup_ports(padctl); | 945 | err = tegra_xusb_setup_ports(padctl); |
| @@ -896,6 +952,8 @@ static int tegra_xusb_padctl_probe(struct platform_device *pdev) | |||
| 896 | 952 | ||
| 897 | remove_pads: | 953 | remove_pads: |
| 898 | tegra_xusb_remove_pads(padctl); | 954 | tegra_xusb_remove_pads(padctl); |
| 955 | power_down: | ||
| 956 | regulator_bulk_disable(padctl->soc->num_supplies, padctl->supplies); | ||
| 899 | reset: | 957 | reset: |
| 900 | reset_control_assert(padctl->rst); | 958 | reset_control_assert(padctl->rst); |
| 901 | remove: | 959 | remove: |
| @@ -911,6 +969,11 @@ static int tegra_xusb_padctl_remove(struct platform_device *pdev) | |||
| 911 | tegra_xusb_remove_ports(padctl); | 969 | tegra_xusb_remove_ports(padctl); |
| 912 | tegra_xusb_remove_pads(padctl); | 970 | tegra_xusb_remove_pads(padctl); |
| 913 | 971 | ||
| 972 | err = regulator_bulk_disable(padctl->soc->num_supplies, | ||
| 973 | padctl->supplies); | ||
| 974 | if (err < 0) | ||
| 975 | dev_err(&pdev->dev, "failed to disable supplies: %d\n", err); | ||
| 976 | |||
| 914 | err = reset_control_assert(padctl->rst); | 977 | err = reset_control_assert(padctl->rst); |
| 915 | if (err < 0) | 978 | if (err < 0) |
| 916 | dev_err(&pdev->dev, "failed to assert reset: %d\n", err); | 979 | dev_err(&pdev->dev, "failed to assert reset: %d\n", err); |
diff --git a/drivers/phy/tegra/xusb.h b/drivers/phy/tegra/xusb.h index b49dbc36efa3..e0028b9fe702 100644 --- a/drivers/phy/tegra/xusb.h +++ b/drivers/phy/tegra/xusb.h | |||
| @@ -19,6 +19,8 @@ | |||
| 19 | #include <linux/mutex.h> | 19 | #include <linux/mutex.h> |
| 20 | #include <linux/workqueue.h> | 20 | #include <linux/workqueue.h> |
| 21 | 21 | ||
| 22 | #include <linux/usb/otg.h> | ||
| 23 | |||
| 22 | /* legacy entry points for backwards-compatibility */ | 24 | /* legacy entry points for backwards-compatibility */ |
| 23 | int tegra_xusb_padctl_legacy_probe(struct platform_device *pdev); | 25 | int tegra_xusb_padctl_legacy_probe(struct platform_device *pdev); |
| 24 | int tegra_xusb_padctl_legacy_remove(struct platform_device *pdev); | 26 | int tegra_xusb_padctl_legacy_remove(struct platform_device *pdev); |
| @@ -54,10 +56,21 @@ struct tegra_xusb_lane { | |||
| 54 | int tegra_xusb_lane_parse_dt(struct tegra_xusb_lane *lane, | 56 | int tegra_xusb_lane_parse_dt(struct tegra_xusb_lane *lane, |
| 55 | struct device_node *np); | 57 | struct device_node *np); |
| 56 | 58 | ||
| 59 | struct tegra_xusb_usb3_lane { | ||
| 60 | struct tegra_xusb_lane base; | ||
| 61 | }; | ||
| 62 | |||
| 63 | static inline struct tegra_xusb_usb3_lane * | ||
| 64 | to_usb3_lane(struct tegra_xusb_lane *lane) | ||
| 65 | { | ||
| 66 | return container_of(lane, struct tegra_xusb_usb3_lane, base); | ||
| 67 | } | ||
| 68 | |||
| 57 | struct tegra_xusb_usb2_lane { | 69 | struct tegra_xusb_usb2_lane { |
| 58 | struct tegra_xusb_lane base; | 70 | struct tegra_xusb_lane base; |
| 59 | 71 | ||
| 60 | u32 hs_curr_level_offset; | 72 | u32 hs_curr_level_offset; |
| 73 | bool powered_on; | ||
| 61 | }; | 74 | }; |
| 62 | 75 | ||
| 63 | static inline struct tegra_xusb_usb2_lane * | 76 | static inline struct tegra_xusb_usb2_lane * |
| @@ -168,6 +181,19 @@ int tegra_xusb_pad_register(struct tegra_xusb_pad *pad, | |||
| 168 | const struct phy_ops *ops); | 181 | const struct phy_ops *ops); |
| 169 | void tegra_xusb_pad_unregister(struct tegra_xusb_pad *pad); | 182 | void tegra_xusb_pad_unregister(struct tegra_xusb_pad *pad); |
| 170 | 183 | ||
| 184 | struct tegra_xusb_usb3_pad { | ||
| 185 | struct tegra_xusb_pad base; | ||
| 186 | |||
| 187 | unsigned int enable; | ||
| 188 | struct mutex lock; | ||
| 189 | }; | ||
| 190 | |||
| 191 | static inline struct tegra_xusb_usb3_pad * | ||
| 192 | to_usb3_pad(struct tegra_xusb_pad *pad) | ||
| 193 | { | ||
| 194 | return container_of(pad, struct tegra_xusb_usb3_pad, base); | ||
| 195 | } | ||
| 196 | |||
| 171 | struct tegra_xusb_usb2_pad { | 197 | struct tegra_xusb_usb2_pad { |
| 172 | struct tegra_xusb_pad base; | 198 | struct tegra_xusb_pad base; |
| 173 | 199 | ||
| @@ -271,6 +297,7 @@ struct tegra_xusb_usb2_port { | |||
| 271 | struct tegra_xusb_port base; | 297 | struct tegra_xusb_port base; |
| 272 | 298 | ||
| 273 | struct regulator *supply; | 299 | struct regulator *supply; |
| 300 | enum usb_dr_mode mode; | ||
| 274 | bool internal; | 301 | bool internal; |
| 275 | }; | 302 | }; |
| 276 | 303 | ||
| @@ -367,6 +394,9 @@ struct tegra_xusb_padctl_soc { | |||
| 367 | } ports; | 394 | } ports; |
| 368 | 395 | ||
| 369 | const struct tegra_xusb_padctl_ops *ops; | 396 | const struct tegra_xusb_padctl_ops *ops; |
| 397 | |||
| 398 | const char * const *supply_names; | ||
| 399 | unsigned int num_supplies; | ||
| 370 | }; | 400 | }; |
| 371 | 401 | ||
| 372 | struct tegra_xusb_padctl { | 402 | struct tegra_xusb_padctl { |
| @@ -390,6 +420,8 @@ struct tegra_xusb_padctl { | |||
| 390 | unsigned int enable; | 420 | unsigned int enable; |
| 391 | 421 | ||
| 392 | struct clk *clk; | 422 | struct clk *clk; |
| 423 | |||
| 424 | struct regulator_bulk_data *supplies; | ||
| 393 | }; | 425 | }; |
| 394 | 426 | ||
| 395 | static inline void padctl_writel(struct tegra_xusb_padctl *padctl, u32 value, | 427 | static inline void padctl_writel(struct tegra_xusb_padctl *padctl, u32 value, |
| @@ -417,5 +449,8 @@ extern const struct tegra_xusb_padctl_soc tegra124_xusb_padctl_soc; | |||
| 417 | #if defined(CONFIG_ARCH_TEGRA_210_SOC) | 449 | #if defined(CONFIG_ARCH_TEGRA_210_SOC) |
| 418 | extern const struct tegra_xusb_padctl_soc tegra210_xusb_padctl_soc; | 450 | extern const struct tegra_xusb_padctl_soc tegra210_xusb_padctl_soc; |
| 419 | #endif | 451 | #endif |
| 452 | #if defined(CONFIG_ARCH_TEGRA_186_SOC) | ||
| 453 | extern const struct tegra_xusb_padctl_soc tegra186_xusb_padctl_soc; | ||
| 454 | #endif | ||
| 420 | 455 | ||
| 421 | #endif /* __PHY_TEGRA_XUSB_H */ | 456 | #endif /* __PHY_TEGRA_XUSB_H */ |
diff --git a/drivers/phy/ti/Kconfig b/drivers/phy/ti/Kconfig index 022ac16f626c..781514efded3 100644 --- a/drivers/phy/ti/Kconfig +++ b/drivers/phy/ti/Kconfig | |||
| @@ -20,6 +20,18 @@ config PHY_DM816X_USB | |||
| 20 | help | 20 | help |
| 21 | Enable this for dm816x USB to work. | 21 | Enable this for dm816x USB to work. |
| 22 | 22 | ||
| 23 | config PHY_AM654_SERDES | ||
| 24 | tristate "TI AM654 SERDES support" | ||
| 25 | depends on OF && ARCH_K3 || COMPILE_TEST | ||
| 26 | depends on COMMON_CLK | ||
| 27 | select GENERIC_PHY | ||
| 28 | select MULTIPLEXER | ||
| 29 | select REGMAP_MMIO | ||
| 30 | select MUX_MMIO | ||
| 31 | help | ||
| 32 | This option enables support for TI AM654 SerDes PHY used for | ||
| 33 | PCIe. | ||
| 34 | |||
| 23 | config OMAP_CONTROL_PHY | 35 | config OMAP_CONTROL_PHY |
| 24 | tristate "OMAP CONTROL PHY Driver" | 36 | tristate "OMAP CONTROL PHY Driver" |
| 25 | depends on ARCH_OMAP2PLUS || COMPILE_TEST | 37 | depends on ARCH_OMAP2PLUS || COMPILE_TEST |
diff --git a/drivers/phy/ti/Makefile b/drivers/phy/ti/Makefile index bea8f25a137a..bff901eb0ecc 100644 --- a/drivers/phy/ti/Makefile +++ b/drivers/phy/ti/Makefile | |||
| @@ -6,4 +6,5 @@ obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o | |||
| 6 | obj-$(CONFIG_TI_PIPE3) += phy-ti-pipe3.o | 6 | obj-$(CONFIG_TI_PIPE3) += phy-ti-pipe3.o |
| 7 | obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o | 7 | obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o |
| 8 | obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o | 8 | obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o |
| 9 | obj-$(CONFIG_PHY_AM654_SERDES) += phy-am654-serdes.o | ||
| 9 | obj-$(CONFIG_PHY_TI_GMII_SEL) += phy-gmii-sel.o | 10 | obj-$(CONFIG_PHY_TI_GMII_SEL) += phy-gmii-sel.o |
diff --git a/drivers/phy/ti/phy-am654-serdes.c b/drivers/phy/ti/phy-am654-serdes.c new file mode 100644 index 000000000000..d3769200cb9b --- /dev/null +++ b/drivers/phy/ti/phy-am654-serdes.c | |||
| @@ -0,0 +1,658 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /** | ||
| 3 | * PCIe SERDES driver for AM654x SoC | ||
| 4 | * | ||
| 5 | * Copyright (C) 2018 - 2019 Texas Instruments Incorporated - http://www.ti.com/ | ||
| 6 | * Author: Kishon Vijay Abraham I <kishon@ti.com> | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <dt-bindings/phy/phy.h> | ||
| 10 | #include <linux/clk.h> | ||
| 11 | #include <linux/clk-provider.h> | ||
| 12 | #include <linux/delay.h> | ||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/mfd/syscon.h> | ||
| 15 | #include <linux/mux/consumer.h> | ||
| 16 | #include <linux/of_address.h> | ||
| 17 | #include <linux/phy/phy.h> | ||
| 18 | #include <linux/platform_device.h> | ||
| 19 | #include <linux/pm_runtime.h> | ||
| 20 | #include <linux/regmap.h> | ||
| 21 | |||
| 22 | #define CMU_R07C 0x7c | ||
| 23 | |||
| 24 | #define COMLANE_R138 0xb38 | ||
| 25 | #define VERSION 0x70 | ||
| 26 | |||
| 27 | #define COMLANE_R190 0xb90 | ||
| 28 | |||
| 29 | #define COMLANE_R194 0xb94 | ||
| 30 | |||
| 31 | #define SERDES_CTRL 0x1fd0 | ||
| 32 | |||
| 33 | #define WIZ_LANEXCTL_STS 0x1fe0 | ||
| 34 | #define TX0_DISABLE_STATE 0x4 | ||
| 35 | #define TX0_SLEEP_STATE 0x5 | ||
| 36 | #define TX0_SNOOZE_STATE 0x6 | ||
| 37 | #define TX0_ENABLE_STATE 0x7 | ||
| 38 | |||
| 39 | #define RX0_DISABLE_STATE 0x4 | ||
| 40 | #define RX0_SLEEP_STATE 0x5 | ||
| 41 | #define RX0_SNOOZE_STATE 0x6 | ||
| 42 | #define RX0_ENABLE_STATE 0x7 | ||
| 43 | |||
| 44 | #define WIZ_PLL_CTRL 0x1ff4 | ||
| 45 | #define PLL_DISABLE_STATE 0x4 | ||
| 46 | #define PLL_SLEEP_STATE 0x5 | ||
| 47 | #define PLL_SNOOZE_STATE 0x6 | ||
| 48 | #define PLL_ENABLE_STATE 0x7 | ||
| 49 | |||
| 50 | #define PLL_LOCK_TIME 100000 /* in microseconds */ | ||
| 51 | #define SLEEP_TIME 100 /* in microseconds */ | ||
| 52 | |||
| 53 | #define LANE_USB3 0x0 | ||
| 54 | #define LANE_PCIE0_LANE0 0x1 | ||
| 55 | |||
| 56 | #define LANE_PCIE1_LANE0 0x0 | ||
| 57 | #define LANE_PCIE0_LANE1 0x1 | ||
| 58 | |||
| 59 | #define SERDES_NUM_CLOCKS 3 | ||
| 60 | |||
| 61 | #define AM654_SERDES_CTRL_CLKSEL_MASK GENMASK(7, 4) | ||
| 62 | #define AM654_SERDES_CTRL_CLKSEL_SHIFT 4 | ||
| 63 | |||
| 64 | struct serdes_am654_clk_mux { | ||
| 65 | struct clk_hw hw; | ||
| 66 | struct regmap *regmap; | ||
| 67 | unsigned int reg; | ||
| 68 | int clk_id; | ||
| 69 | struct clk_init_data clk_data; | ||
| 70 | }; | ||
| 71 | |||
| 72 | #define to_serdes_am654_clk_mux(_hw) \ | ||
| 73 | container_of(_hw, struct serdes_am654_clk_mux, hw) | ||
| 74 | |||
| 75 | static struct regmap_config serdes_am654_regmap_config = { | ||
| 76 | .reg_bits = 32, | ||
| 77 | .val_bits = 32, | ||
| 78 | .reg_stride = 4, | ||
| 79 | .fast_io = true, | ||
| 80 | }; | ||
| 81 | |||
| 82 | static const struct reg_field cmu_master_cdn_o = REG_FIELD(CMU_R07C, 24, 24); | ||
| 83 | static const struct reg_field config_version = REG_FIELD(COMLANE_R138, 16, 23); | ||
| 84 | static const struct reg_field l1_master_cdn_o = REG_FIELD(COMLANE_R190, 9, 9); | ||
| 85 | static const struct reg_field cmu_ok_i_0 = REG_FIELD(COMLANE_R194, 19, 19); | ||
| 86 | static const struct reg_field por_en = REG_FIELD(SERDES_CTRL, 29, 29); | ||
| 87 | static const struct reg_field tx0_enable = REG_FIELD(WIZ_LANEXCTL_STS, 29, 31); | ||
| 88 | static const struct reg_field rx0_enable = REG_FIELD(WIZ_LANEXCTL_STS, 13, 15); | ||
| 89 | static const struct reg_field pll_enable = REG_FIELD(WIZ_PLL_CTRL, 29, 31); | ||
| 90 | static const struct reg_field pll_ok = REG_FIELD(WIZ_PLL_CTRL, 28, 28); | ||
| 91 | |||
| 92 | struct serdes_am654 { | ||
| 93 | struct regmap *regmap; | ||
| 94 | struct regmap_field *cmu_master_cdn_o; | ||
| 95 | struct regmap_field *config_version; | ||
| 96 | struct regmap_field *l1_master_cdn_o; | ||
| 97 | struct regmap_field *cmu_ok_i_0; | ||
| 98 | struct regmap_field *por_en; | ||
| 99 | struct regmap_field *tx0_enable; | ||
| 100 | struct regmap_field *rx0_enable; | ||
| 101 | struct regmap_field *pll_enable; | ||
| 102 | struct regmap_field *pll_ok; | ||
| 103 | |||
| 104 | struct device *dev; | ||
| 105 | struct mux_control *control; | ||
| 106 | bool busy; | ||
| 107 | u32 type; | ||
| 108 | struct device_node *of_node; | ||
| 109 | struct clk_onecell_data clk_data; | ||
| 110 | struct clk *clks[SERDES_NUM_CLOCKS]; | ||
| 111 | }; | ||
| 112 | |||
| 113 | static int serdes_am654_enable_pll(struct serdes_am654 *phy) | ||
| 114 | { | ||
| 115 | int ret; | ||
| 116 | u32 val; | ||
| 117 | |||
| 118 | ret = regmap_field_write(phy->pll_enable, PLL_ENABLE_STATE); | ||
| 119 | if (ret) | ||
| 120 | return ret; | ||
| 121 | |||
| 122 | return regmap_field_read_poll_timeout(phy->pll_ok, val, val, 1000, | ||
| 123 | PLL_LOCK_TIME); | ||
| 124 | } | ||
| 125 | |||
| 126 | static void serdes_am654_disable_pll(struct serdes_am654 *phy) | ||
| 127 | { | ||
| 128 | struct device *dev = phy->dev; | ||
| 129 | int ret; | ||
| 130 | |||
| 131 | ret = regmap_field_write(phy->pll_enable, PLL_DISABLE_STATE); | ||
| 132 | if (ret) | ||
| 133 | dev_err(dev, "Failed to disable PLL\n"); | ||
| 134 | } | ||
| 135 | |||
| 136 | static int serdes_am654_enable_txrx(struct serdes_am654 *phy) | ||
| 137 | { | ||
| 138 | int ret; | ||
| 139 | |||
| 140 | /* Enable TX */ | ||
| 141 | ret = regmap_field_write(phy->tx0_enable, TX0_ENABLE_STATE); | ||
| 142 | if (ret) | ||
| 143 | return ret; | ||
| 144 | |||
| 145 | /* Enable RX */ | ||
| 146 | ret = regmap_field_write(phy->rx0_enable, RX0_ENABLE_STATE); | ||
| 147 | if (ret) | ||
| 148 | return ret; | ||
| 149 | |||
| 150 | return 0; | ||
| 151 | } | ||
| 152 | |||
| 153 | static int serdes_am654_disable_txrx(struct serdes_am654 *phy) | ||
| 154 | { | ||
| 155 | int ret; | ||
| 156 | |||
| 157 | /* Disable TX */ | ||
| 158 | ret = regmap_field_write(phy->tx0_enable, TX0_DISABLE_STATE); | ||
| 159 | if (ret) | ||
| 160 | return ret; | ||
| 161 | |||
| 162 | /* Disable RX */ | ||
| 163 | ret = regmap_field_write(phy->rx0_enable, RX0_DISABLE_STATE); | ||
| 164 | if (ret) | ||
| 165 | return ret; | ||
| 166 | |||
| 167 | return 0; | ||
| 168 | } | ||
| 169 | |||
| 170 | static int serdes_am654_power_on(struct phy *x) | ||
| 171 | { | ||
| 172 | struct serdes_am654 *phy = phy_get_drvdata(x); | ||
| 173 | struct device *dev = phy->dev; | ||
| 174 | int ret; | ||
| 175 | u32 val; | ||
| 176 | |||
| 177 | ret = serdes_am654_enable_pll(phy); | ||
| 178 | if (ret) { | ||
| 179 | dev_err(dev, "Failed to enable PLL\n"); | ||
| 180 | return ret; | ||
| 181 | } | ||
| 182 | |||
| 183 | ret = serdes_am654_enable_txrx(phy); | ||
| 184 | if (ret) { | ||
| 185 | dev_err(dev, "Failed to enable TX RX\n"); | ||
| 186 | return ret; | ||
| 187 | } | ||
| 188 | |||
| 189 | return regmap_field_read_poll_timeout(phy->cmu_ok_i_0, val, val, | ||
| 190 | SLEEP_TIME, PLL_LOCK_TIME); | ||
| 191 | } | ||
| 192 | |||
| 193 | static int serdes_am654_power_off(struct phy *x) | ||
| 194 | { | ||
| 195 | struct serdes_am654 *phy = phy_get_drvdata(x); | ||
| 196 | |||
| 197 | serdes_am654_disable_txrx(phy); | ||
| 198 | serdes_am654_disable_pll(phy); | ||
| 199 | |||
| 200 | return 0; | ||
| 201 | } | ||
| 202 | |||
| 203 | static int serdes_am654_init(struct phy *x) | ||
| 204 | { | ||
| 205 | struct serdes_am654 *phy = phy_get_drvdata(x); | ||
| 206 | int ret; | ||
| 207 | |||
| 208 | ret = regmap_field_write(phy->config_version, VERSION); | ||
| 209 | if (ret) | ||
| 210 | return ret; | ||
| 211 | |||
| 212 | ret = regmap_field_write(phy->cmu_master_cdn_o, 0x1); | ||
| 213 | if (ret) | ||
| 214 | return ret; | ||
| 215 | |||
| 216 | ret = regmap_field_write(phy->l1_master_cdn_o, 0x1); | ||
| 217 | if (ret) | ||
| 218 | return ret; | ||
| 219 | |||
| 220 | return 0; | ||
| 221 | } | ||
| 222 | |||
| 223 | static int serdes_am654_reset(struct phy *x) | ||
| 224 | { | ||
| 225 | struct serdes_am654 *phy = phy_get_drvdata(x); | ||
| 226 | int ret; | ||
| 227 | |||
| 228 | ret = regmap_field_write(phy->por_en, 0x1); | ||
| 229 | if (ret) | ||
| 230 | return ret; | ||
| 231 | |||
| 232 | mdelay(1); | ||
| 233 | |||
| 234 | ret = regmap_field_write(phy->por_en, 0x0); | ||
| 235 | if (ret) | ||
| 236 | return ret; | ||
| 237 | |||
| 238 | return 0; | ||
| 239 | } | ||
| 240 | |||
| 241 | static void serdes_am654_release(struct phy *x) | ||
| 242 | { | ||
| 243 | struct serdes_am654 *phy = phy_get_drvdata(x); | ||
| 244 | |||
| 245 | phy->type = PHY_NONE; | ||
| 246 | phy->busy = false; | ||
| 247 | mux_control_deselect(phy->control); | ||
| 248 | } | ||
| 249 | |||
| 250 | struct phy *serdes_am654_xlate(struct device *dev, struct of_phandle_args | ||
| 251 | *args) | ||
| 252 | { | ||
| 253 | struct serdes_am654 *am654_phy; | ||
| 254 | struct phy *phy; | ||
| 255 | int ret; | ||
| 256 | |||
| 257 | phy = of_phy_simple_xlate(dev, args); | ||
| 258 | if (IS_ERR(phy)) | ||
| 259 | return phy; | ||
| 260 | |||
| 261 | am654_phy = phy_get_drvdata(phy); | ||
| 262 | if (am654_phy->busy) | ||
| 263 | return ERR_PTR(-EBUSY); | ||
| 264 | |||
| 265 | ret = mux_control_select(am654_phy->control, args->args[1]); | ||
| 266 | if (ret) { | ||
| 267 | dev_err(dev, "Failed to select SERDES Lane Function\n"); | ||
| 268 | return ERR_PTR(ret); | ||
| 269 | } | ||
| 270 | |||
| 271 | am654_phy->busy = true; | ||
| 272 | am654_phy->type = args->args[0]; | ||
| 273 | |||
| 274 | return phy; | ||
| 275 | } | ||
| 276 | |||
| 277 | static const struct phy_ops ops = { | ||
| 278 | .reset = serdes_am654_reset, | ||
| 279 | .init = serdes_am654_init, | ||
| 280 | .power_on = serdes_am654_power_on, | ||
| 281 | .power_off = serdes_am654_power_off, | ||
| 282 | .release = serdes_am654_release, | ||
| 283 | .owner = THIS_MODULE, | ||
| 284 | }; | ||
| 285 | |||
| 286 | #define SERDES_NUM_MUX_COMBINATIONS 16 | ||
| 287 | |||
| 288 | #define LICLK 0 | ||
| 289 | #define EXT_REFCLK 1 | ||
| 290 | #define RICLK 2 | ||
| 291 | |||
| 292 | static const int | ||
| 293 | serdes_am654_mux_table[SERDES_NUM_MUX_COMBINATIONS][SERDES_NUM_CLOCKS] = { | ||
| 294 | /* | ||
| 295 | * Each combination maps to one of | ||
| 296 | * "Figure 12-1986. SerDes Reference Clock Distribution" | ||
| 297 | * in TRM. | ||
| 298 | */ | ||
| 299 | /* Parent of CMU refclk, Left output, Right output | ||
| 300 | * either of EXT_REFCLK, LICLK, RICLK | ||
| 301 | */ | ||
| 302 | { EXT_REFCLK, EXT_REFCLK, EXT_REFCLK }, /* 0000 */ | ||
| 303 | { RICLK, EXT_REFCLK, EXT_REFCLK }, /* 0001 */ | ||
| 304 | { EXT_REFCLK, RICLK, LICLK }, /* 0010 */ | ||
| 305 | { RICLK, RICLK, EXT_REFCLK }, /* 0011 */ | ||
| 306 | { LICLK, EXT_REFCLK, EXT_REFCLK }, /* 0100 */ | ||
| 307 | { EXT_REFCLK, EXT_REFCLK, EXT_REFCLK }, /* 0101 */ | ||
| 308 | { LICLK, RICLK, LICLK }, /* 0110 */ | ||
| 309 | { EXT_REFCLK, RICLK, LICLK }, /* 0111 */ | ||
| 310 | { EXT_REFCLK, EXT_REFCLK, LICLK }, /* 1000 */ | ||
| 311 | { RICLK, EXT_REFCLK, LICLK }, /* 1001 */ | ||
| 312 | { EXT_REFCLK, RICLK, EXT_REFCLK }, /* 1010 */ | ||
| 313 | { RICLK, RICLK, EXT_REFCLK }, /* 1011 */ | ||
| 314 | { LICLK, EXT_REFCLK, LICLK }, /* 1100 */ | ||
| 315 | { EXT_REFCLK, EXT_REFCLK, LICLK }, /* 1101 */ | ||
| 316 | { LICLK, RICLK, EXT_REFCLK }, /* 1110 */ | ||
| 317 | { EXT_REFCLK, RICLK, EXT_REFCLK }, /* 1111 */ | ||
| 318 | }; | ||
| 319 | |||
| 320 | static u8 serdes_am654_clk_mux_get_parent(struct clk_hw *hw) | ||
| 321 | { | ||
| 322 | struct serdes_am654_clk_mux *mux = to_serdes_am654_clk_mux(hw); | ||
| 323 | struct regmap *regmap = mux->regmap; | ||
| 324 | unsigned int reg = mux->reg; | ||
| 325 | unsigned int val; | ||
| 326 | |||
| 327 | regmap_read(regmap, reg, &val); | ||
| 328 | val &= AM654_SERDES_CTRL_CLKSEL_MASK; | ||
| 329 | val >>= AM654_SERDES_CTRL_CLKSEL_SHIFT; | ||
| 330 | |||
| 331 | return serdes_am654_mux_table[val][mux->clk_id]; | ||
| 332 | } | ||
| 333 | |||
| 334 | static int serdes_am654_clk_mux_set_parent(struct clk_hw *hw, u8 index) | ||
| 335 | { | ||
| 336 | struct serdes_am654_clk_mux *mux = to_serdes_am654_clk_mux(hw); | ||
| 337 | struct regmap *regmap = mux->regmap; | ||
| 338 | unsigned int reg = mux->reg; | ||
| 339 | int clk_id = mux->clk_id; | ||
| 340 | int parents[SERDES_NUM_CLOCKS]; | ||
| 341 | const int *p; | ||
| 342 | u32 val; | ||
| 343 | int found, i; | ||
| 344 | int ret; | ||
| 345 | |||
| 346 | /* get existing setting */ | ||
| 347 | regmap_read(regmap, reg, &val); | ||
| 348 | val &= AM654_SERDES_CTRL_CLKSEL_MASK; | ||
| 349 | val >>= AM654_SERDES_CTRL_CLKSEL_SHIFT; | ||
| 350 | |||
| 351 | for (i = 0; i < SERDES_NUM_CLOCKS; i++) | ||
| 352 | parents[i] = serdes_am654_mux_table[val][i]; | ||
| 353 | |||
| 354 | /* change parent of this clock. others left intact */ | ||
| 355 | parents[clk_id] = index; | ||
| 356 | |||
| 357 | /* Find the match */ | ||
| 358 | for (val = 0; val < SERDES_NUM_MUX_COMBINATIONS; val++) { | ||
| 359 | p = serdes_am654_mux_table[val]; | ||
| 360 | found = 1; | ||
| 361 | for (i = 0; i < SERDES_NUM_CLOCKS; i++) { | ||
| 362 | if (parents[i] != p[i]) { | ||
| 363 | found = 0; | ||
| 364 | break; | ||
| 365 | } | ||
| 366 | } | ||
| 367 | |||
| 368 | if (found) | ||
| 369 | break; | ||
| 370 | } | ||
| 371 | |||
| 372 | if (!found) { | ||
| 373 | /* | ||
| 374 | * This can never happen, unless we missed | ||
| 375 | * a valid combination in serdes_am654_mux_table. | ||
| 376 | */ | ||
| 377 | WARN(1, "Failed to find the parent of %s clock\n", | ||
| 378 | hw->init->name); | ||
| 379 | return -EINVAL; | ||
| 380 | } | ||
| 381 | |||
| 382 | val <<= AM654_SERDES_CTRL_CLKSEL_SHIFT; | ||
| 383 | ret = regmap_update_bits(regmap, reg, AM654_SERDES_CTRL_CLKSEL_MASK, | ||
| 384 | val); | ||
| 385 | |||
| 386 | return ret; | ||
| 387 | } | ||
| 388 | |||
| 389 | static const struct clk_ops serdes_am654_clk_mux_ops = { | ||
| 390 | .set_parent = serdes_am654_clk_mux_set_parent, | ||
| 391 | .get_parent = serdes_am654_clk_mux_get_parent, | ||
| 392 | }; | ||
| 393 | |||
| 394 | static int serdes_am654_clk_register(struct serdes_am654 *am654_phy, | ||
| 395 | const char *clock_name, int clock_num) | ||
| 396 | { | ||
| 397 | struct device_node *node = am654_phy->of_node; | ||
| 398 | struct device *dev = am654_phy->dev; | ||
| 399 | struct serdes_am654_clk_mux *mux; | ||
| 400 | struct device_node *regmap_node; | ||
| 401 | const char **parent_names; | ||
| 402 | struct clk_init_data *init; | ||
| 403 | unsigned int num_parents; | ||
| 404 | struct regmap *regmap; | ||
| 405 | const __be32 *addr; | ||
| 406 | unsigned int reg; | ||
| 407 | struct clk *clk; | ||
| 408 | |||
| 409 | mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); | ||
| 410 | if (!mux) | ||
| 411 | return -ENOMEM; | ||
| 412 | |||
| 413 | init = &mux->clk_data; | ||
| 414 | |||
| 415 | regmap_node = of_parse_phandle(node, "ti,serdes-clk", 0); | ||
| 416 | of_node_put(regmap_node); | ||
| 417 | if (!regmap_node) { | ||
| 418 | dev_err(dev, "Fail to get serdes-clk node\n"); | ||
| 419 | return -ENODEV; | ||
| 420 | } | ||
| 421 | |||
| 422 | regmap = syscon_node_to_regmap(regmap_node->parent); | ||
| 423 | if (IS_ERR(regmap)) { | ||
| 424 | dev_err(dev, "Fail to get Syscon regmap\n"); | ||
| 425 | return PTR_ERR(regmap); | ||
| 426 | } | ||
| 427 | |||
| 428 | num_parents = of_clk_get_parent_count(node); | ||
| 429 | if (num_parents < 2) { | ||
| 430 | dev_err(dev, "SERDES clock must have parents\n"); | ||
| 431 | return -EINVAL; | ||
| 432 | } | ||
| 433 | |||
| 434 | parent_names = devm_kzalloc(dev, (sizeof(char *) * num_parents), | ||
| 435 | GFP_KERNEL); | ||
| 436 | if (!parent_names) | ||
| 437 | return -ENOMEM; | ||
| 438 | |||
| 439 | of_clk_parent_fill(node, parent_names, num_parents); | ||
| 440 | |||
| 441 | addr = of_get_address(regmap_node, 0, NULL, NULL); | ||
| 442 | if (!addr) | ||
| 443 | return -EINVAL; | ||
| 444 | |||
| 445 | reg = be32_to_cpu(*addr); | ||
| 446 | |||
| 447 | init->ops = &serdes_am654_clk_mux_ops; | ||
| 448 | init->flags = CLK_SET_RATE_NO_REPARENT; | ||
| 449 | init->parent_names = parent_names; | ||
| 450 | init->num_parents = num_parents; | ||
| 451 | init->name = clock_name; | ||
| 452 | |||
| 453 | mux->regmap = regmap; | ||
| 454 | mux->reg = reg; | ||
| 455 | mux->clk_id = clock_num; | ||
| 456 | mux->hw.init = init; | ||
| 457 | |||
| 458 | clk = devm_clk_register(dev, &mux->hw); | ||
| 459 | if (IS_ERR(clk)) | ||
| 460 | return PTR_ERR(clk); | ||
| 461 | |||
| 462 | am654_phy->clks[clock_num] = clk; | ||
| 463 | |||
| 464 | return 0; | ||
| 465 | } | ||
| 466 | |||
| 467 | static const struct of_device_id serdes_am654_id_table[] = { | ||
| 468 | { | ||
| 469 | .compatible = "ti,phy-am654-serdes", | ||
| 470 | }, | ||
| 471 | {} | ||
| 472 | }; | ||
| 473 | MODULE_DEVICE_TABLE(of, serdes_am654_id_table); | ||
| 474 | |||
| 475 | static int serdes_am654_regfield_init(struct serdes_am654 *am654_phy) | ||
| 476 | { | ||
| 477 | struct regmap *regmap = am654_phy->regmap; | ||
| 478 | struct device *dev = am654_phy->dev; | ||
| 479 | |||
| 480 | am654_phy->cmu_master_cdn_o = devm_regmap_field_alloc(dev, regmap, | ||
| 481 | cmu_master_cdn_o); | ||
| 482 | if (IS_ERR(am654_phy->cmu_master_cdn_o)) { | ||
| 483 | dev_err(dev, "CMU_MASTER_CDN_O reg field init failed\n"); | ||
| 484 | return PTR_ERR(am654_phy->cmu_master_cdn_o); | ||
| 485 | } | ||
| 486 | |||
| 487 | am654_phy->config_version = devm_regmap_field_alloc(dev, regmap, | ||
| 488 | config_version); | ||
| 489 | if (IS_ERR(am654_phy->config_version)) { | ||
| 490 | dev_err(dev, "CONFIG_VERSION reg field init failed\n"); | ||
| 491 | return PTR_ERR(am654_phy->config_version); | ||
| 492 | } | ||
| 493 | |||
| 494 | am654_phy->l1_master_cdn_o = devm_regmap_field_alloc(dev, regmap, | ||
| 495 | l1_master_cdn_o); | ||
| 496 | if (IS_ERR(am654_phy->l1_master_cdn_o)) { | ||
| 497 | dev_err(dev, "L1_MASTER_CDN_O reg field init failed\n"); | ||
| 498 | return PTR_ERR(am654_phy->l1_master_cdn_o); | ||
| 499 | } | ||
| 500 | |||
| 501 | am654_phy->cmu_ok_i_0 = devm_regmap_field_alloc(dev, regmap, | ||
| 502 | cmu_ok_i_0); | ||
| 503 | if (IS_ERR(am654_phy->cmu_ok_i_0)) { | ||
| 504 | dev_err(dev, "CMU_OK_I_0 reg field init failed\n"); | ||
| 505 | return PTR_ERR(am654_phy->cmu_ok_i_0); | ||
| 506 | } | ||
| 507 | |||
| 508 | am654_phy->por_en = devm_regmap_field_alloc(dev, regmap, por_en); | ||
| 509 | if (IS_ERR(am654_phy->por_en)) { | ||
| 510 | dev_err(dev, "POR_EN reg field init failed\n"); | ||
| 511 | return PTR_ERR(am654_phy->por_en); | ||
| 512 | } | ||
| 513 | |||
| 514 | am654_phy->tx0_enable = devm_regmap_field_alloc(dev, regmap, | ||
| 515 | tx0_enable); | ||
| 516 | if (IS_ERR(am654_phy->tx0_enable)) { | ||
| 517 | dev_err(dev, "TX0_ENABLE reg field init failed\n"); | ||
| 518 | return PTR_ERR(am654_phy->tx0_enable); | ||
| 519 | } | ||
| 520 | |||
| 521 | am654_phy->rx0_enable = devm_regmap_field_alloc(dev, regmap, | ||
| 522 | rx0_enable); | ||
| 523 | if (IS_ERR(am654_phy->rx0_enable)) { | ||
| 524 | dev_err(dev, "RX0_ENABLE reg field init failed\n"); | ||
| 525 | return PTR_ERR(am654_phy->rx0_enable); | ||
| 526 | } | ||
| 527 | |||
| 528 | am654_phy->pll_enable = devm_regmap_field_alloc(dev, regmap, | ||
| 529 | pll_enable); | ||
| 530 | if (IS_ERR(am654_phy->pll_enable)) { | ||
| 531 | dev_err(dev, "PLL_ENABLE reg field init failed\n"); | ||
| 532 | return PTR_ERR(am654_phy->pll_enable); | ||
| 533 | } | ||
| 534 | |||
| 535 | am654_phy->pll_ok = devm_regmap_field_alloc(dev, regmap, pll_ok); | ||
| 536 | if (IS_ERR(am654_phy->pll_ok)) { | ||
| 537 | dev_err(dev, "PLL_OK reg field init failed\n"); | ||
| 538 | return PTR_ERR(am654_phy->pll_ok); | ||
| 539 | } | ||
| 540 | |||
| 541 | return 0; | ||
| 542 | } | ||
| 543 | |||
| 544 | static int serdes_am654_probe(struct platform_device *pdev) | ||
| 545 | { | ||
| 546 | struct phy_provider *phy_provider; | ||
| 547 | struct device *dev = &pdev->dev; | ||
| 548 | struct device_node *node = dev->of_node; | ||
| 549 | struct clk_onecell_data *clk_data; | ||
| 550 | struct serdes_am654 *am654_phy; | ||
| 551 | struct mux_control *control; | ||
| 552 | const char *clock_name; | ||
| 553 | struct regmap *regmap; | ||
| 554 | void __iomem *base; | ||
| 555 | struct phy *phy; | ||
| 556 | int ret; | ||
| 557 | int i; | ||
| 558 | |||
| 559 | am654_phy = devm_kzalloc(dev, sizeof(*am654_phy), GFP_KERNEL); | ||
| 560 | if (!am654_phy) | ||
| 561 | return -ENOMEM; | ||
| 562 | |||
| 563 | base = devm_platform_ioremap_resource(pdev, 0); | ||
| 564 | if (IS_ERR(base)) | ||
| 565 | return PTR_ERR(base); | ||
| 566 | |||
| 567 | regmap = devm_regmap_init_mmio(dev, base, &serdes_am654_regmap_config); | ||
| 568 | if (IS_ERR(regmap)) { | ||
| 569 | dev_err(dev, "Failed to initialize regmap\n"); | ||
| 570 | return PTR_ERR(regmap); | ||
| 571 | } | ||
| 572 | |||
| 573 | control = devm_mux_control_get(dev, NULL); | ||
| 574 | if (IS_ERR(control)) | ||
| 575 | return PTR_ERR(control); | ||
| 576 | |||
| 577 | am654_phy->dev = dev; | ||
| 578 | am654_phy->of_node = node; | ||
| 579 | am654_phy->regmap = regmap; | ||
| 580 | am654_phy->control = control; | ||
| 581 | am654_phy->type = PHY_NONE; | ||
| 582 | |||
| 583 | ret = serdes_am654_regfield_init(am654_phy); | ||
| 584 | if (ret) { | ||
| 585 | dev_err(dev, "Failed to initialize regfields\n"); | ||
| 586 | return ret; | ||
| 587 | } | ||
| 588 | |||
| 589 | platform_set_drvdata(pdev, am654_phy); | ||
| 590 | |||
| 591 | for (i = 0; i < SERDES_NUM_CLOCKS; i++) { | ||
| 592 | ret = of_property_read_string_index(node, "clock-output-names", | ||
| 593 | i, &clock_name); | ||
| 594 | if (ret) { | ||
| 595 | dev_err(dev, "Failed to get clock name\n"); | ||
| 596 | return ret; | ||
| 597 | } | ||
| 598 | |||
| 599 | ret = serdes_am654_clk_register(am654_phy, clock_name, i); | ||
| 600 | if (ret) { | ||
| 601 | dev_err(dev, "Failed to initialize clock %s\n", | ||
| 602 | clock_name); | ||
| 603 | return ret; | ||
| 604 | } | ||
| 605 | } | ||
| 606 | |||
| 607 | clk_data = &am654_phy->clk_data; | ||
| 608 | clk_data->clks = am654_phy->clks; | ||
| 609 | clk_data->clk_num = SERDES_NUM_CLOCKS; | ||
| 610 | ret = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); | ||
| 611 | if (ret) | ||
| 612 | return ret; | ||
| 613 | |||
| 614 | pm_runtime_enable(dev); | ||
| 615 | |||
| 616 | phy = devm_phy_create(dev, NULL, &ops); | ||
| 617 | if (IS_ERR(phy)) | ||
| 618 | return PTR_ERR(phy); | ||
| 619 | |||
| 620 | phy_set_drvdata(phy, am654_phy); | ||
| 621 | phy_provider = devm_of_phy_provider_register(dev, serdes_am654_xlate); | ||
| 622 | if (IS_ERR(phy_provider)) { | ||
| 623 | ret = PTR_ERR(phy_provider); | ||
| 624 | goto clk_err; | ||
| 625 | } | ||
| 626 | |||
| 627 | return 0; | ||
| 628 | |||
| 629 | clk_err: | ||
| 630 | of_clk_del_provider(node); | ||
| 631 | |||
| 632 | return ret; | ||
| 633 | } | ||
| 634 | |||
| 635 | static int serdes_am654_remove(struct platform_device *pdev) | ||
| 636 | { | ||
| 637 | struct serdes_am654 *am654_phy = platform_get_drvdata(pdev); | ||
| 638 | struct device_node *node = am654_phy->of_node; | ||
| 639 | |||
| 640 | pm_runtime_disable(&pdev->dev); | ||
| 641 | of_clk_del_provider(node); | ||
| 642 | |||
| 643 | return 0; | ||
| 644 | } | ||
| 645 | |||
| 646 | static struct platform_driver serdes_am654_driver = { | ||
| 647 | .probe = serdes_am654_probe, | ||
| 648 | .remove = serdes_am654_remove, | ||
| 649 | .driver = { | ||
| 650 | .name = "phy-am654", | ||
| 651 | .of_match_table = serdes_am654_id_table, | ||
| 652 | }, | ||
| 653 | }; | ||
| 654 | module_platform_driver(serdes_am654_driver); | ||
| 655 | |||
| 656 | MODULE_AUTHOR("Texas Instruments Inc."); | ||
| 657 | MODULE_DESCRIPTION("TI AM654x SERDES driver"); | ||
| 658 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/phy/ti/phy-ti-pipe3.c b/drivers/phy/ti/phy-ti-pipe3.c index 68ce4a082b9b..739aaa0eb0ef 100644 --- a/drivers/phy/ti/phy-ti-pipe3.c +++ b/drivers/phy/ti/phy-ti-pipe3.c | |||
| @@ -56,51 +56,73 @@ | |||
| 56 | 56 | ||
| 57 | #define SATA_PLL_SOFT_RESET BIT(18) | 57 | #define SATA_PLL_SOFT_RESET BIT(18) |
| 58 | 58 | ||
| 59 | #define PIPE3_PHY_PWRCTL_CLK_CMD_MASK 0x003FC000 | 59 | #define PIPE3_PHY_PWRCTL_CLK_CMD_MASK GENMASK(21, 14) |
| 60 | #define PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT 14 | 60 | #define PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT 14 |
| 61 | 61 | ||
| 62 | #define PIPE3_PHY_PWRCTL_CLK_FREQ_MASK 0xFFC00000 | 62 | #define PIPE3_PHY_PWRCTL_CLK_FREQ_MASK GENMASK(31, 22) |
| 63 | #define PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT 22 | 63 | #define PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT 22 |
| 64 | 64 | ||
| 65 | #define PIPE3_PHY_TX_RX_POWERON 0x3 | 65 | #define PIPE3_PHY_RX_POWERON (0x1 << PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT) |
| 66 | #define PIPE3_PHY_TX_RX_POWEROFF 0x0 | 66 | #define PIPE3_PHY_TX_POWERON (0x2 << PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT) |
| 67 | 67 | ||
| 68 | #define PCIE_PCS_MASK 0xFF0000 | 68 | #define PCIE_PCS_MASK 0xFF0000 |
| 69 | #define PCIE_PCS_DELAY_COUNT_SHIFT 0x10 | 69 | #define PCIE_PCS_DELAY_COUNT_SHIFT 0x10 |
| 70 | 70 | ||
| 71 | #define PCIEPHYRX_ANA_PROGRAMMABILITY 0x0000000C | 71 | #define PIPE3_PHY_RX_ANA_PROGRAMMABILITY 0x0000000C |
| 72 | #define INTERFACE_MASK GENMASK(31, 27) | 72 | #define INTERFACE_MASK GENMASK(31, 27) |
| 73 | #define INTERFACE_SHIFT 27 | 73 | #define INTERFACE_SHIFT 27 |
| 74 | #define INTERFACE_MODE_USBSS BIT(4) | ||
| 75 | #define INTERFACE_MODE_SATA_1P5 BIT(3) | ||
| 76 | #define INTERFACE_MODE_SATA_3P0 BIT(2) | ||
| 77 | #define INTERFACE_MODE_PCIE BIT(0) | ||
| 78 | |||
| 74 | #define LOSD_MASK GENMASK(17, 14) | 79 | #define LOSD_MASK GENMASK(17, 14) |
| 75 | #define LOSD_SHIFT 14 | 80 | #define LOSD_SHIFT 14 |
| 76 | #define MEM_PLLDIV GENMASK(6, 5) | 81 | #define MEM_PLLDIV GENMASK(6, 5) |
| 77 | 82 | ||
| 78 | #define PCIEPHYRX_TRIM 0x0000001C | 83 | #define PIPE3_PHY_RX_TRIM 0x0000001C |
| 79 | #define MEM_DLL_TRIM_SEL GENMASK(31, 30) | 84 | #define MEM_DLL_TRIM_SEL_MASK GENMASK(31, 30) |
| 80 | #define MEM_DLL_TRIM_SHIFT 30 | 85 | #define MEM_DLL_TRIM_SHIFT 30 |
| 81 | 86 | ||
| 82 | #define PCIEPHYRX_DLL 0x00000024 | 87 | #define PIPE3_PHY_RX_DLL 0x00000024 |
| 83 | #define MEM_DLL_PHINT_RATE GENMASK(31, 30) | 88 | #define MEM_DLL_PHINT_RATE_MASK GENMASK(31, 30) |
| 89 | #define MEM_DLL_PHINT_RATE_SHIFT 30 | ||
| 84 | 90 | ||
| 85 | #define PCIEPHYRX_DIGITAL_MODES 0x00000028 | 91 | #define PIPE3_PHY_RX_DIGITAL_MODES 0x00000028 |
| 92 | #define MEM_HS_RATE_MASK GENMASK(28, 27) | ||
| 93 | #define MEM_HS_RATE_SHIFT 27 | ||
| 94 | #define MEM_OVRD_HS_RATE BIT(26) | ||
| 95 | #define MEM_OVRD_HS_RATE_SHIFT 26 | ||
| 86 | #define MEM_CDR_FASTLOCK BIT(23) | 96 | #define MEM_CDR_FASTLOCK BIT(23) |
| 87 | #define MEM_CDR_LBW GENMASK(22, 21) | 97 | #define MEM_CDR_FASTLOCK_SHIFT 23 |
| 88 | #define MEM_CDR_STEPCNT GENMASK(20, 19) | 98 | #define MEM_CDR_LBW_MASK GENMASK(22, 21) |
| 99 | #define MEM_CDR_LBW_SHIFT 21 | ||
| 100 | #define MEM_CDR_STEPCNT_MASK GENMASK(20, 19) | ||
| 101 | #define MEM_CDR_STEPCNT_SHIFT 19 | ||
| 89 | #define MEM_CDR_STL_MASK GENMASK(18, 16) | 102 | #define MEM_CDR_STL_MASK GENMASK(18, 16) |
| 90 | #define MEM_CDR_STL_SHIFT 16 | 103 | #define MEM_CDR_STL_SHIFT 16 |
| 91 | #define MEM_CDR_THR_MASK GENMASK(15, 13) | 104 | #define MEM_CDR_THR_MASK GENMASK(15, 13) |
| 92 | #define MEM_CDR_THR_SHIFT 13 | 105 | #define MEM_CDR_THR_SHIFT 13 |
| 93 | #define MEM_CDR_THR_MODE BIT(12) | 106 | #define MEM_CDR_THR_MODE BIT(12) |
| 94 | #define MEM_CDR_CDR_2NDO_SDM_MODE BIT(11) | 107 | #define MEM_CDR_THR_MODE_SHIFT 12 |
| 95 | #define MEM_OVRD_HS_RATE BIT(26) | 108 | #define MEM_CDR_2NDO_SDM_MODE BIT(11) |
| 96 | 109 | #define MEM_CDR_2NDO_SDM_MODE_SHIFT 11 | |
| 97 | #define PCIEPHYRX_EQUALIZER 0x00000038 | 110 | |
| 98 | #define MEM_EQLEV GENMASK(31, 16) | 111 | #define PIPE3_PHY_RX_EQUALIZER 0x00000038 |
| 99 | #define MEM_EQFTC GENMASK(15, 11) | 112 | #define MEM_EQLEV_MASK GENMASK(31, 16) |
| 100 | #define MEM_EQCTL GENMASK(10, 7) | 113 | #define MEM_EQLEV_SHIFT 16 |
| 114 | #define MEM_EQFTC_MASK GENMASK(15, 11) | ||
| 115 | #define MEM_EQFTC_SHIFT 11 | ||
| 116 | #define MEM_EQCTL_MASK GENMASK(10, 7) | ||
| 101 | #define MEM_EQCTL_SHIFT 7 | 117 | #define MEM_EQCTL_SHIFT 7 |
| 102 | #define MEM_OVRD_EQLEV BIT(2) | 118 | #define MEM_OVRD_EQLEV BIT(2) |
| 119 | #define MEM_OVRD_EQLEV_SHIFT 2 | ||
| 103 | #define MEM_OVRD_EQFTC BIT(1) | 120 | #define MEM_OVRD_EQFTC BIT(1) |
| 121 | #define MEM_OVRD_EQFTC_SHIFT 1 | ||
| 122 | |||
| 123 | #define SATA_PHY_RX_IO_AND_A2D_OVERRIDES 0x44 | ||
| 124 | #define MEM_CDR_LOS_SOURCE_MASK GENMASK(10, 9) | ||
| 125 | #define MEM_CDR_LOS_SOURCE_SHIFT 9 | ||
| 104 | 126 | ||
| 105 | /* | 127 | /* |
| 106 | * This is an Empirical value that works, need to confirm the actual | 128 | * This is an Empirical value that works, need to confirm the actual |
| @@ -110,6 +132,10 @@ | |||
| 110 | #define PLL_IDLE_TIME 100 /* in milliseconds */ | 132 | #define PLL_IDLE_TIME 100 /* in milliseconds */ |
| 111 | #define PLL_LOCK_TIME 100 /* in milliseconds */ | 133 | #define PLL_LOCK_TIME 100 /* in milliseconds */ |
| 112 | 134 | ||
| 135 | enum pipe3_mode { PIPE3_MODE_PCIE = 1, | ||
| 136 | PIPE3_MODE_SATA, | ||
| 137 | PIPE3_MODE_USBSS }; | ||
| 138 | |||
| 113 | struct pipe3_dpll_params { | 139 | struct pipe3_dpll_params { |
| 114 | u16 m; | 140 | u16 m; |
| 115 | u8 n; | 141 | u8 n; |
| @@ -123,6 +149,27 @@ struct pipe3_dpll_map { | |||
| 123 | struct pipe3_dpll_params params; | 149 | struct pipe3_dpll_params params; |
| 124 | }; | 150 | }; |
| 125 | 151 | ||
| 152 | struct pipe3_settings { | ||
| 153 | u8 ana_interface; | ||
| 154 | u8 ana_losd; | ||
| 155 | u8 dig_fastlock; | ||
| 156 | u8 dig_lbw; | ||
| 157 | u8 dig_stepcnt; | ||
| 158 | u8 dig_stl; | ||
| 159 | u8 dig_thr; | ||
| 160 | u8 dig_thr_mode; | ||
| 161 | u8 dig_2ndo_sdm_mode; | ||
| 162 | u8 dig_hs_rate; | ||
| 163 | u8 dig_ovrd_hs_rate; | ||
| 164 | u8 dll_trim_sel; | ||
| 165 | u8 dll_phint_rate; | ||
| 166 | u8 eq_lev; | ||
| 167 | u8 eq_ftc; | ||
| 168 | u8 eq_ctl; | ||
| 169 | u8 eq_ovrd_lev; | ||
| 170 | u8 eq_ovrd_ftc; | ||
| 171 | }; | ||
| 172 | |||
| 126 | struct ti_pipe3 { | 173 | struct ti_pipe3 { |
| 127 | void __iomem *pll_ctrl_base; | 174 | void __iomem *pll_ctrl_base; |
| 128 | void __iomem *phy_rx; | 175 | void __iomem *phy_rx; |
| @@ -141,6 +188,8 @@ struct ti_pipe3 { | |||
| 141 | unsigned int power_reg; /* power reg. index within syscon */ | 188 | unsigned int power_reg; /* power reg. index within syscon */ |
| 142 | unsigned int pcie_pcs_reg; /* pcs reg. index in syscon */ | 189 | unsigned int pcie_pcs_reg; /* pcs reg. index in syscon */ |
| 143 | bool sata_refclk_enabled; | 190 | bool sata_refclk_enabled; |
| 191 | enum pipe3_mode mode; | ||
| 192 | struct pipe3_settings settings; | ||
| 144 | }; | 193 | }; |
| 145 | 194 | ||
| 146 | static struct pipe3_dpll_map dpll_map_usb[] = { | 195 | static struct pipe3_dpll_map dpll_map_usb[] = { |
| @@ -163,6 +212,89 @@ static struct pipe3_dpll_map dpll_map_sata[] = { | |||
| 163 | { }, /* Terminator */ | 212 | { }, /* Terminator */ |
| 164 | }; | 213 | }; |
| 165 | 214 | ||
| 215 | struct pipe3_data { | ||
| 216 | enum pipe3_mode mode; | ||
| 217 | struct pipe3_dpll_map *dpll_map; | ||
| 218 | struct pipe3_settings settings; | ||
| 219 | }; | ||
| 220 | |||
| 221 | static struct pipe3_data data_usb = { | ||
| 222 | .mode = PIPE3_MODE_USBSS, | ||
| 223 | .dpll_map = dpll_map_usb, | ||
| 224 | .settings = { | ||
| 225 | /* DRA75x TRM Table 26-17 Preferred USB3_PHY_RX SCP Register Settings */ | ||
| 226 | .ana_interface = INTERFACE_MODE_USBSS, | ||
| 227 | .ana_losd = 0xa, | ||
| 228 | .dig_fastlock = 1, | ||
| 229 | .dig_lbw = 3, | ||
| 230 | .dig_stepcnt = 0, | ||
| 231 | .dig_stl = 0x3, | ||
| 232 | .dig_thr = 1, | ||
| 233 | .dig_thr_mode = 1, | ||
| 234 | .dig_2ndo_sdm_mode = 0, | ||
| 235 | .dig_hs_rate = 0, | ||
| 236 | .dig_ovrd_hs_rate = 1, | ||
| 237 | .dll_trim_sel = 0x2, | ||
| 238 | .dll_phint_rate = 0x3, | ||
| 239 | .eq_lev = 0, | ||
| 240 | .eq_ftc = 0, | ||
| 241 | .eq_ctl = 0x9, | ||
| 242 | .eq_ovrd_lev = 0, | ||
| 243 | .eq_ovrd_ftc = 0, | ||
| 244 | }, | ||
| 245 | }; | ||
| 246 | |||
| 247 | static struct pipe3_data data_sata = { | ||
| 248 | .mode = PIPE3_MODE_SATA, | ||
| 249 | .dpll_map = dpll_map_sata, | ||
| 250 | .settings = { | ||
| 251 | /* DRA75x TRM Table 26-9 Preferred SATA_PHY_RX SCP Register Settings */ | ||
| 252 | .ana_interface = INTERFACE_MODE_SATA_3P0, | ||
| 253 | .ana_losd = 0x5, | ||
| 254 | .dig_fastlock = 1, | ||
| 255 | .dig_lbw = 3, | ||
| 256 | .dig_stepcnt = 0, | ||
| 257 | .dig_stl = 0x3, | ||
| 258 | .dig_thr = 1, | ||
| 259 | .dig_thr_mode = 1, | ||
| 260 | .dig_2ndo_sdm_mode = 0, | ||
| 261 | .dig_hs_rate = 0, /* Not in TRM preferred settings */ | ||
| 262 | .dig_ovrd_hs_rate = 0, /* Not in TRM preferred settings */ | ||
| 263 | .dll_trim_sel = 0x1, | ||
| 264 | .dll_phint_rate = 0x2, /* for 1.5 GHz DPLL clock */ | ||
| 265 | .eq_lev = 0, | ||
| 266 | .eq_ftc = 0x1f, | ||
| 267 | .eq_ctl = 0, | ||
| 268 | .eq_ovrd_lev = 1, | ||
| 269 | .eq_ovrd_ftc = 1, | ||
| 270 | }, | ||
| 271 | }; | ||
| 272 | |||
| 273 | static struct pipe3_data data_pcie = { | ||
| 274 | .mode = PIPE3_MODE_PCIE, | ||
| 275 | .settings = { | ||
| 276 | /* DRA75x TRM Table 26-62 Preferred PCIe_PHY_RX SCP Register Settings */ | ||
| 277 | .ana_interface = INTERFACE_MODE_PCIE, | ||
| 278 | .ana_losd = 0xa, | ||
| 279 | .dig_fastlock = 1, | ||
| 280 | .dig_lbw = 3, | ||
| 281 | .dig_stepcnt = 0, | ||
| 282 | .dig_stl = 0x3, | ||
| 283 | .dig_thr = 1, | ||
| 284 | .dig_thr_mode = 1, | ||
| 285 | .dig_2ndo_sdm_mode = 0, | ||
| 286 | .dig_hs_rate = 0, | ||
| 287 | .dig_ovrd_hs_rate = 0, | ||
| 288 | .dll_trim_sel = 0x2, | ||
| 289 | .dll_phint_rate = 0x3, | ||
| 290 | .eq_lev = 0, | ||
| 291 | .eq_ftc = 0x1f, | ||
| 292 | .eq_ctl = 1, | ||
| 293 | .eq_ovrd_lev = 0, | ||
| 294 | .eq_ovrd_ftc = 0, | ||
| 295 | }, | ||
| 296 | }; | ||
| 297 | |||
| 166 | static inline u32 ti_pipe3_readl(void __iomem *addr, unsigned offset) | 298 | static inline u32 ti_pipe3_readl(void __iomem *addr, unsigned offset) |
| 167 | { | 299 | { |
| 168 | return __raw_readl(addr + offset); | 300 | return __raw_readl(addr + offset); |
| @@ -196,7 +328,6 @@ static void ti_pipe3_disable_clocks(struct ti_pipe3 *phy); | |||
| 196 | 328 | ||
| 197 | static int ti_pipe3_power_off(struct phy *x) | 329 | static int ti_pipe3_power_off(struct phy *x) |
| 198 | { | 330 | { |
| 199 | u32 val; | ||
| 200 | int ret; | 331 | int ret; |
| 201 | struct ti_pipe3 *phy = phy_get_drvdata(x); | 332 | struct ti_pipe3 *phy = phy_get_drvdata(x); |
| 202 | 333 | ||
| @@ -205,13 +336,13 @@ static int ti_pipe3_power_off(struct phy *x) | |||
| 205 | return 0; | 336 | return 0; |
| 206 | } | 337 | } |
| 207 | 338 | ||
| 208 | val = PIPE3_PHY_TX_RX_POWEROFF << PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT; | ||
| 209 | |||
| 210 | ret = regmap_update_bits(phy->phy_power_syscon, phy->power_reg, | 339 | ret = regmap_update_bits(phy->phy_power_syscon, phy->power_reg, |
| 211 | PIPE3_PHY_PWRCTL_CLK_CMD_MASK, val); | 340 | PIPE3_PHY_PWRCTL_CLK_CMD_MASK, 0); |
| 212 | return ret; | 341 | return ret; |
| 213 | } | 342 | } |
| 214 | 343 | ||
| 344 | static void ti_pipe3_calibrate(struct ti_pipe3 *phy); | ||
| 345 | |||
| 215 | static int ti_pipe3_power_on(struct phy *x) | 346 | static int ti_pipe3_power_on(struct phy *x) |
| 216 | { | 347 | { |
| 217 | u32 val; | 348 | u32 val; |
| @@ -219,6 +350,7 @@ static int ti_pipe3_power_on(struct phy *x) | |||
| 219 | int ret; | 350 | int ret; |
| 220 | unsigned long rate; | 351 | unsigned long rate; |
| 221 | struct ti_pipe3 *phy = phy_get_drvdata(x); | 352 | struct ti_pipe3 *phy = phy_get_drvdata(x); |
| 353 | bool rx_pending = false; | ||
| 222 | 354 | ||
| 223 | if (!phy->phy_power_syscon) { | 355 | if (!phy->phy_power_syscon) { |
| 224 | omap_control_phy_power(phy->control_dev, 1); | 356 | omap_control_phy_power(phy->control_dev, 1); |
| @@ -231,14 +363,35 @@ static int ti_pipe3_power_on(struct phy *x) | |||
| 231 | return -EINVAL; | 363 | return -EINVAL; |
| 232 | } | 364 | } |
| 233 | rate = rate / 1000000; | 365 | rate = rate / 1000000; |
| 234 | mask = OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK | | 366 | mask = OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_MASK; |
| 235 | OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_MASK; | 367 | val = rate << OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT; |
| 236 | val = PIPE3_PHY_TX_RX_POWERON << PIPE3_PHY_PWRCTL_CLK_CMD_SHIFT; | ||
| 237 | val |= rate << OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_FREQ_SHIFT; | ||
| 238 | |||
| 239 | ret = regmap_update_bits(phy->phy_power_syscon, phy->power_reg, | 368 | ret = regmap_update_bits(phy->phy_power_syscon, phy->power_reg, |
| 240 | mask, val); | 369 | mask, val); |
| 241 | return ret; | 370 | /* |
| 371 | * For PCIe, TX and RX must be powered on simultaneously. | ||
| 372 | * For USB and SATA, TX must be powered on before RX | ||
| 373 | */ | ||
| 374 | mask = OMAP_CTRL_PIPE3_PHY_PWRCTL_CLK_CMD_MASK; | ||
| 375 | if (phy->mode == PIPE3_MODE_SATA || phy->mode == PIPE3_MODE_USBSS) { | ||
| 376 | val = PIPE3_PHY_TX_POWERON; | ||
| 377 | rx_pending = true; | ||
| 378 | } else { | ||
| 379 | val = PIPE3_PHY_TX_POWERON | PIPE3_PHY_RX_POWERON; | ||
| 380 | } | ||
| 381 | |||
| 382 | regmap_update_bits(phy->phy_power_syscon, phy->power_reg, | ||
| 383 | mask, val); | ||
| 384 | |||
| 385 | if (rx_pending) { | ||
| 386 | val = PIPE3_PHY_TX_POWERON | PIPE3_PHY_RX_POWERON; | ||
| 387 | regmap_update_bits(phy->phy_power_syscon, phy->power_reg, | ||
| 388 | mask, val); | ||
| 389 | } | ||
| 390 | |||
| 391 | if (phy->mode == PIPE3_MODE_PCIE) | ||
| 392 | ti_pipe3_calibrate(phy); | ||
| 393 | |||
| 394 | return 0; | ||
| 242 | } | 395 | } |
| 243 | 396 | ||
| 244 | static int ti_pipe3_dpll_wait_lock(struct ti_pipe3 *phy) | 397 | static int ti_pipe3_dpll_wait_lock(struct ti_pipe3 *phy) |
| @@ -300,32 +453,55 @@ static int ti_pipe3_dpll_program(struct ti_pipe3 *phy) | |||
| 300 | static void ti_pipe3_calibrate(struct ti_pipe3 *phy) | 453 | static void ti_pipe3_calibrate(struct ti_pipe3 *phy) |
| 301 | { | 454 | { |
| 302 | u32 val; | 455 | u32 val; |
| 456 | struct pipe3_settings *s = &phy->settings; | ||
| 303 | 457 | ||
| 304 | val = ti_pipe3_readl(phy->phy_rx, PCIEPHYRX_ANA_PROGRAMMABILITY); | 458 | val = ti_pipe3_readl(phy->phy_rx, PIPE3_PHY_RX_ANA_PROGRAMMABILITY); |
| 305 | val &= ~(INTERFACE_MASK | LOSD_MASK | MEM_PLLDIV); | 459 | val &= ~(INTERFACE_MASK | LOSD_MASK | MEM_PLLDIV); |
| 306 | val = (0x1 << INTERFACE_SHIFT | 0xA << LOSD_SHIFT); | 460 | val |= (s->ana_interface << INTERFACE_SHIFT | s->ana_losd << LOSD_SHIFT); |
| 307 | ti_pipe3_writel(phy->phy_rx, PCIEPHYRX_ANA_PROGRAMMABILITY, val); | 461 | ti_pipe3_writel(phy->phy_rx, PIPE3_PHY_RX_ANA_PROGRAMMABILITY, val); |
| 308 | 462 | ||
| 309 | val = ti_pipe3_readl(phy->phy_rx, PCIEPHYRX_DIGITAL_MODES); | 463 | val = ti_pipe3_readl(phy->phy_rx, PIPE3_PHY_RX_DIGITAL_MODES); |
| 310 | val &= ~(MEM_CDR_STEPCNT | MEM_CDR_STL_MASK | MEM_CDR_THR_MASK | | 464 | val &= ~(MEM_HS_RATE_MASK | MEM_OVRD_HS_RATE | MEM_CDR_FASTLOCK | |
| 311 | MEM_CDR_CDR_2NDO_SDM_MODE | MEM_OVRD_HS_RATE); | 465 | MEM_CDR_LBW_MASK | MEM_CDR_STEPCNT_MASK | MEM_CDR_STL_MASK | |
| 312 | val |= (MEM_CDR_FASTLOCK | MEM_CDR_LBW | 0x3 << MEM_CDR_STL_SHIFT | | 466 | MEM_CDR_THR_MASK | MEM_CDR_THR_MODE | MEM_CDR_2NDO_SDM_MODE); |
| 313 | 0x1 << MEM_CDR_THR_SHIFT | MEM_CDR_THR_MODE); | 467 | val |= s->dig_hs_rate << MEM_HS_RATE_SHIFT | |
| 314 | ti_pipe3_writel(phy->phy_rx, PCIEPHYRX_DIGITAL_MODES, val); | 468 | s->dig_ovrd_hs_rate << MEM_OVRD_HS_RATE_SHIFT | |
| 315 | 469 | s->dig_fastlock << MEM_CDR_FASTLOCK_SHIFT | | |
| 316 | val = ti_pipe3_readl(phy->phy_rx, PCIEPHYRX_TRIM); | 470 | s->dig_lbw << MEM_CDR_LBW_SHIFT | |
| 317 | val &= ~MEM_DLL_TRIM_SEL; | 471 | s->dig_stepcnt << MEM_CDR_STEPCNT_SHIFT | |
| 318 | val |= 0x2 << MEM_DLL_TRIM_SHIFT; | 472 | s->dig_stl << MEM_CDR_STL_SHIFT | |
| 319 | ti_pipe3_writel(phy->phy_rx, PCIEPHYRX_TRIM, val); | 473 | s->dig_thr << MEM_CDR_THR_SHIFT | |
| 320 | 474 | s->dig_thr_mode << MEM_CDR_THR_MODE_SHIFT | | |
| 321 | val = ti_pipe3_readl(phy->phy_rx, PCIEPHYRX_DLL); | 475 | s->dig_2ndo_sdm_mode << MEM_CDR_2NDO_SDM_MODE_SHIFT; |
| 322 | val |= MEM_DLL_PHINT_RATE; | 476 | ti_pipe3_writel(phy->phy_rx, PIPE3_PHY_RX_DIGITAL_MODES, val); |
| 323 | ti_pipe3_writel(phy->phy_rx, PCIEPHYRX_DLL, val); | 477 | |
| 324 | 478 | val = ti_pipe3_readl(phy->phy_rx, PIPE3_PHY_RX_TRIM); | |
| 325 | val = ti_pipe3_readl(phy->phy_rx, PCIEPHYRX_EQUALIZER); | 479 | val &= ~MEM_DLL_TRIM_SEL_MASK; |
| 326 | val &= ~(MEM_EQLEV | MEM_EQCTL | MEM_OVRD_EQLEV | MEM_OVRD_EQFTC); | 480 | val |= s->dll_trim_sel << MEM_DLL_TRIM_SHIFT; |
| 327 | val |= MEM_EQFTC | 0x1 << MEM_EQCTL_SHIFT; | 481 | ti_pipe3_writel(phy->phy_rx, PIPE3_PHY_RX_TRIM, val); |
| 328 | ti_pipe3_writel(phy->phy_rx, PCIEPHYRX_EQUALIZER, val); | 482 | |
| 483 | val = ti_pipe3_readl(phy->phy_rx, PIPE3_PHY_RX_DLL); | ||
| 484 | val &= ~MEM_DLL_PHINT_RATE_MASK; | ||
| 485 | val |= s->dll_phint_rate << MEM_DLL_PHINT_RATE_SHIFT; | ||
| 486 | ti_pipe3_writel(phy->phy_rx, PIPE3_PHY_RX_DLL, val); | ||
| 487 | |||
| 488 | val = ti_pipe3_readl(phy->phy_rx, PIPE3_PHY_RX_EQUALIZER); | ||
| 489 | val &= ~(MEM_EQLEV_MASK | MEM_EQFTC_MASK | MEM_EQCTL_MASK | | ||
| 490 | MEM_OVRD_EQLEV | MEM_OVRD_EQFTC); | ||
| 491 | val |= s->eq_lev << MEM_EQLEV_SHIFT | | ||
| 492 | s->eq_ftc << MEM_EQFTC_SHIFT | | ||
| 493 | s->eq_ctl << MEM_EQCTL_SHIFT | | ||
| 494 | s->eq_ovrd_lev << MEM_OVRD_EQLEV_SHIFT | | ||
| 495 | s->eq_ovrd_ftc << MEM_OVRD_EQFTC_SHIFT; | ||
| 496 | ti_pipe3_writel(phy->phy_rx, PIPE3_PHY_RX_EQUALIZER, val); | ||
| 497 | |||
| 498 | if (phy->mode == PIPE3_MODE_SATA) { | ||
| 499 | val = ti_pipe3_readl(phy->phy_rx, | ||
| 500 | SATA_PHY_RX_IO_AND_A2D_OVERRIDES); | ||
| 501 | val &= ~MEM_CDR_LOS_SOURCE_MASK; | ||
| 502 | ti_pipe3_writel(phy->phy_rx, SATA_PHY_RX_IO_AND_A2D_OVERRIDES, | ||
| 503 | val); | ||
| 504 | } | ||
| 329 | } | 505 | } |
| 330 | 506 | ||
| 331 | static int ti_pipe3_init(struct phy *x) | 507 | static int ti_pipe3_init(struct phy *x) |
| @@ -340,7 +516,7 @@ static int ti_pipe3_init(struct phy *x) | |||
| 340 | * as recommended in AM572x TRM SPRUHZ6, section 18.5.2.2, table | 516 | * as recommended in AM572x TRM SPRUHZ6, section 18.5.2.2, table |
| 341 | * 18-1804. | 517 | * 18-1804. |
| 342 | */ | 518 | */ |
| 343 | if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-pcie")) { | 519 | if (phy->mode == PIPE3_MODE_PCIE) { |
| 344 | if (!phy->pcs_syscon) { | 520 | if (!phy->pcs_syscon) { |
| 345 | omap_control_pcie_pcs(phy->control_dev, 0x96); | 521 | omap_control_pcie_pcs(phy->control_dev, 0x96); |
| 346 | return 0; | 522 | return 0; |
| @@ -349,12 +525,7 @@ static int ti_pipe3_init(struct phy *x) | |||
| 349 | val = 0x96 << OMAP_CTRL_PCIE_PCS_DELAY_COUNT_SHIFT; | 525 | val = 0x96 << OMAP_CTRL_PCIE_PCS_DELAY_COUNT_SHIFT; |
| 350 | ret = regmap_update_bits(phy->pcs_syscon, phy->pcie_pcs_reg, | 526 | ret = regmap_update_bits(phy->pcs_syscon, phy->pcie_pcs_reg, |
| 351 | PCIE_PCS_MASK, val); | 527 | PCIE_PCS_MASK, val); |
| 352 | if (ret) | 528 | return ret; |
| 353 | return ret; | ||
| 354 | |||
| 355 | ti_pipe3_calibrate(phy); | ||
| 356 | |||
| 357 | return 0; | ||
| 358 | } | 529 | } |
| 359 | 530 | ||
| 360 | /* Bring it out of IDLE if it is IDLE */ | 531 | /* Bring it out of IDLE if it is IDLE */ |
| @@ -367,8 +538,7 @@ static int ti_pipe3_init(struct phy *x) | |||
| 367 | 538 | ||
| 368 | /* SATA has issues if re-programmed when locked */ | 539 | /* SATA has issues if re-programmed when locked */ |
| 369 | val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS); | 540 | val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_STATUS); |
| 370 | if ((val & PLL_LOCK) && of_device_is_compatible(phy->dev->of_node, | 541 | if ((val & PLL_LOCK) && phy->mode == PIPE3_MODE_SATA) |
| 371 | "ti,phy-pipe3-sata")) | ||
| 372 | return ret; | 542 | return ret; |
| 373 | 543 | ||
| 374 | /* Program the DPLL */ | 544 | /* Program the DPLL */ |
| @@ -378,6 +548,8 @@ static int ti_pipe3_init(struct phy *x) | |||
| 378 | return -EINVAL; | 548 | return -EINVAL; |
| 379 | } | 549 | } |
| 380 | 550 | ||
| 551 | ti_pipe3_calibrate(phy); | ||
| 552 | |||
| 381 | return ret; | 553 | return ret; |
| 382 | } | 554 | } |
| 383 | 555 | ||
| @@ -390,12 +562,11 @@ static int ti_pipe3_exit(struct phy *x) | |||
| 390 | /* If dpll_reset_syscon is not present we wont power down SATA DPLL | 562 | /* If dpll_reset_syscon is not present we wont power down SATA DPLL |
| 391 | * due to Errata i783 | 563 | * due to Errata i783 |
| 392 | */ | 564 | */ |
| 393 | if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata") && | 565 | if (phy->mode == PIPE3_MODE_SATA && !phy->dpll_reset_syscon) |
| 394 | !phy->dpll_reset_syscon) | ||
| 395 | return 0; | 566 | return 0; |
| 396 | 567 | ||
| 397 | /* PCIe doesn't have internal DPLL */ | 568 | /* PCIe doesn't have internal DPLL */ |
| 398 | if (!of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-pcie")) { | 569 | if (phy->mode != PIPE3_MODE_PCIE) { |
| 399 | /* Put DPLL in IDLE mode */ | 570 | /* Put DPLL in IDLE mode */ |
| 400 | val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2); | 571 | val = ti_pipe3_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2); |
| 401 | val |= PLL_IDLE; | 572 | val |= PLL_IDLE; |
| @@ -418,7 +589,7 @@ static int ti_pipe3_exit(struct phy *x) | |||
| 418 | } | 589 | } |
| 419 | 590 | ||
| 420 | /* i783: SATA needs control bit toggle after PLL unlock */ | 591 | /* i783: SATA needs control bit toggle after PLL unlock */ |
| 421 | if (of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata")) { | 592 | if (phy->mode == PIPE3_MODE_SATA) { |
| 422 | regmap_update_bits(phy->dpll_reset_syscon, phy->dpll_reset_reg, | 593 | regmap_update_bits(phy->dpll_reset_syscon, phy->dpll_reset_reg, |
| 423 | SATA_PLL_SOFT_RESET, SATA_PLL_SOFT_RESET); | 594 | SATA_PLL_SOFT_RESET, SATA_PLL_SOFT_RESET); |
| 424 | regmap_update_bits(phy->dpll_reset_syscon, phy->dpll_reset_reg, | 595 | regmap_update_bits(phy->dpll_reset_syscon, phy->dpll_reset_reg, |
| @@ -443,7 +614,6 @@ static int ti_pipe3_get_clk(struct ti_pipe3 *phy) | |||
| 443 | { | 614 | { |
| 444 | struct clk *clk; | 615 | struct clk *clk; |
| 445 | struct device *dev = phy->dev; | 616 | struct device *dev = phy->dev; |
| 446 | struct device_node *node = dev->of_node; | ||
| 447 | 617 | ||
| 448 | phy->refclk = devm_clk_get(dev, "refclk"); | 618 | phy->refclk = devm_clk_get(dev, "refclk"); |
| 449 | if (IS_ERR(phy->refclk)) { | 619 | if (IS_ERR(phy->refclk)) { |
| @@ -451,11 +621,11 @@ static int ti_pipe3_get_clk(struct ti_pipe3 *phy) | |||
| 451 | /* older DTBs have missing refclk in SATA PHY | 621 | /* older DTBs have missing refclk in SATA PHY |
| 452 | * so don't bail out in case of SATA PHY. | 622 | * so don't bail out in case of SATA PHY. |
| 453 | */ | 623 | */ |
| 454 | if (!of_device_is_compatible(node, "ti,phy-pipe3-sata")) | 624 | if (phy->mode != PIPE3_MODE_SATA) |
| 455 | return PTR_ERR(phy->refclk); | 625 | return PTR_ERR(phy->refclk); |
| 456 | } | 626 | } |
| 457 | 627 | ||
| 458 | if (!of_device_is_compatible(node, "ti,phy-pipe3-sata")) { | 628 | if (phy->mode != PIPE3_MODE_SATA) { |
| 459 | phy->wkupclk = devm_clk_get(dev, "wkupclk"); | 629 | phy->wkupclk = devm_clk_get(dev, "wkupclk"); |
| 460 | if (IS_ERR(phy->wkupclk)) { | 630 | if (IS_ERR(phy->wkupclk)) { |
| 461 | dev_err(dev, "unable to get wkupclk\n"); | 631 | dev_err(dev, "unable to get wkupclk\n"); |
| @@ -465,8 +635,7 @@ static int ti_pipe3_get_clk(struct ti_pipe3 *phy) | |||
| 465 | phy->wkupclk = ERR_PTR(-ENODEV); | 635 | phy->wkupclk = ERR_PTR(-ENODEV); |
| 466 | } | 636 | } |
| 467 | 637 | ||
| 468 | if (!of_device_is_compatible(node, "ti,phy-pipe3-pcie") || | 638 | if (phy->mode != PIPE3_MODE_PCIE || phy->phy_power_syscon) { |
| 469 | phy->phy_power_syscon) { | ||
| 470 | phy->sys_clk = devm_clk_get(dev, "sysclk"); | 639 | phy->sys_clk = devm_clk_get(dev, "sysclk"); |
| 471 | if (IS_ERR(phy->sys_clk)) { | 640 | if (IS_ERR(phy->sys_clk)) { |
| 472 | dev_err(dev, "unable to get sysclk\n"); | 641 | dev_err(dev, "unable to get sysclk\n"); |
| @@ -474,7 +643,7 @@ static int ti_pipe3_get_clk(struct ti_pipe3 *phy) | |||
| 474 | } | 643 | } |
| 475 | } | 644 | } |
| 476 | 645 | ||
| 477 | if (of_device_is_compatible(node, "ti,phy-pipe3-pcie")) { | 646 | if (phy->mode == PIPE3_MODE_PCIE) { |
| 478 | clk = devm_clk_get(dev, "dpll_ref"); | 647 | clk = devm_clk_get(dev, "dpll_ref"); |
| 479 | if (IS_ERR(clk)) { | 648 | if (IS_ERR(clk)) { |
| 480 | dev_err(dev, "unable to get dpll ref clk\n"); | 649 | dev_err(dev, "unable to get dpll ref clk\n"); |
| @@ -546,7 +715,7 @@ static int ti_pipe3_get_sysctrl(struct ti_pipe3 *phy) | |||
| 546 | phy->control_dev = &control_pdev->dev; | 715 | phy->control_dev = &control_pdev->dev; |
| 547 | } | 716 | } |
| 548 | 717 | ||
| 549 | if (of_device_is_compatible(node, "ti,phy-pipe3-pcie")) { | 718 | if (phy->mode == PIPE3_MODE_PCIE) { |
| 550 | phy->pcs_syscon = syscon_regmap_lookup_by_phandle(node, | 719 | phy->pcs_syscon = syscon_regmap_lookup_by_phandle(node, |
| 551 | "syscon-pcs"); | 720 | "syscon-pcs"); |
| 552 | if (IS_ERR(phy->pcs_syscon)) { | 721 | if (IS_ERR(phy->pcs_syscon)) { |
| @@ -564,7 +733,7 @@ static int ti_pipe3_get_sysctrl(struct ti_pipe3 *phy) | |||
| 564 | } | 733 | } |
| 565 | } | 734 | } |
| 566 | 735 | ||
| 567 | if (of_device_is_compatible(node, "ti,phy-pipe3-sata")) { | 736 | if (phy->mode == PIPE3_MODE_SATA) { |
| 568 | phy->dpll_reset_syscon = syscon_regmap_lookup_by_phandle(node, | 737 | phy->dpll_reset_syscon = syscon_regmap_lookup_by_phandle(node, |
| 569 | "syscon-pllreset"); | 738 | "syscon-pllreset"); |
| 570 | if (IS_ERR(phy->dpll_reset_syscon)) { | 739 | if (IS_ERR(phy->dpll_reset_syscon)) { |
| @@ -589,12 +758,8 @@ static int ti_pipe3_get_tx_rx_base(struct ti_pipe3 *phy) | |||
| 589 | { | 758 | { |
| 590 | struct resource *res; | 759 | struct resource *res; |
| 591 | struct device *dev = phy->dev; | 760 | struct device *dev = phy->dev; |
| 592 | struct device_node *node = dev->of_node; | ||
| 593 | struct platform_device *pdev = to_platform_device(dev); | 761 | struct platform_device *pdev = to_platform_device(dev); |
| 594 | 762 | ||
| 595 | if (!of_device_is_compatible(node, "ti,phy-pipe3-pcie")) | ||
| 596 | return 0; | ||
| 597 | |||
| 598 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | 763 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, |
| 599 | "phy_rx"); | 764 | "phy_rx"); |
| 600 | phy->phy_rx = devm_ioremap_resource(dev, res); | 765 | phy->phy_rx = devm_ioremap_resource(dev, res); |
| @@ -611,24 +776,12 @@ static int ti_pipe3_get_tx_rx_base(struct ti_pipe3 *phy) | |||
| 611 | static int ti_pipe3_get_pll_base(struct ti_pipe3 *phy) | 776 | static int ti_pipe3_get_pll_base(struct ti_pipe3 *phy) |
| 612 | { | 777 | { |
| 613 | struct resource *res; | 778 | struct resource *res; |
| 614 | const struct of_device_id *match; | ||
| 615 | struct device *dev = phy->dev; | 779 | struct device *dev = phy->dev; |
| 616 | struct device_node *node = dev->of_node; | ||
| 617 | struct platform_device *pdev = to_platform_device(dev); | 780 | struct platform_device *pdev = to_platform_device(dev); |
| 618 | 781 | ||
| 619 | if (of_device_is_compatible(node, "ti,phy-pipe3-pcie")) | 782 | if (phy->mode == PIPE3_MODE_PCIE) |
| 620 | return 0; | 783 | return 0; |
| 621 | 784 | ||
| 622 | match = of_match_device(ti_pipe3_id_table, dev); | ||
| 623 | if (!match) | ||
| 624 | return -EINVAL; | ||
| 625 | |||
| 626 | phy->dpll_map = (struct pipe3_dpll_map *)match->data; | ||
| 627 | if (!phy->dpll_map) { | ||
| 628 | dev_err(dev, "no DPLL data\n"); | ||
| 629 | return -EINVAL; | ||
| 630 | } | ||
| 631 | |||
| 632 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | 785 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, |
| 633 | "pll_ctrl"); | 786 | "pll_ctrl"); |
| 634 | phy->pll_ctrl_base = devm_ioremap_resource(dev, res); | 787 | phy->pll_ctrl_base = devm_ioremap_resource(dev, res); |
| @@ -640,15 +793,29 @@ static int ti_pipe3_probe(struct platform_device *pdev) | |||
| 640 | struct ti_pipe3 *phy; | 793 | struct ti_pipe3 *phy; |
| 641 | struct phy *generic_phy; | 794 | struct phy *generic_phy; |
| 642 | struct phy_provider *phy_provider; | 795 | struct phy_provider *phy_provider; |
| 643 | struct device_node *node = pdev->dev.of_node; | ||
| 644 | struct device *dev = &pdev->dev; | 796 | struct device *dev = &pdev->dev; |
| 645 | int ret; | 797 | int ret; |
| 798 | const struct of_device_id *match; | ||
| 799 | struct pipe3_data *data; | ||
| 646 | 800 | ||
| 647 | phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); | 801 | phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL); |
| 648 | if (!phy) | 802 | if (!phy) |
| 649 | return -ENOMEM; | 803 | return -ENOMEM; |
| 650 | 804 | ||
| 651 | phy->dev = dev; | 805 | match = of_match_device(ti_pipe3_id_table, dev); |
| 806 | if (!match) | ||
| 807 | return -EINVAL; | ||
| 808 | |||
| 809 | data = (struct pipe3_data *)match->data; | ||
| 810 | if (!data) { | ||
| 811 | dev_err(dev, "no driver data\n"); | ||
| 812 | return -EINVAL; | ||
| 813 | } | ||
| 814 | |||
| 815 | phy->dev = dev; | ||
| 816 | phy->mode = data->mode; | ||
| 817 | phy->dpll_map = data->dpll_map; | ||
| 818 | phy->settings = data->settings; | ||
| 652 | 819 | ||
| 653 | ret = ti_pipe3_get_pll_base(phy); | 820 | ret = ti_pipe3_get_pll_base(phy); |
| 654 | if (ret) | 821 | if (ret) |
| @@ -672,7 +839,7 @@ static int ti_pipe3_probe(struct platform_device *pdev) | |||
| 672 | /* | 839 | /* |
| 673 | * Prevent auto-disable of refclk for SATA PHY due to Errata i783 | 840 | * Prevent auto-disable of refclk for SATA PHY due to Errata i783 |
| 674 | */ | 841 | */ |
| 675 | if (of_device_is_compatible(node, "ti,phy-pipe3-sata")) { | 842 | if (phy->mode == PIPE3_MODE_SATA) { |
| 676 | if (!IS_ERR(phy->refclk)) { | 843 | if (!IS_ERR(phy->refclk)) { |
| 677 | clk_prepare_enable(phy->refclk); | 844 | clk_prepare_enable(phy->refclk); |
| 678 | phy->sata_refclk_enabled = true; | 845 | phy->sata_refclk_enabled = true; |
| @@ -762,18 +929,19 @@ static void ti_pipe3_disable_clocks(struct ti_pipe3 *phy) | |||
| 762 | static const struct of_device_id ti_pipe3_id_table[] = { | 929 | static const struct of_device_id ti_pipe3_id_table[] = { |
| 763 | { | 930 | { |
| 764 | .compatible = "ti,phy-usb3", | 931 | .compatible = "ti,phy-usb3", |
| 765 | .data = dpll_map_usb, | 932 | .data = &data_usb, |
| 766 | }, | 933 | }, |
| 767 | { | 934 | { |
| 768 | .compatible = "ti,omap-usb3", | 935 | .compatible = "ti,omap-usb3", |
| 769 | .data = dpll_map_usb, | 936 | .data = &data_usb, |
| 770 | }, | 937 | }, |
| 771 | { | 938 | { |
| 772 | .compatible = "ti,phy-pipe3-sata", | 939 | .compatible = "ti,phy-pipe3-sata", |
| 773 | .data = dpll_map_sata, | 940 | .data = &data_sata, |
| 774 | }, | 941 | }, |
| 775 | { | 942 | { |
| 776 | .compatible = "ti,phy-pipe3-pcie", | 943 | .compatible = "ti,phy-pipe3-pcie", |
| 944 | .data = &data_pcie, | ||
| 777 | }, | 945 | }, |
| 778 | {} | 946 | {} |
| 779 | }; | 947 | }; |
diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig index 6db37cf306b0..179bda374544 100644 --- a/drivers/scsi/ufs/Kconfig +++ b/drivers/scsi/ufs/Kconfig | |||
| @@ -99,6 +99,7 @@ config SCSI_UFS_DWC_TC_PLATFORM | |||
| 99 | config SCSI_UFS_QCOM | 99 | config SCSI_UFS_QCOM |
| 100 | tristate "QCOM specific hooks to UFS controller platform driver" | 100 | tristate "QCOM specific hooks to UFS controller platform driver" |
| 101 | depends on SCSI_UFSHCD_PLATFORM && ARCH_QCOM | 101 | depends on SCSI_UFSHCD_PLATFORM && ARCH_QCOM |
| 102 | select RESET_CONTROLLER | ||
| 102 | help | 103 | help |
| 103 | This selects the QCOM specific additions to UFSHCD platform driver. | 104 | This selects the QCOM specific additions to UFSHCD platform driver. |
| 104 | UFS host on QCOM needs some vendor specific configuration before | 105 | UFS host on QCOM needs some vendor specific configuration before |
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 3aeadb14aae1..de9d3f56b58c 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/of.h> | 16 | #include <linux/of.h> |
| 17 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
| 18 | #include <linux/phy/phy.h> | 18 | #include <linux/phy/phy.h> |
| 19 | #include <linux/reset-controller.h> | ||
| 19 | 20 | ||
| 20 | #include "ufshcd.h" | 21 | #include "ufshcd.h" |
| 21 | #include "ufshcd-pltfrm.h" | 22 | #include "ufshcd-pltfrm.h" |
| @@ -49,6 +50,11 @@ static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host); | |||
| 49 | static int ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(struct ufs_hba *hba, | 50 | static int ufs_qcom_set_dme_vs_core_clk_ctrl_clear_div(struct ufs_hba *hba, |
| 50 | u32 clk_cycles); | 51 | u32 clk_cycles); |
| 51 | 52 | ||
| 53 | static struct ufs_qcom_host *rcdev_to_ufs_host(struct reset_controller_dev *rcd) | ||
| 54 | { | ||
| 55 | return container_of(rcd, struct ufs_qcom_host, rcdev); | ||
| 56 | } | ||
| 57 | |||
| 52 | static void ufs_qcom_dump_regs_wrapper(struct ufs_hba *hba, int offset, int len, | 58 | static void ufs_qcom_dump_regs_wrapper(struct ufs_hba *hba, int offset, int len, |
| 53 | const char *prefix, void *priv) | 59 | const char *prefix, void *priv) |
| 54 | { | 60 | { |
| @@ -255,11 +261,6 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) | |||
| 255 | if (is_rate_B) | 261 | if (is_rate_B) |
| 256 | phy_set_mode(phy, PHY_MODE_UFS_HS_B); | 262 | phy_set_mode(phy, PHY_MODE_UFS_HS_B); |
| 257 | 263 | ||
| 258 | /* Assert PHY reset and apply PHY calibration values */ | ||
| 259 | ufs_qcom_assert_reset(hba); | ||
| 260 | /* provide 1ms delay to let the reset pulse propagate */ | ||
| 261 | usleep_range(1000, 1100); | ||
| 262 | |||
| 263 | /* phy initialization - calibrate the phy */ | 264 | /* phy initialization - calibrate the phy */ |
| 264 | ret = phy_init(phy); | 265 | ret = phy_init(phy); |
| 265 | if (ret) { | 266 | if (ret) { |
| @@ -268,15 +269,6 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) | |||
| 268 | goto out; | 269 | goto out; |
| 269 | } | 270 | } |
| 270 | 271 | ||
| 271 | /* De-assert PHY reset and start serdes */ | ||
| 272 | ufs_qcom_deassert_reset(hba); | ||
| 273 | |||
| 274 | /* | ||
| 275 | * after reset deassertion, phy will need all ref clocks, | ||
| 276 | * voltage, current to settle down before starting serdes. | ||
| 277 | */ | ||
| 278 | usleep_range(1000, 1100); | ||
| 279 | |||
| 280 | /* power on phy - start serdes and phy's power and clocks */ | 272 | /* power on phy - start serdes and phy's power and clocks */ |
| 281 | ret = phy_power_on(phy); | 273 | ret = phy_power_on(phy); |
| 282 | if (ret) { | 274 | if (ret) { |
| @@ -290,7 +282,6 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) | |||
| 290 | return 0; | 282 | return 0; |
| 291 | 283 | ||
| 292 | out_disable_phy: | 284 | out_disable_phy: |
| 293 | ufs_qcom_assert_reset(hba); | ||
| 294 | phy_exit(phy); | 285 | phy_exit(phy); |
| 295 | out: | 286 | out: |
| 296 | return ret; | 287 | return ret; |
| @@ -554,21 +545,10 @@ static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op) | |||
| 554 | ufs_qcom_disable_lane_clks(host); | 545 | ufs_qcom_disable_lane_clks(host); |
| 555 | phy_power_off(phy); | 546 | phy_power_off(phy); |
| 556 | 547 | ||
| 557 | /* Assert PHY soft reset */ | 548 | } else if (!ufs_qcom_is_link_active(hba)) { |
| 558 | ufs_qcom_assert_reset(hba); | ||
| 559 | goto out; | ||
| 560 | } | ||
| 561 | |||
| 562 | /* | ||
| 563 | * If UniPro link is not active, PHY ref_clk, main PHY analog power | ||
| 564 | * rail and low noise analog power rail for PLL can be switched off. | ||
| 565 | */ | ||
| 566 | if (!ufs_qcom_is_link_active(hba)) { | ||
| 567 | ufs_qcom_disable_lane_clks(host); | 549 | ufs_qcom_disable_lane_clks(host); |
| 568 | phy_power_off(phy); | ||
| 569 | } | 550 | } |
| 570 | 551 | ||
| 571 | out: | ||
| 572 | return ret; | 552 | return ret; |
| 573 | } | 553 | } |
| 574 | 554 | ||
| @@ -578,21 +558,26 @@ static int ufs_qcom_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) | |||
| 578 | struct phy *phy = host->generic_phy; | 558 | struct phy *phy = host->generic_phy; |
| 579 | int err; | 559 | int err; |
| 580 | 560 | ||
| 581 | err = phy_power_on(phy); | 561 | if (ufs_qcom_is_link_off(hba)) { |
| 582 | if (err) { | 562 | err = phy_power_on(phy); |
| 583 | dev_err(hba->dev, "%s: failed enabling regs, err = %d\n", | 563 | if (err) { |
| 584 | __func__, err); | 564 | dev_err(hba->dev, "%s: failed PHY power on: %d\n", |
| 585 | goto out; | 565 | __func__, err); |
| 586 | } | 566 | return err; |
| 567 | } | ||
| 587 | 568 | ||
| 588 | err = ufs_qcom_enable_lane_clks(host); | 569 | err = ufs_qcom_enable_lane_clks(host); |
| 589 | if (err) | 570 | if (err) |
| 590 | goto out; | 571 | return err; |
| 591 | 572 | ||
| 592 | hba->is_sys_suspended = false; | 573 | } else if (!ufs_qcom_is_link_active(hba)) { |
| 574 | err = ufs_qcom_enable_lane_clks(host); | ||
| 575 | if (err) | ||
| 576 | return err; | ||
| 577 | } | ||
| 593 | 578 | ||
| 594 | out: | 579 | hba->is_sys_suspended = false; |
| 595 | return err; | 580 | return 0; |
| 596 | } | 581 | } |
| 597 | 582 | ||
| 598 | struct ufs_qcom_dev_params { | 583 | struct ufs_qcom_dev_params { |
| @@ -1118,8 +1103,6 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on, | |||
| 1118 | return 0; | 1103 | return 0; |
| 1119 | 1104 | ||
| 1120 | if (on && (status == POST_CHANGE)) { | 1105 | if (on && (status == POST_CHANGE)) { |
| 1121 | phy_power_on(host->generic_phy); | ||
| 1122 | |||
| 1123 | /* enable the device ref clock for HS mode*/ | 1106 | /* enable the device ref clock for HS mode*/ |
| 1124 | if (ufshcd_is_hs_mode(&hba->pwr_info)) | 1107 | if (ufshcd_is_hs_mode(&hba->pwr_info)) |
| 1125 | ufs_qcom_dev_ref_clk_ctrl(host, true); | 1108 | ufs_qcom_dev_ref_clk_ctrl(host, true); |
| @@ -1131,9 +1114,6 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on, | |||
| 1131 | if (!ufs_qcom_is_link_active(hba)) { | 1114 | if (!ufs_qcom_is_link_active(hba)) { |
| 1132 | /* disable device ref_clk */ | 1115 | /* disable device ref_clk */ |
| 1133 | ufs_qcom_dev_ref_clk_ctrl(host, false); | 1116 | ufs_qcom_dev_ref_clk_ctrl(host, false); |
| 1134 | |||
| 1135 | /* powering off PHY during aggressive clk gating */ | ||
| 1136 | phy_power_off(host->generic_phy); | ||
| 1137 | } | 1117 | } |
| 1138 | 1118 | ||
| 1139 | vote = host->bus_vote.min_bw_vote; | 1119 | vote = host->bus_vote.min_bw_vote; |
| @@ -1147,6 +1127,41 @@ static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on, | |||
| 1147 | return err; | 1127 | return err; |
| 1148 | } | 1128 | } |
| 1149 | 1129 | ||
| 1130 | static int | ||
| 1131 | ufs_qcom_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) | ||
| 1132 | { | ||
| 1133 | struct ufs_qcom_host *host = rcdev_to_ufs_host(rcdev); | ||
| 1134 | |||
| 1135 | /* Currently this code only knows about a single reset. */ | ||
| 1136 | WARN_ON(id); | ||
| 1137 | ufs_qcom_assert_reset(host->hba); | ||
| 1138 | /* provide 1ms delay to let the reset pulse propagate. */ | ||
| 1139 | usleep_range(1000, 1100); | ||
| 1140 | return 0; | ||
| 1141 | } | ||
| 1142 | |||
| 1143 | static int | ||
| 1144 | ufs_qcom_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) | ||
| 1145 | { | ||
| 1146 | struct ufs_qcom_host *host = rcdev_to_ufs_host(rcdev); | ||
| 1147 | |||
| 1148 | /* Currently this code only knows about a single reset. */ | ||
| 1149 | WARN_ON(id); | ||
| 1150 | ufs_qcom_deassert_reset(host->hba); | ||
| 1151 | |||
| 1152 | /* | ||
| 1153 | * after reset deassertion, phy will need all ref clocks, | ||
| 1154 | * voltage, current to settle down before starting serdes. | ||
| 1155 | */ | ||
| 1156 | usleep_range(1000, 1100); | ||
| 1157 | return 0; | ||
| 1158 | } | ||
| 1159 | |||
| 1160 | static const struct reset_control_ops ufs_qcom_reset_ops = { | ||
| 1161 | .assert = ufs_qcom_reset_assert, | ||
| 1162 | .deassert = ufs_qcom_reset_deassert, | ||
| 1163 | }; | ||
| 1164 | |||
| 1150 | #define ANDROID_BOOT_DEV_MAX 30 | 1165 | #define ANDROID_BOOT_DEV_MAX 30 |
| 1151 | static char android_boot_dev[ANDROID_BOOT_DEV_MAX]; | 1166 | static char android_boot_dev[ANDROID_BOOT_DEV_MAX]; |
| 1152 | 1167 | ||
| @@ -1191,6 +1206,17 @@ static int ufs_qcom_init(struct ufs_hba *hba) | |||
| 1191 | host->hba = hba; | 1206 | host->hba = hba; |
| 1192 | ufshcd_set_variant(hba, host); | 1207 | ufshcd_set_variant(hba, host); |
| 1193 | 1208 | ||
| 1209 | /* Fire up the reset controller. Failure here is non-fatal. */ | ||
| 1210 | host->rcdev.of_node = dev->of_node; | ||
| 1211 | host->rcdev.ops = &ufs_qcom_reset_ops; | ||
| 1212 | host->rcdev.owner = dev->driver->owner; | ||
| 1213 | host->rcdev.nr_resets = 1; | ||
| 1214 | err = devm_reset_controller_register(dev, &host->rcdev); | ||
| 1215 | if (err) { | ||
| 1216 | dev_warn(dev, "Failed to register reset controller\n"); | ||
| 1217 | err = 0; | ||
| 1218 | } | ||
| 1219 | |||
| 1194 | /* | 1220 | /* |
| 1195 | * voting/devoting device ref_clk source is time consuming hence | 1221 | * voting/devoting device ref_clk source is time consuming hence |
| 1196 | * skip devoting it during aggressive clock gating. This clock | 1222 | * skip devoting it during aggressive clock gating. This clock |
diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h index c114826316eb..68a880185752 100644 --- a/drivers/scsi/ufs/ufs-qcom.h +++ b/drivers/scsi/ufs/ufs-qcom.h | |||
| @@ -14,6 +14,8 @@ | |||
| 14 | #ifndef UFS_QCOM_H_ | 14 | #ifndef UFS_QCOM_H_ |
| 15 | #define UFS_QCOM_H_ | 15 | #define UFS_QCOM_H_ |
| 16 | 16 | ||
| 17 | #include <linux/reset-controller.h> | ||
| 18 | |||
| 17 | #define MAX_UFS_QCOM_HOSTS 1 | 19 | #define MAX_UFS_QCOM_HOSTS 1 |
| 18 | #define MAX_U32 (~(u32)0) | 20 | #define MAX_U32 (~(u32)0) |
| 19 | #define MPHY_TX_FSM_STATE 0x41 | 21 | #define MPHY_TX_FSM_STATE 0x41 |
| @@ -237,6 +239,8 @@ struct ufs_qcom_host { | |||
| 237 | /* Bitmask for enabling debug prints */ | 239 | /* Bitmask for enabling debug prints */ |
| 238 | u32 dbg_print_en; | 240 | u32 dbg_print_en; |
| 239 | struct ufs_qcom_testbus testbus; | 241 | struct ufs_qcom_testbus testbus; |
| 242 | |||
| 243 | struct reset_controller_dev rcdev; | ||
| 240 | }; | 244 | }; |
| 241 | 245 | ||
| 242 | static inline u32 | 246 | static inline u32 |
diff --git a/drivers/soc/sunxi/Kconfig b/drivers/soc/sunxi/Kconfig index 353b07e40176..e84eb4e59f58 100644 --- a/drivers/soc/sunxi/Kconfig +++ b/drivers/soc/sunxi/Kconfig | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | config SUNXI_SRAM | 4 | config SUNXI_SRAM |
| 5 | bool | 5 | bool |
| 6 | default ARCH_SUNXI | 6 | default ARCH_SUNXI |
| 7 | select REGMAP_MMIO | ||
| 7 | help | 8 | help |
| 8 | Say y here to enable the SRAM controller support. This | 9 | Say y here to enable the SRAM controller support. This |
| 9 | device is responsible on mapping the SRAM in the sunXi SoCs | 10 | device is responsible on mapping the SRAM in the sunXi SoCs |
diff --git a/drivers/usb/chipidea/ci_hdrc_msm.c b/drivers/usb/chipidea/ci_hdrc_msm.c index 880009987460..b8b3caad889c 100644 --- a/drivers/usb/chipidea/ci_hdrc_msm.c +++ b/drivers/usb/chipidea/ci_hdrc_msm.c | |||
| @@ -205,12 +205,9 @@ static int ci_hdrc_msm_probe(struct platform_device *pdev) | |||
| 205 | if (IS_ERR(clk)) | 205 | if (IS_ERR(clk)) |
| 206 | return PTR_ERR(clk); | 206 | return PTR_ERR(clk); |
| 207 | 207 | ||
| 208 | ci->fs_clk = clk = devm_clk_get(&pdev->dev, "fs"); | 208 | ci->fs_clk = clk = devm_clk_get_optional(&pdev->dev, "fs"); |
| 209 | if (IS_ERR(clk)) { | 209 | if (IS_ERR(clk)) |
| 210 | if (PTR_ERR(clk) == -EPROBE_DEFER) | 210 | return PTR_ERR(clk); |
| 211 | return -EPROBE_DEFER; | ||
| 212 | ci->fs_clk = NULL; | ||
| 213 | } | ||
| 214 | 211 | ||
| 215 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | 212 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
| 216 | ci->base = devm_ioremap_resource(&pdev->dev, res); | 213 | ci->base = devm_ioremap_resource(&pdev->dev, res); |
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index ec666eb4b7b4..183b41753c98 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c | |||
| @@ -468,14 +468,13 @@ static void acm_read_bulk_callback(struct urb *urb) | |||
| 468 | { | 468 | { |
| 469 | struct acm_rb *rb = urb->context; | 469 | struct acm_rb *rb = urb->context; |
| 470 | struct acm *acm = rb->instance; | 470 | struct acm *acm = rb->instance; |
| 471 | unsigned long flags; | ||
| 472 | int status = urb->status; | 471 | int status = urb->status; |
| 472 | bool stopped = false; | ||
| 473 | bool stalled = false; | ||
| 473 | 474 | ||
| 474 | dev_vdbg(&acm->data->dev, "got urb %d, len %d, status %d\n", | 475 | dev_vdbg(&acm->data->dev, "got urb %d, len %d, status %d\n", |
| 475 | rb->index, urb->actual_length, status); | 476 | rb->index, urb->actual_length, status); |
| 476 | 477 | ||
| 477 | set_bit(rb->index, &acm->read_urbs_free); | ||
| 478 | |||
| 479 | if (!acm->dev) { | 478 | if (!acm->dev) { |
| 480 | dev_dbg(&acm->data->dev, "%s - disconnected\n", __func__); | 479 | dev_dbg(&acm->data->dev, "%s - disconnected\n", __func__); |
| 481 | return; | 480 | return; |
| @@ -488,15 +487,16 @@ static void acm_read_bulk_callback(struct urb *urb) | |||
| 488 | break; | 487 | break; |
| 489 | case -EPIPE: | 488 | case -EPIPE: |
| 490 | set_bit(EVENT_RX_STALL, &acm->flags); | 489 | set_bit(EVENT_RX_STALL, &acm->flags); |
| 491 | schedule_work(&acm->work); | 490 | stalled = true; |
| 492 | return; | 491 | break; |
| 493 | case -ENOENT: | 492 | case -ENOENT: |
| 494 | case -ECONNRESET: | 493 | case -ECONNRESET: |
| 495 | case -ESHUTDOWN: | 494 | case -ESHUTDOWN: |
| 496 | dev_dbg(&acm->data->dev, | 495 | dev_dbg(&acm->data->dev, |
| 497 | "%s - urb shutting down with status: %d\n", | 496 | "%s - urb shutting down with status: %d\n", |
| 498 | __func__, status); | 497 | __func__, status); |
| 499 | return; | 498 | stopped = true; |
| 499 | break; | ||
| 500 | default: | 500 | default: |
| 501 | dev_dbg(&acm->data->dev, | 501 | dev_dbg(&acm->data->dev, |
| 502 | "%s - nonzero urb status received: %d\n", | 502 | "%s - nonzero urb status received: %d\n", |
| @@ -505,20 +505,29 @@ static void acm_read_bulk_callback(struct urb *urb) | |||
| 505 | } | 505 | } |
| 506 | 506 | ||
| 507 | /* | 507 | /* |
| 508 | * Unthrottle may run on another CPU which needs to see events | 508 | * Make sure URB processing is done before marking as free to avoid |
| 509 | * in the same order. Submission has an implict barrier | 509 | * racing with unthrottle() on another CPU. Matches the barriers |
| 510 | * implied by the test_and_clear_bit() in acm_submit_read_urb(). | ||
| 510 | */ | 511 | */ |
| 511 | smp_mb__before_atomic(); | 512 | smp_mb__before_atomic(); |
| 513 | set_bit(rb->index, &acm->read_urbs_free); | ||
| 514 | /* | ||
| 515 | * Make sure URB is marked as free before checking the throttled flag | ||
| 516 | * to avoid racing with unthrottle() on another CPU. Matches the | ||
| 517 | * smp_mb() in unthrottle(). | ||
| 518 | */ | ||
| 519 | smp_mb__after_atomic(); | ||
| 512 | 520 | ||
| 513 | /* throttle device if requested by tty */ | 521 | if (stopped || stalled) { |
| 514 | spin_lock_irqsave(&acm->read_lock, flags); | 522 | if (stalled) |
| 515 | acm->throttled = acm->throttle_req; | 523 | schedule_work(&acm->work); |
| 516 | if (!acm->throttled) { | 524 | return; |
| 517 | spin_unlock_irqrestore(&acm->read_lock, flags); | ||
| 518 | acm_submit_read_urb(acm, rb->index, GFP_ATOMIC); | ||
| 519 | } else { | ||
| 520 | spin_unlock_irqrestore(&acm->read_lock, flags); | ||
| 521 | } | 525 | } |
| 526 | |||
| 527 | if (test_bit(ACM_THROTTLED, &acm->flags)) | ||
| 528 | return; | ||
| 529 | |||
| 530 | acm_submit_read_urb(acm, rb->index, GFP_ATOMIC); | ||
| 522 | } | 531 | } |
| 523 | 532 | ||
| 524 | /* data interface wrote those outgoing bytes */ | 533 | /* data interface wrote those outgoing bytes */ |
| @@ -655,10 +664,7 @@ static int acm_port_activate(struct tty_port *port, struct tty_struct *tty) | |||
| 655 | /* | 664 | /* |
| 656 | * Unthrottle device in case the TTY was closed while throttled. | 665 | * Unthrottle device in case the TTY was closed while throttled. |
| 657 | */ | 666 | */ |
| 658 | spin_lock_irq(&acm->read_lock); | 667 | clear_bit(ACM_THROTTLED, &acm->flags); |
| 659 | acm->throttled = 0; | ||
| 660 | acm->throttle_req = 0; | ||
| 661 | spin_unlock_irq(&acm->read_lock); | ||
| 662 | 668 | ||
| 663 | retval = acm_submit_read_urbs(acm, GFP_KERNEL); | 669 | retval = acm_submit_read_urbs(acm, GFP_KERNEL); |
| 664 | if (retval) | 670 | if (retval) |
| @@ -826,24 +832,19 @@ static void acm_tty_throttle(struct tty_struct *tty) | |||
| 826 | { | 832 | { |
| 827 | struct acm *acm = tty->driver_data; | 833 | struct acm *acm = tty->driver_data; |
| 828 | 834 | ||
| 829 | spin_lock_irq(&acm->read_lock); | 835 | set_bit(ACM_THROTTLED, &acm->flags); |
| 830 | acm->throttle_req = 1; | ||
| 831 | spin_unlock_irq(&acm->read_lock); | ||
| 832 | } | 836 | } |
| 833 | 837 | ||
| 834 | static void acm_tty_unthrottle(struct tty_struct *tty) | 838 | static void acm_tty_unthrottle(struct tty_struct *tty) |
| 835 | { | 839 | { |
| 836 | struct acm *acm = tty->driver_data; | 840 | struct acm *acm = tty->driver_data; |
| 837 | unsigned int was_throttled; | ||
| 838 | 841 | ||
| 839 | spin_lock_irq(&acm->read_lock); | 842 | clear_bit(ACM_THROTTLED, &acm->flags); |
| 840 | was_throttled = acm->throttled; | 843 | |
| 841 | acm->throttled = 0; | 844 | /* Matches the smp_mb__after_atomic() in acm_read_bulk_callback(). */ |
| 842 | acm->throttle_req = 0; | 845 | smp_mb(); |
| 843 | spin_unlock_irq(&acm->read_lock); | ||
| 844 | 846 | ||
| 845 | if (was_throttled) | 847 | acm_submit_read_urbs(acm, GFP_KERNEL); |
| 846 | acm_submit_read_urbs(acm, GFP_KERNEL); | ||
| 847 | } | 848 | } |
| 848 | 849 | ||
| 849 | static int acm_tty_break_ctl(struct tty_struct *tty, int state) | 850 | static int acm_tty_break_ctl(struct tty_struct *tty, int state) |
diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h index 515aad0847ee..ca1c026382c2 100644 --- a/drivers/usb/class/cdc-acm.h +++ b/drivers/usb/class/cdc-acm.h | |||
| @@ -108,6 +108,7 @@ struct acm { | |||
| 108 | unsigned long flags; | 108 | unsigned long flags; |
| 109 | # define EVENT_TTY_WAKEUP 0 | 109 | # define EVENT_TTY_WAKEUP 0 |
| 110 | # define EVENT_RX_STALL 1 | 110 | # define EVENT_RX_STALL 1 |
| 111 | # define ACM_THROTTLED 2 | ||
| 111 | struct usb_cdc_line_coding line; /* bits, stop, parity */ | 112 | struct usb_cdc_line_coding line; /* bits, stop, parity */ |
| 112 | struct work_struct work; /* work queue entry for line discipline waking up */ | 113 | struct work_struct work; /* work queue entry for line discipline waking up */ |
| 113 | unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */ | 114 | unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */ |
| @@ -122,8 +123,6 @@ struct acm { | |||
| 122 | unsigned int ctrl_caps; /* control capabilities from the class specific header */ | 123 | unsigned int ctrl_caps; /* control capabilities from the class specific header */ |
| 123 | unsigned int susp_count; /* number of suspended interfaces */ | 124 | unsigned int susp_count; /* number of suspended interfaces */ |
| 124 | unsigned int combined_interfaces:1; /* control and data collapsed */ | 125 | unsigned int combined_interfaces:1; /* control and data collapsed */ |
| 125 | unsigned int throttled:1; /* actually throttled */ | ||
| 126 | unsigned int throttle_req:1; /* throttle requested */ | ||
| 127 | u8 bInterval; | 126 | u8 bInterval; |
| 128 | struct usb_anchor delayed; /* writes queued for a device about to be woken */ | 127 | struct usb_anchor delayed; /* writes queued for a device about to be woken */ |
| 129 | unsigned long quirks; | 128 | unsigned long quirks; |
diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c index 73c8e6591746..18f5dcf58b0d 100644 --- a/drivers/usb/common/common.c +++ b/drivers/usb/common/common.c | |||
| @@ -16,6 +16,22 @@ | |||
| 16 | #include <linux/usb/otg.h> | 16 | #include <linux/usb/otg.h> |
| 17 | #include <linux/of_platform.h> | 17 | #include <linux/of_platform.h> |
| 18 | 18 | ||
| 19 | static const char *const ep_type_names[] = { | ||
| 20 | [USB_ENDPOINT_XFER_CONTROL] = "ctrl", | ||
| 21 | [USB_ENDPOINT_XFER_ISOC] = "isoc", | ||
| 22 | [USB_ENDPOINT_XFER_BULK] = "bulk", | ||
| 23 | [USB_ENDPOINT_XFER_INT] = "intr", | ||
| 24 | }; | ||
| 25 | |||
| 26 | const char *usb_ep_type_string(int ep_type) | ||
| 27 | { | ||
| 28 | if (ep_type < 0 || ep_type >= ARRAY_SIZE(ep_type_names)) | ||
| 29 | return "unknown"; | ||
| 30 | |||
| 31 | return ep_type_names[ep_type]; | ||
| 32 | } | ||
| 33 | EXPORT_SYMBOL_GPL(usb_ep_type_string); | ||
| 34 | |||
| 19 | const char *usb_otg_state_string(enum usb_otg_state state) | 35 | const char *usb_otg_state_string(enum usb_otg_state state) |
| 20 | { | 36 | { |
| 21 | static const char *const names[] = { | 37 | static const char *const names[] = { |
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 975d7c1288e3..94d22551fc1b 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c | |||
| @@ -1878,23 +1878,10 @@ rescan: | |||
| 1878 | /* kick hcd */ | 1878 | /* kick hcd */ |
| 1879 | unlink1(hcd, urb, -ESHUTDOWN); | 1879 | unlink1(hcd, urb, -ESHUTDOWN); |
| 1880 | dev_dbg (hcd->self.controller, | 1880 | dev_dbg (hcd->self.controller, |
| 1881 | "shutdown urb %pK ep%d%s%s\n", | 1881 | "shutdown urb %pK ep%d%s-%s\n", |
| 1882 | urb, usb_endpoint_num(&ep->desc), | 1882 | urb, usb_endpoint_num(&ep->desc), |
| 1883 | is_in ? "in" : "out", | 1883 | is_in ? "in" : "out", |
| 1884 | ({ char *s; | 1884 | usb_ep_type_string(usb_endpoint_type(&ep->desc))); |
| 1885 | |||
| 1886 | switch (usb_endpoint_type(&ep->desc)) { | ||
| 1887 | case USB_ENDPOINT_XFER_CONTROL: | ||
| 1888 | s = ""; break; | ||
| 1889 | case USB_ENDPOINT_XFER_BULK: | ||
| 1890 | s = "-bulk"; break; | ||
| 1891 | case USB_ENDPOINT_XFER_INT: | ||
| 1892 | s = "-intr"; break; | ||
| 1893 | default: | ||
| 1894 | s = "-iso"; break; | ||
| 1895 | }; | ||
| 1896 | s; | ||
| 1897 | })); | ||
| 1898 | usb_put_urb (urb); | 1885 | usb_put_urb (urb); |
| 1899 | 1886 | ||
| 1900 | /* list contents may have changed */ | 1887 | /* list contents may have changed */ |
| @@ -2448,6 +2435,19 @@ EXPORT_SYMBOL_GPL(usb_hcd_irq); | |||
| 2448 | 2435 | ||
| 2449 | /*-------------------------------------------------------------------------*/ | 2436 | /*-------------------------------------------------------------------------*/ |
| 2450 | 2437 | ||
| 2438 | /* Workqueue routine for when the root-hub has died. */ | ||
| 2439 | static void hcd_died_work(struct work_struct *work) | ||
| 2440 | { | ||
| 2441 | struct usb_hcd *hcd = container_of(work, struct usb_hcd, died_work); | ||
| 2442 | static char *env[] = { | ||
| 2443 | "ERROR=DEAD", | ||
| 2444 | NULL | ||
| 2445 | }; | ||
| 2446 | |||
| 2447 | /* Notify user space that the host controller has died */ | ||
| 2448 | kobject_uevent_env(&hcd->self.root_hub->dev.kobj, KOBJ_OFFLINE, env); | ||
| 2449 | } | ||
| 2450 | |||
| 2451 | /** | 2451 | /** |
| 2452 | * usb_hc_died - report abnormal shutdown of a host controller (bus glue) | 2452 | * usb_hc_died - report abnormal shutdown of a host controller (bus glue) |
| 2453 | * @hcd: pointer to the HCD representing the controller | 2453 | * @hcd: pointer to the HCD representing the controller |
| @@ -2488,6 +2488,13 @@ void usb_hc_died (struct usb_hcd *hcd) | |||
| 2488 | usb_kick_hub_wq(hcd->self.root_hub); | 2488 | usb_kick_hub_wq(hcd->self.root_hub); |
| 2489 | } | 2489 | } |
| 2490 | } | 2490 | } |
| 2491 | |||
| 2492 | /* Handle the case where this function gets called with a shared HCD */ | ||
| 2493 | if (usb_hcd_is_primary_hcd(hcd)) | ||
| 2494 | schedule_work(&hcd->died_work); | ||
| 2495 | else | ||
| 2496 | schedule_work(&hcd->primary_hcd->died_work); | ||
| 2497 | |||
| 2491 | spin_unlock_irqrestore (&hcd_root_hub_lock, flags); | 2498 | spin_unlock_irqrestore (&hcd_root_hub_lock, flags); |
| 2492 | /* Make sure that the other roothub is also deallocated. */ | 2499 | /* Make sure that the other roothub is also deallocated. */ |
| 2493 | } | 2500 | } |
| @@ -2555,6 +2562,8 @@ struct usb_hcd *__usb_create_hcd(const struct hc_driver *driver, | |||
| 2555 | INIT_WORK(&hcd->wakeup_work, hcd_resume_work); | 2562 | INIT_WORK(&hcd->wakeup_work, hcd_resume_work); |
| 2556 | #endif | 2563 | #endif |
| 2557 | 2564 | ||
| 2565 | INIT_WORK(&hcd->died_work, hcd_died_work); | ||
| 2566 | |||
| 2558 | hcd->driver = driver; | 2567 | hcd->driver = driver; |
| 2559 | hcd->speed = driver->flags & HCD_MASK; | 2568 | hcd->speed = driver->flags & HCD_MASK; |
| 2560 | hcd->product_desc = (driver->product_desc) ? driver->product_desc : | 2569 | hcd->product_desc = (driver->product_desc) ? driver->product_desc : |
| @@ -2908,6 +2917,7 @@ error_create_attr_group: | |||
| 2908 | #ifdef CONFIG_PM | 2917 | #ifdef CONFIG_PM |
| 2909 | cancel_work_sync(&hcd->wakeup_work); | 2918 | cancel_work_sync(&hcd->wakeup_work); |
| 2910 | #endif | 2919 | #endif |
| 2920 | cancel_work_sync(&hcd->died_work); | ||
| 2911 | mutex_lock(&usb_bus_idr_lock); | 2921 | mutex_lock(&usb_bus_idr_lock); |
| 2912 | usb_disconnect(&rhdev); /* Sets rhdev to NULL */ | 2922 | usb_disconnect(&rhdev); /* Sets rhdev to NULL */ |
| 2913 | mutex_unlock(&usb_bus_idr_lock); | 2923 | mutex_unlock(&usb_bus_idr_lock); |
| @@ -2968,6 +2978,7 @@ void usb_remove_hcd(struct usb_hcd *hcd) | |||
| 2968 | #ifdef CONFIG_PM | 2978 | #ifdef CONFIG_PM |
| 2969 | cancel_work_sync(&hcd->wakeup_work); | 2979 | cancel_work_sync(&hcd->wakeup_work); |
| 2970 | #endif | 2980 | #endif |
| 2981 | cancel_work_sync(&hcd->died_work); | ||
| 2971 | 2982 | ||
| 2972 | mutex_lock(&usb_bus_idr_lock); | 2983 | mutex_lock(&usb_bus_idr_lock); |
| 2973 | usb_disconnect(&rhdev); /* Sets rhdev to NULL */ | 2984 | usb_disconnect(&rhdev); /* Sets rhdev to NULL */ |
| @@ -3020,6 +3031,9 @@ usb_hcd_platform_shutdown(struct platform_device *dev) | |||
| 3020 | { | 3031 | { |
| 3021 | struct usb_hcd *hcd = platform_get_drvdata(dev); | 3032 | struct usb_hcd *hcd = platform_get_drvdata(dev); |
| 3022 | 3033 | ||
| 3034 | /* No need for pm_runtime_put(), we're shutting down */ | ||
| 3035 | pm_runtime_get_sync(&dev->dev); | ||
| 3036 | |||
| 3023 | if (hcd->driver->shutdown) | 3037 | if (hcd->driver->shutdown) |
| 3024 | hcd->driver->shutdown(hcd); | 3038 | hcd->driver->shutdown(hcd); |
| 3025 | } | 3039 | } |
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 8d4631c81b9f..2f94568ba385 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c | |||
| @@ -3174,13 +3174,14 @@ static int usb_disable_remote_wakeup(struct usb_device *udev) | |||
| 3174 | } | 3174 | } |
| 3175 | 3175 | ||
| 3176 | /* Count of wakeup-enabled devices at or below udev */ | 3176 | /* Count of wakeup-enabled devices at or below udev */ |
| 3177 | static unsigned wakeup_enabled_descendants(struct usb_device *udev) | 3177 | unsigned usb_wakeup_enabled_descendants(struct usb_device *udev) |
| 3178 | { | 3178 | { |
| 3179 | struct usb_hub *hub = usb_hub_to_struct_hub(udev); | 3179 | struct usb_hub *hub = usb_hub_to_struct_hub(udev); |
| 3180 | 3180 | ||
| 3181 | return udev->do_remote_wakeup + | 3181 | return udev->do_remote_wakeup + |
| 3182 | (hub ? hub->wakeup_enabled_descendants : 0); | 3182 | (hub ? hub->wakeup_enabled_descendants : 0); |
| 3183 | } | 3183 | } |
| 3184 | EXPORT_SYMBOL_GPL(usb_wakeup_enabled_descendants); | ||
| 3184 | 3185 | ||
| 3185 | /* | 3186 | /* |
| 3186 | * usb_port_suspend - suspend a usb device's upstream port | 3187 | * usb_port_suspend - suspend a usb device's upstream port |
| @@ -3282,7 +3283,7 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) | |||
| 3282 | * Therefore we will turn on the suspend feature if udev or any of its | 3283 | * Therefore we will turn on the suspend feature if udev or any of its |
| 3283 | * descendants is enabled for remote wakeup. | 3284 | * descendants is enabled for remote wakeup. |
| 3284 | */ | 3285 | */ |
| 3285 | else if (PMSG_IS_AUTO(msg) || wakeup_enabled_descendants(udev) > 0) | 3286 | else if (PMSG_IS_AUTO(msg) || usb_wakeup_enabled_descendants(udev) > 0) |
| 3286 | status = set_port_feature(hub->hdev, port1, | 3287 | status = set_port_feature(hub->hdev, port1, |
| 3287 | USB_PORT_FEAT_SUSPEND); | 3288 | USB_PORT_FEAT_SUSPEND); |
| 3288 | else { | 3289 | else { |
| @@ -3668,7 +3669,6 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) | |||
| 3668 | struct usb_hub *hub = usb_get_intfdata(intf); | 3669 | struct usb_hub *hub = usb_get_intfdata(intf); |
| 3669 | struct usb_device *hdev = hub->hdev; | 3670 | struct usb_device *hdev = hub->hdev; |
| 3670 | unsigned port1; | 3671 | unsigned port1; |
| 3671 | int status; | ||
| 3672 | 3672 | ||
| 3673 | /* | 3673 | /* |
| 3674 | * Warn if children aren't already suspended. | 3674 | * Warn if children aren't already suspended. |
| @@ -3687,7 +3687,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) | |||
| 3687 | } | 3687 | } |
| 3688 | if (udev) | 3688 | if (udev) |
| 3689 | hub->wakeup_enabled_descendants += | 3689 | hub->wakeup_enabled_descendants += |
| 3690 | wakeup_enabled_descendants(udev); | 3690 | usb_wakeup_enabled_descendants(udev); |
| 3691 | } | 3691 | } |
| 3692 | 3692 | ||
| 3693 | if (hdev->do_remote_wakeup && hub->quirk_check_port_auto_suspend) { | 3693 | if (hdev->do_remote_wakeup && hub->quirk_check_port_auto_suspend) { |
| @@ -3702,12 +3702,12 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) | |||
| 3702 | if (hub_is_superspeed(hdev) && hdev->do_remote_wakeup) { | 3702 | if (hub_is_superspeed(hdev) && hdev->do_remote_wakeup) { |
| 3703 | /* Enable hub to send remote wakeup for all ports. */ | 3703 | /* Enable hub to send remote wakeup for all ports. */ |
| 3704 | for (port1 = 1; port1 <= hdev->maxchild; port1++) { | 3704 | for (port1 = 1; port1 <= hdev->maxchild; port1++) { |
| 3705 | status = set_port_feature(hdev, | 3705 | set_port_feature(hdev, |
| 3706 | port1 | | 3706 | port1 | |
| 3707 | USB_PORT_FEAT_REMOTE_WAKE_CONNECT | | 3707 | USB_PORT_FEAT_REMOTE_WAKE_CONNECT | |
| 3708 | USB_PORT_FEAT_REMOTE_WAKE_DISCONNECT | | 3708 | USB_PORT_FEAT_REMOTE_WAKE_DISCONNECT | |
| 3709 | USB_PORT_FEAT_REMOTE_WAKE_OVER_CURRENT, | 3709 | USB_PORT_FEAT_REMOTE_WAKE_OVER_CURRENT, |
| 3710 | USB_PORT_FEAT_REMOTE_WAKE_MASK); | 3710 | USB_PORT_FEAT_REMOTE_WAKE_MASK); |
| 3711 | } | 3711 | } |
| 3712 | } | 3712 | } |
| 3713 | 3713 | ||
| @@ -5902,7 +5902,10 @@ int usb_reset_device(struct usb_device *udev) | |||
| 5902 | cintf->needs_binding = 1; | 5902 | cintf->needs_binding = 1; |
| 5903 | } | 5903 | } |
| 5904 | } | 5904 | } |
| 5905 | usb_unbind_and_rebind_marked_interfaces(udev); | 5905 | |
| 5906 | /* If the reset failed, hub_wq will unbind drivers later */ | ||
| 5907 | if (ret == 0) | ||
| 5908 | usb_unbind_and_rebind_marked_interfaces(udev); | ||
| 5906 | } | 5909 | } |
| 5907 | 5910 | ||
| 5908 | usb_autosuspend_device(udev); | 5911 | usb_autosuspend_device(udev); |
diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c index 55d5ae2a7ec7..8b499d643461 100644 --- a/drivers/usb/dwc2/core.c +++ b/drivers/usb/dwc2/core.c | |||
| @@ -1020,6 +1020,205 @@ int dwc2_hsotg_wait_bit_clear(struct dwc2_hsotg *hsotg, u32 offset, u32 mask, | |||
| 1020 | return -ETIMEDOUT; | 1020 | return -ETIMEDOUT; |
| 1021 | } | 1021 | } |
| 1022 | 1022 | ||
| 1023 | /* | ||
| 1024 | * Initializes the FSLSPClkSel field of the HCFG register depending on the | ||
| 1025 | * PHY type | ||
| 1026 | */ | ||
| 1027 | void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg) | ||
| 1028 | { | ||
| 1029 | u32 hcfg, val; | ||
| 1030 | |||
| 1031 | if ((hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI && | ||
| 1032 | hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED && | ||
| 1033 | hsotg->params.ulpi_fs_ls) || | ||
| 1034 | hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS) { | ||
| 1035 | /* Full speed PHY */ | ||
| 1036 | val = HCFG_FSLSPCLKSEL_48_MHZ; | ||
| 1037 | } else { | ||
| 1038 | /* High speed PHY running at full speed or high speed */ | ||
| 1039 | val = HCFG_FSLSPCLKSEL_30_60_MHZ; | ||
| 1040 | } | ||
| 1041 | |||
| 1042 | dev_dbg(hsotg->dev, "Initializing HCFG.FSLSPClkSel to %08x\n", val); | ||
| 1043 | hcfg = dwc2_readl(hsotg, HCFG); | ||
| 1044 | hcfg &= ~HCFG_FSLSPCLKSEL_MASK; | ||
| 1045 | hcfg |= val << HCFG_FSLSPCLKSEL_SHIFT; | ||
| 1046 | dwc2_writel(hsotg, hcfg, HCFG); | ||
| 1047 | } | ||
| 1048 | |||
| 1049 | static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) | ||
| 1050 | { | ||
| 1051 | u32 usbcfg, ggpio, i2cctl; | ||
| 1052 | int retval = 0; | ||
| 1053 | |||
| 1054 | /* | ||
| 1055 | * core_init() is now called on every switch so only call the | ||
| 1056 | * following for the first time through | ||
| 1057 | */ | ||
| 1058 | if (select_phy) { | ||
| 1059 | dev_dbg(hsotg->dev, "FS PHY selected\n"); | ||
| 1060 | |||
| 1061 | usbcfg = dwc2_readl(hsotg, GUSBCFG); | ||
| 1062 | if (!(usbcfg & GUSBCFG_PHYSEL)) { | ||
| 1063 | usbcfg |= GUSBCFG_PHYSEL; | ||
| 1064 | dwc2_writel(hsotg, usbcfg, GUSBCFG); | ||
| 1065 | |||
| 1066 | /* Reset after a PHY select */ | ||
| 1067 | retval = dwc2_core_reset(hsotg, false); | ||
| 1068 | |||
| 1069 | if (retval) { | ||
| 1070 | dev_err(hsotg->dev, | ||
| 1071 | "%s: Reset failed, aborting", __func__); | ||
| 1072 | return retval; | ||
| 1073 | } | ||
| 1074 | } | ||
| 1075 | |||
| 1076 | if (hsotg->params.activate_stm_fs_transceiver) { | ||
| 1077 | ggpio = dwc2_readl(hsotg, GGPIO); | ||
| 1078 | if (!(ggpio & GGPIO_STM32_OTG_GCCFG_PWRDWN)) { | ||
| 1079 | dev_dbg(hsotg->dev, "Activating transceiver\n"); | ||
| 1080 | /* | ||
| 1081 | * STM32F4x9 uses the GGPIO register as general | ||
| 1082 | * core configuration register. | ||
| 1083 | */ | ||
| 1084 | ggpio |= GGPIO_STM32_OTG_GCCFG_PWRDWN; | ||
| 1085 | dwc2_writel(hsotg, ggpio, GGPIO); | ||
| 1086 | } | ||
| 1087 | } | ||
| 1088 | } | ||
| 1089 | |||
| 1090 | /* | ||
| 1091 | * Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS. Also | ||
| 1092 | * do this on HNP Dev/Host mode switches (done in dev_init and | ||
| 1093 | * host_init). | ||
| 1094 | */ | ||
| 1095 | if (dwc2_is_host_mode(hsotg)) | ||
| 1096 | dwc2_init_fs_ls_pclk_sel(hsotg); | ||
| 1097 | |||
| 1098 | if (hsotg->params.i2c_enable) { | ||
| 1099 | dev_dbg(hsotg->dev, "FS PHY enabling I2C\n"); | ||
| 1100 | |||
| 1101 | /* Program GUSBCFG.OtgUtmiFsSel to I2C */ | ||
| 1102 | usbcfg = dwc2_readl(hsotg, GUSBCFG); | ||
| 1103 | usbcfg |= GUSBCFG_OTG_UTMI_FS_SEL; | ||
| 1104 | dwc2_writel(hsotg, usbcfg, GUSBCFG); | ||
| 1105 | |||
| 1106 | /* Program GI2CCTL.I2CEn */ | ||
| 1107 | i2cctl = dwc2_readl(hsotg, GI2CCTL); | ||
| 1108 | i2cctl &= ~GI2CCTL_I2CDEVADDR_MASK; | ||
| 1109 | i2cctl |= 1 << GI2CCTL_I2CDEVADDR_SHIFT; | ||
| 1110 | i2cctl &= ~GI2CCTL_I2CEN; | ||
| 1111 | dwc2_writel(hsotg, i2cctl, GI2CCTL); | ||
| 1112 | i2cctl |= GI2CCTL_I2CEN; | ||
| 1113 | dwc2_writel(hsotg, i2cctl, GI2CCTL); | ||
| 1114 | } | ||
| 1115 | |||
| 1116 | return retval; | ||
| 1117 | } | ||
| 1118 | |||
| 1119 | static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) | ||
| 1120 | { | ||
| 1121 | u32 usbcfg, usbcfg_old; | ||
| 1122 | int retval = 0; | ||
| 1123 | |||
| 1124 | if (!select_phy) | ||
| 1125 | return 0; | ||
| 1126 | |||
| 1127 | usbcfg = dwc2_readl(hsotg, GUSBCFG); | ||
| 1128 | usbcfg_old = usbcfg; | ||
| 1129 | |||
| 1130 | /* | ||
| 1131 | * HS PHY parameters. These parameters are preserved during soft reset | ||
| 1132 | * so only program the first time. Do a soft reset immediately after | ||
| 1133 | * setting phyif. | ||
| 1134 | */ | ||
| 1135 | switch (hsotg->params.phy_type) { | ||
| 1136 | case DWC2_PHY_TYPE_PARAM_ULPI: | ||
| 1137 | /* ULPI interface */ | ||
| 1138 | dev_dbg(hsotg->dev, "HS ULPI PHY selected\n"); | ||
| 1139 | usbcfg |= GUSBCFG_ULPI_UTMI_SEL; | ||
| 1140 | usbcfg &= ~(GUSBCFG_PHYIF16 | GUSBCFG_DDRSEL); | ||
| 1141 | if (hsotg->params.phy_ulpi_ddr) | ||
| 1142 | usbcfg |= GUSBCFG_DDRSEL; | ||
| 1143 | |||
| 1144 | /* Set external VBUS indicator as needed. */ | ||
| 1145 | if (hsotg->params.oc_disable) | ||
| 1146 | usbcfg |= (GUSBCFG_ULPI_INT_VBUS_IND | | ||
| 1147 | GUSBCFG_INDICATORPASSTHROUGH); | ||
| 1148 | break; | ||
| 1149 | case DWC2_PHY_TYPE_PARAM_UTMI: | ||
| 1150 | /* UTMI+ interface */ | ||
| 1151 | dev_dbg(hsotg->dev, "HS UTMI+ PHY selected\n"); | ||
| 1152 | usbcfg &= ~(GUSBCFG_ULPI_UTMI_SEL | GUSBCFG_PHYIF16); | ||
| 1153 | if (hsotg->params.phy_utmi_width == 16) | ||
| 1154 | usbcfg |= GUSBCFG_PHYIF16; | ||
| 1155 | |||
| 1156 | /* Set turnaround time */ | ||
| 1157 | if (dwc2_is_device_mode(hsotg)) { | ||
| 1158 | usbcfg &= ~GUSBCFG_USBTRDTIM_MASK; | ||
| 1159 | if (hsotg->params.phy_utmi_width == 16) | ||
| 1160 | usbcfg |= 5 << GUSBCFG_USBTRDTIM_SHIFT; | ||
| 1161 | else | ||
| 1162 | usbcfg |= 9 << GUSBCFG_USBTRDTIM_SHIFT; | ||
| 1163 | } | ||
| 1164 | break; | ||
| 1165 | default: | ||
| 1166 | dev_err(hsotg->dev, "FS PHY selected at HS!\n"); | ||
| 1167 | break; | ||
| 1168 | } | ||
| 1169 | |||
| 1170 | if (usbcfg != usbcfg_old) { | ||
| 1171 | dwc2_writel(hsotg, usbcfg, GUSBCFG); | ||
| 1172 | |||
| 1173 | /* Reset after setting the PHY parameters */ | ||
| 1174 | retval = dwc2_core_reset(hsotg, false); | ||
| 1175 | if (retval) { | ||
| 1176 | dev_err(hsotg->dev, | ||
| 1177 | "%s: Reset failed, aborting", __func__); | ||
| 1178 | return retval; | ||
| 1179 | } | ||
| 1180 | } | ||
| 1181 | |||
| 1182 | return retval; | ||
| 1183 | } | ||
| 1184 | |||
| 1185 | int dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) | ||
| 1186 | { | ||
| 1187 | u32 usbcfg; | ||
| 1188 | int retval = 0; | ||
| 1189 | |||
| 1190 | if ((hsotg->params.speed == DWC2_SPEED_PARAM_FULL || | ||
| 1191 | hsotg->params.speed == DWC2_SPEED_PARAM_LOW) && | ||
| 1192 | hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS) { | ||
| 1193 | /* If FS/LS mode with FS/LS PHY */ | ||
| 1194 | retval = dwc2_fs_phy_init(hsotg, select_phy); | ||
| 1195 | if (retval) | ||
| 1196 | return retval; | ||
| 1197 | } else { | ||
| 1198 | /* High speed PHY */ | ||
| 1199 | retval = dwc2_hs_phy_init(hsotg, select_phy); | ||
| 1200 | if (retval) | ||
| 1201 | return retval; | ||
| 1202 | } | ||
| 1203 | |||
| 1204 | if (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI && | ||
| 1205 | hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED && | ||
| 1206 | hsotg->params.ulpi_fs_ls) { | ||
| 1207 | dev_dbg(hsotg->dev, "Setting ULPI FSLS\n"); | ||
| 1208 | usbcfg = dwc2_readl(hsotg, GUSBCFG); | ||
| 1209 | usbcfg |= GUSBCFG_ULPI_FS_LS; | ||
| 1210 | usbcfg |= GUSBCFG_ULPI_CLK_SUSP_M; | ||
| 1211 | dwc2_writel(hsotg, usbcfg, GUSBCFG); | ||
| 1212 | } else { | ||
| 1213 | usbcfg = dwc2_readl(hsotg, GUSBCFG); | ||
| 1214 | usbcfg &= ~GUSBCFG_ULPI_FS_LS; | ||
| 1215 | usbcfg &= ~GUSBCFG_ULPI_CLK_SUSP_M; | ||
| 1216 | dwc2_writel(hsotg, usbcfg, GUSBCFG); | ||
| 1217 | } | ||
| 1218 | |||
| 1219 | return retval; | ||
| 1220 | } | ||
| 1221 | |||
| 1023 | MODULE_DESCRIPTION("DESIGNWARE HS OTG Core"); | 1222 | MODULE_DESCRIPTION("DESIGNWARE HS OTG Core"); |
| 1024 | MODULE_AUTHOR("Synopsys, Inc."); | 1223 | MODULE_AUTHOR("Synopsys, Inc."); |
| 1025 | MODULE_LICENSE("Dual BSD/GPL"); | 1224 | MODULE_LICENSE("Dual BSD/GPL"); |
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index 30bab8463c96..152ac41dfb2d 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h | |||
| @@ -859,6 +859,8 @@ struct dwc2_hregs_backup { | |||
| 859 | * @gadget_enabled: Peripheral mode sub-driver initialization indicator. | 859 | * @gadget_enabled: Peripheral mode sub-driver initialization indicator. |
| 860 | * @ll_hw_enabled: Status of low-level hardware resources. | 860 | * @ll_hw_enabled: Status of low-level hardware resources. |
| 861 | * @hibernated: True if core is hibernated | 861 | * @hibernated: True if core is hibernated |
| 862 | * @reset_phy_on_wake: Quirk saying that we should assert PHY reset on a | ||
| 863 | * remote wakeup. | ||
| 862 | * @frame_number: Frame number read from the core. For both device | 864 | * @frame_number: Frame number read from the core. For both device |
| 863 | * and host modes. The value ranges are from 0 | 865 | * and host modes. The value ranges are from 0 |
| 864 | * to HFNUM_MAX_FRNUM. | 866 | * to HFNUM_MAX_FRNUM. |
| @@ -869,7 +871,6 @@ struct dwc2_hregs_backup { | |||
| 869 | * removed once all SoCs support usb transceiver. | 871 | * removed once all SoCs support usb transceiver. |
| 870 | * @supplies: Definition of USB power supplies | 872 | * @supplies: Definition of USB power supplies |
| 871 | * @vbus_supply: Regulator supplying vbus. | 873 | * @vbus_supply: Regulator supplying vbus. |
| 872 | * @phyif: PHY interface width | ||
| 873 | * @lock: Spinlock that protects all the driver data structures | 874 | * @lock: Spinlock that protects all the driver data structures |
| 874 | * @priv: Stores a pointer to the struct usb_hcd | 875 | * @priv: Stores a pointer to the struct usb_hcd |
| 875 | * @queuing_high_bandwidth: True if multiple packets of a high-bandwidth | 876 | * @queuing_high_bandwidth: True if multiple packets of a high-bandwidth |
| @@ -972,6 +973,7 @@ struct dwc2_hregs_backup { | |||
| 972 | * @status_buf_dma: DMA address for status_buf | 973 | * @status_buf_dma: DMA address for status_buf |
| 973 | * @start_work: Delayed work for handling host A-cable connection | 974 | * @start_work: Delayed work for handling host A-cable connection |
| 974 | * @reset_work: Delayed work for handling a port reset | 975 | * @reset_work: Delayed work for handling a port reset |
| 976 | * @phy_reset_work: Work structure for doing a PHY reset | ||
| 975 | * @otg_port: OTG port number | 977 | * @otg_port: OTG port number |
| 976 | * @frame_list: Frame list | 978 | * @frame_list: Frame list |
| 977 | * @frame_list_dma: Frame list DMA address | 979 | * @frame_list_dma: Frame list DMA address |
| @@ -991,6 +993,7 @@ struct dwc2_hregs_backup { | |||
| 991 | * @ctrl_buff: Buffer for EP0 control requests. | 993 | * @ctrl_buff: Buffer for EP0 control requests. |
| 992 | * @ctrl_req: Request for EP0 control packets. | 994 | * @ctrl_req: Request for EP0 control packets. |
| 993 | * @ep0_state: EP0 control transfers state | 995 | * @ep0_state: EP0 control transfers state |
| 996 | * @delayed_status: true when gadget driver asks for delayed status | ||
| 994 | * @test_mode: USB test mode requested by the host | 997 | * @test_mode: USB test mode requested by the host |
| 995 | * @remote_wakeup_allowed: True if device is allowed to wake-up host by | 998 | * @remote_wakeup_allowed: True if device is allowed to wake-up host by |
| 996 | * remote-wakeup signalling | 999 | * remote-wakeup signalling |
| @@ -1045,6 +1048,7 @@ struct dwc2_hsotg { | |||
| 1045 | unsigned int gadget_enabled:1; | 1048 | unsigned int gadget_enabled:1; |
| 1046 | unsigned int ll_hw_enabled:1; | 1049 | unsigned int ll_hw_enabled:1; |
| 1047 | unsigned int hibernated:1; | 1050 | unsigned int hibernated:1; |
| 1051 | unsigned int reset_phy_on_wake:1; | ||
| 1048 | u16 frame_number; | 1052 | u16 frame_number; |
| 1049 | 1053 | ||
| 1050 | struct phy *phy; | 1054 | struct phy *phy; |
| @@ -1052,7 +1056,6 @@ struct dwc2_hsotg { | |||
| 1052 | struct dwc2_hsotg_plat *plat; | 1056 | struct dwc2_hsotg_plat *plat; |
| 1053 | struct regulator_bulk_data supplies[DWC2_NUM_SUPPLIES]; | 1057 | struct regulator_bulk_data supplies[DWC2_NUM_SUPPLIES]; |
| 1054 | struct regulator *vbus_supply; | 1058 | struct regulator *vbus_supply; |
| 1055 | u32 phyif; | ||
| 1056 | 1059 | ||
| 1057 | spinlock_t lock; | 1060 | spinlock_t lock; |
| 1058 | void *priv; | 1061 | void *priv; |
| @@ -1147,6 +1150,7 @@ struct dwc2_hsotg { | |||
| 1147 | 1150 | ||
| 1148 | struct delayed_work start_work; | 1151 | struct delayed_work start_work; |
| 1149 | struct delayed_work reset_work; | 1152 | struct delayed_work reset_work; |
| 1153 | struct work_struct phy_reset_work; | ||
| 1150 | u8 otg_port; | 1154 | u8 otg_port; |
| 1151 | u32 *frame_list; | 1155 | u32 *frame_list; |
| 1152 | dma_addr_t frame_list_dma; | 1156 | dma_addr_t frame_list_dma; |
| @@ -1172,6 +1176,7 @@ struct dwc2_hsotg { | |||
| 1172 | void *ep0_buff; | 1176 | void *ep0_buff; |
| 1173 | void *ctrl_buff; | 1177 | void *ctrl_buff; |
| 1174 | enum dwc2_ep0_state ep0_state; | 1178 | enum dwc2_ep0_state ep0_state; |
| 1179 | unsigned delayed_status : 1; | ||
| 1175 | u8 test_mode; | 1180 | u8 test_mode; |
| 1176 | 1181 | ||
| 1177 | dma_addr_t setup_desc_dma[2]; | 1182 | dma_addr_t setup_desc_dma[2]; |
| @@ -1283,6 +1288,8 @@ int dwc2_exit_partial_power_down(struct dwc2_hsotg *hsotg, bool restore); | |||
| 1283 | int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg, int is_host); | 1288 | int dwc2_enter_hibernation(struct dwc2_hsotg *hsotg, int is_host); |
| 1284 | int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup, | 1289 | int dwc2_exit_hibernation(struct dwc2_hsotg *hsotg, int rem_wakeup, |
| 1285 | int reset, int is_host); | 1290 | int reset, int is_host); |
| 1291 | void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg); | ||
| 1292 | int dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy); | ||
| 1286 | 1293 | ||
| 1287 | void dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host); | 1294 | void dwc2_force_mode(struct dwc2_hsotg *hsotg, bool host); |
| 1288 | void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg); | 1295 | void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg); |
| @@ -1431,6 +1438,8 @@ int dwc2_restore_host_registers(struct dwc2_hsotg *hsotg); | |||
| 1431 | int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg); | 1438 | int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg); |
| 1432 | int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, | 1439 | int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, |
| 1433 | int rem_wakeup, int reset); | 1440 | int rem_wakeup, int reset); |
| 1441 | static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg) | ||
| 1442 | { schedule_work(&hsotg->phy_reset_work); } | ||
| 1434 | #else | 1443 | #else |
| 1435 | static inline int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg) | 1444 | static inline int dwc2_hcd_get_frame_number(struct dwc2_hsotg *hsotg) |
| 1436 | { return 0; } | 1445 | { return 0; } |
| @@ -1454,6 +1463,7 @@ static inline int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg) | |||
| 1454 | static inline int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, | 1463 | static inline int dwc2_host_exit_hibernation(struct dwc2_hsotg *hsotg, |
| 1455 | int rem_wakeup, int reset) | 1464 | int rem_wakeup, int reset) |
| 1456 | { return 0; } | 1465 | { return 0; } |
| 1466 | static inline void dwc2_host_schedule_phy_reset(struct dwc2_hsotg *hsotg) {} | ||
| 1457 | 1467 | ||
| 1458 | #endif | 1468 | #endif |
| 1459 | 1469 | ||
diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c index 19ae2595f1c3..6af6add3d4c0 100644 --- a/drivers/usb/dwc2/core_intr.c +++ b/drivers/usb/dwc2/core_intr.c | |||
| @@ -435,6 +435,18 @@ static void dwc2_handle_wakeup_detected_intr(struct dwc2_hsotg *hsotg) | |||
| 435 | /* Restart the Phy Clock */ | 435 | /* Restart the Phy Clock */ |
| 436 | pcgcctl &= ~PCGCTL_STOPPCLK; | 436 | pcgcctl &= ~PCGCTL_STOPPCLK; |
| 437 | dwc2_writel(hsotg, pcgcctl, PCGCTL); | 437 | dwc2_writel(hsotg, pcgcctl, PCGCTL); |
| 438 | |||
| 439 | /* | ||
| 440 | * If we've got this quirk then the PHY is stuck upon | ||
| 441 | * wakeup. Assert reset. This will propagate out and | ||
| 442 | * eventually we'll re-enumerate the device. Not great | ||
| 443 | * but the best we can do. We can't call phy_reset() | ||
| 444 | * at interrupt time but there's no hurry, so we'll | ||
| 445 | * schedule it for later. | ||
| 446 | */ | ||
| 447 | if (hsotg->reset_phy_on_wake) | ||
| 448 | dwc2_host_schedule_phy_reset(hsotg); | ||
| 449 | |||
| 438 | mod_timer(&hsotg->wkp_timer, | 450 | mod_timer(&hsotg->wkp_timer, |
| 439 | jiffies + msecs_to_jiffies(71)); | 451 | jiffies + msecs_to_jiffies(71)); |
| 440 | } else { | 452 | } else { |
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c index 6812a8a3a98b..16ffd9fd9361 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c | |||
| @@ -27,6 +27,8 @@ | |||
| 27 | #include <linux/usb/ch9.h> | 27 | #include <linux/usb/ch9.h> |
| 28 | #include <linux/usb/gadget.h> | 28 | #include <linux/usb/gadget.h> |
| 29 | #include <linux/usb/phy.h> | 29 | #include <linux/usb/phy.h> |
| 30 | #include <linux/usb/composite.h> | ||
| 31 | |||
| 30 | 32 | ||
| 31 | #include "core.h" | 33 | #include "core.h" |
| 32 | #include "hw.h" | 34 | #include "hw.h" |
| @@ -714,13 +716,11 @@ static unsigned int dwc2_gadget_get_chain_limit(struct dwc2_hsotg_ep *hs_ep) | |||
| 714 | unsigned int maxsize; | 716 | unsigned int maxsize; |
| 715 | 717 | ||
| 716 | if (is_isoc) | 718 | if (is_isoc) |
| 717 | maxsize = hs_ep->dir_in ? DEV_DMA_ISOC_TX_NBYTES_LIMIT : | 719 | maxsize = (hs_ep->dir_in ? DEV_DMA_ISOC_TX_NBYTES_LIMIT : |
| 718 | DEV_DMA_ISOC_RX_NBYTES_LIMIT; | 720 | DEV_DMA_ISOC_RX_NBYTES_LIMIT) * |
| 721 | MAX_DMA_DESC_NUM_HS_ISOC; | ||
| 719 | else | 722 | else |
| 720 | maxsize = DEV_DMA_NBYTES_LIMIT; | 723 | maxsize = DEV_DMA_NBYTES_LIMIT * MAX_DMA_DESC_NUM_GENERIC; |
| 721 | |||
| 722 | /* Above size of one descriptor was chosen, multiple it */ | ||
| 723 | maxsize *= MAX_DMA_DESC_NUM_GENERIC; | ||
| 724 | 724 | ||
| 725 | return maxsize; | 725 | return maxsize; |
| 726 | } | 726 | } |
| @@ -932,7 +932,7 @@ static int dwc2_gadget_fill_isoc_desc(struct dwc2_hsotg_ep *hs_ep, | |||
| 932 | 932 | ||
| 933 | /* Update index of last configured entry in the chain */ | 933 | /* Update index of last configured entry in the chain */ |
| 934 | hs_ep->next_desc++; | 934 | hs_ep->next_desc++; |
| 935 | if (hs_ep->next_desc >= MAX_DMA_DESC_NUM_GENERIC) | 935 | if (hs_ep->next_desc >= MAX_DMA_DESC_NUM_HS_ISOC) |
| 936 | hs_ep->next_desc = 0; | 936 | hs_ep->next_desc = 0; |
| 937 | 937 | ||
| 938 | return 0; | 938 | return 0; |
| @@ -964,7 +964,7 @@ static void dwc2_gadget_start_isoc_ddma(struct dwc2_hsotg_ep *hs_ep) | |||
| 964 | } | 964 | } |
| 965 | 965 | ||
| 966 | /* Initialize descriptor chain by Host Busy status */ | 966 | /* Initialize descriptor chain by Host Busy status */ |
| 967 | for (i = 0; i < MAX_DMA_DESC_NUM_GENERIC; i++) { | 967 | for (i = 0; i < MAX_DMA_DESC_NUM_HS_ISOC; i++) { |
| 968 | desc = &hs_ep->desc_list[i]; | 968 | desc = &hs_ep->desc_list[i]; |
| 969 | desc->status = 0; | 969 | desc->status = 0; |
| 970 | desc->status |= (DEV_DMA_BUFF_STS_HBUSY | 970 | desc->status |= (DEV_DMA_BUFF_STS_HBUSY |
| @@ -1446,6 +1446,11 @@ static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, | |||
| 1446 | return 0; | 1446 | return 0; |
| 1447 | } | 1447 | } |
| 1448 | 1448 | ||
| 1449 | /* Change EP direction if status phase request is after data out */ | ||
| 1450 | if (!hs_ep->index && !req->length && !hs_ep->dir_in && | ||
| 1451 | hs->ep0_state == DWC2_EP0_DATA_OUT) | ||
| 1452 | hs_ep->dir_in = 1; | ||
| 1453 | |||
| 1449 | if (first) { | 1454 | if (first) { |
| 1450 | if (!hs_ep->isochronous) { | 1455 | if (!hs_ep->isochronous) { |
| 1451 | dwc2_hsotg_start_req(hs, hs_ep, hs_req, false); | 1456 | dwc2_hsotg_start_req(hs, hs_ep, hs_req, false); |
| @@ -1938,6 +1943,10 @@ static void dwc2_hsotg_process_control(struct dwc2_hsotg *hsotg, | |||
| 1938 | dev_dbg(hsotg->dev, "driver->setup() ret %d\n", ret); | 1943 | dev_dbg(hsotg->dev, "driver->setup() ret %d\n", ret); |
| 1939 | } | 1944 | } |
| 1940 | 1945 | ||
| 1946 | hsotg->delayed_status = false; | ||
| 1947 | if (ret == USB_GADGET_DELAYED_STATUS) | ||
| 1948 | hsotg->delayed_status = true; | ||
| 1949 | |||
| 1941 | /* | 1950 | /* |
| 1942 | * the request is either unhandlable, or is not formatted correctly | 1951 | * the request is either unhandlable, or is not formatted correctly |
| 1943 | * so respond with a STALL for the status stage to indicate failure. | 1952 | * so respond with a STALL for the status stage to indicate failure. |
| @@ -2157,12 +2166,17 @@ static void dwc2_gadget_complete_isoc_request_ddma(struct dwc2_hsotg_ep *hs_ep) | |||
| 2157 | */ | 2166 | */ |
| 2158 | if (!hs_ep->dir_in && ureq->length & 0x3) | 2167 | if (!hs_ep->dir_in && ureq->length & 0x3) |
| 2159 | ureq->actual += 4 - (ureq->length & 0x3); | 2168 | ureq->actual += 4 - (ureq->length & 0x3); |
| 2169 | |||
| 2170 | /* Set actual frame number for completed transfers */ | ||
| 2171 | ureq->frame_number = | ||
| 2172 | (desc_sts & DEV_DMA_ISOC_FRNUM_MASK) >> | ||
| 2173 | DEV_DMA_ISOC_FRNUM_SHIFT; | ||
| 2160 | } | 2174 | } |
| 2161 | 2175 | ||
| 2162 | dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); | 2176 | dwc2_hsotg_complete_request(hsotg, hs_ep, hs_req, 0); |
| 2163 | 2177 | ||
| 2164 | hs_ep->compl_desc++; | 2178 | hs_ep->compl_desc++; |
| 2165 | if (hs_ep->compl_desc > (MAX_DMA_DESC_NUM_GENERIC - 1)) | 2179 | if (hs_ep->compl_desc > (MAX_DMA_DESC_NUM_HS_ISOC - 1)) |
| 2166 | hs_ep->compl_desc = 0; | 2180 | hs_ep->compl_desc = 0; |
| 2167 | desc_sts = hs_ep->desc_list[hs_ep->compl_desc].status; | 2181 | desc_sts = hs_ep->desc_list[hs_ep->compl_desc].status; |
| 2168 | } | 2182 | } |
| @@ -2311,6 +2325,7 @@ static unsigned int dwc2_gadget_get_xfersize_ddma(struct dwc2_hsotg_ep *hs_ep) | |||
| 2311 | if (status & DEV_DMA_STS_MASK) | 2325 | if (status & DEV_DMA_STS_MASK) |
| 2312 | dev_err(hsotg->dev, "descriptor %d closed with %x\n", | 2326 | dev_err(hsotg->dev, "descriptor %d closed with %x\n", |
| 2313 | i, status & DEV_DMA_STS_MASK); | 2327 | i, status & DEV_DMA_STS_MASK); |
| 2328 | desc++; | ||
| 2314 | } | 2329 | } |
| 2315 | 2330 | ||
| 2316 | return bytes_rem; | 2331 | return bytes_rem; |
| @@ -2387,8 +2402,8 @@ static void dwc2_hsotg_handle_outdone(struct dwc2_hsotg *hsotg, int epnum) | |||
| 2387 | if (!using_desc_dma(hsotg) && epnum == 0 && | 2402 | if (!using_desc_dma(hsotg) && epnum == 0 && |
| 2388 | hsotg->ep0_state == DWC2_EP0_DATA_OUT) { | 2403 | hsotg->ep0_state == DWC2_EP0_DATA_OUT) { |
| 2389 | /* Move to STATUS IN */ | 2404 | /* Move to STATUS IN */ |
| 2390 | dwc2_hsotg_ep0_zlp(hsotg, true); | 2405 | if (!hsotg->delayed_status) |
| 2391 | return; | 2406 | dwc2_hsotg_ep0_zlp(hsotg, true); |
| 2392 | } | 2407 | } |
| 2393 | 2408 | ||
| 2394 | /* | 2409 | /* |
| @@ -3053,8 +3068,20 @@ static void dwc2_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx, | |||
| 3053 | /* Safety check EP0 state when STSPHSERCVD asserted */ | 3068 | /* Safety check EP0 state when STSPHSERCVD asserted */ |
| 3054 | if (hsotg->ep0_state == DWC2_EP0_DATA_OUT) { | 3069 | if (hsotg->ep0_state == DWC2_EP0_DATA_OUT) { |
| 3055 | /* Move to STATUS IN for DDMA */ | 3070 | /* Move to STATUS IN for DDMA */ |
| 3056 | if (using_desc_dma(hsotg)) | 3071 | if (using_desc_dma(hsotg)) { |
| 3057 | dwc2_hsotg_ep0_zlp(hsotg, true); | 3072 | if (!hsotg->delayed_status) |
| 3073 | dwc2_hsotg_ep0_zlp(hsotg, true); | ||
| 3074 | else | ||
| 3075 | /* In case of 3 stage Control Write with delayed | ||
| 3076 | * status, when Status IN transfer started | ||
| 3077 | * before STSPHSERCVD asserted, NAKSTS bit not | ||
| 3078 | * cleared by CNAK in dwc2_hsotg_start_req() | ||
| 3079 | * function. Clear now NAKSTS to allow complete | ||
| 3080 | * transfer. | ||
| 3081 | */ | ||
| 3082 | dwc2_set_bit(hsotg, DIEPCTL(0), | ||
| 3083 | DXEPCTL_CNAK); | ||
| 3084 | } | ||
| 3058 | } | 3085 | } |
| 3059 | 3086 | ||
| 3060 | } | 3087 | } |
| @@ -3314,21 +3341,14 @@ void dwc2_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg, | |||
| 3314 | 3341 | ||
| 3315 | /* keep other bits untouched (so e.g. forced modes are not lost) */ | 3342 | /* keep other bits untouched (so e.g. forced modes are not lost) */ |
| 3316 | usbcfg = dwc2_readl(hsotg, GUSBCFG); | 3343 | usbcfg = dwc2_readl(hsotg, GUSBCFG); |
| 3317 | usbcfg &= ~(GUSBCFG_TOUTCAL_MASK | GUSBCFG_PHYIF16 | GUSBCFG_SRPCAP | | 3344 | usbcfg &= ~GUSBCFG_TOUTCAL_MASK; |
| 3318 | GUSBCFG_HNPCAP | GUSBCFG_USBTRDTIM_MASK); | 3345 | usbcfg |= GUSBCFG_TOUTCAL(7); |
| 3319 | 3346 | ||
| 3320 | if (hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS && | 3347 | /* remove the HNP/SRP and set the PHY */ |
| 3321 | (hsotg->params.speed == DWC2_SPEED_PARAM_FULL || | 3348 | usbcfg &= ~(GUSBCFG_SRPCAP | GUSBCFG_HNPCAP); |
| 3322 | hsotg->params.speed == DWC2_SPEED_PARAM_LOW)) { | 3349 | dwc2_writel(hsotg, usbcfg, GUSBCFG); |
| 3323 | /* FS/LS Dedicated Transceiver Interface */ | 3350 | |
| 3324 | usbcfg |= GUSBCFG_PHYSEL; | 3351 | dwc2_phy_init(hsotg, true); |
| 3325 | } else { | ||
| 3326 | /* set the PLL on, remove the HNP/SRP and set the PHY */ | ||
| 3327 | val = (hsotg->phyif == GUSBCFG_PHYIF8) ? 9 : 5; | ||
| 3328 | usbcfg |= hsotg->phyif | GUSBCFG_TOUTCAL(7) | | ||
| 3329 | (val << GUSBCFG_USBTRDTIM_SHIFT); | ||
| 3330 | } | ||
| 3331 | dwc2_writel(hsotg, usbcfg, GUSBCFG); | ||
| 3332 | 3352 | ||
| 3333 | dwc2_hsotg_init_fifo(hsotg); | 3353 | dwc2_hsotg_init_fifo(hsotg); |
| 3334 | 3354 | ||
| @@ -3899,6 +3919,7 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep, | |||
| 3899 | unsigned int i, val, size; | 3919 | unsigned int i, val, size; |
| 3900 | int ret = 0; | 3920 | int ret = 0; |
| 3901 | unsigned char ep_type; | 3921 | unsigned char ep_type; |
| 3922 | int desc_num; | ||
| 3902 | 3923 | ||
| 3903 | dev_dbg(hsotg->dev, | 3924 | dev_dbg(hsotg->dev, |
| 3904 | "%s: ep %s: a 0x%02x, attr 0x%02x, mps 0x%04x, intr %d\n", | 3925 | "%s: ep %s: a 0x%02x, attr 0x%02x, mps 0x%04x, intr %d\n", |
| @@ -3945,11 +3966,15 @@ static int dwc2_hsotg_ep_enable(struct usb_ep *ep, | |||
| 3945 | dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x from 0x%08x\n", | 3966 | dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x from 0x%08x\n", |
| 3946 | __func__, epctrl, epctrl_reg); | 3967 | __func__, epctrl, epctrl_reg); |
| 3947 | 3968 | ||
| 3969 | if (using_desc_dma(hsotg) && ep_type == USB_ENDPOINT_XFER_ISOC) | ||
| 3970 | desc_num = MAX_DMA_DESC_NUM_HS_ISOC; | ||
| 3971 | else | ||
| 3972 | desc_num = MAX_DMA_DESC_NUM_GENERIC; | ||
| 3973 | |||
| 3948 | /* Allocate DMA descriptor chain for non-ctrl endpoints */ | 3974 | /* Allocate DMA descriptor chain for non-ctrl endpoints */ |
| 3949 | if (using_desc_dma(hsotg) && !hs_ep->desc_list) { | 3975 | if (using_desc_dma(hsotg) && !hs_ep->desc_list) { |
| 3950 | hs_ep->desc_list = dmam_alloc_coherent(hsotg->dev, | 3976 | hs_ep->desc_list = dmam_alloc_coherent(hsotg->dev, |
| 3951 | MAX_DMA_DESC_NUM_GENERIC * | 3977 | desc_num * sizeof(struct dwc2_dma_desc), |
| 3952 | sizeof(struct dwc2_dma_desc), | ||
| 3953 | &hs_ep->desc_list_dma, GFP_ATOMIC); | 3978 | &hs_ep->desc_list_dma, GFP_ATOMIC); |
| 3954 | if (!hs_ep->desc_list) { | 3979 | if (!hs_ep->desc_list) { |
| 3955 | ret = -ENOMEM; | 3980 | ret = -ENOMEM; |
| @@ -4092,7 +4117,7 @@ error1: | |||
| 4092 | 4117 | ||
| 4093 | error2: | 4118 | error2: |
| 4094 | if (ret && using_desc_dma(hsotg) && hs_ep->desc_list) { | 4119 | if (ret && using_desc_dma(hsotg) && hs_ep->desc_list) { |
| 4095 | dmam_free_coherent(hsotg->dev, MAX_DMA_DESC_NUM_GENERIC * | 4120 | dmam_free_coherent(hsotg->dev, desc_num * |
| 4096 | sizeof(struct dwc2_dma_desc), | 4121 | sizeof(struct dwc2_dma_desc), |
| 4097 | hs_ep->desc_list, hs_ep->desc_list_dma); | 4122 | hs_ep->desc_list, hs_ep->desc_list_dma); |
| 4098 | hs_ep->desc_list = NULL; | 4123 | hs_ep->desc_list = NULL; |
| @@ -4328,8 +4353,6 @@ static const struct usb_ep_ops dwc2_hsotg_ep_ops = { | |||
| 4328 | */ | 4353 | */ |
| 4329 | static void dwc2_hsotg_init(struct dwc2_hsotg *hsotg) | 4354 | static void dwc2_hsotg_init(struct dwc2_hsotg *hsotg) |
| 4330 | { | 4355 | { |
| 4331 | u32 trdtim; | ||
| 4332 | u32 usbcfg; | ||
| 4333 | /* unmask subset of endpoint interrupts */ | 4356 | /* unmask subset of endpoint interrupts */ |
| 4334 | 4357 | ||
| 4335 | dwc2_writel(hsotg, DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK | | 4358 | dwc2_writel(hsotg, DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK | |
| @@ -4353,17 +4376,6 @@ static void dwc2_hsotg_init(struct dwc2_hsotg *hsotg) | |||
| 4353 | 4376 | ||
| 4354 | dwc2_hsotg_init_fifo(hsotg); | 4377 | dwc2_hsotg_init_fifo(hsotg); |
| 4355 | 4378 | ||
| 4356 | /* keep other bits untouched (so e.g. forced modes are not lost) */ | ||
| 4357 | usbcfg = dwc2_readl(hsotg, GUSBCFG); | ||
| 4358 | usbcfg &= ~(GUSBCFG_TOUTCAL_MASK | GUSBCFG_PHYIF16 | GUSBCFG_SRPCAP | | ||
| 4359 | GUSBCFG_HNPCAP | GUSBCFG_USBTRDTIM_MASK); | ||
| 4360 | |||
| 4361 | /* set the PLL on, remove the HNP/SRP and set the PHY */ | ||
| 4362 | trdtim = (hsotg->phyif == GUSBCFG_PHYIF8) ? 9 : 5; | ||
| 4363 | usbcfg |= hsotg->phyif | GUSBCFG_TOUTCAL(7) | | ||
| 4364 | (trdtim << GUSBCFG_USBTRDTIM_SHIFT); | ||
| 4365 | dwc2_writel(hsotg, usbcfg, GUSBCFG); | ||
| 4366 | |||
| 4367 | if (using_dma(hsotg)) | 4379 | if (using_dma(hsotg)) |
| 4368 | dwc2_set_bit(hsotg, GAHBCFG, GAHBCFG_DMA_EN); | 4380 | dwc2_set_bit(hsotg, GAHBCFG, GAHBCFG_DMA_EN); |
| 4369 | } | 4381 | } |
| @@ -5073,6 +5085,7 @@ void dwc2_gadget_init_lpm(struct dwc2_hsotg *hsotg) | |||
| 5073 | val |= hsotg->params.lpm_clock_gating ? GLPMCFG_ENBLSLPM : 0; | 5085 | val |= hsotg->params.lpm_clock_gating ? GLPMCFG_ENBLSLPM : 0; |
| 5074 | val |= hsotg->params.hird_threshold << GLPMCFG_HIRD_THRES_SHIFT; | 5086 | val |= hsotg->params.hird_threshold << GLPMCFG_HIRD_THRES_SHIFT; |
| 5075 | val |= hsotg->params.besl ? GLPMCFG_ENBESL : 0; | 5087 | val |= hsotg->params.besl ? GLPMCFG_ENBESL : 0; |
| 5088 | val |= GLPMCFG_LPM_REJECT_CTRL_CONTROL; | ||
| 5076 | val |= GLPMCFG_LPM_ACCEPT_CTRL_ISOC; | 5089 | val |= GLPMCFG_LPM_ACCEPT_CTRL_ISOC; |
| 5077 | dwc2_writel(hsotg, val, GLPMCFG); | 5090 | dwc2_writel(hsotg, val, GLPMCFG); |
| 5078 | dev_dbg(hsotg->dev, "GLPMCFG=0x%08x\n", dwc2_readl(hsotg, GLPMCFG)); | 5091 | dev_dbg(hsotg->dev, "GLPMCFG=0x%08x\n", dwc2_readl(hsotg, GLPMCFG)); |
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index 3f087962f498..b50ec3714fd8 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c | |||
| @@ -97,196 +97,6 @@ static void dwc2_enable_common_interrupts(struct dwc2_hsotg *hsotg) | |||
| 97 | dwc2_writel(hsotg, intmsk, GINTMSK); | 97 | dwc2_writel(hsotg, intmsk, GINTMSK); |
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | /* | ||
| 101 | * Initializes the FSLSPClkSel field of the HCFG register depending on the | ||
| 102 | * PHY type | ||
| 103 | */ | ||
| 104 | static void dwc2_init_fs_ls_pclk_sel(struct dwc2_hsotg *hsotg) | ||
| 105 | { | ||
| 106 | u32 hcfg, val; | ||
| 107 | |||
| 108 | if ((hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI && | ||
| 109 | hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED && | ||
| 110 | hsotg->params.ulpi_fs_ls) || | ||
| 111 | hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS) { | ||
| 112 | /* Full speed PHY */ | ||
| 113 | val = HCFG_FSLSPCLKSEL_48_MHZ; | ||
| 114 | } else { | ||
| 115 | /* High speed PHY running at full speed or high speed */ | ||
| 116 | val = HCFG_FSLSPCLKSEL_30_60_MHZ; | ||
| 117 | } | ||
| 118 | |||
| 119 | dev_dbg(hsotg->dev, "Initializing HCFG.FSLSPClkSel to %08x\n", val); | ||
| 120 | hcfg = dwc2_readl(hsotg, HCFG); | ||
| 121 | hcfg &= ~HCFG_FSLSPCLKSEL_MASK; | ||
| 122 | hcfg |= val << HCFG_FSLSPCLKSEL_SHIFT; | ||
| 123 | dwc2_writel(hsotg, hcfg, HCFG); | ||
| 124 | } | ||
| 125 | |||
| 126 | static int dwc2_fs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) | ||
| 127 | { | ||
| 128 | u32 usbcfg, ggpio, i2cctl; | ||
| 129 | int retval = 0; | ||
| 130 | |||
| 131 | /* | ||
| 132 | * core_init() is now called on every switch so only call the | ||
| 133 | * following for the first time through | ||
| 134 | */ | ||
| 135 | if (select_phy) { | ||
| 136 | dev_dbg(hsotg->dev, "FS PHY selected\n"); | ||
| 137 | |||
| 138 | usbcfg = dwc2_readl(hsotg, GUSBCFG); | ||
| 139 | if (!(usbcfg & GUSBCFG_PHYSEL)) { | ||
| 140 | usbcfg |= GUSBCFG_PHYSEL; | ||
| 141 | dwc2_writel(hsotg, usbcfg, GUSBCFG); | ||
| 142 | |||
| 143 | /* Reset after a PHY select */ | ||
| 144 | retval = dwc2_core_reset(hsotg, false); | ||
| 145 | |||
| 146 | if (retval) { | ||
| 147 | dev_err(hsotg->dev, | ||
| 148 | "%s: Reset failed, aborting", __func__); | ||
| 149 | return retval; | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 153 | if (hsotg->params.activate_stm_fs_transceiver) { | ||
| 154 | ggpio = dwc2_readl(hsotg, GGPIO); | ||
| 155 | if (!(ggpio & GGPIO_STM32_OTG_GCCFG_PWRDWN)) { | ||
| 156 | dev_dbg(hsotg->dev, "Activating transceiver\n"); | ||
| 157 | /* | ||
| 158 | * STM32F4x9 uses the GGPIO register as general | ||
| 159 | * core configuration register. | ||
| 160 | */ | ||
| 161 | ggpio |= GGPIO_STM32_OTG_GCCFG_PWRDWN; | ||
| 162 | dwc2_writel(hsotg, ggpio, GGPIO); | ||
| 163 | } | ||
| 164 | } | ||
| 165 | } | ||
| 166 | |||
| 167 | /* | ||
| 168 | * Program DCFG.DevSpd or HCFG.FSLSPclkSel to 48Mhz in FS. Also | ||
| 169 | * do this on HNP Dev/Host mode switches (done in dev_init and | ||
| 170 | * host_init). | ||
| 171 | */ | ||
| 172 | if (dwc2_is_host_mode(hsotg)) | ||
| 173 | dwc2_init_fs_ls_pclk_sel(hsotg); | ||
| 174 | |||
| 175 | if (hsotg->params.i2c_enable) { | ||
| 176 | dev_dbg(hsotg->dev, "FS PHY enabling I2C\n"); | ||
| 177 | |||
| 178 | /* Program GUSBCFG.OtgUtmiFsSel to I2C */ | ||
| 179 | usbcfg = dwc2_readl(hsotg, GUSBCFG); | ||
| 180 | usbcfg |= GUSBCFG_OTG_UTMI_FS_SEL; | ||
| 181 | dwc2_writel(hsotg, usbcfg, GUSBCFG); | ||
| 182 | |||
| 183 | /* Program GI2CCTL.I2CEn */ | ||
| 184 | i2cctl = dwc2_readl(hsotg, GI2CCTL); | ||
| 185 | i2cctl &= ~GI2CCTL_I2CDEVADDR_MASK; | ||
| 186 | i2cctl |= 1 << GI2CCTL_I2CDEVADDR_SHIFT; | ||
| 187 | i2cctl &= ~GI2CCTL_I2CEN; | ||
| 188 | dwc2_writel(hsotg, i2cctl, GI2CCTL); | ||
| 189 | i2cctl |= GI2CCTL_I2CEN; | ||
| 190 | dwc2_writel(hsotg, i2cctl, GI2CCTL); | ||
| 191 | } | ||
| 192 | |||
| 193 | return retval; | ||
| 194 | } | ||
| 195 | |||
| 196 | static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) | ||
| 197 | { | ||
| 198 | u32 usbcfg, usbcfg_old; | ||
| 199 | int retval = 0; | ||
| 200 | |||
| 201 | if (!select_phy) | ||
| 202 | return 0; | ||
| 203 | |||
| 204 | usbcfg = dwc2_readl(hsotg, GUSBCFG); | ||
| 205 | usbcfg_old = usbcfg; | ||
| 206 | |||
| 207 | /* | ||
| 208 | * HS PHY parameters. These parameters are preserved during soft reset | ||
| 209 | * so only program the first time. Do a soft reset immediately after | ||
| 210 | * setting phyif. | ||
| 211 | */ | ||
| 212 | switch (hsotg->params.phy_type) { | ||
| 213 | case DWC2_PHY_TYPE_PARAM_ULPI: | ||
| 214 | /* ULPI interface */ | ||
| 215 | dev_dbg(hsotg->dev, "HS ULPI PHY selected\n"); | ||
| 216 | usbcfg |= GUSBCFG_ULPI_UTMI_SEL; | ||
| 217 | usbcfg &= ~(GUSBCFG_PHYIF16 | GUSBCFG_DDRSEL); | ||
| 218 | if (hsotg->params.phy_ulpi_ddr) | ||
| 219 | usbcfg |= GUSBCFG_DDRSEL; | ||
| 220 | |||
| 221 | /* Set external VBUS indicator as needed. */ | ||
| 222 | if (hsotg->params.oc_disable) | ||
| 223 | usbcfg |= (GUSBCFG_ULPI_INT_VBUS_IND | | ||
| 224 | GUSBCFG_INDICATORPASSTHROUGH); | ||
| 225 | break; | ||
| 226 | case DWC2_PHY_TYPE_PARAM_UTMI: | ||
| 227 | /* UTMI+ interface */ | ||
| 228 | dev_dbg(hsotg->dev, "HS UTMI+ PHY selected\n"); | ||
| 229 | usbcfg &= ~(GUSBCFG_ULPI_UTMI_SEL | GUSBCFG_PHYIF16); | ||
| 230 | if (hsotg->params.phy_utmi_width == 16) | ||
| 231 | usbcfg |= GUSBCFG_PHYIF16; | ||
| 232 | break; | ||
| 233 | default: | ||
| 234 | dev_err(hsotg->dev, "FS PHY selected at HS!\n"); | ||
| 235 | break; | ||
| 236 | } | ||
| 237 | |||
| 238 | if (usbcfg != usbcfg_old) { | ||
| 239 | dwc2_writel(hsotg, usbcfg, GUSBCFG); | ||
| 240 | |||
| 241 | /* Reset after setting the PHY parameters */ | ||
| 242 | retval = dwc2_core_reset(hsotg, false); | ||
| 243 | if (retval) { | ||
| 244 | dev_err(hsotg->dev, | ||
| 245 | "%s: Reset failed, aborting", __func__); | ||
| 246 | return retval; | ||
| 247 | } | ||
| 248 | } | ||
| 249 | |||
| 250 | return retval; | ||
| 251 | } | ||
| 252 | |||
| 253 | static int dwc2_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) | ||
| 254 | { | ||
| 255 | u32 usbcfg; | ||
| 256 | int retval = 0; | ||
| 257 | |||
| 258 | if ((hsotg->params.speed == DWC2_SPEED_PARAM_FULL || | ||
| 259 | hsotg->params.speed == DWC2_SPEED_PARAM_LOW) && | ||
| 260 | hsotg->params.phy_type == DWC2_PHY_TYPE_PARAM_FS) { | ||
| 261 | /* If FS/LS mode with FS/LS PHY */ | ||
| 262 | retval = dwc2_fs_phy_init(hsotg, select_phy); | ||
| 263 | if (retval) | ||
| 264 | return retval; | ||
| 265 | } else { | ||
| 266 | /* High speed PHY */ | ||
| 267 | retval = dwc2_hs_phy_init(hsotg, select_phy); | ||
| 268 | if (retval) | ||
| 269 | return retval; | ||
| 270 | } | ||
| 271 | |||
| 272 | if (hsotg->hw_params.hs_phy_type == GHWCFG2_HS_PHY_TYPE_ULPI && | ||
| 273 | hsotg->hw_params.fs_phy_type == GHWCFG2_FS_PHY_TYPE_DEDICATED && | ||
| 274 | hsotg->params.ulpi_fs_ls) { | ||
| 275 | dev_dbg(hsotg->dev, "Setting ULPI FSLS\n"); | ||
| 276 | usbcfg = dwc2_readl(hsotg, GUSBCFG); | ||
| 277 | usbcfg |= GUSBCFG_ULPI_FS_LS; | ||
| 278 | usbcfg |= GUSBCFG_ULPI_CLK_SUSP_M; | ||
| 279 | dwc2_writel(hsotg, usbcfg, GUSBCFG); | ||
| 280 | } else { | ||
| 281 | usbcfg = dwc2_readl(hsotg, GUSBCFG); | ||
| 282 | usbcfg &= ~GUSBCFG_ULPI_FS_LS; | ||
| 283 | usbcfg &= ~GUSBCFG_ULPI_CLK_SUSP_M; | ||
| 284 | dwc2_writel(hsotg, usbcfg, GUSBCFG); | ||
| 285 | } | ||
| 286 | |||
| 287 | return retval; | ||
| 288 | } | ||
| 289 | |||
| 290 | static int dwc2_gahbcfg_init(struct dwc2_hsotg *hsotg) | 100 | static int dwc2_gahbcfg_init(struct dwc2_hsotg *hsotg) |
| 291 | { | 101 | { |
| 292 | u32 ahbcfg = dwc2_readl(hsotg, GAHBCFG); | 102 | u32 ahbcfg = dwc2_readl(hsotg, GAHBCFG); |
| @@ -2437,25 +2247,31 @@ static void dwc2_core_host_init(struct dwc2_hsotg *hsotg) | |||
| 2437 | num_channels = hsotg->params.host_channels; | 2247 | num_channels = hsotg->params.host_channels; |
| 2438 | for (i = 0; i < num_channels; i++) { | 2248 | for (i = 0; i < num_channels; i++) { |
| 2439 | hcchar = dwc2_readl(hsotg, HCCHAR(i)); | 2249 | hcchar = dwc2_readl(hsotg, HCCHAR(i)); |
| 2440 | hcchar &= ~HCCHAR_CHENA; | 2250 | if (hcchar & HCCHAR_CHENA) { |
| 2441 | hcchar |= HCCHAR_CHDIS; | 2251 | hcchar &= ~HCCHAR_CHENA; |
| 2442 | hcchar &= ~HCCHAR_EPDIR; | 2252 | hcchar |= HCCHAR_CHDIS; |
| 2443 | dwc2_writel(hsotg, hcchar, HCCHAR(i)); | 2253 | hcchar &= ~HCCHAR_EPDIR; |
| 2254 | dwc2_writel(hsotg, hcchar, HCCHAR(i)); | ||
| 2255 | } | ||
| 2444 | } | 2256 | } |
| 2445 | 2257 | ||
| 2446 | /* Halt all channels to put them into a known state */ | 2258 | /* Halt all channels to put them into a known state */ |
| 2447 | for (i = 0; i < num_channels; i++) { | 2259 | for (i = 0; i < num_channels; i++) { |
| 2448 | hcchar = dwc2_readl(hsotg, HCCHAR(i)); | 2260 | hcchar = dwc2_readl(hsotg, HCCHAR(i)); |
| 2449 | hcchar |= HCCHAR_CHENA | HCCHAR_CHDIS; | 2261 | if (hcchar & HCCHAR_CHENA) { |
| 2450 | hcchar &= ~HCCHAR_EPDIR; | 2262 | hcchar |= HCCHAR_CHENA | HCCHAR_CHDIS; |
| 2451 | dwc2_writel(hsotg, hcchar, HCCHAR(i)); | 2263 | hcchar &= ~HCCHAR_EPDIR; |
| 2452 | dev_dbg(hsotg->dev, "%s: Halt channel %d\n", | 2264 | dwc2_writel(hsotg, hcchar, HCCHAR(i)); |
| 2453 | __func__, i); | 2265 | dev_dbg(hsotg->dev, "%s: Halt channel %d\n", |
| 2454 | 2266 | __func__, i); | |
| 2455 | if (dwc2_hsotg_wait_bit_clear(hsotg, HCCHAR(i), | 2267 | |
| 2456 | HCCHAR_CHENA, 1000)) { | 2268 | if (dwc2_hsotg_wait_bit_clear(hsotg, HCCHAR(i), |
| 2457 | dev_warn(hsotg->dev, "Unable to clear enable on channel %d\n", | 2269 | HCCHAR_CHENA, |
| 2458 | i); | 2270 | 1000)) { |
| 2271 | dev_warn(hsotg->dev, | ||
| 2272 | "Unable to clear enable on channel %d\n", | ||
| 2273 | i); | ||
| 2274 | } | ||
| 2459 | } | 2275 | } |
| 2460 | } | 2276 | } |
| 2461 | } | 2277 | } |
| @@ -4376,6 +4192,17 @@ static void dwc2_hcd_reset_func(struct work_struct *work) | |||
| 4376 | spin_unlock_irqrestore(&hsotg->lock, flags); | 4192 | spin_unlock_irqrestore(&hsotg->lock, flags); |
| 4377 | } | 4193 | } |
| 4378 | 4194 | ||
| 4195 | static void dwc2_hcd_phy_reset_func(struct work_struct *work) | ||
| 4196 | { | ||
| 4197 | struct dwc2_hsotg *hsotg = container_of(work, struct dwc2_hsotg, | ||
| 4198 | phy_reset_work); | ||
| 4199 | int ret; | ||
| 4200 | |||
| 4201 | ret = phy_reset(hsotg->phy); | ||
| 4202 | if (ret) | ||
| 4203 | dev_warn(hsotg->dev, "PHY reset failed\n"); | ||
| 4204 | } | ||
| 4205 | |||
| 4379 | /* | 4206 | /* |
| 4380 | * ========================================================================= | 4207 | * ========================================================================= |
| 4381 | * Linux HC Driver Functions | 4208 | * Linux HC Driver Functions |
| @@ -4471,6 +4298,7 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd) | |||
| 4471 | unsigned long flags; | 4298 | unsigned long flags; |
| 4472 | int ret = 0; | 4299 | int ret = 0; |
| 4473 | u32 hprt0; | 4300 | u32 hprt0; |
| 4301 | u32 pcgctl; | ||
| 4474 | 4302 | ||
| 4475 | spin_lock_irqsave(&hsotg->lock, flags); | 4303 | spin_lock_irqsave(&hsotg->lock, flags); |
| 4476 | 4304 | ||
| @@ -4486,7 +4314,7 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd) | |||
| 4486 | if (hsotg->op_state == OTG_STATE_B_PERIPHERAL) | 4314 | if (hsotg->op_state == OTG_STATE_B_PERIPHERAL) |
| 4487 | goto unlock; | 4315 | goto unlock; |
| 4488 | 4316 | ||
| 4489 | if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_PARTIAL) | 4317 | if (hsotg->params.power_down > DWC2_POWER_DOWN_PARAM_PARTIAL) |
| 4490 | goto skip_power_saving; | 4318 | goto skip_power_saving; |
| 4491 | 4319 | ||
| 4492 | /* | 4320 | /* |
| @@ -4495,21 +4323,35 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd) | |||
| 4495 | */ | 4323 | */ |
| 4496 | if (!hsotg->bus_suspended) { | 4324 | if (!hsotg->bus_suspended) { |
| 4497 | hprt0 = dwc2_read_hprt0(hsotg); | 4325 | hprt0 = dwc2_read_hprt0(hsotg); |
| 4498 | hprt0 |= HPRT0_SUSP; | 4326 | if (hprt0 & HPRT0_CONNSTS) { |
| 4499 | hprt0 &= ~HPRT0_PWR; | 4327 | hprt0 |= HPRT0_SUSP; |
| 4500 | dwc2_writel(hsotg, hprt0, HPRT0); | 4328 | if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_PARTIAL) |
| 4501 | spin_unlock_irqrestore(&hsotg->lock, flags); | 4329 | hprt0 &= ~HPRT0_PWR; |
| 4502 | dwc2_vbus_supply_exit(hsotg); | 4330 | dwc2_writel(hsotg, hprt0, HPRT0); |
| 4503 | spin_lock_irqsave(&hsotg->lock, flags); | 4331 | } |
| 4332 | if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_PARTIAL) { | ||
| 4333 | spin_unlock_irqrestore(&hsotg->lock, flags); | ||
| 4334 | dwc2_vbus_supply_exit(hsotg); | ||
| 4335 | spin_lock_irqsave(&hsotg->lock, flags); | ||
| 4336 | } else { | ||
| 4337 | pcgctl = readl(hsotg->regs + PCGCTL); | ||
| 4338 | pcgctl |= PCGCTL_STOPPCLK; | ||
| 4339 | writel(pcgctl, hsotg->regs + PCGCTL); | ||
| 4340 | } | ||
| 4504 | } | 4341 | } |
| 4505 | 4342 | ||
| 4506 | /* Enter partial_power_down */ | 4343 | if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_PARTIAL) { |
| 4507 | ret = dwc2_enter_partial_power_down(hsotg); | 4344 | /* Enter partial_power_down */ |
| 4508 | if (ret) { | 4345 | ret = dwc2_enter_partial_power_down(hsotg); |
| 4509 | if (ret != -ENOTSUPP) | 4346 | if (ret) { |
| 4510 | dev_err(hsotg->dev, | 4347 | if (ret != -ENOTSUPP) |
| 4511 | "enter partial_power_down failed\n"); | 4348 | dev_err(hsotg->dev, |
| 4512 | goto skip_power_saving; | 4349 | "enter partial_power_down failed\n"); |
| 4350 | goto skip_power_saving; | ||
| 4351 | } | ||
| 4352 | |||
| 4353 | /* After entering partial_power_down, hardware is no more accessible */ | ||
| 4354 | clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); | ||
| 4513 | } | 4355 | } |
| 4514 | 4356 | ||
| 4515 | /* Ask phy to be suspended */ | 4357 | /* Ask phy to be suspended */ |
| @@ -4519,9 +4361,6 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd) | |||
| 4519 | spin_lock_irqsave(&hsotg->lock, flags); | 4361 | spin_lock_irqsave(&hsotg->lock, flags); |
| 4520 | } | 4362 | } |
| 4521 | 4363 | ||
| 4522 | /* After entering partial_power_down, hardware is no more accessible */ | ||
| 4523 | clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); | ||
| 4524 | |||
| 4525 | skip_power_saving: | 4364 | skip_power_saving: |
| 4526 | hsotg->lx_state = DWC2_L2; | 4365 | hsotg->lx_state = DWC2_L2; |
| 4527 | unlock: | 4366 | unlock: |
| @@ -4534,6 +4373,7 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd) | |||
| 4534 | { | 4373 | { |
| 4535 | struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); | 4374 | struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); |
| 4536 | unsigned long flags; | 4375 | unsigned long flags; |
| 4376 | u32 pcgctl; | ||
| 4537 | int ret = 0; | 4377 | int ret = 0; |
| 4538 | 4378 | ||
| 4539 | spin_lock_irqsave(&hsotg->lock, flags); | 4379 | spin_lock_irqsave(&hsotg->lock, flags); |
| @@ -4544,18 +4384,12 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd) | |||
| 4544 | if (hsotg->lx_state != DWC2_L2) | 4384 | if (hsotg->lx_state != DWC2_L2) |
| 4545 | goto unlock; | 4385 | goto unlock; |
| 4546 | 4386 | ||
| 4547 | if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_PARTIAL) { | 4387 | if (hsotg->params.power_down > DWC2_POWER_DOWN_PARAM_PARTIAL) { |
| 4548 | hsotg->lx_state = DWC2_L0; | 4388 | hsotg->lx_state = DWC2_L0; |
| 4549 | goto unlock; | 4389 | goto unlock; |
| 4550 | } | 4390 | } |
| 4551 | 4391 | ||
| 4552 | /* | 4392 | /* |
| 4553 | * Set HW accessible bit before powering on the controller | ||
| 4554 | * since an interrupt may rise. | ||
| 4555 | */ | ||
| 4556 | set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); | ||
| 4557 | |||
| 4558 | /* | ||
| 4559 | * Enable power if not already done. | 4393 | * Enable power if not already done. |
| 4560 | * This must not be spinlocked since duration | 4394 | * This must not be spinlocked since duration |
| 4561 | * of this call is unknown. | 4395 | * of this call is unknown. |
| @@ -4566,10 +4400,23 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd) | |||
| 4566 | spin_lock_irqsave(&hsotg->lock, flags); | 4400 | spin_lock_irqsave(&hsotg->lock, flags); |
| 4567 | } | 4401 | } |
| 4568 | 4402 | ||
| 4569 | /* Exit partial_power_down */ | 4403 | if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_PARTIAL) { |
| 4570 | ret = dwc2_exit_partial_power_down(hsotg, true); | 4404 | /* |
| 4571 | if (ret && (ret != -ENOTSUPP)) | 4405 | * Set HW accessible bit before powering on the controller |
| 4572 | dev_err(hsotg->dev, "exit partial_power_down failed\n"); | 4406 | * since an interrupt may rise. |
| 4407 | */ | ||
| 4408 | set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); | ||
| 4409 | |||
| 4410 | |||
| 4411 | /* Exit partial_power_down */ | ||
| 4412 | ret = dwc2_exit_partial_power_down(hsotg, true); | ||
| 4413 | if (ret && (ret != -ENOTSUPP)) | ||
| 4414 | dev_err(hsotg->dev, "exit partial_power_down failed\n"); | ||
| 4415 | } else { | ||
| 4416 | pcgctl = readl(hsotg->regs + PCGCTL); | ||
| 4417 | pcgctl &= ~PCGCTL_STOPPCLK; | ||
| 4418 | writel(pcgctl, hsotg->regs + PCGCTL); | ||
| 4419 | } | ||
| 4573 | 4420 | ||
| 4574 | hsotg->lx_state = DWC2_L0; | 4421 | hsotg->lx_state = DWC2_L0; |
| 4575 | 4422 | ||
| @@ -4581,10 +4428,12 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd) | |||
| 4581 | spin_unlock_irqrestore(&hsotg->lock, flags); | 4428 | spin_unlock_irqrestore(&hsotg->lock, flags); |
| 4582 | dwc2_port_resume(hsotg); | 4429 | dwc2_port_resume(hsotg); |
| 4583 | } else { | 4430 | } else { |
| 4584 | dwc2_vbus_supply_init(hsotg); | 4431 | if (hsotg->params.power_down == DWC2_POWER_DOWN_PARAM_PARTIAL) { |
| 4432 | dwc2_vbus_supply_init(hsotg); | ||
| 4585 | 4433 | ||
| 4586 | /* Wait for controller to correctly update D+/D- level */ | 4434 | /* Wait for controller to correctly update D+/D- level */ |
| 4587 | usleep_range(3000, 5000); | 4435 | usleep_range(3000, 5000); |
| 4436 | } | ||
| 4588 | 4437 | ||
| 4589 | /* | 4438 | /* |
| 4590 | * Clear Port Enable and Port Status changes. | 4439 | * Clear Port Enable and Port Status changes. |
| @@ -5130,6 +4979,8 @@ static void dwc2_hcd_free(struct dwc2_hsotg *hsotg) | |||
| 5130 | destroy_workqueue(hsotg->wq_otg); | 4979 | destroy_workqueue(hsotg->wq_otg); |
| 5131 | } | 4980 | } |
| 5132 | 4981 | ||
| 4982 | cancel_work_sync(&hsotg->phy_reset_work); | ||
| 4983 | |||
| 5133 | del_timer(&hsotg->wkp_timer); | 4984 | del_timer(&hsotg->wkp_timer); |
| 5134 | } | 4985 | } |
| 5135 | 4986 | ||
| @@ -5271,11 +5122,10 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg) | |||
| 5271 | hsotg->hc_ptr_array[i] = channel; | 5122 | hsotg->hc_ptr_array[i] = channel; |
| 5272 | } | 5123 | } |
| 5273 | 5124 | ||
| 5274 | /* Initialize hsotg start work */ | 5125 | /* Initialize work */ |
| 5275 | INIT_DELAYED_WORK(&hsotg->start_work, dwc2_hcd_start_func); | 5126 | INIT_DELAYED_WORK(&hsotg->start_work, dwc2_hcd_start_func); |
| 5276 | |||
| 5277 | /* Initialize port reset work */ | ||
| 5278 | INIT_DELAYED_WORK(&hsotg->reset_work, dwc2_hcd_reset_func); | 5127 | INIT_DELAYED_WORK(&hsotg->reset_work, dwc2_hcd_reset_func); |
| 5128 | INIT_WORK(&hsotg->phy_reset_work, dwc2_hcd_phy_reset_func); | ||
| 5279 | 5129 | ||
| 5280 | /* | 5130 | /* |
| 5281 | * Allocate space for storing data on status transactions. Normally no | 5131 | * Allocate space for storing data on status transactions. Normally no |
diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h index 98af924a9a5c..510e87ec0be8 100644 --- a/drivers/usb/dwc2/hw.h +++ b/drivers/usb/dwc2/hw.h | |||
| @@ -310,12 +310,12 @@ | |||
| 310 | #define GHWCFG4_NUM_DEV_MODE_CTRL_EP_SHIFT 16 | 310 | #define GHWCFG4_NUM_DEV_MODE_CTRL_EP_SHIFT 16 |
| 311 | #define GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK (0x3 << 14) | 311 | #define GHWCFG4_UTMI_PHY_DATA_WIDTH_MASK (0x3 << 14) |
| 312 | #define GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT 14 | 312 | #define GHWCFG4_UTMI_PHY_DATA_WIDTH_SHIFT 14 |
| 313 | #define GHWCFG4_ACG_SUPPORTED BIT(12) | ||
| 314 | #define GHWCFG4_IPG_ISOC_SUPPORTED BIT(11) | ||
| 315 | #define GHWCFG4_SERVICE_INTERVAL_SUPPORTED BIT(10) | ||
| 316 | #define GHWCFG4_UTMI_PHY_DATA_WIDTH_8 0 | 313 | #define GHWCFG4_UTMI_PHY_DATA_WIDTH_8 0 |
| 317 | #define GHWCFG4_UTMI_PHY_DATA_WIDTH_16 1 | 314 | #define GHWCFG4_UTMI_PHY_DATA_WIDTH_16 1 |
| 318 | #define GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16 2 | 315 | #define GHWCFG4_UTMI_PHY_DATA_WIDTH_8_OR_16 2 |
| 316 | #define GHWCFG4_ACG_SUPPORTED BIT(12) | ||
| 317 | #define GHWCFG4_IPG_ISOC_SUPPORTED BIT(11) | ||
| 318 | #define GHWCFG4_SERVICE_INTERVAL_SUPPORTED BIT(10) | ||
| 319 | #define GHWCFG4_XHIBER BIT(7) | 319 | #define GHWCFG4_XHIBER BIT(7) |
| 320 | #define GHWCFG4_HIBER BIT(6) | 320 | #define GHWCFG4_HIBER BIT(6) |
| 321 | #define GHWCFG4_MIN_AHB_FREQ BIT(5) | 321 | #define GHWCFG4_MIN_AHB_FREQ BIT(5) |
| @@ -333,7 +333,7 @@ | |||
| 333 | #define GLPMCFG_SNDLPM BIT(24) | 333 | #define GLPMCFG_SNDLPM BIT(24) |
| 334 | #define GLPMCFG_RETRY_CNT_MASK (0x7 << 21) | 334 | #define GLPMCFG_RETRY_CNT_MASK (0x7 << 21) |
| 335 | #define GLPMCFG_RETRY_CNT_SHIFT 21 | 335 | #define GLPMCFG_RETRY_CNT_SHIFT 21 |
| 336 | #define GLPMCFG_LPM_ACCEPT_CTRL_CONTROL BIT(21) | 336 | #define GLPMCFG_LPM_REJECT_CTRL_CONTROL BIT(21) |
| 337 | #define GLPMCFG_LPM_ACCEPT_CTRL_ISOC BIT(22) | 337 | #define GLPMCFG_LPM_ACCEPT_CTRL_ISOC BIT(22) |
| 338 | #define GLPMCFG_LPM_CHNL_INDX_MASK (0xf << 17) | 338 | #define GLPMCFG_LPM_CHNL_INDX_MASK (0xf << 17) |
| 339 | #define GLPMCFG_LPM_CHNL_INDX_SHIFT 17 | 339 | #define GLPMCFG_LPM_CHNL_INDX_SHIFT 17 |
diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c index 24ff5f21cb25..6900eea57526 100644 --- a/drivers/usb/dwc2/params.c +++ b/drivers/usb/dwc2/params.c | |||
| @@ -121,6 +121,16 @@ static void dwc2_set_amlogic_params(struct dwc2_hsotg *hsotg) | |||
| 121 | p->power_down = DWC2_POWER_DOWN_PARAM_NONE; | 121 | p->power_down = DWC2_POWER_DOWN_PARAM_NONE; |
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | static void dwc2_set_amlogic_g12a_params(struct dwc2_hsotg *hsotg) | ||
| 125 | { | ||
| 126 | struct dwc2_core_params *p = &hsotg->params; | ||
| 127 | |||
| 128 | p->lpm = false; | ||
| 129 | p->lpm_clock_gating = false; | ||
| 130 | p->besl = false; | ||
| 131 | p->hird_threshold_en = false; | ||
| 132 | } | ||
| 133 | |||
| 124 | static void dwc2_set_amcc_params(struct dwc2_hsotg *hsotg) | 134 | static void dwc2_set_amcc_params(struct dwc2_hsotg *hsotg) |
| 125 | { | 135 | { |
| 126 | struct dwc2_core_params *p = &hsotg->params; | 136 | struct dwc2_core_params *p = &hsotg->params; |
| @@ -167,6 +177,8 @@ const struct of_device_id dwc2_of_match_table[] = { | |||
| 167 | .data = dwc2_set_amlogic_params }, | 177 | .data = dwc2_set_amlogic_params }, |
| 168 | { .compatible = "amlogic,meson-gxbb-usb", | 178 | { .compatible = "amlogic,meson-gxbb-usb", |
| 169 | .data = dwc2_set_amlogic_params }, | 179 | .data = dwc2_set_amlogic_params }, |
| 180 | { .compatible = "amlogic,meson-g12a-usb", | ||
| 181 | .data = dwc2_set_amlogic_g12a_params }, | ||
| 170 | { .compatible = "amcc,dwc-otg", .data = dwc2_set_amcc_params }, | 182 | { .compatible = "amcc,dwc-otg", .data = dwc2_set_amcc_params }, |
| 171 | { .compatible = "st,stm32f4x9-fsotg", | 183 | { .compatible = "st,stm32f4x9-fsotg", |
| 172 | .data = dwc2_set_stm32f4x9_fsotg_params }, | 184 | .data = dwc2_set_stm32f4x9_fsotg_params }, |
| @@ -273,6 +285,23 @@ static void dwc2_set_param_power_down(struct dwc2_hsotg *hsotg) | |||
| 273 | hsotg->params.power_down = val; | 285 | hsotg->params.power_down = val; |
| 274 | } | 286 | } |
| 275 | 287 | ||
| 288 | static void dwc2_set_param_lpm(struct dwc2_hsotg *hsotg) | ||
| 289 | { | ||
| 290 | struct dwc2_core_params *p = &hsotg->params; | ||
| 291 | |||
| 292 | p->lpm = hsotg->hw_params.lpm_mode; | ||
| 293 | if (p->lpm) { | ||
| 294 | p->lpm_clock_gating = true; | ||
| 295 | p->besl = true; | ||
| 296 | p->hird_threshold_en = true; | ||
| 297 | p->hird_threshold = 4; | ||
| 298 | } else { | ||
| 299 | p->lpm_clock_gating = false; | ||
| 300 | p->besl = false; | ||
| 301 | p->hird_threshold_en = false; | ||
| 302 | } | ||
| 303 | } | ||
| 304 | |||
| 276 | /** | 305 | /** |
| 277 | * dwc2_set_default_params() - Set all core parameters to their | 306 | * dwc2_set_default_params() - Set all core parameters to their |
| 278 | * auto-detected default values. | 307 | * auto-detected default values. |
| @@ -291,6 +320,7 @@ static void dwc2_set_default_params(struct dwc2_hsotg *hsotg) | |||
| 291 | dwc2_set_param_speed(hsotg); | 320 | dwc2_set_param_speed(hsotg); |
| 292 | dwc2_set_param_phy_utmi_width(hsotg); | 321 | dwc2_set_param_phy_utmi_width(hsotg); |
| 293 | dwc2_set_param_power_down(hsotg); | 322 | dwc2_set_param_power_down(hsotg); |
| 323 | dwc2_set_param_lpm(hsotg); | ||
| 294 | p->phy_ulpi_ddr = false; | 324 | p->phy_ulpi_ddr = false; |
| 295 | p->phy_ulpi_ext_vbus = false; | 325 | p->phy_ulpi_ext_vbus = false; |
| 296 | 326 | ||
| @@ -303,11 +333,6 @@ static void dwc2_set_default_params(struct dwc2_hsotg *hsotg) | |||
| 303 | p->reload_ctl = (hw->snpsid >= DWC2_CORE_REV_2_92a); | 333 | p->reload_ctl = (hw->snpsid >= DWC2_CORE_REV_2_92a); |
| 304 | p->uframe_sched = true; | 334 | p->uframe_sched = true; |
| 305 | p->external_id_pin_ctl = false; | 335 | p->external_id_pin_ctl = false; |
| 306 | p->lpm = true; | ||
| 307 | p->lpm_clock_gating = true; | ||
| 308 | p->besl = true; | ||
| 309 | p->hird_threshold_en = true; | ||
| 310 | p->hird_threshold = 4; | ||
| 311 | p->ipg_isoc_en = false; | 336 | p->ipg_isoc_en = false; |
| 312 | p->service_interval = false; | 337 | p->service_interval = false; |
| 313 | p->max_packet_count = hw->max_packet_count; | 338 | p->max_packet_count = hw->max_packet_count; |
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index c0b64d483552..d10a7f8daec3 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c | |||
| @@ -230,9 +230,6 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) | |||
| 230 | 230 | ||
| 231 | reset_control_deassert(hsotg->reset_ecc); | 231 | reset_control_deassert(hsotg->reset_ecc); |
| 232 | 232 | ||
| 233 | /* Set default UTMI width */ | ||
| 234 | hsotg->phyif = GUSBCFG_PHYIF16; | ||
| 235 | |||
| 236 | /* | 233 | /* |
| 237 | * Attempt to find a generic PHY, then look for an old style | 234 | * Attempt to find a generic PHY, then look for an old style |
| 238 | * USB PHY and then fall back to pdata | 235 | * USB PHY and then fall back to pdata |
| @@ -280,14 +277,14 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) | |||
| 280 | * width is 8-bit and set the phyif appropriately. | 277 | * width is 8-bit and set the phyif appropriately. |
| 281 | */ | 278 | */ |
| 282 | if (phy_get_bus_width(hsotg->phy) == 8) | 279 | if (phy_get_bus_width(hsotg->phy) == 8) |
| 283 | hsotg->phyif = GUSBCFG_PHYIF8; | 280 | hsotg->params.phy_utmi_width = 8; |
| 284 | } | 281 | } |
| 285 | 282 | ||
| 286 | /* Clock */ | 283 | /* Clock */ |
| 287 | hsotg->clk = devm_clk_get(hsotg->dev, "otg"); | 284 | hsotg->clk = devm_clk_get_optional(hsotg->dev, "otg"); |
| 288 | if (IS_ERR(hsotg->clk)) { | 285 | if (IS_ERR(hsotg->clk)) { |
| 289 | hsotg->clk = NULL; | 286 | dev_err(hsotg->dev, "cannot get otg clock\n"); |
| 290 | dev_dbg(hsotg->dev, "cannot get otg clock\n"); | 287 | return PTR_ERR(hsotg->clk); |
| 291 | } | 288 | } |
| 292 | 289 | ||
| 293 | /* Regulators */ | 290 | /* Regulators */ |
| @@ -481,6 +478,15 @@ static int dwc2_driver_probe(struct platform_device *dev) | |||
| 481 | hsotg->gadget_enabled = 1; | 478 | hsotg->gadget_enabled = 1; |
| 482 | } | 479 | } |
| 483 | 480 | ||
| 481 | hsotg->reset_phy_on_wake = | ||
| 482 | of_property_read_bool(dev->dev.of_node, | ||
| 483 | "snps,reset-phy-on-wake"); | ||
| 484 | if (hsotg->reset_phy_on_wake && !hsotg->phy) { | ||
| 485 | dev_warn(hsotg->dev, | ||
| 486 | "Quirk reset-phy-on-wake only supports generic PHYs\n"); | ||
| 487 | hsotg->reset_phy_on_wake = false; | ||
| 488 | } | ||
| 489 | |||
| 484 | if (hsotg->dr_mode != USB_DR_MODE_PERIPHERAL) { | 490 | if (hsotg->dr_mode != USB_DR_MODE_PERIPHERAL) { |
| 485 | retval = dwc2_hcd_init(hsotg); | 491 | retval = dwc2_hcd_init(hsotg); |
| 486 | if (retval) { | 492 | if (retval) { |
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index 2b1494460d0c..4a62045cc812 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig | |||
| @@ -54,7 +54,8 @@ comment "Platform Glue Driver Support" | |||
| 54 | 54 | ||
| 55 | config USB_DWC3_OMAP | 55 | config USB_DWC3_OMAP |
| 56 | tristate "Texas Instruments OMAP5 and similar Platforms" | 56 | tristate "Texas Instruments OMAP5 and similar Platforms" |
| 57 | depends on EXTCON && (ARCH_OMAP2PLUS || COMPILE_TEST) | 57 | depends on ARCH_OMAP2PLUS || COMPILE_TEST |
| 58 | depends on EXTCON || !EXTCON | ||
| 58 | depends on OF | 59 | depends on OF |
| 59 | default USB_DWC3 | 60 | default USB_DWC3 |
| 60 | help | 61 | help |
| @@ -95,6 +96,16 @@ config USB_DWC3_KEYSTONE | |||
| 95 | Support of USB2/3 functionality in TI Keystone2 and AM654 platforms. | 96 | Support of USB2/3 functionality in TI Keystone2 and AM654 platforms. |
| 96 | Say 'Y' or 'M' here if you have one such device | 97 | Say 'Y' or 'M' here if you have one such device |
| 97 | 98 | ||
| 99 | config USB_DWC3_MESON_G12A | ||
| 100 | tristate "Amlogic Meson G12A Platforms" | ||
| 101 | depends on OF && COMMON_CLK | ||
| 102 | depends on ARCH_MESON || COMPILE_TEST | ||
| 103 | default USB_DWC3 | ||
| 104 | select USB_ROLE_SWITCH | ||
| 105 | help | ||
| 106 | Support USB2/3 functionality in Amlogic G12A platforms. | ||
| 107 | Say 'Y' or 'M' if you have one such device. | ||
| 108 | |||
| 98 | config USB_DWC3_OF_SIMPLE | 109 | config USB_DWC3_OF_SIMPLE |
| 99 | tristate "Generic OF Simple Glue Layer" | 110 | tristate "Generic OF Simple Glue Layer" |
| 100 | depends on OF && COMMON_CLK | 111 | depends on OF && COMMON_CLK |
| @@ -115,7 +126,8 @@ config USB_DWC3_ST | |||
| 115 | 126 | ||
| 116 | config USB_DWC3_QCOM | 127 | config USB_DWC3_QCOM |
| 117 | tristate "Qualcomm Platform" | 128 | tristate "Qualcomm Platform" |
| 118 | depends on EXTCON && (ARCH_QCOM || COMPILE_TEST) | 129 | depends on ARCH_QCOM || COMPILE_TEST |
| 130 | depends on EXTCON || !EXTCON | ||
| 119 | depends on OF | 131 | depends on OF |
| 120 | default USB_DWC3 | 132 | default USB_DWC3 |
| 121 | help | 133 | help |
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile index 6e3ef6144e5d..ae86da0dc5bd 100644 --- a/drivers/usb/dwc3/Makefile +++ b/drivers/usb/dwc3/Makefile | |||
| @@ -47,6 +47,7 @@ obj-$(CONFIG_USB_DWC3_EXYNOS) += dwc3-exynos.o | |||
| 47 | obj-$(CONFIG_USB_DWC3_PCI) += dwc3-pci.o | 47 | obj-$(CONFIG_USB_DWC3_PCI) += dwc3-pci.o |
| 48 | obj-$(CONFIG_USB_DWC3_HAPS) += dwc3-haps.o | 48 | obj-$(CONFIG_USB_DWC3_HAPS) += dwc3-haps.o |
| 49 | obj-$(CONFIG_USB_DWC3_KEYSTONE) += dwc3-keystone.o | 49 | obj-$(CONFIG_USB_DWC3_KEYSTONE) += dwc3-keystone.o |
| 50 | obj-$(CONFIG_USB_DWC3_MESON_G12A) += dwc3-meson-g12a.o | ||
| 50 | obj-$(CONFIG_USB_DWC3_OF_SIMPLE) += dwc3-of-simple.o | 51 | obj-$(CONFIG_USB_DWC3_OF_SIMPLE) += dwc3-of-simple.o |
| 51 | obj-$(CONFIG_USB_DWC3_ST) += dwc3-st.o | 52 | obj-$(CONFIG_USB_DWC3_ST) += dwc3-st.o |
| 52 | obj-$(CONFIG_USB_DWC3_QCOM) += dwc3-qcom.o | 53 | obj-$(CONFIG_USB_DWC3_QCOM) += dwc3-qcom.o |
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index a1b126f90261..4aff1d8dbc4f 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c | |||
| @@ -828,6 +828,7 @@ static void dwc3_set_incr_burst_type(struct dwc3 *dwc) | |||
| 828 | ret = device_property_read_u32_array(dev, | 828 | ret = device_property_read_u32_array(dev, |
| 829 | "snps,incr-burst-type-adjustment", vals, ntype); | 829 | "snps,incr-burst-type-adjustment", vals, ntype); |
| 830 | if (ret) { | 830 | if (ret) { |
| 831 | kfree(vals); | ||
| 831 | dev_err(dev, "Error to get property\n"); | 832 | dev_err(dev, "Error to get property\n"); |
| 832 | return; | 833 | return; |
| 833 | } | 834 | } |
| @@ -846,6 +847,8 @@ static void dwc3_set_incr_burst_type(struct dwc3 *dwc) | |||
| 846 | incrx_mode = INCRX_BURST_MODE; | 847 | incrx_mode = INCRX_BURST_MODE; |
| 847 | } | 848 | } |
| 848 | 849 | ||
| 850 | kfree(vals); | ||
| 851 | |||
| 849 | /* Enable Undefined Length INCR Burst and Enable INCRx Burst */ | 852 | /* Enable Undefined Length INCR Burst and Enable INCRx Burst */ |
| 850 | cfg &= ~DWC3_GSBUSCFG0_INCRBRST_MASK; | 853 | cfg &= ~DWC3_GSBUSCFG0_INCRBRST_MASK; |
| 851 | if (incrx_mode) | 854 | if (incrx_mode) |
| @@ -893,12 +896,6 @@ static int dwc3_core_init(struct dwc3 *dwc) | |||
| 893 | u32 reg; | 896 | u32 reg; |
| 894 | int ret; | 897 | int ret; |
| 895 | 898 | ||
| 896 | if (!dwc3_core_is_valid(dwc)) { | ||
| 897 | dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n"); | ||
| 898 | ret = -ENODEV; | ||
| 899 | goto err0; | ||
| 900 | } | ||
| 901 | |||
| 902 | /* | 899 | /* |
| 903 | * Write Linux Version Code to our GUID register so it's easy to figure | 900 | * Write Linux Version Code to our GUID register so it's easy to figure |
| 904 | * out which kernel version a bug was found. | 901 | * out which kernel version a bug was found. |
| @@ -1218,7 +1215,7 @@ static void dwc3_get_properties(struct dwc3 *dwc) | |||
| 1218 | u8 tx_max_burst_prd; | 1215 | u8 tx_max_burst_prd; |
| 1219 | 1216 | ||
| 1220 | /* default to highest possible threshold */ | 1217 | /* default to highest possible threshold */ |
| 1221 | lpm_nyet_threshold = 0xff; | 1218 | lpm_nyet_threshold = 0xf; |
| 1222 | 1219 | ||
| 1223 | /* default to -3.5dB de-emphasis */ | 1220 | /* default to -3.5dB de-emphasis */ |
| 1224 | tx_de_emphasis = 1; | 1221 | tx_de_emphasis = 1; |
| @@ -1426,6 +1423,11 @@ static int dwc3_probe(struct platform_device *pdev) | |||
| 1426 | dwc->regs = regs; | 1423 | dwc->regs = regs; |
| 1427 | dwc->regs_size = resource_size(&dwc_res); | 1424 | dwc->regs_size = resource_size(&dwc_res); |
| 1428 | 1425 | ||
| 1426 | if (!dwc3_core_is_valid(dwc)) { | ||
| 1427 | dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n"); | ||
| 1428 | return -ENODEV; | ||
| 1429 | } | ||
| 1430 | |||
| 1429 | dwc3_get_properties(dwc); | 1431 | dwc3_get_properties(dwc); |
| 1430 | 1432 | ||
| 1431 | dwc->reset = devm_reset_control_get_optional_shared(dev, NULL); | 1433 | dwc->reset = devm_reset_control_get_optional_shared(dev, NULL); |
| @@ -1600,6 +1602,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg) | |||
| 1600 | spin_lock_irqsave(&dwc->lock, flags); | 1602 | spin_lock_irqsave(&dwc->lock, flags); |
| 1601 | dwc3_gadget_suspend(dwc); | 1603 | dwc3_gadget_suspend(dwc); |
| 1602 | spin_unlock_irqrestore(&dwc->lock, flags); | 1604 | spin_unlock_irqrestore(&dwc->lock, flags); |
| 1605 | synchronize_irq(dwc->irq_gadget); | ||
| 1603 | dwc3_core_exit(dwc); | 1606 | dwc3_core_exit(dwc); |
| 1604 | break; | 1607 | break; |
| 1605 | case DWC3_GCTL_PRTCAP_HOST: | 1608 | case DWC3_GCTL_PRTCAP_HOST: |
| @@ -1632,6 +1635,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg) | |||
| 1632 | spin_lock_irqsave(&dwc->lock, flags); | 1635 | spin_lock_irqsave(&dwc->lock, flags); |
| 1633 | dwc3_gadget_suspend(dwc); | 1636 | dwc3_gadget_suspend(dwc); |
| 1634 | spin_unlock_irqrestore(&dwc->lock, flags); | 1637 | spin_unlock_irqrestore(&dwc->lock, flags); |
| 1638 | synchronize_irq(dwc->irq_gadget); | ||
| 1635 | } | 1639 | } |
| 1636 | 1640 | ||
| 1637 | dwc3_otg_exit(dwc); | 1641 | dwc3_otg_exit(dwc); |
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 1528d395b156..f19cbeb01087 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h | |||
| @@ -406,8 +406,7 @@ | |||
| 406 | #define DWC3_DCTL_TRGTULST_SS_INACT (DWC3_DCTL_TRGTULST(6)) | 406 | #define DWC3_DCTL_TRGTULST_SS_INACT (DWC3_DCTL_TRGTULST(6)) |
| 407 | 407 | ||
| 408 | /* These apply for core versions 1.94a and later */ | 408 | /* These apply for core versions 1.94a and later */ |
| 409 | #define DWC3_DCTL_LPM_ERRATA_MASK DWC3_DCTL_LPM_ERRATA(0xf) | 409 | #define DWC3_DCTL_NYET_THRES(n) (((n) & 0xf) << 20) |
| 410 | #define DWC3_DCTL_LPM_ERRATA(n) ((n) << 20) | ||
| 411 | 410 | ||
| 412 | #define DWC3_DCTL_KEEP_CONNECT BIT(19) | 411 | #define DWC3_DCTL_KEEP_CONNECT BIT(19) |
| 413 | #define DWC3_DCTL_L1_HIBER_EN BIT(18) | 412 | #define DWC3_DCTL_L1_HIBER_EN BIT(18) |
diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h index 6759a7efd8d5..068259fdfb0c 100644 --- a/drivers/usb/dwc3/debug.h +++ b/drivers/usb/dwc3/debug.h | |||
| @@ -250,6 +250,9 @@ static inline void dwc3_decode_get_status(__u8 t, __u16 i, __u16 l, char *str, | |||
| 250 | size_t size) | 250 | size_t size) |
| 251 | { | 251 | { |
| 252 | switch (t & USB_RECIP_MASK) { | 252 | switch (t & USB_RECIP_MASK) { |
| 253 | case USB_RECIP_DEVICE: | ||
| 254 | snprintf(str, size, "Get Device Status(Length = %d)", l); | ||
| 255 | break; | ||
| 253 | case USB_RECIP_INTERFACE: | 256 | case USB_RECIP_INTERFACE: |
| 254 | snprintf(str, size, "Get Interface Status(Intf = %d, Length = %d)", | 257 | snprintf(str, size, "Get Interface Status(Intf = %d, Length = %d)", |
| 255 | i, l); | 258 | i, l); |
diff --git a/drivers/usb/dwc3/dwc3-meson-g12a.c b/drivers/usb/dwc3/dwc3-meson-g12a.c new file mode 100644 index 000000000000..2aec31a2eacb --- /dev/null +++ b/drivers/usb/dwc3/dwc3-meson-g12a.c | |||
| @@ -0,0 +1,604 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * USB Glue for Amlogic G12A SoCs | ||
| 4 | * | ||
| 5 | * Copyright (c) 2019 BayLibre, SAS | ||
| 6 | * Author: Neil Armstrong <narmstrong@baylibre.com> | ||
| 7 | */ | ||
| 8 | |||
| 9 | /* | ||
| 10 | * The USB is organized with a glue around the DWC3 Controller IP as : | ||
| 11 | * - Control registers for each USB2 Ports | ||
| 12 | * - Control registers for the USB PHY layer | ||
| 13 | * - SuperSpeed PHY can be enabled only if port is used | ||
| 14 | * | ||
| 15 | * TOFIX: | ||
| 16 | * - Add dynamic OTG switching with ID change interrupt | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <linux/module.h> | ||
| 20 | #include <linux/kernel.h> | ||
| 21 | #include <linux/platform_device.h> | ||
| 22 | #include <linux/clk.h> | ||
| 23 | #include <linux/of.h> | ||
| 24 | #include <linux/of_platform.h> | ||
| 25 | #include <linux/pm_runtime.h> | ||
| 26 | #include <linux/regmap.h> | ||
| 27 | #include <linux/bitfield.h> | ||
| 28 | #include <linux/bitops.h> | ||
| 29 | #include <linux/reset.h> | ||
| 30 | #include <linux/phy/phy.h> | ||
| 31 | #include <linux/usb/otg.h> | ||
| 32 | #include <linux/usb/role.h> | ||
| 33 | #include <linux/regulator/consumer.h> | ||
| 34 | |||
| 35 | /* USB2 Ports Control Registers */ | ||
| 36 | |||
| 37 | #define U2P_REG_SIZE 0x20 | ||
| 38 | |||
| 39 | #define U2P_R0 0x0 | ||
| 40 | #define U2P_R0_HOST_DEVICE BIT(0) | ||
| 41 | #define U2P_R0_POWER_OK BIT(1) | ||
| 42 | #define U2P_R0_HAST_MODE BIT(2) | ||
| 43 | #define U2P_R0_POWER_ON_RESET BIT(3) | ||
| 44 | #define U2P_R0_ID_PULLUP BIT(4) | ||
| 45 | #define U2P_R0_DRV_VBUS BIT(5) | ||
| 46 | |||
| 47 | #define U2P_R1 0x4 | ||
| 48 | #define U2P_R1_PHY_READY BIT(0) | ||
| 49 | #define U2P_R1_ID_DIG BIT(1) | ||
| 50 | #define U2P_R1_OTG_SESSION_VALID BIT(2) | ||
| 51 | #define U2P_R1_VBUS_VALID BIT(3) | ||
| 52 | |||
| 53 | /* USB Glue Control Registers */ | ||
| 54 | |||
| 55 | #define USB_R0 0x80 | ||
| 56 | #define USB_R0_P30_LANE0_TX2RX_LOOPBACK BIT(17) | ||
| 57 | #define USB_R0_P30_LANE0_EXT_PCLK_REQ BIT(18) | ||
| 58 | #define USB_R0_P30_PCS_RX_LOS_MASK_VAL_MASK GENMASK(28, 19) | ||
| 59 | #define USB_R0_U2D_SS_SCALEDOWN_MODE_MASK GENMASK(30, 29) | ||
| 60 | #define USB_R0_U2D_ACT BIT(31) | ||
| 61 | |||
| 62 | #define USB_R1 0x84 | ||
| 63 | #define USB_R1_U3H_BIGENDIAN_GS BIT(0) | ||
| 64 | #define USB_R1_U3H_PME_ENABLE BIT(1) | ||
| 65 | #define USB_R1_U3H_HUB_PORT_OVERCURRENT_MASK GENMASK(4, 2) | ||
| 66 | #define USB_R1_U3H_HUB_PORT_PERM_ATTACH_MASK GENMASK(9, 7) | ||
| 67 | #define USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK GENMASK(13, 12) | ||
| 68 | #define USB_R1_U3H_HOST_U3_PORT_DISABLE BIT(16) | ||
| 69 | #define USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT BIT(17) | ||
| 70 | #define USB_R1_U3H_HOST_MSI_ENABLE BIT(18) | ||
| 71 | #define USB_R1_U3H_FLADJ_30MHZ_REG_MASK GENMASK(24, 19) | ||
| 72 | #define USB_R1_P30_PCS_TX_SWING_FULL_MASK GENMASK(31, 25) | ||
| 73 | |||
| 74 | #define USB_R2 0x88 | ||
| 75 | #define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK GENMASK(25, 20) | ||
| 76 | #define USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK GENMASK(31, 26) | ||
| 77 | |||
| 78 | #define USB_R3 0x8c | ||
| 79 | #define USB_R3_P30_SSC_ENABLE BIT(0) | ||
| 80 | #define USB_R3_P30_SSC_RANGE_MASK GENMASK(3, 1) | ||
| 81 | #define USB_R3_P30_SSC_REF_CLK_SEL_MASK GENMASK(12, 4) | ||
| 82 | #define USB_R3_P30_REF_SSP_EN BIT(13) | ||
| 83 | |||
| 84 | #define USB_R4 0x90 | ||
| 85 | #define USB_R4_P21_PORT_RESET_0 BIT(0) | ||
| 86 | #define USB_R4_P21_SLEEP_M0 BIT(1) | ||
| 87 | #define USB_R4_MEM_PD_MASK GENMASK(3, 2) | ||
| 88 | #define USB_R4_P21_ONLY BIT(4) | ||
| 89 | |||
| 90 | #define USB_R5 0x94 | ||
| 91 | #define USB_R5_ID_DIG_SYNC BIT(0) | ||
| 92 | #define USB_R5_ID_DIG_REG BIT(1) | ||
| 93 | #define USB_R5_ID_DIG_CFG_MASK GENMASK(3, 2) | ||
| 94 | #define USB_R5_ID_DIG_EN_0 BIT(4) | ||
| 95 | #define USB_R5_ID_DIG_EN_1 BIT(5) | ||
| 96 | #define USB_R5_ID_DIG_CURR BIT(6) | ||
| 97 | #define USB_R5_ID_DIG_IRQ BIT(7) | ||
| 98 | #define USB_R5_ID_DIG_TH_MASK GENMASK(15, 8) | ||
| 99 | #define USB_R5_ID_DIG_CNT_MASK GENMASK(23, 16) | ||
| 100 | |||
| 101 | enum { | ||
| 102 | USB2_HOST_PHY = 0, | ||
| 103 | USB2_OTG_PHY, | ||
| 104 | USB3_HOST_PHY, | ||
| 105 | PHY_COUNT, | ||
| 106 | }; | ||
| 107 | |||
| 108 | static const char *phy_names[PHY_COUNT] = { | ||
| 109 | "usb2-phy0", "usb2-phy1", "usb3-phy0", | ||
| 110 | }; | ||
| 111 | |||
| 112 | struct dwc3_meson_g12a { | ||
| 113 | struct device *dev; | ||
| 114 | struct regmap *regmap; | ||
| 115 | struct clk *clk; | ||
| 116 | struct reset_control *reset; | ||
| 117 | struct phy *phys[PHY_COUNT]; | ||
| 118 | enum usb_dr_mode otg_mode; | ||
| 119 | enum phy_mode otg_phy_mode; | ||
| 120 | unsigned int usb2_ports; | ||
| 121 | unsigned int usb3_ports; | ||
| 122 | struct regulator *vbus; | ||
| 123 | struct usb_role_switch_desc switch_desc; | ||
| 124 | struct usb_role_switch *role_switch; | ||
| 125 | }; | ||
| 126 | |||
| 127 | static void dwc3_meson_g12a_usb2_set_mode(struct dwc3_meson_g12a *priv, | ||
| 128 | int i, enum phy_mode mode) | ||
| 129 | { | ||
| 130 | if (mode == PHY_MODE_USB_HOST) | ||
| 131 | regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i), | ||
| 132 | U2P_R0_HOST_DEVICE, | ||
| 133 | U2P_R0_HOST_DEVICE); | ||
| 134 | else | ||
| 135 | regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i), | ||
| 136 | U2P_R0_HOST_DEVICE, 0); | ||
| 137 | } | ||
| 138 | |||
| 139 | static int dwc3_meson_g12a_usb2_init(struct dwc3_meson_g12a *priv) | ||
| 140 | { | ||
| 141 | int i; | ||
| 142 | |||
| 143 | if (priv->otg_mode == USB_DR_MODE_PERIPHERAL) | ||
| 144 | priv->otg_phy_mode = PHY_MODE_USB_DEVICE; | ||
| 145 | else | ||
| 146 | priv->otg_phy_mode = PHY_MODE_USB_HOST; | ||
| 147 | |||
| 148 | for (i = 0 ; i < USB3_HOST_PHY ; ++i) { | ||
| 149 | if (!priv->phys[i]) | ||
| 150 | continue; | ||
| 151 | |||
| 152 | regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i), | ||
| 153 | U2P_R0_POWER_ON_RESET, | ||
| 154 | U2P_R0_POWER_ON_RESET); | ||
| 155 | |||
| 156 | if (i == USB2_OTG_PHY) { | ||
| 157 | regmap_update_bits(priv->regmap, | ||
| 158 | U2P_R0 + (U2P_REG_SIZE * i), | ||
| 159 | U2P_R0_ID_PULLUP | U2P_R0_DRV_VBUS, | ||
| 160 | U2P_R0_ID_PULLUP | U2P_R0_DRV_VBUS); | ||
| 161 | |||
| 162 | dwc3_meson_g12a_usb2_set_mode(priv, i, | ||
| 163 | priv->otg_phy_mode); | ||
| 164 | } else | ||
| 165 | dwc3_meson_g12a_usb2_set_mode(priv, i, | ||
| 166 | PHY_MODE_USB_HOST); | ||
| 167 | |||
| 168 | regmap_update_bits(priv->regmap, U2P_R0 + (U2P_REG_SIZE * i), | ||
| 169 | U2P_R0_POWER_ON_RESET, 0); | ||
| 170 | } | ||
| 171 | |||
| 172 | return 0; | ||
| 173 | } | ||
| 174 | |||
| 175 | static void dwc3_meson_g12a_usb3_init(struct dwc3_meson_g12a *priv) | ||
| 176 | { | ||
| 177 | regmap_update_bits(priv->regmap, USB_R3, | ||
| 178 | USB_R3_P30_SSC_RANGE_MASK | | ||
| 179 | USB_R3_P30_REF_SSP_EN, | ||
| 180 | USB_R3_P30_SSC_ENABLE | | ||
| 181 | FIELD_PREP(USB_R3_P30_SSC_RANGE_MASK, 2) | | ||
| 182 | USB_R3_P30_REF_SSP_EN); | ||
| 183 | udelay(2); | ||
| 184 | |||
| 185 | regmap_update_bits(priv->regmap, USB_R2, | ||
| 186 | USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK, | ||
| 187 | FIELD_PREP(USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK, 0x15)); | ||
| 188 | |||
| 189 | regmap_update_bits(priv->regmap, USB_R2, | ||
| 190 | USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK, | ||
| 191 | FIELD_PREP(USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK, 0x20)); | ||
| 192 | |||
| 193 | udelay(2); | ||
| 194 | |||
| 195 | regmap_update_bits(priv->regmap, USB_R1, | ||
| 196 | USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT, | ||
| 197 | USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT); | ||
| 198 | |||
| 199 | regmap_update_bits(priv->regmap, USB_R1, | ||
| 200 | USB_R1_P30_PCS_TX_SWING_FULL_MASK, | ||
| 201 | FIELD_PREP(USB_R1_P30_PCS_TX_SWING_FULL_MASK, 127)); | ||
| 202 | } | ||
| 203 | |||
| 204 | static void dwc3_meson_g12a_usb_otg_apply_mode(struct dwc3_meson_g12a *priv) | ||
| 205 | { | ||
| 206 | if (priv->otg_phy_mode == PHY_MODE_USB_DEVICE) { | ||
| 207 | regmap_update_bits(priv->regmap, USB_R0, | ||
| 208 | USB_R0_U2D_ACT, USB_R0_U2D_ACT); | ||
| 209 | regmap_update_bits(priv->regmap, USB_R0, | ||
| 210 | USB_R0_U2D_SS_SCALEDOWN_MODE_MASK, 0); | ||
| 211 | regmap_update_bits(priv->regmap, USB_R4, | ||
| 212 | USB_R4_P21_SLEEP_M0, USB_R4_P21_SLEEP_M0); | ||
| 213 | } else { | ||
| 214 | regmap_update_bits(priv->regmap, USB_R0, | ||
| 215 | USB_R0_U2D_ACT, 0); | ||
| 216 | regmap_update_bits(priv->regmap, USB_R4, | ||
| 217 | USB_R4_P21_SLEEP_M0, 0); | ||
| 218 | } | ||
| 219 | } | ||
| 220 | |||
| 221 | static int dwc3_meson_g12a_usb_init(struct dwc3_meson_g12a *priv) | ||
| 222 | { | ||
| 223 | int ret; | ||
| 224 | |||
| 225 | ret = dwc3_meson_g12a_usb2_init(priv); | ||
| 226 | if (ret) | ||
| 227 | return ret; | ||
| 228 | |||
| 229 | regmap_update_bits(priv->regmap, USB_R1, | ||
| 230 | USB_R1_U3H_FLADJ_30MHZ_REG_MASK, | ||
| 231 | FIELD_PREP(USB_R1_U3H_FLADJ_30MHZ_REG_MASK, 0x20)); | ||
| 232 | |||
| 233 | regmap_update_bits(priv->regmap, USB_R5, | ||
| 234 | USB_R5_ID_DIG_EN_0, | ||
| 235 | USB_R5_ID_DIG_EN_0); | ||
| 236 | regmap_update_bits(priv->regmap, USB_R5, | ||
| 237 | USB_R5_ID_DIG_EN_1, | ||
| 238 | USB_R5_ID_DIG_EN_1); | ||
| 239 | regmap_update_bits(priv->regmap, USB_R5, | ||
| 240 | USB_R5_ID_DIG_TH_MASK, | ||
| 241 | FIELD_PREP(USB_R5_ID_DIG_TH_MASK, 0xff)); | ||
| 242 | |||
| 243 | /* If we have an actual SuperSpeed port, initialize it */ | ||
| 244 | if (priv->usb3_ports) | ||
| 245 | dwc3_meson_g12a_usb3_init(priv); | ||
| 246 | |||
| 247 | dwc3_meson_g12a_usb_otg_apply_mode(priv); | ||
| 248 | |||
| 249 | return 0; | ||
| 250 | } | ||
| 251 | |||
| 252 | static const struct regmap_config phy_meson_g12a_usb3_regmap_conf = { | ||
| 253 | .reg_bits = 8, | ||
| 254 | .val_bits = 32, | ||
| 255 | .reg_stride = 4, | ||
| 256 | .max_register = USB_R5, | ||
| 257 | }; | ||
| 258 | |||
| 259 | static int dwc3_meson_g12a_get_phys(struct dwc3_meson_g12a *priv) | ||
| 260 | { | ||
| 261 | int i; | ||
| 262 | |||
| 263 | for (i = 0 ; i < PHY_COUNT ; ++i) { | ||
| 264 | priv->phys[i] = devm_phy_optional_get(priv->dev, phy_names[i]); | ||
| 265 | if (!priv->phys[i]) | ||
| 266 | continue; | ||
| 267 | |||
| 268 | if (IS_ERR(priv->phys[i])) | ||
| 269 | return PTR_ERR(priv->phys[i]); | ||
| 270 | |||
| 271 | if (i == USB3_HOST_PHY) | ||
| 272 | priv->usb3_ports++; | ||
| 273 | else | ||
| 274 | priv->usb2_ports++; | ||
| 275 | } | ||
| 276 | |||
| 277 | dev_info(priv->dev, "USB2 ports: %d\n", priv->usb2_ports); | ||
| 278 | dev_info(priv->dev, "USB3 ports: %d\n", priv->usb3_ports); | ||
| 279 | |||
| 280 | return 0; | ||
| 281 | } | ||
| 282 | |||
| 283 | static enum phy_mode dwc3_meson_g12a_get_id(struct dwc3_meson_g12a *priv) | ||
| 284 | { | ||
| 285 | u32 reg; | ||
| 286 | |||
| 287 | regmap_read(priv->regmap, USB_R5, ®); | ||
| 288 | |||
| 289 | if (reg & (USB_R5_ID_DIG_SYNC | USB_R5_ID_DIG_REG)) | ||
| 290 | return PHY_MODE_USB_DEVICE; | ||
| 291 | |||
| 292 | return PHY_MODE_USB_HOST; | ||
| 293 | } | ||
| 294 | |||
| 295 | static int dwc3_meson_g12a_otg_mode_set(struct dwc3_meson_g12a *priv, | ||
| 296 | enum phy_mode mode) | ||
| 297 | { | ||
| 298 | int ret; | ||
| 299 | |||
| 300 | if (!priv->phys[USB2_OTG_PHY]) | ||
| 301 | return -EINVAL; | ||
| 302 | |||
| 303 | if (mode == PHY_MODE_USB_HOST) | ||
| 304 | dev_info(priv->dev, "switching to Host Mode\n"); | ||
| 305 | else | ||
| 306 | dev_info(priv->dev, "switching to Device Mode\n"); | ||
| 307 | |||
| 308 | if (priv->vbus) { | ||
| 309 | if (mode == PHY_MODE_USB_DEVICE) | ||
| 310 | ret = regulator_disable(priv->vbus); | ||
| 311 | else | ||
| 312 | ret = regulator_enable(priv->vbus); | ||
| 313 | if (ret) | ||
| 314 | return ret; | ||
| 315 | } | ||
| 316 | |||
| 317 | priv->otg_phy_mode = mode; | ||
| 318 | |||
| 319 | dwc3_meson_g12a_usb2_set_mode(priv, USB2_OTG_PHY, mode); | ||
| 320 | |||
| 321 | dwc3_meson_g12a_usb_otg_apply_mode(priv); | ||
| 322 | |||
| 323 | return 0; | ||
| 324 | } | ||
| 325 | |||
| 326 | static int dwc3_meson_g12a_role_set(struct device *dev, enum usb_role role) | ||
| 327 | { | ||
| 328 | struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); | ||
| 329 | enum phy_mode mode; | ||
| 330 | |||
| 331 | if (role == USB_ROLE_NONE) | ||
| 332 | return 0; | ||
| 333 | |||
| 334 | mode = (role == USB_ROLE_HOST) ? PHY_MODE_USB_HOST | ||
| 335 | : PHY_MODE_USB_DEVICE; | ||
| 336 | |||
| 337 | if (mode == priv->otg_phy_mode) | ||
| 338 | return 0; | ||
| 339 | |||
| 340 | return dwc3_meson_g12a_otg_mode_set(priv, mode); | ||
| 341 | } | ||
| 342 | |||
| 343 | static enum usb_role dwc3_meson_g12a_role_get(struct device *dev) | ||
| 344 | { | ||
| 345 | struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); | ||
| 346 | |||
| 347 | return priv->otg_phy_mode == PHY_MODE_USB_HOST ? | ||
| 348 | USB_ROLE_HOST : USB_ROLE_DEVICE; | ||
| 349 | } | ||
| 350 | |||
| 351 | static struct device *dwc3_meson_g12_find_child(struct device *dev, | ||
| 352 | const char *compatible) | ||
| 353 | { | ||
| 354 | struct platform_device *pdev; | ||
| 355 | struct device_node *np; | ||
| 356 | |||
| 357 | np = of_get_compatible_child(dev->of_node, compatible); | ||
| 358 | if (!np) | ||
| 359 | return NULL; | ||
| 360 | |||
| 361 | pdev = of_find_device_by_node(np); | ||
| 362 | of_node_put(np); | ||
| 363 | if (!pdev) | ||
| 364 | return NULL; | ||
| 365 | |||
| 366 | return &pdev->dev; | ||
| 367 | } | ||
| 368 | |||
| 369 | static int dwc3_meson_g12a_probe(struct platform_device *pdev) | ||
| 370 | { | ||
| 371 | struct dwc3_meson_g12a *priv; | ||
| 372 | struct device *dev = &pdev->dev; | ||
| 373 | struct device_node *np = dev->of_node; | ||
| 374 | void __iomem *base; | ||
| 375 | struct resource *res; | ||
| 376 | enum phy_mode otg_id; | ||
| 377 | int ret, i; | ||
| 378 | |||
| 379 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | ||
| 380 | if (!priv) | ||
| 381 | return -ENOMEM; | ||
| 382 | |||
| 383 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 384 | base = devm_ioremap_resource(dev, res); | ||
| 385 | if (IS_ERR(base)) | ||
| 386 | return PTR_ERR(base); | ||
| 387 | |||
| 388 | priv->regmap = devm_regmap_init_mmio(dev, base, | ||
| 389 | &phy_meson_g12a_usb3_regmap_conf); | ||
| 390 | if (IS_ERR(priv->regmap)) | ||
| 391 | return PTR_ERR(priv->regmap); | ||
| 392 | |||
| 393 | priv->vbus = devm_regulator_get_optional(dev, "vbus"); | ||
| 394 | if (IS_ERR(priv->vbus)) { | ||
| 395 | if (PTR_ERR(priv->vbus) == -EPROBE_DEFER) | ||
| 396 | return PTR_ERR(priv->vbus); | ||
| 397 | priv->vbus = NULL; | ||
| 398 | } | ||
| 399 | |||
| 400 | priv->clk = devm_clk_get(dev, NULL); | ||
| 401 | if (IS_ERR(priv->clk)) | ||
| 402 | return PTR_ERR(priv->clk); | ||
| 403 | |||
| 404 | ret = clk_prepare_enable(priv->clk); | ||
| 405 | if (ret) | ||
| 406 | return ret; | ||
| 407 | |||
| 408 | devm_add_action_or_reset(dev, | ||
| 409 | (void(*)(void *))clk_disable_unprepare, | ||
| 410 | priv->clk); | ||
| 411 | |||
| 412 | platform_set_drvdata(pdev, priv); | ||
| 413 | priv->dev = dev; | ||
| 414 | |||
| 415 | priv->reset = devm_reset_control_get(dev, NULL); | ||
| 416 | if (IS_ERR(priv->reset)) { | ||
| 417 | ret = PTR_ERR(priv->reset); | ||
| 418 | dev_err(dev, "failed to get device reset, err=%d\n", ret); | ||
| 419 | return ret; | ||
| 420 | } | ||
| 421 | |||
| 422 | ret = reset_control_reset(priv->reset); | ||
| 423 | if (ret) | ||
| 424 | return ret; | ||
| 425 | |||
| 426 | ret = dwc3_meson_g12a_get_phys(priv); | ||
| 427 | if (ret) | ||
| 428 | return ret; | ||
| 429 | |||
| 430 | if (priv->vbus) { | ||
| 431 | ret = regulator_enable(priv->vbus); | ||
| 432 | if (ret) | ||
| 433 | return ret; | ||
| 434 | } | ||
| 435 | |||
| 436 | /* Get dr_mode */ | ||
| 437 | priv->otg_mode = usb_get_dr_mode(dev); | ||
| 438 | |||
| 439 | dwc3_meson_g12a_usb_init(priv); | ||
| 440 | |||
| 441 | /* Init PHYs */ | ||
| 442 | for (i = 0 ; i < PHY_COUNT ; ++i) { | ||
| 443 | ret = phy_init(priv->phys[i]); | ||
| 444 | if (ret) | ||
| 445 | return ret; | ||
| 446 | } | ||
| 447 | |||
| 448 | /* Set PHY Power */ | ||
| 449 | for (i = 0 ; i < PHY_COUNT ; ++i) { | ||
| 450 | ret = phy_power_on(priv->phys[i]); | ||
| 451 | if (ret) | ||
| 452 | goto err_phys_exit; | ||
| 453 | } | ||
| 454 | |||
| 455 | ret = of_platform_populate(np, NULL, NULL, dev); | ||
| 456 | if (ret) { | ||
| 457 | clk_disable_unprepare(priv->clk); | ||
| 458 | goto err_phys_power; | ||
| 459 | } | ||
| 460 | |||
| 461 | /* Setup OTG mode corresponding to the ID pin */ | ||
| 462 | if (priv->otg_mode == USB_DR_MODE_OTG) { | ||
| 463 | /* TOFIX Handle ID mode toggling via IRQ */ | ||
| 464 | otg_id = dwc3_meson_g12a_get_id(priv); | ||
| 465 | if (otg_id != priv->otg_phy_mode) { | ||
| 466 | if (dwc3_meson_g12a_otg_mode_set(priv, otg_id)) | ||
| 467 | dev_warn(dev, "Failed to switch OTG mode\n"); | ||
| 468 | } | ||
| 469 | } | ||
| 470 | |||
| 471 | /* Setup role switcher */ | ||
| 472 | priv->switch_desc.usb2_port = dwc3_meson_g12_find_child(dev, | ||
| 473 | "snps,dwc3"); | ||
| 474 | priv->switch_desc.udc = dwc3_meson_g12_find_child(dev, "snps,dwc2"); | ||
| 475 | priv->switch_desc.allow_userspace_control = true; | ||
| 476 | priv->switch_desc.set = dwc3_meson_g12a_role_set; | ||
| 477 | priv->switch_desc.get = dwc3_meson_g12a_role_get; | ||
| 478 | |||
| 479 | priv->role_switch = usb_role_switch_register(dev, &priv->switch_desc); | ||
| 480 | if (IS_ERR(priv->role_switch)) | ||
| 481 | dev_warn(dev, "Unable to register Role Switch\n"); | ||
| 482 | |||
| 483 | pm_runtime_set_active(dev); | ||
| 484 | pm_runtime_enable(dev); | ||
| 485 | pm_runtime_get_sync(dev); | ||
| 486 | |||
| 487 | return 0; | ||
| 488 | |||
| 489 | err_phys_power: | ||
| 490 | for (i = 0 ; i < PHY_COUNT ; ++i) | ||
| 491 | phy_power_off(priv->phys[i]); | ||
| 492 | |||
| 493 | err_phys_exit: | ||
| 494 | for (i = 0 ; i < PHY_COUNT ; ++i) | ||
| 495 | phy_exit(priv->phys[i]); | ||
| 496 | |||
| 497 | return ret; | ||
| 498 | } | ||
| 499 | |||
| 500 | static int dwc3_meson_g12a_remove(struct platform_device *pdev) | ||
| 501 | { | ||
| 502 | struct dwc3_meson_g12a *priv = platform_get_drvdata(pdev); | ||
| 503 | struct device *dev = &pdev->dev; | ||
| 504 | int i; | ||
| 505 | |||
| 506 | usb_role_switch_unregister(priv->role_switch); | ||
| 507 | |||
| 508 | of_platform_depopulate(dev); | ||
| 509 | |||
| 510 | for (i = 0 ; i < PHY_COUNT ; ++i) { | ||
| 511 | phy_power_off(priv->phys[i]); | ||
| 512 | phy_exit(priv->phys[i]); | ||
| 513 | } | ||
| 514 | |||
| 515 | pm_runtime_disable(dev); | ||
| 516 | pm_runtime_put_noidle(dev); | ||
| 517 | pm_runtime_set_suspended(dev); | ||
| 518 | |||
| 519 | return 0; | ||
| 520 | } | ||
| 521 | |||
| 522 | static int __maybe_unused dwc3_meson_g12a_runtime_suspend(struct device *dev) | ||
| 523 | { | ||
| 524 | struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); | ||
| 525 | |||
| 526 | clk_disable(priv->clk); | ||
| 527 | |||
| 528 | return 0; | ||
| 529 | } | ||
| 530 | |||
| 531 | static int __maybe_unused dwc3_meson_g12a_runtime_resume(struct device *dev) | ||
| 532 | { | ||
| 533 | struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); | ||
| 534 | |||
| 535 | return clk_enable(priv->clk); | ||
| 536 | } | ||
| 537 | |||
| 538 | static int __maybe_unused dwc3_meson_g12a_suspend(struct device *dev) | ||
| 539 | { | ||
| 540 | struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); | ||
| 541 | int i; | ||
| 542 | |||
| 543 | for (i = 0 ; i < PHY_COUNT ; ++i) { | ||
| 544 | phy_power_off(priv->phys[i]); | ||
| 545 | phy_exit(priv->phys[i]); | ||
| 546 | } | ||
| 547 | |||
| 548 | reset_control_assert(priv->reset); | ||
| 549 | |||
| 550 | return 0; | ||
| 551 | } | ||
| 552 | |||
| 553 | static int __maybe_unused dwc3_meson_g12a_resume(struct device *dev) | ||
| 554 | { | ||
| 555 | struct dwc3_meson_g12a *priv = dev_get_drvdata(dev); | ||
| 556 | int i, ret; | ||
| 557 | |||
| 558 | reset_control_deassert(priv->reset); | ||
| 559 | |||
| 560 | dwc3_meson_g12a_usb_init(priv); | ||
| 561 | |||
| 562 | /* Init PHYs */ | ||
| 563 | for (i = 0 ; i < PHY_COUNT ; ++i) { | ||
| 564 | ret = phy_init(priv->phys[i]); | ||
| 565 | if (ret) | ||
| 566 | return ret; | ||
| 567 | } | ||
| 568 | |||
| 569 | /* Set PHY Power */ | ||
| 570 | for (i = 0 ; i < PHY_COUNT ; ++i) { | ||
| 571 | ret = phy_power_on(priv->phys[i]); | ||
| 572 | if (ret) | ||
| 573 | return ret; | ||
| 574 | } | ||
| 575 | |||
| 576 | return 0; | ||
| 577 | } | ||
| 578 | |||
| 579 | static const struct dev_pm_ops dwc3_meson_g12a_dev_pm_ops = { | ||
| 580 | SET_SYSTEM_SLEEP_PM_OPS(dwc3_meson_g12a_suspend, dwc3_meson_g12a_resume) | ||
| 581 | SET_RUNTIME_PM_OPS(dwc3_meson_g12a_runtime_suspend, | ||
| 582 | dwc3_meson_g12a_runtime_resume, NULL) | ||
| 583 | }; | ||
| 584 | |||
| 585 | static const struct of_device_id dwc3_meson_g12a_match[] = { | ||
| 586 | { .compatible = "amlogic,meson-g12a-usb-ctrl" }, | ||
| 587 | { /* Sentinel */ } | ||
| 588 | }; | ||
| 589 | MODULE_DEVICE_TABLE(of, dwc3_meson_g12a_match); | ||
| 590 | |||
| 591 | static struct platform_driver dwc3_meson_g12a_driver = { | ||
| 592 | .probe = dwc3_meson_g12a_probe, | ||
| 593 | .remove = dwc3_meson_g12a_remove, | ||
| 594 | .driver = { | ||
| 595 | .name = "dwc3-meson-g12a", | ||
| 596 | .of_match_table = dwc3_meson_g12a_match, | ||
| 597 | .pm = &dwc3_meson_g12a_dev_pm_ops, | ||
| 598 | }, | ||
| 599 | }; | ||
| 600 | |||
| 601 | module_platform_driver(dwc3_meson_g12a_driver); | ||
| 602 | MODULE_LICENSE("GPL v2"); | ||
| 603 | MODULE_DESCRIPTION("Amlogic Meson G12A USB Glue Layer"); | ||
| 604 | MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>"); | ||
diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of-simple.c index 4c2771c5e727..c4da82dd15c7 100644 --- a/drivers/usb/dwc3/dwc3-of-simple.c +++ b/drivers/usb/dwc3/dwc3-of-simple.c | |||
| @@ -24,59 +24,13 @@ | |||
| 24 | 24 | ||
| 25 | struct dwc3_of_simple { | 25 | struct dwc3_of_simple { |
| 26 | struct device *dev; | 26 | struct device *dev; |
| 27 | struct clk **clks; | 27 | struct clk_bulk_data *clks; |
| 28 | int num_clocks; | 28 | int num_clocks; |
| 29 | struct reset_control *resets; | 29 | struct reset_control *resets; |
| 30 | bool pulse_resets; | 30 | bool pulse_resets; |
| 31 | bool need_reset; | 31 | bool need_reset; |
| 32 | }; | 32 | }; |
| 33 | 33 | ||
| 34 | static int dwc3_of_simple_clk_init(struct dwc3_of_simple *simple, int count) | ||
| 35 | { | ||
| 36 | struct device *dev = simple->dev; | ||
| 37 | struct device_node *np = dev->of_node; | ||
| 38 | int i; | ||
| 39 | |||
| 40 | simple->num_clocks = count; | ||
| 41 | |||
| 42 | if (!count) | ||
| 43 | return 0; | ||
| 44 | |||
| 45 | simple->clks = devm_kcalloc(dev, simple->num_clocks, | ||
| 46 | sizeof(struct clk *), GFP_KERNEL); | ||
| 47 | if (!simple->clks) | ||
| 48 | return -ENOMEM; | ||
| 49 | |||
| 50 | for (i = 0; i < simple->num_clocks; i++) { | ||
| 51 | struct clk *clk; | ||
| 52 | int ret; | ||
| 53 | |||
| 54 | clk = of_clk_get(np, i); | ||
| 55 | if (IS_ERR(clk)) { | ||
| 56 | while (--i >= 0) { | ||
| 57 | clk_disable_unprepare(simple->clks[i]); | ||
| 58 | clk_put(simple->clks[i]); | ||
| 59 | } | ||
| 60 | return PTR_ERR(clk); | ||
| 61 | } | ||
| 62 | |||
| 63 | ret = clk_prepare_enable(clk); | ||
| 64 | if (ret < 0) { | ||
| 65 | while (--i >= 0) { | ||
| 66 | clk_disable_unprepare(simple->clks[i]); | ||
| 67 | clk_put(simple->clks[i]); | ||
| 68 | } | ||
| 69 | clk_put(clk); | ||
| 70 | |||
| 71 | return ret; | ||
| 72 | } | ||
| 73 | |||
| 74 | simple->clks[i] = clk; | ||
| 75 | } | ||
| 76 | |||
| 77 | return 0; | ||
| 78 | } | ||
| 79 | |||
| 80 | static int dwc3_of_simple_probe(struct platform_device *pdev) | 34 | static int dwc3_of_simple_probe(struct platform_device *pdev) |
| 81 | { | 35 | { |
| 82 | struct dwc3_of_simple *simple; | 36 | struct dwc3_of_simple *simple; |
| @@ -84,7 +38,6 @@ static int dwc3_of_simple_probe(struct platform_device *pdev) | |||
| 84 | struct device_node *np = dev->of_node; | 38 | struct device_node *np = dev->of_node; |
| 85 | 39 | ||
| 86 | int ret; | 40 | int ret; |
| 87 | int i; | ||
| 88 | bool shared_resets = false; | 41 | bool shared_resets = false; |
| 89 | 42 | ||
| 90 | simple = devm_kzalloc(dev, sizeof(*simple), GFP_KERNEL); | 43 | simple = devm_kzalloc(dev, sizeof(*simple), GFP_KERNEL); |
| @@ -124,20 +77,18 @@ static int dwc3_of_simple_probe(struct platform_device *pdev) | |||
| 124 | goto err_resetc_put; | 77 | goto err_resetc_put; |
| 125 | } | 78 | } |
| 126 | 79 | ||
| 127 | ret = dwc3_of_simple_clk_init(simple, of_count_phandle_with_args(np, | 80 | ret = clk_bulk_get_all(simple->dev, &simple->clks); |
| 128 | "clocks", "#clock-cells")); | 81 | if (ret < 0) |
| 82 | goto err_resetc_assert; | ||
| 83 | |||
| 84 | simple->num_clocks = ret; | ||
| 85 | ret = clk_bulk_prepare_enable(simple->num_clocks, simple->clks); | ||
| 129 | if (ret) | 86 | if (ret) |
| 130 | goto err_resetc_assert; | 87 | goto err_resetc_assert; |
| 131 | 88 | ||
| 132 | ret = of_platform_populate(np, NULL, NULL, dev); | 89 | ret = of_platform_populate(np, NULL, NULL, dev); |
| 133 | if (ret) { | 90 | if (ret) |
| 134 | for (i = 0; i < simple->num_clocks; i++) { | 91 | goto err_clk_put; |
| 135 | clk_disable_unprepare(simple->clks[i]); | ||
| 136 | clk_put(simple->clks[i]); | ||
| 137 | } | ||
| 138 | |||
| 139 | goto err_resetc_assert; | ||
| 140 | } | ||
| 141 | 92 | ||
| 142 | pm_runtime_set_active(dev); | 93 | pm_runtime_set_active(dev); |
| 143 | pm_runtime_enable(dev); | 94 | pm_runtime_enable(dev); |
| @@ -145,6 +96,10 @@ static int dwc3_of_simple_probe(struct platform_device *pdev) | |||
| 145 | 96 | ||
| 146 | return 0; | 97 | return 0; |
| 147 | 98 | ||
| 99 | err_clk_put: | ||
| 100 | clk_bulk_disable_unprepare(simple->num_clocks, simple->clks); | ||
| 101 | clk_bulk_put_all(simple->num_clocks, simple->clks); | ||
| 102 | |||
| 148 | err_resetc_assert: | 103 | err_resetc_assert: |
| 149 | if (!simple->pulse_resets) | 104 | if (!simple->pulse_resets) |
| 150 | reset_control_assert(simple->resets); | 105 | reset_control_assert(simple->resets); |
| @@ -158,14 +113,11 @@ static int dwc3_of_simple_remove(struct platform_device *pdev) | |||
| 158 | { | 113 | { |
| 159 | struct dwc3_of_simple *simple = platform_get_drvdata(pdev); | 114 | struct dwc3_of_simple *simple = platform_get_drvdata(pdev); |
| 160 | struct device *dev = &pdev->dev; | 115 | struct device *dev = &pdev->dev; |
| 161 | int i; | ||
| 162 | 116 | ||
| 163 | of_platform_depopulate(dev); | 117 | of_platform_depopulate(dev); |
| 164 | 118 | ||
| 165 | for (i = 0; i < simple->num_clocks; i++) { | 119 | clk_bulk_disable_unprepare(simple->num_clocks, simple->clks); |
| 166 | clk_disable_unprepare(simple->clks[i]); | 120 | clk_bulk_put_all(simple->num_clocks, simple->clks); |
| 167 | clk_put(simple->clks[i]); | ||
| 168 | } | ||
| 169 | simple->num_clocks = 0; | 121 | simple->num_clocks = 0; |
| 170 | 122 | ||
| 171 | if (!simple->pulse_resets) | 123 | if (!simple->pulse_resets) |
| @@ -183,10 +135,8 @@ static int dwc3_of_simple_remove(struct platform_device *pdev) | |||
| 183 | static int __maybe_unused dwc3_of_simple_runtime_suspend(struct device *dev) | 135 | static int __maybe_unused dwc3_of_simple_runtime_suspend(struct device *dev) |
| 184 | { | 136 | { |
| 185 | struct dwc3_of_simple *simple = dev_get_drvdata(dev); | 137 | struct dwc3_of_simple *simple = dev_get_drvdata(dev); |
| 186 | int i; | ||
| 187 | 138 | ||
| 188 | for (i = 0; i < simple->num_clocks; i++) | 139 | clk_bulk_disable(simple->num_clocks, simple->clks); |
| 189 | clk_disable(simple->clks[i]); | ||
| 190 | 140 | ||
| 191 | return 0; | 141 | return 0; |
| 192 | } | 142 | } |
| @@ -194,19 +144,8 @@ static int __maybe_unused dwc3_of_simple_runtime_suspend(struct device *dev) | |||
| 194 | static int __maybe_unused dwc3_of_simple_runtime_resume(struct device *dev) | 144 | static int __maybe_unused dwc3_of_simple_runtime_resume(struct device *dev) |
| 195 | { | 145 | { |
| 196 | struct dwc3_of_simple *simple = dev_get_drvdata(dev); | 146 | struct dwc3_of_simple *simple = dev_get_drvdata(dev); |
| 197 | int ret; | ||
| 198 | int i; | ||
| 199 | |||
| 200 | for (i = 0; i < simple->num_clocks; i++) { | ||
| 201 | ret = clk_enable(simple->clks[i]); | ||
| 202 | if (ret < 0) { | ||
| 203 | while (--i >= 0) | ||
| 204 | clk_disable(simple->clks[i]); | ||
| 205 | return ret; | ||
| 206 | } | ||
| 207 | } | ||
| 208 | 147 | ||
| 209 | return 0; | 148 | return clk_bulk_enable(simple->num_clocks, simple->clks); |
| 210 | } | 149 | } |
| 211 | 150 | ||
| 212 | static int __maybe_unused dwc3_of_simple_suspend(struct device *dev) | 151 | static int __maybe_unused dwc3_of_simple_suspend(struct device *dev) |
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index e293400cc6e9..d67655384eb2 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c | |||
| @@ -2863,7 +2863,7 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) | |||
| 2863 | "LPM Erratum not available on dwc3 revisions < 2.40a\n"); | 2863 | "LPM Erratum not available on dwc3 revisions < 2.40a\n"); |
| 2864 | 2864 | ||
| 2865 | if (dwc->has_lpm_erratum && dwc->revision >= DWC3_REVISION_240A) | 2865 | if (dwc->has_lpm_erratum && dwc->revision >= DWC3_REVISION_240A) |
| 2866 | reg |= DWC3_DCTL_LPM_ERRATA(dwc->lpm_nyet_threshold); | 2866 | reg |= DWC3_DCTL_NYET_THRES(dwc->lpm_nyet_threshold); |
| 2867 | 2867 | ||
| 2868 | dwc3_writel(dwc->regs, DWC3_DCTL, reg); | 2868 | dwc3_writel(dwc->regs, DWC3_DCTL, reg); |
| 2869 | } else { | 2869 | } else { |
| @@ -3301,6 +3301,7 @@ int dwc3_gadget_init(struct dwc3 *dwc) | |||
| 3301 | dwc->gadget.sg_supported = true; | 3301 | dwc->gadget.sg_supported = true; |
| 3302 | dwc->gadget.name = "dwc3-gadget"; | 3302 | dwc->gadget.name = "dwc3-gadget"; |
| 3303 | dwc->gadget.is_otg = dwc->dr_mode == USB_DR_MODE_OTG; | 3303 | dwc->gadget.is_otg = dwc->dr_mode == USB_DR_MODE_OTG; |
| 3304 | dwc->gadget.lpm_capable = true; | ||
| 3304 | 3305 | ||
| 3305 | /* | 3306 | /* |
| 3306 | * FIXME We might be setting max_speed to <SUPER, however versions | 3307 | * FIXME We might be setting max_speed to <SUPER, however versions |
| @@ -3384,8 +3385,6 @@ int dwc3_gadget_suspend(struct dwc3 *dwc) | |||
| 3384 | dwc3_disconnect_gadget(dwc); | 3385 | dwc3_disconnect_gadget(dwc); |
| 3385 | __dwc3_gadget_stop(dwc); | 3386 | __dwc3_gadget_stop(dwc); |
| 3386 | 3387 | ||
| 3387 | synchronize_irq(dwc->irq_gadget); | ||
| 3388 | |||
| 3389 | return 0; | 3388 | return 0; |
| 3390 | } | 3389 | } |
| 3391 | 3390 | ||
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 20413c276c61..47be961f1bf3 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c | |||
| @@ -1133,7 +1133,8 @@ error_lock: | |||
| 1133 | error_mutex: | 1133 | error_mutex: |
| 1134 | mutex_unlock(&epfile->mutex); | 1134 | mutex_unlock(&epfile->mutex); |
| 1135 | error: | 1135 | error: |
| 1136 | ffs_free_buffer(io_data); | 1136 | if (ret != -EIOCBQUEUED) /* don't free if there is iocb queued */ |
| 1137 | ffs_free_buffer(io_data); | ||
| 1137 | return ret; | 1138 | return ret; |
| 1138 | } | 1139 | } |
| 1139 | 1140 | ||
diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index 5780fba620ab..2d6e76e4cffa 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include "u_ether.h" | 23 | #include "u_ether.h" |
| 24 | #include "u_ether_configfs.h" | 24 | #include "u_ether_configfs.h" |
| 25 | #include "u_ncm.h" | 25 | #include "u_ncm.h" |
| 26 | #include "configfs.h" | ||
| 26 | 27 | ||
| 27 | /* | 28 | /* |
| 28 | * This function is a "CDC Network Control Model" (CDC NCM) Ethernet link. | 29 | * This function is a "CDC Network Control Model" (CDC NCM) Ethernet link. |
| @@ -35,9 +36,7 @@ | |||
| 35 | 36 | ||
| 36 | /* to trigger crc/non-crc ndp signature */ | 37 | /* to trigger crc/non-crc ndp signature */ |
| 37 | 38 | ||
| 38 | #define NCM_NDP_HDR_CRC_MASK 0x01000000 | ||
| 39 | #define NCM_NDP_HDR_CRC 0x01000000 | 39 | #define NCM_NDP_HDR_CRC 0x01000000 |
| 40 | #define NCM_NDP_HDR_NOCRC 0x00000000 | ||
| 41 | 40 | ||
| 42 | enum ncm_notify_state { | 41 | enum ncm_notify_state { |
| 43 | NCM_NOTIFY_NONE, /* don't notify */ | 42 | NCM_NOTIFY_NONE, /* don't notify */ |
| @@ -526,6 +525,7 @@ static inline void ncm_reset_values(struct f_ncm *ncm) | |||
| 526 | { | 525 | { |
| 527 | ncm->parser_opts = &ndp16_opts; | 526 | ncm->parser_opts = &ndp16_opts; |
| 528 | ncm->is_crc = false; | 527 | ncm->is_crc = false; |
| 528 | ncm->ndp_sign = ncm->parser_opts->ndp_sign; | ||
| 529 | ncm->port.cdc_filter = DEFAULT_FILTER; | 529 | ncm->port.cdc_filter = DEFAULT_FILTER; |
| 530 | 530 | ||
| 531 | /* doesn't make sense for ncm, fixed size used */ | 531 | /* doesn't make sense for ncm, fixed size used */ |
| @@ -805,25 +805,20 @@ static int ncm_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) | |||
| 805 | case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) | 805 | case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) |
| 806 | | USB_CDC_SET_CRC_MODE: | 806 | | USB_CDC_SET_CRC_MODE: |
| 807 | { | 807 | { |
| 808 | int ndp_hdr_crc = 0; | ||
| 809 | |||
| 810 | if (w_length != 0 || w_index != ncm->ctrl_id) | 808 | if (w_length != 0 || w_index != ncm->ctrl_id) |
| 811 | goto invalid; | 809 | goto invalid; |
| 812 | switch (w_value) { | 810 | switch (w_value) { |
| 813 | case 0x0000: | 811 | case 0x0000: |
| 814 | ncm->is_crc = false; | 812 | ncm->is_crc = false; |
| 815 | ndp_hdr_crc = NCM_NDP_HDR_NOCRC; | ||
| 816 | DBG(cdev, "non-CRC mode selected\n"); | 813 | DBG(cdev, "non-CRC mode selected\n"); |
| 817 | break; | 814 | break; |
| 818 | case 0x0001: | 815 | case 0x0001: |
| 819 | ncm->is_crc = true; | 816 | ncm->is_crc = true; |
| 820 | ndp_hdr_crc = NCM_NDP_HDR_CRC; | ||
| 821 | DBG(cdev, "CRC mode selected\n"); | 817 | DBG(cdev, "CRC mode selected\n"); |
| 822 | break; | 818 | break; |
| 823 | default: | 819 | default: |
| 824 | goto invalid; | 820 | goto invalid; |
| 825 | } | 821 | } |
| 826 | ncm->ndp_sign = ncm->parser_opts->ndp_sign | ndp_hdr_crc; | ||
| 827 | value = 0; | 822 | value = 0; |
| 828 | break; | 823 | break; |
| 829 | } | 824 | } |
| @@ -840,6 +835,8 @@ invalid: | |||
| 840 | ctrl->bRequestType, ctrl->bRequest, | 835 | ctrl->bRequestType, ctrl->bRequest, |
| 841 | w_value, w_index, w_length); | 836 | w_value, w_index, w_length); |
| 842 | } | 837 | } |
| 838 | ncm->ndp_sign = ncm->parser_opts->ndp_sign | | ||
| 839 | (ncm->is_crc ? NCM_NDP_HDR_CRC : 0); | ||
| 843 | 840 | ||
| 844 | /* respond with data transfer or status phase? */ | 841 | /* respond with data transfer or status phase? */ |
| 845 | if (value >= 0) { | 842 | if (value >= 0) { |
| @@ -1395,6 +1392,16 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) | |||
| 1395 | return -EINVAL; | 1392 | return -EINVAL; |
| 1396 | 1393 | ||
| 1397 | ncm_opts = container_of(f->fi, struct f_ncm_opts, func_inst); | 1394 | ncm_opts = container_of(f->fi, struct f_ncm_opts, func_inst); |
| 1395 | |||
| 1396 | if (cdev->use_os_string) { | ||
| 1397 | f->os_desc_table = kzalloc(sizeof(*f->os_desc_table), | ||
| 1398 | GFP_KERNEL); | ||
| 1399 | if (!f->os_desc_table) | ||
| 1400 | return -ENOMEM; | ||
| 1401 | f->os_desc_n = 1; | ||
| 1402 | f->os_desc_table[0].os_desc = &ncm_opts->ncm_os_desc; | ||
| 1403 | } | ||
| 1404 | |||
| 1398 | /* | 1405 | /* |
| 1399 | * in drivers/usb/gadget/configfs.c:configfs_composite_bind() | 1406 | * in drivers/usb/gadget/configfs.c:configfs_composite_bind() |
| 1400 | * configurations are bound in sequence with list_for_each_entry, | 1407 | * configurations are bound in sequence with list_for_each_entry, |
| @@ -1408,13 +1415,15 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) | |||
| 1408 | status = gether_register_netdev(ncm_opts->net); | 1415 | status = gether_register_netdev(ncm_opts->net); |
| 1409 | mutex_unlock(&ncm_opts->lock); | 1416 | mutex_unlock(&ncm_opts->lock); |
| 1410 | if (status) | 1417 | if (status) |
| 1411 | return status; | 1418 | goto fail; |
| 1412 | ncm_opts->bound = true; | 1419 | ncm_opts->bound = true; |
| 1413 | } | 1420 | } |
| 1414 | us = usb_gstrings_attach(cdev, ncm_strings, | 1421 | us = usb_gstrings_attach(cdev, ncm_strings, |
| 1415 | ARRAY_SIZE(ncm_string_defs)); | 1422 | ARRAY_SIZE(ncm_string_defs)); |
| 1416 | if (IS_ERR(us)) | 1423 | if (IS_ERR(us)) { |
| 1417 | return PTR_ERR(us); | 1424 | status = PTR_ERR(us); |
| 1425 | goto fail; | ||
| 1426 | } | ||
| 1418 | ncm_control_intf.iInterface = us[STRING_CTRL_IDX].id; | 1427 | ncm_control_intf.iInterface = us[STRING_CTRL_IDX].id; |
| 1419 | ncm_data_nop_intf.iInterface = us[STRING_DATA_IDX].id; | 1428 | ncm_data_nop_intf.iInterface = us[STRING_DATA_IDX].id; |
| 1420 | ncm_data_intf.iInterface = us[STRING_DATA_IDX].id; | 1429 | ncm_data_intf.iInterface = us[STRING_DATA_IDX].id; |
| @@ -1431,6 +1440,10 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) | |||
| 1431 | ncm_control_intf.bInterfaceNumber = status; | 1440 | ncm_control_intf.bInterfaceNumber = status; |
| 1432 | ncm_union_desc.bMasterInterface0 = status; | 1441 | ncm_union_desc.bMasterInterface0 = status; |
| 1433 | 1442 | ||
| 1443 | if (cdev->use_os_string) | ||
| 1444 | f->os_desc_table[0].if_id = | ||
| 1445 | ncm_iad_desc.bFirstInterface; | ||
| 1446 | |||
| 1434 | status = usb_interface_id(c, f); | 1447 | status = usb_interface_id(c, f); |
| 1435 | if (status < 0) | 1448 | if (status < 0) |
| 1436 | goto fail; | 1449 | goto fail; |
| @@ -1510,6 +1523,9 @@ static int ncm_bind(struct usb_configuration *c, struct usb_function *f) | |||
| 1510 | return 0; | 1523 | return 0; |
| 1511 | 1524 | ||
| 1512 | fail: | 1525 | fail: |
| 1526 | kfree(f->os_desc_table); | ||
| 1527 | f->os_desc_n = 0; | ||
| 1528 | |||
| 1513 | if (ncm->notify_req) { | 1529 | if (ncm->notify_req) { |
| 1514 | kfree(ncm->notify_req->buf); | 1530 | kfree(ncm->notify_req->buf); |
| 1515 | usb_ep_free_request(ncm->notify, ncm->notify_req); | 1531 | usb_ep_free_request(ncm->notify, ncm->notify_req); |
| @@ -1564,16 +1580,22 @@ static void ncm_free_inst(struct usb_function_instance *f) | |||
| 1564 | gether_cleanup(netdev_priv(opts->net)); | 1580 | gether_cleanup(netdev_priv(opts->net)); |
| 1565 | else | 1581 | else |
| 1566 | free_netdev(opts->net); | 1582 | free_netdev(opts->net); |
| 1583 | kfree(opts->ncm_interf_group); | ||
| 1567 | kfree(opts); | 1584 | kfree(opts); |
| 1568 | } | 1585 | } |
| 1569 | 1586 | ||
| 1570 | static struct usb_function_instance *ncm_alloc_inst(void) | 1587 | static struct usb_function_instance *ncm_alloc_inst(void) |
| 1571 | { | 1588 | { |
| 1572 | struct f_ncm_opts *opts; | 1589 | struct f_ncm_opts *opts; |
| 1590 | struct usb_os_desc *descs[1]; | ||
| 1591 | char *names[1]; | ||
| 1592 | struct config_group *ncm_interf_group; | ||
| 1573 | 1593 | ||
| 1574 | opts = kzalloc(sizeof(*opts), GFP_KERNEL); | 1594 | opts = kzalloc(sizeof(*opts), GFP_KERNEL); |
| 1575 | if (!opts) | 1595 | if (!opts) |
| 1576 | return ERR_PTR(-ENOMEM); | 1596 | return ERR_PTR(-ENOMEM); |
| 1597 | opts->ncm_os_desc.ext_compat_id = opts->ncm_ext_compat_id; | ||
| 1598 | |||
| 1577 | mutex_init(&opts->lock); | 1599 | mutex_init(&opts->lock); |
| 1578 | opts->func_inst.free_func_inst = ncm_free_inst; | 1600 | opts->func_inst.free_func_inst = ncm_free_inst; |
| 1579 | opts->net = gether_setup_default(); | 1601 | opts->net = gether_setup_default(); |
| @@ -1582,8 +1604,20 @@ static struct usb_function_instance *ncm_alloc_inst(void) | |||
| 1582 | kfree(opts); | 1604 | kfree(opts); |
| 1583 | return ERR_CAST(net); | 1605 | return ERR_CAST(net); |
| 1584 | } | 1606 | } |
| 1607 | INIT_LIST_HEAD(&opts->ncm_os_desc.ext_prop); | ||
| 1608 | |||
| 1609 | descs[0] = &opts->ncm_os_desc; | ||
| 1610 | names[0] = "ncm"; | ||
| 1585 | 1611 | ||
| 1586 | config_group_init_type_name(&opts->func_inst.group, "", &ncm_func_type); | 1612 | config_group_init_type_name(&opts->func_inst.group, "", &ncm_func_type); |
| 1613 | ncm_interf_group = | ||
| 1614 | usb_os_desc_prepare_interf_dir(&opts->func_inst.group, 1, descs, | ||
| 1615 | names, THIS_MODULE); | ||
| 1616 | if (IS_ERR(ncm_interf_group)) { | ||
| 1617 | ncm_free_inst(&opts->func_inst); | ||
| 1618 | return ERR_CAST(ncm_interf_group); | ||
| 1619 | } | ||
| 1620 | opts->ncm_interf_group = ncm_interf_group; | ||
| 1587 | 1621 | ||
| 1588 | return &opts->func_inst; | 1622 | return &opts->func_inst; |
| 1589 | } | 1623 | } |
| @@ -1609,6 +1643,9 @@ static void ncm_unbind(struct usb_configuration *c, struct usb_function *f) | |||
| 1609 | 1643 | ||
| 1610 | hrtimer_cancel(&ncm->task_timer); | 1644 | hrtimer_cancel(&ncm->task_timer); |
| 1611 | 1645 | ||
| 1646 | kfree(f->os_desc_table); | ||
| 1647 | f->os_desc_n = 0; | ||
| 1648 | |||
| 1612 | ncm_string_defs[0].id = 0; | 1649 | ncm_string_defs[0].id = 0; |
| 1613 | usb_free_all_descriptors(f); | 1650 | usb_free_all_descriptors(f); |
| 1614 | 1651 | ||
diff --git a/drivers/usb/gadget/function/f_uac1_legacy.c b/drivers/usb/gadget/function/f_uac1_legacy.c index 24c086bcdeaa..6677ae932de0 100644 --- a/drivers/usb/gadget/function/f_uac1_legacy.c +++ b/drivers/usb/gadget/function/f_uac1_legacy.c | |||
| @@ -54,8 +54,8 @@ static struct uac1_ac_header_descriptor_1 ac_header_desc = { | |||
| 54 | .bLength = UAC_DT_AC_HEADER_LENGTH, | 54 | .bLength = UAC_DT_AC_HEADER_LENGTH, |
| 55 | .bDescriptorType = USB_DT_CS_INTERFACE, | 55 | .bDescriptorType = USB_DT_CS_INTERFACE, |
| 56 | .bDescriptorSubtype = UAC_HEADER, | 56 | .bDescriptorSubtype = UAC_HEADER, |
| 57 | .bcdADC = __constant_cpu_to_le16(0x0100), | 57 | .bcdADC = cpu_to_le16(0x0100), |
| 58 | .wTotalLength = __constant_cpu_to_le16(UAC_DT_TOTAL_LENGTH), | 58 | .wTotalLength = cpu_to_le16(UAC_DT_TOTAL_LENGTH), |
| 59 | .bInCollection = F_AUDIO_NUM_INTERFACES, | 59 | .bInCollection = F_AUDIO_NUM_INTERFACES, |
| 60 | .baInterfaceNr = { | 60 | .baInterfaceNr = { |
| 61 | /* Interface number of the first AudioStream interface */ | 61 | /* Interface number of the first AudioStream interface */ |
| @@ -183,7 +183,7 @@ static struct uac_iso_endpoint_descriptor as_iso_out_desc = { | |||
| 183 | .bDescriptorSubtype = UAC_EP_GENERAL, | 183 | .bDescriptorSubtype = UAC_EP_GENERAL, |
| 184 | .bmAttributes = 1, | 184 | .bmAttributes = 1, |
| 185 | .bLockDelayUnits = 1, | 185 | .bLockDelayUnits = 1, |
| 186 | .wLockDelay = __constant_cpu_to_le16(1), | 186 | .wLockDelay = cpu_to_le16(1), |
| 187 | }; | 187 | }; |
| 188 | 188 | ||
| 189 | static struct usb_descriptor_header *f_audio_desc[] = { | 189 | static struct usb_descriptor_header *f_audio_desc[] = { |
diff --git a/drivers/usb/gadget/function/u_ncm.h b/drivers/usb/gadget/function/u_ncm.h index d483e45c0f77..70da3201a1d0 100644 --- a/drivers/usb/gadget/function/u_ncm.h +++ b/drivers/usb/gadget/function/u_ncm.h | |||
| @@ -20,6 +20,9 @@ struct f_ncm_opts { | |||
| 20 | struct net_device *net; | 20 | struct net_device *net; |
| 21 | bool bound; | 21 | bool bound; |
| 22 | 22 | ||
| 23 | struct config_group *ncm_interf_group; | ||
| 24 | struct usb_os_desc ncm_os_desc; | ||
| 25 | char ncm_ext_compat_id[16]; | ||
| 23 | /* | 26 | /* |
| 24 | * Read/write access to configfs attributes is handled by configfs. | 27 | * Read/write access to configfs attributes is handled by configfs. |
| 25 | * | 28 | * |
diff --git a/drivers/usb/gadget/udc/aspeed-vhub/epn.c b/drivers/usb/gadget/udc/aspeed-vhub/epn.c index 83340f4fdc6e..35941dc125f9 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/epn.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/epn.c | |||
| @@ -593,10 +593,6 @@ static int ast_vhub_epn_disable(struct usb_ep* u_ep) | |||
| 593 | static int ast_vhub_epn_enable(struct usb_ep* u_ep, | 593 | static int ast_vhub_epn_enable(struct usb_ep* u_ep, |
| 594 | const struct usb_endpoint_descriptor *desc) | 594 | const struct usb_endpoint_descriptor *desc) |
| 595 | { | 595 | { |
| 596 | static const char *ep_type_string[] __maybe_unused = { "ctrl", | ||
| 597 | "isoc", | ||
| 598 | "bulk", | ||
| 599 | "intr" }; | ||
| 600 | struct ast_vhub_ep *ep = to_ast_ep(u_ep); | 596 | struct ast_vhub_ep *ep = to_ast_ep(u_ep); |
| 601 | struct ast_vhub_dev *dev; | 597 | struct ast_vhub_dev *dev; |
| 602 | struct ast_vhub *vhub; | 598 | struct ast_vhub *vhub; |
| @@ -646,7 +642,7 @@ static int ast_vhub_epn_enable(struct usb_ep* u_ep, | |||
| 646 | ep->epn.wedged = false; | 642 | ep->epn.wedged = false; |
| 647 | 643 | ||
| 648 | EPDBG(ep, "Enabling [%s] %s num %d maxpacket=%d\n", | 644 | EPDBG(ep, "Enabling [%s] %s num %d maxpacket=%d\n", |
| 649 | ep->epn.is_in ? "in" : "out", ep_type_string[type], | 645 | ep->epn.is_in ? "in" : "out", usb_ep_type_string(type), |
| 650 | usb_endpoint_num(desc), maxpacket); | 646 | usb_endpoint_num(desc), maxpacket); |
| 651 | 647 | ||
| 652 | /* Can we use DMA descriptor mode ? */ | 648 | /* Can we use DMA descriptor mode ? */ |
diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index 660712e0bf98..503d275bc4c4 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c | |||
| @@ -358,8 +358,20 @@ static inline u32 usba_int_enb_get(struct usba_udc *udc) | |||
| 358 | return udc->int_enb_cache; | 358 | return udc->int_enb_cache; |
| 359 | } | 359 | } |
| 360 | 360 | ||
| 361 | static inline void usba_int_enb_set(struct usba_udc *udc, u32 val) | 361 | static inline void usba_int_enb_set(struct usba_udc *udc, u32 mask) |
| 362 | { | 362 | { |
| 363 | u32 val; | ||
| 364 | |||
| 365 | val = udc->int_enb_cache | mask; | ||
| 366 | usba_writel(udc, INT_ENB, val); | ||
| 367 | udc->int_enb_cache = val; | ||
| 368 | } | ||
| 369 | |||
| 370 | static inline void usba_int_enb_clear(struct usba_udc *udc, u32 mask) | ||
| 371 | { | ||
| 372 | u32 val; | ||
| 373 | |||
| 374 | val = udc->int_enb_cache & ~mask; | ||
| 363 | usba_writel(udc, INT_ENB, val); | 375 | usba_writel(udc, INT_ENB, val); |
| 364 | udc->int_enb_cache = val; | 376 | udc->int_enb_cache = val; |
| 365 | } | 377 | } |
| @@ -629,14 +641,12 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) | |||
| 629 | if (ep->can_dma) { | 641 | if (ep->can_dma) { |
| 630 | u32 ctrl; | 642 | u32 ctrl; |
| 631 | 643 | ||
| 632 | usba_int_enb_set(udc, usba_int_enb_get(udc) | | 644 | usba_int_enb_set(udc, USBA_BF(EPT_INT, 1 << ep->index) | |
| 633 | USBA_BF(EPT_INT, 1 << ep->index) | | ||
| 634 | USBA_BF(DMA_INT, 1 << ep->index)); | 645 | USBA_BF(DMA_INT, 1 << ep->index)); |
| 635 | ctrl = USBA_AUTO_VALID | USBA_INTDIS_DMA; | 646 | ctrl = USBA_AUTO_VALID | USBA_INTDIS_DMA; |
| 636 | usba_ep_writel(ep, CTL_ENB, ctrl); | 647 | usba_ep_writel(ep, CTL_ENB, ctrl); |
| 637 | } else { | 648 | } else { |
| 638 | usba_int_enb_set(udc, usba_int_enb_get(udc) | | 649 | usba_int_enb_set(udc, USBA_BF(EPT_INT, 1 << ep->index)); |
| 639 | USBA_BF(EPT_INT, 1 << ep->index)); | ||
| 640 | } | 650 | } |
| 641 | 651 | ||
| 642 | spin_unlock_irqrestore(&udc->lock, flags); | 652 | spin_unlock_irqrestore(&udc->lock, flags); |
| @@ -680,8 +690,7 @@ static int usba_ep_disable(struct usb_ep *_ep) | |||
| 680 | usba_dma_readl(ep, STATUS); | 690 | usba_dma_readl(ep, STATUS); |
| 681 | } | 691 | } |
| 682 | usba_ep_writel(ep, CTL_DIS, USBA_EPT_ENABLE); | 692 | usba_ep_writel(ep, CTL_DIS, USBA_EPT_ENABLE); |
| 683 | usba_int_enb_set(udc, usba_int_enb_get(udc) & | 693 | usba_int_enb_clear(udc, USBA_BF(EPT_INT, 1 << ep->index)); |
| 684 | ~USBA_BF(EPT_INT, 1 << ep->index)); | ||
| 685 | 694 | ||
| 686 | request_complete_list(ep, &req_list, -ESHUTDOWN); | 695 | request_complete_list(ep, &req_list, -ESHUTDOWN); |
| 687 | 696 | ||
| @@ -1694,6 +1703,9 @@ static void usba_dma_irq(struct usba_udc *udc, struct usba_ep *ep) | |||
| 1694 | } | 1703 | } |
| 1695 | } | 1704 | } |
| 1696 | 1705 | ||
| 1706 | static int start_clock(struct usba_udc *udc); | ||
| 1707 | static void stop_clock(struct usba_udc *udc); | ||
| 1708 | |||
| 1697 | static irqreturn_t usba_udc_irq(int irq, void *devid) | 1709 | static irqreturn_t usba_udc_irq(int irq, void *devid) |
| 1698 | { | 1710 | { |
| 1699 | struct usba_udc *udc = devid; | 1711 | struct usba_udc *udc = devid; |
| @@ -1708,10 +1720,13 @@ static irqreturn_t usba_udc_irq(int irq, void *devid) | |||
| 1708 | DBG(DBG_INT, "irq, status=%#08x\n", status); | 1720 | DBG(DBG_INT, "irq, status=%#08x\n", status); |
| 1709 | 1721 | ||
| 1710 | if (status & USBA_DET_SUSPEND) { | 1722 | if (status & USBA_DET_SUSPEND) { |
| 1723 | usba_writel(udc, INT_CLR, USBA_DET_SUSPEND|USBA_WAKE_UP); | ||
| 1724 | usba_int_enb_set(udc, USBA_WAKE_UP); | ||
| 1725 | usba_int_enb_clear(udc, USBA_DET_SUSPEND); | ||
| 1726 | udc->suspended = true; | ||
| 1711 | toggle_bias(udc, 0); | 1727 | toggle_bias(udc, 0); |
| 1712 | usba_writel(udc, INT_CLR, USBA_DET_SUSPEND); | ||
| 1713 | usba_int_enb_set(udc, int_enb | USBA_WAKE_UP); | ||
| 1714 | udc->bias_pulse_needed = true; | 1728 | udc->bias_pulse_needed = true; |
| 1729 | stop_clock(udc); | ||
| 1715 | DBG(DBG_BUS, "Suspend detected\n"); | 1730 | DBG(DBG_BUS, "Suspend detected\n"); |
| 1716 | if (udc->gadget.speed != USB_SPEED_UNKNOWN | 1731 | if (udc->gadget.speed != USB_SPEED_UNKNOWN |
| 1717 | && udc->driver && udc->driver->suspend) { | 1732 | && udc->driver && udc->driver->suspend) { |
| @@ -1722,14 +1737,17 @@ static irqreturn_t usba_udc_irq(int irq, void *devid) | |||
| 1722 | } | 1737 | } |
| 1723 | 1738 | ||
| 1724 | if (status & USBA_WAKE_UP) { | 1739 | if (status & USBA_WAKE_UP) { |
| 1740 | start_clock(udc); | ||
| 1725 | toggle_bias(udc, 1); | 1741 | toggle_bias(udc, 1); |
| 1726 | usba_writel(udc, INT_CLR, USBA_WAKE_UP); | 1742 | usba_writel(udc, INT_CLR, USBA_WAKE_UP); |
| 1727 | usba_int_enb_set(udc, int_enb & ~USBA_WAKE_UP); | ||
| 1728 | DBG(DBG_BUS, "Wake Up CPU detected\n"); | 1743 | DBG(DBG_BUS, "Wake Up CPU detected\n"); |
| 1729 | } | 1744 | } |
| 1730 | 1745 | ||
| 1731 | if (status & USBA_END_OF_RESUME) { | 1746 | if (status & USBA_END_OF_RESUME) { |
| 1747 | udc->suspended = false; | ||
| 1732 | usba_writel(udc, INT_CLR, USBA_END_OF_RESUME); | 1748 | usba_writel(udc, INT_CLR, USBA_END_OF_RESUME); |
| 1749 | usba_int_enb_clear(udc, USBA_WAKE_UP); | ||
| 1750 | usba_int_enb_set(udc, USBA_DET_SUSPEND); | ||
| 1733 | generate_bias_pulse(udc); | 1751 | generate_bias_pulse(udc); |
| 1734 | DBG(DBG_BUS, "Resume detected\n"); | 1752 | DBG(DBG_BUS, "Resume detected\n"); |
| 1735 | if (udc->gadget.speed != USB_SPEED_UNKNOWN | 1753 | if (udc->gadget.speed != USB_SPEED_UNKNOWN |
| @@ -1744,6 +1762,8 @@ static irqreturn_t usba_udc_irq(int irq, void *devid) | |||
| 1744 | if (dma_status) { | 1762 | if (dma_status) { |
| 1745 | int i; | 1763 | int i; |
| 1746 | 1764 | ||
| 1765 | usba_int_enb_set(udc, USBA_DET_SUSPEND); | ||
| 1766 | |||
| 1747 | for (i = 1; i <= USBA_NR_DMAS; i++) | 1767 | for (i = 1; i <= USBA_NR_DMAS; i++) |
| 1748 | if (dma_status & (1 << i)) | 1768 | if (dma_status & (1 << i)) |
| 1749 | usba_dma_irq(udc, &udc->usba_ep[i]); | 1769 | usba_dma_irq(udc, &udc->usba_ep[i]); |
| @@ -1753,6 +1773,8 @@ static irqreturn_t usba_udc_irq(int irq, void *devid) | |||
| 1753 | if (ep_status) { | 1773 | if (ep_status) { |
| 1754 | int i; | 1774 | int i; |
| 1755 | 1775 | ||
| 1776 | usba_int_enb_set(udc, USBA_DET_SUSPEND); | ||
| 1777 | |||
| 1756 | for (i = 0; i < udc->num_ep; i++) | 1778 | for (i = 0; i < udc->num_ep; i++) |
| 1757 | if (ep_status & (1 << i)) { | 1779 | if (ep_status & (1 << i)) { |
| 1758 | if (ep_is_control(&udc->usba_ep[i])) | 1780 | if (ep_is_control(&udc->usba_ep[i])) |
| @@ -1766,7 +1788,9 @@ static irqreturn_t usba_udc_irq(int irq, void *devid) | |||
| 1766 | struct usba_ep *ep0, *ep; | 1788 | struct usba_ep *ep0, *ep; |
| 1767 | int i, n; | 1789 | int i, n; |
| 1768 | 1790 | ||
| 1769 | usba_writel(udc, INT_CLR, USBA_END_OF_RESET); | 1791 | usba_writel(udc, INT_CLR, |
| 1792 | USBA_END_OF_RESET|USBA_END_OF_RESUME | ||
| 1793 | |USBA_DET_SUSPEND|USBA_WAKE_UP); | ||
| 1770 | generate_bias_pulse(udc); | 1794 | generate_bias_pulse(udc); |
| 1771 | reset_all_endpoints(udc); | 1795 | reset_all_endpoints(udc); |
| 1772 | 1796 | ||
| @@ -1793,7 +1817,12 @@ static irqreturn_t usba_udc_irq(int irq, void *devid) | |||
| 1793 | | USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE))); | 1817 | | USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE))); |
| 1794 | usba_ep_writel(ep0, CTL_ENB, | 1818 | usba_ep_writel(ep0, CTL_ENB, |
| 1795 | USBA_EPT_ENABLE | USBA_RX_SETUP); | 1819 | USBA_EPT_ENABLE | USBA_RX_SETUP); |
| 1796 | usba_int_enb_set(udc, int_enb | USBA_BF(EPT_INT, 1) | | 1820 | |
| 1821 | /* If we get reset while suspended... */ | ||
| 1822 | udc->suspended = false; | ||
| 1823 | usba_int_enb_clear(udc, USBA_WAKE_UP); | ||
| 1824 | |||
| 1825 | usba_int_enb_set(udc, USBA_BF(EPT_INT, 1) | | ||
| 1797 | USBA_DET_SUSPEND | USBA_END_OF_RESUME); | 1826 | USBA_DET_SUSPEND | USBA_END_OF_RESUME); |
| 1798 | 1827 | ||
| 1799 | /* | 1828 | /* |
| @@ -1827,6 +1856,8 @@ static int start_clock(struct usba_udc *udc) | |||
| 1827 | if (udc->clocked) | 1856 | if (udc->clocked) |
| 1828 | return 0; | 1857 | return 0; |
| 1829 | 1858 | ||
| 1859 | pm_stay_awake(&udc->pdev->dev); | ||
| 1860 | |||
| 1830 | ret = clk_prepare_enable(udc->pclk); | 1861 | ret = clk_prepare_enable(udc->pclk); |
| 1831 | if (ret) | 1862 | if (ret) |
| 1832 | return ret; | 1863 | return ret; |
| @@ -1849,6 +1880,8 @@ static void stop_clock(struct usba_udc *udc) | |||
| 1849 | clk_disable_unprepare(udc->pclk); | 1880 | clk_disable_unprepare(udc->pclk); |
| 1850 | 1881 | ||
| 1851 | udc->clocked = false; | 1882 | udc->clocked = false; |
| 1883 | |||
| 1884 | pm_relax(&udc->pdev->dev); | ||
| 1852 | } | 1885 | } |
| 1853 | 1886 | ||
| 1854 | static int usba_start(struct usba_udc *udc) | 1887 | static int usba_start(struct usba_udc *udc) |
| @@ -1860,9 +1893,19 @@ static int usba_start(struct usba_udc *udc) | |||
| 1860 | if (ret) | 1893 | if (ret) |
| 1861 | return ret; | 1894 | return ret; |
| 1862 | 1895 | ||
| 1896 | if (udc->suspended) | ||
| 1897 | return 0; | ||
| 1898 | |||
| 1863 | spin_lock_irqsave(&udc->lock, flags); | 1899 | spin_lock_irqsave(&udc->lock, flags); |
| 1864 | toggle_bias(udc, 1); | 1900 | toggle_bias(udc, 1); |
| 1865 | usba_writel(udc, CTRL, USBA_ENABLE_MASK); | 1901 | usba_writel(udc, CTRL, USBA_ENABLE_MASK); |
| 1902 | /* Clear all requested and pending interrupts... */ | ||
| 1903 | usba_writel(udc, INT_ENB, 0); | ||
| 1904 | udc->int_enb_cache = 0; | ||
| 1905 | usba_writel(udc, INT_CLR, | ||
| 1906 | USBA_END_OF_RESET|USBA_END_OF_RESUME | ||
| 1907 | |USBA_DET_SUSPEND|USBA_WAKE_UP); | ||
| 1908 | /* ...and enable just 'reset' IRQ to get us started */ | ||
| 1866 | usba_int_enb_set(udc, USBA_END_OF_RESET); | 1909 | usba_int_enb_set(udc, USBA_END_OF_RESET); |
| 1867 | spin_unlock_irqrestore(&udc->lock, flags); | 1910 | spin_unlock_irqrestore(&udc->lock, flags); |
| 1868 | 1911 | ||
| @@ -1873,6 +1916,9 @@ static void usba_stop(struct usba_udc *udc) | |||
| 1873 | { | 1916 | { |
| 1874 | unsigned long flags; | 1917 | unsigned long flags; |
| 1875 | 1918 | ||
| 1919 | if (udc->suspended) | ||
| 1920 | return; | ||
| 1921 | |||
| 1876 | spin_lock_irqsave(&udc->lock, flags); | 1922 | spin_lock_irqsave(&udc->lock, flags); |
| 1877 | udc->gadget.speed = USB_SPEED_UNKNOWN; | 1923 | udc->gadget.speed = USB_SPEED_UNKNOWN; |
| 1878 | reset_all_endpoints(udc); | 1924 | reset_all_endpoints(udc); |
| @@ -1900,6 +1946,7 @@ static irqreturn_t usba_vbus_irq_thread(int irq, void *devid) | |||
| 1900 | if (vbus) { | 1946 | if (vbus) { |
| 1901 | usba_start(udc); | 1947 | usba_start(udc); |
| 1902 | } else { | 1948 | } else { |
| 1949 | udc->suspended = false; | ||
| 1903 | usba_stop(udc); | 1950 | usba_stop(udc); |
| 1904 | 1951 | ||
| 1905 | if (udc->driver->disconnect) | 1952 | if (udc->driver->disconnect) |
| @@ -1963,6 +2010,7 @@ static int atmel_usba_stop(struct usb_gadget *gadget) | |||
| 1963 | if (fifo_mode == 0) | 2010 | if (fifo_mode == 0) |
| 1964 | udc->configured_ep = 1; | 2011 | udc->configured_ep = 1; |
| 1965 | 2012 | ||
| 2013 | udc->suspended = false; | ||
| 1966 | usba_stop(udc); | 2014 | usba_stop(udc); |
| 1967 | 2015 | ||
| 1968 | udc->driver = NULL; | 2016 | udc->driver = NULL; |
| @@ -2276,6 +2324,7 @@ static int usba_udc_suspend(struct device *dev) | |||
| 2276 | mutex_lock(&udc->vbus_mutex); | 2324 | mutex_lock(&udc->vbus_mutex); |
| 2277 | 2325 | ||
| 2278 | if (!device_may_wakeup(dev)) { | 2326 | if (!device_may_wakeup(dev)) { |
| 2327 | udc->suspended = false; | ||
| 2279 | usba_stop(udc); | 2328 | usba_stop(udc); |
| 2280 | goto out; | 2329 | goto out; |
| 2281 | } | 2330 | } |
| @@ -2285,10 +2334,13 @@ static int usba_udc_suspend(struct device *dev) | |||
| 2285 | * to request vbus irq, assuming always on. | 2334 | * to request vbus irq, assuming always on. |
| 2286 | */ | 2335 | */ |
| 2287 | if (udc->vbus_pin) { | 2336 | if (udc->vbus_pin) { |
| 2337 | /* FIXME: right to stop here...??? */ | ||
| 2288 | usba_stop(udc); | 2338 | usba_stop(udc); |
| 2289 | enable_irq_wake(gpiod_to_irq(udc->vbus_pin)); | 2339 | enable_irq_wake(gpiod_to_irq(udc->vbus_pin)); |
| 2290 | } | 2340 | } |
| 2291 | 2341 | ||
| 2342 | enable_irq_wake(udc->irq); | ||
| 2343 | |||
| 2292 | out: | 2344 | out: |
| 2293 | mutex_unlock(&udc->vbus_mutex); | 2345 | mutex_unlock(&udc->vbus_mutex); |
| 2294 | return 0; | 2346 | return 0; |
| @@ -2302,8 +2354,12 @@ static int usba_udc_resume(struct device *dev) | |||
| 2302 | if (!udc->driver) | 2354 | if (!udc->driver) |
| 2303 | return 0; | 2355 | return 0; |
| 2304 | 2356 | ||
| 2305 | if (device_may_wakeup(dev) && udc->vbus_pin) | 2357 | if (device_may_wakeup(dev)) { |
| 2306 | disable_irq_wake(gpiod_to_irq(udc->vbus_pin)); | 2358 | if (udc->vbus_pin) |
| 2359 | disable_irq_wake(gpiod_to_irq(udc->vbus_pin)); | ||
| 2360 | |||
| 2361 | disable_irq_wake(udc->irq); | ||
| 2362 | } | ||
| 2307 | 2363 | ||
| 2308 | /* If Vbus is present, enable the controller and wait for reset */ | 2364 | /* If Vbus is present, enable the controller and wait for reset */ |
| 2309 | mutex_lock(&udc->vbus_mutex); | 2365 | mutex_lock(&udc->vbus_mutex); |
diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.h b/drivers/usb/gadget/udc/atmel_usba_udc.h index 030bf797cd25..a0225e4543d4 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.h +++ b/drivers/usb/gadget/udc/atmel_usba_udc.h | |||
| @@ -331,6 +331,7 @@ struct usba_udc { | |||
| 331 | struct usba_ep *usba_ep; | 331 | struct usba_ep *usba_ep; |
| 332 | bool bias_pulse_needed; | 332 | bool bias_pulse_needed; |
| 333 | bool clocked; | 333 | bool clocked; |
| 334 | bool suspended; | ||
| 334 | 335 | ||
| 335 | u16 devstatus; | 336 | u16 devstatus; |
| 336 | 337 | ||
diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c index 213b52508621..8414fac74493 100644 --- a/drivers/usb/gadget/udc/dummy_hcd.c +++ b/drivers/usb/gadget/udc/dummy_hcd.c | |||
| @@ -617,21 +617,7 @@ static int dummy_enable(struct usb_ep *_ep, | |||
| 617 | _ep->name, | 617 | _ep->name, |
| 618 | desc->bEndpointAddress & 0x0f, | 618 | desc->bEndpointAddress & 0x0f, |
| 619 | (desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out", | 619 | (desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out", |
| 620 | ({ char *val; | 620 | usb_ep_type_string(usb_endpoint_type(desc)), |
| 621 | switch (usb_endpoint_type(desc)) { | ||
| 622 | case USB_ENDPOINT_XFER_BULK: | ||
| 623 | val = "bulk"; | ||
| 624 | break; | ||
| 625 | case USB_ENDPOINT_XFER_ISOC: | ||
| 626 | val = "iso"; | ||
| 627 | break; | ||
| 628 | case USB_ENDPOINT_XFER_INT: | ||
| 629 | val = "intr"; | ||
| 630 | break; | ||
| 631 | default: | ||
| 632 | val = "ctrl"; | ||
| 633 | break; | ||
| 634 | } val; }), | ||
| 635 | max, ep->stream_en ? "enabled" : "disabled"); | 621 | max, ep->stream_en ? "enabled" : "disabled"); |
| 636 | 622 | ||
| 637 | /* at this point real hardware should be NAKing transfers | 623 | /* at this point real hardware should be NAKing transfers |
diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c index b0781771704e..d8f1c60793ed 100644 --- a/drivers/usb/gadget/udc/lpc32xx_udc.c +++ b/drivers/usb/gadget/udc/lpc32xx_udc.c | |||
| @@ -115,6 +115,11 @@ struct lpc32xx_ep { | |||
| 115 | bool wedge; | 115 | bool wedge; |
| 116 | }; | 116 | }; |
| 117 | 117 | ||
| 118 | enum atx_type { | ||
| 119 | ISP1301, | ||
| 120 | STOTG04, | ||
| 121 | }; | ||
| 122 | |||
| 118 | /* | 123 | /* |
| 119 | * Common UDC structure | 124 | * Common UDC structure |
| 120 | */ | 125 | */ |
| @@ -129,8 +134,6 @@ struct lpc32xx_udc { | |||
| 129 | 134 | ||
| 130 | /* Board and device specific */ | 135 | /* Board and device specific */ |
| 131 | struct lpc32xx_usbd_cfg *board; | 136 | struct lpc32xx_usbd_cfg *board; |
| 132 | u32 io_p_start; | ||
| 133 | u32 io_p_size; | ||
| 134 | void __iomem *udp_baseaddr; | 137 | void __iomem *udp_baseaddr; |
| 135 | int udp_irq[4]; | 138 | int udp_irq[4]; |
| 136 | struct clk *usb_slv_clk; | 139 | struct clk *usb_slv_clk; |
| @@ -151,10 +154,10 @@ struct lpc32xx_udc { | |||
| 151 | u8 last_vbus; | 154 | u8 last_vbus; |
| 152 | int pullup; | 155 | int pullup; |
| 153 | int poweron; | 156 | int poweron; |
| 157 | enum atx_type atx; | ||
| 154 | 158 | ||
| 155 | /* Work queues related to I2C support */ | 159 | /* Work queues related to I2C support */ |
| 156 | struct work_struct pullup_job; | 160 | struct work_struct pullup_job; |
| 157 | struct work_struct vbus_job; | ||
| 158 | struct work_struct power_job; | 161 | struct work_struct power_job; |
| 159 | 162 | ||
| 160 | /* USB device peripheral - various */ | 163 | /* USB device peripheral - various */ |
| @@ -553,6 +556,15 @@ static inline void remove_debug_file(struct lpc32xx_udc *udc) {} | |||
| 553 | /* Primary initialization sequence for the ISP1301 transceiver */ | 556 | /* Primary initialization sequence for the ISP1301 transceiver */ |
| 554 | static void isp1301_udc_configure(struct lpc32xx_udc *udc) | 557 | static void isp1301_udc_configure(struct lpc32xx_udc *udc) |
| 555 | { | 558 | { |
| 559 | u8 value; | ||
| 560 | s32 vendor, product; | ||
| 561 | |||
| 562 | vendor = i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x00); | ||
| 563 | product = i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x02); | ||
| 564 | |||
| 565 | if (vendor == 0x0483 && product == 0xa0c4) | ||
| 566 | udc->atx = STOTG04; | ||
| 567 | |||
| 556 | /* LPC32XX only supports DAT_SE0 USB mode */ | 568 | /* LPC32XX only supports DAT_SE0 USB mode */ |
| 557 | /* This sequence is important */ | 569 | /* This sequence is important */ |
| 558 | 570 | ||
| @@ -572,8 +584,12 @@ static void isp1301_udc_configure(struct lpc32xx_udc *udc) | |||
| 572 | */ | 584 | */ |
| 573 | i2c_smbus_write_byte_data(udc->isp1301_i2c_client, | 585 | i2c_smbus_write_byte_data(udc->isp1301_i2c_client, |
| 574 | (ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR), ~0); | 586 | (ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR), ~0); |
| 587 | |||
| 588 | value = MC2_BI_DI; | ||
| 589 | if (udc->atx != STOTG04) | ||
| 590 | value |= MC2_SPD_SUSP_CTRL; | ||
| 575 | i2c_smbus_write_byte_data(udc->isp1301_i2c_client, | 591 | i2c_smbus_write_byte_data(udc->isp1301_i2c_client, |
| 576 | ISP1301_I2C_MODE_CONTROL_2, (MC2_BI_DI | MC2_SPD_SUSP_CTRL)); | 592 | ISP1301_I2C_MODE_CONTROL_2, value); |
| 577 | 593 | ||
| 578 | /* Driver VBUS_DRV high or low depending on board setup */ | 594 | /* Driver VBUS_DRV high or low depending on board setup */ |
| 579 | if (udc->board->vbus_drv_pol != 0) | 595 | if (udc->board->vbus_drv_pol != 0) |
| @@ -601,24 +617,19 @@ static void isp1301_udc_configure(struct lpc32xx_udc *udc) | |||
| 601 | (ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR), | 617 | (ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR), |
| 602 | OTG1_VBUS_DISCHRG); | 618 | OTG1_VBUS_DISCHRG); |
| 603 | 619 | ||
| 604 | /* Clear and enable VBUS high edge interrupt */ | ||
| 605 | i2c_smbus_write_byte_data(udc->isp1301_i2c_client, | 620 | i2c_smbus_write_byte_data(udc->isp1301_i2c_client, |
| 606 | ISP1301_I2C_INTERRUPT_LATCH | ISP1301_I2C_REG_CLEAR_ADDR, ~0); | 621 | ISP1301_I2C_INTERRUPT_LATCH | ISP1301_I2C_REG_CLEAR_ADDR, ~0); |
| 622 | |||
| 607 | i2c_smbus_write_byte_data(udc->isp1301_i2c_client, | 623 | i2c_smbus_write_byte_data(udc->isp1301_i2c_client, |
| 608 | ISP1301_I2C_INTERRUPT_FALLING | ISP1301_I2C_REG_CLEAR_ADDR, ~0); | 624 | ISP1301_I2C_INTERRUPT_FALLING | ISP1301_I2C_REG_CLEAR_ADDR, ~0); |
| 609 | i2c_smbus_write_byte_data(udc->isp1301_i2c_client, | 625 | i2c_smbus_write_byte_data(udc->isp1301_i2c_client, |
| 610 | ISP1301_I2C_INTERRUPT_FALLING, INT_VBUS_VLD); | ||
| 611 | i2c_smbus_write_byte_data(udc->isp1301_i2c_client, | ||
| 612 | ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR, ~0); | 626 | ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR, ~0); |
| 613 | i2c_smbus_write_byte_data(udc->isp1301_i2c_client, | ||
| 614 | ISP1301_I2C_INTERRUPT_RISING, INT_VBUS_VLD); | ||
| 615 | 627 | ||
| 616 | dev_info(udc->dev, "ISP1301 Vendor ID : 0x%04x\n", | 628 | dev_info(udc->dev, "ISP1301 Vendor ID : 0x%04x\n", vendor); |
| 617 | i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x00)); | 629 | dev_info(udc->dev, "ISP1301 Product ID : 0x%04x\n", product); |
| 618 | dev_info(udc->dev, "ISP1301 Product ID : 0x%04x\n", | ||
| 619 | i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x02)); | ||
| 620 | dev_info(udc->dev, "ISP1301 Version ID : 0x%04x\n", | 630 | dev_info(udc->dev, "ISP1301 Version ID : 0x%04x\n", |
| 621 | i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x14)); | 631 | i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x14)); |
| 632 | |||
| 622 | } | 633 | } |
| 623 | 634 | ||
| 624 | /* Enables or disables the USB device pullup via the ISP1301 transceiver */ | 635 | /* Enables or disables the USB device pullup via the ISP1301 transceiver */ |
| @@ -661,6 +672,10 @@ static void isp1301_pullup_enable(struct lpc32xx_udc *udc, int en_pullup, | |||
| 661 | /* Powers up or down the ISP1301 transceiver */ | 672 | /* Powers up or down the ISP1301 transceiver */ |
| 662 | static void isp1301_set_powerstate(struct lpc32xx_udc *udc, int enable) | 673 | static void isp1301_set_powerstate(struct lpc32xx_udc *udc, int enable) |
| 663 | { | 674 | { |
| 675 | /* There is no "global power down" register for stotg04 */ | ||
| 676 | if (udc->atx == STOTG04) | ||
| 677 | return; | ||
| 678 | |||
| 664 | if (enable != 0) | 679 | if (enable != 0) |
| 665 | /* Power up ISP1301 - this ISP1301 will automatically wakeup | 680 | /* Power up ISP1301 - this ISP1301 will automatically wakeup |
| 666 | when VBUS is detected */ | 681 | when VBUS is detected */ |
| @@ -2830,11 +2845,9 @@ static irqreturn_t lpc32xx_usb_devdma_irq(int irq, void *_udc) | |||
| 2830 | * VBUS detection, pullup handler, and Gadget cable state notification | 2845 | * VBUS detection, pullup handler, and Gadget cable state notification |
| 2831 | * | 2846 | * |
| 2832 | */ | 2847 | */ |
| 2833 | static void vbus_work(struct work_struct *work) | 2848 | static void vbus_work(struct lpc32xx_udc *udc) |
| 2834 | { | 2849 | { |
| 2835 | u8 value; | 2850 | u8 value; |
| 2836 | struct lpc32xx_udc *udc = container_of(work, struct lpc32xx_udc, | ||
| 2837 | vbus_job); | ||
| 2838 | 2851 | ||
| 2839 | if (udc->enabled != 0) { | 2852 | if (udc->enabled != 0) { |
| 2840 | /* Discharge VBUS real quick */ | 2853 | /* Discharge VBUS real quick */ |
| @@ -2870,18 +2883,13 @@ static void vbus_work(struct work_struct *work) | |||
| 2870 | lpc32xx_vbus_session(&udc->gadget, udc->vbus); | 2883 | lpc32xx_vbus_session(&udc->gadget, udc->vbus); |
| 2871 | } | 2884 | } |
| 2872 | } | 2885 | } |
| 2873 | |||
| 2874 | /* Re-enable after completion */ | ||
| 2875 | enable_irq(udc->udp_irq[IRQ_USB_ATX]); | ||
| 2876 | } | 2886 | } |
| 2877 | 2887 | ||
| 2878 | static irqreturn_t lpc32xx_usb_vbus_irq(int irq, void *_udc) | 2888 | static irqreturn_t lpc32xx_usb_vbus_irq(int irq, void *_udc) |
| 2879 | { | 2889 | { |
| 2880 | struct lpc32xx_udc *udc = _udc; | 2890 | struct lpc32xx_udc *udc = _udc; |
| 2881 | 2891 | ||
| 2882 | /* Defer handling of VBUS IRQ to work queue */ | 2892 | vbus_work(udc); |
| 2883 | disable_irq_nosync(udc->udp_irq[IRQ_USB_ATX]); | ||
| 2884 | schedule_work(&udc->vbus_job); | ||
| 2885 | 2893 | ||
| 2886 | return IRQ_HANDLED; | 2894 | return IRQ_HANDLED; |
| 2887 | } | 2895 | } |
| @@ -2890,7 +2898,6 @@ static int lpc32xx_start(struct usb_gadget *gadget, | |||
| 2890 | struct usb_gadget_driver *driver) | 2898 | struct usb_gadget_driver *driver) |
| 2891 | { | 2899 | { |
| 2892 | struct lpc32xx_udc *udc = to_udc(gadget); | 2900 | struct lpc32xx_udc *udc = to_udc(gadget); |
| 2893 | int i; | ||
| 2894 | 2901 | ||
| 2895 | if (!driver || driver->max_speed < USB_SPEED_FULL || !driver->setup) { | 2902 | if (!driver || driver->max_speed < USB_SPEED_FULL || !driver->setup) { |
| 2896 | dev_err(udc->dev, "bad parameter.\n"); | 2903 | dev_err(udc->dev, "bad parameter.\n"); |
| @@ -2910,22 +2917,25 @@ static int lpc32xx_start(struct usb_gadget *gadget, | |||
| 2910 | 2917 | ||
| 2911 | /* Force VBUS process once to check for cable insertion */ | 2918 | /* Force VBUS process once to check for cable insertion */ |
| 2912 | udc->last_vbus = udc->vbus = 0; | 2919 | udc->last_vbus = udc->vbus = 0; |
| 2913 | schedule_work(&udc->vbus_job); | 2920 | vbus_work(udc); |
| 2914 | 2921 | ||
| 2915 | /* Do not re-enable ATX IRQ (3) */ | 2922 | /* enable interrupts */ |
| 2916 | for (i = IRQ_USB_LP; i < IRQ_USB_ATX; i++) | 2923 | i2c_smbus_write_byte_data(udc->isp1301_i2c_client, |
| 2917 | enable_irq(udc->udp_irq[i]); | 2924 | ISP1301_I2C_INTERRUPT_FALLING, INT_SESS_VLD | INT_VBUS_VLD); |
| 2925 | i2c_smbus_write_byte_data(udc->isp1301_i2c_client, | ||
| 2926 | ISP1301_I2C_INTERRUPT_RISING, INT_SESS_VLD | INT_VBUS_VLD); | ||
| 2918 | 2927 | ||
| 2919 | return 0; | 2928 | return 0; |
| 2920 | } | 2929 | } |
| 2921 | 2930 | ||
| 2922 | static int lpc32xx_stop(struct usb_gadget *gadget) | 2931 | static int lpc32xx_stop(struct usb_gadget *gadget) |
| 2923 | { | 2932 | { |
| 2924 | int i; | ||
| 2925 | struct lpc32xx_udc *udc = to_udc(gadget); | 2933 | struct lpc32xx_udc *udc = to_udc(gadget); |
| 2926 | 2934 | ||
| 2927 | for (i = IRQ_USB_LP; i <= IRQ_USB_ATX; i++) | 2935 | i2c_smbus_write_byte_data(udc->isp1301_i2c_client, |
| 2928 | disable_irq(udc->udp_irq[i]); | 2936 | ISP1301_I2C_INTERRUPT_FALLING | ISP1301_I2C_REG_CLEAR_ADDR, ~0); |
| 2937 | i2c_smbus_write_byte_data(udc->isp1301_i2c_client, | ||
| 2938 | ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR, ~0); | ||
| 2929 | 2939 | ||
| 2930 | if (udc->clocked) { | 2940 | if (udc->clocked) { |
| 2931 | spin_lock(&udc->lock); | 2941 | spin_lock(&udc->lock); |
| @@ -2999,7 +3009,7 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) | |||
| 2999 | dma_addr_t dma_handle; | 3009 | dma_addr_t dma_handle; |
| 3000 | struct device_node *isp1301_node; | 3010 | struct device_node *isp1301_node; |
| 3001 | 3011 | ||
| 3002 | udc = kmemdup(&controller_template, sizeof(*udc), GFP_KERNEL); | 3012 | udc = devm_kmemdup(dev, &controller_template, sizeof(*udc), GFP_KERNEL); |
| 3003 | if (!udc) | 3013 | if (!udc) |
| 3004 | return -ENOMEM; | 3014 | return -ENOMEM; |
| 3005 | 3015 | ||
| @@ -3022,8 +3032,7 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) | |||
| 3022 | 3032 | ||
| 3023 | udc->isp1301_i2c_client = isp1301_get_client(isp1301_node); | 3033 | udc->isp1301_i2c_client = isp1301_get_client(isp1301_node); |
| 3024 | if (!udc->isp1301_i2c_client) { | 3034 | if (!udc->isp1301_i2c_client) { |
| 3025 | retval = -EPROBE_DEFER; | 3035 | return -EPROBE_DEFER; |
| 3026 | goto phy_fail; | ||
| 3027 | } | 3036 | } |
| 3028 | 3037 | ||
| 3029 | dev_info(udc->dev, "ISP1301 I2C device at address 0x%x\n", | 3038 | dev_info(udc->dev, "ISP1301 I2C device at address 0x%x\n", |
| @@ -3032,7 +3041,7 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) | |||
| 3032 | pdev->dev.dma_mask = &lpc32xx_usbd_dmamask; | 3041 | pdev->dev.dma_mask = &lpc32xx_usbd_dmamask; |
| 3033 | retval = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); | 3042 | retval = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); |
| 3034 | if (retval) | 3043 | if (retval) |
| 3035 | goto resource_fail; | 3044 | return retval; |
| 3036 | 3045 | ||
| 3037 | udc->board = &lpc32xx_usbddata; | 3046 | udc->board = &lpc32xx_usbddata; |
| 3038 | 3047 | ||
| @@ -3045,10 +3054,8 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) | |||
| 3045 | * IORESOURCE_IRQ, USB transceiver interrupt number | 3054 | * IORESOURCE_IRQ, USB transceiver interrupt number |
| 3046 | */ | 3055 | */ |
| 3047 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 3056 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 3048 | if (!res) { | 3057 | if (!res) |
| 3049 | retval = -ENXIO; | 3058 | return -ENXIO; |
| 3050 | goto resource_fail; | ||
| 3051 | } | ||
| 3052 | 3059 | ||
| 3053 | spin_lock_init(&udc->lock); | 3060 | spin_lock_init(&udc->lock); |
| 3054 | 3061 | ||
| @@ -3058,45 +3065,33 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) | |||
| 3058 | if (udc->udp_irq[i] < 0) { | 3065 | if (udc->udp_irq[i] < 0) { |
| 3059 | dev_err(udc->dev, | 3066 | dev_err(udc->dev, |
| 3060 | "irq resource %d not available!\n", i); | 3067 | "irq resource %d not available!\n", i); |
| 3061 | retval = udc->udp_irq[i]; | 3068 | return udc->udp_irq[i]; |
| 3062 | goto irq_fail; | ||
| 3063 | } | 3069 | } |
| 3064 | } | 3070 | } |
| 3065 | 3071 | ||
| 3066 | udc->io_p_start = res->start; | 3072 | udc->udp_baseaddr = devm_ioremap_resource(dev, res); |
| 3067 | udc->io_p_size = resource_size(res); | ||
| 3068 | if (!request_mem_region(udc->io_p_start, udc->io_p_size, driver_name)) { | ||
| 3069 | dev_err(udc->dev, "someone's using UDC memory\n"); | ||
| 3070 | retval = -EBUSY; | ||
| 3071 | goto request_mem_region_fail; | ||
| 3072 | } | ||
| 3073 | |||
| 3074 | udc->udp_baseaddr = ioremap(udc->io_p_start, udc->io_p_size); | ||
| 3075 | if (!udc->udp_baseaddr) { | 3073 | if (!udc->udp_baseaddr) { |
| 3076 | retval = -ENOMEM; | ||
| 3077 | dev_err(udc->dev, "IO map failure\n"); | 3074 | dev_err(udc->dev, "IO map failure\n"); |
| 3078 | goto io_map_fail; | 3075 | return -ENOMEM; |
| 3079 | } | 3076 | } |
| 3080 | 3077 | ||
| 3081 | /* Get USB device clock */ | 3078 | /* Get USB device clock */ |
| 3082 | udc->usb_slv_clk = clk_get(&pdev->dev, NULL); | 3079 | udc->usb_slv_clk = devm_clk_get(&pdev->dev, NULL); |
| 3083 | if (IS_ERR(udc->usb_slv_clk)) { | 3080 | if (IS_ERR(udc->usb_slv_clk)) { |
| 3084 | dev_err(udc->dev, "failed to acquire USB device clock\n"); | 3081 | dev_err(udc->dev, "failed to acquire USB device clock\n"); |
| 3085 | retval = PTR_ERR(udc->usb_slv_clk); | 3082 | return PTR_ERR(udc->usb_slv_clk); |
| 3086 | goto usb_clk_get_fail; | ||
| 3087 | } | 3083 | } |
| 3088 | 3084 | ||
| 3089 | /* Enable USB device clock */ | 3085 | /* Enable USB device clock */ |
| 3090 | retval = clk_prepare_enable(udc->usb_slv_clk); | 3086 | retval = clk_prepare_enable(udc->usb_slv_clk); |
| 3091 | if (retval < 0) { | 3087 | if (retval < 0) { |
| 3092 | dev_err(udc->dev, "failed to start USB device clock\n"); | 3088 | dev_err(udc->dev, "failed to start USB device clock\n"); |
| 3093 | goto usb_clk_enable_fail; | 3089 | return retval; |
| 3094 | } | 3090 | } |
| 3095 | 3091 | ||
| 3096 | /* Setup deferred workqueue data */ | 3092 | /* Setup deferred workqueue data */ |
| 3097 | udc->poweron = udc->pullup = 0; | 3093 | udc->poweron = udc->pullup = 0; |
| 3098 | INIT_WORK(&udc->pullup_job, pullup_work); | 3094 | INIT_WORK(&udc->pullup_job, pullup_work); |
| 3099 | INIT_WORK(&udc->vbus_job, vbus_work); | ||
| 3100 | #ifdef CONFIG_PM | 3095 | #ifdef CONFIG_PM |
| 3101 | INIT_WORK(&udc->power_job, power_work); | 3096 | INIT_WORK(&udc->power_job, power_work); |
| 3102 | #endif | 3097 | #endif |
| @@ -3134,47 +3129,44 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) | |||
| 3134 | 3129 | ||
| 3135 | /* Request IRQs - low and high priority USB device IRQs are routed to | 3130 | /* Request IRQs - low and high priority USB device IRQs are routed to |
| 3136 | * the same handler, while the DMA interrupt is routed elsewhere */ | 3131 | * the same handler, while the DMA interrupt is routed elsewhere */ |
| 3137 | retval = request_irq(udc->udp_irq[IRQ_USB_LP], lpc32xx_usb_lp_irq, | 3132 | retval = devm_request_irq(dev, udc->udp_irq[IRQ_USB_LP], |
| 3138 | 0, "udc_lp", udc); | 3133 | lpc32xx_usb_lp_irq, 0, "udc_lp", udc); |
| 3139 | if (retval < 0) { | 3134 | if (retval < 0) { |
| 3140 | dev_err(udc->dev, "LP request irq %d failed\n", | 3135 | dev_err(udc->dev, "LP request irq %d failed\n", |
| 3141 | udc->udp_irq[IRQ_USB_LP]); | 3136 | udc->udp_irq[IRQ_USB_LP]); |
| 3142 | goto irq_lp_fail; | 3137 | goto irq_req_fail; |
| 3143 | } | 3138 | } |
| 3144 | retval = request_irq(udc->udp_irq[IRQ_USB_HP], lpc32xx_usb_hp_irq, | 3139 | retval = devm_request_irq(dev, udc->udp_irq[IRQ_USB_HP], |
| 3145 | 0, "udc_hp", udc); | 3140 | lpc32xx_usb_hp_irq, 0, "udc_hp", udc); |
| 3146 | if (retval < 0) { | 3141 | if (retval < 0) { |
| 3147 | dev_err(udc->dev, "HP request irq %d failed\n", | 3142 | dev_err(udc->dev, "HP request irq %d failed\n", |
| 3148 | udc->udp_irq[IRQ_USB_HP]); | 3143 | udc->udp_irq[IRQ_USB_HP]); |
| 3149 | goto irq_hp_fail; | 3144 | goto irq_req_fail; |
| 3150 | } | 3145 | } |
| 3151 | 3146 | ||
| 3152 | retval = request_irq(udc->udp_irq[IRQ_USB_DEVDMA], | 3147 | retval = devm_request_irq(dev, udc->udp_irq[IRQ_USB_DEVDMA], |
| 3153 | lpc32xx_usb_devdma_irq, 0, "udc_dma", udc); | 3148 | lpc32xx_usb_devdma_irq, 0, "udc_dma", udc); |
| 3154 | if (retval < 0) { | 3149 | if (retval < 0) { |
| 3155 | dev_err(udc->dev, "DEV request irq %d failed\n", | 3150 | dev_err(udc->dev, "DEV request irq %d failed\n", |
| 3156 | udc->udp_irq[IRQ_USB_DEVDMA]); | 3151 | udc->udp_irq[IRQ_USB_DEVDMA]); |
| 3157 | goto irq_dev_fail; | 3152 | goto irq_req_fail; |
| 3158 | } | 3153 | } |
| 3159 | 3154 | ||
| 3160 | /* The transceiver interrupt is used for VBUS detection and will | 3155 | /* The transceiver interrupt is used for VBUS detection and will |
| 3161 | kick off the VBUS handler function */ | 3156 | kick off the VBUS handler function */ |
| 3162 | retval = request_irq(udc->udp_irq[IRQ_USB_ATX], lpc32xx_usb_vbus_irq, | 3157 | retval = devm_request_threaded_irq(dev, udc->udp_irq[IRQ_USB_ATX], NULL, |
| 3163 | 0, "udc_otg", udc); | 3158 | lpc32xx_usb_vbus_irq, IRQF_ONESHOT, |
| 3159 | "udc_otg", udc); | ||
| 3164 | if (retval < 0) { | 3160 | if (retval < 0) { |
| 3165 | dev_err(udc->dev, "VBUS request irq %d failed\n", | 3161 | dev_err(udc->dev, "VBUS request irq %d failed\n", |
| 3166 | udc->udp_irq[IRQ_USB_ATX]); | 3162 | udc->udp_irq[IRQ_USB_ATX]); |
| 3167 | goto irq_xcvr_fail; | 3163 | goto irq_req_fail; |
| 3168 | } | 3164 | } |
| 3169 | 3165 | ||
| 3170 | /* Initialize wait queue */ | 3166 | /* Initialize wait queue */ |
| 3171 | init_waitqueue_head(&udc->ep_disable_wait_queue); | 3167 | init_waitqueue_head(&udc->ep_disable_wait_queue); |
| 3172 | atomic_set(&udc->enabled_ep_cnt, 0); | 3168 | atomic_set(&udc->enabled_ep_cnt, 0); |
| 3173 | 3169 | ||
| 3174 | /* Keep all IRQs disabled until GadgetFS starts up */ | ||
| 3175 | for (i = IRQ_USB_LP; i <= IRQ_USB_ATX; i++) | ||
| 3176 | disable_irq(udc->udp_irq[i]); | ||
| 3177 | |||
| 3178 | retval = usb_add_gadget_udc(dev, &udc->gadget); | 3170 | retval = usb_add_gadget_udc(dev, &udc->gadget); |
| 3179 | if (retval < 0) | 3171 | if (retval < 0) |
| 3180 | goto add_gadget_fail; | 3172 | goto add_gadget_fail; |
| @@ -3190,32 +3182,15 @@ static int lpc32xx_udc_probe(struct platform_device *pdev) | |||
| 3190 | return 0; | 3182 | return 0; |
| 3191 | 3183 | ||
| 3192 | add_gadget_fail: | 3184 | add_gadget_fail: |
| 3193 | free_irq(udc->udp_irq[IRQ_USB_ATX], udc); | 3185 | irq_req_fail: |
| 3194 | irq_xcvr_fail: | ||
| 3195 | free_irq(udc->udp_irq[IRQ_USB_DEVDMA], udc); | ||
| 3196 | irq_dev_fail: | ||
| 3197 | free_irq(udc->udp_irq[IRQ_USB_HP], udc); | ||
| 3198 | irq_hp_fail: | ||
| 3199 | free_irq(udc->udp_irq[IRQ_USB_LP], udc); | ||
| 3200 | irq_lp_fail: | ||
| 3201 | dma_pool_destroy(udc->dd_cache); | 3186 | dma_pool_destroy(udc->dd_cache); |
| 3202 | dma_alloc_fail: | 3187 | dma_alloc_fail: |
| 3203 | dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE, | 3188 | dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE, |
| 3204 | udc->udca_v_base, udc->udca_p_base); | 3189 | udc->udca_v_base, udc->udca_p_base); |
| 3205 | i2c_fail: | 3190 | i2c_fail: |
| 3206 | clk_disable_unprepare(udc->usb_slv_clk); | 3191 | clk_disable_unprepare(udc->usb_slv_clk); |
| 3207 | usb_clk_enable_fail: | ||
| 3208 | clk_put(udc->usb_slv_clk); | ||
| 3209 | usb_clk_get_fail: | ||
| 3210 | iounmap(udc->udp_baseaddr); | ||
| 3211 | io_map_fail: | ||
| 3212 | release_mem_region(udc->io_p_start, udc->io_p_size); | ||
| 3213 | dev_err(udc->dev, "%s probe failed, %d\n", driver_name, retval); | 3192 | dev_err(udc->dev, "%s probe failed, %d\n", driver_name, retval); |
| 3214 | request_mem_region_fail: | 3193 | |
| 3215 | irq_fail: | ||
| 3216 | resource_fail: | ||
| 3217 | phy_fail: | ||
| 3218 | kfree(udc); | ||
| 3219 | return retval; | 3194 | return retval; |
| 3220 | } | 3195 | } |
| 3221 | 3196 | ||
| @@ -3231,24 +3206,14 @@ static int lpc32xx_udc_remove(struct platform_device *pdev) | |||
| 3231 | udc_disable(udc); | 3206 | udc_disable(udc); |
| 3232 | pullup(udc, 0); | 3207 | pullup(udc, 0); |
| 3233 | 3208 | ||
| 3234 | free_irq(udc->udp_irq[IRQ_USB_ATX], udc); | ||
| 3235 | |||
| 3236 | device_init_wakeup(&pdev->dev, 0); | 3209 | device_init_wakeup(&pdev->dev, 0); |
| 3237 | remove_debug_file(udc); | 3210 | remove_debug_file(udc); |
| 3238 | 3211 | ||
| 3239 | dma_pool_destroy(udc->dd_cache); | 3212 | dma_pool_destroy(udc->dd_cache); |
| 3240 | dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE, | 3213 | dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE, |
| 3241 | udc->udca_v_base, udc->udca_p_base); | 3214 | udc->udca_v_base, udc->udca_p_base); |
| 3242 | free_irq(udc->udp_irq[IRQ_USB_DEVDMA], udc); | ||
| 3243 | free_irq(udc->udp_irq[IRQ_USB_HP], udc); | ||
| 3244 | free_irq(udc->udp_irq[IRQ_USB_LP], udc); | ||
| 3245 | 3215 | ||
| 3246 | clk_disable_unprepare(udc->usb_slv_clk); | 3216 | clk_disable_unprepare(udc->usb_slv_clk); |
| 3247 | clk_put(udc->usb_slv_clk); | ||
| 3248 | |||
| 3249 | iounmap(udc->udp_baseaddr); | ||
| 3250 | release_mem_region(udc->io_p_start, udc->io_p_size); | ||
| 3251 | kfree(udc); | ||
| 3252 | 3217 | ||
| 3253 | return 0; | 3218 | return 0; |
| 3254 | } | 3219 | } |
diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c index c2011cd7df8c..564aeee1a1fe 100644 --- a/drivers/usb/gadget/udc/net2272.c +++ b/drivers/usb/gadget/udc/net2272.c | |||
| @@ -573,8 +573,7 @@ net2272_read_fifo(struct net2272_ep *ep, struct net2272_request *req) | |||
| 573 | 573 | ||
| 574 | /* completion */ | 574 | /* completion */ |
| 575 | if (unlikely(cleanup || is_short || | 575 | if (unlikely(cleanup || is_short || |
| 576 | ((req->req.actual == req->req.length) | 576 | req->req.actual == req->req.length)) { |
| 577 | && !req->req.zero))) { | ||
| 578 | 577 | ||
| 579 | if (cleanup) { | 578 | if (cleanup) { |
| 580 | net2272_out_flush(ep); | 579 | net2272_out_flush(ep); |
diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c index 898339e5df10..b6bbe2e448ba 100644 --- a/drivers/usb/gadget/udc/net2280.c +++ b/drivers/usb/gadget/udc/net2280.c | |||
| @@ -789,8 +789,7 @@ static int read_fifo(struct net2280_ep *ep, struct net2280_request *req) | |||
| 789 | (void) readl(&ep->regs->ep_rsp); | 789 | (void) readl(&ep->regs->ep_rsp); |
| 790 | } | 790 | } |
| 791 | 791 | ||
| 792 | return is_short || ((req->req.actual == req->req.length) && | 792 | return is_short || req->req.actual == req->req.length; |
| 793 | !req->req.zero); | ||
| 794 | } | 793 | } |
| 795 | 794 | ||
| 796 | /* fill out dma descriptor to match a given request */ | 795 | /* fill out dma descriptor to match a given request */ |
| @@ -1058,7 +1057,7 @@ net2280_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) | |||
| 1058 | /* PIO ... stuff the fifo, or unblock it. */ | 1057 | /* PIO ... stuff the fifo, or unblock it. */ |
| 1059 | if (ep->is_in) | 1058 | if (ep->is_in) |
| 1060 | write_fifo(ep, _req); | 1059 | write_fifo(ep, _req); |
| 1061 | else if (list_empty(&ep->queue)) { | 1060 | else { |
| 1062 | u32 s; | 1061 | u32 s; |
| 1063 | 1062 | ||
| 1064 | /* OUT FIFO might have packet(s) buffered */ | 1063 | /* OUT FIFO might have packet(s) buffered */ |
diff --git a/drivers/usb/host/fhci-sched.c b/drivers/usb/host/fhci-sched.c index 3d12cdd5f999..3235d5307403 100644 --- a/drivers/usb/host/fhci-sched.c +++ b/drivers/usb/host/fhci-sched.c | |||
| @@ -727,8 +727,7 @@ void fhci_queue_urb(struct fhci_hcd *fhci, struct urb *urb) | |||
| 727 | } | 727 | } |
| 728 | ed->speed = (urb->dev->speed == USB_SPEED_LOW) ? | 728 | ed->speed = (urb->dev->speed == USB_SPEED_LOW) ? |
| 729 | FHCI_LOW_SPEED : FHCI_FULL_SPEED; | 729 | FHCI_LOW_SPEED : FHCI_FULL_SPEED; |
| 730 | ed->max_pkt_size = usb_maxpacket(urb->dev, | 730 | ed->max_pkt_size = usb_endpoint_maxp(&urb->ep->desc); |
| 731 | urb->pipe, usb_pipeout(urb->pipe)); | ||
| 732 | urb->ep->hcpriv = ed; | 731 | urb->ep->hcpriv = ed; |
| 733 | fhci_dbg(fhci, "new ep speed=%d max_pkt_size=%d\n", | 732 | fhci_dbg(fhci, "new ep speed=%d max_pkt_size=%d\n", |
| 734 | ed->speed, ed->max_pkt_size); | 733 | ed->speed, ed->max_pkt_size); |
| @@ -768,8 +767,7 @@ void fhci_queue_urb(struct fhci_hcd *fhci, struct urb *urb) | |||
| 768 | if (urb->transfer_flags & URB_ZERO_PACKET && | 767 | if (urb->transfer_flags & URB_ZERO_PACKET && |
| 769 | urb->transfer_buffer_length > 0 && | 768 | urb->transfer_buffer_length > 0 && |
| 770 | ((urb->transfer_buffer_length % | 769 | ((urb->transfer_buffer_length % |
| 771 | usb_maxpacket(urb->dev, urb->pipe, | 770 | usb_endpoint_maxp(&urb->ep->desc)) == 0)) |
| 772 | usb_pipeout(urb->pipe))) == 0)) | ||
| 773 | urb_state = US_BULK0; | 771 | urb_state = US_BULK0; |
| 774 | while (data_len > 4096) { | 772 | while (data_len > 4096) { |
| 775 | td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt, | 773 | td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt, |
| @@ -807,8 +805,8 @@ void fhci_queue_urb(struct fhci_hcd *fhci, struct urb *urb) | |||
| 807 | break; | 805 | break; |
| 808 | case FHCI_TF_CTRL: | 806 | case FHCI_TF_CTRL: |
| 809 | ed->dev_addr = usb_pipedevice(urb->pipe); | 807 | ed->dev_addr = usb_pipedevice(urb->pipe); |
| 810 | ed->max_pkt_size = usb_maxpacket(urb->dev, urb->pipe, | 808 | ed->max_pkt_size = usb_endpoint_maxp(&urb->ep->desc); |
| 811 | usb_pipeout(urb->pipe)); | 809 | |
| 812 | /* setup stage */ | 810 | /* setup stage */ |
| 813 | td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, FHCI_TA_SETUP, | 811 | td = fhci_td_fill(fhci, urb, urb_priv, ed, cnt++, FHCI_TA_SETUP, |
| 814 | USB_TD_TOGGLE_DATA0, urb->setup_packet, 8, 0, 0, true); | 812 | USB_TD_TOGGLE_DATA0, urb->setup_packet, 8, 0, 0, true); |
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 6343fbacd244..4a5c9b599c57 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c | |||
| @@ -3203,6 +3203,8 @@ static int __init u132_hcd_init(void) | |||
| 3203 | return -ENODEV; | 3203 | return -ENODEV; |
| 3204 | printk(KERN_INFO "driver %s\n", hcd_name); | 3204 | printk(KERN_INFO "driver %s\n", hcd_name); |
| 3205 | workqueue = create_singlethread_workqueue("u132"); | 3205 | workqueue = create_singlethread_workqueue("u132"); |
| 3206 | if (!workqueue) | ||
| 3207 | return -ENOMEM; | ||
| 3206 | retval = platform_driver_register(&u132_platform_driver); | 3208 | retval = platform_driver_register(&u132_platform_driver); |
| 3207 | if (retval) | 3209 | if (retval) |
| 3208 | destroy_workqueue(workqueue); | 3210 | destroy_workqueue(workqueue); |
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 96a740543183..3abe70ff1b1e 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c | |||
| @@ -487,8 +487,8 @@ static void xhci_disable_port(struct usb_hcd *hcd, struct xhci_hcd *xhci, | |||
| 487 | /* Write 1 to disable the port */ | 487 | /* Write 1 to disable the port */ |
| 488 | writel(port_status | PORT_PE, addr); | 488 | writel(port_status | PORT_PE, addr); |
| 489 | port_status = readl(addr); | 489 | port_status = readl(addr); |
| 490 | xhci_dbg(xhci, "disable port, actual port %d status = 0x%x\n", | 490 | xhci_dbg(xhci, "disable port %d-%d, portsc: 0x%x\n", |
| 491 | wIndex, port_status); | 491 | hcd->self.busnum, wIndex + 1, port_status); |
| 492 | } | 492 | } |
| 493 | 493 | ||
| 494 | static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue, | 494 | static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue, |
| @@ -537,8 +537,9 @@ static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue, | |||
| 537 | /* Change bits are all write 1 to clear */ | 537 | /* Change bits are all write 1 to clear */ |
| 538 | writel(port_status | status, addr); | 538 | writel(port_status | status, addr); |
| 539 | port_status = readl(addr); | 539 | port_status = readl(addr); |
| 540 | xhci_dbg(xhci, "clear port %s change, actual port %d status = 0x%x\n", | 540 | |
| 541 | port_change_bit, wIndex, port_status); | 541 | xhci_dbg(xhci, "clear port%d %s change, portsc: 0x%x\n", |
| 542 | wIndex + 1, port_change_bit, port_status); | ||
| 542 | } | 543 | } |
| 543 | 544 | ||
| 544 | struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd) | 545 | struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd) |
| @@ -565,13 +566,16 @@ static void xhci_set_port_power(struct xhci_hcd *xhci, struct usb_hcd *hcd, | |||
| 565 | rhub = xhci_get_rhub(hcd); | 566 | rhub = xhci_get_rhub(hcd); |
| 566 | port = rhub->ports[index]; | 567 | port = rhub->ports[index]; |
| 567 | temp = readl(port->addr); | 568 | temp = readl(port->addr); |
| 569 | |||
| 570 | xhci_dbg(xhci, "set port power %d-%d %s, portsc: 0x%x\n", | ||
| 571 | hcd->self.busnum, index + 1, on ? "ON" : "OFF", temp); | ||
| 572 | |||
| 568 | temp = xhci_port_state_to_neutral(temp); | 573 | temp = xhci_port_state_to_neutral(temp); |
| 574 | |||
| 569 | if (on) { | 575 | if (on) { |
| 570 | /* Power on */ | 576 | /* Power on */ |
| 571 | writel(temp | PORT_POWER, port->addr); | 577 | writel(temp | PORT_POWER, port->addr); |
| 572 | temp = readl(port->addr); | 578 | readl(port->addr); |
| 573 | xhci_dbg(xhci, "set port power, actual port %d status = 0x%x\n", | ||
| 574 | index, temp); | ||
| 575 | } else { | 579 | } else { |
| 576 | /* Power off */ | 580 | /* Power off */ |
| 577 | writel(temp & ~PORT_POWER, port->addr); | 581 | writel(temp & ~PORT_POWER, port->addr); |
| @@ -666,12 +670,17 @@ void xhci_set_link_state(struct xhci_hcd *xhci, struct xhci_port *port, | |||
| 666 | u32 link_state) | 670 | u32 link_state) |
| 667 | { | 671 | { |
| 668 | u32 temp; | 672 | u32 temp; |
| 673 | u32 portsc; | ||
| 669 | 674 | ||
| 670 | temp = readl(port->addr); | 675 | portsc = readl(port->addr); |
| 671 | temp = xhci_port_state_to_neutral(temp); | 676 | temp = xhci_port_state_to_neutral(portsc); |
| 672 | temp &= ~PORT_PLS_MASK; | 677 | temp &= ~PORT_PLS_MASK; |
| 673 | temp |= PORT_LINK_STROBE | link_state; | 678 | temp |= PORT_LINK_STROBE | link_state; |
| 674 | writel(temp, port->addr); | 679 | writel(temp, port->addr); |
| 680 | |||
| 681 | xhci_dbg(xhci, "Set port %d-%d link state, portsc: 0x%x, write 0x%x", | ||
| 682 | port->rhub->hcd->self.busnum, port->hcd_portnum + 1, | ||
| 683 | portsc, temp); | ||
| 675 | } | 684 | } |
| 676 | 685 | ||
| 677 | static void xhci_set_remote_wake_mask(struct xhci_hcd *xhci, | 686 | static void xhci_set_remote_wake_mask(struct xhci_hcd *xhci, |
| @@ -840,7 +849,9 @@ static int xhci_handle_usb2_port_link_resume(struct xhci_port *port, | |||
| 840 | } else if (time_after_eq(jiffies, bus_state->resume_done[wIndex])) { | 849 | } else if (time_after_eq(jiffies, bus_state->resume_done[wIndex])) { |
| 841 | int time_left; | 850 | int time_left; |
| 842 | 851 | ||
| 843 | xhci_dbg(xhci, "Resume USB2 port %d\n", wIndex + 1); | 852 | xhci_dbg(xhci, "resume USB2 port %d-%d\n", |
| 853 | hcd->self.busnum, wIndex + 1); | ||
| 854 | |||
| 844 | bus_state->resume_done[wIndex] = 0; | 855 | bus_state->resume_done[wIndex] = 0; |
| 845 | clear_bit(wIndex, &bus_state->resuming_ports); | 856 | clear_bit(wIndex, &bus_state->resuming_ports); |
| 846 | 857 | ||
| @@ -867,9 +878,8 @@ static int xhci_handle_usb2_port_link_resume(struct xhci_port *port, | |||
| 867 | } else { | 878 | } else { |
| 868 | int port_status = readl(port->addr); | 879 | int port_status = readl(port->addr); |
| 869 | 880 | ||
| 870 | xhci_warn(xhci, "Port resume %i msec timed out, portsc = 0x%x\n", | 881 | xhci_warn(xhci, "Port resume timed out, port %d-%d: 0x%x\n", |
| 871 | XHCI_MAX_REXIT_TIMEOUT_MS, | 882 | hcd->self.busnum, wIndex + 1, port_status); |
| 872 | port_status); | ||
| 873 | *status |= USB_PORT_STAT_SUSPEND; | 883 | *status |= USB_PORT_STAT_SUSPEND; |
| 874 | clear_bit(wIndex, &bus_state->rexit_ports); | 884 | clear_bit(wIndex, &bus_state->rexit_ports); |
| 875 | } | 885 | } |
| @@ -1124,9 +1134,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
| 1124 | if (status == 0xffffffff) | 1134 | if (status == 0xffffffff) |
| 1125 | goto error; | 1135 | goto error; |
| 1126 | 1136 | ||
| 1127 | xhci_dbg(xhci, "get port status, actual port %d status = 0x%x\n", | 1137 | xhci_dbg(xhci, "Get port status %d-%d read: 0x%x, return 0x%x", |
| 1128 | wIndex, temp); | 1138 | hcd->self.busnum, wIndex + 1, temp, status); |
| 1129 | xhci_dbg(xhci, "Get port status returned 0x%x\n", status); | ||
| 1130 | 1139 | ||
| 1131 | put_unaligned(cpu_to_le32(status), (__le32 *) buf); | 1140 | put_unaligned(cpu_to_le32(status), (__le32 *) buf); |
| 1132 | /* if USB 3.1 extended port status return additional 4 bytes */ | 1141 | /* if USB 3.1 extended port status return additional 4 bytes */ |
| @@ -1182,7 +1191,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
| 1182 | temp = readl(ports[wIndex]->addr); | 1191 | temp = readl(ports[wIndex]->addr); |
| 1183 | if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) | 1192 | if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) |
| 1184 | || (temp & PORT_PLS_MASK) >= XDEV_U3) { | 1193 | || (temp & PORT_PLS_MASK) >= XDEV_U3) { |
| 1185 | xhci_warn(xhci, "USB core suspending device not in U0/U1/U2.\n"); | 1194 | xhci_warn(xhci, "USB core suspending port %d-%d not in U0/U1/U2\n", |
| 1195 | hcd->self.busnum, wIndex + 1); | ||
| 1186 | goto error; | 1196 | goto error; |
| 1187 | } | 1197 | } |
| 1188 | 1198 | ||
diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c index 60987c787e44..026fe18972d3 100644 --- a/drivers/usb/host/xhci-mtk.c +++ b/drivers/usb/host/xhci-mtk.c | |||
| @@ -206,19 +206,6 @@ static int xhci_mtk_ssusb_config(struct xhci_hcd_mtk *mtk) | |||
| 206 | return xhci_mtk_host_enable(mtk); | 206 | return xhci_mtk_host_enable(mtk); |
| 207 | } | 207 | } |
| 208 | 208 | ||
| 209 | /* ignore the error if the clock does not exist */ | ||
| 210 | static struct clk *optional_clk_get(struct device *dev, const char *id) | ||
| 211 | { | ||
| 212 | struct clk *opt_clk; | ||
| 213 | |||
| 214 | opt_clk = devm_clk_get(dev, id); | ||
| 215 | /* ignore error number except EPROBE_DEFER */ | ||
| 216 | if (IS_ERR(opt_clk) && (PTR_ERR(opt_clk) != -EPROBE_DEFER)) | ||
| 217 | opt_clk = NULL; | ||
| 218 | |||
| 219 | return opt_clk; | ||
| 220 | } | ||
| 221 | |||
| 222 | static int xhci_mtk_clks_get(struct xhci_hcd_mtk *mtk) | 209 | static int xhci_mtk_clks_get(struct xhci_hcd_mtk *mtk) |
| 223 | { | 210 | { |
| 224 | struct device *dev = mtk->dev; | 211 | struct device *dev = mtk->dev; |
| @@ -229,15 +216,15 @@ static int xhci_mtk_clks_get(struct xhci_hcd_mtk *mtk) | |||
| 229 | return PTR_ERR(mtk->sys_clk); | 216 | return PTR_ERR(mtk->sys_clk); |
| 230 | } | 217 | } |
| 231 | 218 | ||
| 232 | mtk->ref_clk = optional_clk_get(dev, "ref_ck"); | 219 | mtk->ref_clk = devm_clk_get_optional(dev, "ref_ck"); |
| 233 | if (IS_ERR(mtk->ref_clk)) | 220 | if (IS_ERR(mtk->ref_clk)) |
| 234 | return PTR_ERR(mtk->ref_clk); | 221 | return PTR_ERR(mtk->ref_clk); |
| 235 | 222 | ||
| 236 | mtk->mcu_clk = optional_clk_get(dev, "mcu_ck"); | 223 | mtk->mcu_clk = devm_clk_get_optional(dev, "mcu_ck"); |
| 237 | if (IS_ERR(mtk->mcu_clk)) | 224 | if (IS_ERR(mtk->mcu_clk)) |
| 238 | return PTR_ERR(mtk->mcu_clk); | 225 | return PTR_ERR(mtk->mcu_clk); |
| 239 | 226 | ||
| 240 | mtk->dma_clk = optional_clk_get(dev, "dma_ck"); | 227 | mtk->dma_clk = devm_clk_get_optional(dev, "dma_ck"); |
| 241 | return PTR_ERR_OR_ZERO(mtk->dma_clk); | 228 | return PTR_ERR_OR_ZERO(mtk->dma_clk); |
| 242 | } | 229 | } |
| 243 | 230 | ||
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 0ac4ec975547..998241f5fce3 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c | |||
| @@ -165,8 +165,6 @@ static int xhci_plat_probe(struct platform_device *pdev) | |||
| 165 | struct xhci_hcd *xhci; | 165 | struct xhci_hcd *xhci; |
| 166 | struct resource *res; | 166 | struct resource *res; |
| 167 | struct usb_hcd *hcd; | 167 | struct usb_hcd *hcd; |
| 168 | struct clk *clk; | ||
| 169 | struct clk *reg_clk; | ||
| 170 | int ret; | 168 | int ret; |
| 171 | int irq; | 169 | int irq; |
| 172 | 170 | ||
| @@ -235,31 +233,32 @@ static int xhci_plat_probe(struct platform_device *pdev) | |||
| 235 | hcd->rsrc_start = res->start; | 233 | hcd->rsrc_start = res->start; |
| 236 | hcd->rsrc_len = resource_size(res); | 234 | hcd->rsrc_len = resource_size(res); |
| 237 | 235 | ||
| 236 | xhci = hcd_to_xhci(hcd); | ||
| 237 | |||
| 238 | /* | 238 | /* |
| 239 | * Not all platforms have clks so it is not an error if the | 239 | * Not all platforms have clks so it is not an error if the |
| 240 | * clock do not exist. | 240 | * clock do not exist. |
| 241 | */ | 241 | */ |
| 242 | reg_clk = devm_clk_get(&pdev->dev, "reg"); | 242 | xhci->reg_clk = devm_clk_get_optional(&pdev->dev, "reg"); |
| 243 | if (!IS_ERR(reg_clk)) { | 243 | if (IS_ERR(xhci->reg_clk)) { |
| 244 | ret = clk_prepare_enable(reg_clk); | 244 | ret = PTR_ERR(xhci->reg_clk); |
| 245 | if (ret) | ||
| 246 | goto put_hcd; | ||
| 247 | } else if (PTR_ERR(reg_clk) == -EPROBE_DEFER) { | ||
| 248 | ret = -EPROBE_DEFER; | ||
| 249 | goto put_hcd; | 245 | goto put_hcd; |
| 250 | } | 246 | } |
| 251 | 247 | ||
| 252 | clk = devm_clk_get(&pdev->dev, NULL); | 248 | ret = clk_prepare_enable(xhci->reg_clk); |
| 253 | if (!IS_ERR(clk)) { | 249 | if (ret) |
| 254 | ret = clk_prepare_enable(clk); | 250 | goto put_hcd; |
| 255 | if (ret) | 251 | |
| 256 | goto disable_reg_clk; | 252 | xhci->clk = devm_clk_get_optional(&pdev->dev, NULL); |
| 257 | } else if (PTR_ERR(clk) == -EPROBE_DEFER) { | 253 | if (IS_ERR(xhci->clk)) { |
| 258 | ret = -EPROBE_DEFER; | 254 | ret = PTR_ERR(xhci->clk); |
| 259 | goto disable_reg_clk; | 255 | goto disable_reg_clk; |
| 260 | } | 256 | } |
| 261 | 257 | ||
| 262 | xhci = hcd_to_xhci(hcd); | 258 | ret = clk_prepare_enable(xhci->clk); |
| 259 | if (ret) | ||
| 260 | goto disable_reg_clk; | ||
| 261 | |||
| 263 | priv_match = of_device_get_match_data(&pdev->dev); | 262 | priv_match = of_device_get_match_data(&pdev->dev); |
| 264 | if (priv_match) { | 263 | if (priv_match) { |
| 265 | struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); | 264 | struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd); |
| @@ -271,8 +270,6 @@ static int xhci_plat_probe(struct platform_device *pdev) | |||
| 271 | 270 | ||
| 272 | device_wakeup_enable(hcd->self.controller); | 271 | device_wakeup_enable(hcd->self.controller); |
| 273 | 272 | ||
| 274 | xhci->clk = clk; | ||
| 275 | xhci->reg_clk = reg_clk; | ||
| 276 | xhci->main_hcd = hcd; | 273 | xhci->main_hcd = hcd; |
| 277 | xhci->shared_hcd = __usb_create_hcd(driver, sysdev, &pdev->dev, | 274 | xhci->shared_hcd = __usb_create_hcd(driver, sysdev, &pdev->dev, |
| 278 | dev_name(&pdev->dev), hcd); | 275 | dev_name(&pdev->dev), hcd); |
| @@ -348,10 +345,10 @@ put_usb3_hcd: | |||
| 348 | usb_put_hcd(xhci->shared_hcd); | 345 | usb_put_hcd(xhci->shared_hcd); |
| 349 | 346 | ||
| 350 | disable_clk: | 347 | disable_clk: |
| 351 | clk_disable_unprepare(clk); | 348 | clk_disable_unprepare(xhci->clk); |
| 352 | 349 | ||
| 353 | disable_reg_clk: | 350 | disable_reg_clk: |
| 354 | clk_disable_unprepare(reg_clk); | 351 | clk_disable_unprepare(xhci->reg_clk); |
| 355 | 352 | ||
| 356 | put_hcd: | 353 | put_hcd: |
| 357 | usb_put_hcd(hcd); | 354 | usb_put_hcd(hcd); |
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 9215a28dad40..fed3385aeac0 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c | |||
| @@ -1569,18 +1569,19 @@ static void handle_port_status(struct xhci_hcd *xhci, | |||
| 1569 | "WARN: xHC returned failed port status event\n"); | 1569 | "WARN: xHC returned failed port status event\n"); |
| 1570 | 1570 | ||
| 1571 | port_id = GET_PORT_ID(le32_to_cpu(event->generic.field[0])); | 1571 | port_id = GET_PORT_ID(le32_to_cpu(event->generic.field[0])); |
| 1572 | xhci_dbg(xhci, "Port Status Change Event for port %d\n", port_id); | ||
| 1573 | |||
| 1574 | max_ports = HCS_MAX_PORTS(xhci->hcs_params1); | 1572 | max_ports = HCS_MAX_PORTS(xhci->hcs_params1); |
| 1573 | |||
| 1575 | if ((port_id <= 0) || (port_id > max_ports)) { | 1574 | if ((port_id <= 0) || (port_id > max_ports)) { |
| 1576 | xhci_warn(xhci, "Invalid port id %d\n", port_id); | 1575 | xhci_warn(xhci, "Port change event with invalid port ID %d\n", |
| 1576 | port_id); | ||
| 1577 | inc_deq(xhci, xhci->event_ring); | 1577 | inc_deq(xhci, xhci->event_ring); |
| 1578 | return; | 1578 | return; |
| 1579 | } | 1579 | } |
| 1580 | 1580 | ||
| 1581 | port = &xhci->hw_ports[port_id - 1]; | 1581 | port = &xhci->hw_ports[port_id - 1]; |
| 1582 | if (!port || !port->rhub || port->hcd_portnum == DUPLICATE_ENTRY) { | 1582 | if (!port || !port->rhub || port->hcd_portnum == DUPLICATE_ENTRY) { |
| 1583 | xhci_warn(xhci, "Event for invalid port %u\n", port_id); | 1583 | xhci_warn(xhci, "Port change event, no port for port ID %u\n", |
| 1584 | port_id); | ||
| 1584 | bogus_port_status = true; | 1585 | bogus_port_status = true; |
| 1585 | goto cleanup; | 1586 | goto cleanup; |
| 1586 | } | 1587 | } |
| @@ -1597,6 +1598,9 @@ static void handle_port_status(struct xhci_hcd *xhci, | |||
| 1597 | hcd_portnum = port->hcd_portnum; | 1598 | hcd_portnum = port->hcd_portnum; |
| 1598 | portsc = readl(port->addr); | 1599 | portsc = readl(port->addr); |
| 1599 | 1600 | ||
| 1601 | xhci_dbg(xhci, "Port change event, %d-%d, id %d, portsc: 0x%x\n", | ||
| 1602 | hcd->self.busnum, hcd_portnum + 1, port_id, portsc); | ||
| 1603 | |||
| 1600 | trace_xhci_handle_port_status(hcd_portnum, portsc); | 1604 | trace_xhci_handle_port_status(hcd_portnum, portsc); |
| 1601 | 1605 | ||
| 1602 | if (hcd->state == HC_STATE_SUSPENDED) { | 1606 | if (hcd->state == HC_STATE_SUSPENDED) { |
| @@ -3275,6 +3279,12 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, | |||
| 3275 | field |= TRB_IOC; | 3279 | field |= TRB_IOC; |
| 3276 | more_trbs_coming = false; | 3280 | more_trbs_coming = false; |
| 3277 | td->last_trb = ring->enqueue; | 3281 | td->last_trb = ring->enqueue; |
| 3282 | |||
| 3283 | if (xhci_urb_suitable_for_idt(urb)) { | ||
| 3284 | memcpy(&send_addr, urb->transfer_buffer, | ||
| 3285 | trb_buff_len); | ||
| 3286 | field |= TRB_IDT; | ||
| 3287 | } | ||
| 3278 | } | 3288 | } |
| 3279 | 3289 | ||
| 3280 | /* Only set interrupt on short packet for IN endpoints */ | 3290 | /* Only set interrupt on short packet for IN endpoints */ |
| @@ -3414,6 +3424,12 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, | |||
| 3414 | if (urb->transfer_buffer_length > 0) { | 3424 | if (urb->transfer_buffer_length > 0) { |
| 3415 | u32 length_field, remainder; | 3425 | u32 length_field, remainder; |
| 3416 | 3426 | ||
| 3427 | if (xhci_urb_suitable_for_idt(urb)) { | ||
| 3428 | memcpy(&urb->transfer_dma, urb->transfer_buffer, | ||
| 3429 | urb->transfer_buffer_length); | ||
| 3430 | field |= TRB_IDT; | ||
| 3431 | } | ||
| 3432 | |||
| 3417 | remainder = xhci_td_remainder(xhci, 0, | 3433 | remainder = xhci_td_remainder(xhci, 0, |
| 3418 | urb->transfer_buffer_length, | 3434 | urb->transfer_buffer_length, |
| 3419 | urb->transfer_buffer_length, | 3435 | urb->transfer_buffer_length, |
diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c index efb0cad8710e..294158113d62 100644 --- a/drivers/usb/host/xhci-tegra.c +++ b/drivers/usb/host/xhci-tegra.c | |||
| @@ -161,6 +161,7 @@ struct tegra_xusb_soc { | |||
| 161 | } ports; | 161 | } ports; |
| 162 | 162 | ||
| 163 | bool scale_ss_clock; | 163 | bool scale_ss_clock; |
| 164 | bool has_ipfs; | ||
| 164 | }; | 165 | }; |
| 165 | 166 | ||
| 166 | struct tegra_xusb { | 167 | struct tegra_xusb { |
| @@ -637,16 +638,18 @@ static irqreturn_t tegra_xusb_mbox_thread(int irq, void *data) | |||
| 637 | return IRQ_HANDLED; | 638 | return IRQ_HANDLED; |
| 638 | } | 639 | } |
| 639 | 640 | ||
| 640 | static void tegra_xusb_ipfs_config(struct tegra_xusb *tegra, | 641 | static void tegra_xusb_config(struct tegra_xusb *tegra, |
| 641 | struct resource *regs) | 642 | struct resource *regs) |
| 642 | { | 643 | { |
| 643 | u32 value; | 644 | u32 value; |
| 644 | 645 | ||
| 645 | value = ipfs_readl(tegra, IPFS_XUSB_HOST_CONFIGURATION_0); | 646 | if (tegra->soc->has_ipfs) { |
| 646 | value |= IPFS_EN_FPCI; | 647 | value = ipfs_readl(tegra, IPFS_XUSB_HOST_CONFIGURATION_0); |
| 647 | ipfs_writel(tegra, value, IPFS_XUSB_HOST_CONFIGURATION_0); | 648 | value |= IPFS_EN_FPCI; |
| 649 | ipfs_writel(tegra, value, IPFS_XUSB_HOST_CONFIGURATION_0); | ||
| 648 | 650 | ||
| 649 | usleep_range(10, 20); | 651 | usleep_range(10, 20); |
| 652 | } | ||
| 650 | 653 | ||
| 651 | /* Program BAR0 space */ | 654 | /* Program BAR0 space */ |
| 652 | value = fpci_readl(tegra, XUSB_CFG_4); | 655 | value = fpci_readl(tegra, XUSB_CFG_4); |
| @@ -661,13 +664,15 @@ static void tegra_xusb_ipfs_config(struct tegra_xusb *tegra, | |||
| 661 | value |= XUSB_IO_SPACE_EN | XUSB_MEM_SPACE_EN | XUSB_BUS_MASTER_EN; | 664 | value |= XUSB_IO_SPACE_EN | XUSB_MEM_SPACE_EN | XUSB_BUS_MASTER_EN; |
| 662 | fpci_writel(tegra, value, XUSB_CFG_1); | 665 | fpci_writel(tegra, value, XUSB_CFG_1); |
| 663 | 666 | ||
| 664 | /* Enable interrupt assertion */ | 667 | if (tegra->soc->has_ipfs) { |
| 665 | value = ipfs_readl(tegra, IPFS_XUSB_HOST_INTR_MASK_0); | 668 | /* Enable interrupt assertion */ |
| 666 | value |= IPFS_IP_INT_MASK; | 669 | value = ipfs_readl(tegra, IPFS_XUSB_HOST_INTR_MASK_0); |
| 667 | ipfs_writel(tegra, value, IPFS_XUSB_HOST_INTR_MASK_0); | 670 | value |= IPFS_IP_INT_MASK; |
| 671 | ipfs_writel(tegra, value, IPFS_XUSB_HOST_INTR_MASK_0); | ||
| 668 | 672 | ||
| 669 | /* Set hysteresis */ | 673 | /* Set hysteresis */ |
| 670 | ipfs_writel(tegra, 0x80, IPFS_XUSB_HOST_CLKGATE_HYSTERESIS_0); | 674 | ipfs_writel(tegra, 0x80, IPFS_XUSB_HOST_CLKGATE_HYSTERESIS_0); |
| 675 | } | ||
| 671 | } | 676 | } |
| 672 | 677 | ||
| 673 | static int tegra_xusb_clk_enable(struct tegra_xusb *tegra) | 678 | static int tegra_xusb_clk_enable(struct tegra_xusb *tegra) |
| @@ -1015,10 +1020,12 @@ static int tegra_xusb_probe(struct platform_device *pdev) | |||
| 1015 | if (IS_ERR(tegra->fpci_base)) | 1020 | if (IS_ERR(tegra->fpci_base)) |
| 1016 | return PTR_ERR(tegra->fpci_base); | 1021 | return PTR_ERR(tegra->fpci_base); |
| 1017 | 1022 | ||
| 1018 | res = platform_get_resource(pdev, IORESOURCE_MEM, 2); | 1023 | if (tegra->soc->has_ipfs) { |
| 1019 | tegra->ipfs_base = devm_ioremap_resource(&pdev->dev, res); | 1024 | res = platform_get_resource(pdev, IORESOURCE_MEM, 2); |
| 1020 | if (IS_ERR(tegra->ipfs_base)) | 1025 | tegra->ipfs_base = devm_ioremap_resource(&pdev->dev, res); |
| 1021 | return PTR_ERR(tegra->ipfs_base); | 1026 | if (IS_ERR(tegra->ipfs_base)) |
| 1027 | return PTR_ERR(tegra->ipfs_base); | ||
| 1028 | } | ||
| 1022 | 1029 | ||
| 1023 | tegra->xhci_irq = platform_get_irq(pdev, 0); | 1030 | tegra->xhci_irq = platform_get_irq(pdev, 0); |
| 1024 | if (tegra->xhci_irq < 0) | 1031 | if (tegra->xhci_irq < 0) |
| @@ -1208,7 +1215,7 @@ static int tegra_xusb_probe(struct platform_device *pdev) | |||
| 1208 | goto disable_rpm; | 1215 | goto disable_rpm; |
| 1209 | } | 1216 | } |
| 1210 | 1217 | ||
| 1211 | tegra_xusb_ipfs_config(tegra, regs); | 1218 | tegra_xusb_config(tegra, regs); |
| 1212 | 1219 | ||
| 1213 | err = tegra_xusb_load_firmware(tegra); | 1220 | err = tegra_xusb_load_firmware(tegra); |
| 1214 | if (err < 0) { | 1221 | if (err < 0) { |
| @@ -1380,6 +1387,7 @@ static const struct tegra_xusb_soc tegra124_soc = { | |||
| 1380 | .usb3 = { .offset = 0, .count = 2, }, | 1387 | .usb3 = { .offset = 0, .count = 2, }, |
| 1381 | }, | 1388 | }, |
| 1382 | .scale_ss_clock = true, | 1389 | .scale_ss_clock = true, |
| 1390 | .has_ipfs = true, | ||
| 1383 | }; | 1391 | }; |
| 1384 | MODULE_FIRMWARE("nvidia/tegra124/xusb.bin"); | 1392 | MODULE_FIRMWARE("nvidia/tegra124/xusb.bin"); |
| 1385 | 1393 | ||
| @@ -1411,12 +1419,38 @@ static const struct tegra_xusb_soc tegra210_soc = { | |||
| 1411 | .usb3 = { .offset = 0, .count = 4, }, | 1419 | .usb3 = { .offset = 0, .count = 4, }, |
| 1412 | }, | 1420 | }, |
| 1413 | .scale_ss_clock = false, | 1421 | .scale_ss_clock = false, |
| 1422 | .has_ipfs = true, | ||
| 1414 | }; | 1423 | }; |
| 1415 | MODULE_FIRMWARE("nvidia/tegra210/xusb.bin"); | 1424 | MODULE_FIRMWARE("nvidia/tegra210/xusb.bin"); |
| 1416 | 1425 | ||
| 1426 | static const char * const tegra186_supply_names[] = { | ||
| 1427 | }; | ||
| 1428 | |||
| 1429 | static const struct tegra_xusb_phy_type tegra186_phy_types[] = { | ||
| 1430 | { .name = "usb3", .num = 3, }, | ||
| 1431 | { .name = "usb2", .num = 3, }, | ||
| 1432 | { .name = "hsic", .num = 1, }, | ||
| 1433 | }; | ||
| 1434 | |||
| 1435 | static const struct tegra_xusb_soc tegra186_soc = { | ||
| 1436 | .firmware = "nvidia/tegra186/xusb.bin", | ||
| 1437 | .supply_names = tegra186_supply_names, | ||
| 1438 | .num_supplies = ARRAY_SIZE(tegra186_supply_names), | ||
| 1439 | .phy_types = tegra186_phy_types, | ||
| 1440 | .num_types = ARRAY_SIZE(tegra186_phy_types), | ||
| 1441 | .ports = { | ||
| 1442 | .usb3 = { .offset = 0, .count = 3, }, | ||
| 1443 | .usb2 = { .offset = 3, .count = 3, }, | ||
| 1444 | .hsic = { .offset = 6, .count = 1, }, | ||
| 1445 | }, | ||
| 1446 | .scale_ss_clock = false, | ||
| 1447 | .has_ipfs = false, | ||
| 1448 | }; | ||
| 1449 | |||
| 1417 | static const struct of_device_id tegra_xusb_of_match[] = { | 1450 | static const struct of_device_id tegra_xusb_of_match[] = { |
| 1418 | { .compatible = "nvidia,tegra124-xusb", .data = &tegra124_soc }, | 1451 | { .compatible = "nvidia,tegra124-xusb", .data = &tegra124_soc }, |
| 1419 | { .compatible = "nvidia,tegra210-xusb", .data = &tegra210_soc }, | 1452 | { .compatible = "nvidia,tegra210-xusb", .data = &tegra210_soc }, |
| 1453 | { .compatible = "nvidia,tegra186-xusb", .data = &tegra186_soc }, | ||
| 1420 | { }, | 1454 | { }, |
| 1421 | }; | 1455 | }; |
| 1422 | MODULE_DEVICE_TABLE(of, tegra_xusb_of_match); | 1456 | MODULE_DEVICE_TABLE(of, tegra_xusb_of_match); |
diff --git a/drivers/usb/host/xhci-trace.h b/drivers/usb/host/xhci-trace.h index 88b427434bd8..052a269d86f2 100644 --- a/drivers/usb/host/xhci-trace.h +++ b/drivers/usb/host/xhci-trace.h | |||
| @@ -366,6 +366,11 @@ DEFINE_EVENT(xhci_log_ep_ctx, xhci_handle_cmd_config_ep, | |||
| 366 | TP_ARGS(ctx) | 366 | TP_ARGS(ctx) |
| 367 | ); | 367 | ); |
| 368 | 368 | ||
| 369 | DEFINE_EVENT(xhci_log_ep_ctx, xhci_add_endpoint, | ||
| 370 | TP_PROTO(struct xhci_ep_ctx *ctx), | ||
| 371 | TP_ARGS(ctx) | ||
| 372 | ); | ||
| 373 | |||
| 369 | DECLARE_EVENT_CLASS(xhci_log_slot_ctx, | 374 | DECLARE_EVENT_CLASS(xhci_log_slot_ctx, |
| 370 | TP_PROTO(struct xhci_slot_ctx *ctx), | 375 | TP_PROTO(struct xhci_slot_ctx *ctx), |
| 371 | TP_ARGS(ctx), | 376 | TP_ARGS(ctx), |
| @@ -432,6 +437,31 @@ DEFINE_EVENT(xhci_log_slot_ctx, xhci_configure_endpoint, | |||
| 432 | TP_ARGS(ctx) | 437 | TP_ARGS(ctx) |
| 433 | ); | 438 | ); |
| 434 | 439 | ||
| 440 | DECLARE_EVENT_CLASS(xhci_log_ctrl_ctx, | ||
| 441 | TP_PROTO(struct xhci_input_control_ctx *ctrl_ctx), | ||
| 442 | TP_ARGS(ctrl_ctx), | ||
| 443 | TP_STRUCT__entry( | ||
| 444 | __field(u32, drop) | ||
| 445 | __field(u32, add) | ||
| 446 | ), | ||
| 447 | TP_fast_assign( | ||
| 448 | __entry->drop = le32_to_cpu(ctrl_ctx->drop_flags); | ||
| 449 | __entry->add = le32_to_cpu(ctrl_ctx->add_flags); | ||
| 450 | ), | ||
| 451 | TP_printk("%s", xhci_decode_ctrl_ctx(__entry->drop, __entry->add) | ||
| 452 | ) | ||
| 453 | ); | ||
| 454 | |||
| 455 | DEFINE_EVENT(xhci_log_ctrl_ctx, xhci_address_ctrl_ctx, | ||
| 456 | TP_PROTO(struct xhci_input_control_ctx *ctrl_ctx), | ||
| 457 | TP_ARGS(ctrl_ctx) | ||
| 458 | ); | ||
| 459 | |||
| 460 | DEFINE_EVENT(xhci_log_ctrl_ctx, xhci_configure_endpoint_ctrl_ctx, | ||
| 461 | TP_PROTO(struct xhci_input_control_ctx *ctrl_ctx), | ||
| 462 | TP_ARGS(ctrl_ctx) | ||
| 463 | ); | ||
| 464 | |||
| 435 | DECLARE_EVENT_CLASS(xhci_log_ring, | 465 | DECLARE_EVENT_CLASS(xhci_log_ring, |
| 436 | TP_PROTO(struct xhci_ring *ring), | 466 | TP_PROTO(struct xhci_ring *ring), |
| 437 | TP_ARGS(ring), | 467 | TP_ARGS(ring), |
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 7fa58c99f126..a9bb796794e3 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c | |||
| @@ -893,7 +893,7 @@ static void xhci_disable_port_wake_on_bits(struct xhci_hcd *xhci) | |||
| 893 | struct xhci_port **ports; | 893 | struct xhci_port **ports; |
| 894 | int port_index; | 894 | int port_index; |
| 895 | unsigned long flags; | 895 | unsigned long flags; |
| 896 | u32 t1, t2; | 896 | u32 t1, t2, portsc; |
| 897 | 897 | ||
| 898 | spin_lock_irqsave(&xhci->lock, flags); | 898 | spin_lock_irqsave(&xhci->lock, flags); |
| 899 | 899 | ||
| @@ -902,10 +902,15 @@ static void xhci_disable_port_wake_on_bits(struct xhci_hcd *xhci) | |||
| 902 | ports = xhci->usb3_rhub.ports; | 902 | ports = xhci->usb3_rhub.ports; |
| 903 | while (port_index--) { | 903 | while (port_index--) { |
| 904 | t1 = readl(ports[port_index]->addr); | 904 | t1 = readl(ports[port_index]->addr); |
| 905 | portsc = t1; | ||
| 905 | t1 = xhci_port_state_to_neutral(t1); | 906 | t1 = xhci_port_state_to_neutral(t1); |
| 906 | t2 = t1 & ~PORT_WAKE_BITS; | 907 | t2 = t1 & ~PORT_WAKE_BITS; |
| 907 | if (t1 != t2) | 908 | if (t1 != t2) { |
| 908 | writel(t2, ports[port_index]->addr); | 909 | writel(t2, ports[port_index]->addr); |
| 910 | xhci_dbg(xhci, "disable wake bits port %d-%d, portsc: 0x%x, write: 0x%x\n", | ||
| 911 | xhci->usb3_rhub.hcd->self.busnum, | ||
| 912 | port_index + 1, portsc, t2); | ||
| 913 | } | ||
| 909 | } | 914 | } |
| 910 | 915 | ||
| 911 | /* disable usb2 ports Wake bits */ | 916 | /* disable usb2 ports Wake bits */ |
| @@ -913,12 +918,16 @@ static void xhci_disable_port_wake_on_bits(struct xhci_hcd *xhci) | |||
| 913 | ports = xhci->usb2_rhub.ports; | 918 | ports = xhci->usb2_rhub.ports; |
| 914 | while (port_index--) { | 919 | while (port_index--) { |
| 915 | t1 = readl(ports[port_index]->addr); | 920 | t1 = readl(ports[port_index]->addr); |
| 921 | portsc = t1; | ||
| 916 | t1 = xhci_port_state_to_neutral(t1); | 922 | t1 = xhci_port_state_to_neutral(t1); |
| 917 | t2 = t1 & ~PORT_WAKE_BITS; | 923 | t2 = t1 & ~PORT_WAKE_BITS; |
| 918 | if (t1 != t2) | 924 | if (t1 != t2) { |
| 919 | writel(t2, ports[port_index]->addr); | 925 | writel(t2, ports[port_index]->addr); |
| 926 | xhci_dbg(xhci, "disable wake bits port %d-%d, portsc: 0x%x, write: 0x%x\n", | ||
| 927 | xhci->usb2_rhub.hcd->self.busnum, | ||
| 928 | port_index + 1, portsc, t2); | ||
| 929 | } | ||
| 920 | } | 930 | } |
| 921 | |||
| 922 | spin_unlock_irqrestore(&xhci->lock, flags); | 931 | spin_unlock_irqrestore(&xhci->lock, flags); |
| 923 | } | 932 | } |
| 924 | 933 | ||
| @@ -1238,6 +1247,21 @@ EXPORT_SYMBOL_GPL(xhci_resume); | |||
| 1238 | 1247 | ||
| 1239 | /*-------------------------------------------------------------------------*/ | 1248 | /*-------------------------------------------------------------------------*/ |
| 1240 | 1249 | ||
| 1250 | /* | ||
| 1251 | * Bypass the DMA mapping if URB is suitable for Immediate Transfer (IDT), | ||
| 1252 | * we'll copy the actual data into the TRB address register. This is limited to | ||
| 1253 | * transfers up to 8 bytes on output endpoints of any kind with wMaxPacketSize | ||
| 1254 | * >= 8 bytes. If suitable for IDT only one Transfer TRB per TD is allowed. | ||
| 1255 | */ | ||
| 1256 | static int xhci_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, | ||
| 1257 | gfp_t mem_flags) | ||
| 1258 | { | ||
| 1259 | if (xhci_urb_suitable_for_idt(urb)) | ||
| 1260 | return 0; | ||
| 1261 | |||
| 1262 | return usb_hcd_map_urb_for_dma(hcd, urb, mem_flags); | ||
| 1263 | } | ||
| 1264 | |||
| 1241 | /** | 1265 | /** |
| 1242 | * xhci_get_endpoint_index - Used for passing endpoint bitmasks between the core and | 1266 | * xhci_get_endpoint_index - Used for passing endpoint bitmasks between the core and |
| 1243 | * HCDs. Find the index for an endpoint given its descriptor. Use the return | 1267 | * HCDs. Find the index for an endpoint given its descriptor. Use the return |
| @@ -1783,6 +1807,7 @@ static int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, | |||
| 1783 | struct xhci_container_ctx *in_ctx; | 1807 | struct xhci_container_ctx *in_ctx; |
| 1784 | unsigned int ep_index; | 1808 | unsigned int ep_index; |
| 1785 | struct xhci_input_control_ctx *ctrl_ctx; | 1809 | struct xhci_input_control_ctx *ctrl_ctx; |
| 1810 | struct xhci_ep_ctx *ep_ctx; | ||
| 1786 | u32 added_ctxs; | 1811 | u32 added_ctxs; |
| 1787 | u32 new_add_flags, new_drop_flags; | 1812 | u32 new_add_flags, new_drop_flags; |
| 1788 | struct xhci_virt_device *virt_dev; | 1813 | struct xhci_virt_device *virt_dev; |
| @@ -1873,6 +1898,9 @@ static int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, | |||
| 1873 | /* Store the usb_device pointer for later use */ | 1898 | /* Store the usb_device pointer for later use */ |
| 1874 | ep->hcpriv = udev; | 1899 | ep->hcpriv = udev; |
| 1875 | 1900 | ||
| 1901 | ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index); | ||
| 1902 | trace_xhci_add_endpoint(ep_ctx); | ||
| 1903 | |||
| 1876 | xhci_debugfs_create_endpoint(xhci, virt_dev, ep_index); | 1904 | xhci_debugfs_create_endpoint(xhci, virt_dev, ep_index); |
| 1877 | 1905 | ||
| 1878 | xhci_dbg(xhci, "add ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x\n", | 1906 | xhci_dbg(xhci, "add ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x\n", |
| @@ -2747,6 +2775,8 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, | |||
| 2747 | } | 2775 | } |
| 2748 | 2776 | ||
| 2749 | slot_ctx = xhci_get_slot_ctx(xhci, command->in_ctx); | 2777 | slot_ctx = xhci_get_slot_ctx(xhci, command->in_ctx); |
| 2778 | |||
| 2779 | trace_xhci_configure_endpoint_ctrl_ctx(ctrl_ctx); | ||
| 2750 | trace_xhci_configure_endpoint(slot_ctx); | 2780 | trace_xhci_configure_endpoint(slot_ctx); |
| 2751 | 2781 | ||
| 2752 | if (!ctx_change) | 2782 | if (!ctx_change) |
| @@ -4012,6 +4042,7 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev, | |||
| 4012 | trace_xhci_address_ctx(xhci, virt_dev->in_ctx, | 4042 | trace_xhci_address_ctx(xhci, virt_dev->in_ctx, |
| 4013 | le32_to_cpu(slot_ctx->dev_info) >> 27); | 4043 | le32_to_cpu(slot_ctx->dev_info) >> 27); |
| 4014 | 4044 | ||
| 4045 | trace_xhci_address_ctrl_ctx(ctrl_ctx); | ||
| 4015 | spin_lock_irqsave(&xhci->lock, flags); | 4046 | spin_lock_irqsave(&xhci->lock, flags); |
| 4016 | trace_xhci_setup_device(virt_dev); | 4047 | trace_xhci_setup_device(virt_dev); |
| 4017 | ret = xhci_queue_address_device(xhci, command, virt_dev->in_ctx->dma, | 4048 | ret = xhci_queue_address_device(xhci, command, virt_dev->in_ctx->dma, |
| @@ -5154,6 +5185,7 @@ static const struct hc_driver xhci_hc_driver = { | |||
| 5154 | /* | 5185 | /* |
| 5155 | * managing i/o requests and associated device resources | 5186 | * managing i/o requests and associated device resources |
| 5156 | */ | 5187 | */ |
| 5188 | .map_urb_for_dma = xhci_map_urb_for_dma, | ||
| 5157 | .urb_enqueue = xhci_urb_enqueue, | 5189 | .urb_enqueue = xhci_urb_enqueue, |
| 5158 | .urb_dequeue = xhci_urb_dequeue, | 5190 | .urb_dequeue = xhci_urb_dequeue, |
| 5159 | .alloc_dev = xhci_alloc_dev, | 5191 | .alloc_dev = xhci_alloc_dev, |
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 9334cdee382a..a450a99e90eb 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h | |||
| @@ -1303,6 +1303,8 @@ enum xhci_setup_dev { | |||
| 1303 | #define TRB_IOC (1<<5) | 1303 | #define TRB_IOC (1<<5) |
| 1304 | /* The buffer pointer contains immediate data */ | 1304 | /* The buffer pointer contains immediate data */ |
| 1305 | #define TRB_IDT (1<<6) | 1305 | #define TRB_IDT (1<<6) |
| 1306 | /* TDs smaller than this might use IDT */ | ||
| 1307 | #define TRB_IDT_MAX_SIZE 8 | ||
| 1306 | 1308 | ||
| 1307 | /* Block Event Interrupt */ | 1309 | /* Block Event Interrupt */ |
| 1308 | #define TRB_BEI (1<<9) | 1310 | #define TRB_BEI (1<<9) |
| @@ -2149,6 +2151,21 @@ static inline struct xhci_ring *xhci_urb_to_transfer_ring(struct xhci_hcd *xhci, | |||
| 2149 | urb->stream_id); | 2151 | urb->stream_id); |
| 2150 | } | 2152 | } |
| 2151 | 2153 | ||
| 2154 | /* | ||
| 2155 | * TODO: As per spec Isochronous IDT transmissions are supported. We bypass | ||
| 2156 | * them anyways as we where unable to find a device that matches the | ||
| 2157 | * constraints. | ||
| 2158 | */ | ||
| 2159 | static inline bool xhci_urb_suitable_for_idt(struct urb *urb) | ||
| 2160 | { | ||
| 2161 | if (!usb_endpoint_xfer_isoc(&urb->ep->desc) && usb_urb_dir_out(urb) && | ||
| 2162 | usb_endpoint_maxp(&urb->ep->desc) >= TRB_IDT_MAX_SIZE && | ||
| 2163 | urb->transfer_buffer_length <= TRB_IDT_MAX_SIZE) | ||
| 2164 | return true; | ||
| 2165 | |||
| 2166 | return false; | ||
| 2167 | } | ||
| 2168 | |||
| 2152 | static inline char *xhci_slot_state_string(u32 state) | 2169 | static inline char *xhci_slot_state_string(u32 state) |
| 2153 | { | 2170 | { |
| 2154 | switch (state) { | 2171 | switch (state) { |
| @@ -2384,6 +2401,35 @@ static inline const char *xhci_decode_trb(u32 field0, u32 field1, u32 field2, | |||
| 2384 | return str; | 2401 | return str; |
| 2385 | } | 2402 | } |
| 2386 | 2403 | ||
| 2404 | static inline const char *xhci_decode_ctrl_ctx(unsigned long drop, | ||
| 2405 | unsigned long add) | ||
| 2406 | { | ||
| 2407 | static char str[1024]; | ||
| 2408 | unsigned int bit; | ||
| 2409 | int ret = 0; | ||
| 2410 | |||
| 2411 | if (drop) { | ||
| 2412 | ret = sprintf(str, "Drop:"); | ||
| 2413 | for_each_set_bit(bit, &drop, 32) | ||
| 2414 | ret += sprintf(str + ret, " %d%s", | ||
| 2415 | bit / 2, | ||
| 2416 | bit % 2 ? "in":"out"); | ||
| 2417 | ret += sprintf(str + ret, ", "); | ||
| 2418 | } | ||
| 2419 | |||
| 2420 | if (add) { | ||
| 2421 | ret += sprintf(str + ret, "Add:%s%s", | ||
| 2422 | (add & SLOT_FLAG) ? " slot":"", | ||
| 2423 | (add & EP0_FLAG) ? " ep0":""); | ||
| 2424 | add &= ~(SLOT_FLAG | EP0_FLAG); | ||
| 2425 | for_each_set_bit(bit, &add, 32) | ||
| 2426 | ret += sprintf(str + ret, " %d%s", | ||
| 2427 | bit / 2, | ||
| 2428 | bit % 2 ? "in":"out"); | ||
| 2429 | } | ||
| 2430 | return str; | ||
| 2431 | } | ||
| 2432 | |||
| 2387 | static inline const char *xhci_decode_slot_context(u32 info, u32 info2, | 2433 | static inline const char *xhci_decode_slot_context(u32 info, u32 info2, |
| 2388 | u32 tt_info, u32 state) | 2434 | u32 tt_info, u32 state) |
| 2389 | { | 2435 | { |
diff --git a/drivers/usb/isp1760/isp1760-hcd.c b/drivers/usb/isp1760/isp1760-hcd.c index 8142c6b4c4cf..320fc4739835 100644 --- a/drivers/usb/isp1760/isp1760-hcd.c +++ b/drivers/usb/isp1760/isp1760-hcd.c | |||
| @@ -788,11 +788,11 @@ static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh, | |||
| 788 | mem_reads8(hcd->regs, qtd->payload_addr, | 788 | mem_reads8(hcd->regs, qtd->payload_addr, |
| 789 | qtd->data_buffer, | 789 | qtd->data_buffer, |
| 790 | qtd->actual_length); | 790 | qtd->actual_length); |
| 791 | /* Fall through (?) */ | 791 | /* Fall through */ |
| 792 | case OUT_PID: | 792 | case OUT_PID: |
| 793 | qtd->urb->actual_length += | 793 | qtd->urb->actual_length += |
| 794 | qtd->actual_length; | 794 | qtd->actual_length; |
| 795 | /* Fall through ... */ | 795 | /* Fall through */ |
| 796 | case SETUP_PID: | 796 | case SETUP_PID: |
| 797 | break; | 797 | break; |
| 798 | } | 798 | } |
diff --git a/drivers/usb/misc/usb251xb.c b/drivers/usb/misc/usb251xb.c index 04684849d683..4d6ae3795a88 100644 --- a/drivers/usb/misc/usb251xb.c +++ b/drivers/usb/misc/usb251xb.c | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | 12 | ||
| 13 | #include <linux/delay.h> | 13 | #include <linux/delay.h> |
| 14 | #include <linux/gpio/consumer.h> | 14 | #include <linux/gpio/consumer.h> |
| 15 | #include <linux/gpio/driver.h> | ||
| 15 | #include <linux/i2c.h> | 16 | #include <linux/i2c.h> |
| 16 | #include <linux/module.h> | 17 | #include <linux/module.h> |
| 17 | #include <linux/nls.h> | 18 | #include <linux/nls.h> |
| @@ -222,11 +223,51 @@ static const struct usb251xb_data usb2517i_data = { | |||
| 222 | .product_str = "USB2517i", | 223 | .product_str = "USB2517i", |
| 223 | }; | 224 | }; |
| 224 | 225 | ||
| 226 | #ifdef CONFIG_GPIOLIB | ||
| 227 | static int usb251xb_check_dev_children(struct device *dev, void *child) | ||
| 228 | { | ||
| 229 | if (dev->type == &i2c_adapter_type) { | ||
| 230 | return device_for_each_child(dev, child, | ||
| 231 | usb251xb_check_dev_children); | ||
| 232 | } | ||
| 233 | |||
| 234 | return (dev == child); | ||
| 235 | } | ||
| 236 | |||
| 237 | static int usb251x_check_gpio_chip(struct usb251xb *hub) | ||
| 238 | { | ||
| 239 | struct gpio_chip *gc = gpiod_to_chip(hub->gpio_reset); | ||
| 240 | struct i2c_adapter *adap = hub->i2c->adapter; | ||
| 241 | int ret; | ||
| 242 | |||
| 243 | if (!hub->gpio_reset) | ||
| 244 | return 0; | ||
| 245 | |||
| 246 | if (!gc) | ||
| 247 | return -EINVAL; | ||
| 248 | |||
| 249 | ret = usb251xb_check_dev_children(&adap->dev, gc->parent); | ||
| 250 | if (ret) { | ||
| 251 | dev_err(hub->dev, "Reset GPIO chip is at the same i2c-bus\n"); | ||
| 252 | return -EINVAL; | ||
| 253 | } | ||
| 254 | |||
| 255 | return 0; | ||
| 256 | } | ||
| 257 | #else | ||
| 258 | static int usb251x_check_gpio_chip(struct usb251xb *hub) | ||
| 259 | { | ||
| 260 | return 0; | ||
| 261 | } | ||
| 262 | #endif | ||
| 263 | |||
| 225 | static void usb251xb_reset(struct usb251xb *hub, int state) | 264 | static void usb251xb_reset(struct usb251xb *hub, int state) |
| 226 | { | 265 | { |
| 227 | if (!hub->gpio_reset) | 266 | if (!hub->gpio_reset) |
| 228 | return; | 267 | return; |
| 229 | 268 | ||
| 269 | i2c_lock_bus(hub->i2c->adapter, I2C_LOCK_SEGMENT); | ||
| 270 | |||
| 230 | gpiod_set_value_cansleep(hub->gpio_reset, state); | 271 | gpiod_set_value_cansleep(hub->gpio_reset, state); |
| 231 | 272 | ||
| 232 | /* wait for hub recovery/stabilization */ | 273 | /* wait for hub recovery/stabilization */ |
| @@ -234,6 +275,8 @@ static void usb251xb_reset(struct usb251xb *hub, int state) | |||
| 234 | usleep_range(500, 750); /* >=500us at power on */ | 275 | usleep_range(500, 750); /* >=500us at power on */ |
| 235 | else | 276 | else |
| 236 | usleep_range(1, 10); /* >=1us at power down */ | 277 | usleep_range(1, 10); /* >=1us at power down */ |
| 278 | |||
| 279 | i2c_unlock_bus(hub->i2c->adapter, I2C_LOCK_SEGMENT); | ||
| 237 | } | 280 | } |
| 238 | 281 | ||
| 239 | static int usb251xb_connect(struct usb251xb *hub) | 282 | static int usb251xb_connect(struct usb251xb *hub) |
| @@ -331,18 +374,31 @@ out_err: | |||
| 331 | } | 374 | } |
| 332 | 375 | ||
| 333 | #ifdef CONFIG_OF | 376 | #ifdef CONFIG_OF |
| 377 | static void usb251xb_get_ports_field(struct usb251xb *hub, | ||
| 378 | const char *prop_name, u8 port_cnt, u8 *fld) | ||
| 379 | { | ||
| 380 | struct device *dev = hub->dev; | ||
| 381 | struct property *prop; | ||
| 382 | const __be32 *p; | ||
| 383 | u32 port; | ||
| 384 | |||
| 385 | of_property_for_each_u32(dev->of_node, prop_name, prop, p, port) { | ||
| 386 | if ((port >= 1) && (port <= port_cnt)) | ||
| 387 | *fld |= BIT(port); | ||
| 388 | else | ||
| 389 | dev_warn(dev, "port %u doesn't exist\n", port); | ||
| 390 | } | ||
| 391 | } | ||
| 392 | |||
| 334 | static int usb251xb_get_ofdata(struct usb251xb *hub, | 393 | static int usb251xb_get_ofdata(struct usb251xb *hub, |
| 335 | struct usb251xb_data *data) | 394 | struct usb251xb_data *data) |
| 336 | { | 395 | { |
| 337 | struct device *dev = hub->dev; | 396 | struct device *dev = hub->dev; |
| 338 | struct device_node *np = dev->of_node; | 397 | struct device_node *np = dev->of_node; |
| 339 | int len, err, i; | 398 | int len, err; |
| 340 | u32 port, property_u32 = 0; | 399 | u32 property_u32 = 0; |
| 341 | const u32 *cproperty_u32; | ||
| 342 | const char *cproperty_char; | 400 | const char *cproperty_char; |
| 343 | char str[USB251XB_STRING_BUFSIZE / 2]; | 401 | char str[USB251XB_STRING_BUFSIZE / 2]; |
| 344 | struct property *prop; | ||
| 345 | const __be32 *p; | ||
| 346 | 402 | ||
| 347 | if (!np) { | 403 | if (!np) { |
| 348 | dev_err(dev, "failed to get ofdata\n"); | 404 | dev_err(dev, "failed to get ofdata\n"); |
| @@ -444,46 +500,16 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, | |||
| 444 | hub->conf_data3 |= BIT(0); | 500 | hub->conf_data3 |= BIT(0); |
| 445 | 501 | ||
| 446 | hub->non_rem_dev = USB251XB_DEF_NON_REMOVABLE_DEVICES; | 502 | hub->non_rem_dev = USB251XB_DEF_NON_REMOVABLE_DEVICES; |
| 447 | cproperty_u32 = of_get_property(np, "non-removable-ports", &len); | 503 | usb251xb_get_ports_field(hub, "non-removable-ports", data->port_cnt, |
| 448 | if (cproperty_u32 && (len / sizeof(u32)) > 0) { | 504 | &hub->non_rem_dev); |
| 449 | for (i = 0; i < len / sizeof(u32); i++) { | ||
| 450 | u32 port = be32_to_cpu(cproperty_u32[i]); | ||
| 451 | |||
| 452 | if ((port >= 1) && (port <= data->port_cnt)) | ||
| 453 | hub->non_rem_dev |= BIT(port); | ||
| 454 | else | ||
| 455 | dev_warn(dev, "NRD port %u doesn't exist\n", | ||
| 456 | port); | ||
| 457 | } | ||
| 458 | } | ||
| 459 | 505 | ||
| 460 | hub->port_disable_sp = USB251XB_DEF_PORT_DISABLE_SELF; | 506 | hub->port_disable_sp = USB251XB_DEF_PORT_DISABLE_SELF; |
| 461 | cproperty_u32 = of_get_property(np, "sp-disabled-ports", &len); | 507 | usb251xb_get_ports_field(hub, "sp-disabled-ports", data->port_cnt, |
| 462 | if (cproperty_u32 && (len / sizeof(u32)) > 0) { | 508 | &hub->port_disable_sp); |
| 463 | for (i = 0; i < len / sizeof(u32); i++) { | ||
| 464 | u32 port = be32_to_cpu(cproperty_u32[i]); | ||
| 465 | |||
| 466 | if ((port >= 1) && (port <= data->port_cnt)) | ||
| 467 | hub->port_disable_sp |= BIT(port); | ||
| 468 | else | ||
| 469 | dev_warn(dev, "PDS port %u doesn't exist\n", | ||
| 470 | port); | ||
| 471 | } | ||
| 472 | } | ||
| 473 | 509 | ||
| 474 | hub->port_disable_bp = USB251XB_DEF_PORT_DISABLE_BUS; | 510 | hub->port_disable_bp = USB251XB_DEF_PORT_DISABLE_BUS; |
| 475 | cproperty_u32 = of_get_property(np, "bp-disabled-ports", &len); | 511 | usb251xb_get_ports_field(hub, "bp-disabled-ports", data->port_cnt, |
| 476 | if (cproperty_u32 && (len / sizeof(u32)) > 0) { | 512 | &hub->port_disable_bp); |
| 477 | for (i = 0; i < len / sizeof(u32); i++) { | ||
| 478 | u32 port = be32_to_cpu(cproperty_u32[i]); | ||
| 479 | |||
| 480 | if ((port >= 1) && (port <= data->port_cnt)) | ||
| 481 | hub->port_disable_bp |= BIT(port); | ||
| 482 | else | ||
| 483 | dev_warn(dev, "PDB port %u doesn't exist\n", | ||
| 484 | port); | ||
| 485 | } | ||
| 486 | } | ||
| 487 | 513 | ||
| 488 | hub->max_power_sp = USB251XB_DEF_MAX_POWER_SELF; | 514 | hub->max_power_sp = USB251XB_DEF_MAX_POWER_SELF; |
| 489 | if (!of_property_read_u32(np, "sp-max-total-current-microamp", | 515 | if (!of_property_read_u32(np, "sp-max-total-current-microamp", |
| @@ -546,10 +572,10 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, | |||
| 546 | * register controls the USB DP/DM signal swapping for each port. | 572 | * register controls the USB DP/DM signal swapping for each port. |
| 547 | */ | 573 | */ |
| 548 | hub->port_swap = USB251XB_DEF_PORT_SWAP; | 574 | hub->port_swap = USB251XB_DEF_PORT_SWAP; |
| 549 | of_property_for_each_u32(np, "swap-dx-lanes", prop, p, port) { | 575 | usb251xb_get_ports_field(hub, "swap-dx-lanes", data->port_cnt, |
| 550 | if (port <= data->port_cnt) | 576 | &hub->port_swap); |
| 551 | hub->port_swap |= BIT(port); | 577 | if (of_get_property(np, "swap-us-lanes", NULL)) |
| 552 | } | 578 | hub->port_swap |= BIT(0); |
| 553 | 579 | ||
| 554 | /* The following parameters are currently not exposed to devicetree, but | 580 | /* The following parameters are currently not exposed to devicetree, but |
| 555 | * may be as soon as needed. | 581 | * may be as soon as needed. |
| @@ -621,6 +647,25 @@ static int usb251xb_probe(struct usb251xb *hub) | |||
| 621 | } | 647 | } |
| 622 | } | 648 | } |
| 623 | 649 | ||
| 650 | /* | ||
| 651 | * usb251x SMBus-slave SCL lane is muxed with CFG_SEL0 pin. So if anyone | ||
| 652 | * tries to work with the bus at the moment the hub reset is released, | ||
| 653 | * it may cause an invalid config being latched by usb251x. Particularly | ||
| 654 | * one of the config modes makes the hub loading a default registers | ||
| 655 | * value without SMBus-slave interface activation. If the hub | ||
| 656 | * accidentally gets this mode, this will cause the driver SMBus- | ||
| 657 | * functions failure. Normally we could just lock the SMBus-segment the | ||
| 658 | * hub i2c-interface resides for the device-specific reset timing. But | ||
| 659 | * the GPIO controller, which is used to handle the hub reset, might be | ||
| 660 | * placed at the same i2c-bus segment. In this case an error should be | ||
| 661 | * returned since we can't safely use the GPIO controller to clear the | ||
| 662 | * reset state (it may affect the hub configuration) and we can't lock | ||
| 663 | * the i2c-bus segment (it will cause a deadlock). | ||
| 664 | */ | ||
| 665 | err = usb251x_check_gpio_chip(hub); | ||
| 666 | if (err) | ||
| 667 | return err; | ||
| 668 | |||
| 624 | err = usb251xb_connect(hub); | 669 | err = usb251xb_connect(hub); |
| 625 | if (err) { | 670 | if (err) { |
| 626 | dev_err(dev, "Failed to connect hub (%d)\n", err); | 671 | dev_err(dev, "Failed to connect hub (%d)\n", err); |
diff --git a/drivers/usb/misc/usb3503.c b/drivers/usb/misc/usb3503.c index d5141aa79dd4..72f39a9751b5 100644 --- a/drivers/usb/misc/usb3503.c +++ b/drivers/usb/misc/usb3503.c | |||
| @@ -172,7 +172,6 @@ static int usb3503_probe(struct usb3503 *hub) | |||
| 172 | hub->gpio_reset = pdata->gpio_reset; | 172 | hub->gpio_reset = pdata->gpio_reset; |
| 173 | hub->mode = pdata->initial_mode; | 173 | hub->mode = pdata->initial_mode; |
| 174 | } else if (np) { | 174 | } else if (np) { |
| 175 | struct clk *clk; | ||
| 176 | u32 rate = 0; | 175 | u32 rate = 0; |
| 177 | hub->port_off_mask = 0; | 176 | hub->port_off_mask = 0; |
| 178 | 177 | ||
| @@ -198,34 +197,29 @@ static int usb3503_probe(struct usb3503 *hub) | |||
| 198 | } | 197 | } |
| 199 | } | 198 | } |
| 200 | 199 | ||
| 201 | clk = devm_clk_get(dev, "refclk"); | 200 | hub->clk = devm_clk_get_optional(dev, "refclk"); |
| 202 | if (IS_ERR(clk) && PTR_ERR(clk) != -ENOENT) { | 201 | if (IS_ERR(hub->clk)) { |
| 203 | dev_err(dev, "unable to request refclk (%ld)\n", | 202 | dev_err(dev, "unable to request refclk (%ld)\n", |
| 204 | PTR_ERR(clk)); | 203 | PTR_ERR(hub->clk)); |
| 205 | return PTR_ERR(clk); | 204 | return PTR_ERR(hub->clk); |
| 206 | } | 205 | } |
| 207 | 206 | ||
| 208 | if (!IS_ERR(clk)) { | 207 | if (rate != 0) { |
| 209 | hub->clk = clk; | 208 | err = clk_set_rate(hub->clk, rate); |
| 210 | |||
| 211 | if (rate != 0) { | ||
| 212 | err = clk_set_rate(hub->clk, rate); | ||
| 213 | if (err) { | ||
| 214 | dev_err(dev, | ||
| 215 | "unable to set reference clock rate to %d\n", | ||
| 216 | (int) rate); | ||
| 217 | return err; | ||
| 218 | } | ||
| 219 | } | ||
| 220 | |||
| 221 | err = clk_prepare_enable(hub->clk); | ||
| 222 | if (err) { | 209 | if (err) { |
| 223 | dev_err(dev, | 210 | dev_err(dev, |
| 224 | "unable to enable reference clock\n"); | 211 | "unable to set reference clock rate to %d\n", |
| 212 | (int)rate); | ||
| 225 | return err; | 213 | return err; |
| 226 | } | 214 | } |
| 227 | } | 215 | } |
| 228 | 216 | ||
| 217 | err = clk_prepare_enable(hub->clk); | ||
| 218 | if (err) { | ||
| 219 | dev_err(dev, "unable to enable reference clock\n"); | ||
| 220 | return err; | ||
| 221 | } | ||
| 222 | |||
| 229 | property = of_get_property(np, "disabled-ports", &len); | 223 | property = of_get_property(np, "disabled-ports", &len); |
| 230 | if (property && (len / sizeof(u32)) > 0) { | 224 | if (property && (len / sizeof(u32)) > 0) { |
| 231 | int i; | 225 | int i; |
| @@ -324,8 +318,7 @@ static int usb3503_i2c_remove(struct i2c_client *i2c) | |||
| 324 | struct usb3503 *hub; | 318 | struct usb3503 *hub; |
| 325 | 319 | ||
| 326 | hub = i2c_get_clientdata(i2c); | 320 | hub = i2c_get_clientdata(i2c); |
| 327 | if (hub->clk) | 321 | clk_disable_unprepare(hub->clk); |
| 328 | clk_disable_unprepare(hub->clk); | ||
| 329 | 322 | ||
| 330 | return 0; | 323 | return 0; |
| 331 | } | 324 | } |
| @@ -348,8 +341,7 @@ static int usb3503_platform_remove(struct platform_device *pdev) | |||
| 348 | struct usb3503 *hub; | 341 | struct usb3503 *hub; |
| 349 | 342 | ||
| 350 | hub = platform_get_drvdata(pdev); | 343 | hub = platform_get_drvdata(pdev); |
| 351 | if (hub->clk) | 344 | clk_disable_unprepare(hub->clk); |
| 352 | clk_disable_unprepare(hub->clk); | ||
| 353 | 345 | ||
| 354 | return 0; | 346 | return 0; |
| 355 | } | 347 | } |
| @@ -358,18 +350,14 @@ static int usb3503_platform_remove(struct platform_device *pdev) | |||
| 358 | static int usb3503_suspend(struct usb3503 *hub) | 350 | static int usb3503_suspend(struct usb3503 *hub) |
| 359 | { | 351 | { |
| 360 | usb3503_switch_mode(hub, USB3503_MODE_STANDBY); | 352 | usb3503_switch_mode(hub, USB3503_MODE_STANDBY); |
| 361 | 353 | clk_disable_unprepare(hub->clk); | |
| 362 | if (hub->clk) | ||
| 363 | clk_disable_unprepare(hub->clk); | ||
| 364 | 354 | ||
| 365 | return 0; | 355 | return 0; |
| 366 | } | 356 | } |
| 367 | 357 | ||
| 368 | static int usb3503_resume(struct usb3503 *hub) | 358 | static int usb3503_resume(struct usb3503 *hub) |
| 369 | { | 359 | { |
| 370 | if (hub->clk) | 360 | clk_prepare_enable(hub->clk); |
| 371 | clk_prepare_enable(hub->clk); | ||
| 372 | |||
| 373 | usb3503_switch_mode(hub, hub->mode); | 361 | usb3503_switch_mode(hub, hub->mode); |
| 374 | 362 | ||
| 375 | return 0; | 363 | return 0; |
diff --git a/drivers/usb/mtu3/Makefile b/drivers/usb/mtu3/Makefile index 4a9715812bf9..3bf8cbcc1add 100644 --- a/drivers/usb/mtu3/Makefile +++ b/drivers/usb/mtu3/Makefile | |||
| @@ -2,10 +2,17 @@ | |||
| 2 | 2 | ||
| 3 | ccflags-$(CONFIG_USB_MTU3_DEBUG) += -DDEBUG | 3 | ccflags-$(CONFIG_USB_MTU3_DEBUG) += -DDEBUG |
| 4 | 4 | ||
| 5 | # define_trace.h needs to know how to find our header | ||
| 6 | CFLAGS_mtu3_trace.o := -I$(src) | ||
| 7 | |||
| 5 | obj-$(CONFIG_USB_MTU3) += mtu3.o | 8 | obj-$(CONFIG_USB_MTU3) += mtu3.o |
| 6 | 9 | ||
| 7 | mtu3-y := mtu3_plat.o | 10 | mtu3-y := mtu3_plat.o |
| 8 | 11 | ||
| 12 | ifneq ($(CONFIG_TRACING),) | ||
| 13 | mtu3-y += mtu3_trace.o | ||
| 14 | endif | ||
| 15 | |||
| 9 | ifneq ($(filter y,$(CONFIG_USB_MTU3_HOST) $(CONFIG_USB_MTU3_DUAL_ROLE)),) | 16 | ifneq ($(filter y,$(CONFIG_USB_MTU3_HOST) $(CONFIG_USB_MTU3_DUAL_ROLE)),) |
| 10 | mtu3-y += mtu3_host.o | 17 | mtu3-y += mtu3_host.o |
| 11 | endif | 18 | endif |
| @@ -17,3 +24,7 @@ endif | |||
| 17 | ifneq ($(CONFIG_USB_MTU3_DUAL_ROLE),) | 24 | ifneq ($(CONFIG_USB_MTU3_DUAL_ROLE),) |
| 18 | mtu3-y += mtu3_dr.o | 25 | mtu3-y += mtu3_dr.o |
| 19 | endif | 26 | endif |
| 27 | |||
| 28 | ifneq ($(CONFIG_DEBUG_FS),) | ||
| 29 | mtu3-y += mtu3_debugfs.o | ||
| 30 | endif | ||
diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h index 87823ac0d120..76ecf12fdf62 100644 --- a/drivers/usb/mtu3/mtu3.h +++ b/drivers/usb/mtu3/mtu3.h | |||
| @@ -63,6 +63,15 @@ struct mtu3_request; | |||
| 63 | #define MTU3_U2_IP_SLOT_DEFAULT 1 | 63 | #define MTU3_U2_IP_SLOT_DEFAULT 1 |
| 64 | 64 | ||
| 65 | /** | 65 | /** |
| 66 | * IP TRUNK version | ||
| 67 | * from 0x1003 version, USB3 Gen2 is supported, two changes affect driver: | ||
| 68 | * 1. MAXPKT and MULTI bits layout of TXCSR1 and RXCSR1 are adjusted, | ||
| 69 | * but not backward compatible | ||
| 70 | * 2. QMU extend buffer length supported | ||
| 71 | */ | ||
| 72 | #define MTU3_TRUNK_VERS_1003 0x1003 | ||
| 73 | |||
| 74 | /** | ||
| 66 | * Normally the device works on HS or SS, to simplify fifo management, | 75 | * Normally the device works on HS or SS, to simplify fifo management, |
| 67 | * devide fifo into some 512B parts, use bitmap to manage it; And | 76 | * devide fifo into some 512B parts, use bitmap to manage it; And |
| 68 | * 128 bits size of bitmap is large enough, that means it can manage | 77 | * 128 bits size of bitmap is large enough, that means it can manage |
| @@ -135,45 +144,33 @@ struct mtu3_fifo_info { | |||
| 135 | * The format of TX GPD is a little different from RX one. | 144 | * The format of TX GPD is a little different from RX one. |
| 136 | * And the size of GPD is 16 bytes. | 145 | * And the size of GPD is 16 bytes. |
| 137 | * | 146 | * |
| 138 | * @flag: | 147 | * @dw0_info: |
| 139 | * bit0: Hardware Own (HWO) | 148 | * bit0: Hardware Own (HWO) |
| 140 | * bit1: Buffer Descriptor Present (BDP), always 0, BD is not supported | 149 | * bit1: Buffer Descriptor Present (BDP), always 0, BD is not supported |
| 141 | * bit2: Bypass (BPS), 1: HW skips this GPD if HWO = 1 | 150 | * bit2: Bypass (BPS), 1: HW skips this GPD if HWO = 1 |
| 151 | * bit6: [EL] Zero Length Packet (ZLP), moved from @dw3_info[29] | ||
| 142 | * bit7: Interrupt On Completion (IOC) | 152 | * bit7: Interrupt On Completion (IOC) |
| 143 | * @chksum: This is used to validate the contents of this GPD; | 153 | * bit[31:16]: ([EL] bit[31:12]) allow data buffer length (RX ONLY), |
| 144 | * If TXQ_CS_EN / RXQ_CS_EN bit is set, an interrupt is issued | 154 | * the buffer length of the data to receive |
| 145 | * when checksum validation fails; | 155 | * bit[23:16]: ([EL] bit[31:24]) extension address (TX ONLY), |
| 146 | * Checksum value is calculated over the 16 bytes of the GPD by default; | 156 | * lower 4 bits are extension bits of @buffer, |
| 147 | * @data_buf_len (RX ONLY): This value indicates the length of | 157 | * upper 4 bits are extension bits of @next_gpd |
| 148 | * the assigned data buffer | ||
| 149 | * @tx_ext_addr (TX ONLY): [3:0] are 4 extension bits of @buffer, | ||
| 150 | * [7:4] are 4 extension bits of @next_gpd | ||
| 151 | * @next_gpd: Physical address of the next GPD | 158 | * @next_gpd: Physical address of the next GPD |
| 152 | * @buffer: Physical address of the data buffer | 159 | * @buffer: Physical address of the data buffer |
| 153 | * @buf_len: | 160 | * @dw3_info: |
| 154 | * (TX): This value indicates the length of the assigned data buffer | 161 | * bit[15:0]: ([EL] bit[19:0]) data buffer length, |
| 155 | * (RX): The total length of data received | 162 | * (TX): the buffer length of the data to transmit |
| 156 | * @ext_len: reserved | 163 | * (RX): The total length of data received |
| 157 | * @rx_ext_addr(RX ONLY): [3:0] are 4 extension bits of @buffer, | 164 | * bit[23:16]: ([EL] bit[31:24]) extension address (RX ONLY), |
| 158 | * [7:4] are 4 extension bits of @next_gpd | 165 | * lower 4 bits are extension bits of @buffer, |
| 159 | * @ext_flag: | 166 | * upper 4 bits are extension bits of @next_gpd |
| 160 | * bit5 (TX ONLY): Zero Length Packet (ZLP), | 167 | * bit29: ([EL] abandoned) Zero Length Packet (ZLP) (TX ONLY) |
| 161 | */ | 168 | */ |
| 162 | struct qmu_gpd { | 169 | struct qmu_gpd { |
| 163 | __u8 flag; | 170 | __le32 dw0_info; |
| 164 | __u8 chksum; | ||
| 165 | union { | ||
| 166 | __le16 data_buf_len; | ||
| 167 | __le16 tx_ext_addr; | ||
| 168 | }; | ||
| 169 | __le32 next_gpd; | 171 | __le32 next_gpd; |
| 170 | __le32 buffer; | 172 | __le32 buffer; |
| 171 | __le16 buf_len; | 173 | __le32 dw3_info; |
| 172 | union { | ||
| 173 | __u8 ext_len; | ||
| 174 | __u8 rx_ext_addr; | ||
| 175 | }; | ||
| 176 | __u8 ext_flag; | ||
| 177 | } __packed; | 174 | } __packed; |
| 178 | 175 | ||
| 179 | /** | 176 | /** |
| @@ -316,6 +313,7 @@ static inline struct ssusb_mtk *dev_to_ssusb(struct device *dev) | |||
| 316 | * @may_wakeup: means device's remote wakeup is enabled | 313 | * @may_wakeup: means device's remote wakeup is enabled |
| 317 | * @is_self_powered: is reported in device status and the config descriptor | 314 | * @is_self_powered: is reported in device status and the config descriptor |
| 318 | * @delayed_status: true when function drivers ask for delayed status | 315 | * @delayed_status: true when function drivers ask for delayed status |
| 316 | * @gen2cp: compatible with USB3 Gen2 IP | ||
| 319 | * @ep0_req: dummy request used while handling standard USB requests | 317 | * @ep0_req: dummy request used while handling standard USB requests |
| 320 | * for GET_STATUS and SET_SEL | 318 | * for GET_STATUS and SET_SEL |
| 321 | * @setup_buf: ep0 response buffer for GET_STATUS and SET_SEL requests | 319 | * @setup_buf: ep0 response buffer for GET_STATUS and SET_SEL requests |
| @@ -356,6 +354,7 @@ struct mtu3 { | |||
| 356 | unsigned u2_enable:1; | 354 | unsigned u2_enable:1; |
| 357 | unsigned is_u3_ip:1; | 355 | unsigned is_u3_ip:1; |
| 358 | unsigned delayed_status:1; | 356 | unsigned delayed_status:1; |
| 357 | unsigned gen2cp:1; | ||
| 359 | 358 | ||
| 360 | u8 address; | 359 | u8 address; |
| 361 | u8 test_mode_nr; | 360 | u8 test_mode_nr; |
diff --git a/drivers/usb/mtu3/mtu3_core.c b/drivers/usb/mtu3/mtu3_core.c index 4fee200795a5..f8bd1d57e795 100644 --- a/drivers/usb/mtu3/mtu3_core.c +++ b/drivers/usb/mtu3/mtu3_core.c | |||
| @@ -16,6 +16,8 @@ | |||
| 16 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
| 17 | 17 | ||
| 18 | #include "mtu3.h" | 18 | #include "mtu3.h" |
| 19 | #include "mtu3_debug.h" | ||
| 20 | #include "mtu3_trace.h" | ||
| 19 | 21 | ||
| 20 | static int ep_fifo_alloc(struct mtu3_ep *mep, u32 seg_size) | 22 | static int ep_fifo_alloc(struct mtu3_ep *mep, u32 seg_size) |
| 21 | { | 23 | { |
| @@ -299,6 +301,7 @@ int mtu3_config_ep(struct mtu3 *mtu, struct mtu3_ep *mep, | |||
| 299 | int interval, int burst, int mult) | 301 | int interval, int burst, int mult) |
| 300 | { | 302 | { |
| 301 | void __iomem *mbase = mtu->mac_base; | 303 | void __iomem *mbase = mtu->mac_base; |
| 304 | bool gen2cp = mtu->gen2cp; | ||
| 302 | int epnum = mep->epnum; | 305 | int epnum = mep->epnum; |
| 303 | u32 csr0, csr1, csr2; | 306 | u32 csr0, csr1, csr2; |
| 304 | int fifo_sgsz, fifo_addr; | 307 | int fifo_sgsz, fifo_addr; |
| @@ -319,7 +322,7 @@ int mtu3_config_ep(struct mtu3 *mtu, struct mtu3_ep *mep, | |||
| 319 | 322 | ||
| 320 | num_pkts = (burst + 1) * (mult + 1) - 1; | 323 | num_pkts = (burst + 1) * (mult + 1) - 1; |
| 321 | csr1 = TX_SS_BURST(burst) | TX_SLOT(mep->slot); | 324 | csr1 = TX_SS_BURST(burst) | TX_SLOT(mep->slot); |
| 322 | csr1 |= TX_MAX_PKT(num_pkts) | TX_MULT(mult); | 325 | csr1 |= TX_MAX_PKT(gen2cp, num_pkts) | TX_MULT(gen2cp, mult); |
| 323 | 326 | ||
| 324 | csr2 = TX_FIFOADDR(fifo_addr >> 4); | 327 | csr2 = TX_FIFOADDR(fifo_addr >> 4); |
| 325 | csr2 |= TX_FIFOSEGSIZE(fifo_sgsz); | 328 | csr2 |= TX_FIFOSEGSIZE(fifo_sgsz); |
| @@ -355,7 +358,7 @@ int mtu3_config_ep(struct mtu3 *mtu, struct mtu3_ep *mep, | |||
| 355 | 358 | ||
| 356 | num_pkts = (burst + 1) * (mult + 1) - 1; | 359 | num_pkts = (burst + 1) * (mult + 1) - 1; |
| 357 | csr1 = RX_SS_BURST(burst) | RX_SLOT(mep->slot); | 360 | csr1 = RX_SS_BURST(burst) | RX_SLOT(mep->slot); |
| 358 | csr1 |= RX_MAX_PKT(num_pkts) | RX_MULT(mult); | 361 | csr1 |= RX_MAX_PKT(gen2cp, num_pkts) | RX_MULT(gen2cp, mult); |
| 359 | 362 | ||
| 360 | csr2 = RX_FIFOADDR(fifo_addr >> 4); | 363 | csr2 = RX_FIFOADDR(fifo_addr >> 4); |
| 361 | csr2 |= RX_FIFOSEGSIZE(fifo_sgsz); | 364 | csr2 |= RX_FIFOSEGSIZE(fifo_sgsz); |
| @@ -600,6 +603,10 @@ static void mtu3_regs_init(struct mtu3 *mtu) | |||
| 600 | mtu3_clrbits(mbase, U3D_MISC_CTRL, VBUS_FRC_EN | VBUS_ON); | 603 | mtu3_clrbits(mbase, U3D_MISC_CTRL, VBUS_FRC_EN | VBUS_ON); |
| 601 | /* enable automatical HWRW from L1 */ | 604 | /* enable automatical HWRW from L1 */ |
| 602 | mtu3_setbits(mbase, U3D_POWER_MANAGEMENT, LPM_HRWE); | 605 | mtu3_setbits(mbase, U3D_POWER_MANAGEMENT, LPM_HRWE); |
| 606 | |||
| 607 | /* use new QMU format when HW version >= 0x1003 */ | ||
| 608 | if (mtu->gen2cp) | ||
| 609 | mtu3_writel(mbase, U3D_QFCR, ~0x0); | ||
| 603 | } | 610 | } |
| 604 | 611 | ||
| 605 | static irqreturn_t mtu3_link_isr(struct mtu3 *mtu) | 612 | static irqreturn_t mtu3_link_isr(struct mtu3 *mtu) |
| @@ -650,6 +657,8 @@ static irqreturn_t mtu3_link_isr(struct mtu3 *mtu) | |||
| 650 | break; | 657 | break; |
| 651 | } | 658 | } |
| 652 | dev_dbg(mtu->dev, "%s: %s\n", __func__, usb_speed_string(udev_speed)); | 659 | dev_dbg(mtu->dev, "%s: %s\n", __func__, usb_speed_string(udev_speed)); |
| 660 | mtu3_dbg_trace(mtu->dev, "link speed %s", | ||
| 661 | usb_speed_string(udev_speed)); | ||
| 653 | 662 | ||
| 654 | mtu->g.speed = udev_speed; | 663 | mtu->g.speed = udev_speed; |
| 655 | mtu->g.ep0->maxpacket = maxpkt; | 664 | mtu->g.ep0->maxpacket = maxpkt; |
| @@ -672,6 +681,7 @@ static irqreturn_t mtu3_u3_ltssm_isr(struct mtu3 *mtu) | |||
| 672 | ltssm &= mtu3_readl(mbase, U3D_LTSSM_INTR_ENABLE); | 681 | ltssm &= mtu3_readl(mbase, U3D_LTSSM_INTR_ENABLE); |
| 673 | mtu3_writel(mbase, U3D_LTSSM_INTR, ltssm); /* W1C */ | 682 | mtu3_writel(mbase, U3D_LTSSM_INTR, ltssm); /* W1C */ |
| 674 | dev_dbg(mtu->dev, "=== LTSSM[%x] ===\n", ltssm); | 683 | dev_dbg(mtu->dev, "=== LTSSM[%x] ===\n", ltssm); |
| 684 | trace_mtu3_u3_ltssm_isr(ltssm); | ||
| 675 | 685 | ||
| 676 | if (ltssm & (HOT_RST_INTR | WARM_RST_INTR)) | 686 | if (ltssm & (HOT_RST_INTR | WARM_RST_INTR)) |
| 677 | mtu3_gadget_reset(mtu); | 687 | mtu3_gadget_reset(mtu); |
| @@ -702,6 +712,7 @@ static irqreturn_t mtu3_u2_common_isr(struct mtu3 *mtu) | |||
| 702 | u2comm &= mtu3_readl(mbase, U3D_COMMON_USB_INTR_ENABLE); | 712 | u2comm &= mtu3_readl(mbase, U3D_COMMON_USB_INTR_ENABLE); |
| 703 | mtu3_writel(mbase, U3D_COMMON_USB_INTR, u2comm); /* W1C */ | 713 | mtu3_writel(mbase, U3D_COMMON_USB_INTR, u2comm); /* W1C */ |
| 704 | dev_dbg(mtu->dev, "=== U2COMM[%x] ===\n", u2comm); | 714 | dev_dbg(mtu->dev, "=== U2COMM[%x] ===\n", u2comm); |
| 715 | trace_mtu3_u2_common_isr(u2comm); | ||
| 705 | 716 | ||
| 706 | if (u2comm & SUSPEND_INTR) | 717 | if (u2comm & SUSPEND_INTR) |
| 707 | mtu3_gadget_suspend(mtu); | 718 | mtu3_gadget_suspend(mtu); |
| @@ -749,13 +760,15 @@ static irqreturn_t mtu3_irq(int irq, void *data) | |||
| 749 | 760 | ||
| 750 | static int mtu3_hw_init(struct mtu3 *mtu) | 761 | static int mtu3_hw_init(struct mtu3 *mtu) |
| 751 | { | 762 | { |
| 752 | u32 cap_dev; | 763 | u32 value; |
| 753 | int ret; | 764 | int ret; |
| 754 | 765 | ||
| 755 | mtu->hw_version = mtu3_readl(mtu->ippc_base, U3D_SSUSB_HW_ID); | 766 | value = mtu3_readl(mtu->ippc_base, U3D_SSUSB_IP_TRUNK_VERS); |
| 767 | mtu->hw_version = IP_TRUNK_VERS(value); | ||
| 768 | mtu->gen2cp = !!(mtu->hw_version >= MTU3_TRUNK_VERS_1003); | ||
| 756 | 769 | ||
| 757 | cap_dev = mtu3_readl(mtu->ippc_base, U3D_SSUSB_IP_DEV_CAP); | 770 | value = mtu3_readl(mtu->ippc_base, U3D_SSUSB_IP_DEV_CAP); |
| 758 | mtu->is_u3_ip = !!SSUSB_IP_DEV_U3_PORT_NUM(cap_dev); | 771 | mtu->is_u3_ip = !!SSUSB_IP_DEV_U3_PORT_NUM(value); |
| 759 | 772 | ||
| 760 | dev_info(mtu->dev, "IP version 0x%x(%s IP)\n", mtu->hw_version, | 773 | dev_info(mtu->dev, "IP version 0x%x(%s IP)\n", mtu->hw_version, |
| 761 | mtu->is_u3_ip ? "U3" : "U2"); | 774 | mtu->is_u3_ip ? "U3" : "U2"); |
| @@ -893,6 +906,8 @@ int ssusb_gadget_init(struct ssusb_mtk *ssusb) | |||
| 893 | if (mtu->ssusb->dr_mode == USB_DR_MODE_OTG) | 906 | if (mtu->ssusb->dr_mode == USB_DR_MODE_OTG) |
| 894 | mtu3_stop(mtu); | 907 | mtu3_stop(mtu); |
| 895 | 908 | ||
| 909 | ssusb_dev_debugfs_init(ssusb); | ||
| 910 | |||
| 896 | dev_dbg(dev, " %s() done...\n", __func__); | 911 | dev_dbg(dev, " %s() done...\n", __func__); |
| 897 | 912 | ||
| 898 | return 0; | 913 | return 0; |
diff --git a/drivers/usb/mtu3/mtu3_debug.h b/drivers/usb/mtu3/mtu3_debug.h new file mode 100644 index 000000000000..e96a69234d05 --- /dev/null +++ b/drivers/usb/mtu3/mtu3_debug.h | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * mtu3_debug.h - debug header | ||
| 4 | * | ||
| 5 | * Copyright (C) 2019 MediaTek Inc. | ||
| 6 | * | ||
| 7 | * Author: Chunfeng Yun <chunfeng.yun@mediatek.com> | ||
| 8 | */ | ||
| 9 | |||
| 10 | #ifndef __MTU3_DEBUG_H__ | ||
| 11 | #define __MTU3_DEBUG_H__ | ||
| 12 | |||
| 13 | #include <linux/debugfs.h> | ||
| 14 | |||
| 15 | #define MTU3_DEBUGFS_NAME_LEN 32 | ||
| 16 | |||
| 17 | struct mtu3_regset { | ||
| 18 | char name[MTU3_DEBUGFS_NAME_LEN]; | ||
| 19 | struct debugfs_regset32 regset; | ||
| 20 | size_t nregs; | ||
| 21 | }; | ||
| 22 | |||
| 23 | struct mtu3_file_map { | ||
| 24 | const char *name; | ||
| 25 | int (*show)(struct seq_file *s, void *unused); | ||
| 26 | }; | ||
| 27 | |||
| 28 | #if IS_ENABLED(CONFIG_DEBUG_FS) | ||
| 29 | void ssusb_dev_debugfs_init(struct ssusb_mtk *ssusb); | ||
| 30 | void ssusb_dr_debugfs_init(struct ssusb_mtk *ssusb); | ||
| 31 | void ssusb_debugfs_create_root(struct ssusb_mtk *ssusb); | ||
| 32 | void ssusb_debugfs_remove_root(struct ssusb_mtk *ssusb); | ||
| 33 | |||
| 34 | #else | ||
| 35 | static inline void ssusb_dev_debugfs_init(struct ssusb_mtk *ssusb) {} | ||
| 36 | static inline void ssusb_dr_debugfs_init(struct ssusb_mtk *ssusb) {} | ||
| 37 | static inline void ssusb_debugfs_create_root(struct ssusb_mtk *ssusb) {} | ||
| 38 | static inline void ssusb_debugfs_remove_root(struct ssusb_mtk *ssusb) {} | ||
| 39 | |||
| 40 | #endif /* CONFIG_DEBUG_FS */ | ||
| 41 | |||
| 42 | #if IS_ENABLED(CONFIG_TRACING) | ||
| 43 | void mtu3_dbg_trace(struct device *dev, const char *fmt, ...); | ||
| 44 | |||
| 45 | #else | ||
| 46 | static inline void mtu3_dbg_trace(struct device *dev, const char *fmt, ...) {} | ||
| 47 | |||
| 48 | #endif /* CONFIG_TRACING */ | ||
| 49 | |||
| 50 | #endif /* __MTU3_DEBUG_H__ */ | ||
diff --git a/drivers/usb/mtu3/mtu3_debugfs.c b/drivers/usb/mtu3/mtu3_debugfs.c new file mode 100644 index 000000000000..62c57ddc554e --- /dev/null +++ b/drivers/usb/mtu3/mtu3_debugfs.c | |||
| @@ -0,0 +1,539 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * mtu3_debugfs.c - debugfs interface | ||
| 4 | * | ||
| 5 | * Copyright (C) 2019 MediaTek Inc. | ||
| 6 | * | ||
| 7 | * Author: Chunfeng Yun <chunfeng.yun@mediatek.com> | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <linux/uaccess.h> | ||
| 11 | |||
| 12 | #include "mtu3.h" | ||
| 13 | #include "mtu3_dr.h" | ||
| 14 | #include "mtu3_debug.h" | ||
| 15 | |||
| 16 | #define dump_register(nm) \ | ||
| 17 | { \ | ||
| 18 | .name = __stringify(nm), \ | ||
| 19 | .offset = U3D_ ##nm, \ | ||
| 20 | } | ||
| 21 | |||
| 22 | #define dump_prb_reg(nm, os) \ | ||
| 23 | { \ | ||
| 24 | .name = nm, \ | ||
| 25 | .offset = os, \ | ||
| 26 | } | ||
| 27 | |||
| 28 | static const struct debugfs_reg32 mtu3_ippc_regs[] = { | ||
| 29 | dump_register(SSUSB_IP_PW_CTRL0), | ||
| 30 | dump_register(SSUSB_IP_PW_CTRL1), | ||
| 31 | dump_register(SSUSB_IP_PW_CTRL2), | ||
| 32 | dump_register(SSUSB_IP_PW_CTRL3), | ||
| 33 | dump_register(SSUSB_OTG_STS), | ||
| 34 | dump_register(SSUSB_IP_XHCI_CAP), | ||
| 35 | dump_register(SSUSB_IP_DEV_CAP), | ||
| 36 | dump_register(SSUSB_U3_CTRL_0P), | ||
| 37 | dump_register(SSUSB_U2_CTRL_0P), | ||
| 38 | dump_register(SSUSB_HW_ID), | ||
| 39 | dump_register(SSUSB_HW_SUB_ID), | ||
| 40 | dump_register(SSUSB_IP_SPARE0), | ||
| 41 | }; | ||
| 42 | |||
| 43 | static const struct debugfs_reg32 mtu3_dev_regs[] = { | ||
| 44 | dump_register(LV1ISR), | ||
| 45 | dump_register(LV1IER), | ||
| 46 | dump_register(EPISR), | ||
| 47 | dump_register(EPIER), | ||
| 48 | dump_register(EP0CSR), | ||
| 49 | dump_register(RXCOUNT0), | ||
| 50 | dump_register(QISAR0), | ||
| 51 | dump_register(QIER0), | ||
| 52 | dump_register(QISAR1), | ||
| 53 | dump_register(QIER1), | ||
| 54 | dump_register(CAP_EPNTXFFSZ), | ||
| 55 | dump_register(CAP_EPNRXFFSZ), | ||
| 56 | dump_register(CAP_EPINFO), | ||
| 57 | dump_register(MISC_CTRL), | ||
| 58 | }; | ||
| 59 | |||
| 60 | static const struct debugfs_reg32 mtu3_csr_regs[] = { | ||
| 61 | dump_register(DEVICE_CONF), | ||
| 62 | dump_register(DEV_LINK_INTR_ENABLE), | ||
| 63 | dump_register(DEV_LINK_INTR), | ||
| 64 | dump_register(LTSSM_CTRL), | ||
| 65 | dump_register(USB3_CONFIG), | ||
| 66 | dump_register(LINK_STATE_MACHINE), | ||
| 67 | dump_register(LTSSM_INTR_ENABLE), | ||
| 68 | dump_register(LTSSM_INTR), | ||
| 69 | dump_register(U3U2_SWITCH_CTRL), | ||
| 70 | dump_register(POWER_MANAGEMENT), | ||
| 71 | dump_register(DEVICE_CONTROL), | ||
| 72 | dump_register(COMMON_USB_INTR_ENABLE), | ||
| 73 | dump_register(COMMON_USB_INTR), | ||
| 74 | dump_register(USB20_MISC_CONTROL), | ||
| 75 | dump_register(USB20_OPSTATE), | ||
| 76 | }; | ||
| 77 | |||
| 78 | static int mtu3_link_state_show(struct seq_file *sf, void *unused) | ||
| 79 | { | ||
| 80 | struct mtu3 *mtu = sf->private; | ||
| 81 | void __iomem *mbase = mtu->mac_base; | ||
| 82 | |||
| 83 | seq_printf(sf, "opstate: %#x, ltssm: %#x\n", | ||
| 84 | mtu3_readl(mbase, U3D_USB20_OPSTATE), | ||
| 85 | LTSSM_STATE(mtu3_readl(mbase, U3D_LINK_STATE_MACHINE))); | ||
| 86 | |||
| 87 | return 0; | ||
| 88 | } | ||
| 89 | |||
| 90 | static int mtu3_ep_used_show(struct seq_file *sf, void *unused) | ||
| 91 | { | ||
| 92 | struct mtu3 *mtu = sf->private; | ||
| 93 | struct mtu3_ep *mep; | ||
| 94 | unsigned long flags; | ||
| 95 | int used = 0; | ||
| 96 | int i; | ||
| 97 | |||
| 98 | spin_lock_irqsave(&mtu->lock, flags); | ||
| 99 | |||
| 100 | for (i = 0; i < mtu->num_eps; i++) { | ||
| 101 | mep = mtu->in_eps + i; | ||
| 102 | if (mep->flags & MTU3_EP_ENABLED) { | ||
| 103 | seq_printf(sf, "%s - type: %d\n", mep->name, mep->type); | ||
| 104 | used++; | ||
| 105 | } | ||
| 106 | |||
| 107 | mep = mtu->out_eps + i; | ||
| 108 | if (mep->flags & MTU3_EP_ENABLED) { | ||
| 109 | seq_printf(sf, "%s - type: %d\n", mep->name, mep->type); | ||
| 110 | used++; | ||
| 111 | } | ||
| 112 | } | ||
| 113 | seq_printf(sf, "total used: %d eps\n", used); | ||
| 114 | |||
| 115 | spin_unlock_irqrestore(&mtu->lock, flags); | ||
| 116 | |||
| 117 | return 0; | ||
| 118 | } | ||
| 119 | |||
| 120 | DEFINE_SHOW_ATTRIBUTE(mtu3_link_state); | ||
| 121 | DEFINE_SHOW_ATTRIBUTE(mtu3_ep_used); | ||
| 122 | |||
| 123 | static void mtu3_debugfs_regset(struct mtu3 *mtu, void __iomem *base, | ||
| 124 | const struct debugfs_reg32 *regs, size_t nregs, | ||
| 125 | const char *name, struct dentry *parent) | ||
| 126 | { | ||
| 127 | struct debugfs_regset32 *regset; | ||
| 128 | struct mtu3_regset *mregs; | ||
| 129 | |||
| 130 | mregs = devm_kzalloc(mtu->dev, sizeof(*regset), GFP_KERNEL); | ||
| 131 | if (!mregs) | ||
| 132 | return; | ||
| 133 | |||
| 134 | sprintf(mregs->name, "%s", name); | ||
| 135 | regset = &mregs->regset; | ||
| 136 | regset->regs = regs; | ||
| 137 | regset->nregs = nregs; | ||
| 138 | regset->base = base; | ||
| 139 | |||
| 140 | debugfs_create_regset32(mregs->name, 0444, parent, regset); | ||
| 141 | } | ||
| 142 | |||
| 143 | static void mtu3_debugfs_ep_regset(struct mtu3 *mtu, struct mtu3_ep *mep, | ||
| 144 | struct dentry *parent) | ||
| 145 | { | ||
| 146 | struct debugfs_reg32 *regs; | ||
| 147 | int epnum = mep->epnum; | ||
| 148 | int in = mep->is_in; | ||
| 149 | |||
| 150 | regs = devm_kcalloc(mtu->dev, 7, sizeof(*regs), GFP_KERNEL); | ||
| 151 | if (!regs) | ||
| 152 | return; | ||
| 153 | |||
| 154 | regs[0].name = in ? "TCR0" : "RCR0"; | ||
| 155 | regs[0].offset = in ? MU3D_EP_TXCR0(epnum) : MU3D_EP_RXCR0(epnum); | ||
| 156 | regs[1].name = in ? "TCR1" : "RCR1"; | ||
| 157 | regs[1].offset = in ? MU3D_EP_TXCR1(epnum) : MU3D_EP_RXCR1(epnum); | ||
| 158 | regs[2].name = in ? "TCR2" : "RCR2"; | ||
| 159 | regs[2].offset = in ? MU3D_EP_TXCR2(epnum) : MU3D_EP_RXCR2(epnum); | ||
| 160 | regs[3].name = in ? "TQHIAR" : "RQHIAR"; | ||
| 161 | regs[3].offset = in ? USB_QMU_TQHIAR(epnum) : USB_QMU_RQHIAR(epnum); | ||
| 162 | regs[4].name = in ? "TQCSR" : "RQCSR"; | ||
| 163 | regs[4].offset = in ? USB_QMU_TQCSR(epnum) : USB_QMU_RQCSR(epnum); | ||
| 164 | regs[5].name = in ? "TQSAR" : "RQSAR"; | ||
| 165 | regs[5].offset = in ? USB_QMU_TQSAR(epnum) : USB_QMU_RQSAR(epnum); | ||
| 166 | regs[6].name = in ? "TQCPR" : "RQCPR"; | ||
| 167 | regs[6].offset = in ? USB_QMU_TQCPR(epnum) : USB_QMU_RQCPR(epnum); | ||
| 168 | |||
| 169 | mtu3_debugfs_regset(mtu, mtu->mac_base, regs, 7, "ep-regs", parent); | ||
| 170 | } | ||
| 171 | |||
| 172 | static int mtu3_ep_info_show(struct seq_file *sf, void *unused) | ||
| 173 | { | ||
| 174 | struct mtu3_ep *mep = sf->private; | ||
| 175 | struct mtu3 *mtu = mep->mtu; | ||
| 176 | unsigned long flags; | ||
| 177 | |||
| 178 | spin_lock_irqsave(&mtu->lock, flags); | ||
| 179 | seq_printf(sf, "ep - type:%d, maxp:%d, slot:%d, flags:%x\n", | ||
| 180 | mep->type, mep->maxp, mep->slot, mep->flags); | ||
| 181 | spin_unlock_irqrestore(&mtu->lock, flags); | ||
| 182 | |||
| 183 | return 0; | ||
| 184 | } | ||
| 185 | |||
| 186 | static int mtu3_fifo_show(struct seq_file *sf, void *unused) | ||
| 187 | { | ||
| 188 | struct mtu3_ep *mep = sf->private; | ||
| 189 | struct mtu3 *mtu = mep->mtu; | ||
| 190 | unsigned long flags; | ||
| 191 | |||
| 192 | spin_lock_irqsave(&mtu->lock, flags); | ||
| 193 | seq_printf(sf, "fifo - seg_size:%d, addr:%d, size:%d\n", | ||
| 194 | mep->fifo_seg_size, mep->fifo_addr, mep->fifo_size); | ||
| 195 | spin_unlock_irqrestore(&mtu->lock, flags); | ||
| 196 | |||
| 197 | return 0; | ||
| 198 | } | ||
| 199 | |||
| 200 | static int mtu3_qmu_ring_show(struct seq_file *sf, void *unused) | ||
| 201 | { | ||
| 202 | struct mtu3_ep *mep = sf->private; | ||
| 203 | struct mtu3 *mtu = mep->mtu; | ||
| 204 | struct mtu3_gpd_ring *ring; | ||
| 205 | unsigned long flags; | ||
| 206 | |||
| 207 | ring = &mep->gpd_ring; | ||
| 208 | spin_lock_irqsave(&mtu->lock, flags); | ||
| 209 | seq_printf(sf, | ||
| 210 | "qmu-ring - dma:%pad, start:%p, end:%p, enq:%p, dep:%p\n", | ||
| 211 | &ring->dma, ring->start, ring->end, | ||
| 212 | ring->enqueue, ring->dequeue); | ||
| 213 | spin_unlock_irqrestore(&mtu->lock, flags); | ||
| 214 | |||
| 215 | return 0; | ||
| 216 | } | ||
| 217 | |||
| 218 | static int mtu3_qmu_gpd_show(struct seq_file *sf, void *unused) | ||
| 219 | { | ||
| 220 | struct mtu3_ep *mep = sf->private; | ||
| 221 | struct mtu3 *mtu = mep->mtu; | ||
| 222 | struct mtu3_gpd_ring *ring; | ||
| 223 | struct qmu_gpd *gpd; | ||
| 224 | dma_addr_t dma; | ||
| 225 | unsigned long flags; | ||
| 226 | int i; | ||
| 227 | |||
| 228 | spin_lock_irqsave(&mtu->lock, flags); | ||
| 229 | ring = &mep->gpd_ring; | ||
| 230 | gpd = ring->start; | ||
| 231 | if (!gpd || !(mep->flags & MTU3_EP_ENABLED)) { | ||
| 232 | seq_puts(sf, "empty!\n"); | ||
| 233 | goto out; | ||
| 234 | } | ||
| 235 | |||
| 236 | for (i = 0; i < MAX_GPD_NUM; i++, gpd++) { | ||
| 237 | dma = ring->dma + i * sizeof(*gpd); | ||
| 238 | seq_printf(sf, "gpd.%03d -> %pad, %p: %08x %08x %08x %08x\n", | ||
| 239 | i, &dma, gpd, gpd->dw0_info, gpd->next_gpd, | ||
| 240 | gpd->buffer, gpd->dw3_info); | ||
| 241 | } | ||
| 242 | |||
| 243 | out: | ||
| 244 | spin_unlock_irqrestore(&mtu->lock, flags); | ||
| 245 | |||
| 246 | return 0; | ||
| 247 | } | ||
| 248 | |||
| 249 | static const struct mtu3_file_map mtu3_ep_files[] = { | ||
| 250 | {"ep-info", mtu3_ep_info_show, }, | ||
| 251 | {"fifo", mtu3_fifo_show, }, | ||
| 252 | {"qmu-ring", mtu3_qmu_ring_show, }, | ||
| 253 | {"qmu-gpd", mtu3_qmu_gpd_show, }, | ||
| 254 | }; | ||
| 255 | |||
| 256 | static int mtu3_ep_open(struct inode *inode, struct file *file) | ||
| 257 | { | ||
| 258 | const char *file_name = file_dentry(file)->d_iname; | ||
| 259 | const struct mtu3_file_map *f_map; | ||
| 260 | int i; | ||
| 261 | |||
| 262 | for (i = 0; i < ARRAY_SIZE(mtu3_ep_files); i++) { | ||
| 263 | f_map = &mtu3_ep_files[i]; | ||
| 264 | |||
| 265 | if (strcmp(f_map->name, file_name) == 0) | ||
| 266 | break; | ||
| 267 | } | ||
| 268 | |||
| 269 | return single_open(file, f_map->show, inode->i_private); | ||
| 270 | } | ||
| 271 | |||
| 272 | static const struct file_operations mtu3_ep_fops = { | ||
| 273 | .open = mtu3_ep_open, | ||
| 274 | .read = seq_read, | ||
| 275 | .llseek = seq_lseek, | ||
| 276 | .release = single_release, | ||
| 277 | }; | ||
| 278 | |||
| 279 | static struct debugfs_reg32 mtu3_prb_regs[] = { | ||
| 280 | dump_prb_reg("enable", U3D_SSUSB_PRB_CTRL0), | ||
| 281 | dump_prb_reg("byte-sell", U3D_SSUSB_PRB_CTRL1), | ||
| 282 | dump_prb_reg("byte-selh", U3D_SSUSB_PRB_CTRL2), | ||
| 283 | dump_prb_reg("module-sel", U3D_SSUSB_PRB_CTRL3), | ||
| 284 | dump_prb_reg("sw-out", U3D_SSUSB_PRB_CTRL4), | ||
| 285 | dump_prb_reg("data", U3D_SSUSB_PRB_CTRL5), | ||
| 286 | }; | ||
| 287 | |||
| 288 | static int mtu3_probe_show(struct seq_file *sf, void *unused) | ||
| 289 | { | ||
| 290 | const char *file_name = file_dentry(sf->file)->d_iname; | ||
| 291 | struct mtu3 *mtu = sf->private; | ||
| 292 | const struct debugfs_reg32 *regs; | ||
| 293 | int i; | ||
| 294 | |||
| 295 | for (i = 0; i < ARRAY_SIZE(mtu3_prb_regs); i++) { | ||
| 296 | regs = &mtu3_prb_regs[i]; | ||
| 297 | |||
| 298 | if (strcmp(regs->name, file_name) == 0) | ||
| 299 | break; | ||
| 300 | } | ||
| 301 | |||
| 302 | seq_printf(sf, "0x%04x - 0x%08x\n", (u32)regs->offset, | ||
| 303 | mtu3_readl(mtu->ippc_base, (u32)regs->offset)); | ||
| 304 | |||
| 305 | return 0; | ||
| 306 | } | ||
| 307 | |||
| 308 | static int mtu3_probe_open(struct inode *inode, struct file *file) | ||
| 309 | { | ||
| 310 | return single_open(file, mtu3_probe_show, inode->i_private); | ||
| 311 | } | ||
| 312 | |||
| 313 | static ssize_t mtu3_probe_write(struct file *file, const char __user *ubuf, | ||
| 314 | size_t count, loff_t *ppos) | ||
| 315 | { | ||
| 316 | const char *file_name = file_dentry(file)->d_iname; | ||
| 317 | struct seq_file *sf = file->private_data; | ||
| 318 | struct mtu3 *mtu = sf->private; | ||
| 319 | const struct debugfs_reg32 *regs; | ||
| 320 | char buf[32]; | ||
| 321 | u32 val; | ||
| 322 | int i; | ||
| 323 | |||
| 324 | if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) | ||
| 325 | return -EFAULT; | ||
| 326 | |||
| 327 | if (kstrtou32(buf, 0, &val)) | ||
| 328 | return -EINVAL; | ||
| 329 | |||
| 330 | for (i = 0; i < ARRAY_SIZE(mtu3_prb_regs); i++) { | ||
| 331 | regs = &mtu3_prb_regs[i]; | ||
| 332 | |||
| 333 | if (strcmp(regs->name, file_name) == 0) | ||
| 334 | break; | ||
| 335 | } | ||
| 336 | mtu3_writel(mtu->ippc_base, (u32)regs->offset, val); | ||
| 337 | |||
| 338 | return count; | ||
| 339 | } | ||
| 340 | |||
| 341 | static const struct file_operations mtu3_probe_fops = { | ||
| 342 | .open = mtu3_probe_open, | ||
| 343 | .write = mtu3_probe_write, | ||
| 344 | .read = seq_read, | ||
| 345 | .llseek = seq_lseek, | ||
| 346 | .release = single_release, | ||
| 347 | }; | ||
| 348 | |||
| 349 | static void mtu3_debugfs_create_prb_files(struct mtu3 *mtu) | ||
| 350 | { | ||
| 351 | struct ssusb_mtk *ssusb = mtu->ssusb; | ||
| 352 | struct debugfs_reg32 *regs; | ||
| 353 | struct dentry *dir_prb; | ||
| 354 | int i; | ||
| 355 | |||
| 356 | dir_prb = debugfs_create_dir("probe", ssusb->dbgfs_root); | ||
| 357 | |||
| 358 | for (i = 0; i < ARRAY_SIZE(mtu3_prb_regs); i++) { | ||
| 359 | regs = &mtu3_prb_regs[i]; | ||
| 360 | debugfs_create_file(regs->name, 0644, dir_prb, | ||
| 361 | mtu, &mtu3_probe_fops); | ||
| 362 | } | ||
| 363 | |||
| 364 | mtu3_debugfs_regset(mtu, mtu->ippc_base, mtu3_prb_regs, | ||
| 365 | ARRAY_SIZE(mtu3_prb_regs), "regs", dir_prb); | ||
| 366 | } | ||
| 367 | |||
| 368 | static void mtu3_debugfs_create_ep_dir(struct mtu3_ep *mep, | ||
| 369 | struct dentry *parent) | ||
| 370 | { | ||
| 371 | const struct mtu3_file_map *files; | ||
| 372 | struct dentry *dir_ep; | ||
| 373 | int i; | ||
| 374 | |||
| 375 | dir_ep = debugfs_create_dir(mep->name, parent); | ||
| 376 | mtu3_debugfs_ep_regset(mep->mtu, mep, dir_ep); | ||
| 377 | |||
| 378 | for (i = 0; i < ARRAY_SIZE(mtu3_ep_files); i++) { | ||
| 379 | files = &mtu3_ep_files[i]; | ||
| 380 | |||
| 381 | debugfs_create_file(files->name, 0444, dir_ep, | ||
| 382 | mep, &mtu3_ep_fops); | ||
| 383 | } | ||
| 384 | } | ||
| 385 | |||
| 386 | static void mtu3_debugfs_create_ep_dirs(struct mtu3 *mtu) | ||
| 387 | { | ||
| 388 | struct ssusb_mtk *ssusb = mtu->ssusb; | ||
| 389 | struct dentry *dir_eps; | ||
| 390 | int i; | ||
| 391 | |||
| 392 | dir_eps = debugfs_create_dir("eps", ssusb->dbgfs_root); | ||
| 393 | |||
| 394 | for (i = 1; i < mtu->num_eps; i++) { | ||
| 395 | mtu3_debugfs_create_ep_dir(mtu->in_eps + i, dir_eps); | ||
| 396 | mtu3_debugfs_create_ep_dir(mtu->out_eps + i, dir_eps); | ||
| 397 | } | ||
| 398 | } | ||
| 399 | |||
| 400 | void ssusb_dev_debugfs_init(struct ssusb_mtk *ssusb) | ||
| 401 | { | ||
| 402 | struct mtu3 *mtu = ssusb->u3d; | ||
| 403 | struct dentry *dir_regs; | ||
| 404 | |||
| 405 | dir_regs = debugfs_create_dir("regs", ssusb->dbgfs_root); | ||
| 406 | |||
| 407 | mtu3_debugfs_regset(mtu, mtu->ippc_base, | ||
| 408 | mtu3_ippc_regs, ARRAY_SIZE(mtu3_ippc_regs), | ||
| 409 | "reg-ippc", dir_regs); | ||
| 410 | |||
| 411 | mtu3_debugfs_regset(mtu, mtu->mac_base, | ||
| 412 | mtu3_dev_regs, ARRAY_SIZE(mtu3_dev_regs), | ||
| 413 | "reg-dev", dir_regs); | ||
| 414 | |||
| 415 | mtu3_debugfs_regset(mtu, mtu->mac_base, | ||
| 416 | mtu3_csr_regs, ARRAY_SIZE(mtu3_csr_regs), | ||
| 417 | "reg-csr", dir_regs); | ||
| 418 | |||
| 419 | mtu3_debugfs_create_ep_dirs(mtu); | ||
| 420 | |||
| 421 | mtu3_debugfs_create_prb_files(mtu); | ||
| 422 | |||
| 423 | debugfs_create_file("link-state", 0444, ssusb->dbgfs_root, | ||
| 424 | mtu, &mtu3_link_state_fops); | ||
| 425 | debugfs_create_file("ep-used", 0444, ssusb->dbgfs_root, | ||
| 426 | mtu, &mtu3_ep_used_fops); | ||
| 427 | } | ||
| 428 | |||
| 429 | static int ssusb_mode_show(struct seq_file *sf, void *unused) | ||
| 430 | { | ||
| 431 | struct ssusb_mtk *ssusb = sf->private; | ||
| 432 | |||
| 433 | seq_printf(sf, "current mode: %s(%s drd)\n(echo device/host)\n", | ||
| 434 | ssusb->is_host ? "host" : "device", | ||
| 435 | ssusb->otg_switch.manual_drd_enabled ? "manual" : "auto"); | ||
| 436 | |||
| 437 | return 0; | ||
| 438 | } | ||
| 439 | |||
| 440 | static int ssusb_mode_open(struct inode *inode, struct file *file) | ||
| 441 | { | ||
| 442 | return single_open(file, ssusb_mode_show, inode->i_private); | ||
| 443 | } | ||
| 444 | |||
| 445 | static ssize_t ssusb_mode_write(struct file *file, const char __user *ubuf, | ||
| 446 | size_t count, loff_t *ppos) | ||
| 447 | { | ||
| 448 | struct seq_file *sf = file->private_data; | ||
| 449 | struct ssusb_mtk *ssusb = sf->private; | ||
| 450 | char buf[16]; | ||
| 451 | |||
| 452 | if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) | ||
| 453 | return -EFAULT; | ||
| 454 | |||
| 455 | if (!strncmp(buf, "host", 4) && !ssusb->is_host) { | ||
| 456 | ssusb_mode_manual_switch(ssusb, 1); | ||
| 457 | } else if (!strncmp(buf, "device", 6) && ssusb->is_host) { | ||
| 458 | ssusb_mode_manual_switch(ssusb, 0); | ||
| 459 | } else { | ||
| 460 | dev_err(ssusb->dev, "wrong or duplicated setting\n"); | ||
| 461 | return -EINVAL; | ||
| 462 | } | ||
| 463 | |||
| 464 | return count; | ||
| 465 | } | ||
| 466 | |||
| 467 | static const struct file_operations ssusb_mode_fops = { | ||
| 468 | .open = ssusb_mode_open, | ||
| 469 | .write = ssusb_mode_write, | ||
| 470 | .read = seq_read, | ||
| 471 | .llseek = seq_lseek, | ||
| 472 | .release = single_release, | ||
| 473 | }; | ||
| 474 | |||
| 475 | static int ssusb_vbus_show(struct seq_file *sf, void *unused) | ||
| 476 | { | ||
| 477 | struct ssusb_mtk *ssusb = sf->private; | ||
| 478 | struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; | ||
| 479 | |||
| 480 | seq_printf(sf, "vbus state: %s\n(echo on/off)\n", | ||
| 481 | regulator_is_enabled(otg_sx->vbus) ? "on" : "off"); | ||
| 482 | |||
| 483 | return 0; | ||
| 484 | } | ||
| 485 | |||
| 486 | static int ssusb_vbus_open(struct inode *inode, struct file *file) | ||
| 487 | { | ||
| 488 | return single_open(file, ssusb_vbus_show, inode->i_private); | ||
| 489 | } | ||
| 490 | |||
| 491 | static ssize_t ssusb_vbus_write(struct file *file, const char __user *ubuf, | ||
| 492 | size_t count, loff_t *ppos) | ||
| 493 | { | ||
| 494 | struct seq_file *sf = file->private_data; | ||
| 495 | struct ssusb_mtk *ssusb = sf->private; | ||
| 496 | struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; | ||
| 497 | char buf[16]; | ||
| 498 | bool enable; | ||
| 499 | |||
| 500 | if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) | ||
| 501 | return -EFAULT; | ||
| 502 | |||
| 503 | if (kstrtobool(buf, &enable)) { | ||
| 504 | dev_err(ssusb->dev, "wrong setting\n"); | ||
| 505 | return -EINVAL; | ||
| 506 | } | ||
| 507 | |||
| 508 | ssusb_set_vbus(otg_sx, enable); | ||
| 509 | |||
| 510 | return count; | ||
| 511 | } | ||
| 512 | |||
| 513 | static const struct file_operations ssusb_vbus_fops = { | ||
| 514 | .open = ssusb_vbus_open, | ||
| 515 | .write = ssusb_vbus_write, | ||
| 516 | .read = seq_read, | ||
| 517 | .llseek = seq_lseek, | ||
| 518 | .release = single_release, | ||
| 519 | }; | ||
| 520 | |||
| 521 | void ssusb_dr_debugfs_init(struct ssusb_mtk *ssusb) | ||
| 522 | { | ||
| 523 | struct dentry *root = ssusb->dbgfs_root; | ||
| 524 | |||
| 525 | debugfs_create_file("mode", 0644, root, ssusb, &ssusb_mode_fops); | ||
| 526 | debugfs_create_file("vbus", 0644, root, ssusb, &ssusb_vbus_fops); | ||
| 527 | } | ||
| 528 | |||
| 529 | void ssusb_debugfs_create_root(struct ssusb_mtk *ssusb) | ||
| 530 | { | ||
| 531 | ssusb->dbgfs_root = | ||
| 532 | debugfs_create_dir(dev_name(ssusb->dev), usb_debug_root); | ||
| 533 | } | ||
| 534 | |||
| 535 | void ssusb_debugfs_remove_root(struct ssusb_mtk *ssusb) | ||
| 536 | { | ||
| 537 | debugfs_remove_recursive(ssusb->dbgfs_root); | ||
| 538 | ssusb->dbgfs_root = NULL; | ||
| 539 | } | ||
diff --git a/drivers/usb/mtu3/mtu3_dr.c b/drivers/usb/mtu3/mtu3_dr.c index ac60e9c8564e..5fcb71af875a 100644 --- a/drivers/usb/mtu3/mtu3_dr.c +++ b/drivers/usb/mtu3/mtu3_dr.c | |||
| @@ -7,16 +7,9 @@ | |||
| 7 | * Author: Chunfeng Yun <chunfeng.yun@mediatek.com> | 7 | * Author: Chunfeng Yun <chunfeng.yun@mediatek.com> |
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | #include <linux/debugfs.h> | ||
| 11 | #include <linux/irq.h> | ||
| 12 | #include <linux/kernel.h> | ||
| 13 | #include <linux/of_device.h> | ||
| 14 | #include <linux/pinctrl/consumer.h> | ||
| 15 | #include <linux/seq_file.h> | ||
| 16 | #include <linux/uaccess.h> | ||
| 17 | |||
| 18 | #include "mtu3.h" | 10 | #include "mtu3.h" |
| 19 | #include "mtu3_dr.h" | 11 | #include "mtu3_dr.h" |
| 12 | #include "mtu3_debug.h" | ||
| 20 | 13 | ||
| 21 | #define USB2_PORT 2 | 14 | #define USB2_PORT 2 |
| 22 | #define USB3_PORT 3 | 15 | #define USB3_PORT 3 |
| @@ -28,6 +21,22 @@ enum mtu3_vbus_id_state { | |||
| 28 | MTU3_VBUS_VALID, | 21 | MTU3_VBUS_VALID, |
| 29 | }; | 22 | }; |
| 30 | 23 | ||
| 24 | static char *mailbox_state_string(enum mtu3_vbus_id_state state) | ||
| 25 | { | ||
| 26 | switch (state) { | ||
| 27 | case MTU3_ID_FLOAT: | ||
| 28 | return "ID_FLOAT"; | ||
| 29 | case MTU3_ID_GROUND: | ||
| 30 | return "ID_GROUND"; | ||
| 31 | case MTU3_VBUS_OFF: | ||
| 32 | return "VBUS_OFF"; | ||
| 33 | case MTU3_VBUS_VALID: | ||
| 34 | return "VBUS_VALID"; | ||
| 35 | default: | ||
| 36 | return "UNKNOWN"; | ||
| 37 | } | ||
| 38 | } | ||
| 39 | |||
| 31 | static void toggle_opstate(struct ssusb_mtk *ssusb) | 40 | static void toggle_opstate(struct ssusb_mtk *ssusb) |
| 32 | { | 41 | { |
| 33 | if (!ssusb->otg_switch.is_u3_drd) { | 42 | if (!ssusb->otg_switch.is_u3_drd) { |
| @@ -147,7 +156,8 @@ static void ssusb_set_mailbox(struct otg_switch_mtk *otg_sx, | |||
| 147 | container_of(otg_sx, struct ssusb_mtk, otg_switch); | 156 | container_of(otg_sx, struct ssusb_mtk, otg_switch); |
| 148 | struct mtu3 *mtu = ssusb->u3d; | 157 | struct mtu3 *mtu = ssusb->u3d; |
| 149 | 158 | ||
| 150 | dev_dbg(ssusb->dev, "mailbox state(%d)\n", status); | 159 | dev_dbg(ssusb->dev, "mailbox %s\n", mailbox_state_string(status)); |
| 160 | mtu3_dbg_trace(ssusb->dev, "mailbox %s", mailbox_state_string(status)); | ||
| 151 | 161 | ||
| 152 | switch (status) { | 162 | switch (status) { |
| 153 | case MTU3_ID_GROUND: | 163 | case MTU3_ID_GROUND: |
| @@ -238,14 +248,18 @@ static int ssusb_extcon_register(struct otg_switch_mtk *otg_sx) | |||
| 238 | otg_sx->vbus_nb.notifier_call = ssusb_vbus_notifier; | 248 | otg_sx->vbus_nb.notifier_call = ssusb_vbus_notifier; |
| 239 | ret = devm_extcon_register_notifier(ssusb->dev, edev, EXTCON_USB, | 249 | ret = devm_extcon_register_notifier(ssusb->dev, edev, EXTCON_USB, |
| 240 | &otg_sx->vbus_nb); | 250 | &otg_sx->vbus_nb); |
| 241 | if (ret < 0) | 251 | if (ret < 0) { |
| 242 | dev_err(ssusb->dev, "failed to register notifier for USB\n"); | 252 | dev_err(ssusb->dev, "failed to register notifier for USB\n"); |
| 253 | return ret; | ||
| 254 | } | ||
| 243 | 255 | ||
| 244 | otg_sx->id_nb.notifier_call = ssusb_id_notifier; | 256 | otg_sx->id_nb.notifier_call = ssusb_id_notifier; |
| 245 | ret = devm_extcon_register_notifier(ssusb->dev, edev, EXTCON_USB_HOST, | 257 | ret = devm_extcon_register_notifier(ssusb->dev, edev, EXTCON_USB_HOST, |
| 246 | &otg_sx->id_nb); | 258 | &otg_sx->id_nb); |
| 247 | if (ret < 0) | 259 | if (ret < 0) { |
| 248 | dev_err(ssusb->dev, "failed to register notifier for USB-HOST\n"); | 260 | dev_err(ssusb->dev, "failed to register notifier for USB-HOST\n"); |
| 261 | return ret; | ||
| 262 | } | ||
| 249 | 263 | ||
| 250 | dev_dbg(ssusb->dev, "EXTCON_USB: %d, EXTCON_USB_HOST: %d\n", | 264 | dev_dbg(ssusb->dev, "EXTCON_USB: %d, EXTCON_USB_HOST: %d\n", |
| 251 | extcon_get_state(edev, EXTCON_USB), | 265 | extcon_get_state(edev, EXTCON_USB), |
| @@ -266,7 +280,7 @@ static int ssusb_extcon_register(struct otg_switch_mtk *otg_sx) | |||
| 266 | * This is useful in special cases, such as uses TYPE-A receptacle but also | 280 | * This is useful in special cases, such as uses TYPE-A receptacle but also |
| 267 | * wants to support dual-role mode. | 281 | * wants to support dual-role mode. |
| 268 | */ | 282 | */ |
| 269 | static void ssusb_mode_manual_switch(struct ssusb_mtk *ssusb, int to_host) | 283 | void ssusb_mode_manual_switch(struct ssusb_mtk *ssusb, int to_host) |
| 270 | { | 284 | { |
| 271 | struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; | 285 | struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; |
| 272 | 286 | ||
| @@ -281,114 +295,6 @@ static void ssusb_mode_manual_switch(struct ssusb_mtk *ssusb, int to_host) | |||
| 281 | } | 295 | } |
| 282 | } | 296 | } |
| 283 | 297 | ||
| 284 | static int ssusb_mode_show(struct seq_file *sf, void *unused) | ||
| 285 | { | ||
| 286 | struct ssusb_mtk *ssusb = sf->private; | ||
| 287 | |||
| 288 | seq_printf(sf, "current mode: %s(%s drd)\n(echo device/host)\n", | ||
| 289 | ssusb->is_host ? "host" : "device", | ||
| 290 | ssusb->otg_switch.manual_drd_enabled ? "manual" : "auto"); | ||
| 291 | |||
| 292 | return 0; | ||
| 293 | } | ||
| 294 | |||
| 295 | static int ssusb_mode_open(struct inode *inode, struct file *file) | ||
| 296 | { | ||
| 297 | return single_open(file, ssusb_mode_show, inode->i_private); | ||
| 298 | } | ||
| 299 | |||
| 300 | static ssize_t ssusb_mode_write(struct file *file, | ||
| 301 | const char __user *ubuf, size_t count, loff_t *ppos) | ||
| 302 | { | ||
| 303 | struct seq_file *sf = file->private_data; | ||
| 304 | struct ssusb_mtk *ssusb = sf->private; | ||
| 305 | char buf[16]; | ||
| 306 | |||
| 307 | if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) | ||
| 308 | return -EFAULT; | ||
| 309 | |||
| 310 | if (!strncmp(buf, "host", 4) && !ssusb->is_host) { | ||
| 311 | ssusb_mode_manual_switch(ssusb, 1); | ||
| 312 | } else if (!strncmp(buf, "device", 6) && ssusb->is_host) { | ||
| 313 | ssusb_mode_manual_switch(ssusb, 0); | ||
| 314 | } else { | ||
| 315 | dev_err(ssusb->dev, "wrong or duplicated setting\n"); | ||
| 316 | return -EINVAL; | ||
| 317 | } | ||
| 318 | |||
| 319 | return count; | ||
| 320 | } | ||
| 321 | |||
| 322 | static const struct file_operations ssusb_mode_fops = { | ||
| 323 | .open = ssusb_mode_open, | ||
| 324 | .write = ssusb_mode_write, | ||
| 325 | .read = seq_read, | ||
| 326 | .llseek = seq_lseek, | ||
| 327 | .release = single_release, | ||
| 328 | }; | ||
| 329 | |||
| 330 | static int ssusb_vbus_show(struct seq_file *sf, void *unused) | ||
| 331 | { | ||
| 332 | struct ssusb_mtk *ssusb = sf->private; | ||
| 333 | struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; | ||
| 334 | |||
| 335 | seq_printf(sf, "vbus state: %s\n(echo on/off)\n", | ||
| 336 | regulator_is_enabled(otg_sx->vbus) ? "on" : "off"); | ||
| 337 | |||
| 338 | return 0; | ||
| 339 | } | ||
| 340 | |||
| 341 | static int ssusb_vbus_open(struct inode *inode, struct file *file) | ||
| 342 | { | ||
| 343 | return single_open(file, ssusb_vbus_show, inode->i_private); | ||
| 344 | } | ||
| 345 | |||
| 346 | static ssize_t ssusb_vbus_write(struct file *file, | ||
| 347 | const char __user *ubuf, size_t count, loff_t *ppos) | ||
| 348 | { | ||
| 349 | struct seq_file *sf = file->private_data; | ||
| 350 | struct ssusb_mtk *ssusb = sf->private; | ||
| 351 | struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; | ||
| 352 | char buf[16]; | ||
| 353 | bool enable; | ||
| 354 | |||
| 355 | if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) | ||
| 356 | return -EFAULT; | ||
| 357 | |||
| 358 | if (kstrtobool(buf, &enable)) { | ||
| 359 | dev_err(ssusb->dev, "wrong setting\n"); | ||
| 360 | return -EINVAL; | ||
| 361 | } | ||
| 362 | |||
| 363 | ssusb_set_vbus(otg_sx, enable); | ||
| 364 | |||
| 365 | return count; | ||
| 366 | } | ||
| 367 | |||
| 368 | static const struct file_operations ssusb_vbus_fops = { | ||
| 369 | .open = ssusb_vbus_open, | ||
| 370 | .write = ssusb_vbus_write, | ||
| 371 | .read = seq_read, | ||
| 372 | .llseek = seq_lseek, | ||
| 373 | .release = single_release, | ||
| 374 | }; | ||
| 375 | |||
| 376 | static void ssusb_debugfs_init(struct ssusb_mtk *ssusb) | ||
| 377 | { | ||
| 378 | struct dentry *root; | ||
| 379 | |||
| 380 | root = debugfs_create_dir(dev_name(ssusb->dev), usb_debug_root); | ||
| 381 | ssusb->dbgfs_root = root; | ||
| 382 | |||
| 383 | debugfs_create_file("mode", 0644, root, ssusb, &ssusb_mode_fops); | ||
| 384 | debugfs_create_file("vbus", 0644, root, ssusb, &ssusb_vbus_fops); | ||
| 385 | } | ||
| 386 | |||
| 387 | static void ssusb_debugfs_exit(struct ssusb_mtk *ssusb) | ||
| 388 | { | ||
| 389 | debugfs_remove_recursive(ssusb->dbgfs_root); | ||
| 390 | } | ||
| 391 | |||
| 392 | void ssusb_set_force_mode(struct ssusb_mtk *ssusb, | 298 | void ssusb_set_force_mode(struct ssusb_mtk *ssusb, |
| 393 | enum mtu3_dr_force_mode mode) | 299 | enum mtu3_dr_force_mode mode) |
| 394 | { | 300 | { |
| @@ -415,25 +321,23 @@ void ssusb_set_force_mode(struct ssusb_mtk *ssusb, | |||
| 415 | int ssusb_otg_switch_init(struct ssusb_mtk *ssusb) | 321 | int ssusb_otg_switch_init(struct ssusb_mtk *ssusb) |
| 416 | { | 322 | { |
| 417 | struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; | 323 | struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; |
| 324 | int ret = 0; | ||
| 418 | 325 | ||
| 419 | INIT_WORK(&otg_sx->id_work, ssusb_id_work); | 326 | INIT_WORK(&otg_sx->id_work, ssusb_id_work); |
| 420 | INIT_WORK(&otg_sx->vbus_work, ssusb_vbus_work); | 327 | INIT_WORK(&otg_sx->vbus_work, ssusb_vbus_work); |
| 421 | 328 | ||
| 422 | if (otg_sx->manual_drd_enabled) | 329 | if (otg_sx->manual_drd_enabled) |
| 423 | ssusb_debugfs_init(ssusb); | 330 | ssusb_dr_debugfs_init(ssusb); |
| 424 | else | 331 | else |
| 425 | ssusb_extcon_register(otg_sx); | 332 | ret = ssusb_extcon_register(otg_sx); |
| 426 | 333 | ||
| 427 | return 0; | 334 | return ret; |
| 428 | } | 335 | } |
| 429 | 336 | ||
| 430 | void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb) | 337 | void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb) |
| 431 | { | 338 | { |
| 432 | struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; | 339 | struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; |
| 433 | 340 | ||
| 434 | if (otg_sx->manual_drd_enabled) | ||
| 435 | ssusb_debugfs_exit(ssusb); | ||
| 436 | |||
| 437 | cancel_work_sync(&otg_sx->id_work); | 341 | cancel_work_sync(&otg_sx->id_work); |
| 438 | cancel_work_sync(&otg_sx->vbus_work); | 342 | cancel_work_sync(&otg_sx->vbus_work); |
| 439 | } | 343 | } |
diff --git a/drivers/usb/mtu3/mtu3_dr.h b/drivers/usb/mtu3/mtu3_dr.h index 50702fdcde28..ba6fe357ce29 100644 --- a/drivers/usb/mtu3/mtu3_dr.h +++ b/drivers/usb/mtu3/mtu3_dr.h | |||
| @@ -71,6 +71,7 @@ static inline void ssusb_gadget_exit(struct ssusb_mtk *ssusb) | |||
| 71 | #if IS_ENABLED(CONFIG_USB_MTU3_DUAL_ROLE) | 71 | #if IS_ENABLED(CONFIG_USB_MTU3_DUAL_ROLE) |
| 72 | int ssusb_otg_switch_init(struct ssusb_mtk *ssusb); | 72 | int ssusb_otg_switch_init(struct ssusb_mtk *ssusb); |
| 73 | void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb); | 73 | void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb); |
| 74 | void ssusb_mode_manual_switch(struct ssusb_mtk *ssusb, int to_host); | ||
| 74 | int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on); | 75 | int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on); |
| 75 | void ssusb_set_force_mode(struct ssusb_mtk *ssusb, | 76 | void ssusb_set_force_mode(struct ssusb_mtk *ssusb, |
| 76 | enum mtu3_dr_force_mode mode); | 77 | enum mtu3_dr_force_mode mode); |
| @@ -85,6 +86,9 @@ static inline int ssusb_otg_switch_init(struct ssusb_mtk *ssusb) | |||
| 85 | static inline void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb) | 86 | static inline void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb) |
| 86 | {} | 87 | {} |
| 87 | 88 | ||
| 89 | static inline void | ||
| 90 | ssusb_mode_manual_switch(struct ssusb_mtk *ssusb, int to_host) {} | ||
| 91 | |||
| 88 | static inline int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on) | 92 | static inline int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on) |
| 89 | { | 93 | { |
| 90 | return 0; | 94 | return 0; |
diff --git a/drivers/usb/mtu3/mtu3_gadget.c b/drivers/usb/mtu3/mtu3_gadget.c index bbcd3332471d..f93732e53fd8 100644 --- a/drivers/usb/mtu3/mtu3_gadget.c +++ b/drivers/usb/mtu3/mtu3_gadget.c | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | */ | 8 | */ |
| 9 | 9 | ||
| 10 | #include "mtu3.h" | 10 | #include "mtu3.h" |
| 11 | #include "mtu3_trace.h" | ||
| 11 | 12 | ||
| 12 | void mtu3_req_complete(struct mtu3_ep *mep, | 13 | void mtu3_req_complete(struct mtu3_ep *mep, |
| 13 | struct usb_request *req, int status) | 14 | struct usb_request *req, int status) |
| @@ -25,6 +26,8 @@ __acquires(mep->mtu->lock) | |||
| 25 | 26 | ||
| 26 | mtu = mreq->mtu; | 27 | mtu = mreq->mtu; |
| 27 | mep->busy = 1; | 28 | mep->busy = 1; |
| 29 | |||
| 30 | trace_mtu3_req_complete(mreq); | ||
| 28 | spin_unlock(&mtu->lock); | 31 | spin_unlock(&mtu->lock); |
| 29 | 32 | ||
| 30 | /* ep0 makes use of PIO, needn't unmap it */ | 33 | /* ep0 makes use of PIO, needn't unmap it */ |
| @@ -201,6 +204,7 @@ error: | |||
| 201 | spin_unlock_irqrestore(&mtu->lock, flags); | 204 | spin_unlock_irqrestore(&mtu->lock, flags); |
| 202 | 205 | ||
| 203 | dev_dbg(mtu->dev, "%s active_ep=%d\n", __func__, mtu->active_ep); | 206 | dev_dbg(mtu->dev, "%s active_ep=%d\n", __func__, mtu->active_ep); |
| 207 | trace_mtu3_gadget_ep_enable(mep); | ||
| 204 | 208 | ||
| 205 | return ret; | 209 | return ret; |
| 206 | } | 210 | } |
| @@ -212,6 +216,7 @@ static int mtu3_gadget_ep_disable(struct usb_ep *ep) | |||
| 212 | unsigned long flags; | 216 | unsigned long flags; |
| 213 | 217 | ||
| 214 | dev_dbg(mtu->dev, "%s %s\n", __func__, mep->name); | 218 | dev_dbg(mtu->dev, "%s %s\n", __func__, mep->name); |
| 219 | trace_mtu3_gadget_ep_disable(mep); | ||
| 215 | 220 | ||
| 216 | if (!(mep->flags & MTU3_EP_ENABLED)) { | 221 | if (!(mep->flags & MTU3_EP_ENABLED)) { |
| 217 | dev_warn(mtu->dev, "%s is already disabled\n", mep->name); | 222 | dev_warn(mtu->dev, "%s is already disabled\n", mep->name); |
| @@ -242,13 +247,17 @@ struct usb_request *mtu3_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) | |||
| 242 | mreq->request.dma = DMA_ADDR_INVALID; | 247 | mreq->request.dma = DMA_ADDR_INVALID; |
| 243 | mreq->epnum = mep->epnum; | 248 | mreq->epnum = mep->epnum; |
| 244 | mreq->mep = mep; | 249 | mreq->mep = mep; |
| 250 | trace_mtu3_alloc_request(mreq); | ||
| 245 | 251 | ||
| 246 | return &mreq->request; | 252 | return &mreq->request; |
| 247 | } | 253 | } |
| 248 | 254 | ||
| 249 | void mtu3_free_request(struct usb_ep *ep, struct usb_request *req) | 255 | void mtu3_free_request(struct usb_ep *ep, struct usb_request *req) |
| 250 | { | 256 | { |
| 251 | kfree(to_mtu3_request(req)); | 257 | struct mtu3_request *mreq = to_mtu3_request(req); |
| 258 | |||
| 259 | trace_mtu3_free_request(mreq); | ||
| 260 | kfree(mreq); | ||
| 252 | } | 261 | } |
| 253 | 262 | ||
| 254 | static int mtu3_gadget_queue(struct usb_ep *ep, | 263 | static int mtu3_gadget_queue(struct usb_ep *ep, |
| @@ -278,10 +287,12 @@ static int mtu3_gadget_queue(struct usb_ep *ep, | |||
| 278 | __func__, mep->is_in ? "TX" : "RX", mreq->epnum, ep->name, | 287 | __func__, mep->is_in ? "TX" : "RX", mreq->epnum, ep->name, |
| 279 | mreq, ep->maxpacket, mreq->request.length); | 288 | mreq, ep->maxpacket, mreq->request.length); |
| 280 | 289 | ||
| 281 | if (req->length > GPD_BUF_SIZE) { | 290 | if (req->length > GPD_BUF_SIZE || |
| 291 | (mtu->gen2cp && req->length > GPD_BUF_SIZE_EL)) { | ||
| 282 | dev_warn(mtu->dev, | 292 | dev_warn(mtu->dev, |
| 283 | "req length > supported MAX:%d requested:%d\n", | 293 | "req length > supported MAX:%d requested:%d\n", |
| 284 | GPD_BUF_SIZE, req->length); | 294 | mtu->gen2cp ? GPD_BUF_SIZE_EL : GPD_BUF_SIZE, |
| 295 | req->length); | ||
| 285 | return -EOPNOTSUPP; | 296 | return -EOPNOTSUPP; |
| 286 | } | 297 | } |
| 287 | 298 | ||
| @@ -314,6 +325,7 @@ static int mtu3_gadget_queue(struct usb_ep *ep, | |||
| 314 | 325 | ||
| 315 | error: | 326 | error: |
| 316 | spin_unlock_irqrestore(&mtu->lock, flags); | 327 | spin_unlock_irqrestore(&mtu->lock, flags); |
| 328 | trace_mtu3_gadget_queue(mreq); | ||
| 317 | 329 | ||
| 318 | return ret; | 330 | return ret; |
| 319 | } | 331 | } |
| @@ -331,6 +343,7 @@ static int mtu3_gadget_dequeue(struct usb_ep *ep, struct usb_request *req) | |||
| 331 | return -EINVAL; | 343 | return -EINVAL; |
| 332 | 344 | ||
| 333 | dev_dbg(mtu->dev, "%s : req=%p\n", __func__, req); | 345 | dev_dbg(mtu->dev, "%s : req=%p\n", __func__, req); |
| 346 | trace_mtu3_gadget_dequeue(mreq); | ||
| 334 | 347 | ||
| 335 | spin_lock_irqsave(&mtu->lock, flags); | 348 | spin_lock_irqsave(&mtu->lock, flags); |
| 336 | 349 | ||
| @@ -401,6 +414,7 @@ static int mtu3_gadget_ep_set_halt(struct usb_ep *ep, int value) | |||
| 401 | 414 | ||
| 402 | done: | 415 | done: |
| 403 | spin_unlock_irqrestore(&mtu->lock, flags); | 416 | spin_unlock_irqrestore(&mtu->lock, flags); |
| 417 | trace_mtu3_gadget_ep_set_halt(mep); | ||
| 404 | 418 | ||
| 405 | return ret; | 419 | return ret; |
| 406 | } | 420 | } |
diff --git a/drivers/usb/mtu3/mtu3_gadget_ep0.c b/drivers/usb/mtu3/mtu3_gadget_ep0.c index 7cb7ac980446..4da216c99726 100644 --- a/drivers/usb/mtu3/mtu3_gadget_ep0.c +++ b/drivers/usb/mtu3/mtu3_gadget_ep0.c | |||
| @@ -11,6 +11,8 @@ | |||
| 11 | #include <linux/usb/composite.h> | 11 | #include <linux/usb/composite.h> |
| 12 | 12 | ||
| 13 | #include "mtu3.h" | 13 | #include "mtu3.h" |
| 14 | #include "mtu3_debug.h" | ||
| 15 | #include "mtu3_trace.h" | ||
| 14 | 16 | ||
| 15 | /* ep0 is always mtu3->in_eps[0] */ | 17 | /* ep0 is always mtu3->in_eps[0] */ |
| 16 | #define next_ep0_request(mtu) next_request((mtu)->ep0) | 18 | #define next_ep0_request(mtu) next_request((mtu)->ep0) |
| @@ -634,6 +636,7 @@ __acquires(mtu->lock) | |||
| 634 | int handled = 0; | 636 | int handled = 0; |
| 635 | 637 | ||
| 636 | ep0_read_setup(mtu, &setup); | 638 | ep0_read_setup(mtu, &setup); |
| 639 | trace_mtu3_handle_setup(&setup); | ||
| 637 | 640 | ||
| 638 | if ((setup.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) | 641 | if ((setup.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) |
| 639 | handled = handle_standard_request(mtu, &setup); | 642 | handled = handle_standard_request(mtu, &setup); |
| @@ -710,6 +713,7 @@ irqreturn_t mtu3_ep0_isr(struct mtu3 *mtu) | |||
| 710 | ret = IRQ_HANDLED; | 713 | ret = IRQ_HANDLED; |
| 711 | } | 714 | } |
| 712 | dev_dbg(mtu->dev, "ep0_state: %s\n", decode_ep0_state(mtu)); | 715 | dev_dbg(mtu->dev, "ep0_state: %s\n", decode_ep0_state(mtu)); |
| 716 | mtu3_dbg_trace(mtu->dev, "ep0_state %s", decode_ep0_state(mtu)); | ||
| 713 | 717 | ||
| 714 | switch (mtu->ep0_state) { | 718 | switch (mtu->ep0_state) { |
| 715 | case MU3D_EP0_STATE_TX: | 719 | case MU3D_EP0_STATE_TX: |
diff --git a/drivers/usb/mtu3/mtu3_hw_regs.h b/drivers/usb/mtu3/mtu3_hw_regs.h index 1d65b7476f23..8382d066749e 100644 --- a/drivers/usb/mtu3/mtu3_hw_regs.h +++ b/drivers/usb/mtu3/mtu3_hw_regs.h | |||
| @@ -49,6 +49,7 @@ | |||
| 49 | #define U3D_QCR1 (SSUSB_DEV_BASE + 0x0404) | 49 | #define U3D_QCR1 (SSUSB_DEV_BASE + 0x0404) |
| 50 | #define U3D_QCR2 (SSUSB_DEV_BASE + 0x0408) | 50 | #define U3D_QCR2 (SSUSB_DEV_BASE + 0x0408) |
| 51 | #define U3D_QCR3 (SSUSB_DEV_BASE + 0x040C) | 51 | #define U3D_QCR3 (SSUSB_DEV_BASE + 0x040C) |
| 52 | #define U3D_QFCR (SSUSB_DEV_BASE + 0x0428) | ||
| 52 | #define U3D_TXQHIAR1 (SSUSB_DEV_BASE + 0x0484) | 53 | #define U3D_TXQHIAR1 (SSUSB_DEV_BASE + 0x0484) |
| 53 | #define U3D_RXQHIAR1 (SSUSB_DEV_BASE + 0x04C4) | 54 | #define U3D_RXQHIAR1 (SSUSB_DEV_BASE + 0x04C4) |
| 54 | 55 | ||
| @@ -133,11 +134,23 @@ | |||
| 133 | #define TX_W1C_BITS (~(TX_SENTSTALL)) | 134 | #define TX_W1C_BITS (~(TX_SENTSTALL)) |
| 134 | 135 | ||
| 135 | /* U3D_TX1CSR1 */ | 136 | /* U3D_TX1CSR1 */ |
| 136 | #define TX_MULT(x) (((x) & 0x3) << 22) | 137 | #define TX_MAX_PKT_G2(x) (((x) & 0x7f) << 24) |
| 137 | #define TX_MAX_PKT(x) (((x) & 0x3f) << 16) | 138 | #define TX_MULT_G2(x) (((x) & 0x7) << 21) |
| 139 | #define TX_MULT_OG(x) (((x) & 0x3) << 22) | ||
| 140 | #define TX_MAX_PKT_OG(x) (((x) & 0x3f) << 16) | ||
| 138 | #define TX_SLOT(x) (((x) & 0x3f) << 8) | 141 | #define TX_SLOT(x) (((x) & 0x3f) << 8) |
| 139 | #define TX_TYPE(x) (((x) & 0x3) << 4) | 142 | #define TX_TYPE(x) (((x) & 0x3) << 4) |
| 140 | #define TX_SS_BURST(x) (((x) & 0xf) << 0) | 143 | #define TX_SS_BURST(x) (((x) & 0xf) << 0) |
| 144 | #define TX_MULT(g2c, x) \ | ||
| 145 | ({ \ | ||
| 146 | typeof(x) x_ = (x); \ | ||
| 147 | (g2c) ? TX_MULT_G2(x_) : TX_MULT_OG(x_); \ | ||
| 148 | }) | ||
| 149 | #define TX_MAX_PKT(g2c, x) \ | ||
| 150 | ({ \ | ||
| 151 | typeof(x) x_ = (x); \ | ||
| 152 | (g2c) ? TX_MAX_PKT_G2(x_) : TX_MAX_PKT_OG(x_); \ | ||
| 153 | }) | ||
| 141 | 154 | ||
| 142 | /* for TX_TYPE & RX_TYPE */ | 155 | /* for TX_TYPE & RX_TYPE */ |
| 143 | #define TYPE_BULK (0x0) | 156 | #define TYPE_BULK (0x0) |
| @@ -160,11 +173,23 @@ | |||
| 160 | #define RX_W1C_BITS (~(RX_SENTSTALL | RX_RXPKTRDY)) | 173 | #define RX_W1C_BITS (~(RX_SENTSTALL | RX_RXPKTRDY)) |
| 161 | 174 | ||
| 162 | /* U3D_RX1CSR1 */ | 175 | /* U3D_RX1CSR1 */ |
| 163 | #define RX_MULT(x) (((x) & 0x3) << 22) | 176 | #define RX_MAX_PKT_G2(x) (((x) & 0x7f) << 24) |
| 164 | #define RX_MAX_PKT(x) (((x) & 0x3f) << 16) | 177 | #define RX_MULT_G2(x) (((x) & 0x7) << 21) |
| 178 | #define RX_MULT_OG(x) (((x) & 0x3) << 22) | ||
| 179 | #define RX_MAX_PKT_OG(x) (((x) & 0x3f) << 16) | ||
| 165 | #define RX_SLOT(x) (((x) & 0x3f) << 8) | 180 | #define RX_SLOT(x) (((x) & 0x3f) << 8) |
| 166 | #define RX_TYPE(x) (((x) & 0x3) << 4) | 181 | #define RX_TYPE(x) (((x) & 0x3) << 4) |
| 167 | #define RX_SS_BURST(x) (((x) & 0xf) << 0) | 182 | #define RX_SS_BURST(x) (((x) & 0xf) << 0) |
| 183 | #define RX_MULT(g2c, x) \ | ||
| 184 | ({ \ | ||
| 185 | typeof(x) x_ = (x); \ | ||
| 186 | (g2c) ? RX_MULT_G2(x_) : RX_MULT_OG(x_); \ | ||
| 187 | }) | ||
| 188 | #define RX_MAX_PKT(g2c, x) \ | ||
| 189 | ({ \ | ||
| 190 | typeof(x) x_ = (x); \ | ||
| 191 | (g2c) ? RX_MAX_PKT_G2(x_) : RX_MAX_PKT_OG(x_); \ | ||
| 192 | }) | ||
| 168 | 193 | ||
| 169 | /* U3D_RX1CSR2 */ | 194 | /* U3D_RX1CSR2 */ |
| 170 | #define RX_BINTERVAL(x) (((x) & 0xff) << 24) | 195 | #define RX_BINTERVAL(x) (((x) & 0xff) << 24) |
| @@ -265,6 +290,7 @@ | |||
| 265 | #define U3D_LTSSM_CTRL (SSUSB_USB3_MAC_CSR_BASE + 0x0010) | 290 | #define U3D_LTSSM_CTRL (SSUSB_USB3_MAC_CSR_BASE + 0x0010) |
| 266 | #define U3D_USB3_CONFIG (SSUSB_USB3_MAC_CSR_BASE + 0x001C) | 291 | #define U3D_USB3_CONFIG (SSUSB_USB3_MAC_CSR_BASE + 0x001C) |
| 267 | 292 | ||
| 293 | #define U3D_LINK_STATE_MACHINE (SSUSB_USB3_MAC_CSR_BASE + 0x0134) | ||
| 268 | #define U3D_LTSSM_INTR_ENABLE (SSUSB_USB3_MAC_CSR_BASE + 0x013C) | 294 | #define U3D_LTSSM_INTR_ENABLE (SSUSB_USB3_MAC_CSR_BASE + 0x013C) |
| 269 | #define U3D_LTSSM_INTR (SSUSB_USB3_MAC_CSR_BASE + 0x0140) | 295 | #define U3D_LTSSM_INTR (SSUSB_USB3_MAC_CSR_BASE + 0x0140) |
| 270 | 296 | ||
| @@ -282,6 +308,9 @@ | |||
| 282 | /* U3D_USB3_CONFIG */ | 308 | /* U3D_USB3_CONFIG */ |
| 283 | #define USB3_EN BIT(0) | 309 | #define USB3_EN BIT(0) |
| 284 | 310 | ||
| 311 | /* U3D_LINK_STATE_MACHINE */ | ||
| 312 | #define LTSSM_STATE(x) ((x) & 0x1f) | ||
| 313 | |||
| 285 | /* U3D_LTSSM_INTR_ENABLE */ | 314 | /* U3D_LTSSM_INTR_ENABLE */ |
| 286 | /* U3D_LTSSM_INTR */ | 315 | /* U3D_LTSSM_INTR */ |
| 287 | #define U3_RESUME_INTR BIT(18) | 316 | #define U3_RESUME_INTR BIT(18) |
| @@ -347,6 +376,7 @@ | |||
| 347 | #define U3D_USB20_FRAME_NUM (SSUSB_USB2_CSR_BASE + 0x003C) | 376 | #define U3D_USB20_FRAME_NUM (SSUSB_USB2_CSR_BASE + 0x003C) |
| 348 | #define U3D_USB20_LPM_PARAMETER (SSUSB_USB2_CSR_BASE + 0x0044) | 377 | #define U3D_USB20_LPM_PARAMETER (SSUSB_USB2_CSR_BASE + 0x0044) |
| 349 | #define U3D_USB20_MISC_CONTROL (SSUSB_USB2_CSR_BASE + 0x004C) | 378 | #define U3D_USB20_MISC_CONTROL (SSUSB_USB2_CSR_BASE + 0x004C) |
| 379 | #define U3D_USB20_OPSTATE (SSUSB_USB2_CSR_BASE + 0x0060) | ||
| 350 | 380 | ||
| 351 | /*---------------- SSUSB_USB2_CSR FIELD DEFINITION ----------------*/ | 381 | /*---------------- SSUSB_USB2_CSR FIELD DEFINITION ----------------*/ |
| 352 | 382 | ||
| @@ -419,6 +449,13 @@ | |||
| 419 | #define U3D_SSUSB_DEV_RST_CTRL (SSUSB_SIFSLV_IPPC_BASE + 0x0098) | 449 | #define U3D_SSUSB_DEV_RST_CTRL (SSUSB_SIFSLV_IPPC_BASE + 0x0098) |
| 420 | #define U3D_SSUSB_HW_ID (SSUSB_SIFSLV_IPPC_BASE + 0x00A0) | 450 | #define U3D_SSUSB_HW_ID (SSUSB_SIFSLV_IPPC_BASE + 0x00A0) |
| 421 | #define U3D_SSUSB_HW_SUB_ID (SSUSB_SIFSLV_IPPC_BASE + 0x00A4) | 451 | #define U3D_SSUSB_HW_SUB_ID (SSUSB_SIFSLV_IPPC_BASE + 0x00A4) |
| 452 | #define U3D_SSUSB_IP_TRUNK_VERS (U3D_SSUSB_HW_SUB_ID) | ||
| 453 | #define U3D_SSUSB_PRB_CTRL0 (SSUSB_SIFSLV_IPPC_BASE + 0x00B0) | ||
| 454 | #define U3D_SSUSB_PRB_CTRL1 (SSUSB_SIFSLV_IPPC_BASE + 0x00B4) | ||
| 455 | #define U3D_SSUSB_PRB_CTRL2 (SSUSB_SIFSLV_IPPC_BASE + 0x00B8) | ||
| 456 | #define U3D_SSUSB_PRB_CTRL3 (SSUSB_SIFSLV_IPPC_BASE + 0x00BC) | ||
| 457 | #define U3D_SSUSB_PRB_CTRL4 (SSUSB_SIFSLV_IPPC_BASE + 0x00C0) | ||
| 458 | #define U3D_SSUSB_PRB_CTRL5 (SSUSB_SIFSLV_IPPC_BASE + 0x00C4) | ||
| 422 | #define U3D_SSUSB_IP_SPARE0 (SSUSB_SIFSLV_IPPC_BASE + 0x00C8) | 459 | #define U3D_SSUSB_IP_SPARE0 (SSUSB_SIFSLV_IPPC_BASE + 0x00C8) |
| 423 | 460 | ||
| 424 | /*---------------- SSUSB_SIFSLV_IPPC FIELD DEFINITION ----------------*/ | 461 | /*---------------- SSUSB_SIFSLV_IPPC FIELD DEFINITION ----------------*/ |
| @@ -483,4 +520,7 @@ | |||
| 483 | /* U3D_SSUSB_DEV_RST_CTRL */ | 520 | /* U3D_SSUSB_DEV_RST_CTRL */ |
| 484 | #define SSUSB_DEV_SW_RST BIT(0) | 521 | #define SSUSB_DEV_SW_RST BIT(0) |
| 485 | 522 | ||
| 523 | /* U3D_SSUSB_IP_TRUNK_VERS */ | ||
| 524 | #define IP_TRUNK_VERS(x) (((x) >> 16) & 0xffff) | ||
| 525 | |||
| 486 | #endif /* _SSUSB_HW_REGS_H_ */ | 526 | #endif /* _SSUSB_HW_REGS_H_ */ |
diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c index e086630e41a9..fd0f6c5dfbc1 100644 --- a/drivers/usb/mtu3/mtu3_plat.c +++ b/drivers/usb/mtu3/mtu3_plat.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | 16 | ||
| 17 | #include "mtu3.h" | 17 | #include "mtu3.h" |
| 18 | #include "mtu3_dr.h" | 18 | #include "mtu3_dr.h" |
| 19 | #include "mtu3_debug.h" | ||
| 19 | 20 | ||
| 20 | /* u2-port0 should be powered on and enabled; */ | 21 | /* u2-port0 should be powered on and enabled; */ |
| 21 | int ssusb_check_clocks(struct ssusb_mtk *ssusb, u32 ex_clks) | 22 | int ssusb_check_clocks(struct ssusb_mtk *ssusb, u32 ex_clks) |
| @@ -210,30 +211,16 @@ static void ssusb_ip_sw_reset(struct ssusb_mtk *ssusb) | |||
| 210 | mtu3_setbits(ssusb->ippc_base, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN); | 211 | mtu3_setbits(ssusb->ippc_base, U3D_SSUSB_IP_PW_CTRL2, SSUSB_IP_DEV_PDN); |
| 211 | } | 212 | } |
| 212 | 213 | ||
| 213 | /* ignore the error if the clock does not exist */ | ||
| 214 | static struct clk *get_optional_clk(struct device *dev, const char *id) | ||
| 215 | { | ||
| 216 | struct clk *opt_clk; | ||
| 217 | |||
| 218 | opt_clk = devm_clk_get(dev, id); | ||
| 219 | /* ignore error number except EPROBE_DEFER */ | ||
| 220 | if (IS_ERR(opt_clk) && (PTR_ERR(opt_clk) != -EPROBE_DEFER)) | ||
| 221 | opt_clk = NULL; | ||
| 222 | |||
| 223 | return opt_clk; | ||
| 224 | } | ||
| 225 | |||
| 226 | static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb) | 214 | static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb) |
| 227 | { | 215 | { |
| 228 | struct device_node *node = pdev->dev.of_node; | 216 | struct device_node *node = pdev->dev.of_node; |
| 229 | struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; | 217 | struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; |
| 230 | struct device *dev = &pdev->dev; | 218 | struct device *dev = &pdev->dev; |
| 231 | struct regulator *vbus; | ||
| 232 | struct resource *res; | 219 | struct resource *res; |
| 233 | int i; | 220 | int i; |
| 234 | int ret; | 221 | int ret; |
| 235 | 222 | ||
| 236 | ssusb->vusb33 = devm_regulator_get(&pdev->dev, "vusb33"); | 223 | ssusb->vusb33 = devm_regulator_get(dev, "vusb33"); |
| 237 | if (IS_ERR(ssusb->vusb33)) { | 224 | if (IS_ERR(ssusb->vusb33)) { |
| 238 | dev_err(dev, "failed to get vusb33\n"); | 225 | dev_err(dev, "failed to get vusb33\n"); |
| 239 | return PTR_ERR(ssusb->vusb33); | 226 | return PTR_ERR(ssusb->vusb33); |
| @@ -245,15 +232,15 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb) | |||
| 245 | return PTR_ERR(ssusb->sys_clk); | 232 | return PTR_ERR(ssusb->sys_clk); |
| 246 | } | 233 | } |
| 247 | 234 | ||
| 248 | ssusb->ref_clk = get_optional_clk(dev, "ref_ck"); | 235 | ssusb->ref_clk = devm_clk_get_optional(dev, "ref_ck"); |
| 249 | if (IS_ERR(ssusb->ref_clk)) | 236 | if (IS_ERR(ssusb->ref_clk)) |
| 250 | return PTR_ERR(ssusb->ref_clk); | 237 | return PTR_ERR(ssusb->ref_clk); |
| 251 | 238 | ||
| 252 | ssusb->mcu_clk = get_optional_clk(dev, "mcu_ck"); | 239 | ssusb->mcu_clk = devm_clk_get_optional(dev, "mcu_ck"); |
| 253 | if (IS_ERR(ssusb->mcu_clk)) | 240 | if (IS_ERR(ssusb->mcu_clk)) |
| 254 | return PTR_ERR(ssusb->mcu_clk); | 241 | return PTR_ERR(ssusb->mcu_clk); |
| 255 | 242 | ||
| 256 | ssusb->dma_clk = get_optional_clk(dev, "dma_ck"); | 243 | ssusb->dma_clk = devm_clk_get_optional(dev, "dma_ck"); |
| 257 | if (IS_ERR(ssusb->dma_clk)) | 244 | if (IS_ERR(ssusb->dma_clk)) |
| 258 | return PTR_ERR(ssusb->dma_clk); | 245 | return PTR_ERR(ssusb->dma_clk); |
| 259 | 246 | ||
| @@ -286,7 +273,7 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb) | |||
| 286 | ssusb->dr_mode = USB_DR_MODE_OTG; | 273 | ssusb->dr_mode = USB_DR_MODE_OTG; |
| 287 | 274 | ||
| 288 | if (ssusb->dr_mode == USB_DR_MODE_PERIPHERAL) | 275 | if (ssusb->dr_mode == USB_DR_MODE_PERIPHERAL) |
| 289 | return 0; | 276 | goto out; |
| 290 | 277 | ||
| 291 | /* if host role is supported */ | 278 | /* if host role is supported */ |
| 292 | ret = ssusb_wakeup_of_property_parse(ssusb, node); | 279 | ret = ssusb_wakeup_of_property_parse(ssusb, node); |
| @@ -299,15 +286,14 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb) | |||
| 299 | of_property_read_u32(node, "mediatek,u3p-dis-msk", | 286 | of_property_read_u32(node, "mediatek,u3p-dis-msk", |
| 300 | &ssusb->u3p_dis_msk); | 287 | &ssusb->u3p_dis_msk); |
| 301 | 288 | ||
| 302 | vbus = devm_regulator_get(&pdev->dev, "vbus"); | 289 | otg_sx->vbus = devm_regulator_get(dev, "vbus"); |
| 303 | if (IS_ERR(vbus)) { | 290 | if (IS_ERR(otg_sx->vbus)) { |
| 304 | dev_err(dev, "failed to get vbus\n"); | 291 | dev_err(dev, "failed to get vbus\n"); |
| 305 | return PTR_ERR(vbus); | 292 | return PTR_ERR(otg_sx->vbus); |
| 306 | } | 293 | } |
| 307 | otg_sx->vbus = vbus; | ||
| 308 | 294 | ||
| 309 | if (ssusb->dr_mode == USB_DR_MODE_HOST) | 295 | if (ssusb->dr_mode == USB_DR_MODE_HOST) |
| 310 | return 0; | 296 | goto out; |
| 311 | 297 | ||
| 312 | /* if dual-role mode is supported */ | 298 | /* if dual-role mode is supported */ |
| 313 | otg_sx->is_u3_drd = of_property_read_bool(node, "mediatek,usb3-drd"); | 299 | otg_sx->is_u3_drd = of_property_read_bool(node, "mediatek,usb3-drd"); |
| @@ -322,6 +308,7 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb) | |||
| 322 | } | 308 | } |
| 323 | } | 309 | } |
| 324 | 310 | ||
| 311 | out: | ||
| 325 | dev_info(dev, "dr_mode: %d, is_u3_dr: %d, u3p_dis_msk: %x, drd: %s\n", | 312 | dev_info(dev, "dr_mode: %d, is_u3_dr: %d, u3p_dis_msk: %x, drd: %s\n", |
| 326 | ssusb->dr_mode, otg_sx->is_u3_drd, ssusb->u3p_dis_msk, | 313 | ssusb->dr_mode, otg_sx->is_u3_drd, ssusb->u3p_dis_msk, |
| 327 | otg_sx->manual_drd_enabled ? "manual" : "auto"); | 314 | otg_sx->manual_drd_enabled ? "manual" : "auto"); |
| @@ -354,6 +341,8 @@ static int mtu3_probe(struct platform_device *pdev) | |||
| 354 | if (ret) | 341 | if (ret) |
| 355 | return ret; | 342 | return ret; |
| 356 | 343 | ||
| 344 | ssusb_debugfs_create_root(ssusb); | ||
| 345 | |||
| 357 | /* enable power domain */ | 346 | /* enable power domain */ |
| 358 | pm_runtime_enable(dev); | 347 | pm_runtime_enable(dev); |
| 359 | pm_runtime_get_sync(dev); | 348 | pm_runtime_get_sync(dev); |
| @@ -401,7 +390,11 @@ static int mtu3_probe(struct platform_device *pdev) | |||
| 401 | goto gadget_exit; | 390 | goto gadget_exit; |
| 402 | } | 391 | } |
| 403 | 392 | ||
| 404 | ssusb_otg_switch_init(ssusb); | 393 | ret = ssusb_otg_switch_init(ssusb); |
| 394 | if (ret) { | ||
| 395 | dev_err(dev, "failed to initialize switch\n"); | ||
| 396 | goto host_exit; | ||
| 397 | } | ||
| 405 | break; | 398 | break; |
| 406 | default: | 399 | default: |
| 407 | dev_err(dev, "unsupported mode: %d\n", ssusb->dr_mode); | 400 | dev_err(dev, "unsupported mode: %d\n", ssusb->dr_mode); |
| @@ -411,6 +404,8 @@ static int mtu3_probe(struct platform_device *pdev) | |||
| 411 | 404 | ||
| 412 | return 0; | 405 | return 0; |
| 413 | 406 | ||
| 407 | host_exit: | ||
| 408 | ssusb_host_exit(ssusb); | ||
| 414 | gadget_exit: | 409 | gadget_exit: |
| 415 | ssusb_gadget_exit(ssusb); | 410 | ssusb_gadget_exit(ssusb); |
| 416 | comm_exit: | 411 | comm_exit: |
| @@ -418,6 +413,7 @@ comm_exit: | |||
| 418 | comm_init_err: | 413 | comm_init_err: |
| 419 | pm_runtime_put_sync(dev); | 414 | pm_runtime_put_sync(dev); |
| 420 | pm_runtime_disable(dev); | 415 | pm_runtime_disable(dev); |
| 416 | ssusb_debugfs_remove_root(ssusb); | ||
| 421 | 417 | ||
| 422 | return ret; | 418 | return ret; |
| 423 | } | 419 | } |
| @@ -445,6 +441,7 @@ static int mtu3_remove(struct platform_device *pdev) | |||
| 445 | ssusb_rscs_exit(ssusb); | 441 | ssusb_rscs_exit(ssusb); |
| 446 | pm_runtime_put_sync(&pdev->dev); | 442 | pm_runtime_put_sync(&pdev->dev); |
| 447 | pm_runtime_disable(&pdev->dev); | 443 | pm_runtime_disable(&pdev->dev); |
| 444 | ssusb_debugfs_remove_root(ssusb); | ||
| 448 | 445 | ||
| 449 | return 0; | 446 | return 0; |
| 450 | } | 447 | } |
diff --git a/drivers/usb/mtu3/mtu3_qmu.c b/drivers/usb/mtu3/mtu3_qmu.c index 09f19f70fe8f..3f414f91b589 100644 --- a/drivers/usb/mtu3/mtu3_qmu.c +++ b/drivers/usb/mtu3/mtu3_qmu.c | |||
| @@ -22,17 +22,49 @@ | |||
| 22 | #include <linux/iopoll.h> | 22 | #include <linux/iopoll.h> |
| 23 | 23 | ||
| 24 | #include "mtu3.h" | 24 | #include "mtu3.h" |
| 25 | #include "mtu3_trace.h" | ||
| 25 | 26 | ||
| 26 | #define QMU_CHECKSUM_LEN 16 | 27 | #define QMU_CHECKSUM_LEN 16 |
| 27 | 28 | ||
| 28 | #define GPD_FLAGS_HWO BIT(0) | 29 | #define GPD_FLAGS_HWO BIT(0) |
| 29 | #define GPD_FLAGS_BDP BIT(1) | 30 | #define GPD_FLAGS_BDP BIT(1) |
| 30 | #define GPD_FLAGS_BPS BIT(2) | 31 | #define GPD_FLAGS_BPS BIT(2) |
| 32 | #define GPD_FLAGS_ZLP BIT(6) | ||
| 31 | #define GPD_FLAGS_IOC BIT(7) | 33 | #define GPD_FLAGS_IOC BIT(7) |
| 32 | 34 | #define GET_GPD_HWO(gpd) (le32_to_cpu((gpd)->dw0_info) & GPD_FLAGS_HWO) | |
| 33 | #define GPD_EXT_FLAG_ZLP BIT(5) | 35 | |
| 34 | #define GPD_EXT_NGP(x) (((x) & 0xf) << 4) | 36 | #define GPD_RX_BUF_LEN_OG(x) (((x) & 0xffff) << 16) |
| 35 | #define GPD_EXT_BUF(x) (((x) & 0xf) << 0) | 37 | #define GPD_RX_BUF_LEN_EL(x) (((x) & 0xfffff) << 12) |
| 38 | #define GPD_RX_BUF_LEN(mtu, x) \ | ||
| 39 | ({ \ | ||
| 40 | typeof(x) x_ = (x); \ | ||
| 41 | ((mtu)->gen2cp) ? GPD_RX_BUF_LEN_EL(x_) : GPD_RX_BUF_LEN_OG(x_); \ | ||
| 42 | }) | ||
| 43 | |||
| 44 | #define GPD_DATA_LEN_OG(x) ((x) & 0xffff) | ||
| 45 | #define GPD_DATA_LEN_EL(x) ((x) & 0xfffff) | ||
| 46 | #define GPD_DATA_LEN(mtu, x) \ | ||
| 47 | ({ \ | ||
| 48 | typeof(x) x_ = (x); \ | ||
| 49 | ((mtu)->gen2cp) ? GPD_DATA_LEN_EL(x_) : GPD_DATA_LEN_OG(x_); \ | ||
| 50 | }) | ||
| 51 | |||
| 52 | #define GPD_EXT_FLAG_ZLP BIT(29) | ||
| 53 | #define GPD_EXT_NGP_OG(x) (((x) & 0xf) << 20) | ||
| 54 | #define GPD_EXT_BUF_OG(x) (((x) & 0xf) << 16) | ||
| 55 | #define GPD_EXT_NGP_EL(x) (((x) & 0xf) << 28) | ||
| 56 | #define GPD_EXT_BUF_EL(x) (((x) & 0xf) << 24) | ||
| 57 | #define GPD_EXT_NGP(mtu, x) \ | ||
| 58 | ({ \ | ||
| 59 | typeof(x) x_ = (x); \ | ||
| 60 | ((mtu)->gen2cp) ? GPD_EXT_NGP_EL(x_) : GPD_EXT_NGP_OG(x_); \ | ||
| 61 | }) | ||
| 62 | |||
| 63 | #define GPD_EXT_BUF(mtu, x) \ | ||
| 64 | ({ \ | ||
| 65 | typeof(x) x_ = (x); \ | ||
| 66 | ((mtu)->gen2cp) ? GPD_EXT_BUF_EL(x_) : GPD_EXT_BUF_OG(x_); \ | ||
| 67 | }) | ||
| 36 | 68 | ||
| 37 | #define HILO_GEN64(hi, lo) (((u64)(hi) << 32) + (lo)) | 69 | #define HILO_GEN64(hi, lo) (((u64)(hi) << 32) + (lo)) |
| 38 | #define HILO_DMA(hi, lo) \ | 70 | #define HILO_DMA(hi, lo) \ |
| @@ -125,7 +157,7 @@ static void reset_gpd_list(struct mtu3_ep *mep) | |||
| 125 | struct qmu_gpd *gpd = ring->start; | 157 | struct qmu_gpd *gpd = ring->start; |
| 126 | 158 | ||
| 127 | if (gpd) { | 159 | if (gpd) { |
| 128 | gpd->flag &= ~GPD_FLAGS_HWO; | 160 | gpd->dw0_info &= cpu_to_le32(~GPD_FLAGS_HWO); |
| 129 | gpd_ring_init(ring, gpd); | 161 | gpd_ring_init(ring, gpd); |
| 130 | } | 162 | } |
| 131 | } | 163 | } |
| @@ -214,16 +246,14 @@ static int mtu3_prepare_tx_gpd(struct mtu3_ep *mep, struct mtu3_request *mreq) | |||
| 214 | struct mtu3_gpd_ring *ring = &mep->gpd_ring; | 246 | struct mtu3_gpd_ring *ring = &mep->gpd_ring; |
| 215 | struct qmu_gpd *gpd = ring->enqueue; | 247 | struct qmu_gpd *gpd = ring->enqueue; |
| 216 | struct usb_request *req = &mreq->request; | 248 | struct usb_request *req = &mreq->request; |
| 249 | struct mtu3 *mtu = mep->mtu; | ||
| 217 | dma_addr_t enq_dma; | 250 | dma_addr_t enq_dma; |
| 218 | u16 ext_addr; | 251 | u32 ext_addr; |
| 219 | |||
| 220 | /* set all fields to zero as default value */ | ||
| 221 | memset(gpd, 0, sizeof(*gpd)); | ||
| 222 | 252 | ||
| 253 | gpd->dw0_info = 0; /* SW own it */ | ||
| 223 | gpd->buffer = cpu_to_le32(lower_32_bits(req->dma)); | 254 | gpd->buffer = cpu_to_le32(lower_32_bits(req->dma)); |
| 224 | ext_addr = GPD_EXT_BUF(upper_32_bits(req->dma)); | 255 | ext_addr = GPD_EXT_BUF(mtu, upper_32_bits(req->dma)); |
| 225 | gpd->buf_len = cpu_to_le16(req->length); | 256 | gpd->dw3_info = cpu_to_le32(GPD_DATA_LEN(mtu, req->length)); |
| 226 | gpd->flag |= GPD_FLAGS_IOC; | ||
| 227 | 257 | ||
| 228 | /* get the next GPD */ | 258 | /* get the next GPD */ |
| 229 | enq = advance_enq_gpd(ring); | 259 | enq = advance_enq_gpd(ring); |
| @@ -231,17 +261,22 @@ static int mtu3_prepare_tx_gpd(struct mtu3_ep *mep, struct mtu3_request *mreq) | |||
| 231 | dev_dbg(mep->mtu->dev, "TX-EP%d queue gpd=%p, enq=%p, qdma=%pad\n", | 261 | dev_dbg(mep->mtu->dev, "TX-EP%d queue gpd=%p, enq=%p, qdma=%pad\n", |
| 232 | mep->epnum, gpd, enq, &enq_dma); | 262 | mep->epnum, gpd, enq, &enq_dma); |
| 233 | 263 | ||
| 234 | enq->flag &= ~GPD_FLAGS_HWO; | 264 | enq->dw0_info &= cpu_to_le32(~GPD_FLAGS_HWO); |
| 235 | gpd->next_gpd = cpu_to_le32(lower_32_bits(enq_dma)); | 265 | gpd->next_gpd = cpu_to_le32(lower_32_bits(enq_dma)); |
| 236 | ext_addr |= GPD_EXT_NGP(upper_32_bits(enq_dma)); | 266 | ext_addr |= GPD_EXT_NGP(mtu, upper_32_bits(enq_dma)); |
| 237 | gpd->tx_ext_addr = cpu_to_le16(ext_addr); | 267 | gpd->dw0_info = cpu_to_le32(ext_addr); |
| 238 | 268 | ||
| 239 | if (req->zero) | 269 | if (req->zero) { |
| 240 | gpd->ext_flag |= GPD_EXT_FLAG_ZLP; | 270 | if (mtu->gen2cp) |
| 271 | gpd->dw0_info |= cpu_to_le32(GPD_FLAGS_ZLP); | ||
| 272 | else | ||
| 273 | gpd->dw3_info |= cpu_to_le32(GPD_EXT_FLAG_ZLP); | ||
| 274 | } | ||
| 241 | 275 | ||
| 242 | gpd->flag |= GPD_FLAGS_HWO; | 276 | gpd->dw0_info |= cpu_to_le32(GPD_FLAGS_IOC | GPD_FLAGS_HWO); |
| 243 | 277 | ||
| 244 | mreq->gpd = gpd; | 278 | mreq->gpd = gpd; |
| 279 | trace_mtu3_prepare_gpd(mep, gpd); | ||
| 245 | 280 | ||
| 246 | return 0; | 281 | return 0; |
| 247 | } | 282 | } |
| @@ -252,16 +287,14 @@ static int mtu3_prepare_rx_gpd(struct mtu3_ep *mep, struct mtu3_request *mreq) | |||
| 252 | struct mtu3_gpd_ring *ring = &mep->gpd_ring; | 287 | struct mtu3_gpd_ring *ring = &mep->gpd_ring; |
| 253 | struct qmu_gpd *gpd = ring->enqueue; | 288 | struct qmu_gpd *gpd = ring->enqueue; |
| 254 | struct usb_request *req = &mreq->request; | 289 | struct usb_request *req = &mreq->request; |
| 290 | struct mtu3 *mtu = mep->mtu; | ||
| 255 | dma_addr_t enq_dma; | 291 | dma_addr_t enq_dma; |
| 256 | u16 ext_addr; | 292 | u32 ext_addr; |
| 257 | |||
| 258 | /* set all fields to zero as default value */ | ||
| 259 | memset(gpd, 0, sizeof(*gpd)); | ||
| 260 | 293 | ||
| 294 | gpd->dw0_info = 0; /* SW own it */ | ||
| 261 | gpd->buffer = cpu_to_le32(lower_32_bits(req->dma)); | 295 | gpd->buffer = cpu_to_le32(lower_32_bits(req->dma)); |
| 262 | ext_addr = GPD_EXT_BUF(upper_32_bits(req->dma)); | 296 | ext_addr = GPD_EXT_BUF(mtu, upper_32_bits(req->dma)); |
| 263 | gpd->data_buf_len = cpu_to_le16(req->length); | 297 | gpd->dw0_info = cpu_to_le32(GPD_RX_BUF_LEN(mtu, req->length)); |
| 264 | gpd->flag |= GPD_FLAGS_IOC; | ||
| 265 | 298 | ||
| 266 | /* get the next GPD */ | 299 | /* get the next GPD */ |
| 267 | enq = advance_enq_gpd(ring); | 300 | enq = advance_enq_gpd(ring); |
| @@ -269,13 +302,14 @@ static int mtu3_prepare_rx_gpd(struct mtu3_ep *mep, struct mtu3_request *mreq) | |||
| 269 | dev_dbg(mep->mtu->dev, "RX-EP%d queue gpd=%p, enq=%p, qdma=%pad\n", | 302 | dev_dbg(mep->mtu->dev, "RX-EP%d queue gpd=%p, enq=%p, qdma=%pad\n", |
| 270 | mep->epnum, gpd, enq, &enq_dma); | 303 | mep->epnum, gpd, enq, &enq_dma); |
| 271 | 304 | ||
| 272 | enq->flag &= ~GPD_FLAGS_HWO; | 305 | enq->dw0_info &= cpu_to_le32(~GPD_FLAGS_HWO); |
| 273 | gpd->next_gpd = cpu_to_le32(lower_32_bits(enq_dma)); | 306 | gpd->next_gpd = cpu_to_le32(lower_32_bits(enq_dma)); |
| 274 | ext_addr |= GPD_EXT_NGP(upper_32_bits(enq_dma)); | 307 | ext_addr |= GPD_EXT_NGP(mtu, upper_32_bits(enq_dma)); |
| 275 | gpd->rx_ext_addr = cpu_to_le16(ext_addr); | 308 | gpd->dw3_info = cpu_to_le32(ext_addr); |
| 276 | gpd->flag |= GPD_FLAGS_HWO; | 309 | gpd->dw0_info |= cpu_to_le32(GPD_FLAGS_IOC | GPD_FLAGS_HWO); |
| 277 | 310 | ||
| 278 | mreq->gpd = gpd; | 311 | mreq->gpd = gpd; |
| 312 | trace_mtu3_prepare_gpd(mep, gpd); | ||
| 279 | 313 | ||
| 280 | return 0; | 314 | return 0; |
| 281 | } | 315 | } |
| @@ -382,27 +416,25 @@ static void qmu_tx_zlp_error_handler(struct mtu3 *mtu, u8 epnum) | |||
| 382 | struct mtu3_gpd_ring *ring = &mep->gpd_ring; | 416 | struct mtu3_gpd_ring *ring = &mep->gpd_ring; |
| 383 | void __iomem *mbase = mtu->mac_base; | 417 | void __iomem *mbase = mtu->mac_base; |
| 384 | struct qmu_gpd *gpd_current = NULL; | 418 | struct qmu_gpd *gpd_current = NULL; |
| 385 | struct usb_request *req = NULL; | ||
| 386 | struct mtu3_request *mreq; | 419 | struct mtu3_request *mreq; |
| 387 | dma_addr_t cur_gpd_dma; | 420 | dma_addr_t cur_gpd_dma; |
| 388 | u32 txcsr = 0; | 421 | u32 txcsr = 0; |
| 389 | int ret; | 422 | int ret; |
| 390 | 423 | ||
| 391 | mreq = next_request(mep); | 424 | mreq = next_request(mep); |
| 392 | if (mreq && mreq->request.length == 0) | 425 | if (mreq && mreq->request.length != 0) |
| 393 | req = &mreq->request; | ||
| 394 | else | ||
| 395 | return; | 426 | return; |
| 396 | 427 | ||
| 397 | cur_gpd_dma = read_txq_cur_addr(mbase, epnum); | 428 | cur_gpd_dma = read_txq_cur_addr(mbase, epnum); |
| 398 | gpd_current = gpd_dma_to_virt(ring, cur_gpd_dma); | 429 | gpd_current = gpd_dma_to_virt(ring, cur_gpd_dma); |
| 399 | 430 | ||
| 400 | if (le16_to_cpu(gpd_current->buf_len) != 0) { | 431 | if (GPD_DATA_LEN(mtu, le32_to_cpu(gpd_current->dw3_info)) != 0) { |
| 401 | dev_err(mtu->dev, "TX EP%d buffer length error(!=0)\n", epnum); | 432 | dev_err(mtu->dev, "TX EP%d buffer length error(!=0)\n", epnum); |
| 402 | return; | 433 | return; |
| 403 | } | 434 | } |
| 404 | 435 | ||
| 405 | dev_dbg(mtu->dev, "%s send ZLP for req=%p\n", __func__, req); | 436 | dev_dbg(mtu->dev, "%s send ZLP for req=%p\n", __func__, mreq); |
| 437 | trace_mtu3_zlp_exp_gpd(mep, gpd_current); | ||
| 406 | 438 | ||
| 407 | mtu3_clrbits(mbase, MU3D_EP_TXCR0(mep->epnum), TX_DMAREQEN); | 439 | mtu3_clrbits(mbase, MU3D_EP_TXCR0(mep->epnum), TX_DMAREQEN); |
| 408 | 440 | ||
| @@ -415,8 +447,7 @@ static void qmu_tx_zlp_error_handler(struct mtu3 *mtu, u8 epnum) | |||
| 415 | mtu3_setbits(mbase, MU3D_EP_TXCR0(mep->epnum), TX_TXPKTRDY); | 447 | mtu3_setbits(mbase, MU3D_EP_TXCR0(mep->epnum), TX_TXPKTRDY); |
| 416 | 448 | ||
| 417 | /* by pass the current GDP */ | 449 | /* by pass the current GDP */ |
| 418 | gpd_current->flag |= GPD_FLAGS_BPS; | 450 | gpd_current->dw0_info |= cpu_to_le32(GPD_FLAGS_BPS | GPD_FLAGS_HWO); |
| 419 | gpd_current->flag |= GPD_FLAGS_HWO; | ||
| 420 | 451 | ||
| 421 | /*enable DMAREQEN, switch back to QMU mode */ | 452 | /*enable DMAREQEN, switch back to QMU mode */ |
| 422 | mtu3_setbits(mbase, MU3D_EP_TXCR0(mep->epnum), TX_DMAREQEN); | 453 | mtu3_setbits(mbase, MU3D_EP_TXCR0(mep->epnum), TX_DMAREQEN); |
| @@ -448,7 +479,7 @@ static void qmu_done_tx(struct mtu3 *mtu, u8 epnum) | |||
| 448 | dev_dbg(mtu->dev, "%s EP%d, last=%p, current=%p, enq=%p\n", | 479 | dev_dbg(mtu->dev, "%s EP%d, last=%p, current=%p, enq=%p\n", |
| 449 | __func__, epnum, gpd, gpd_current, ring->enqueue); | 480 | __func__, epnum, gpd, gpd_current, ring->enqueue); |
| 450 | 481 | ||
| 451 | while (gpd != gpd_current && !(gpd->flag & GPD_FLAGS_HWO)) { | 482 | while (gpd != gpd_current && !GET_GPD_HWO(gpd)) { |
| 452 | 483 | ||
| 453 | mreq = next_request(mep); | 484 | mreq = next_request(mep); |
| 454 | 485 | ||
| @@ -458,7 +489,8 @@ static void qmu_done_tx(struct mtu3 *mtu, u8 epnum) | |||
| 458 | } | 489 | } |
| 459 | 490 | ||
| 460 | request = &mreq->request; | 491 | request = &mreq->request; |
| 461 | request->actual = le16_to_cpu(gpd->buf_len); | 492 | request->actual = GPD_DATA_LEN(mtu, le32_to_cpu(gpd->dw3_info)); |
| 493 | trace_mtu3_complete_gpd(mep, gpd); | ||
| 462 | mtu3_req_complete(mep, request, 0); | 494 | mtu3_req_complete(mep, request, 0); |
| 463 | 495 | ||
| 464 | gpd = advance_deq_gpd(ring); | 496 | gpd = advance_deq_gpd(ring); |
| @@ -486,7 +518,7 @@ static void qmu_done_rx(struct mtu3 *mtu, u8 epnum) | |||
| 486 | dev_dbg(mtu->dev, "%s EP%d, last=%p, current=%p, enq=%p\n", | 518 | dev_dbg(mtu->dev, "%s EP%d, last=%p, current=%p, enq=%p\n", |
| 487 | __func__, epnum, gpd, gpd_current, ring->enqueue); | 519 | __func__, epnum, gpd, gpd_current, ring->enqueue); |
| 488 | 520 | ||
| 489 | while (gpd != gpd_current && !(gpd->flag & GPD_FLAGS_HWO)) { | 521 | while (gpd != gpd_current && !GET_GPD_HWO(gpd)) { |
| 490 | 522 | ||
| 491 | mreq = next_request(mep); | 523 | mreq = next_request(mep); |
| 492 | 524 | ||
| @@ -496,7 +528,8 @@ static void qmu_done_rx(struct mtu3 *mtu, u8 epnum) | |||
| 496 | } | 528 | } |
| 497 | req = &mreq->request; | 529 | req = &mreq->request; |
| 498 | 530 | ||
| 499 | req->actual = le16_to_cpu(gpd->buf_len); | 531 | req->actual = GPD_DATA_LEN(mtu, le32_to_cpu(gpd->dw3_info)); |
| 532 | trace_mtu3_complete_gpd(mep, gpd); | ||
| 500 | mtu3_req_complete(mep, req, 0); | 533 | mtu3_req_complete(mep, req, 0); |
| 501 | 534 | ||
| 502 | gpd = advance_deq_gpd(ring); | 535 | gpd = advance_deq_gpd(ring); |
| @@ -574,6 +607,7 @@ irqreturn_t mtu3_qmu_isr(struct mtu3 *mtu) | |||
| 574 | dev_dbg(mtu->dev, "=== QMUdone[tx=%x, rx=%x] QMUexp[%x] ===\n", | 607 | dev_dbg(mtu->dev, "=== QMUdone[tx=%x, rx=%x] QMUexp[%x] ===\n", |
| 575 | (qmu_done_status & 0xFFFF), qmu_done_status >> 16, | 608 | (qmu_done_status & 0xFFFF), qmu_done_status >> 16, |
| 576 | qmu_status); | 609 | qmu_status); |
| 610 | trace_mtu3_qmu_isr(qmu_done_status, qmu_status); | ||
| 577 | 611 | ||
| 578 | if (qmu_done_status) | 612 | if (qmu_done_status) |
| 579 | qmu_done_isr(mtu, qmu_done_status); | 613 | qmu_done_isr(mtu, qmu_done_status); |
diff --git a/drivers/usb/mtu3/mtu3_qmu.h b/drivers/usb/mtu3/mtu3_qmu.h index 81f5151a55ed..9cfde201db63 100644 --- a/drivers/usb/mtu3/mtu3_qmu.h +++ b/drivers/usb/mtu3/mtu3_qmu.h | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #define QMU_GPD_RING_SIZE (MAX_GPD_NUM * QMU_GPD_SIZE) | 15 | #define QMU_GPD_RING_SIZE (MAX_GPD_NUM * QMU_GPD_SIZE) |
| 16 | 16 | ||
| 17 | #define GPD_BUF_SIZE 65532 | 17 | #define GPD_BUF_SIZE 65532 |
| 18 | #define GPD_BUF_SIZE_EL 1048572 | ||
| 18 | 19 | ||
| 19 | void mtu3_qmu_stop(struct mtu3_ep *mep); | 20 | void mtu3_qmu_stop(struct mtu3_ep *mep); |
| 20 | int mtu3_qmu_start(struct mtu3_ep *mep); | 21 | int mtu3_qmu_start(struct mtu3_ep *mep); |
diff --git a/drivers/usb/mtu3/mtu3_trace.c b/drivers/usb/mtu3/mtu3_trace.c new file mode 100644 index 000000000000..4f5e7857ec31 --- /dev/null +++ b/drivers/usb/mtu3/mtu3_trace.c | |||
| @@ -0,0 +1,23 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /** | ||
| 3 | * mtu3_trace.c - trace support | ||
| 4 | * | ||
| 5 | * Copyright (C) 2019 MediaTek Inc. | ||
| 6 | * | ||
| 7 | * Author: Chunfeng Yun <chunfeng.yun@mediatek.com> | ||
| 8 | */ | ||
| 9 | |||
| 10 | #define CREATE_TRACE_POINTS | ||
| 11 | #include "mtu3_trace.h" | ||
| 12 | |||
| 13 | void mtu3_dbg_trace(struct device *dev, const char *fmt, ...) | ||
| 14 | { | ||
| 15 | struct va_format vaf; | ||
| 16 | va_list args; | ||
| 17 | |||
| 18 | va_start(args, fmt); | ||
| 19 | vaf.fmt = fmt; | ||
| 20 | vaf.va = &args; | ||
| 21 | trace_mtu3_log(dev, &vaf); | ||
| 22 | va_end(args); | ||
| 23 | } | ||
diff --git a/drivers/usb/mtu3/mtu3_trace.h b/drivers/usb/mtu3/mtu3_trace.h new file mode 100644 index 000000000000..050e30f0fbd4 --- /dev/null +++ b/drivers/usb/mtu3/mtu3_trace.h | |||
| @@ -0,0 +1,279 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /** | ||
| 3 | * mtu3_trace.h - trace support | ||
| 4 | * | ||
| 5 | * Copyright (C) 2019 MediaTek Inc. | ||
| 6 | * | ||
| 7 | * Author: Chunfeng Yun <chunfeng.yun@mediatek.com> | ||
| 8 | */ | ||
| 9 | |||
| 10 | #undef TRACE_SYSTEM | ||
| 11 | #define TRACE_SYSTEM mtu3 | ||
| 12 | |||
| 13 | #if !defined(__MTU3_TRACE_H__) || defined(TRACE_HEADER_MULTI_READ) | ||
| 14 | #define __MTU3_TRACE_H__ | ||
| 15 | |||
| 16 | #include <linux/types.h> | ||
| 17 | #include <linux/tracepoint.h> | ||
| 18 | |||
| 19 | #include "mtu3.h" | ||
| 20 | |||
| 21 | #define MTU3_MSG_MAX 256 | ||
| 22 | |||
| 23 | TRACE_EVENT(mtu3_log, | ||
| 24 | TP_PROTO(struct device *dev, struct va_format *vaf), | ||
| 25 | TP_ARGS(dev, vaf), | ||
| 26 | TP_STRUCT__entry( | ||
| 27 | __string(name, dev_name(dev)) | ||
| 28 | __dynamic_array(char, msg, MTU3_MSG_MAX) | ||
| 29 | ), | ||
| 30 | TP_fast_assign( | ||
| 31 | __assign_str(name, dev_name(dev)); | ||
| 32 | vsnprintf(__get_str(msg), MTU3_MSG_MAX, vaf->fmt, *vaf->va); | ||
| 33 | ), | ||
| 34 | TP_printk("%s: %s", __get_str(name), __get_str(msg)) | ||
| 35 | ); | ||
| 36 | |||
| 37 | TRACE_EVENT(mtu3_u3_ltssm_isr, | ||
| 38 | TP_PROTO(u32 intr), | ||
| 39 | TP_ARGS(intr), | ||
| 40 | TP_STRUCT__entry( | ||
| 41 | __field(u32, intr) | ||
| 42 | ), | ||
| 43 | TP_fast_assign( | ||
| 44 | __entry->intr = intr; | ||
| 45 | ), | ||
| 46 | TP_printk("(%08x) %s %s %s %s %s %s", __entry->intr, | ||
| 47 | __entry->intr & HOT_RST_INTR ? "HOT_RST" : "", | ||
| 48 | __entry->intr & WARM_RST_INTR ? "WARM_RST" : "", | ||
| 49 | __entry->intr & ENTER_U3_INTR ? "ENT_U3" : "", | ||
| 50 | __entry->intr & EXIT_U3_INTR ? "EXIT_U3" : "", | ||
| 51 | __entry->intr & VBUS_RISE_INTR ? "VBUS_RISE" : "", | ||
| 52 | __entry->intr & VBUS_FALL_INTR ? "VBUS_FALL" : "" | ||
| 53 | ) | ||
| 54 | ); | ||
| 55 | |||
| 56 | TRACE_EVENT(mtu3_u2_common_isr, | ||
| 57 | TP_PROTO(u32 intr), | ||
| 58 | TP_ARGS(intr), | ||
| 59 | TP_STRUCT__entry( | ||
| 60 | __field(u32, intr) | ||
| 61 | ), | ||
| 62 | TP_fast_assign( | ||
| 63 | __entry->intr = intr; | ||
| 64 | ), | ||
| 65 | TP_printk("(%08x) %s %s %s", __entry->intr, | ||
| 66 | __entry->intr & SUSPEND_INTR ? "SUSPEND" : "", | ||
| 67 | __entry->intr & RESUME_INTR ? "RESUME" : "", | ||
| 68 | __entry->intr & RESET_INTR ? "RESET" : "" | ||
| 69 | ) | ||
| 70 | ); | ||
| 71 | |||
| 72 | TRACE_EVENT(mtu3_qmu_isr, | ||
| 73 | TP_PROTO(u32 done_intr, u32 exp_intr), | ||
| 74 | TP_ARGS(done_intr, exp_intr), | ||
| 75 | TP_STRUCT__entry( | ||
| 76 | __field(u32, done_intr) | ||
| 77 | __field(u32, exp_intr) | ||
| 78 | ), | ||
| 79 | TP_fast_assign( | ||
| 80 | __entry->done_intr = done_intr; | ||
| 81 | __entry->exp_intr = exp_intr; | ||
| 82 | ), | ||
| 83 | TP_printk("done (tx %04x, rx %04x), exp (%08x)", | ||
| 84 | __entry->done_intr & 0xffff, | ||
| 85 | __entry->done_intr >> 16, | ||
| 86 | __entry->exp_intr | ||
| 87 | ) | ||
| 88 | ); | ||
| 89 | |||
| 90 | DECLARE_EVENT_CLASS(mtu3_log_setup, | ||
| 91 | TP_PROTO(struct usb_ctrlrequest *setup), | ||
| 92 | TP_ARGS(setup), | ||
| 93 | TP_STRUCT__entry( | ||
| 94 | __field(__u8, bRequestType) | ||
| 95 | __field(__u8, bRequest) | ||
| 96 | __field(__u16, wValue) | ||
| 97 | __field(__u16, wIndex) | ||
| 98 | __field(__u16, wLength) | ||
| 99 | ), | ||
| 100 | TP_fast_assign( | ||
| 101 | __entry->bRequestType = setup->bRequestType; | ||
| 102 | __entry->bRequest = setup->bRequest; | ||
| 103 | __entry->wValue = le16_to_cpu(setup->wValue); | ||
| 104 | __entry->wIndex = le16_to_cpu(setup->wIndex); | ||
| 105 | __entry->wLength = le16_to_cpu(setup->wLength); | ||
| 106 | ), | ||
| 107 | TP_printk("setup - %02x %02x %04x %04x %04x", | ||
| 108 | __entry->bRequestType, __entry->bRequest, | ||
| 109 | __entry->wValue, __entry->wIndex, __entry->wLength | ||
| 110 | ) | ||
| 111 | ); | ||
| 112 | |||
| 113 | DEFINE_EVENT(mtu3_log_setup, mtu3_handle_setup, | ||
| 114 | TP_PROTO(struct usb_ctrlrequest *setup), | ||
| 115 | TP_ARGS(setup) | ||
| 116 | ); | ||
| 117 | |||
| 118 | DECLARE_EVENT_CLASS(mtu3_log_request, | ||
| 119 | TP_PROTO(struct mtu3_request *mreq), | ||
| 120 | TP_ARGS(mreq), | ||
| 121 | TP_STRUCT__entry( | ||
| 122 | __string(name, mreq->mep->name) | ||
| 123 | __field(struct mtu3_request *, mreq) | ||
| 124 | __field(struct qmu_gpd *, gpd) | ||
| 125 | __field(unsigned int, actual) | ||
| 126 | __field(unsigned int, length) | ||
| 127 | __field(int, status) | ||
| 128 | __field(int, zero) | ||
| 129 | __field(int, no_interrupt) | ||
| 130 | ), | ||
| 131 | TP_fast_assign( | ||
| 132 | __assign_str(name, mreq->mep->name); | ||
| 133 | __entry->mreq = mreq; | ||
| 134 | __entry->gpd = mreq->gpd; | ||
| 135 | __entry->actual = mreq->request.actual; | ||
| 136 | __entry->length = mreq->request.length; | ||
| 137 | __entry->status = mreq->request.status; | ||
| 138 | __entry->zero = mreq->request.zero; | ||
| 139 | __entry->no_interrupt = mreq->request.no_interrupt; | ||
| 140 | ), | ||
| 141 | TP_printk("%s: req %p gpd %p len %u/%u %s%s --> %d", | ||
| 142 | __get_str(name), __entry->mreq, __entry->gpd, | ||
| 143 | __entry->actual, __entry->length, | ||
| 144 | __entry->zero ? "Z" : "z", | ||
| 145 | __entry->no_interrupt ? "i" : "I", | ||
| 146 | __entry->status | ||
| 147 | ) | ||
| 148 | ); | ||
| 149 | |||
| 150 | DEFINE_EVENT(mtu3_log_request, mtu3_alloc_request, | ||
| 151 | TP_PROTO(struct mtu3_request *req), | ||
| 152 | TP_ARGS(req) | ||
| 153 | ); | ||
| 154 | |||
| 155 | DEFINE_EVENT(mtu3_log_request, mtu3_free_request, | ||
| 156 | TP_PROTO(struct mtu3_request *req), | ||
| 157 | TP_ARGS(req) | ||
| 158 | ); | ||
| 159 | |||
| 160 | DEFINE_EVENT(mtu3_log_request, mtu3_gadget_queue, | ||
| 161 | TP_PROTO(struct mtu3_request *req), | ||
| 162 | TP_ARGS(req) | ||
| 163 | ); | ||
| 164 | |||
| 165 | DEFINE_EVENT(mtu3_log_request, mtu3_gadget_dequeue, | ||
| 166 | TP_PROTO(struct mtu3_request *req), | ||
| 167 | TP_ARGS(req) | ||
| 168 | ); | ||
| 169 | |||
| 170 | DEFINE_EVENT(mtu3_log_request, mtu3_req_complete, | ||
| 171 | TP_PROTO(struct mtu3_request *req), | ||
| 172 | TP_ARGS(req) | ||
| 173 | ); | ||
| 174 | |||
| 175 | DECLARE_EVENT_CLASS(mtu3_log_gpd, | ||
| 176 | TP_PROTO(struct mtu3_ep *mep, struct qmu_gpd *gpd), | ||
| 177 | TP_ARGS(mep, gpd), | ||
| 178 | TP_STRUCT__entry( | ||
| 179 | __string(name, mep->name) | ||
| 180 | __field(struct qmu_gpd *, gpd) | ||
| 181 | __field(u32, dw0) | ||
| 182 | __field(u32, dw1) | ||
| 183 | __field(u32, dw2) | ||
| 184 | __field(u32, dw3) | ||
| 185 | ), | ||
| 186 | TP_fast_assign( | ||
| 187 | __assign_str(name, mep->name); | ||
| 188 | __entry->gpd = gpd; | ||
| 189 | __entry->dw0 = le32_to_cpu(gpd->dw0_info); | ||
| 190 | __entry->dw1 = le32_to_cpu(gpd->next_gpd); | ||
| 191 | __entry->dw2 = le32_to_cpu(gpd->buffer); | ||
| 192 | __entry->dw3 = le32_to_cpu(gpd->dw3_info); | ||
| 193 | ), | ||
| 194 | TP_printk("%s: gpd %p - %08x %08x %08x %08x", | ||
| 195 | __get_str(name), __entry->gpd, | ||
| 196 | __entry->dw0, __entry->dw1, | ||
| 197 | __entry->dw2, __entry->dw3 | ||
| 198 | ) | ||
| 199 | ); | ||
| 200 | |||
| 201 | DEFINE_EVENT(mtu3_log_gpd, mtu3_prepare_gpd, | ||
| 202 | TP_PROTO(struct mtu3_ep *mep, struct qmu_gpd *gpd), | ||
| 203 | TP_ARGS(mep, gpd) | ||
| 204 | ); | ||
| 205 | |||
| 206 | DEFINE_EVENT(mtu3_log_gpd, mtu3_complete_gpd, | ||
| 207 | TP_PROTO(struct mtu3_ep *mep, struct qmu_gpd *gpd), | ||
| 208 | TP_ARGS(mep, gpd) | ||
| 209 | ); | ||
| 210 | |||
| 211 | DEFINE_EVENT(mtu3_log_gpd, mtu3_zlp_exp_gpd, | ||
| 212 | TP_PROTO(struct mtu3_ep *mep, struct qmu_gpd *gpd), | ||
| 213 | TP_ARGS(mep, gpd) | ||
| 214 | ); | ||
| 215 | |||
| 216 | DECLARE_EVENT_CLASS(mtu3_log_ep, | ||
| 217 | TP_PROTO(struct mtu3_ep *mep), | ||
| 218 | TP_ARGS(mep), | ||
| 219 | TP_STRUCT__entry( | ||
| 220 | __string(name, mep->name) | ||
| 221 | __field(unsigned int, type) | ||
| 222 | __field(unsigned int, slot) | ||
| 223 | __field(unsigned int, maxp) | ||
| 224 | __field(unsigned int, mult) | ||
| 225 | __field(unsigned int, maxburst) | ||
| 226 | __field(unsigned int, flags) | ||
| 227 | __field(unsigned int, direction) | ||
| 228 | __field(struct mtu3_gpd_ring *, gpd_ring) | ||
| 229 | ), | ||
| 230 | TP_fast_assign( | ||
| 231 | __assign_str(name, mep->name); | ||
| 232 | __entry->type = mep->type; | ||
| 233 | __entry->slot = mep->slot; | ||
| 234 | __entry->maxp = mep->ep.maxpacket; | ||
| 235 | __entry->mult = mep->ep.mult; | ||
| 236 | __entry->maxburst = mep->ep.maxburst; | ||
| 237 | __entry->flags = mep->flags; | ||
| 238 | __entry->direction = mep->is_in; | ||
| 239 | __entry->gpd_ring = &mep->gpd_ring; | ||
| 240 | ), | ||
| 241 | TP_printk("%s: type %d maxp %d slot %d mult %d burst %d ring %p/%pad flags %c:%c%c%c:%c", | ||
| 242 | __get_str(name), __entry->type, | ||
| 243 | __entry->maxp, __entry->slot, | ||
| 244 | __entry->mult, __entry->maxburst, | ||
| 245 | __entry->gpd_ring, &__entry->gpd_ring->dma, | ||
| 246 | __entry->flags & MTU3_EP_ENABLED ? 'E' : 'e', | ||
| 247 | __entry->flags & MTU3_EP_STALL ? 'S' : 's', | ||
| 248 | __entry->flags & MTU3_EP_WEDGE ? 'W' : 'w', | ||
| 249 | __entry->flags & MTU3_EP_BUSY ? 'B' : 'b', | ||
| 250 | __entry->direction ? '<' : '>' | ||
| 251 | ) | ||
| 252 | ); | ||
| 253 | |||
| 254 | DEFINE_EVENT(mtu3_log_ep, mtu3_gadget_ep_enable, | ||
| 255 | TP_PROTO(struct mtu3_ep *mep), | ||
| 256 | TP_ARGS(mep) | ||
| 257 | ); | ||
| 258 | |||
| 259 | DEFINE_EVENT(mtu3_log_ep, mtu3_gadget_ep_disable, | ||
| 260 | TP_PROTO(struct mtu3_ep *mep), | ||
| 261 | TP_ARGS(mep) | ||
| 262 | ); | ||
| 263 | |||
| 264 | DEFINE_EVENT(mtu3_log_ep, mtu3_gadget_ep_set_halt, | ||
| 265 | TP_PROTO(struct mtu3_ep *mep), | ||
| 266 | TP_ARGS(mep) | ||
| 267 | ); | ||
| 268 | |||
| 269 | #endif /* __MTU3_TRACE_H__ */ | ||
| 270 | |||
| 271 | /* this part has to be here */ | ||
| 272 | |||
| 273 | #undef TRACE_INCLUDE_PATH | ||
| 274 | #define TRACE_INCLUDE_PATH . | ||
| 275 | |||
| 276 | #undef TRACE_INCLUDE_FILE | ||
| 277 | #define TRACE_INCLUDE_FILE mtu3_trace | ||
| 278 | |||
| 279 | #include <trace/define_trace.h> | ||
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index f742fddc5e2c..52f8e2b57ad5 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig | |||
| @@ -67,7 +67,7 @@ config USB_MUSB_SUNXI | |||
| 67 | depends on NOP_USB_XCEIV | 67 | depends on NOP_USB_XCEIV |
| 68 | depends on PHY_SUN4I_USB | 68 | depends on PHY_SUN4I_USB |
| 69 | depends on EXTCON | 69 | depends on EXTCON |
| 70 | depends on GENERIC_PHY | 70 | select GENERIC_PHY |
| 71 | select SUNXI_SRAM | 71 | select SUNXI_SRAM |
| 72 | 72 | ||
| 73 | config USB_MUSB_DAVINCI | 73 | config USB_MUSB_DAVINCI |
diff --git a/drivers/usb/musb/jz4740.c b/drivers/usb/musb/jz4740.c index a60627bf7be3..5261f8dfedec 100644 --- a/drivers/usb/musb/jz4740.c +++ b/drivers/usb/musb/jz4740.c | |||
| @@ -74,10 +74,14 @@ static struct musb_hdrc_platform_data jz4740_musb_platform_data = { | |||
| 74 | 74 | ||
| 75 | static int jz4740_musb_init(struct musb *musb) | 75 | static int jz4740_musb_init(struct musb *musb) |
| 76 | { | 76 | { |
| 77 | usb_phy_generic_register(); | 77 | struct device *dev = musb->controller->parent; |
| 78 | musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); | 78 | |
| 79 | if (dev->of_node) | ||
| 80 | musb->xceiv = devm_usb_get_phy_by_phandle(dev, "phys", 0); | ||
| 81 | else | ||
| 82 | musb->xceiv = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); | ||
| 79 | if (IS_ERR(musb->xceiv)) { | 83 | if (IS_ERR(musb->xceiv)) { |
| 80 | pr_err("HS UDC: no transceiver configured\n"); | 84 | dev_err(dev, "No transceiver configured\n"); |
| 81 | return PTR_ERR(musb->xceiv); | 85 | return PTR_ERR(musb->xceiv); |
| 82 | } | 86 | } |
| 83 | 87 | ||
| @@ -91,13 +95,6 @@ static int jz4740_musb_init(struct musb *musb) | |||
| 91 | return 0; | 95 | return 0; |
| 92 | } | 96 | } |
| 93 | 97 | ||
| 94 | static int jz4740_musb_exit(struct musb *musb) | ||
| 95 | { | ||
| 96 | usb_put_phy(musb->xceiv); | ||
| 97 | |||
| 98 | return 0; | ||
| 99 | } | ||
| 100 | |||
| 101 | /* | 98 | /* |
| 102 | * DMA has not been confirmed to work with CONFIG_USB_INVENTRA_DMA, | 99 | * DMA has not been confirmed to work with CONFIG_USB_INVENTRA_DMA, |
| 103 | * so let's not set up the dma function pointers yet. | 100 | * so let's not set up the dma function pointers yet. |
| @@ -106,7 +103,6 @@ static const struct musb_platform_ops jz4740_musb_ops = { | |||
| 106 | .quirks = MUSB_DMA_INVENTRA | MUSB_INDEXED_EP, | 103 | .quirks = MUSB_DMA_INVENTRA | MUSB_INDEXED_EP, |
| 107 | .fifo_mode = 2, | 104 | .fifo_mode = 2, |
| 108 | .init = jz4740_musb_init, | 105 | .init = jz4740_musb_init, |
| 109 | .exit = jz4740_musb_exit, | ||
| 110 | }; | 106 | }; |
| 111 | 107 | ||
| 112 | static int jz4740_probe(struct platform_device *pdev) | 108 | static int jz4740_probe(struct platform_device *pdev) |
| @@ -183,7 +179,6 @@ static int jz4740_remove(struct platform_device *pdev) | |||
| 183 | struct jz4740_glue *glue = platform_get_drvdata(pdev); | 179 | struct jz4740_glue *glue = platform_get_drvdata(pdev); |
| 184 | 180 | ||
| 185 | platform_device_unregister(glue->musb); | 181 | platform_device_unregister(glue->musb); |
| 186 | usb_phy_generic_unregister(pdev); | ||
| 187 | clk_disable_unprepare(glue->clk); | 182 | clk_disable_unprepare(glue->clk); |
| 188 | 183 | ||
| 189 | return 0; | 184 | return 0; |
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index b7d56272f9d1..9f5a4819a744 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c | |||
| @@ -1497,10 +1497,11 @@ static int musb_core_init(u16 musb_type, struct musb *musb) | |||
| 1497 | } else { | 1497 | } else { |
| 1498 | musb->is_multipoint = 0; | 1498 | musb->is_multipoint = 0; |
| 1499 | type = ""; | 1499 | type = ""; |
| 1500 | #ifndef CONFIG_USB_OTG_BLACKLIST_HUB | 1500 | if (IS_ENABLED(CONFIG_USB) && |
| 1501 | pr_err("%s: kernel must blacklist external hubs\n", | 1501 | !IS_ENABLED(CONFIG_USB_OTG_BLACKLIST_HUB)) { |
| 1502 | musb_driver_name); | 1502 | pr_err("%s: kernel must blacklist external hubs\n", |
| 1503 | #endif | 1503 | musb_driver_name); |
| 1504 | } | ||
| 1504 | } | 1505 | } |
| 1505 | 1506 | ||
| 1506 | /* log release info */ | 1507 | /* log release info */ |
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 403eb97915f8..327d4f7baaf7 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c | |||
| @@ -168,8 +168,7 @@ static void dsps_mod_timer_optional(struct dsps_glue *glue) | |||
| 168 | static void dsps_musb_enable(struct musb *musb) | 168 | static void dsps_musb_enable(struct musb *musb) |
| 169 | { | 169 | { |
| 170 | struct device *dev = musb->controller; | 170 | struct device *dev = musb->controller; |
| 171 | struct platform_device *pdev = to_platform_device(dev->parent); | 171 | struct dsps_glue *glue = dev_get_drvdata(dev->parent); |
| 172 | struct dsps_glue *glue = platform_get_drvdata(pdev); | ||
| 173 | const struct dsps_musb_wrapper *wrp = glue->wrp; | 172 | const struct dsps_musb_wrapper *wrp = glue->wrp; |
| 174 | void __iomem *reg_base = musb->ctrl_base; | 173 | void __iomem *reg_base = musb->ctrl_base; |
| 175 | u32 epmask, coremask; | 174 | u32 epmask, coremask; |
| @@ -195,8 +194,7 @@ static void dsps_musb_enable(struct musb *musb) | |||
| 195 | static void dsps_musb_disable(struct musb *musb) | 194 | static void dsps_musb_disable(struct musb *musb) |
| 196 | { | 195 | { |
| 197 | struct device *dev = musb->controller; | 196 | struct device *dev = musb->controller; |
| 198 | struct platform_device *pdev = to_platform_device(dev->parent); | 197 | struct dsps_glue *glue = dev_get_drvdata(dev->parent); |
| 199 | struct dsps_glue *glue = platform_get_drvdata(pdev); | ||
| 200 | const struct dsps_musb_wrapper *wrp = glue->wrp; | 198 | const struct dsps_musb_wrapper *wrp = glue->wrp; |
| 201 | void __iomem *reg_base = musb->ctrl_base; | 199 | void __iomem *reg_base = musb->ctrl_base; |
| 202 | 200 | ||
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index b1dd81fb5f55..a3d2fef67746 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c | |||
| @@ -531,6 +531,9 @@ static int omap2430_runtime_suspend(struct device *dev) | |||
| 531 | 531 | ||
| 532 | omap2430_low_level_exit(musb); | 532 | omap2430_low_level_exit(musb); |
| 533 | 533 | ||
| 534 | phy_power_off(musb->phy); | ||
| 535 | phy_exit(musb->phy); | ||
| 536 | |||
| 534 | return 0; | 537 | return 0; |
| 535 | } | 538 | } |
| 536 | 539 | ||
| @@ -542,6 +545,9 @@ static int omap2430_runtime_resume(struct device *dev) | |||
| 542 | if (!musb) | 545 | if (!musb) |
| 543 | return 0; | 546 | return 0; |
| 544 | 547 | ||
| 548 | phy_init(musb->phy); | ||
| 549 | phy_power_on(musb->phy); | ||
| 550 | |||
| 545 | omap2430_low_level_init(musb); | 551 | omap2430_low_level_init(musb); |
| 546 | musb_writel(musb->mregs, OTG_INTERFSEL, | 552 | musb_writel(musb->mregs, OTG_INTERFSEL, |
| 547 | musb->context.otg_interfsel); | 553 | musb->context.otg_interfsel); |
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 8c509b060c09..24b4f091acb8 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig | |||
| @@ -21,7 +21,7 @@ config AB8500_USB | |||
| 21 | in host mode, low speed. | 21 | in host mode, low speed. |
| 22 | 22 | ||
| 23 | config FSL_USB2_OTG | 23 | config FSL_USB2_OTG |
| 24 | bool "Freescale USB OTG Transceiver Driver" | 24 | tristate "Freescale USB OTG Transceiver Driver" |
| 25 | depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_OTG_FSM=y && PM | 25 | depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_OTG_FSM=y && PM |
| 26 | depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y' | 26 | depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y' |
| 27 | select USB_PHY | 27 | select USB_PHY |
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index ff38aa8963cf..71a9206ea1e2 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c | |||
| @@ -189,16 +189,6 @@ static int ark3116_port_remove(struct usb_serial_port *port) | |||
| 189 | return 0; | 189 | return 0; |
| 190 | } | 190 | } |
| 191 | 191 | ||
| 192 | static void ark3116_init_termios(struct tty_struct *tty) | ||
| 193 | { | ||
| 194 | struct ktermios *termios = &tty->termios; | ||
| 195 | *termios = tty_std_termios; | ||
| 196 | termios->c_cflag = B9600 | CS8 | ||
| 197 | | CREAD | HUPCL | CLOCAL; | ||
| 198 | termios->c_ispeed = 9600; | ||
| 199 | termios->c_ospeed = 9600; | ||
| 200 | } | ||
| 201 | |||
| 202 | static void ark3116_set_termios(struct tty_struct *tty, | 192 | static void ark3116_set_termios(struct tty_struct *tty, |
| 203 | struct usb_serial_port *port, | 193 | struct usb_serial_port *port, |
| 204 | struct ktermios *old_termios) | 194 | struct ktermios *old_termios) |
| @@ -645,7 +635,6 @@ static struct usb_serial_driver ark3116_device = { | |||
| 645 | .port_probe = ark3116_port_probe, | 635 | .port_probe = ark3116_port_probe, |
| 646 | .port_remove = ark3116_port_remove, | 636 | .port_remove = ark3116_port_remove, |
| 647 | .set_termios = ark3116_set_termios, | 637 | .set_termios = ark3116_set_termios, |
| 648 | .init_termios = ark3116_init_termios, | ||
| 649 | .get_serial = ark3116_get_serial_info, | 638 | .get_serial = ark3116_get_serial_info, |
| 650 | .tiocmget = ark3116_tiocmget, | 639 | .tiocmget = ark3116_tiocmget, |
| 651 | .tiocmset = ark3116_tiocmset, | 640 | .tiocmset = ark3116_tiocmset, |
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index ed51bc48eea6..72d3ae1ebc64 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c | |||
| @@ -98,7 +98,6 @@ struct cypress_private { | |||
| 98 | int write_urb_interval; /* interval to use for write urb */ | 98 | int write_urb_interval; /* interval to use for write urb */ |
| 99 | int read_urb_interval; /* interval to use for read urb */ | 99 | int read_urb_interval; /* interval to use for read urb */ |
| 100 | int comm_is_ok; /* true if communication is (still) ok */ | 100 | int comm_is_ok; /* true if communication is (still) ok */ |
| 101 | int termios_initialized; | ||
| 102 | __u8 line_control; /* holds dtr / rts value */ | 101 | __u8 line_control; /* holds dtr / rts value */ |
| 103 | __u8 current_status; /* received from last read - info on dsr,cts,cd,ri,etc */ | 102 | __u8 current_status; /* received from last read - info on dsr,cts,cd,ri,etc */ |
| 104 | __u8 current_config; /* stores the current configuration byte */ | 103 | __u8 current_config; /* stores the current configuration byte */ |
| @@ -107,11 +106,7 @@ struct cypress_private { | |||
| 107 | int get_cfg_unsafe; /* If true, the CYPRESS_GET_CONFIG is unsafe */ | 106 | int get_cfg_unsafe; /* If true, the CYPRESS_GET_CONFIG is unsafe */ |
| 108 | int baud_rate; /* stores current baud rate in | 107 | int baud_rate; /* stores current baud rate in |
| 109 | integer form */ | 108 | integer form */ |
| 110 | int isthrottled; /* if throttled, discard reads */ | ||
| 111 | char prev_status; /* used for TIOCMIWAIT */ | 109 | char prev_status; /* used for TIOCMIWAIT */ |
| 112 | /* we pass a pointer to this as the argument sent to | ||
| 113 | cypress_set_termios old_termios */ | ||
| 114 | struct ktermios tmp_termios; /* stores the old termios settings */ | ||
| 115 | }; | 110 | }; |
| 116 | 111 | ||
| 117 | /* function prototypes for the Cypress USB to serial device */ | 112 | /* function prototypes for the Cypress USB to serial device */ |
| @@ -126,6 +121,7 @@ static int cypress_write(struct tty_struct *tty, struct usb_serial_port *port, | |||
| 126 | const unsigned char *buf, int count); | 121 | const unsigned char *buf, int count); |
| 127 | static void cypress_send(struct usb_serial_port *port); | 122 | static void cypress_send(struct usb_serial_port *port); |
| 128 | static int cypress_write_room(struct tty_struct *tty); | 123 | static int cypress_write_room(struct tty_struct *tty); |
| 124 | static void cypress_earthmate_init_termios(struct tty_struct *tty); | ||
| 129 | static void cypress_set_termios(struct tty_struct *tty, | 125 | static void cypress_set_termios(struct tty_struct *tty, |
| 130 | struct usb_serial_port *port, struct ktermios *old); | 126 | struct usb_serial_port *port, struct ktermios *old); |
| 131 | static int cypress_tiocmget(struct tty_struct *tty); | 127 | static int cypress_tiocmget(struct tty_struct *tty); |
| @@ -153,6 +149,7 @@ static struct usb_serial_driver cypress_earthmate_device = { | |||
| 153 | .dtr_rts = cypress_dtr_rts, | 149 | .dtr_rts = cypress_dtr_rts, |
| 154 | .write = cypress_write, | 150 | .write = cypress_write, |
| 155 | .write_room = cypress_write_room, | 151 | .write_room = cypress_write_room, |
| 152 | .init_termios = cypress_earthmate_init_termios, | ||
| 156 | .set_termios = cypress_set_termios, | 153 | .set_termios = cypress_set_termios, |
| 157 | .tiocmget = cypress_tiocmget, | 154 | .tiocmget = cypress_tiocmget, |
| 158 | .tiocmset = cypress_tiocmset, | 155 | .tiocmset = cypress_tiocmset, |
| @@ -467,7 +464,6 @@ static int cypress_generic_port_probe(struct usb_serial_port *port) | |||
| 467 | 464 | ||
| 468 | priv->cmd_ctrl = 0; | 465 | priv->cmd_ctrl = 0; |
| 469 | priv->line_control = 0; | 466 | priv->line_control = 0; |
| 470 | priv->termios_initialized = 0; | ||
| 471 | priv->rx_flags = 0; | 467 | priv->rx_flags = 0; |
| 472 | /* Default packet format setting is determined by packet size. | 468 | /* Default packet format setting is determined by packet size. |
| 473 | Anything with a size larger then 9 must have a separate | 469 | Anything with a size larger then 9 must have a separate |
| @@ -604,7 +600,7 @@ static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port) | |||
| 604 | cypress_send(port); | 600 | cypress_send(port); |
| 605 | 601 | ||
| 606 | if (tty) | 602 | if (tty) |
| 607 | cypress_set_termios(tty, port, &priv->tmp_termios); | 603 | cypress_set_termios(tty, port, NULL); |
| 608 | 604 | ||
| 609 | /* setup the port and start reading from the device */ | 605 | /* setup the port and start reading from the device */ |
| 610 | usb_fill_int_urb(port->interrupt_in_urb, serial->dev, | 606 | usb_fill_int_urb(port->interrupt_in_urb, serial->dev, |
| @@ -857,6 +853,11 @@ static int cypress_tiocmset(struct tty_struct *tty, | |||
| 857 | return cypress_write(tty, port, NULL, 0); | 853 | return cypress_write(tty, port, NULL, 0); |
| 858 | } | 854 | } |
| 859 | 855 | ||
| 856 | static void cypress_earthmate_init_termios(struct tty_struct *tty) | ||
| 857 | { | ||
| 858 | tty_encode_baud_rate(tty, 4800, 4800); | ||
| 859 | } | ||
| 860 | |||
| 860 | static void cypress_set_termios(struct tty_struct *tty, | 861 | static void cypress_set_termios(struct tty_struct *tty, |
| 861 | struct usb_serial_port *port, struct ktermios *old_termios) | 862 | struct usb_serial_port *port, struct ktermios *old_termios) |
| 862 | { | 863 | { |
| @@ -868,45 +869,11 @@ static void cypress_set_termios(struct tty_struct *tty, | |||
| 868 | __u8 oldlines; | 869 | __u8 oldlines; |
| 869 | int linechange = 0; | 870 | int linechange = 0; |
| 870 | 871 | ||
| 871 | spin_lock_irqsave(&priv->lock, flags); | ||
| 872 | /* We can't clean this one up as we don't know the device type | ||
| 873 | early enough */ | ||
| 874 | if (!priv->termios_initialized) { | ||
| 875 | if (priv->chiptype == CT_EARTHMATE) { | ||
| 876 | tty->termios = tty_std_termios; | ||
| 877 | tty->termios.c_cflag = B4800 | CS8 | CREAD | HUPCL | | ||
| 878 | CLOCAL; | ||
| 879 | tty->termios.c_ispeed = 4800; | ||
| 880 | tty->termios.c_ospeed = 4800; | ||
| 881 | } else if (priv->chiptype == CT_CYPHIDCOM) { | ||
| 882 | tty->termios = tty_std_termios; | ||
| 883 | tty->termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | | ||
| 884 | CLOCAL; | ||
| 885 | tty->termios.c_ispeed = 9600; | ||
| 886 | tty->termios.c_ospeed = 9600; | ||
| 887 | } else if (priv->chiptype == CT_CA42V2) { | ||
| 888 | tty->termios = tty_std_termios; | ||
| 889 | tty->termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | | ||
| 890 | CLOCAL; | ||
| 891 | tty->termios.c_ispeed = 9600; | ||
| 892 | tty->termios.c_ospeed = 9600; | ||
| 893 | } | ||
| 894 | priv->termios_initialized = 1; | ||
| 895 | } | ||
| 896 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 897 | |||
| 898 | /* Unsupported features need clearing */ | 872 | /* Unsupported features need clearing */ |
| 899 | tty->termios.c_cflag &= ~(CMSPAR|CRTSCTS); | 873 | tty->termios.c_cflag &= ~(CMSPAR|CRTSCTS); |
| 900 | 874 | ||
| 901 | cflag = tty->termios.c_cflag; | 875 | cflag = tty->termios.c_cflag; |
| 902 | 876 | ||
| 903 | /* check if there are new settings */ | ||
| 904 | if (old_termios) { | ||
| 905 | spin_lock_irqsave(&priv->lock, flags); | ||
| 906 | priv->tmp_termios = tty->termios; | ||
| 907 | spin_unlock_irqrestore(&priv->lock, flags); | ||
| 908 | } | ||
| 909 | |||
| 910 | /* set number of data bits, parity, stop bits */ | 877 | /* set number of data bits, parity, stop bits */ |
| 911 | /* when parity is disabled the parity type bit is ignored */ | 878 | /* when parity is disabled the parity type bit is ignored */ |
| 912 | 879 | ||
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index e7f244cf2c07..578ebdd86520 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c | |||
| @@ -569,9 +569,9 @@ static int digi_set_modem_signals(struct usb_serial_port *port, | |||
| 569 | ret = usb_submit_urb(oob_port->write_urb, GFP_ATOMIC); | 569 | ret = usb_submit_urb(oob_port->write_urb, GFP_ATOMIC); |
| 570 | if (ret == 0) { | 570 | if (ret == 0) { |
| 571 | oob_priv->dp_write_urb_in_use = 1; | 571 | oob_priv->dp_write_urb_in_use = 1; |
| 572 | port_priv->dp_modem_signals = | 572 | port_priv->dp_modem_signals &= ~(TIOCM_DTR | TIOCM_RTS); |
| 573 | (port_priv->dp_modem_signals&~(TIOCM_DTR|TIOCM_RTS)) | 573 | port_priv->dp_modem_signals |= |
| 574 | | (modem_signals&(TIOCM_DTR|TIOCM_RTS)); | 574 | modem_signals & (TIOCM_DTR | TIOCM_RTS); |
| 575 | } | 575 | } |
| 576 | spin_unlock(&port_priv->dp_port_lock); | 576 | spin_unlock(&port_priv->dp_port_lock); |
| 577 | spin_unlock_irqrestore(&oob_priv->dp_port_lock, flags); | 577 | spin_unlock_irqrestore(&oob_priv->dp_port_lock, flags); |
| @@ -740,9 +740,9 @@ static void digi_set_termios(struct tty_struct *tty, | |||
| 740 | /* set parity */ | 740 | /* set parity */ |
| 741 | tty->termios.c_cflag &= ~CMSPAR; | 741 | tty->termios.c_cflag &= ~CMSPAR; |
| 742 | 742 | ||
| 743 | if ((cflag&(PARENB|PARODD)) != (old_cflag&(PARENB|PARODD))) { | 743 | if ((cflag & (PARENB | PARODD)) != (old_cflag & (PARENB | PARODD))) { |
| 744 | if (cflag&PARENB) { | 744 | if (cflag & PARENB) { |
| 745 | if (cflag&PARODD) | 745 | if (cflag & PARODD) |
| 746 | arg = DIGI_PARITY_ODD; | 746 | arg = DIGI_PARITY_ODD; |
| 747 | else | 747 | else |
| 748 | arg = DIGI_PARITY_EVEN; | 748 | arg = DIGI_PARITY_EVEN; |
| @@ -755,9 +755,9 @@ static void digi_set_termios(struct tty_struct *tty, | |||
| 755 | buf[i++] = 0; | 755 | buf[i++] = 0; |
| 756 | } | 756 | } |
| 757 | /* set word size */ | 757 | /* set word size */ |
| 758 | if ((cflag&CSIZE) != (old_cflag&CSIZE)) { | 758 | if ((cflag & CSIZE) != (old_cflag & CSIZE)) { |
| 759 | arg = -1; | 759 | arg = -1; |
| 760 | switch (cflag&CSIZE) { | 760 | switch (cflag & CSIZE) { |
| 761 | case CS5: arg = DIGI_WORD_SIZE_5; break; | 761 | case CS5: arg = DIGI_WORD_SIZE_5; break; |
| 762 | case CS6: arg = DIGI_WORD_SIZE_6; break; | 762 | case CS6: arg = DIGI_WORD_SIZE_6; break; |
| 763 | case CS7: arg = DIGI_WORD_SIZE_7; break; | 763 | case CS7: arg = DIGI_WORD_SIZE_7; break; |
| @@ -765,7 +765,7 @@ static void digi_set_termios(struct tty_struct *tty, | |||
| 765 | default: | 765 | default: |
| 766 | dev_dbg(dev, | 766 | dev_dbg(dev, |
| 767 | "digi_set_termios: can't handle word size %d\n", | 767 | "digi_set_termios: can't handle word size %d\n", |
| 768 | (cflag&CSIZE)); | 768 | cflag & CSIZE); |
| 769 | break; | 769 | break; |
| 770 | } | 770 | } |
| 771 | 771 | ||
| @@ -779,9 +779,9 @@ static void digi_set_termios(struct tty_struct *tty, | |||
| 779 | } | 779 | } |
| 780 | 780 | ||
| 781 | /* set stop bits */ | 781 | /* set stop bits */ |
| 782 | if ((cflag&CSTOPB) != (old_cflag&CSTOPB)) { | 782 | if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) { |
| 783 | 783 | ||
| 784 | if ((cflag&CSTOPB)) | 784 | if ((cflag & CSTOPB)) |
| 785 | arg = DIGI_STOP_BITS_2; | 785 | arg = DIGI_STOP_BITS_2; |
| 786 | else | 786 | else |
| 787 | arg = DIGI_STOP_BITS_1; | 787 | arg = DIGI_STOP_BITS_1; |
| @@ -794,15 +794,15 @@ static void digi_set_termios(struct tty_struct *tty, | |||
| 794 | } | 794 | } |
| 795 | 795 | ||
| 796 | /* set input flow control */ | 796 | /* set input flow control */ |
| 797 | if ((iflag&IXOFF) != (old_iflag&IXOFF) | 797 | if ((iflag & IXOFF) != (old_iflag & IXOFF) || |
| 798 | || (cflag&CRTSCTS) != (old_cflag&CRTSCTS)) { | 798 | (cflag & CRTSCTS) != (old_cflag & CRTSCTS)) { |
| 799 | arg = 0; | 799 | arg = 0; |
| 800 | if (iflag&IXOFF) | 800 | if (iflag & IXOFF) |
| 801 | arg |= DIGI_INPUT_FLOW_CONTROL_XON_XOFF; | 801 | arg |= DIGI_INPUT_FLOW_CONTROL_XON_XOFF; |
| 802 | else | 802 | else |
| 803 | arg &= ~DIGI_INPUT_FLOW_CONTROL_XON_XOFF; | 803 | arg &= ~DIGI_INPUT_FLOW_CONTROL_XON_XOFF; |
| 804 | 804 | ||
| 805 | if (cflag&CRTSCTS) { | 805 | if (cflag & CRTSCTS) { |
| 806 | arg |= DIGI_INPUT_FLOW_CONTROL_RTS; | 806 | arg |= DIGI_INPUT_FLOW_CONTROL_RTS; |
| 807 | 807 | ||
| 808 | /* On USB-4 it is necessary to assert RTS prior */ | 808 | /* On USB-4 it is necessary to assert RTS prior */ |
| @@ -822,19 +822,18 @@ static void digi_set_termios(struct tty_struct *tty, | |||
| 822 | } | 822 | } |
| 823 | 823 | ||
| 824 | /* set output flow control */ | 824 | /* set output flow control */ |
| 825 | if ((iflag & IXON) != (old_iflag & IXON) | 825 | if ((iflag & IXON) != (old_iflag & IXON) || |
| 826 | || (cflag & CRTSCTS) != (old_cflag & CRTSCTS)) { | 826 | (cflag & CRTSCTS) != (old_cflag & CRTSCTS)) { |
| 827 | arg = 0; | 827 | arg = 0; |
| 828 | if (iflag & IXON) | 828 | if (iflag & IXON) |
| 829 | arg |= DIGI_OUTPUT_FLOW_CONTROL_XON_XOFF; | 829 | arg |= DIGI_OUTPUT_FLOW_CONTROL_XON_XOFF; |
| 830 | else | 830 | else |
| 831 | arg &= ~DIGI_OUTPUT_FLOW_CONTROL_XON_XOFF; | 831 | arg &= ~DIGI_OUTPUT_FLOW_CONTROL_XON_XOFF; |
| 832 | 832 | ||
| 833 | if (cflag & CRTSCTS) { | 833 | if (cflag & CRTSCTS) |
| 834 | arg |= DIGI_OUTPUT_FLOW_CONTROL_CTS; | 834 | arg |= DIGI_OUTPUT_FLOW_CONTROL_CTS; |
| 835 | } else { | 835 | else |
| 836 | arg &= ~DIGI_OUTPUT_FLOW_CONTROL_CTS; | 836 | arg &= ~DIGI_OUTPUT_FLOW_CONTROL_CTS; |
| 837 | } | ||
| 838 | 837 | ||
| 839 | buf[i++] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL; | 838 | buf[i++] = DIGI_CMD_SET_OUTPUT_FLOW_CONTROL; |
| 840 | buf[i++] = priv->dp_port_num; | 839 | buf[i++] = priv->dp_port_num; |
| @@ -1084,7 +1083,7 @@ static int digi_chars_in_buffer(struct tty_struct *tty) | |||
| 1084 | static void digi_dtr_rts(struct usb_serial_port *port, int on) | 1083 | static void digi_dtr_rts(struct usb_serial_port *port, int on) |
| 1085 | { | 1084 | { |
| 1086 | /* Adjust DTR and RTS */ | 1085 | /* Adjust DTR and RTS */ |
| 1087 | digi_set_modem_signals(port, on * (TIOCM_DTR|TIOCM_RTS), 1); | 1086 | digi_set_modem_signals(port, on * (TIOCM_DTR | TIOCM_RTS), 1); |
| 1088 | } | 1087 | } |
| 1089 | 1088 | ||
| 1090 | static int digi_open(struct tty_struct *tty, struct usb_serial_port *port) | 1089 | static int digi_open(struct tty_struct *tty, struct usb_serial_port *port) |
diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c index 0dcdcb4b2cde..43fa1f0716b7 100644 --- a/drivers/usb/serial/f81232.c +++ b/drivers/usb/serial/f81232.c | |||
| @@ -28,7 +28,8 @@ static const struct usb_device_id id_table[] = { | |||
| 28 | MODULE_DEVICE_TABLE(usb, id_table); | 28 | MODULE_DEVICE_TABLE(usb, id_table); |
| 29 | 29 | ||
| 30 | /* Maximum baudrate for F81232 */ | 30 | /* Maximum baudrate for F81232 */ |
| 31 | #define F81232_MAX_BAUDRATE 115200 | 31 | #define F81232_MAX_BAUDRATE 1500000 |
| 32 | #define F81232_DEF_BAUDRATE 9600 | ||
| 32 | 33 | ||
| 33 | /* USB Control EP parameter */ | 34 | /* USB Control EP parameter */ |
| 34 | #define F81232_REGISTER_REQUEST 0xa0 | 35 | #define F81232_REGISTER_REQUEST 0xa0 |
| @@ -41,19 +42,46 @@ MODULE_DEVICE_TABLE(usb, id_table); | |||
| 41 | #define FIFO_CONTROL_REGISTER (0x02 + SERIAL_BASE_ADDRESS) | 42 | #define FIFO_CONTROL_REGISTER (0x02 + SERIAL_BASE_ADDRESS) |
| 42 | #define LINE_CONTROL_REGISTER (0x03 + SERIAL_BASE_ADDRESS) | 43 | #define LINE_CONTROL_REGISTER (0x03 + SERIAL_BASE_ADDRESS) |
| 43 | #define MODEM_CONTROL_REGISTER (0x04 + SERIAL_BASE_ADDRESS) | 44 | #define MODEM_CONTROL_REGISTER (0x04 + SERIAL_BASE_ADDRESS) |
| 45 | #define LINE_STATUS_REGISTER (0x05 + SERIAL_BASE_ADDRESS) | ||
| 44 | #define MODEM_STATUS_REGISTER (0x06 + SERIAL_BASE_ADDRESS) | 46 | #define MODEM_STATUS_REGISTER (0x06 + SERIAL_BASE_ADDRESS) |
| 45 | 47 | ||
| 48 | /* | ||
| 49 | * F81232 Clock registers (106h) | ||
| 50 | * | ||
| 51 | * Bit1-0: Clock source selector | ||
| 52 | * 00: 1.846MHz. | ||
| 53 | * 01: 18.46MHz. | ||
| 54 | * 10: 24MHz. | ||
| 55 | * 11: 14.77MHz. | ||
| 56 | */ | ||
| 57 | #define F81232_CLK_REGISTER 0x106 | ||
| 58 | #define F81232_CLK_1_846_MHZ 0 | ||
| 59 | #define F81232_CLK_18_46_MHZ BIT(0) | ||
| 60 | #define F81232_CLK_24_MHZ BIT(1) | ||
| 61 | #define F81232_CLK_14_77_MHZ (BIT(1) | BIT(0)) | ||
| 62 | #define F81232_CLK_MASK GENMASK(1, 0) | ||
| 63 | |||
| 46 | struct f81232_private { | 64 | struct f81232_private { |
| 47 | struct mutex lock; | 65 | struct mutex lock; |
| 48 | u8 modem_control; | 66 | u8 modem_control; |
| 49 | u8 modem_status; | 67 | u8 modem_status; |
| 68 | u8 shadow_lcr; | ||
| 69 | speed_t baud_base; | ||
| 70 | struct work_struct lsr_work; | ||
| 50 | struct work_struct interrupt_work; | 71 | struct work_struct interrupt_work; |
| 51 | struct usb_serial_port *port; | 72 | struct usb_serial_port *port; |
| 52 | }; | 73 | }; |
| 53 | 74 | ||
| 54 | static int calc_baud_divisor(speed_t baudrate) | 75 | static u32 const baudrate_table[] = { 115200, 921600, 1152000, 1500000 }; |
| 76 | static u8 const clock_table[] = { F81232_CLK_1_846_MHZ, F81232_CLK_14_77_MHZ, | ||
| 77 | F81232_CLK_18_46_MHZ, F81232_CLK_24_MHZ }; | ||
| 78 | |||
| 79 | static int calc_baud_divisor(speed_t baudrate, speed_t clockrate) | ||
| 55 | { | 80 | { |
| 56 | return DIV_ROUND_CLOSEST(F81232_MAX_BAUDRATE, baudrate); | 81 | if (!baudrate) |
| 82 | return 0; | ||
| 83 | |||
| 84 | return DIV_ROUND_CLOSEST(clockrate, baudrate); | ||
| 57 | } | 85 | } |
| 58 | 86 | ||
| 59 | static int f81232_get_register(struct usb_serial_port *port, u16 reg, u8 *val) | 87 | static int f81232_get_register(struct usb_serial_port *port, u16 reg, u8 *val) |
| @@ -127,6 +155,21 @@ static int f81232_set_register(struct usb_serial_port *port, u16 reg, u8 val) | |||
| 127 | return status; | 155 | return status; |
| 128 | } | 156 | } |
| 129 | 157 | ||
| 158 | static int f81232_set_mask_register(struct usb_serial_port *port, u16 reg, | ||
| 159 | u8 mask, u8 val) | ||
| 160 | { | ||
| 161 | int status; | ||
| 162 | u8 tmp; | ||
| 163 | |||
| 164 | status = f81232_get_register(port, reg, &tmp); | ||
| 165 | if (status) | ||
| 166 | return status; | ||
| 167 | |||
| 168 | tmp = (tmp & ~mask) | (val & mask); | ||
| 169 | |||
| 170 | return f81232_set_register(port, reg, tmp); | ||
| 171 | } | ||
| 172 | |||
| 130 | static void f81232_read_msr(struct usb_serial_port *port) | 173 | static void f81232_read_msr(struct usb_serial_port *port) |
| 131 | { | 174 | { |
| 132 | int status; | 175 | int status; |
| @@ -282,6 +325,7 @@ exit: | |||
| 282 | static void f81232_process_read_urb(struct urb *urb) | 325 | static void f81232_process_read_urb(struct urb *urb) |
| 283 | { | 326 | { |
| 284 | struct usb_serial_port *port = urb->context; | 327 | struct usb_serial_port *port = urb->context; |
| 328 | struct f81232_private *priv = usb_get_serial_port_data(port); | ||
| 285 | unsigned char *data = urb->transfer_buffer; | 329 | unsigned char *data = urb->transfer_buffer; |
| 286 | char tty_flag; | 330 | char tty_flag; |
| 287 | unsigned int i; | 331 | unsigned int i; |
| @@ -315,6 +359,7 @@ static void f81232_process_read_urb(struct urb *urb) | |||
| 315 | 359 | ||
| 316 | if (lsr & UART_LSR_OE) { | 360 | if (lsr & UART_LSR_OE) { |
| 317 | port->icount.overrun++; | 361 | port->icount.overrun++; |
| 362 | schedule_work(&priv->lsr_work); | ||
| 318 | tty_insert_flip_char(&port->port, 0, | 363 | tty_insert_flip_char(&port->port, 0, |
| 319 | TTY_OVERRUN); | 364 | TTY_OVERRUN); |
| 320 | } | 365 | } |
| @@ -333,22 +378,72 @@ static void f81232_process_read_urb(struct urb *urb) | |||
| 333 | 378 | ||
| 334 | static void f81232_break_ctl(struct tty_struct *tty, int break_state) | 379 | static void f81232_break_ctl(struct tty_struct *tty, int break_state) |
| 335 | { | 380 | { |
| 336 | /* FIXME - Stubbed out for now */ | 381 | struct usb_serial_port *port = tty->driver_data; |
| 382 | struct f81232_private *priv = usb_get_serial_port_data(port); | ||
| 383 | int status; | ||
| 337 | 384 | ||
| 338 | /* | 385 | mutex_lock(&priv->lock); |
| 339 | * break_state = -1 to turn on break, and 0 to turn off break | 386 | |
| 340 | * see drivers/char/tty_io.c to see it used. | 387 | if (break_state) |
| 341 | * last_set_data_urb_value NEVER has the break bit set in it. | 388 | priv->shadow_lcr |= UART_LCR_SBC; |
| 342 | */ | 389 | else |
| 390 | priv->shadow_lcr &= ~UART_LCR_SBC; | ||
| 391 | |||
| 392 | status = f81232_set_register(port, LINE_CONTROL_REGISTER, | ||
| 393 | priv->shadow_lcr); | ||
| 394 | if (status) | ||
| 395 | dev_err(&port->dev, "set break failed: %d\n", status); | ||
| 396 | |||
| 397 | mutex_unlock(&priv->lock); | ||
| 343 | } | 398 | } |
| 344 | 399 | ||
| 345 | static void f81232_set_baudrate(struct usb_serial_port *port, speed_t baudrate) | 400 | static int f81232_find_clk(speed_t baudrate) |
| 346 | { | 401 | { |
| 402 | int idx; | ||
| 403 | |||
| 404 | for (idx = 0; idx < ARRAY_SIZE(baudrate_table); ++idx) { | ||
| 405 | if (baudrate <= baudrate_table[idx] && | ||
| 406 | baudrate_table[idx] % baudrate == 0) | ||
| 407 | return idx; | ||
| 408 | } | ||
| 409 | |||
| 410 | return -EINVAL; | ||
| 411 | } | ||
| 412 | |||
| 413 | static void f81232_set_baudrate(struct tty_struct *tty, | ||
| 414 | struct usb_serial_port *port, speed_t baudrate, | ||
| 415 | speed_t old_baudrate) | ||
| 416 | { | ||
| 417 | struct f81232_private *priv = usb_get_serial_port_data(port); | ||
| 347 | u8 lcr; | 418 | u8 lcr; |
| 348 | int divisor; | 419 | int divisor; |
| 349 | int status = 0; | 420 | int status = 0; |
| 421 | int i; | ||
| 422 | int idx; | ||
| 423 | speed_t baud_list[] = { baudrate, old_baudrate, F81232_DEF_BAUDRATE }; | ||
| 424 | |||
| 425 | for (i = 0; i < ARRAY_SIZE(baud_list); ++i) { | ||
| 426 | idx = f81232_find_clk(baud_list[i]); | ||
| 427 | if (idx >= 0) { | ||
| 428 | baudrate = baud_list[i]; | ||
| 429 | tty_encode_baud_rate(tty, baudrate, baudrate); | ||
| 430 | break; | ||
| 431 | } | ||
| 432 | } | ||
| 350 | 433 | ||
| 351 | divisor = calc_baud_divisor(baudrate); | 434 | if (idx < 0) |
| 435 | return; | ||
| 436 | |||
| 437 | priv->baud_base = baudrate_table[idx]; | ||
| 438 | divisor = calc_baud_divisor(baudrate, priv->baud_base); | ||
| 439 | |||
| 440 | status = f81232_set_mask_register(port, F81232_CLK_REGISTER, | ||
| 441 | F81232_CLK_MASK, clock_table[idx]); | ||
| 442 | if (status) { | ||
| 443 | dev_err(&port->dev, "%s failed to set CLK_REG: %d\n", | ||
| 444 | __func__, status); | ||
| 445 | return; | ||
| 446 | } | ||
| 352 | 447 | ||
| 353 | status = f81232_get_register(port, LINE_CONTROL_REGISTER, | 448 | status = f81232_get_register(port, LINE_CONTROL_REGISTER, |
| 354 | &lcr); /* get LCR */ | 449 | &lcr); /* get LCR */ |
| @@ -435,9 +530,11 @@ static int f81232_port_disable(struct usb_serial_port *port) | |||
| 435 | static void f81232_set_termios(struct tty_struct *tty, | 530 | static void f81232_set_termios(struct tty_struct *tty, |
| 436 | struct usb_serial_port *port, struct ktermios *old_termios) | 531 | struct usb_serial_port *port, struct ktermios *old_termios) |
| 437 | { | 532 | { |
| 533 | struct f81232_private *priv = usb_get_serial_port_data(port); | ||
| 438 | u8 new_lcr = 0; | 534 | u8 new_lcr = 0; |
| 439 | int status = 0; | 535 | int status = 0; |
| 440 | speed_t baudrate; | 536 | speed_t baudrate; |
| 537 | speed_t old_baud; | ||
| 441 | 538 | ||
| 442 | /* Don't change anything if nothing has changed */ | 539 | /* Don't change anything if nothing has changed */ |
| 443 | if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios)) | 540 | if (old_termios && !tty_termios_hw_change(&tty->termios, old_termios)) |
| @@ -450,11 +547,12 @@ static void f81232_set_termios(struct tty_struct *tty, | |||
| 450 | 547 | ||
| 451 | baudrate = tty_get_baud_rate(tty); | 548 | baudrate = tty_get_baud_rate(tty); |
| 452 | if (baudrate > 0) { | 549 | if (baudrate > 0) { |
| 453 | if (baudrate > F81232_MAX_BAUDRATE) { | 550 | if (old_termios) |
| 454 | baudrate = F81232_MAX_BAUDRATE; | 551 | old_baud = tty_termios_baud_rate(old_termios); |
| 455 | tty_encode_baud_rate(tty, baudrate, baudrate); | 552 | else |
| 456 | } | 553 | old_baud = F81232_DEF_BAUDRATE; |
| 457 | f81232_set_baudrate(port, baudrate); | 554 | |
| 555 | f81232_set_baudrate(tty, port, baudrate, old_baud); | ||
| 458 | } | 556 | } |
| 459 | 557 | ||
| 460 | if (C_PARENB(tty)) { | 558 | if (C_PARENB(tty)) { |
| @@ -486,11 +584,18 @@ static void f81232_set_termios(struct tty_struct *tty, | |||
| 486 | break; | 584 | break; |
| 487 | } | 585 | } |
| 488 | 586 | ||
| 587 | mutex_lock(&priv->lock); | ||
| 588 | |||
| 589 | new_lcr |= (priv->shadow_lcr & UART_LCR_SBC); | ||
| 489 | status = f81232_set_register(port, LINE_CONTROL_REGISTER, new_lcr); | 590 | status = f81232_set_register(port, LINE_CONTROL_REGISTER, new_lcr); |
| 490 | if (status) { | 591 | if (status) { |
| 491 | dev_err(&port->dev, "%s failed to set LCR: %d\n", | 592 | dev_err(&port->dev, "%s failed to set LCR: %d\n", |
| 492 | __func__, status); | 593 | __func__, status); |
| 493 | } | 594 | } |
| 595 | |||
| 596 | priv->shadow_lcr = new_lcr; | ||
| 597 | |||
| 598 | mutex_unlock(&priv->lock); | ||
| 494 | } | 599 | } |
| 495 | 600 | ||
| 496 | static int f81232_tiocmget(struct tty_struct *tty) | 601 | static int f81232_tiocmget(struct tty_struct *tty) |
| @@ -556,9 +661,13 @@ static int f81232_open(struct tty_struct *tty, struct usb_serial_port *port) | |||
| 556 | 661 | ||
| 557 | static void f81232_close(struct usb_serial_port *port) | 662 | static void f81232_close(struct usb_serial_port *port) |
| 558 | { | 663 | { |
| 664 | struct f81232_private *port_priv = usb_get_serial_port_data(port); | ||
| 665 | |||
| 559 | f81232_port_disable(port); | 666 | f81232_port_disable(port); |
| 560 | usb_serial_generic_close(port); | 667 | usb_serial_generic_close(port); |
| 561 | usb_kill_urb(port->interrupt_in_urb); | 668 | usb_kill_urb(port->interrupt_in_urb); |
| 669 | flush_work(&port_priv->interrupt_work); | ||
| 670 | flush_work(&port_priv->lsr_work); | ||
| 562 | } | 671 | } |
| 563 | 672 | ||
| 564 | static void f81232_dtr_rts(struct usb_serial_port *port, int on) | 673 | static void f81232_dtr_rts(struct usb_serial_port *port, int on) |
| @@ -587,11 +696,12 @@ static int f81232_get_serial_info(struct tty_struct *tty, | |||
| 587 | struct serial_struct *ss) | 696 | struct serial_struct *ss) |
| 588 | { | 697 | { |
| 589 | struct usb_serial_port *port = tty->driver_data; | 698 | struct usb_serial_port *port = tty->driver_data; |
| 699 | struct f81232_private *priv = usb_get_serial_port_data(port); | ||
| 590 | 700 | ||
| 591 | ss->type = PORT_16550A; | 701 | ss->type = PORT_16550A; |
| 592 | ss->line = port->minor; | 702 | ss->line = port->minor; |
| 593 | ss->port = port->port_number; | 703 | ss->port = port->port_number; |
| 594 | ss->baud_base = F81232_MAX_BAUDRATE; | 704 | ss->baud_base = priv->baud_base; |
| 595 | return 0; | 705 | return 0; |
| 596 | } | 706 | } |
| 597 | 707 | ||
| @@ -603,6 +713,21 @@ static void f81232_interrupt_work(struct work_struct *work) | |||
| 603 | f81232_read_msr(priv->port); | 713 | f81232_read_msr(priv->port); |
| 604 | } | 714 | } |
| 605 | 715 | ||
| 716 | static void f81232_lsr_worker(struct work_struct *work) | ||
| 717 | { | ||
| 718 | struct f81232_private *priv; | ||
| 719 | struct usb_serial_port *port; | ||
| 720 | int status; | ||
| 721 | u8 tmp; | ||
| 722 | |||
| 723 | priv = container_of(work, struct f81232_private, lsr_work); | ||
| 724 | port = priv->port; | ||
| 725 | |||
| 726 | status = f81232_get_register(port, LINE_STATUS_REGISTER, &tmp); | ||
| 727 | if (status) | ||
| 728 | dev_warn(&port->dev, "read LSR failed: %d\n", status); | ||
| 729 | } | ||
| 730 | |||
| 606 | static int f81232_port_probe(struct usb_serial_port *port) | 731 | static int f81232_port_probe(struct usb_serial_port *port) |
| 607 | { | 732 | { |
| 608 | struct f81232_private *priv; | 733 | struct f81232_private *priv; |
| @@ -613,6 +738,7 @@ static int f81232_port_probe(struct usb_serial_port *port) | |||
| 613 | 738 | ||
| 614 | mutex_init(&priv->lock); | 739 | mutex_init(&priv->lock); |
| 615 | INIT_WORK(&priv->interrupt_work, f81232_interrupt_work); | 740 | INIT_WORK(&priv->interrupt_work, f81232_interrupt_work); |
| 741 | INIT_WORK(&priv->lsr_work, f81232_lsr_worker); | ||
| 616 | 742 | ||
| 617 | usb_set_serial_port_data(port, priv); | 743 | usb_set_serial_port_data(port, priv); |
| 618 | 744 | ||
| @@ -632,6 +758,42 @@ static int f81232_port_remove(struct usb_serial_port *port) | |||
| 632 | return 0; | 758 | return 0; |
| 633 | } | 759 | } |
| 634 | 760 | ||
| 761 | static int f81232_suspend(struct usb_serial *serial, pm_message_t message) | ||
| 762 | { | ||
| 763 | struct usb_serial_port *port = serial->port[0]; | ||
| 764 | struct f81232_private *port_priv = usb_get_serial_port_data(port); | ||
| 765 | int i; | ||
| 766 | |||
| 767 | for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) | ||
| 768 | usb_kill_urb(port->read_urbs[i]); | ||
| 769 | |||
| 770 | usb_kill_urb(port->interrupt_in_urb); | ||
| 771 | |||
| 772 | if (port_priv) { | ||
| 773 | flush_work(&port_priv->interrupt_work); | ||
| 774 | flush_work(&port_priv->lsr_work); | ||
| 775 | } | ||
| 776 | |||
| 777 | return 0; | ||
| 778 | } | ||
| 779 | |||
| 780 | static int f81232_resume(struct usb_serial *serial) | ||
| 781 | { | ||
| 782 | struct usb_serial_port *port = serial->port[0]; | ||
| 783 | int result; | ||
| 784 | |||
| 785 | if (tty_port_initialized(&port->port)) { | ||
| 786 | result = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO); | ||
| 787 | if (result) { | ||
| 788 | dev_err(&port->dev, "submit interrupt urb failed: %d\n", | ||
| 789 | result); | ||
| 790 | return result; | ||
| 791 | } | ||
| 792 | } | ||
| 793 | |||
| 794 | return usb_serial_generic_resume(serial); | ||
| 795 | } | ||
| 796 | |||
| 635 | static struct usb_serial_driver f81232_device = { | 797 | static struct usb_serial_driver f81232_device = { |
| 636 | .driver = { | 798 | .driver = { |
| 637 | .owner = THIS_MODULE, | 799 | .owner = THIS_MODULE, |
| @@ -655,6 +817,8 @@ static struct usb_serial_driver f81232_device = { | |||
| 655 | .read_int_callback = f81232_read_int_callback, | 817 | .read_int_callback = f81232_read_int_callback, |
| 656 | .port_probe = f81232_port_probe, | 818 | .port_probe = f81232_port_probe, |
| 657 | .port_remove = f81232_port_remove, | 819 | .port_remove = f81232_port_remove, |
| 820 | .suspend = f81232_suspend, | ||
| 821 | .resume = f81232_resume, | ||
| 658 | }; | 822 | }; |
| 659 | 823 | ||
| 660 | static struct usb_serial_driver * const serial_drivers[] = { | 824 | static struct usb_serial_driver * const serial_drivers[] = { |
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 2274d9625f63..1be8bea372a2 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c | |||
| @@ -106,12 +106,8 @@ void usb_serial_generic_deregister(void) | |||
| 106 | int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port) | 106 | int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port) |
| 107 | { | 107 | { |
| 108 | int result = 0; | 108 | int result = 0; |
| 109 | unsigned long flags; | ||
| 110 | 109 | ||
| 111 | spin_lock_irqsave(&port->lock, flags); | 110 | clear_bit(USB_SERIAL_THROTTLED, &port->flags); |
| 112 | port->throttled = 0; | ||
| 113 | port->throttle_req = 0; | ||
| 114 | spin_unlock_irqrestore(&port->lock, flags); | ||
| 115 | 111 | ||
| 116 | if (port->bulk_in_size) | 112 | if (port->bulk_in_size) |
| 117 | result = usb_serial_generic_submit_read_urbs(port, GFP_KERNEL); | 113 | result = usb_serial_generic_submit_read_urbs(port, GFP_KERNEL); |
| @@ -375,7 +371,7 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb) | |||
| 375 | { | 371 | { |
| 376 | struct usb_serial_port *port = urb->context; | 372 | struct usb_serial_port *port = urb->context; |
| 377 | unsigned char *data = urb->transfer_buffer; | 373 | unsigned char *data = urb->transfer_buffer; |
| 378 | unsigned long flags; | 374 | bool stopped = false; |
| 379 | int status = urb->status; | 375 | int status = urb->status; |
| 380 | int i; | 376 | int i; |
| 381 | 377 | ||
| @@ -383,42 +379,55 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb) | |||
| 383 | if (urb == port->read_urbs[i]) | 379 | if (urb == port->read_urbs[i]) |
| 384 | break; | 380 | break; |
| 385 | } | 381 | } |
| 386 | set_bit(i, &port->read_urbs_free); | ||
| 387 | 382 | ||
| 388 | dev_dbg(&port->dev, "%s - urb %d, len %d\n", __func__, i, | 383 | dev_dbg(&port->dev, "%s - urb %d, len %d\n", __func__, i, |
| 389 | urb->actual_length); | 384 | urb->actual_length); |
| 390 | switch (status) { | 385 | switch (status) { |
| 391 | case 0: | 386 | case 0: |
| 387 | usb_serial_debug_data(&port->dev, __func__, urb->actual_length, | ||
| 388 | data); | ||
| 389 | port->serial->type->process_read_urb(urb); | ||
| 392 | break; | 390 | break; |
| 393 | case -ENOENT: | 391 | case -ENOENT: |
| 394 | case -ECONNRESET: | 392 | case -ECONNRESET: |
| 395 | case -ESHUTDOWN: | 393 | case -ESHUTDOWN: |
| 396 | dev_dbg(&port->dev, "%s - urb stopped: %d\n", | 394 | dev_dbg(&port->dev, "%s - urb stopped: %d\n", |
| 397 | __func__, status); | 395 | __func__, status); |
| 398 | return; | 396 | stopped = true; |
| 397 | break; | ||
| 399 | case -EPIPE: | 398 | case -EPIPE: |
| 400 | dev_err(&port->dev, "%s - urb stopped: %d\n", | 399 | dev_err(&port->dev, "%s - urb stopped: %d\n", |
| 401 | __func__, status); | 400 | __func__, status); |
| 402 | return; | 401 | stopped = true; |
| 402 | break; | ||
| 403 | default: | 403 | default: |
| 404 | dev_dbg(&port->dev, "%s - nonzero urb status: %d\n", | 404 | dev_dbg(&port->dev, "%s - nonzero urb status: %d\n", |
| 405 | __func__, status); | 405 | __func__, status); |
| 406 | goto resubmit; | 406 | break; |
| 407 | } | 407 | } |
| 408 | 408 | ||
| 409 | usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data); | 409 | /* |
| 410 | port->serial->type->process_read_urb(urb); | 410 | * Make sure URB processing is done before marking as free to avoid |
| 411 | * racing with unthrottle() on another CPU. Matches the barriers | ||
| 412 | * implied by the test_and_clear_bit() in | ||
| 413 | * usb_serial_generic_submit_read_urb(). | ||
| 414 | */ | ||
| 415 | smp_mb__before_atomic(); | ||
| 416 | set_bit(i, &port->read_urbs_free); | ||
| 417 | /* | ||
| 418 | * Make sure URB is marked as free before checking the throttled flag | ||
| 419 | * to avoid racing with unthrottle() on another CPU. Matches the | ||
| 420 | * smp_mb() in unthrottle(). | ||
| 421 | */ | ||
| 422 | smp_mb__after_atomic(); | ||
| 411 | 423 | ||
| 412 | resubmit: | 424 | if (stopped) |
| 413 | /* Throttle the device if requested by tty */ | 425 | return; |
| 414 | spin_lock_irqsave(&port->lock, flags); | 426 | |
| 415 | port->throttled = port->throttle_req; | 427 | if (test_bit(USB_SERIAL_THROTTLED, &port->flags)) |
| 416 | if (!port->throttled) { | 428 | return; |
| 417 | spin_unlock_irqrestore(&port->lock, flags); | 429 | |
| 418 | usb_serial_generic_submit_read_urb(port, i, GFP_ATOMIC); | 430 | usb_serial_generic_submit_read_urb(port, i, GFP_ATOMIC); |
| 419 | } else { | ||
| 420 | spin_unlock_irqrestore(&port->lock, flags); | ||
| 421 | } | ||
| 422 | } | 431 | } |
| 423 | EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback); | 432 | EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback); |
| 424 | 433 | ||
| @@ -454,10 +463,9 @@ void usb_serial_generic_write_bulk_callback(struct urb *urb) | |||
| 454 | default: | 463 | default: |
| 455 | dev_err_console(port, "%s - nonzero urb status: %d\n", | 464 | dev_err_console(port, "%s - nonzero urb status: %d\n", |
| 456 | __func__, status); | 465 | __func__, status); |
| 457 | goto resubmit; | 466 | break; |
| 458 | } | 467 | } |
| 459 | 468 | ||
| 460 | resubmit: | ||
| 461 | usb_serial_generic_write_start(port, GFP_ATOMIC); | 469 | usb_serial_generic_write_start(port, GFP_ATOMIC); |
| 462 | usb_serial_port_softint(port); | 470 | usb_serial_port_softint(port); |
| 463 | } | 471 | } |
| @@ -466,26 +474,24 @@ EXPORT_SYMBOL_GPL(usb_serial_generic_write_bulk_callback); | |||
| 466 | void usb_serial_generic_throttle(struct tty_struct *tty) | 474 | void usb_serial_generic_throttle(struct tty_struct *tty) |
| 467 | { | 475 | { |
| 468 | struct usb_serial_port *port = tty->driver_data; | 476 | struct usb_serial_port *port = tty->driver_data; |
| 469 | unsigned long flags; | ||
| 470 | 477 | ||
| 471 | spin_lock_irqsave(&port->lock, flags); | 478 | set_bit(USB_SERIAL_THROTTLED, &port->flags); |
| 472 | port->throttle_req = 1; | ||
| 473 | spin_unlock_irqrestore(&port->lock, flags); | ||
| 474 | } | 479 | } |
| 475 | EXPORT_SYMBOL_GPL(usb_serial_generic_throttle); | 480 | EXPORT_SYMBOL_GPL(usb_serial_generic_throttle); |
| 476 | 481 | ||
| 477 | void usb_serial_generic_unthrottle(struct tty_struct *tty) | 482 | void usb_serial_generic_unthrottle(struct tty_struct *tty) |
| 478 | { | 483 | { |
| 479 | struct usb_serial_port *port = tty->driver_data; | 484 | struct usb_serial_port *port = tty->driver_data; |
| 480 | int was_throttled; | ||
| 481 | 485 | ||
| 482 | spin_lock_irq(&port->lock); | 486 | clear_bit(USB_SERIAL_THROTTLED, &port->flags); |
| 483 | was_throttled = port->throttled; | 487 | |
| 484 | port->throttled = port->throttle_req = 0; | 488 | /* |
| 485 | spin_unlock_irq(&port->lock); | 489 | * Matches the smp_mb__after_atomic() in |
| 490 | * usb_serial_generic_read_bulk_callback(). | ||
| 491 | */ | ||
| 492 | smp_mb(); | ||
| 486 | 493 | ||
| 487 | if (was_throttled) | 494 | usb_serial_generic_submit_read_urbs(port, GFP_KERNEL); |
| 488 | usb_serial_generic_submit_read_urbs(port, GFP_KERNEL); | ||
| 489 | } | 495 | } |
| 490 | EXPORT_SYMBOL_GPL(usb_serial_generic_unthrottle); | 496 | EXPORT_SYMBOL_GPL(usb_serial_generic_unthrottle); |
| 491 | 497 | ||
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index 4ca31c0e4174..48a439298a68 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c | |||
| @@ -1751,7 +1751,7 @@ static void process_rcvd_data(struct edgeport_serial *edge_serial, | |||
| 1751 | edge_serial->rxState = EXPECT_HDR2; | 1751 | edge_serial->rxState = EXPECT_HDR2; |
| 1752 | break; | 1752 | break; |
| 1753 | } | 1753 | } |
| 1754 | /* otherwise, drop on through */ | 1754 | /* Fall through */ |
| 1755 | case EXPECT_HDR2: | 1755 | case EXPECT_HDR2: |
| 1756 | edge_serial->rxHeader2 = *buffer; | 1756 | edge_serial->rxHeader2 = *buffer; |
| 1757 | ++buffer; | 1757 | ++buffer; |
| @@ -1790,29 +1790,20 @@ static void process_rcvd_data(struct edgeport_serial *edge_serial, | |||
| 1790 | edge_serial->rxHeader2, 0); | 1790 | edge_serial->rxHeader2, 0); |
| 1791 | edge_serial->rxState = EXPECT_HDR1; | 1791 | edge_serial->rxState = EXPECT_HDR1; |
| 1792 | break; | 1792 | break; |
| 1793 | } else { | ||
| 1794 | edge_serial->rxPort = | ||
| 1795 | IOSP_GET_HDR_PORT(edge_serial->rxHeader1); | ||
| 1796 | edge_serial->rxBytesRemaining = | ||
| 1797 | IOSP_GET_HDR_DATA_LEN( | ||
| 1798 | edge_serial->rxHeader1, | ||
| 1799 | edge_serial->rxHeader2); | ||
| 1800 | dev_dbg(dev, "%s - Data for Port %u Len %u\n", | ||
| 1801 | __func__, | ||
| 1802 | edge_serial->rxPort, | ||
| 1803 | edge_serial->rxBytesRemaining); | ||
| 1804 | |||
| 1805 | /* ASSERT(DevExt->RxPort < DevExt->NumPorts); | ||
| 1806 | * ASSERT(DevExt->RxBytesRemaining < | ||
| 1807 | * IOSP_MAX_DATA_LENGTH); | ||
| 1808 | */ | ||
| 1809 | |||
| 1810 | if (bufferLength == 0) { | ||
| 1811 | edge_serial->rxState = EXPECT_DATA; | ||
| 1812 | break; | ||
| 1813 | } | ||
| 1814 | /* Else, drop through */ | ||
| 1815 | } | 1793 | } |
| 1794 | |||
| 1795 | edge_serial->rxPort = IOSP_GET_HDR_PORT(edge_serial->rxHeader1); | ||
| 1796 | edge_serial->rxBytesRemaining = IOSP_GET_HDR_DATA_LEN(edge_serial->rxHeader1, | ||
| 1797 | edge_serial->rxHeader2); | ||
| 1798 | dev_dbg(dev, "%s - Data for Port %u Len %u\n", __func__, | ||
| 1799 | edge_serial->rxPort, | ||
| 1800 | edge_serial->rxBytesRemaining); | ||
| 1801 | |||
| 1802 | if (bufferLength == 0) { | ||
| 1803 | edge_serial->rxState = EXPECT_DATA; | ||
| 1804 | break; | ||
| 1805 | } | ||
| 1806 | /* Fall through */ | ||
| 1816 | case EXPECT_DATA: /* Expect data */ | 1807 | case EXPECT_DATA: /* Expect data */ |
| 1817 | if (bufferLength < edge_serial->rxBytesRemaining) { | 1808 | if (bufferLength < edge_serial->rxBytesRemaining) { |
| 1818 | rxLen = bufferLength; | 1809 | rxLen = bufferLength; |
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index 449e89db9cea..d5bff69b1769 100644 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c | |||
| @@ -942,9 +942,7 @@ static void iuu_close(struct usb_serial_port *port) | |||
| 942 | 942 | ||
| 943 | static void iuu_init_termios(struct tty_struct *tty) | 943 | static void iuu_init_termios(struct tty_struct *tty) |
| 944 | { | 944 | { |
| 945 | tty->termios = tty_std_termios; | 945 | tty->termios.c_cflag = B9600 | CS8 | CSTOPB | CREAD | PARENB | CLOCAL; |
| 946 | tty->termios.c_cflag = CLOCAL | CREAD | CS8 | B9600 | ||
| 947 | | TIOCM_CTS | CSTOPB | PARENB; | ||
| 948 | tty->termios.c_ispeed = 9600; | 946 | tty->termios.c_ispeed = 9600; |
| 949 | tty->termios.c_ospeed = 9600; | 947 | tty->termios.c_ospeed = 9600; |
| 950 | tty->termios.c_lflag = 0; | 948 | tty->termios.c_lflag = 0; |
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index ae9cb15ee02d..38ae0fc826cc 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c | |||
| @@ -393,10 +393,7 @@ static int oti6858_chars_in_buffer(struct tty_struct *tty) | |||
| 393 | 393 | ||
| 394 | static void oti6858_init_termios(struct tty_struct *tty) | 394 | static void oti6858_init_termios(struct tty_struct *tty) |
| 395 | { | 395 | { |
| 396 | tty->termios = tty_std_termios; | 396 | tty_encode_baud_rate(tty, 38400, 38400); |
| 397 | tty->termios.c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL; | ||
| 398 | tty->termios.c_ispeed = 38400; | ||
| 399 | tty->termios.c_ospeed = 38400; | ||
| 400 | } | 397 | } |
| 401 | 398 | ||
| 402 | static void oti6858_set_termios(struct tty_struct *tty, | 399 | static void oti6858_set_termios(struct tty_struct *tty, |
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index bb3f9aa4a909..55122ac84518 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c | |||
| @@ -145,6 +145,8 @@ MODULE_DEVICE_TABLE(usb, id_table); | |||
| 145 | #define UART_OVERRUN_ERROR 0x40 | 145 | #define UART_OVERRUN_ERROR 0x40 |
| 146 | #define UART_CTS 0x80 | 146 | #define UART_CTS 0x80 |
| 147 | 147 | ||
| 148 | #define PL2303_FLOWCTRL_MASK 0xf0 | ||
| 149 | |||
| 148 | static void pl2303_set_break(struct usb_serial_port *port, bool enable); | 150 | static void pl2303_set_break(struct usb_serial_port *port, bool enable); |
| 149 | 151 | ||
| 150 | enum pl2303_type { | 152 | enum pl2303_type { |
| @@ -156,6 +158,7 @@ enum pl2303_type { | |||
| 156 | struct pl2303_type_data { | 158 | struct pl2303_type_data { |
| 157 | speed_t max_baud_rate; | 159 | speed_t max_baud_rate; |
| 158 | unsigned long quirks; | 160 | unsigned long quirks; |
| 161 | unsigned int no_autoxonxoff:1; | ||
| 159 | }; | 162 | }; |
| 160 | 163 | ||
| 161 | struct pl2303_serial_private { | 164 | struct pl2303_serial_private { |
| @@ -173,11 +176,12 @@ struct pl2303_private { | |||
| 173 | 176 | ||
| 174 | static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = { | 177 | static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = { |
| 175 | [TYPE_01] = { | 178 | [TYPE_01] = { |
| 176 | .max_baud_rate = 1228800, | 179 | .max_baud_rate = 1228800, |
| 177 | .quirks = PL2303_QUIRK_LEGACY, | 180 | .quirks = PL2303_QUIRK_LEGACY, |
| 181 | .no_autoxonxoff = true, | ||
| 178 | }, | 182 | }, |
| 179 | [TYPE_HX] = { | 183 | [TYPE_HX] = { |
| 180 | .max_baud_rate = 12000000, | 184 | .max_baud_rate = 12000000, |
| 181 | }, | 185 | }, |
| 182 | }; | 186 | }; |
| 183 | 187 | ||
| @@ -223,6 +227,29 @@ static int pl2303_vendor_write(struct usb_serial *serial, u16 value, u16 index) | |||
| 223 | return 0; | 227 | return 0; |
| 224 | } | 228 | } |
| 225 | 229 | ||
| 230 | static int pl2303_update_reg(struct usb_serial *serial, u8 reg, u8 mask, u8 val) | ||
| 231 | { | ||
| 232 | int ret = 0; | ||
| 233 | u8 *buf; | ||
| 234 | |||
| 235 | buf = kmalloc(1, GFP_KERNEL); | ||
| 236 | if (!buf) | ||
| 237 | return -ENOMEM; | ||
| 238 | |||
| 239 | ret = pl2303_vendor_read(serial, reg | 0x80, buf); | ||
| 240 | if (ret) | ||
| 241 | goto out_free; | ||
| 242 | |||
| 243 | *buf &= ~mask; | ||
| 244 | *buf |= val & mask; | ||
| 245 | |||
| 246 | ret = pl2303_vendor_write(serial, reg, *buf); | ||
| 247 | out_free: | ||
| 248 | kfree(buf); | ||
| 249 | |||
| 250 | return ret; | ||
| 251 | } | ||
| 252 | |||
| 226 | static int pl2303_probe(struct usb_serial *serial, | 253 | static int pl2303_probe(struct usb_serial *serial, |
| 227 | const struct usb_device_id *id) | 254 | const struct usb_device_id *id) |
| 228 | { | 255 | { |
| @@ -552,6 +579,20 @@ static bool pl2303_termios_change(const struct ktermios *a, const struct ktermio | |||
| 552 | return tty_termios_hw_change(a, b) || ixon_change; | 579 | return tty_termios_hw_change(a, b) || ixon_change; |
| 553 | } | 580 | } |
| 554 | 581 | ||
| 582 | static bool pl2303_enable_xonxoff(struct tty_struct *tty, const struct pl2303_type_data *type) | ||
| 583 | { | ||
| 584 | if (!I_IXON(tty) || I_IXANY(tty)) | ||
| 585 | return false; | ||
| 586 | |||
| 587 | if (START_CHAR(tty) != 0x11 || STOP_CHAR(tty) != 0x13) | ||
| 588 | return false; | ||
| 589 | |||
| 590 | if (type->no_autoxonxoff) | ||
| 591 | return false; | ||
| 592 | |||
| 593 | return true; | ||
| 594 | } | ||
| 595 | |||
| 555 | static void pl2303_set_termios(struct tty_struct *tty, | 596 | static void pl2303_set_termios(struct tty_struct *tty, |
| 556 | struct usb_serial_port *port, struct ktermios *old_termios) | 597 | struct usb_serial_port *port, struct ktermios *old_termios) |
| 557 | { | 598 | { |
| @@ -678,14 +719,13 @@ static void pl2303_set_termios(struct tty_struct *tty, | |||
| 678 | 719 | ||
| 679 | if (C_CRTSCTS(tty)) { | 720 | if (C_CRTSCTS(tty)) { |
| 680 | if (spriv->quirks & PL2303_QUIRK_LEGACY) | 721 | if (spriv->quirks & PL2303_QUIRK_LEGACY) |
| 681 | pl2303_vendor_write(serial, 0x0, 0x41); | 722 | pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0x40); |
| 682 | else | 723 | else |
| 683 | pl2303_vendor_write(serial, 0x0, 0x61); | 724 | pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0x60); |
| 684 | } else if (I_IXON(tty) && !I_IXANY(tty) && START_CHAR(tty) == 0x11 && | 725 | } else if (pl2303_enable_xonxoff(tty, spriv->type)) { |
| 685 | STOP_CHAR(tty) == 0x13) { | 726 | pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0xc0); |
| 686 | pl2303_vendor_write(serial, 0x0, 0xc0); | ||
| 687 | } else { | 727 | } else { |
| 688 | pl2303_vendor_write(serial, 0x0, 0x0); | 728 | pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0); |
| 689 | } | 729 | } |
| 690 | 730 | ||
| 691 | kfree(buf); | 731 | kfree(buf); |
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c index b42714855364..3bac55bd9bd9 100644 --- a/drivers/usb/serial/spcp8x5.c +++ b/drivers/usb/serial/spcp8x5.c | |||
| @@ -281,10 +281,7 @@ static void spcp8x5_dtr_rts(struct usb_serial_port *port, int on) | |||
| 281 | 281 | ||
| 282 | static void spcp8x5_init_termios(struct tty_struct *tty) | 282 | static void spcp8x5_init_termios(struct tty_struct *tty) |
| 283 | { | 283 | { |
| 284 | tty->termios = tty_std_termios; | 284 | tty_encode_baud_rate(tty, 115200, 115200); |
| 285 | tty->termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL; | ||
| 286 | tty->termios.c_ispeed = 115200; | ||
| 287 | tty->termios.c_ospeed = 115200; | ||
| 288 | } | 285 | } |
| 289 | 286 | ||
| 290 | static void spcp8x5_set_termios(struct tty_struct *tty, | 287 | static void spcp8x5_set_termios(struct tty_struct *tty, |
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 7e89efbf2c28..676c296103a2 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c | |||
| @@ -164,9 +164,9 @@ void usb_serial_put(struct usb_serial *serial) | |||
| 164 | * @driver: the driver (USB in our case) | 164 | * @driver: the driver (USB in our case) |
| 165 | * @tty: the tty being created | 165 | * @tty: the tty being created |
| 166 | * | 166 | * |
| 167 | * Create the termios objects for this tty. We use the default | 167 | * Initialise the termios structure for this tty. We use the default |
| 168 | * USB serial settings but permit them to be overridden by | 168 | * USB serial settings but permit them to be overridden by |
| 169 | * serial->type->init_termios. | 169 | * serial->type->init_termios on first open. |
| 170 | * | 170 | * |
| 171 | * This is the first place a new tty gets used. Hence this is where we | 171 | * This is the first place a new tty gets used. Hence this is where we |
| 172 | * acquire references to the usb_serial structure and the driver module, | 172 | * acquire references to the usb_serial structure and the driver module, |
| @@ -178,6 +178,7 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty) | |||
| 178 | int idx = tty->index; | 178 | int idx = tty->index; |
| 179 | struct usb_serial *serial; | 179 | struct usb_serial *serial; |
| 180 | struct usb_serial_port *port; | 180 | struct usb_serial_port *port; |
| 181 | bool init_termios; | ||
| 181 | int retval = -ENODEV; | 182 | int retval = -ENODEV; |
| 182 | 183 | ||
| 183 | port = usb_serial_port_get_by_minor(idx); | 184 | port = usb_serial_port_get_by_minor(idx); |
| @@ -192,14 +193,16 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty) | |||
| 192 | if (retval) | 193 | if (retval) |
| 193 | goto error_get_interface; | 194 | goto error_get_interface; |
| 194 | 195 | ||
| 196 | init_termios = (driver->termios[idx] == NULL); | ||
| 197 | |||
| 195 | retval = tty_standard_install(driver, tty); | 198 | retval = tty_standard_install(driver, tty); |
| 196 | if (retval) | 199 | if (retval) |
| 197 | goto error_init_termios; | 200 | goto error_init_termios; |
| 198 | 201 | ||
| 199 | mutex_unlock(&serial->disc_mutex); | 202 | mutex_unlock(&serial->disc_mutex); |
| 200 | 203 | ||
| 201 | /* allow the driver to update the settings */ | 204 | /* allow the driver to update the initial settings */ |
| 202 | if (serial->type->init_termios) | 205 | if (init_termios && serial->type->init_termios) |
| 203 | serial->type->init_termios(tty); | 206 | serial->type->init_termios(tty); |
| 204 | 207 | ||
| 205 | tty->driver_data = port; | 208 | tty->driver_data = port; |
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index a73ea495d5a7..59190d88fa9f 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c | |||
| @@ -65,6 +65,7 @@ static const char* host_info(struct Scsi_Host *host) | |||
| 65 | static int slave_alloc (struct scsi_device *sdev) | 65 | static int slave_alloc (struct scsi_device *sdev) |
| 66 | { | 66 | { |
| 67 | struct us_data *us = host_to_us(sdev->host); | 67 | struct us_data *us = host_to_us(sdev->host); |
| 68 | int maxp; | ||
| 68 | 69 | ||
| 69 | /* | 70 | /* |
| 70 | * Set the INQUIRY transfer length to 36. We don't use any of | 71 | * Set the INQUIRY transfer length to 36. We don't use any of |
| @@ -74,20 +75,17 @@ static int slave_alloc (struct scsi_device *sdev) | |||
| 74 | sdev->inquiry_len = 36; | 75 | sdev->inquiry_len = 36; |
| 75 | 76 | ||
| 76 | /* | 77 | /* |
| 77 | * USB has unusual DMA-alignment requirements: Although the | 78 | * USB has unusual scatter-gather requirements: the length of each |
| 78 | * starting address of each scatter-gather element doesn't matter, | 79 | * scatterlist element except the last must be divisible by the |
| 79 | * the length of each element except the last must be divisible | 80 | * Bulk maxpacket value. Fortunately this value is always a |
| 80 | * by the Bulk maxpacket value. There's currently no way to | 81 | * power of 2. Inform the block layer about this requirement. |
| 81 | * express this by block-layer constraints, so we'll cop out | 82 | */ |
| 82 | * and simply require addresses to be aligned at 512-byte | 83 | maxp = usb_maxpacket(us->pusb_dev, us->recv_bulk_pipe, 0); |
| 83 | * boundaries. This is okay since most block I/O involves | 84 | blk_queue_virt_boundary(sdev->request_queue, maxp - 1); |
| 84 | * hardware sectors that are multiples of 512 bytes in length, | 85 | |
| 85 | * and since host controllers up through USB 2.0 have maxpacket | 86 | /* |
| 86 | * values no larger than 512. | 87 | * Some host controllers may have alignment requirements. |
| 87 | * | 88 | * We'll play it safe by requiring 512-byte alignment always. |
| 88 | * But it doesn't suffice for Wireless USB, where Bulk maxpacket | ||
| 89 | * values can be as large as 2048. To make that work properly | ||
| 90 | * will require changes to the block layer. | ||
| 91 | */ | 89 | */ |
| 92 | blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1)); | 90 | blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1)); |
| 93 | 91 | ||
diff --git a/drivers/usb/storage/sierra_ms.c b/drivers/usb/storage/sierra_ms.c index 6ac60abd2e15..e605cbc3d8bf 100644 --- a/drivers/usb/storage/sierra_ms.c +++ b/drivers/usb/storage/sierra_ms.c | |||
| @@ -194,8 +194,6 @@ int sierra_ms_init(struct us_data *us) | |||
| 194 | kfree(swocInfo); | 194 | kfree(swocInfo); |
| 195 | } | 195 | } |
| 196 | complete: | 196 | complete: |
| 197 | result = device_create_file(&us->pusb_intf->dev, &dev_attr_truinst); | 197 | return device_create_file(&us->pusb_intf->dev, &dev_attr_truinst); |
| 198 | |||
| 199 | return 0; | ||
| 200 | } | 198 | } |
| 201 | 199 | ||
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index a6d68191c861..047c5922618f 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c | |||
| @@ -789,24 +789,33 @@ static int uas_slave_alloc(struct scsi_device *sdev) | |||
| 789 | { | 789 | { |
| 790 | struct uas_dev_info *devinfo = | 790 | struct uas_dev_info *devinfo = |
| 791 | (struct uas_dev_info *)sdev->host->hostdata; | 791 | (struct uas_dev_info *)sdev->host->hostdata; |
| 792 | int maxp; | ||
| 792 | 793 | ||
| 793 | sdev->hostdata = devinfo; | 794 | sdev->hostdata = devinfo; |
| 794 | 795 | ||
| 795 | /* | 796 | /* |
| 796 | * USB has unusual DMA-alignment requirements: Although the | 797 | * We have two requirements here. We must satisfy the requirements |
| 797 | * starting address of each scatter-gather element doesn't matter, | 798 | * of the physical HC and the demands of the protocol, as we |
| 798 | * the length of each element except the last must be divisible | 799 | * definitely want no additional memory allocation in this path |
| 799 | * by the Bulk maxpacket value. There's currently no way to | 800 | * ruling out using bounce buffers. |
| 800 | * express this by block-layer constraints, so we'll cop out | ||
| 801 | * and simply require addresses to be aligned at 512-byte | ||
| 802 | * boundaries. This is okay since most block I/O involves | ||
| 803 | * hardware sectors that are multiples of 512 bytes in length, | ||
| 804 | * and since host controllers up through USB 2.0 have maxpacket | ||
| 805 | * values no larger than 512. | ||
| 806 | * | 801 | * |
| 807 | * But it doesn't suffice for Wireless USB, where Bulk maxpacket | 802 | * For a transmission on USB to continue we must never send |
| 808 | * values can be as large as 2048. To make that work properly | 803 | * a package that is smaller than maxpacket. Hence the length of each |
| 809 | * will require changes to the block layer. | 804 | * scatterlist element except the last must be divisible by the |
| 805 | * Bulk maxpacket value. | ||
| 806 | * If the HC does not ensure that through SG, | ||
| 807 | * the upper layer must do that. We must assume nothing | ||
| 808 | * about the capabilities off the HC, so we use the most | ||
| 809 | * pessimistic requirement. | ||
| 810 | */ | ||
| 811 | |||
| 812 | maxp = usb_maxpacket(devinfo->udev, devinfo->data_in_pipe, 0); | ||
| 813 | blk_queue_virt_boundary(sdev->request_queue, maxp - 1); | ||
| 814 | |||
| 815 | /* | ||
| 816 | * The protocol has no requirements on alignment in the strict sense. | ||
| 817 | * Controllers may or may not have alignment restrictions. | ||
| 818 | * As this is not exported, we use an extremely conservative guess. | ||
| 810 | */ | 819 | */ |
| 811 | blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1)); | 820 | blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1)); |
| 812 | 821 | ||
diff --git a/drivers/usb/typec/altmodes/Kconfig b/drivers/usb/typec/altmodes/Kconfig index ef2226eb7a33..187690fd1a5b 100644 --- a/drivers/usb/typec/altmodes/Kconfig +++ b/drivers/usb/typec/altmodes/Kconfig | |||
| @@ -12,4 +12,14 @@ config TYPEC_DP_ALTMODE | |||
| 12 | To compile this driver as a module, choose M here: the | 12 | To compile this driver as a module, choose M here: the |
| 13 | module will be called typec_displayport. | 13 | module will be called typec_displayport. |
| 14 | 14 | ||
| 15 | config TYPEC_NVIDIA_ALTMODE | ||
| 16 | tristate "NVIDIA Alternate Mode driver" | ||
| 17 | depends on TYPEC_DP_ALTMODE | ||
| 18 | help | ||
| 19 | Latest NVIDIA GPUs support VirtualLink devices. Select this | ||
| 20 | to enable support for VirtualLink devices with NVIDIA GPUs. | ||
| 21 | |||
| 22 | To compile this driver as a module, choose M here: the | ||
| 23 | module will be called typec_displayport. | ||
| 24 | |||
| 15 | endmenu | 25 | endmenu |
diff --git a/drivers/usb/typec/altmodes/Makefile b/drivers/usb/typec/altmodes/Makefile index eda8456f1c92..45717548b396 100644 --- a/drivers/usb/typec/altmodes/Makefile +++ b/drivers/usb/typec/altmodes/Makefile | |||
| @@ -2,3 +2,5 @@ | |||
| 2 | 2 | ||
| 3 | obj-$(CONFIG_TYPEC_DP_ALTMODE) += typec_displayport.o | 3 | obj-$(CONFIG_TYPEC_DP_ALTMODE) += typec_displayport.o |
| 4 | typec_displayport-y := displayport.o | 4 | typec_displayport-y := displayport.o |
| 5 | obj-$(CONFIG_TYPEC_NVIDIA_ALTMODE) += typec_nvidia.o | ||
| 6 | typec_nvidia-y := nvidia.o | ||
diff --git a/drivers/usb/typec/altmodes/displayport.c b/drivers/usb/typec/altmodes/displayport.c index 610d790bc9be..4092248a5936 100644 --- a/drivers/usb/typec/altmodes/displayport.c +++ b/drivers/usb/typec/altmodes/displayport.c | |||
| @@ -14,7 +14,7 @@ | |||
| 14 | #include <linux/usb/pd_vdo.h> | 14 | #include <linux/usb/pd_vdo.h> |
| 15 | #include <linux/usb/typec_dp.h> | 15 | #include <linux/usb/typec_dp.h> |
| 16 | 16 | ||
| 17 | #define DP_HEADER(cmd) (VDO(USB_TYPEC_DP_SID, 1, cmd) | \ | 17 | #define DP_HEADER(_dp, cmd) (VDO((_dp)->alt->svid, 1, cmd) | \ |
| 18 | VDO_OPOS(USB_TYPEC_DP_MODE)) | 18 | VDO_OPOS(USB_TYPEC_DP_MODE)) |
| 19 | 19 | ||
| 20 | enum { | 20 | enum { |
| @@ -100,7 +100,7 @@ static int dp_altmode_configure(struct dp_altmode *dp, u8 con) | |||
| 100 | if (dp->data.status & DP_STATUS_PREFER_MULTI_FUNC && | 100 | if (dp->data.status & DP_STATUS_PREFER_MULTI_FUNC && |
| 101 | pin_assign & DP_PIN_ASSIGN_MULTI_FUNC_MASK) | 101 | pin_assign & DP_PIN_ASSIGN_MULTI_FUNC_MASK) |
| 102 | pin_assign &= DP_PIN_ASSIGN_MULTI_FUNC_MASK; | 102 | pin_assign &= DP_PIN_ASSIGN_MULTI_FUNC_MASK; |
| 103 | else | 103 | else if (pin_assign & DP_PIN_ASSIGN_DP_ONLY_MASK) |
| 104 | pin_assign &= DP_PIN_ASSIGN_DP_ONLY_MASK; | 104 | pin_assign &= DP_PIN_ASSIGN_DP_ONLY_MASK; |
| 105 | 105 | ||
| 106 | if (!pin_assign) | 106 | if (!pin_assign) |
| @@ -155,7 +155,7 @@ static int dp_altmode_configured(struct dp_altmode *dp) | |||
| 155 | 155 | ||
| 156 | static int dp_altmode_configure_vdm(struct dp_altmode *dp, u32 conf) | 156 | static int dp_altmode_configure_vdm(struct dp_altmode *dp, u32 conf) |
| 157 | { | 157 | { |
| 158 | u32 header = DP_HEADER(DP_CMD_CONFIGURE); | 158 | u32 header = DP_HEADER(dp, DP_CMD_CONFIGURE); |
| 159 | int ret; | 159 | int ret; |
| 160 | 160 | ||
| 161 | ret = typec_altmode_notify(dp->alt, TYPEC_STATE_SAFE, &dp->data); | 161 | ret = typec_altmode_notify(dp->alt, TYPEC_STATE_SAFE, &dp->data); |
| @@ -193,7 +193,7 @@ static void dp_altmode_work(struct work_struct *work) | |||
| 193 | dev_err(&dp->alt->dev, "failed to enter mode\n"); | 193 | dev_err(&dp->alt->dev, "failed to enter mode\n"); |
| 194 | break; | 194 | break; |
| 195 | case DP_STATE_UPDATE: | 195 | case DP_STATE_UPDATE: |
| 196 | header = DP_HEADER(DP_CMD_STATUS_UPDATE); | 196 | header = DP_HEADER(dp, DP_CMD_STATUS_UPDATE); |
| 197 | vdo = 1; | 197 | vdo = 1; |
| 198 | ret = typec_altmode_vdm(dp->alt, header, &vdo, 2); | 198 | ret = typec_altmode_vdm(dp->alt, header, &vdo, 2); |
| 199 | if (ret) | 199 | if (ret) |
| @@ -507,7 +507,7 @@ static const struct attribute_group dp_altmode_group = { | |||
| 507 | .attrs = dp_altmode_attrs, | 507 | .attrs = dp_altmode_attrs, |
| 508 | }; | 508 | }; |
| 509 | 509 | ||
| 510 | static int dp_altmode_probe(struct typec_altmode *alt) | 510 | int dp_altmode_probe(struct typec_altmode *alt) |
| 511 | { | 511 | { |
| 512 | const struct typec_altmode *port = typec_altmode_get_partner(alt); | 512 | const struct typec_altmode *port = typec_altmode_get_partner(alt); |
| 513 | struct dp_altmode *dp; | 513 | struct dp_altmode *dp; |
| @@ -545,14 +545,16 @@ static int dp_altmode_probe(struct typec_altmode *alt) | |||
| 545 | 545 | ||
| 546 | return 0; | 546 | return 0; |
| 547 | } | 547 | } |
| 548 | EXPORT_SYMBOL_GPL(dp_altmode_probe); | ||
| 548 | 549 | ||
| 549 | static void dp_altmode_remove(struct typec_altmode *alt) | 550 | void dp_altmode_remove(struct typec_altmode *alt) |
| 550 | { | 551 | { |
| 551 | struct dp_altmode *dp = typec_altmode_get_drvdata(alt); | 552 | struct dp_altmode *dp = typec_altmode_get_drvdata(alt); |
| 552 | 553 | ||
| 553 | sysfs_remove_group(&alt->dev.kobj, &dp_altmode_group); | 554 | sysfs_remove_group(&alt->dev.kobj, &dp_altmode_group); |
| 554 | cancel_work_sync(&dp->work); | 555 | cancel_work_sync(&dp->work); |
| 555 | } | 556 | } |
| 557 | EXPORT_SYMBOL_GPL(dp_altmode_remove); | ||
| 556 | 558 | ||
| 557 | static const struct typec_device_id dp_typec_id[] = { | 559 | static const struct typec_device_id dp_typec_id[] = { |
| 558 | { USB_TYPEC_DP_SID, USB_TYPEC_DP_MODE }, | 560 | { USB_TYPEC_DP_SID, USB_TYPEC_DP_MODE }, |
diff --git a/drivers/usb/typec/altmodes/displayport.h b/drivers/usb/typec/altmodes/displayport.h new file mode 100644 index 000000000000..e120364da9fd --- /dev/null +++ b/drivers/usb/typec/altmodes/displayport.h | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | #if IS_ENABLED(CONFIG_TYPEC_DP_ALTMODE) | ||
| 3 | int dp_altmode_probe(struct typec_altmode *alt); | ||
| 4 | void dp_altmode_remove(struct typec_altmode *alt); | ||
| 5 | #else | ||
| 6 | int dp_altmode_probe(struct typec_altmode *alt) { return -ENOTSUPP; } | ||
| 7 | void dp_altmode_remove(struct typec_altmode *alt) { } | ||
| 8 | #endif /* CONFIG_TYPEC_DP_ALTMODE */ | ||
diff --git a/drivers/usb/typec/altmodes/nvidia.c b/drivers/usb/typec/altmodes/nvidia.c new file mode 100644 index 000000000000..c36769736405 --- /dev/null +++ b/drivers/usb/typec/altmodes/nvidia.c | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * Copyright (C) 2019 NVIDIA Corporation. All rights reserved. | ||
| 4 | * | ||
| 5 | * NVIDIA USB Type-C Alt Mode Driver | ||
| 6 | */ | ||
| 7 | #include <linux/module.h> | ||
| 8 | #include <linux/usb/typec_altmode.h> | ||
| 9 | #include <linux/usb/typec_dp.h> | ||
| 10 | #include "displayport.h" | ||
| 11 | |||
| 12 | static int nvidia_altmode_probe(struct typec_altmode *alt) | ||
| 13 | { | ||
| 14 | if (alt->svid == USB_TYPEC_NVIDIA_VLINK_SID) | ||
| 15 | return dp_altmode_probe(alt); | ||
| 16 | else | ||
| 17 | return -ENOTSUPP; | ||
| 18 | } | ||
| 19 | |||
| 20 | static void nvidia_altmode_remove(struct typec_altmode *alt) | ||
| 21 | { | ||
| 22 | if (alt->svid == USB_TYPEC_NVIDIA_VLINK_SID) | ||
| 23 | dp_altmode_remove(alt); | ||
| 24 | } | ||
| 25 | |||
| 26 | static const struct typec_device_id nvidia_typec_id[] = { | ||
| 27 | { USB_TYPEC_NVIDIA_VLINK_SID, TYPEC_ANY_MODE }, | ||
| 28 | { }, | ||
| 29 | }; | ||
| 30 | MODULE_DEVICE_TABLE(typec, nvidia_typec_id); | ||
| 31 | |||
| 32 | static struct typec_altmode_driver nvidia_altmode_driver = { | ||
| 33 | .id_table = nvidia_typec_id, | ||
| 34 | .probe = nvidia_altmode_probe, | ||
| 35 | .remove = nvidia_altmode_remove, | ||
| 36 | .driver = { | ||
| 37 | .name = "typec_nvidia", | ||
| 38 | .owner = THIS_MODULE, | ||
| 39 | }, | ||
| 40 | }; | ||
| 41 | module_typec_altmode_driver(nvidia_altmode_driver); | ||
| 42 | |||
| 43 | MODULE_LICENSE("GPL v2"); | ||
| 44 | MODULE_DESCRIPTION("NVIDIA USB Type-C Alt Mode Driver"); | ||
diff --git a/drivers/usb/typec/mux/pi3usb30532.c b/drivers/usb/typec/mux/pi3usb30532.c index 64eb5983e17a..9294e85fd34b 100644 --- a/drivers/usb/typec/mux/pi3usb30532.c +++ b/drivers/usb/typec/mux/pi3usb30532.c | |||
| @@ -84,7 +84,8 @@ static int pi3usb30532_mux_set(struct typec_mux *mux, int state) | |||
| 84 | 84 | ||
| 85 | switch (state) { | 85 | switch (state) { |
| 86 | case TYPEC_STATE_SAFE: | 86 | case TYPEC_STATE_SAFE: |
| 87 | new_conf = PI3USB30532_CONF_OPEN; | 87 | new_conf = (new_conf & PI3USB30532_CONF_SWAP) | |
| 88 | PI3USB30532_CONF_OPEN; | ||
| 88 | break; | 89 | break; |
| 89 | case TYPEC_STATE_USB: | 90 | case TYPEC_STATE_USB: |
| 90 | new_conf = (new_conf & PI3USB30532_CONF_SWAP) | | 91 | new_conf = (new_conf & PI3USB30532_CONF_SWAP) | |
diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c index e9344997329c..7302f7501ec9 100644 --- a/drivers/usb/typec/tcpm/fusb302.c +++ b/drivers/usb/typec/tcpm/fusb302.c | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include <linux/sched/clock.h> | 23 | #include <linux/sched/clock.h> |
| 24 | #include <linux/seq_file.h> | 24 | #include <linux/seq_file.h> |
| 25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
| 26 | #include <linux/spinlock.h> | ||
| 26 | #include <linux/string.h> | 27 | #include <linux/string.h> |
| 27 | #include <linux/types.h> | 28 | #include <linux/types.h> |
| 28 | #include <linux/usb/typec.h> | 29 | #include <linux/usb/typec.h> |
| @@ -78,6 +79,10 @@ struct fusb302_chip { | |||
| 78 | 79 | ||
| 79 | struct regulator *vbus; | 80 | struct regulator *vbus; |
| 80 | 81 | ||
| 82 | spinlock_t irq_lock; | ||
| 83 | struct work_struct irq_work; | ||
| 84 | bool irq_suspended; | ||
| 85 | bool irq_while_suspended; | ||
| 81 | int gpio_int_n; | 86 | int gpio_int_n; |
| 82 | int gpio_int_n_irq; | 87 | int gpio_int_n_irq; |
| 83 | struct extcon_dev *extcon; | 88 | struct extcon_dev *extcon; |
| @@ -85,9 +90,6 @@ struct fusb302_chip { | |||
| 85 | struct workqueue_struct *wq; | 90 | struct workqueue_struct *wq; |
| 86 | struct delayed_work bc_lvl_handler; | 91 | struct delayed_work bc_lvl_handler; |
| 87 | 92 | ||
| 88 | atomic_t pm_suspend; | ||
| 89 | atomic_t i2c_busy; | ||
| 90 | |||
| 91 | /* lock for sharing chip states */ | 93 | /* lock for sharing chip states */ |
| 92 | struct mutex lock; | 94 | struct mutex lock; |
| 93 | 95 | ||
| @@ -99,7 +101,6 @@ struct fusb302_chip { | |||
| 99 | bool intr_comp_chng; | 101 | bool intr_comp_chng; |
| 100 | 102 | ||
| 101 | /* port status */ | 103 | /* port status */ |
| 102 | bool pull_up; | ||
| 103 | bool vconn_on; | 104 | bool vconn_on; |
| 104 | bool vbus_on; | 105 | bool vbus_on; |
| 105 | bool charge_on; | 106 | bool charge_on; |
| @@ -124,13 +125,13 @@ struct fusb302_chip { | |||
| 124 | */ | 125 | */ |
| 125 | 126 | ||
| 126 | #ifdef CONFIG_DEBUG_FS | 127 | #ifdef CONFIG_DEBUG_FS |
| 127 | |||
| 128 | static bool fusb302_log_full(struct fusb302_chip *chip) | 128 | static bool fusb302_log_full(struct fusb302_chip *chip) |
| 129 | { | 129 | { |
| 130 | return chip->logbuffer_tail == | 130 | return chip->logbuffer_tail == |
| 131 | (chip->logbuffer_head + 1) % LOG_BUFFER_ENTRIES; | 131 | (chip->logbuffer_head + 1) % LOG_BUFFER_ENTRIES; |
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | __printf(2, 0) | ||
| 134 | static void _fusb302_log(struct fusb302_chip *chip, const char *fmt, | 135 | static void _fusb302_log(struct fusb302_chip *chip, const char *fmt, |
| 135 | va_list args) | 136 | va_list args) |
| 136 | { | 137 | { |
| @@ -234,43 +235,15 @@ static void fusb302_debugfs_exit(const struct fusb302_chip *chip) { } | |||
| 234 | 235 | ||
| 235 | #endif | 236 | #endif |
| 236 | 237 | ||
| 237 | #define FUSB302_RESUME_RETRY 10 | ||
| 238 | #define FUSB302_RESUME_RETRY_SLEEP 50 | ||
| 239 | |||
| 240 | static bool fusb302_is_suspended(struct fusb302_chip *chip) | ||
| 241 | { | ||
| 242 | int retry_cnt; | ||
| 243 | |||
| 244 | for (retry_cnt = 0; retry_cnt < FUSB302_RESUME_RETRY; retry_cnt++) { | ||
| 245 | if (atomic_read(&chip->pm_suspend)) { | ||
| 246 | dev_err(chip->dev, "i2c: pm suspend, retry %d/%d\n", | ||
| 247 | retry_cnt + 1, FUSB302_RESUME_RETRY); | ||
| 248 | msleep(FUSB302_RESUME_RETRY_SLEEP); | ||
| 249 | } else { | ||
| 250 | return false; | ||
| 251 | } | ||
| 252 | } | ||
| 253 | |||
| 254 | return true; | ||
| 255 | } | ||
| 256 | |||
| 257 | static int fusb302_i2c_write(struct fusb302_chip *chip, | 238 | static int fusb302_i2c_write(struct fusb302_chip *chip, |
| 258 | u8 address, u8 data) | 239 | u8 address, u8 data) |
| 259 | { | 240 | { |
| 260 | int ret = 0; | 241 | int ret = 0; |
| 261 | 242 | ||
| 262 | atomic_set(&chip->i2c_busy, 1); | ||
| 263 | |||
| 264 | if (fusb302_is_suspended(chip)) { | ||
| 265 | atomic_set(&chip->i2c_busy, 0); | ||
| 266 | return -ETIMEDOUT; | ||
| 267 | } | ||
| 268 | |||
| 269 | ret = i2c_smbus_write_byte_data(chip->i2c_client, address, data); | 243 | ret = i2c_smbus_write_byte_data(chip->i2c_client, address, data); |
| 270 | if (ret < 0) | 244 | if (ret < 0) |
| 271 | fusb302_log(chip, "cannot write 0x%02x to 0x%02x, ret=%d", | 245 | fusb302_log(chip, "cannot write 0x%02x to 0x%02x, ret=%d", |
| 272 | data, address, ret); | 246 | data, address, ret); |
| 273 | atomic_set(&chip->i2c_busy, 0); | ||
| 274 | 247 | ||
| 275 | return ret; | 248 | return ret; |
| 276 | } | 249 | } |
| @@ -282,19 +255,12 @@ static int fusb302_i2c_block_write(struct fusb302_chip *chip, u8 address, | |||
| 282 | 255 | ||
| 283 | if (length <= 0) | 256 | if (length <= 0) |
| 284 | return ret; | 257 | return ret; |
| 285 | atomic_set(&chip->i2c_busy, 1); | ||
| 286 | |||
| 287 | if (fusb302_is_suspended(chip)) { | ||
| 288 | atomic_set(&chip->i2c_busy, 0); | ||
| 289 | return -ETIMEDOUT; | ||
| 290 | } | ||
| 291 | 258 | ||
| 292 | ret = i2c_smbus_write_i2c_block_data(chip->i2c_client, address, | 259 | ret = i2c_smbus_write_i2c_block_data(chip->i2c_client, address, |
| 293 | length, data); | 260 | length, data); |
| 294 | if (ret < 0) | 261 | if (ret < 0) |
| 295 | fusb302_log(chip, "cannot block write 0x%02x, len=%d, ret=%d", | 262 | fusb302_log(chip, "cannot block write 0x%02x, len=%d, ret=%d", |
| 296 | address, length, ret); | 263 | address, length, ret); |
| 297 | atomic_set(&chip->i2c_busy, 0); | ||
| 298 | 264 | ||
| 299 | return ret; | 265 | return ret; |
| 300 | } | 266 | } |
| @@ -304,18 +270,10 @@ static int fusb302_i2c_read(struct fusb302_chip *chip, | |||
| 304 | { | 270 | { |
| 305 | int ret = 0; | 271 | int ret = 0; |
| 306 | 272 | ||
| 307 | atomic_set(&chip->i2c_busy, 1); | ||
| 308 | |||
| 309 | if (fusb302_is_suspended(chip)) { | ||
| 310 | atomic_set(&chip->i2c_busy, 0); | ||
| 311 | return -ETIMEDOUT; | ||
| 312 | } | ||
| 313 | |||
| 314 | ret = i2c_smbus_read_byte_data(chip->i2c_client, address); | 273 | ret = i2c_smbus_read_byte_data(chip->i2c_client, address); |
| 315 | *data = (u8)ret; | 274 | *data = (u8)ret; |
| 316 | if (ret < 0) | 275 | if (ret < 0) |
| 317 | fusb302_log(chip, "cannot read %02x, ret=%d", address, ret); | 276 | fusb302_log(chip, "cannot read %02x, ret=%d", address, ret); |
| 318 | atomic_set(&chip->i2c_busy, 0); | ||
| 319 | 277 | ||
| 320 | return ret; | 278 | return ret; |
| 321 | } | 279 | } |
| @@ -327,12 +285,6 @@ static int fusb302_i2c_block_read(struct fusb302_chip *chip, u8 address, | |||
| 327 | 285 | ||
| 328 | if (length <= 0) | 286 | if (length <= 0) |
| 329 | return ret; | 287 | return ret; |
| 330 | atomic_set(&chip->i2c_busy, 1); | ||
| 331 | |||
| 332 | if (fusb302_is_suspended(chip)) { | ||
| 333 | atomic_set(&chip->i2c_busy, 0); | ||
| 334 | return -ETIMEDOUT; | ||
| 335 | } | ||
| 336 | 288 | ||
| 337 | ret = i2c_smbus_read_i2c_block_data(chip->i2c_client, address, | 289 | ret = i2c_smbus_read_i2c_block_data(chip->i2c_client, address, |
| 338 | length, data); | 290 | length, data); |
| @@ -348,8 +300,6 @@ static int fusb302_i2c_block_read(struct fusb302_chip *chip, u8 address, | |||
| 348 | } | 300 | } |
| 349 | 301 | ||
| 350 | done: | 302 | done: |
| 351 | atomic_set(&chip->i2c_busy, 0); | ||
| 352 | |||
| 353 | return ret; | 303 | return ret; |
| 354 | } | 304 | } |
| 355 | 305 | ||
| @@ -519,32 +469,6 @@ static int tcpm_get_current_limit(struct tcpc_dev *dev) | |||
| 519 | return current_limit; | 469 | return current_limit; |
| 520 | } | 470 | } |
| 521 | 471 | ||
| 522 | static int fusb302_set_cc_pull(struct fusb302_chip *chip, | ||
| 523 | bool pull_up, bool pull_down) | ||
| 524 | { | ||
| 525 | int ret = 0; | ||
| 526 | u8 data = 0x00; | ||
| 527 | u8 mask = FUSB_REG_SWITCHES0_CC1_PU_EN | | ||
| 528 | FUSB_REG_SWITCHES0_CC2_PU_EN | | ||
| 529 | FUSB_REG_SWITCHES0_CC1_PD_EN | | ||
| 530 | FUSB_REG_SWITCHES0_CC2_PD_EN; | ||
| 531 | |||
| 532 | if (pull_up) | ||
| 533 | data |= (chip->cc_polarity == TYPEC_POLARITY_CC1) ? | ||
| 534 | FUSB_REG_SWITCHES0_CC1_PU_EN : | ||
| 535 | FUSB_REG_SWITCHES0_CC2_PU_EN; | ||
| 536 | if (pull_down) | ||
| 537 | data |= FUSB_REG_SWITCHES0_CC1_PD_EN | | ||
| 538 | FUSB_REG_SWITCHES0_CC2_PD_EN; | ||
| 539 | ret = fusb302_i2c_mask_write(chip, FUSB_REG_SWITCHES0, | ||
| 540 | mask, data); | ||
| 541 | if (ret < 0) | ||
| 542 | return ret; | ||
| 543 | chip->pull_up = pull_up; | ||
| 544 | |||
| 545 | return ret; | ||
| 546 | } | ||
| 547 | |||
| 548 | static int fusb302_set_src_current(struct fusb302_chip *chip, | 472 | static int fusb302_set_src_current(struct fusb302_chip *chip, |
| 549 | enum src_current_status status) | 473 | enum src_current_status status) |
| 550 | { | 474 | { |
| @@ -634,6 +558,8 @@ static int fusb302_set_toggling(struct fusb302_chip *chip, | |||
| 634 | return ret; | 558 | return ret; |
| 635 | chip->intr_togdone = false; | 559 | chip->intr_togdone = false; |
| 636 | } else { | 560 | } else { |
| 561 | /* Datasheet says vconn MUST be off when toggling */ | ||
| 562 | WARN(chip->vconn_on, "Vconn is on during toggle start"); | ||
| 637 | /* unmask TOGDONE interrupt */ | 563 | /* unmask TOGDONE interrupt */ |
| 638 | ret = fusb302_i2c_clear_bits(chip, FUSB_REG_MASKA, | 564 | ret = fusb302_i2c_clear_bits(chip, FUSB_REG_MASKA, |
| 639 | FUSB_REG_MASKA_TOGDONE); | 565 | FUSB_REG_MASKA_TOGDONE); |
| @@ -676,26 +602,27 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum typec_cc_status cc) | |||
| 676 | { | 602 | { |
| 677 | struct fusb302_chip *chip = container_of(dev, struct fusb302_chip, | 603 | struct fusb302_chip *chip = container_of(dev, struct fusb302_chip, |
| 678 | tcpc_dev); | 604 | tcpc_dev); |
| 605 | u8 switches0_mask = FUSB_REG_SWITCHES0_CC1_PU_EN | | ||
| 606 | FUSB_REG_SWITCHES0_CC2_PU_EN | | ||
| 607 | FUSB_REG_SWITCHES0_CC1_PD_EN | | ||
| 608 | FUSB_REG_SWITCHES0_CC2_PD_EN; | ||
| 609 | u8 rd_mda, switches0_data = 0x00; | ||
| 679 | int ret = 0; | 610 | int ret = 0; |
| 680 | bool pull_up, pull_down; | ||
| 681 | u8 rd_mda; | ||
| 682 | enum toggling_mode mode; | ||
| 683 | 611 | ||
| 684 | mutex_lock(&chip->lock); | 612 | mutex_lock(&chip->lock); |
| 685 | switch (cc) { | 613 | switch (cc) { |
| 686 | case TYPEC_CC_OPEN: | 614 | case TYPEC_CC_OPEN: |
| 687 | pull_up = false; | ||
| 688 | pull_down = false; | ||
| 689 | break; | 615 | break; |
| 690 | case TYPEC_CC_RD: | 616 | case TYPEC_CC_RD: |
| 691 | pull_up = false; | 617 | switches0_data |= FUSB_REG_SWITCHES0_CC1_PD_EN | |
| 692 | pull_down = true; | 618 | FUSB_REG_SWITCHES0_CC2_PD_EN; |
| 693 | break; | 619 | break; |
| 694 | case TYPEC_CC_RP_DEF: | 620 | case TYPEC_CC_RP_DEF: |
| 695 | case TYPEC_CC_RP_1_5: | 621 | case TYPEC_CC_RP_1_5: |
| 696 | case TYPEC_CC_RP_3_0: | 622 | case TYPEC_CC_RP_3_0: |
| 697 | pull_up = true; | 623 | switches0_data |= (chip->cc_polarity == TYPEC_POLARITY_CC1) ? |
| 698 | pull_down = false; | 624 | FUSB_REG_SWITCHES0_CC1_PU_EN : |
| 625 | FUSB_REG_SWITCHES0_CC2_PU_EN; | ||
| 699 | break; | 626 | break; |
| 700 | default: | 627 | default: |
| 701 | fusb302_log(chip, "unsupported cc value %s", | 628 | fusb302_log(chip, "unsupported cc value %s", |
| @@ -703,34 +630,38 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum typec_cc_status cc) | |||
| 703 | ret = -EINVAL; | 630 | ret = -EINVAL; |
| 704 | goto done; | 631 | goto done; |
| 705 | } | 632 | } |
| 633 | |||
| 634 | fusb302_log(chip, "cc := %s", typec_cc_status_name[cc]); | ||
| 635 | |||
| 706 | ret = fusb302_set_toggling(chip, TOGGLING_MODE_OFF); | 636 | ret = fusb302_set_toggling(chip, TOGGLING_MODE_OFF); |
| 707 | if (ret < 0) { | 637 | if (ret < 0) { |
| 708 | fusb302_log(chip, "cannot stop toggling, ret=%d", ret); | 638 | fusb302_log(chip, "cannot set toggling mode, ret=%d", ret); |
| 709 | goto done; | 639 | goto done; |
| 710 | } | 640 | } |
| 711 | ret = fusb302_set_cc_pull(chip, pull_up, pull_down); | 641 | |
| 642 | ret = fusb302_i2c_mask_write(chip, FUSB_REG_SWITCHES0, | ||
| 643 | switches0_mask, switches0_data); | ||
| 712 | if (ret < 0) { | 644 | if (ret < 0) { |
| 713 | fusb302_log(chip, | 645 | fusb302_log(chip, "cannot set pull-up/-down, ret = %d", ret); |
| 714 | "cannot set cc pulling up %s, down %s, ret = %d", | ||
| 715 | pull_up ? "True" : "False", | ||
| 716 | pull_down ? "True" : "False", | ||
| 717 | ret); | ||
| 718 | goto done; | 646 | goto done; |
| 719 | } | 647 | } |
| 720 | /* reset the cc status */ | 648 | /* reset the cc status */ |
| 721 | chip->cc1 = TYPEC_CC_OPEN; | 649 | chip->cc1 = TYPEC_CC_OPEN; |
| 722 | chip->cc2 = TYPEC_CC_OPEN; | 650 | chip->cc2 = TYPEC_CC_OPEN; |
| 651 | |||
| 723 | /* adjust current for SRC */ | 652 | /* adjust current for SRC */ |
| 724 | if (pull_up) { | 653 | ret = fusb302_set_src_current(chip, cc_src_current[cc]); |
| 725 | ret = fusb302_set_src_current(chip, cc_src_current[cc]); | 654 | if (ret < 0) { |
| 726 | if (ret < 0) { | 655 | fusb302_log(chip, "cannot set src current %s, ret=%d", |
| 727 | fusb302_log(chip, "cannot set src current %s, ret=%d", | 656 | typec_cc_status_name[cc], ret); |
| 728 | typec_cc_status_name[cc], ret); | 657 | goto done; |
| 729 | goto done; | ||
| 730 | } | ||
| 731 | } | 658 | } |
| 659 | |||
| 732 | /* enable/disable interrupts, BC_LVL for SNK and COMP_CHNG for SRC */ | 660 | /* enable/disable interrupts, BC_LVL for SNK and COMP_CHNG for SRC */ |
| 733 | if (pull_up) { | 661 | switch (cc) { |
| 662 | case TYPEC_CC_RP_DEF: | ||
| 663 | case TYPEC_CC_RP_1_5: | ||
| 664 | case TYPEC_CC_RP_3_0: | ||
| 734 | rd_mda = rd_mda_value[cc_src_current[cc]]; | 665 | rd_mda = rd_mda_value[cc_src_current[cc]]; |
| 735 | ret = fusb302_i2c_write(chip, FUSB_REG_MEASURE, rd_mda); | 666 | ret = fusb302_i2c_write(chip, FUSB_REG_MEASURE, rd_mda); |
| 736 | if (ret < 0) { | 667 | if (ret < 0) { |
| @@ -748,10 +679,9 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum typec_cc_status cc) | |||
| 748 | ret); | 679 | ret); |
| 749 | goto done; | 680 | goto done; |
| 750 | } | 681 | } |
| 751 | chip->intr_bc_lvl = false; | ||
| 752 | chip->intr_comp_chng = true; | 682 | chip->intr_comp_chng = true; |
| 753 | } | 683 | break; |
| 754 | if (pull_down) { | 684 | case TYPEC_CC_RD: |
| 755 | ret = fusb302_i2c_mask_write(chip, FUSB_REG_MASK, | 685 | ret = fusb302_i2c_mask_write(chip, FUSB_REG_MASK, |
| 756 | FUSB_REG_MASK_BC_LVL | | 686 | FUSB_REG_MASK_BC_LVL | |
| 757 | FUSB_REG_MASK_COMP_CHNG, | 687 | FUSB_REG_MASK_COMP_CHNG, |
| @@ -762,32 +692,10 @@ static int tcpm_set_cc(struct tcpc_dev *dev, enum typec_cc_status cc) | |||
| 762 | goto done; | 692 | goto done; |
| 763 | } | 693 | } |
| 764 | chip->intr_bc_lvl = true; | 694 | chip->intr_bc_lvl = true; |
| 765 | chip->intr_comp_chng = false; | ||
| 766 | } | ||
| 767 | fusb302_log(chip, "cc := %s", typec_cc_status_name[cc]); | ||
| 768 | |||
| 769 | /* Enable detection for fixed SNK or SRC only roles */ | ||
| 770 | switch (cc) { | ||
| 771 | case TYPEC_CC_RD: | ||
| 772 | mode = TOGGLING_MODE_SNK; | ||
| 773 | break; | ||
| 774 | case TYPEC_CC_RP_DEF: | ||
| 775 | case TYPEC_CC_RP_1_5: | ||
| 776 | case TYPEC_CC_RP_3_0: | ||
| 777 | mode = TOGGLING_MODE_SRC; | ||
| 778 | break; | 695 | break; |
| 779 | default: | 696 | default: |
| 780 | mode = TOGGLING_MODE_OFF; | ||
| 781 | break; | 697 | break; |
| 782 | } | 698 | } |
| 783 | |||
| 784 | if (mode != TOGGLING_MODE_OFF) { | ||
| 785 | ret = fusb302_set_toggling(chip, mode); | ||
| 786 | if (ret < 0) | ||
| 787 | fusb302_log(chip, | ||
| 788 | "cannot set fixed role toggling mode, ret=%d", | ||
| 789 | ret); | ||
| 790 | } | ||
| 791 | done: | 699 | done: |
| 792 | mutex_unlock(&chip->lock); | 700 | mutex_unlock(&chip->lock); |
| 793 | 701 | ||
| @@ -1005,13 +913,27 @@ done: | |||
| 1005 | return ret; | 913 | return ret; |
| 1006 | } | 914 | } |
| 1007 | 915 | ||
| 1008 | static int tcpm_start_drp_toggling(struct tcpc_dev *dev, | 916 | static int tcpm_start_toggling(struct tcpc_dev *dev, |
| 1009 | enum typec_cc_status cc) | 917 | enum typec_port_type port_type, |
| 918 | enum typec_cc_status cc) | ||
| 1010 | { | 919 | { |
| 1011 | struct fusb302_chip *chip = container_of(dev, struct fusb302_chip, | 920 | struct fusb302_chip *chip = container_of(dev, struct fusb302_chip, |
| 1012 | tcpc_dev); | 921 | tcpc_dev); |
| 922 | enum toggling_mode mode = TOGGLING_MODE_OFF; | ||
| 1013 | int ret = 0; | 923 | int ret = 0; |
| 1014 | 924 | ||
| 925 | switch (port_type) { | ||
| 926 | case TYPEC_PORT_SRC: | ||
| 927 | mode = TOGGLING_MODE_SRC; | ||
| 928 | break; | ||
| 929 | case TYPEC_PORT_SNK: | ||
| 930 | mode = TOGGLING_MODE_SNK; | ||
| 931 | break; | ||
| 932 | case TYPEC_PORT_DRP: | ||
| 933 | mode = TOGGLING_MODE_DRP; | ||
| 934 | break; | ||
| 935 | } | ||
| 936 | |||
| 1015 | mutex_lock(&chip->lock); | 937 | mutex_lock(&chip->lock); |
| 1016 | ret = fusb302_set_src_current(chip, cc_src_current[cc]); | 938 | ret = fusb302_set_src_current(chip, cc_src_current[cc]); |
| 1017 | if (ret < 0) { | 939 | if (ret < 0) { |
| @@ -1019,7 +941,7 @@ static int tcpm_start_drp_toggling(struct tcpc_dev *dev, | |||
| 1019 | typec_cc_status_name[cc], ret); | 941 | typec_cc_status_name[cc], ret); |
| 1020 | goto done; | 942 | goto done; |
| 1021 | } | 943 | } |
| 1022 | ret = fusb302_set_toggling(chip, TOGGLING_MODE_DRP); | 944 | ret = fusb302_set_toggling(chip, mode); |
| 1023 | if (ret < 0) { | 945 | if (ret < 0) { |
| 1024 | fusb302_log(chip, | 946 | fusb302_log(chip, |
| 1025 | "unable to start drp toggling, ret=%d", ret); | 947 | "unable to start drp toggling, ret=%d", ret); |
| @@ -1217,7 +1139,7 @@ static void init_tcpc_dev(struct tcpc_dev *fusb302_tcpc_dev) | |||
| 1217 | fusb302_tcpc_dev->set_vbus = tcpm_set_vbus; | 1139 | fusb302_tcpc_dev->set_vbus = tcpm_set_vbus; |
| 1218 | fusb302_tcpc_dev->set_pd_rx = tcpm_set_pd_rx; | 1140 | fusb302_tcpc_dev->set_pd_rx = tcpm_set_pd_rx; |
| 1219 | fusb302_tcpc_dev->set_roles = tcpm_set_roles; | 1141 | fusb302_tcpc_dev->set_roles = tcpm_set_roles; |
| 1220 | fusb302_tcpc_dev->start_drp_toggling = tcpm_start_drp_toggling; | 1142 | fusb302_tcpc_dev->start_toggling = tcpm_start_toggling; |
| 1221 | fusb302_tcpc_dev->pd_transmit = tcpm_pd_transmit; | 1143 | fusb302_tcpc_dev->pd_transmit = tcpm_pd_transmit; |
| 1222 | } | 1144 | } |
| 1223 | 1145 | ||
| @@ -1226,38 +1148,36 @@ static const char * const cc_polarity_name[] = { | |||
| 1226 | [TYPEC_POLARITY_CC2] = "Polarity_CC2", | 1148 | [TYPEC_POLARITY_CC2] = "Polarity_CC2", |
| 1227 | }; | 1149 | }; |
| 1228 | 1150 | ||
| 1229 | static int fusb302_set_cc_polarity(struct fusb302_chip *chip, | 1151 | static int fusb302_set_cc_polarity_and_pull(struct fusb302_chip *chip, |
| 1230 | enum typec_cc_polarity cc_polarity) | 1152 | enum typec_cc_polarity cc_polarity, |
| 1153 | bool pull_up, bool pull_down) | ||
| 1231 | { | 1154 | { |
| 1232 | int ret = 0; | 1155 | int ret = 0; |
| 1233 | u8 switches0_mask = FUSB_REG_SWITCHES0_CC1_PU_EN | | ||
| 1234 | FUSB_REG_SWITCHES0_CC2_PU_EN | | ||
| 1235 | FUSB_REG_SWITCHES0_VCONN_CC1 | | ||
| 1236 | FUSB_REG_SWITCHES0_VCONN_CC2 | | ||
| 1237 | FUSB_REG_SWITCHES0_MEAS_CC1 | | ||
| 1238 | FUSB_REG_SWITCHES0_MEAS_CC2; | ||
| 1239 | u8 switches0_data = 0x00; | 1156 | u8 switches0_data = 0x00; |
| 1240 | u8 switches1_mask = FUSB_REG_SWITCHES1_TXCC1_EN | | 1157 | u8 switches1_mask = FUSB_REG_SWITCHES1_TXCC1_EN | |
| 1241 | FUSB_REG_SWITCHES1_TXCC2_EN; | 1158 | FUSB_REG_SWITCHES1_TXCC2_EN; |
| 1242 | u8 switches1_data = 0x00; | 1159 | u8 switches1_data = 0x00; |
| 1243 | 1160 | ||
| 1161 | if (pull_down) | ||
| 1162 | switches0_data |= FUSB_REG_SWITCHES0_CC1_PD_EN | | ||
| 1163 | FUSB_REG_SWITCHES0_CC2_PD_EN; | ||
| 1164 | |||
| 1244 | if (cc_polarity == TYPEC_POLARITY_CC1) { | 1165 | if (cc_polarity == TYPEC_POLARITY_CC1) { |
| 1245 | switches0_data = FUSB_REG_SWITCHES0_MEAS_CC1; | 1166 | switches0_data |= FUSB_REG_SWITCHES0_MEAS_CC1; |
| 1246 | if (chip->vconn_on) | 1167 | if (chip->vconn_on) |
| 1247 | switches0_data |= FUSB_REG_SWITCHES0_VCONN_CC2; | 1168 | switches0_data |= FUSB_REG_SWITCHES0_VCONN_CC2; |
| 1248 | if (chip->pull_up) | 1169 | if (pull_up) |
| 1249 | switches0_data |= FUSB_REG_SWITCHES0_CC1_PU_EN; | 1170 | switches0_data |= FUSB_REG_SWITCHES0_CC1_PU_EN; |
| 1250 | switches1_data = FUSB_REG_SWITCHES1_TXCC1_EN; | 1171 | switches1_data = FUSB_REG_SWITCHES1_TXCC1_EN; |
| 1251 | } else { | 1172 | } else { |
| 1252 | switches0_data = FUSB_REG_SWITCHES0_MEAS_CC2; | 1173 | switches0_data |= FUSB_REG_SWITCHES0_MEAS_CC2; |
| 1253 | if (chip->vconn_on) | 1174 | if (chip->vconn_on) |
| 1254 | switches0_data |= FUSB_REG_SWITCHES0_VCONN_CC1; | 1175 | switches0_data |= FUSB_REG_SWITCHES0_VCONN_CC1; |
| 1255 | if (chip->pull_up) | 1176 | if (pull_up) |
| 1256 | switches0_data |= FUSB_REG_SWITCHES0_CC2_PU_EN; | 1177 | switches0_data |= FUSB_REG_SWITCHES0_CC2_PU_EN; |
| 1257 | switches1_data = FUSB_REG_SWITCHES1_TXCC2_EN; | 1178 | switches1_data = FUSB_REG_SWITCHES1_TXCC2_EN; |
| 1258 | } | 1179 | } |
| 1259 | ret = fusb302_i2c_mask_write(chip, FUSB_REG_SWITCHES0, | 1180 | ret = fusb302_i2c_write(chip, FUSB_REG_SWITCHES0, switches0_data); |
| 1260 | switches0_mask, switches0_data); | ||
| 1261 | if (ret < 0) | 1181 | if (ret < 0) |
| 1262 | return ret; | 1182 | return ret; |
| 1263 | ret = fusb302_i2c_mask_write(chip, FUSB_REG_SWITCHES1, | 1183 | ret = fusb302_i2c_mask_write(chip, FUSB_REG_SWITCHES1, |
| @@ -1278,16 +1198,10 @@ static int fusb302_handle_togdone_snk(struct fusb302_chip *chip, | |||
| 1278 | enum typec_cc_polarity cc_polarity; | 1198 | enum typec_cc_polarity cc_polarity; |
| 1279 | enum typec_cc_status cc_status_active, cc1, cc2; | 1199 | enum typec_cc_status cc_status_active, cc1, cc2; |
| 1280 | 1200 | ||
| 1281 | /* set pull_up, pull_down */ | 1201 | /* set polarity and pull_up, pull_down */ |
| 1282 | ret = fusb302_set_cc_pull(chip, false, true); | ||
| 1283 | if (ret < 0) { | ||
| 1284 | fusb302_log(chip, "cannot set cc to pull down, ret=%d", ret); | ||
| 1285 | return ret; | ||
| 1286 | } | ||
| 1287 | /* set polarity */ | ||
| 1288 | cc_polarity = (togdone_result == FUSB_REG_STATUS1A_TOGSS_SNK1) ? | 1202 | cc_polarity = (togdone_result == FUSB_REG_STATUS1A_TOGSS_SNK1) ? |
| 1289 | TYPEC_POLARITY_CC1 : TYPEC_POLARITY_CC2; | 1203 | TYPEC_POLARITY_CC1 : TYPEC_POLARITY_CC2; |
| 1290 | ret = fusb302_set_cc_polarity(chip, cc_polarity); | 1204 | ret = fusb302_set_cc_polarity_and_pull(chip, cc_polarity, false, true); |
| 1291 | if (ret < 0) { | 1205 | if (ret < 0) { |
| 1292 | fusb302_log(chip, "cannot set cc polarity %s, ret=%d", | 1206 | fusb302_log(chip, "cannot set cc polarity %s, ret=%d", |
| 1293 | cc_polarity_name[cc_polarity], ret); | 1207 | cc_polarity_name[cc_polarity], ret); |
| @@ -1337,6 +1251,62 @@ static int fusb302_handle_togdone_snk(struct fusb302_chip *chip, | |||
| 1337 | return ret; | 1251 | return ret; |
| 1338 | } | 1252 | } |
| 1339 | 1253 | ||
| 1254 | /* On error returns < 0, otherwise a typec_cc_status value */ | ||
| 1255 | static int fusb302_get_src_cc_status(struct fusb302_chip *chip, | ||
| 1256 | enum typec_cc_polarity cc_polarity, | ||
| 1257 | enum typec_cc_status *cc) | ||
| 1258 | { | ||
| 1259 | u8 ra_mda = ra_mda_value[chip->src_current_status]; | ||
| 1260 | u8 rd_mda = rd_mda_value[chip->src_current_status]; | ||
| 1261 | u8 switches0_data, status0; | ||
| 1262 | int ret; | ||
| 1263 | |||
| 1264 | /* Step 1: Set switches so that we measure the right CC pin */ | ||
| 1265 | switches0_data = (cc_polarity == TYPEC_POLARITY_CC1) ? | ||
| 1266 | FUSB_REG_SWITCHES0_CC1_PU_EN | FUSB_REG_SWITCHES0_MEAS_CC1 : | ||
| 1267 | FUSB_REG_SWITCHES0_CC2_PU_EN | FUSB_REG_SWITCHES0_MEAS_CC2; | ||
| 1268 | ret = fusb302_i2c_write(chip, FUSB_REG_SWITCHES0, switches0_data); | ||
| 1269 | if (ret < 0) | ||
| 1270 | return ret; | ||
| 1271 | |||
| 1272 | fusb302_i2c_read(chip, FUSB_REG_SWITCHES0, &status0); | ||
| 1273 | fusb302_log(chip, "get_src_cc_status switches: 0x%0x", status0); | ||
| 1274 | |||
| 1275 | /* Step 2: Set compararator volt to differentiate between Open and Rd */ | ||
| 1276 | ret = fusb302_i2c_write(chip, FUSB_REG_MEASURE, rd_mda); | ||
| 1277 | if (ret < 0) | ||
| 1278 | return ret; | ||
| 1279 | |||
| 1280 | usleep_range(50, 100); | ||
| 1281 | ret = fusb302_i2c_read(chip, FUSB_REG_STATUS0, &status0); | ||
| 1282 | if (ret < 0) | ||
| 1283 | return ret; | ||
| 1284 | |||
| 1285 | fusb302_log(chip, "get_src_cc_status rd_mda status0: 0x%0x", status0); | ||
| 1286 | if (status0 & FUSB_REG_STATUS0_COMP) { | ||
| 1287 | *cc = TYPEC_CC_OPEN; | ||
| 1288 | return 0; | ||
| 1289 | } | ||
| 1290 | |||
| 1291 | /* Step 3: Set compararator input to differentiate between Rd and Ra. */ | ||
| 1292 | ret = fusb302_i2c_write(chip, FUSB_REG_MEASURE, ra_mda); | ||
| 1293 | if (ret < 0) | ||
| 1294 | return ret; | ||
| 1295 | |||
| 1296 | usleep_range(50, 100); | ||
| 1297 | ret = fusb302_i2c_read(chip, FUSB_REG_STATUS0, &status0); | ||
| 1298 | if (ret < 0) | ||
| 1299 | return ret; | ||
| 1300 | |||
| 1301 | fusb302_log(chip, "get_src_cc_status ra_mda status0: 0x%0x", status0); | ||
| 1302 | if (status0 & FUSB_REG_STATUS0_COMP) | ||
| 1303 | *cc = TYPEC_CC_RD; | ||
| 1304 | else | ||
| 1305 | *cc = TYPEC_CC_RA; | ||
| 1306 | |||
| 1307 | return 0; | ||
| 1308 | } | ||
| 1309 | |||
| 1340 | static int fusb302_handle_togdone_src(struct fusb302_chip *chip, | 1310 | static int fusb302_handle_togdone_src(struct fusb302_chip *chip, |
| 1341 | u8 togdone_result) | 1311 | u8 togdone_result) |
| 1342 | { | 1312 | { |
| @@ -1347,77 +1317,62 @@ static int fusb302_handle_togdone_src(struct fusb302_chip *chip, | |||
| 1347 | * - set I_COMP interrupt on | 1317 | * - set I_COMP interrupt on |
| 1348 | */ | 1318 | */ |
| 1349 | int ret = 0; | 1319 | int ret = 0; |
| 1350 | u8 status0; | ||
| 1351 | u8 ra_mda = ra_mda_value[chip->src_current_status]; | ||
| 1352 | u8 rd_mda = rd_mda_value[chip->src_current_status]; | 1320 | u8 rd_mda = rd_mda_value[chip->src_current_status]; |
| 1353 | bool ra_comp, rd_comp; | 1321 | enum toggling_mode toggling_mode = chip->toggling_mode; |
| 1354 | enum typec_cc_polarity cc_polarity; | 1322 | enum typec_cc_polarity cc_polarity; |
| 1355 | enum typec_cc_status cc_status_active, cc1, cc2; | 1323 | enum typec_cc_status cc1, cc2; |
| 1356 | 1324 | ||
| 1357 | /* set pull_up, pull_down */ | 1325 | /* |
| 1358 | ret = fusb302_set_cc_pull(chip, true, false); | 1326 | * The toggle-engine will stop in a src state if it sees either Ra or |
| 1359 | if (ret < 0) { | 1327 | * Rd. Determine the status for both CC pins, starting with the one |
| 1360 | fusb302_log(chip, "cannot set cc to pull up, ret=%d", ret); | 1328 | * where toggling stopped, as that is where the switches point now. |
| 1329 | */ | ||
| 1330 | if (togdone_result == FUSB_REG_STATUS1A_TOGSS_SRC1) | ||
| 1331 | ret = fusb302_get_src_cc_status(chip, TYPEC_POLARITY_CC1, &cc1); | ||
| 1332 | else | ||
| 1333 | ret = fusb302_get_src_cc_status(chip, TYPEC_POLARITY_CC2, &cc2); | ||
| 1334 | if (ret < 0) | ||
| 1361 | return ret; | 1335 | return ret; |
| 1362 | } | 1336 | /* we must turn off toggling before we can measure the other pin */ |
| 1363 | /* set polarity */ | 1337 | ret = fusb302_set_toggling(chip, TOGGLING_MODE_OFF); |
| 1364 | cc_polarity = (togdone_result == FUSB_REG_STATUS1A_TOGSS_SRC1) ? | ||
| 1365 | TYPEC_POLARITY_CC1 : TYPEC_POLARITY_CC2; | ||
| 1366 | ret = fusb302_set_cc_polarity(chip, cc_polarity); | ||
| 1367 | if (ret < 0) { | 1338 | if (ret < 0) { |
| 1368 | fusb302_log(chip, "cannot set cc polarity %s, ret=%d", | 1339 | fusb302_log(chip, "cannot set toggling mode off, ret=%d", ret); |
| 1369 | cc_polarity_name[cc_polarity], ret); | ||
| 1370 | return ret; | 1340 | return ret; |
| 1371 | } | 1341 | } |
| 1372 | /* fusb302_set_cc_polarity() has set the correct measure block */ | 1342 | /* get the status of the other pin */ |
| 1373 | ret = fusb302_i2c_write(chip, FUSB_REG_MEASURE, rd_mda); | 1343 | if (togdone_result == FUSB_REG_STATUS1A_TOGSS_SRC1) |
| 1374 | if (ret < 0) | 1344 | ret = fusb302_get_src_cc_status(chip, TYPEC_POLARITY_CC2, &cc2); |
| 1375 | return ret; | 1345 | else |
| 1376 | usleep_range(50, 100); | 1346 | ret = fusb302_get_src_cc_status(chip, TYPEC_POLARITY_CC1, &cc1); |
| 1377 | ret = fusb302_i2c_read(chip, FUSB_REG_STATUS0, &status0); | ||
| 1378 | if (ret < 0) | 1347 | if (ret < 0) |
| 1379 | return ret; | 1348 | return ret; |
| 1380 | rd_comp = !!(status0 & FUSB_REG_STATUS0_COMP); | 1349 | |
| 1381 | if (!rd_comp) { | 1350 | /* determine polarity based on the status of both pins */ |
| 1382 | ret = fusb302_i2c_write(chip, FUSB_REG_MEASURE, ra_mda); | 1351 | if (cc1 == TYPEC_CC_RD && |
| 1383 | if (ret < 0) | 1352 | (cc2 == TYPEC_CC_OPEN || cc2 == TYPEC_CC_RA)) { |
| 1384 | return ret; | 1353 | cc_polarity = TYPEC_POLARITY_CC1; |
| 1385 | usleep_range(50, 100); | 1354 | } else if (cc2 == TYPEC_CC_RD && |
| 1386 | ret = fusb302_i2c_read(chip, FUSB_REG_STATUS0, &status0); | 1355 | (cc1 == TYPEC_CC_OPEN || cc1 == TYPEC_CC_RA)) { |
| 1387 | if (ret < 0) | 1356 | cc_polarity = TYPEC_POLARITY_CC2; |
| 1388 | return ret; | 1357 | } else { |
| 1389 | ra_comp = !!(status0 & FUSB_REG_STATUS0_COMP); | 1358 | fusb302_log(chip, "unexpected CC status cc1=%s, cc2=%s, restarting toggling", |
| 1359 | typec_cc_status_name[cc1], | ||
| 1360 | typec_cc_status_name[cc2]); | ||
| 1361 | return fusb302_set_toggling(chip, toggling_mode); | ||
| 1390 | } | 1362 | } |
| 1391 | if (rd_comp) | 1363 | /* set polarity and pull_up, pull_down */ |
| 1392 | cc_status_active = TYPEC_CC_OPEN; | 1364 | ret = fusb302_set_cc_polarity_and_pull(chip, cc_polarity, true, false); |
| 1393 | else if (ra_comp) | 1365 | if (ret < 0) { |
| 1394 | cc_status_active = TYPEC_CC_RD; | 1366 | fusb302_log(chip, "cannot set cc polarity %s, ret=%d", |
| 1395 | else | 1367 | cc_polarity_name[cc_polarity], ret); |
| 1396 | /* Ra is not supported, report as Open */ | ||
| 1397 | cc_status_active = TYPEC_CC_OPEN; | ||
| 1398 | /* restart toggling if the cc status on the active line is OPEN */ | ||
| 1399 | if (cc_status_active == TYPEC_CC_OPEN) { | ||
| 1400 | fusb302_log(chip, "restart toggling as CC_OPEN detected"); | ||
| 1401 | ret = fusb302_set_toggling(chip, chip->toggling_mode); | ||
| 1402 | return ret; | 1368 | return ret; |
| 1403 | } | 1369 | } |
| 1404 | /* update tcpm with the new cc value */ | 1370 | /* update tcpm with the new cc value */ |
| 1405 | cc1 = (cc_polarity == TYPEC_POLARITY_CC1) ? | ||
| 1406 | cc_status_active : TYPEC_CC_OPEN; | ||
| 1407 | cc2 = (cc_polarity == TYPEC_POLARITY_CC2) ? | ||
| 1408 | cc_status_active : TYPEC_CC_OPEN; | ||
| 1409 | if ((chip->cc1 != cc1) || (chip->cc2 != cc2)) { | 1371 | if ((chip->cc1 != cc1) || (chip->cc2 != cc2)) { |
| 1410 | chip->cc1 = cc1; | 1372 | chip->cc1 = cc1; |
| 1411 | chip->cc2 = cc2; | 1373 | chip->cc2 = cc2; |
| 1412 | tcpm_cc_change(chip->tcpm_port); | 1374 | tcpm_cc_change(chip->tcpm_port); |
| 1413 | } | 1375 | } |
| 1414 | /* turn off toggling */ | ||
| 1415 | ret = fusb302_set_toggling(chip, TOGGLING_MODE_OFF); | ||
| 1416 | if (ret < 0) { | ||
| 1417 | fusb302_log(chip, | ||
| 1418 | "cannot set toggling mode off, ret=%d", ret); | ||
| 1419 | return ret; | ||
| 1420 | } | ||
| 1421 | /* set MDAC to Rd threshold, and unmask I_COMP for unplug detection */ | 1376 | /* set MDAC to Rd threshold, and unmask I_COMP for unplug detection */ |
| 1422 | ret = fusb302_i2c_write(chip, FUSB_REG_MEASURE, rd_mda); | 1377 | ret = fusb302_i2c_write(chip, FUSB_REG_MEASURE, rd_mda); |
| 1423 | if (ret < 0) | 1378 | if (ret < 0) |
| @@ -1427,7 +1382,7 @@ static int fusb302_handle_togdone_src(struct fusb302_chip *chip, | |||
| 1427 | FUSB_REG_MASK_COMP_CHNG); | 1382 | FUSB_REG_MASK_COMP_CHNG); |
| 1428 | if (ret < 0) { | 1383 | if (ret < 0) { |
| 1429 | fusb302_log(chip, | 1384 | fusb302_log(chip, |
| 1430 | "cannot unmask bc_lcl interrupt, ret=%d", ret); | 1385 | "cannot unmask comp_chng interrupt, ret=%d", ret); |
| 1431 | return ret; | 1386 | return ret; |
| 1432 | } | 1387 | } |
| 1433 | chip->intr_comp_chng = true; | 1388 | chip->intr_comp_chng = true; |
| @@ -1532,6 +1487,25 @@ static int fusb302_pd_read_message(struct fusb302_chip *chip, | |||
| 1532 | static irqreturn_t fusb302_irq_intn(int irq, void *dev_id) | 1487 | static irqreturn_t fusb302_irq_intn(int irq, void *dev_id) |
| 1533 | { | 1488 | { |
| 1534 | struct fusb302_chip *chip = dev_id; | 1489 | struct fusb302_chip *chip = dev_id; |
| 1490 | unsigned long flags; | ||
| 1491 | |||
| 1492 | /* Disable our level triggered IRQ until our irq_work has cleared it */ | ||
| 1493 | disable_irq_nosync(chip->gpio_int_n_irq); | ||
| 1494 | |||
| 1495 | spin_lock_irqsave(&chip->irq_lock, flags); | ||
| 1496 | if (chip->irq_suspended) | ||
| 1497 | chip->irq_while_suspended = true; | ||
| 1498 | else | ||
| 1499 | schedule_work(&chip->irq_work); | ||
| 1500 | spin_unlock_irqrestore(&chip->irq_lock, flags); | ||
| 1501 | |||
| 1502 | return IRQ_HANDLED; | ||
| 1503 | } | ||
| 1504 | |||
| 1505 | static void fusb302_irq_work(struct work_struct *work) | ||
| 1506 | { | ||
| 1507 | struct fusb302_chip *chip = container_of(work, struct fusb302_chip, | ||
| 1508 | irq_work); | ||
| 1535 | int ret = 0; | 1509 | int ret = 0; |
| 1536 | u8 interrupt; | 1510 | u8 interrupt; |
| 1537 | u8 interrupta; | 1511 | u8 interrupta; |
| @@ -1602,11 +1576,9 @@ static irqreturn_t fusb302_irq_intn(int irq, void *dev_id) | |||
| 1602 | fusb302_log(chip, "IRQ: COMP_CHNG, comp=%s", | 1576 | fusb302_log(chip, "IRQ: COMP_CHNG, comp=%s", |
| 1603 | comp_result ? "true" : "false"); | 1577 | comp_result ? "true" : "false"); |
| 1604 | if (comp_result) { | 1578 | if (comp_result) { |
| 1605 | /* cc level > Rd_threashold, detach */ | 1579 | /* cc level > Rd_threshold, detach */ |
| 1606 | if (chip->cc_polarity == TYPEC_POLARITY_CC1) | 1580 | chip->cc1 = TYPEC_CC_OPEN; |
| 1607 | chip->cc1 = TYPEC_CC_OPEN; | 1581 | chip->cc2 = TYPEC_CC_OPEN; |
| 1608 | else | ||
| 1609 | chip->cc2 = TYPEC_CC_OPEN; | ||
| 1610 | tcpm_cc_change(chip->tcpm_port); | 1582 | tcpm_cc_change(chip->tcpm_port); |
| 1611 | } | 1583 | } |
| 1612 | } | 1584 | } |
| @@ -1662,8 +1634,7 @@ static irqreturn_t fusb302_irq_intn(int irq, void *dev_id) | |||
| 1662 | } | 1634 | } |
| 1663 | done: | 1635 | done: |
| 1664 | mutex_unlock(&chip->lock); | 1636 | mutex_unlock(&chip->lock); |
| 1665 | 1637 | enable_irq(chip->gpio_int_n_irq); | |
| 1666 | return IRQ_HANDLED; | ||
| 1667 | } | 1638 | } |
| 1668 | 1639 | ||
| 1669 | static int init_gpio(struct fusb302_chip *chip) | 1640 | static int init_gpio(struct fusb302_chip *chip) |
| @@ -1779,6 +1750,8 @@ static int fusb302_probe(struct i2c_client *client, | |||
| 1779 | if (!chip->wq) | 1750 | if (!chip->wq) |
| 1780 | return -ENOMEM; | 1751 | return -ENOMEM; |
| 1781 | 1752 | ||
| 1753 | spin_lock_init(&chip->irq_lock); | ||
| 1754 | INIT_WORK(&chip->irq_work, fusb302_irq_work); | ||
| 1782 | INIT_DELAYED_WORK(&chip->bc_lvl_handler, fusb302_bc_lvl_handler_work); | 1755 | INIT_DELAYED_WORK(&chip->bc_lvl_handler, fusb302_bc_lvl_handler_work); |
| 1783 | init_tcpc_dev(&chip->tcpc_dev); | 1756 | init_tcpc_dev(&chip->tcpc_dev); |
| 1784 | 1757 | ||
| @@ -1798,10 +1771,9 @@ static int fusb302_probe(struct i2c_client *client, | |||
| 1798 | goto destroy_workqueue; | 1771 | goto destroy_workqueue; |
| 1799 | } | 1772 | } |
| 1800 | 1773 | ||
| 1801 | ret = devm_request_threaded_irq(chip->dev, chip->gpio_int_n_irq, | 1774 | ret = request_irq(chip->gpio_int_n_irq, fusb302_irq_intn, |
| 1802 | NULL, fusb302_irq_intn, | 1775 | IRQF_ONESHOT | IRQF_TRIGGER_LOW, |
| 1803 | IRQF_ONESHOT | IRQF_TRIGGER_LOW, | 1776 | "fsc_interrupt_int_n", chip); |
| 1804 | "fsc_interrupt_int_n", chip); | ||
| 1805 | if (ret < 0) { | 1777 | if (ret < 0) { |
| 1806 | dev_err(dev, "cannot request IRQ for GPIO Int_N, ret=%d", ret); | 1778 | dev_err(dev, "cannot request IRQ for GPIO Int_N, ret=%d", ret); |
| 1807 | goto tcpm_unregister_port; | 1779 | goto tcpm_unregister_port; |
| @@ -1824,6 +1796,10 @@ static int fusb302_remove(struct i2c_client *client) | |||
| 1824 | { | 1796 | { |
| 1825 | struct fusb302_chip *chip = i2c_get_clientdata(client); | 1797 | struct fusb302_chip *chip = i2c_get_clientdata(client); |
| 1826 | 1798 | ||
| 1799 | disable_irq_wake(chip->gpio_int_n_irq); | ||
| 1800 | free_irq(chip->gpio_int_n_irq, chip); | ||
| 1801 | cancel_work_sync(&chip->irq_work); | ||
| 1802 | cancel_delayed_work_sync(&chip->bc_lvl_handler); | ||
| 1827 | tcpm_unregister_port(chip->tcpm_port); | 1803 | tcpm_unregister_port(chip->tcpm_port); |
| 1828 | destroy_workqueue(chip->wq); | 1804 | destroy_workqueue(chip->wq); |
| 1829 | fusb302_debugfs_exit(chip); | 1805 | fusb302_debugfs_exit(chip); |
| @@ -1834,19 +1810,29 @@ static int fusb302_remove(struct i2c_client *client) | |||
| 1834 | static int fusb302_pm_suspend(struct device *dev) | 1810 | static int fusb302_pm_suspend(struct device *dev) |
| 1835 | { | 1811 | { |
| 1836 | struct fusb302_chip *chip = dev->driver_data; | 1812 | struct fusb302_chip *chip = dev->driver_data; |
| 1813 | unsigned long flags; | ||
| 1837 | 1814 | ||
| 1838 | if (atomic_read(&chip->i2c_busy)) | 1815 | spin_lock_irqsave(&chip->irq_lock, flags); |
| 1839 | return -EBUSY; | 1816 | chip->irq_suspended = true; |
| 1840 | atomic_set(&chip->pm_suspend, 1); | 1817 | spin_unlock_irqrestore(&chip->irq_lock, flags); |
| 1841 | 1818 | ||
| 1819 | /* Make sure any pending irq_work is finished before the bus suspends */ | ||
| 1820 | flush_work(&chip->irq_work); | ||
| 1842 | return 0; | 1821 | return 0; |
| 1843 | } | 1822 | } |
| 1844 | 1823 | ||
| 1845 | static int fusb302_pm_resume(struct device *dev) | 1824 | static int fusb302_pm_resume(struct device *dev) |
| 1846 | { | 1825 | { |
| 1847 | struct fusb302_chip *chip = dev->driver_data; | 1826 | struct fusb302_chip *chip = dev->driver_data; |
| 1827 | unsigned long flags; | ||
| 1848 | 1828 | ||
| 1849 | atomic_set(&chip->pm_suspend, 0); | 1829 | spin_lock_irqsave(&chip->irq_lock, flags); |
| 1830 | if (chip->irq_while_suspended) { | ||
| 1831 | schedule_work(&chip->irq_work); | ||
| 1832 | chip->irq_while_suspended = false; | ||
| 1833 | } | ||
| 1834 | chip->irq_suspended = false; | ||
| 1835 | spin_unlock_irqrestore(&chip->irq_lock, flags); | ||
| 1850 | 1836 | ||
| 1851 | return 0; | 1837 | return 0; |
| 1852 | } | 1838 | } |
diff --git a/drivers/usb/typec/tcpm/tcpci.c b/drivers/usb/typec/tcpm/tcpci.c index ac6b418b15f1..c1f7073a56de 100644 --- a/drivers/usb/typec/tcpm/tcpci.c +++ b/drivers/usb/typec/tcpm/tcpci.c | |||
| @@ -100,13 +100,17 @@ static int tcpci_set_cc(struct tcpc_dev *tcpc, enum typec_cc_status cc) | |||
| 100 | return 0; | 100 | return 0; |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | static int tcpci_start_drp_toggling(struct tcpc_dev *tcpc, | 103 | static int tcpci_start_toggling(struct tcpc_dev *tcpc, |
| 104 | enum typec_cc_status cc) | 104 | enum typec_port_type port_type, |
| 105 | enum typec_cc_status cc) | ||
| 105 | { | 106 | { |
| 106 | int ret; | 107 | int ret; |
| 107 | struct tcpci *tcpci = tcpc_to_tcpci(tcpc); | 108 | struct tcpci *tcpci = tcpc_to_tcpci(tcpc); |
| 108 | unsigned int reg = TCPC_ROLE_CTRL_DRP; | 109 | unsigned int reg = TCPC_ROLE_CTRL_DRP; |
| 109 | 110 | ||
| 111 | if (port_type != TYPEC_PORT_DRP) | ||
| 112 | return -EOPNOTSUPP; | ||
| 113 | |||
| 110 | /* Handle vendor drp toggling */ | 114 | /* Handle vendor drp toggling */ |
| 111 | if (tcpci->data->start_drp_toggling) { | 115 | if (tcpci->data->start_drp_toggling) { |
| 112 | ret = tcpci->data->start_drp_toggling(tcpci, tcpci->data, cc); | 116 | ret = tcpci->data->start_drp_toggling(tcpci, tcpci->data, cc); |
| @@ -511,7 +515,7 @@ struct tcpci *tcpci_register_port(struct device *dev, struct tcpci_data *data) | |||
| 511 | tcpci->tcpc.get_cc = tcpci_get_cc; | 515 | tcpci->tcpc.get_cc = tcpci_get_cc; |
| 512 | tcpci->tcpc.set_polarity = tcpci_set_polarity; | 516 | tcpci->tcpc.set_polarity = tcpci_set_polarity; |
| 513 | tcpci->tcpc.set_vconn = tcpci_set_vconn; | 517 | tcpci->tcpc.set_vconn = tcpci_set_vconn; |
| 514 | tcpci->tcpc.start_drp_toggling = tcpci_start_drp_toggling; | 518 | tcpci->tcpc.start_toggling = tcpci_start_toggling; |
| 515 | 519 | ||
| 516 | tcpci->tcpc.set_pd_rx = tcpci_set_pd_rx; | 520 | tcpci->tcpc.set_pd_rx = tcpci_set_pd_rx; |
| 517 | tcpci->tcpc.set_roles = tcpci_set_roles; | 521 | tcpci->tcpc.set_roles = tcpci_set_roles; |
diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index a2233d72ae7c..fba32d84e578 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c | |||
| @@ -31,7 +31,7 @@ | |||
| 31 | 31 | ||
| 32 | #define FOREACH_STATE(S) \ | 32 | #define FOREACH_STATE(S) \ |
| 33 | S(INVALID_STATE), \ | 33 | S(INVALID_STATE), \ |
| 34 | S(DRP_TOGGLING), \ | 34 | S(TOGGLING), \ |
| 35 | S(SRC_UNATTACHED), \ | 35 | S(SRC_UNATTACHED), \ |
| 36 | S(SRC_ATTACH_WAIT), \ | 36 | S(SRC_ATTACH_WAIT), \ |
| 37 | S(SRC_ATTACHED), \ | 37 | S(SRC_ATTACHED), \ |
| @@ -472,7 +472,7 @@ static void tcpm_log(struct tcpm_port *port, const char *fmt, ...) | |||
| 472 | /* Do not log while disconnected and unattached */ | 472 | /* Do not log while disconnected and unattached */ |
| 473 | if (tcpm_port_is_disconnected(port) && | 473 | if (tcpm_port_is_disconnected(port) && |
| 474 | (port->state == SRC_UNATTACHED || port->state == SNK_UNATTACHED || | 474 | (port->state == SRC_UNATTACHED || port->state == SNK_UNATTACHED || |
| 475 | port->state == DRP_TOGGLING)) | 475 | port->state == TOGGLING)) |
| 476 | return; | 476 | return; |
| 477 | 477 | ||
| 478 | va_start(args, fmt); | 478 | va_start(args, fmt); |
| @@ -2540,20 +2540,16 @@ static int tcpm_set_charge(struct tcpm_port *port, bool charge) | |||
| 2540 | return 0; | 2540 | return 0; |
| 2541 | } | 2541 | } |
| 2542 | 2542 | ||
| 2543 | static bool tcpm_start_drp_toggling(struct tcpm_port *port, | 2543 | static bool tcpm_start_toggling(struct tcpm_port *port, enum typec_cc_status cc) |
| 2544 | enum typec_cc_status cc) | ||
| 2545 | { | 2544 | { |
| 2546 | int ret; | 2545 | int ret; |
| 2547 | 2546 | ||
| 2548 | if (port->tcpc->start_drp_toggling && | 2547 | if (!port->tcpc->start_toggling) |
| 2549 | port->port_type == TYPEC_PORT_DRP) { | 2548 | return false; |
| 2550 | tcpm_log_force(port, "Start DRP toggling"); | ||
| 2551 | ret = port->tcpc->start_drp_toggling(port->tcpc, cc); | ||
| 2552 | if (!ret) | ||
| 2553 | return true; | ||
| 2554 | } | ||
| 2555 | 2549 | ||
| 2556 | return false; | 2550 | tcpm_log_force(port, "Start toggling"); |
| 2551 | ret = port->tcpc->start_toggling(port->tcpc, port->port_type, cc); | ||
| 2552 | return ret == 0; | ||
| 2557 | } | 2553 | } |
| 2558 | 2554 | ||
| 2559 | static void tcpm_set_cc(struct tcpm_port *port, enum typec_cc_status cc) | 2555 | static void tcpm_set_cc(struct tcpm_port *port, enum typec_cc_status cc) |
| @@ -2847,15 +2843,15 @@ static void run_state_machine(struct tcpm_port *port) | |||
| 2847 | 2843 | ||
| 2848 | port->enter_state = port->state; | 2844 | port->enter_state = port->state; |
| 2849 | switch (port->state) { | 2845 | switch (port->state) { |
| 2850 | case DRP_TOGGLING: | 2846 | case TOGGLING: |
| 2851 | break; | 2847 | break; |
| 2852 | /* SRC states */ | 2848 | /* SRC states */ |
| 2853 | case SRC_UNATTACHED: | 2849 | case SRC_UNATTACHED: |
| 2854 | if (!port->non_pd_role_swap) | 2850 | if (!port->non_pd_role_swap) |
| 2855 | tcpm_swap_complete(port, -ENOTCONN); | 2851 | tcpm_swap_complete(port, -ENOTCONN); |
| 2856 | tcpm_src_detach(port); | 2852 | tcpm_src_detach(port); |
| 2857 | if (tcpm_start_drp_toggling(port, tcpm_rp_cc(port))) { | 2853 | if (tcpm_start_toggling(port, tcpm_rp_cc(port))) { |
| 2858 | tcpm_set_state(port, DRP_TOGGLING, 0); | 2854 | tcpm_set_state(port, TOGGLING, 0); |
| 2859 | break; | 2855 | break; |
| 2860 | } | 2856 | } |
| 2861 | tcpm_set_cc(port, tcpm_rp_cc(port)); | 2857 | tcpm_set_cc(port, tcpm_rp_cc(port)); |
| @@ -3053,8 +3049,8 @@ static void run_state_machine(struct tcpm_port *port) | |||
| 3053 | tcpm_swap_complete(port, -ENOTCONN); | 3049 | tcpm_swap_complete(port, -ENOTCONN); |
| 3054 | tcpm_pps_complete(port, -ENOTCONN); | 3050 | tcpm_pps_complete(port, -ENOTCONN); |
| 3055 | tcpm_snk_detach(port); | 3051 | tcpm_snk_detach(port); |
| 3056 | if (tcpm_start_drp_toggling(port, TYPEC_CC_RD)) { | 3052 | if (tcpm_start_toggling(port, TYPEC_CC_RD)) { |
| 3057 | tcpm_set_state(port, DRP_TOGGLING, 0); | 3053 | tcpm_set_state(port, TOGGLING, 0); |
| 3058 | break; | 3054 | break; |
| 3059 | } | 3055 | } |
| 3060 | tcpm_set_cc(port, TYPEC_CC_RD); | 3056 | tcpm_set_cc(port, TYPEC_CC_RD); |
| @@ -3621,7 +3617,7 @@ static void _tcpm_cc_change(struct tcpm_port *port, enum typec_cc_status cc1, | |||
| 3621 | : "connected"); | 3617 | : "connected"); |
| 3622 | 3618 | ||
| 3623 | switch (port->state) { | 3619 | switch (port->state) { |
| 3624 | case DRP_TOGGLING: | 3620 | case TOGGLING: |
| 3625 | if (tcpm_port_is_debug(port) || tcpm_port_is_audio(port) || | 3621 | if (tcpm_port_is_debug(port) || tcpm_port_is_audio(port) || |
| 3626 | tcpm_port_is_source(port)) | 3622 | tcpm_port_is_source(port)) |
| 3627 | tcpm_set_state(port, SRC_ATTACH_WAIT, 0); | 3623 | tcpm_set_state(port, SRC_ATTACH_WAIT, 0); |
diff --git a/drivers/usb/typec/tcpm/wcove.c b/drivers/usb/typec/tcpm/wcove.c index 6770afd40765..6b317c150bdd 100644 --- a/drivers/usb/typec/tcpm/wcove.c +++ b/drivers/usb/typec/tcpm/wcove.c | |||
| @@ -416,12 +416,16 @@ static int wcove_pd_transmit(struct tcpc_dev *tcpc, | |||
| 416 | return regmap_write(wcove->regmap, USBC_TXCMD, cmd | USBC_TXCMD_START); | 416 | return regmap_write(wcove->regmap, USBC_TXCMD, cmd | USBC_TXCMD_START); |
| 417 | } | 417 | } |
| 418 | 418 | ||
| 419 | static int wcove_start_drp_toggling(struct tcpc_dev *tcpc, | 419 | static int wcove_start_toggling(struct tcpc_dev *tcpc, |
| 420 | enum typec_cc_status cc) | 420 | enum typec_port_type port_type, |
| 421 | enum typec_cc_status cc) | ||
| 421 | { | 422 | { |
| 422 | struct wcove_typec *wcove = tcpc_to_wcove(tcpc); | 423 | struct wcove_typec *wcove = tcpc_to_wcove(tcpc); |
| 423 | unsigned int usbc_ctrl; | 424 | unsigned int usbc_ctrl; |
| 424 | 425 | ||
| 426 | if (port_type != TYPEC_PORT_DRP) | ||
| 427 | return -EOPNOTSUPP; | ||
| 428 | |||
| 425 | usbc_ctrl = USBC_CONTROL1_MODE_DRP | USBC_CONTROL1_DRPTOGGLE_RANDOM; | 429 | usbc_ctrl = USBC_CONTROL1_MODE_DRP | USBC_CONTROL1_DRPTOGGLE_RANDOM; |
| 426 | 430 | ||
| 427 | switch (cc) { | 431 | switch (cc) { |
| @@ -587,17 +591,14 @@ static const u32 snk_pdo[] = { | |||
| 587 | PDO_VAR(5000, 12000, 3000), | 591 | PDO_VAR(5000, 12000, 3000), |
| 588 | }; | 592 | }; |
| 589 | 593 | ||
| 590 | static struct tcpc_config wcove_typec_config = { | 594 | static const struct property_entry wcove_props[] = { |
| 591 | .src_pdo = src_pdo, | 595 | PROPERTY_ENTRY_STRING("data-role", "dual"), |
| 592 | .nr_src_pdo = ARRAY_SIZE(src_pdo), | 596 | PROPERTY_ENTRY_STRING("power-role", "dual"), |
| 593 | .snk_pdo = snk_pdo, | 597 | PROPERTY_ENTRY_STRING("try-power-role", "sink"), |
| 594 | .nr_snk_pdo = ARRAY_SIZE(snk_pdo), | 598 | PROPERTY_ENTRY_U32_ARRAY("source-pdos", src_pdo), |
| 595 | 599 | PROPERTY_ENTRY_U32_ARRAY("sink-pdos", snk_pdo), | |
| 596 | .operating_snk_mw = 15000, | 600 | PROPERTY_ENTRY_U32("op-sink-microwatt", 15000), |
| 597 | 601 | { } | |
| 598 | .type = TYPEC_PORT_DRP, | ||
| 599 | .data = TYPEC_PORT_DRD, | ||
| 600 | .default_role = TYPEC_SINK, | ||
| 601 | }; | 602 | }; |
| 602 | 603 | ||
| 603 | static int wcove_typec_probe(struct platform_device *pdev) | 604 | static int wcove_typec_probe(struct platform_device *pdev) |
| @@ -642,23 +643,28 @@ static int wcove_typec_probe(struct platform_device *pdev) | |||
| 642 | wcove->tcpc.set_polarity = wcove_set_polarity; | 643 | wcove->tcpc.set_polarity = wcove_set_polarity; |
| 643 | wcove->tcpc.set_vconn = wcove_set_vconn; | 644 | wcove->tcpc.set_vconn = wcove_set_vconn; |
| 644 | wcove->tcpc.set_current_limit = wcove_set_current_limit; | 645 | wcove->tcpc.set_current_limit = wcove_set_current_limit; |
| 645 | wcove->tcpc.start_drp_toggling = wcove_start_drp_toggling; | 646 | wcove->tcpc.start_toggling = wcove_start_toggling; |
| 646 | 647 | ||
| 647 | wcove->tcpc.set_pd_rx = wcove_set_pd_rx; | 648 | wcove->tcpc.set_pd_rx = wcove_set_pd_rx; |
| 648 | wcove->tcpc.set_roles = wcove_set_roles; | 649 | wcove->tcpc.set_roles = wcove_set_roles; |
| 649 | wcove->tcpc.pd_transmit = wcove_pd_transmit; | 650 | wcove->tcpc.pd_transmit = wcove_pd_transmit; |
| 650 | 651 | ||
| 651 | wcove->tcpc.config = &wcove_typec_config; | 652 | wcove->tcpc.fwnode = fwnode_create_software_node(wcove_props, NULL); |
| 653 | if (IS_ERR(wcove->tcpc.fwnode)) | ||
| 654 | return PTR_ERR(wcove->tcpc.fwnode); | ||
| 652 | 655 | ||
| 653 | wcove->tcpm = tcpm_register_port(wcove->dev, &wcove->tcpc); | 656 | wcove->tcpm = tcpm_register_port(wcove->dev, &wcove->tcpc); |
| 654 | if (IS_ERR(wcove->tcpm)) | 657 | if (IS_ERR(wcove->tcpm)) { |
| 658 | fwnode_remove_software_node(wcove->tcpc.fwnode); | ||
| 655 | return PTR_ERR(wcove->tcpm); | 659 | return PTR_ERR(wcove->tcpm); |
| 660 | } | ||
| 656 | 661 | ||
| 657 | ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, | 662 | ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, |
| 658 | wcove_typec_irq, IRQF_ONESHOT, | 663 | wcove_typec_irq, IRQF_ONESHOT, |
| 659 | "wcove_typec", wcove); | 664 | "wcove_typec", wcove); |
| 660 | if (ret) { | 665 | if (ret) { |
| 661 | tcpm_unregister_port(wcove->tcpm); | 666 | tcpm_unregister_port(wcove->tcpm); |
| 667 | fwnode_remove_software_node(wcove->tcpc.fwnode); | ||
| 662 | return ret; | 668 | return ret; |
| 663 | } | 669 | } |
| 664 | 670 | ||
| @@ -678,6 +684,7 @@ static int wcove_typec_remove(struct platform_device *pdev) | |||
| 678 | regmap_write(wcove->regmap, USBC_IRQMASK2, val | USBC_IRQMASK2_ALL); | 684 | regmap_write(wcove->regmap, USBC_IRQMASK2, val | USBC_IRQMASK2_ALL); |
| 679 | 685 | ||
| 680 | tcpm_unregister_port(wcove->tcpm); | 686 | tcpm_unregister_port(wcove->tcpm); |
| 687 | fwnode_remove_software_node(wcove->tcpc.fwnode); | ||
| 681 | 688 | ||
| 682 | return 0; | 689 | return 0; |
| 683 | } | 690 | } |
diff --git a/drivers/usb/typec/ucsi/Makefile b/drivers/usb/typec/ucsi/Makefile index 2f4900b26210..b35e15a1f02c 100644 --- a/drivers/usb/typec/ucsi/Makefile +++ b/drivers/usb/typec/ucsi/Makefile | |||
| @@ -1,12 +1,15 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0 | 1 | # SPDX-License-Identifier: GPL-2.0 |
| 2 | CFLAGS_trace.o := -I$(src) | 2 | CFLAGS_trace.o := -I$(src) |
| 3 | 3 | ||
| 4 | obj-$(CONFIG_TYPEC_UCSI) += typec_ucsi.o | 4 | obj-$(CONFIG_TYPEC_UCSI) += typec_ucsi.o |
| 5 | 5 | ||
| 6 | typec_ucsi-y := ucsi.o | 6 | typec_ucsi-y := ucsi.o |
| 7 | 7 | ||
| 8 | typec_ucsi-$(CONFIG_TRACING) += trace.o | 8 | typec_ucsi-$(CONFIG_TRACING) += trace.o |
| 9 | 9 | ||
| 10 | obj-$(CONFIG_UCSI_ACPI) += ucsi_acpi.o | 10 | ifneq ($(CONFIG_TYPEC_DP_ALTMODE),) |
| 11 | typec_ucsi-y += displayport.o | ||
| 12 | endif | ||
| 11 | 13 | ||
| 12 | obj-$(CONFIG_UCSI_CCG) += ucsi_ccg.o | 14 | obj-$(CONFIG_UCSI_ACPI) += ucsi_acpi.o |
| 15 | obj-$(CONFIG_UCSI_CCG) += ucsi_ccg.o | ||
diff --git a/drivers/usb/typec/ucsi/displayport.c b/drivers/usb/typec/ucsi/displayport.c new file mode 100644 index 000000000000..6c103697c582 --- /dev/null +++ b/drivers/usb/typec/ucsi/displayport.c | |||
| @@ -0,0 +1,315 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * UCSI DisplayPort Alternate Mode Support | ||
| 4 | * | ||
| 5 | * Copyright (C) 2018, Intel Corporation | ||
| 6 | * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com> | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/usb/typec_dp.h> | ||
| 10 | #include <linux/usb/pd_vdo.h> | ||
| 11 | |||
| 12 | #include "ucsi.h" | ||
| 13 | |||
| 14 | #define UCSI_CMD_SET_NEW_CAM(_con_num_, _enter_, _cam_, _am_) \ | ||
| 15 | (UCSI_SET_NEW_CAM | ((_con_num_) << 16) | ((_enter_) << 23) | \ | ||
| 16 | ((_cam_) << 24) | ((u64)(_am_) << 32)) | ||
| 17 | |||
| 18 | struct ucsi_dp { | ||
| 19 | struct typec_displayport_data data; | ||
| 20 | struct ucsi_connector *con; | ||
| 21 | struct typec_altmode *alt; | ||
| 22 | struct work_struct work; | ||
| 23 | int offset; | ||
| 24 | |||
| 25 | bool override; | ||
| 26 | bool initialized; | ||
| 27 | |||
| 28 | u32 header; | ||
| 29 | u32 *vdo_data; | ||
| 30 | u8 vdo_size; | ||
| 31 | }; | ||
| 32 | |||
| 33 | /* | ||
| 34 | * Note. Alternate mode control is optional feature in UCSI. It means that even | ||
| 35 | * if the system supports alternate modes, the OS may not be aware of them. | ||
| 36 | * | ||
| 37 | * In most cases however, the OS will be able to see the supported alternate | ||
| 38 | * modes, but it may still not be able to configure them, not even enter or exit | ||
| 39 | * them. That is because UCSI defines alt mode details and alt mode "overriding" | ||
| 40 | * as separate options. | ||
| 41 | * | ||
| 42 | * In case alt mode details are supported, but overriding is not, the driver | ||
| 43 | * will still display the supported pin assignments and configuration, but any | ||
| 44 | * changes the user attempts to do will lead into failure with return value of | ||
| 45 | * -EOPNOTSUPP. | ||
| 46 | */ | ||
| 47 | |||
| 48 | static int ucsi_displayport_enter(struct typec_altmode *alt) | ||
| 49 | { | ||
| 50 | struct ucsi_dp *dp = typec_altmode_get_drvdata(alt); | ||
| 51 | struct ucsi_control ctrl; | ||
| 52 | u8 cur = 0; | ||
| 53 | int ret; | ||
| 54 | |||
| 55 | mutex_lock(&dp->con->lock); | ||
| 56 | |||
| 57 | if (!dp->override && dp->initialized) { | ||
| 58 | const struct typec_altmode *p = typec_altmode_get_partner(alt); | ||
| 59 | |||
| 60 | dev_warn(&p->dev, | ||
| 61 | "firmware doesn't support alternate mode overriding\n"); | ||
| 62 | mutex_unlock(&dp->con->lock); | ||
| 63 | return -EOPNOTSUPP; | ||
| 64 | } | ||
| 65 | |||
| 66 | UCSI_CMD_GET_CURRENT_CAM(ctrl, dp->con->num); | ||
| 67 | ret = ucsi_send_command(dp->con->ucsi, &ctrl, &cur, sizeof(cur)); | ||
| 68 | if (ret < 0) { | ||
| 69 | if (dp->con->ucsi->ppm->data->version > 0x0100) { | ||
| 70 | mutex_unlock(&dp->con->lock); | ||
| 71 | return ret; | ||
| 72 | } | ||
| 73 | cur = 0xff; | ||
| 74 | } | ||
| 75 | |||
| 76 | if (cur != 0xff) { | ||
| 77 | mutex_unlock(&dp->con->lock); | ||
| 78 | return -EBUSY; | ||
| 79 | } | ||
| 80 | |||
| 81 | /* | ||
| 82 | * We can't send the New CAM command yet to the PPM as it needs the | ||
| 83 | * configuration value as well. Pretending that we have now entered the | ||
| 84 | * mode, and letting the alt mode driver continue. | ||
| 85 | */ | ||
| 86 | |||
| 87 | dp->header = VDO(USB_TYPEC_DP_SID, 1, CMD_ENTER_MODE); | ||
| 88 | dp->header |= VDO_OPOS(USB_TYPEC_DP_MODE); | ||
| 89 | dp->header |= VDO_CMDT(CMDT_RSP_ACK); | ||
| 90 | |||
| 91 | dp->vdo_data = NULL; | ||
| 92 | dp->vdo_size = 1; | ||
| 93 | |||
| 94 | schedule_work(&dp->work); | ||
| 95 | |||
| 96 | mutex_unlock(&dp->con->lock); | ||
| 97 | |||
| 98 | return 0; | ||
| 99 | } | ||
| 100 | |||
| 101 | static int ucsi_displayport_exit(struct typec_altmode *alt) | ||
| 102 | { | ||
| 103 | struct ucsi_dp *dp = typec_altmode_get_drvdata(alt); | ||
| 104 | struct ucsi_control ctrl; | ||
| 105 | int ret = 0; | ||
| 106 | |||
| 107 | mutex_lock(&dp->con->lock); | ||
| 108 | |||
| 109 | if (!dp->override) { | ||
| 110 | const struct typec_altmode *p = typec_altmode_get_partner(alt); | ||
| 111 | |||
| 112 | dev_warn(&p->dev, | ||
| 113 | "firmware doesn't support alternate mode overriding\n"); | ||
| 114 | ret = -EOPNOTSUPP; | ||
| 115 | goto out_unlock; | ||
| 116 | } | ||
| 117 | |||
| 118 | ctrl.raw_cmd = UCSI_CMD_SET_NEW_CAM(dp->con->num, 0, dp->offset, 0); | ||
| 119 | ret = ucsi_send_command(dp->con->ucsi, &ctrl, NULL, 0); | ||
| 120 | if (ret < 0) | ||
| 121 | goto out_unlock; | ||
| 122 | |||
| 123 | dp->header = VDO(USB_TYPEC_DP_SID, 1, CMD_EXIT_MODE); | ||
| 124 | dp->header |= VDO_OPOS(USB_TYPEC_DP_MODE); | ||
| 125 | dp->header |= VDO_CMDT(CMDT_RSP_ACK); | ||
| 126 | |||
| 127 | dp->vdo_data = NULL; | ||
| 128 | dp->vdo_size = 1; | ||
| 129 | |||
| 130 | schedule_work(&dp->work); | ||
| 131 | |||
| 132 | out_unlock: | ||
| 133 | mutex_unlock(&dp->con->lock); | ||
| 134 | |||
| 135 | return ret; | ||
| 136 | } | ||
| 137 | |||
| 138 | /* | ||
| 139 | * We do not actually have access to the Status Update VDO, so we have to guess | ||
| 140 | * things. | ||
| 141 | */ | ||
| 142 | static int ucsi_displayport_status_update(struct ucsi_dp *dp) | ||
| 143 | { | ||
| 144 | u32 cap = dp->alt->vdo; | ||
| 145 | |||
| 146 | dp->data.status = DP_STATUS_ENABLED; | ||
| 147 | |||
| 148 | /* | ||
| 149 | * If pin assignement D is supported, claiming always | ||
| 150 | * that Multi-function is preferred. | ||
| 151 | */ | ||
| 152 | if (DP_CAP_CAPABILITY(cap) & DP_CAP_UFP_D) { | ||
| 153 | dp->data.status |= DP_STATUS_CON_UFP_D; | ||
| 154 | |||
| 155 | if (DP_CAP_UFP_D_PIN_ASSIGN(cap) & BIT(DP_PIN_ASSIGN_D)) | ||
| 156 | dp->data.status |= DP_STATUS_PREFER_MULTI_FUNC; | ||
| 157 | } else { | ||
| 158 | dp->data.status |= DP_STATUS_CON_DFP_D; | ||
| 159 | |||
| 160 | if (DP_CAP_DFP_D_PIN_ASSIGN(cap) & BIT(DP_PIN_ASSIGN_D)) | ||
| 161 | dp->data.status |= DP_STATUS_PREFER_MULTI_FUNC; | ||
| 162 | } | ||
| 163 | |||
| 164 | dp->vdo_data = &dp->data.status; | ||
| 165 | dp->vdo_size = 2; | ||
| 166 | |||
| 167 | return 0; | ||
| 168 | } | ||
| 169 | |||
| 170 | static int ucsi_displayport_configure(struct ucsi_dp *dp) | ||
| 171 | { | ||
| 172 | u32 pins = DP_CONF_GET_PIN_ASSIGN(dp->data.conf); | ||
| 173 | struct ucsi_control ctrl; | ||
| 174 | |||
| 175 | if (!dp->override) | ||
| 176 | return 0; | ||
| 177 | |||
| 178 | ctrl.raw_cmd = UCSI_CMD_SET_NEW_CAM(dp->con->num, 1, dp->offset, pins); | ||
| 179 | |||
| 180 | return ucsi_send_command(dp->con->ucsi, &ctrl, NULL, 0); | ||
| 181 | } | ||
| 182 | |||
| 183 | static int ucsi_displayport_vdm(struct typec_altmode *alt, | ||
| 184 | u32 header, const u32 *data, int count) | ||
| 185 | { | ||
| 186 | struct ucsi_dp *dp = typec_altmode_get_drvdata(alt); | ||
| 187 | int cmd_type = PD_VDO_CMDT(header); | ||
| 188 | int cmd = PD_VDO_CMD(header); | ||
| 189 | |||
| 190 | mutex_lock(&dp->con->lock); | ||
| 191 | |||
| 192 | if (!dp->override && dp->initialized) { | ||
| 193 | const struct typec_altmode *p = typec_altmode_get_partner(alt); | ||
| 194 | |||
| 195 | dev_warn(&p->dev, | ||
| 196 | "firmware doesn't support alternate mode overriding\n"); | ||
| 197 | mutex_unlock(&dp->con->lock); | ||
| 198 | return -EOPNOTSUPP; | ||
| 199 | } | ||
| 200 | |||
| 201 | switch (cmd_type) { | ||
| 202 | case CMDT_INIT: | ||
| 203 | dp->header = VDO(USB_TYPEC_DP_SID, 1, cmd); | ||
| 204 | dp->header |= VDO_OPOS(USB_TYPEC_DP_MODE); | ||
| 205 | |||
| 206 | switch (cmd) { | ||
| 207 | case DP_CMD_STATUS_UPDATE: | ||
| 208 | if (ucsi_displayport_status_update(dp)) | ||
| 209 | dp->header |= VDO_CMDT(CMDT_RSP_NAK); | ||
| 210 | else | ||
| 211 | dp->header |= VDO_CMDT(CMDT_RSP_ACK); | ||
| 212 | break; | ||
| 213 | case DP_CMD_CONFIGURE: | ||
| 214 | dp->data.conf = *data; | ||
| 215 | if (ucsi_displayport_configure(dp)) { | ||
| 216 | dp->header |= VDO_CMDT(CMDT_RSP_NAK); | ||
| 217 | } else { | ||
| 218 | dp->header |= VDO_CMDT(CMDT_RSP_ACK); | ||
| 219 | if (dp->initialized) | ||
| 220 | ucsi_altmode_update_active(dp->con); | ||
| 221 | else | ||
| 222 | dp->initialized = true; | ||
| 223 | } | ||
| 224 | break; | ||
| 225 | default: | ||
| 226 | dp->header |= VDO_CMDT(CMDT_RSP_ACK); | ||
| 227 | break; | ||
| 228 | } | ||
| 229 | |||
| 230 | schedule_work(&dp->work); | ||
| 231 | break; | ||
| 232 | default: | ||
| 233 | break; | ||
| 234 | } | ||
| 235 | |||
| 236 | mutex_unlock(&dp->con->lock); | ||
| 237 | |||
| 238 | return 0; | ||
| 239 | } | ||
| 240 | |||
| 241 | static const struct typec_altmode_ops ucsi_displayport_ops = { | ||
| 242 | .enter = ucsi_displayport_enter, | ||
| 243 | .exit = ucsi_displayport_exit, | ||
| 244 | .vdm = ucsi_displayport_vdm, | ||
| 245 | }; | ||
| 246 | |||
| 247 | static void ucsi_displayport_work(struct work_struct *work) | ||
| 248 | { | ||
| 249 | struct ucsi_dp *dp = container_of(work, struct ucsi_dp, work); | ||
| 250 | int ret; | ||
| 251 | |||
| 252 | mutex_lock(&dp->con->lock); | ||
| 253 | |||
| 254 | ret = typec_altmode_vdm(dp->alt, dp->header, | ||
| 255 | dp->vdo_data, dp->vdo_size); | ||
| 256 | if (ret) | ||
| 257 | dev_err(&dp->alt->dev, "VDM 0x%x failed\n", dp->header); | ||
| 258 | |||
| 259 | dp->vdo_data = NULL; | ||
| 260 | dp->vdo_size = 0; | ||
| 261 | dp->header = 0; | ||
| 262 | |||
| 263 | mutex_unlock(&dp->con->lock); | ||
| 264 | } | ||
| 265 | |||
| 266 | void ucsi_displayport_remove_partner(struct typec_altmode *alt) | ||
| 267 | { | ||
| 268 | struct ucsi_dp *dp; | ||
| 269 | |||
| 270 | if (!alt) | ||
| 271 | return; | ||
| 272 | |||
| 273 | dp = typec_altmode_get_drvdata(alt); | ||
| 274 | dp->data.conf = 0; | ||
| 275 | dp->data.status = 0; | ||
| 276 | dp->initialized = false; | ||
| 277 | } | ||
| 278 | |||
| 279 | struct typec_altmode *ucsi_register_displayport(struct ucsi_connector *con, | ||
| 280 | bool override, int offset, | ||
| 281 | struct typec_altmode_desc *desc) | ||
| 282 | { | ||
| 283 | u8 all_assignments = BIT(DP_PIN_ASSIGN_C) | BIT(DP_PIN_ASSIGN_D) | | ||
| 284 | BIT(DP_PIN_ASSIGN_E); | ||
| 285 | struct typec_altmode *alt; | ||
| 286 | struct ucsi_dp *dp; | ||
| 287 | |||
| 288 | /* We can't rely on the firmware with the capabilities. */ | ||
| 289 | desc->vdo |= DP_CAP_DP_SIGNALING | DP_CAP_RECEPTACLE; | ||
| 290 | |||
| 291 | /* Claiming that we support all pin assignments */ | ||
| 292 | desc->vdo |= all_assignments << 8; | ||
| 293 | desc->vdo |= all_assignments << 16; | ||
| 294 | |||
| 295 | alt = typec_port_register_altmode(con->port, desc); | ||
| 296 | if (IS_ERR(alt)) | ||
| 297 | return alt; | ||
| 298 | |||
| 299 | dp = devm_kzalloc(&alt->dev, sizeof(*dp), GFP_KERNEL); | ||
| 300 | if (!dp) { | ||
| 301 | typec_unregister_altmode(alt); | ||
| 302 | return ERR_PTR(-ENOMEM); | ||
| 303 | } | ||
| 304 | |||
| 305 | INIT_WORK(&dp->work, ucsi_displayport_work); | ||
| 306 | dp->override = override; | ||
| 307 | dp->offset = offset; | ||
| 308 | dp->con = con; | ||
| 309 | dp->alt = alt; | ||
| 310 | |||
| 311 | alt->ops = &ucsi_displayport_ops; | ||
| 312 | typec_altmode_set_drvdata(alt, dp); | ||
| 313 | |||
| 314 | return alt; | ||
| 315 | } | ||
diff --git a/drivers/usb/typec/ucsi/trace.c b/drivers/usb/typec/ucsi/trace.c index ffa3b4c3f338..1dabafb74320 100644 --- a/drivers/usb/typec/ucsi/trace.c +++ b/drivers/usb/typec/ucsi/trace.c | |||
| @@ -60,3 +60,15 @@ const char *ucsi_cci_str(u32 cci) | |||
| 60 | 60 | ||
| 61 | return ""; | 61 | return ""; |
| 62 | } | 62 | } |
| 63 | |||
| 64 | static const char * const ucsi_recipient_strs[] = { | ||
| 65 | [UCSI_RECIPIENT_CON] = "port", | ||
| 66 | [UCSI_RECIPIENT_SOP] = "partner", | ||
| 67 | [UCSI_RECIPIENT_SOP_P] = "plug (prime)", | ||
| 68 | [UCSI_RECIPIENT_SOP_PP] = "plug (double prime)", | ||
| 69 | }; | ||
| 70 | |||
| 71 | const char *ucsi_recipient_str(u8 recipient) | ||
| 72 | { | ||
| 73 | return ucsi_recipient_strs[recipient]; | ||
| 74 | } | ||
diff --git a/drivers/usb/typec/ucsi/trace.h b/drivers/usb/typec/ucsi/trace.h index 5e2906df2db7..783ec9c72055 100644 --- a/drivers/usb/typec/ucsi/trace.h +++ b/drivers/usb/typec/ucsi/trace.h | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #define __UCSI_TRACE_H | 7 | #define __UCSI_TRACE_H |
| 8 | 8 | ||
| 9 | #include <linux/tracepoint.h> | 9 | #include <linux/tracepoint.h> |
| 10 | #include <linux/usb/typec_altmode.h> | ||
| 10 | 11 | ||
| 11 | const char *ucsi_cmd_str(u64 raw_cmd); | 12 | const char *ucsi_cmd_str(u64 raw_cmd); |
| 12 | const char *ucsi_ack_str(u8 ack); | 13 | const char *ucsi_ack_str(u8 ack); |
| @@ -134,6 +135,31 @@ DEFINE_EVENT(ucsi_log_connector_status, ucsi_register_port, | |||
| 134 | TP_ARGS(port, status) | 135 | TP_ARGS(port, status) |
| 135 | ); | 136 | ); |
| 136 | 137 | ||
| 138 | DECLARE_EVENT_CLASS(ucsi_log_register_altmode, | ||
| 139 | TP_PROTO(u8 recipient, struct typec_altmode *alt), | ||
| 140 | TP_ARGS(recipient, alt), | ||
| 141 | TP_STRUCT__entry( | ||
| 142 | __field(u8, recipient) | ||
| 143 | __field(u16, svid) | ||
| 144 | __field(u8, mode) | ||
| 145 | __field(u32, vdo) | ||
| 146 | ), | ||
| 147 | TP_fast_assign( | ||
| 148 | __entry->recipient = recipient; | ||
| 149 | __entry->svid = alt->svid; | ||
| 150 | __entry->mode = alt->mode; | ||
| 151 | __entry->vdo = alt->vdo; | ||
| 152 | ), | ||
| 153 | TP_printk("%s alt mode: svid %04x, mode %d vdo %x", | ||
| 154 | ucsi_recipient_str(__entry->recipient), __entry->svid, | ||
| 155 | __entry->mode, __entry->vdo) | ||
| 156 | ); | ||
| 157 | |||
| 158 | DEFINE_EVENT(ucsi_log_register_altmode, ucsi_register_altmode, | ||
| 159 | TP_PROTO(u8 recipient, struct typec_altmode *alt), | ||
| 160 | TP_ARGS(recipient, alt) | ||
| 161 | ); | ||
| 162 | |||
| 137 | #endif /* __UCSI_TRACE_H */ | 163 | #endif /* __UCSI_TRACE_H */ |
| 138 | 164 | ||
| 139 | /* This part must be outside protection */ | 165 | /* This part must be outside protection */ |
diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index 8d0a6fe748bd..7850b851cecd 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c | |||
| @@ -12,7 +12,7 @@ | |||
| 12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
| 13 | #include <linux/delay.h> | 13 | #include <linux/delay.h> |
| 14 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
| 15 | #include <linux/usb/typec.h> | 15 | #include <linux/usb/typec_dp.h> |
| 16 | 16 | ||
| 17 | #include "ucsi.h" | 17 | #include "ucsi.h" |
| 18 | #include "trace.h" | 18 | #include "trace.h" |
| @@ -39,49 +39,6 @@ | |||
| 39 | */ | 39 | */ |
| 40 | #define UCSI_SWAP_TIMEOUT_MS 5000 | 40 | #define UCSI_SWAP_TIMEOUT_MS 5000 |
| 41 | 41 | ||
| 42 | enum ucsi_status { | ||
| 43 | UCSI_IDLE = 0, | ||
| 44 | UCSI_BUSY, | ||
| 45 | UCSI_ERROR, | ||
| 46 | }; | ||
| 47 | |||
| 48 | struct ucsi_connector { | ||
| 49 | int num; | ||
| 50 | |||
| 51 | struct ucsi *ucsi; | ||
| 52 | struct work_struct work; | ||
| 53 | struct completion complete; | ||
| 54 | |||
| 55 | struct typec_port *port; | ||
| 56 | struct typec_partner *partner; | ||
| 57 | |||
| 58 | struct typec_capability typec_cap; | ||
| 59 | |||
| 60 | struct ucsi_connector_status status; | ||
| 61 | struct ucsi_connector_capability cap; | ||
| 62 | }; | ||
| 63 | |||
| 64 | struct ucsi { | ||
| 65 | struct device *dev; | ||
| 66 | struct ucsi_ppm *ppm; | ||
| 67 | |||
| 68 | enum ucsi_status status; | ||
| 69 | struct completion complete; | ||
| 70 | struct ucsi_capability cap; | ||
| 71 | struct ucsi_connector *connector; | ||
| 72 | |||
| 73 | struct work_struct work; | ||
| 74 | |||
| 75 | /* PPM Communication lock */ | ||
| 76 | struct mutex ppm_lock; | ||
| 77 | |||
| 78 | /* PPM communication flags */ | ||
| 79 | unsigned long flags; | ||
| 80 | #define EVENT_PENDING 0 | ||
| 81 | #define COMMAND_PENDING 1 | ||
| 82 | #define ACK_PENDING 2 | ||
| 83 | }; | ||
| 84 | |||
| 85 | static inline int ucsi_sync(struct ucsi *ucsi) | 42 | static inline int ucsi_sync(struct ucsi *ucsi) |
| 86 | { | 43 | { |
| 87 | if (ucsi->ppm && ucsi->ppm->sync) | 44 | if (ucsi->ppm && ucsi->ppm->sync) |
| @@ -238,8 +195,226 @@ err: | |||
| 238 | return ret; | 195 | return ret; |
| 239 | } | 196 | } |
| 240 | 197 | ||
| 198 | int ucsi_send_command(struct ucsi *ucsi, struct ucsi_control *ctrl, | ||
| 199 | void *retval, size_t size) | ||
| 200 | { | ||
| 201 | int ret; | ||
| 202 | |||
| 203 | mutex_lock(&ucsi->ppm_lock); | ||
| 204 | ret = ucsi_run_command(ucsi, ctrl, retval, size); | ||
| 205 | mutex_unlock(&ucsi->ppm_lock); | ||
| 206 | |||
| 207 | return ret; | ||
| 208 | } | ||
| 209 | |||
| 241 | /* -------------------------------------------------------------------------- */ | 210 | /* -------------------------------------------------------------------------- */ |
| 242 | 211 | ||
| 212 | void ucsi_altmode_update_active(struct ucsi_connector *con) | ||
| 213 | { | ||
| 214 | const struct typec_altmode *altmode = NULL; | ||
| 215 | struct ucsi_control ctrl; | ||
| 216 | int ret; | ||
| 217 | u8 cur; | ||
| 218 | int i; | ||
| 219 | |||
| 220 | UCSI_CMD_GET_CURRENT_CAM(ctrl, con->num); | ||
| 221 | ret = ucsi_run_command(con->ucsi, &ctrl, &cur, sizeof(cur)); | ||
| 222 | if (ret < 0) { | ||
| 223 | if (con->ucsi->ppm->data->version > 0x0100) { | ||
| 224 | dev_err(con->ucsi->dev, | ||
| 225 | "GET_CURRENT_CAM command failed\n"); | ||
| 226 | return; | ||
| 227 | } | ||
| 228 | cur = 0xff; | ||
| 229 | } | ||
| 230 | |||
| 231 | if (cur < UCSI_MAX_ALTMODES) | ||
| 232 | altmode = typec_altmode_get_partner(con->port_altmode[cur]); | ||
| 233 | |||
| 234 | for (i = 0; con->partner_altmode[i]; i++) | ||
| 235 | typec_altmode_update_active(con->partner_altmode[i], | ||
| 236 | con->partner_altmode[i] == altmode); | ||
| 237 | } | ||
| 238 | |||
| 239 | static u8 ucsi_altmode_next_mode(struct typec_altmode **alt, u16 svid) | ||
| 240 | { | ||
| 241 | u8 mode = 1; | ||
| 242 | int i; | ||
| 243 | |||
| 244 | for (i = 0; alt[i]; i++) | ||
| 245 | if (alt[i]->svid == svid) | ||
| 246 | mode++; | ||
| 247 | |||
| 248 | return mode; | ||
| 249 | } | ||
| 250 | |||
| 251 | static int ucsi_next_altmode(struct typec_altmode **alt) | ||
| 252 | { | ||
| 253 | int i = 0; | ||
| 254 | |||
| 255 | for (i = 0; i < UCSI_MAX_ALTMODES; i++) | ||
| 256 | if (!alt[i]) | ||
| 257 | return i; | ||
| 258 | |||
| 259 | return -ENOENT; | ||
| 260 | } | ||
| 261 | |||
| 262 | static int ucsi_register_altmode(struct ucsi_connector *con, | ||
| 263 | struct typec_altmode_desc *desc, | ||
| 264 | u8 recipient) | ||
| 265 | { | ||
| 266 | struct typec_altmode *alt; | ||
| 267 | bool override; | ||
| 268 | int ret; | ||
| 269 | int i; | ||
| 270 | |||
| 271 | override = !!(con->ucsi->cap.features & UCSI_CAP_ALT_MODE_OVERRIDE); | ||
| 272 | |||
| 273 | switch (recipient) { | ||
| 274 | case UCSI_RECIPIENT_CON: | ||
| 275 | i = ucsi_next_altmode(con->port_altmode); | ||
| 276 | if (i < 0) { | ||
| 277 | ret = i; | ||
| 278 | goto err; | ||
| 279 | } | ||
| 280 | |||
| 281 | desc->mode = ucsi_altmode_next_mode(con->port_altmode, | ||
| 282 | desc->svid); | ||
| 283 | |||
| 284 | switch (desc->svid) { | ||
| 285 | case USB_TYPEC_DP_SID: | ||
| 286 | case USB_TYPEC_NVIDIA_VLINK_SID: | ||
| 287 | alt = ucsi_register_displayport(con, override, i, desc); | ||
| 288 | break; | ||
| 289 | default: | ||
| 290 | alt = typec_port_register_altmode(con->port, desc); | ||
| 291 | break; | ||
| 292 | } | ||
| 293 | |||
| 294 | if (IS_ERR(alt)) { | ||
| 295 | ret = PTR_ERR(alt); | ||
| 296 | goto err; | ||
| 297 | } | ||
| 298 | |||
| 299 | con->port_altmode[i] = alt; | ||
| 300 | break; | ||
| 301 | case UCSI_RECIPIENT_SOP: | ||
| 302 | i = ucsi_next_altmode(con->partner_altmode); | ||
| 303 | if (i < 0) { | ||
| 304 | ret = i; | ||
| 305 | goto err; | ||
| 306 | } | ||
| 307 | |||
| 308 | desc->mode = ucsi_altmode_next_mode(con->partner_altmode, | ||
| 309 | desc->svid); | ||
| 310 | |||
| 311 | alt = typec_partner_register_altmode(con->partner, desc); | ||
| 312 | if (IS_ERR(alt)) { | ||
| 313 | ret = PTR_ERR(alt); | ||
| 314 | goto err; | ||
| 315 | } | ||
| 316 | |||
| 317 | con->partner_altmode[i] = alt; | ||
| 318 | break; | ||
| 319 | default: | ||
| 320 | return -EINVAL; | ||
| 321 | } | ||
| 322 | |||
| 323 | trace_ucsi_register_altmode(recipient, alt); | ||
| 324 | |||
| 325 | return 0; | ||
| 326 | |||
| 327 | err: | ||
| 328 | dev_err(con->ucsi->dev, "failed to registers svid 0x%04x mode %d\n", | ||
| 329 | desc->svid, desc->mode); | ||
| 330 | |||
| 331 | return ret; | ||
| 332 | } | ||
| 333 | |||
| 334 | static int ucsi_register_altmodes(struct ucsi_connector *con, u8 recipient) | ||
| 335 | { | ||
| 336 | int max_altmodes = UCSI_MAX_ALTMODES; | ||
| 337 | struct typec_altmode_desc desc; | ||
| 338 | struct ucsi_altmode alt[2]; | ||
| 339 | struct ucsi_control ctrl; | ||
| 340 | int num = 1; | ||
| 341 | int ret; | ||
| 342 | int len; | ||
| 343 | int j; | ||
| 344 | int i; | ||
| 345 | |||
| 346 | if (!(con->ucsi->cap.features & UCSI_CAP_ALT_MODE_DETAILS)) | ||
| 347 | return 0; | ||
| 348 | |||
| 349 | if (recipient == UCSI_RECIPIENT_SOP && con->partner_altmode[0]) | ||
| 350 | return 0; | ||
| 351 | |||
| 352 | if (recipient == UCSI_RECIPIENT_CON) | ||
| 353 | max_altmodes = con->ucsi->cap.num_alt_modes; | ||
| 354 | |||
| 355 | for (i = 0; i < max_altmodes;) { | ||
| 356 | memset(alt, 0, sizeof(alt)); | ||
| 357 | UCSI_CMD_GET_ALTERNATE_MODES(ctrl, recipient, con->num, i, 1); | ||
| 358 | len = ucsi_run_command(con->ucsi, &ctrl, alt, sizeof(alt)); | ||
| 359 | if (len <= 0) | ||
| 360 | return len; | ||
| 361 | |||
| 362 | /* | ||
| 363 | * This code is requesting one alt mode at a time, but some PPMs | ||
| 364 | * may still return two. If that happens both alt modes need be | ||
| 365 | * registered and the offset for the next alt mode has to be | ||
| 366 | * incremented. | ||
| 367 | */ | ||
| 368 | num = len / sizeof(alt[0]); | ||
| 369 | i += num; | ||
| 370 | |||
| 371 | for (j = 0; j < num; j++) { | ||
| 372 | if (!alt[j].svid) | ||
| 373 | return 0; | ||
| 374 | |||
| 375 | memset(&desc, 0, sizeof(desc)); | ||
| 376 | desc.vdo = alt[j].mid; | ||
| 377 | desc.svid = alt[j].svid; | ||
| 378 | desc.roles = TYPEC_PORT_DRD; | ||
| 379 | |||
| 380 | ret = ucsi_register_altmode(con, &desc, recipient); | ||
| 381 | if (ret) | ||
| 382 | return ret; | ||
| 383 | } | ||
| 384 | } | ||
| 385 | |||
| 386 | return 0; | ||
| 387 | } | ||
| 388 | |||
| 389 | static void ucsi_unregister_altmodes(struct ucsi_connector *con, u8 recipient) | ||
| 390 | { | ||
| 391 | const struct typec_altmode *pdev; | ||
| 392 | struct typec_altmode **adev; | ||
| 393 | int i = 0; | ||
| 394 | |||
| 395 | switch (recipient) { | ||
| 396 | case UCSI_RECIPIENT_CON: | ||
| 397 | adev = con->port_altmode; | ||
| 398 | break; | ||
| 399 | case UCSI_RECIPIENT_SOP: | ||
| 400 | adev = con->partner_altmode; | ||
| 401 | break; | ||
| 402 | default: | ||
| 403 | return; | ||
| 404 | } | ||
| 405 | |||
| 406 | while (adev[i]) { | ||
| 407 | if (recipient == UCSI_RECIPIENT_SOP && | ||
| 408 | (adev[i]->svid == USB_TYPEC_DP_SID || | ||
| 409 | adev[i]->svid == USB_TYPEC_NVIDIA_VLINK_SID)) { | ||
| 410 | pdev = typec_altmode_get_partner(adev[i]); | ||
| 411 | ucsi_displayport_remove_partner((void *)pdev); | ||
| 412 | } | ||
| 413 | typec_unregister_altmode(adev[i]); | ||
| 414 | adev[i++] = NULL; | ||
| 415 | } | ||
| 416 | } | ||
| 417 | |||
| 243 | static void ucsi_pwr_opmode_change(struct ucsi_connector *con) | 418 | static void ucsi_pwr_opmode_change(struct ucsi_connector *con) |
| 244 | { | 419 | { |
| 245 | switch (con->status.pwr_op_mode) { | 420 | switch (con->status.pwr_op_mode) { |
| @@ -299,10 +474,43 @@ static void ucsi_unregister_partner(struct ucsi_connector *con) | |||
| 299 | if (!con->partner) | 474 | if (!con->partner) |
| 300 | return; | 475 | return; |
| 301 | 476 | ||
| 477 | ucsi_unregister_altmodes(con, UCSI_RECIPIENT_SOP); | ||
| 302 | typec_unregister_partner(con->partner); | 478 | typec_unregister_partner(con->partner); |
| 303 | con->partner = NULL; | 479 | con->partner = NULL; |
| 304 | } | 480 | } |
| 305 | 481 | ||
| 482 | static void ucsi_partner_change(struct ucsi_connector *con) | ||
| 483 | { | ||
| 484 | int ret; | ||
| 485 | |||
| 486 | if (!con->partner) | ||
| 487 | return; | ||
| 488 | |||
| 489 | switch (con->status.partner_type) { | ||
| 490 | case UCSI_CONSTAT_PARTNER_TYPE_UFP: | ||
| 491 | typec_set_data_role(con->port, TYPEC_HOST); | ||
| 492 | break; | ||
| 493 | case UCSI_CONSTAT_PARTNER_TYPE_DFP: | ||
| 494 | typec_set_data_role(con->port, TYPEC_DEVICE); | ||
| 495 | break; | ||
| 496 | default: | ||
| 497 | break; | ||
| 498 | } | ||
| 499 | |||
| 500 | /* Complete pending data role swap */ | ||
| 501 | if (!completion_done(&con->complete)) | ||
| 502 | complete(&con->complete); | ||
| 503 | |||
| 504 | /* Can't rely on Partner Flags field. Always checking the alt modes. */ | ||
| 505 | ret = ucsi_register_altmodes(con, UCSI_RECIPIENT_SOP); | ||
| 506 | if (ret) | ||
| 507 | dev_err(con->ucsi->dev, | ||
| 508 | "con%d: failed to register partner alternate modes\n", | ||
| 509 | con->num); | ||
| 510 | else | ||
| 511 | ucsi_altmode_update_active(con); | ||
| 512 | } | ||
| 513 | |||
| 306 | static void ucsi_connector_change(struct work_struct *work) | 514 | static void ucsi_connector_change(struct work_struct *work) |
| 307 | { | 515 | { |
| 308 | struct ucsi_connector *con = container_of(work, struct ucsi_connector, | 516 | struct ucsi_connector *con = container_of(work, struct ucsi_connector, |
| @@ -311,10 +519,10 @@ static void ucsi_connector_change(struct work_struct *work) | |||
| 311 | struct ucsi_control ctrl; | 519 | struct ucsi_control ctrl; |
| 312 | int ret; | 520 | int ret; |
| 313 | 521 | ||
| 314 | mutex_lock(&ucsi->ppm_lock); | 522 | mutex_lock(&con->lock); |
| 315 | 523 | ||
| 316 | UCSI_CMD_GET_CONNECTOR_STATUS(ctrl, con->num); | 524 | UCSI_CMD_GET_CONNECTOR_STATUS(ctrl, con->num); |
| 317 | ret = ucsi_run_command(ucsi, &ctrl, &con->status, sizeof(con->status)); | 525 | ret = ucsi_send_command(ucsi, &ctrl, &con->status, sizeof(con->status)); |
| 318 | if (ret < 0) { | 526 | if (ret < 0) { |
| 319 | dev_err(ucsi->dev, "%s: GET_CONNECTOR_STATUS failed (%d)\n", | 527 | dev_err(ucsi->dev, "%s: GET_CONNECTOR_STATUS failed (%d)\n", |
| 320 | __func__, ret); | 528 | __func__, ret); |
| @@ -332,23 +540,6 @@ static void ucsi_connector_change(struct work_struct *work) | |||
| 332 | complete(&con->complete); | 540 | complete(&con->complete); |
| 333 | } | 541 | } |
| 334 | 542 | ||
| 335 | if (con->status.change & UCSI_CONSTAT_PARTNER_CHANGE) { | ||
| 336 | switch (con->status.partner_type) { | ||
| 337 | case UCSI_CONSTAT_PARTNER_TYPE_UFP: | ||
| 338 | typec_set_data_role(con->port, TYPEC_HOST); | ||
| 339 | break; | ||
| 340 | case UCSI_CONSTAT_PARTNER_TYPE_DFP: | ||
| 341 | typec_set_data_role(con->port, TYPEC_DEVICE); | ||
| 342 | break; | ||
| 343 | default: | ||
| 344 | break; | ||
| 345 | } | ||
| 346 | |||
| 347 | /* Complete pending data role swap */ | ||
| 348 | if (!completion_done(&con->complete)) | ||
| 349 | complete(&con->complete); | ||
| 350 | } | ||
| 351 | |||
| 352 | if (con->status.change & UCSI_CONSTAT_CONNECT_CHANGE) { | 543 | if (con->status.change & UCSI_CONSTAT_CONNECT_CHANGE) { |
| 353 | typec_set_pwr_role(con->port, con->status.pwr_dir); | 544 | typec_set_pwr_role(con->port, con->status.pwr_dir); |
| 354 | 545 | ||
| @@ -369,6 +560,19 @@ static void ucsi_connector_change(struct work_struct *work) | |||
| 369 | ucsi_unregister_partner(con); | 560 | ucsi_unregister_partner(con); |
| 370 | } | 561 | } |
| 371 | 562 | ||
| 563 | if (con->status.change & UCSI_CONSTAT_CAM_CHANGE) { | ||
| 564 | /* | ||
| 565 | * We don't need to know the currently supported alt modes here. | ||
| 566 | * Running GET_CAM_SUPPORTED command just to make sure the PPM | ||
| 567 | * does not get stuck in case it assumes we do so. | ||
| 568 | */ | ||
| 569 | UCSI_CMD_GET_CAM_SUPPORTED(ctrl, con->num); | ||
| 570 | ucsi_run_command(con->ucsi, &ctrl, NULL, 0); | ||
| 571 | } | ||
| 572 | |||
| 573 | if (con->status.change & UCSI_CONSTAT_PARTNER_CHANGE) | ||
| 574 | ucsi_partner_change(con); | ||
| 575 | |||
| 372 | ret = ucsi_ack(ucsi, UCSI_ACK_EVENT); | 576 | ret = ucsi_ack(ucsi, UCSI_ACK_EVENT); |
| 373 | if (ret) | 577 | if (ret) |
| 374 | dev_err(ucsi->dev, "%s: ACK failed (%d)", __func__, ret); | 578 | dev_err(ucsi->dev, "%s: ACK failed (%d)", __func__, ret); |
| @@ -377,7 +581,7 @@ static void ucsi_connector_change(struct work_struct *work) | |||
| 377 | 581 | ||
| 378 | out_unlock: | 582 | out_unlock: |
| 379 | clear_bit(EVENT_PENDING, &ucsi->flags); | 583 | clear_bit(EVENT_PENDING, &ucsi->flags); |
| 380 | mutex_unlock(&ucsi->ppm_lock); | 584 | mutex_unlock(&con->lock); |
| 381 | } | 585 | } |
| 382 | 586 | ||
| 383 | /** | 587 | /** |
| @@ -427,7 +631,7 @@ static int ucsi_reset_connector(struct ucsi_connector *con, bool hard) | |||
| 427 | 631 | ||
| 428 | UCSI_CMD_CONNECTOR_RESET(ctrl, con, hard); | 632 | UCSI_CMD_CONNECTOR_RESET(ctrl, con, hard); |
| 429 | 633 | ||
| 430 | return ucsi_run_command(con->ucsi, &ctrl, NULL, 0); | 634 | return ucsi_send_command(con->ucsi, &ctrl, NULL, 0); |
| 431 | } | 635 | } |
| 432 | 636 | ||
| 433 | static int ucsi_reset_ppm(struct ucsi *ucsi) | 637 | static int ucsi_reset_ppm(struct ucsi *ucsi) |
| @@ -481,15 +685,17 @@ static int ucsi_role_cmd(struct ucsi_connector *con, struct ucsi_control *ctrl) | |||
| 481 | { | 685 | { |
| 482 | int ret; | 686 | int ret; |
| 483 | 687 | ||
| 484 | ret = ucsi_run_command(con->ucsi, ctrl, NULL, 0); | 688 | ret = ucsi_send_command(con->ucsi, ctrl, NULL, 0); |
| 485 | if (ret == -ETIMEDOUT) { | 689 | if (ret == -ETIMEDOUT) { |
| 486 | struct ucsi_control c; | 690 | struct ucsi_control c; |
| 487 | 691 | ||
| 488 | /* PPM most likely stopped responding. Resetting everything. */ | 692 | /* PPM most likely stopped responding. Resetting everything. */ |
| 693 | mutex_lock(&con->ucsi->ppm_lock); | ||
| 489 | ucsi_reset_ppm(con->ucsi); | 694 | ucsi_reset_ppm(con->ucsi); |
| 695 | mutex_unlock(&con->ucsi->ppm_lock); | ||
| 490 | 696 | ||
| 491 | UCSI_CMD_SET_NTFY_ENABLE(c, UCSI_ENABLE_NTFY_ALL); | 697 | UCSI_CMD_SET_NTFY_ENABLE(c, UCSI_ENABLE_NTFY_ALL); |
| 492 | ucsi_run_command(con->ucsi, &c, NULL, 0); | 698 | ucsi_send_command(con->ucsi, &c, NULL, 0); |
| 493 | 699 | ||
| 494 | ucsi_reset_connector(con, true); | 700 | ucsi_reset_connector(con, true); |
| 495 | } | 701 | } |
| @@ -504,10 +710,12 @@ ucsi_dr_swap(const struct typec_capability *cap, enum typec_data_role role) | |||
| 504 | struct ucsi_control ctrl; | 710 | struct ucsi_control ctrl; |
| 505 | int ret = 0; | 711 | int ret = 0; |
| 506 | 712 | ||
| 507 | if (!con->partner) | 713 | mutex_lock(&con->lock); |
| 508 | return -ENOTCONN; | ||
| 509 | 714 | ||
| 510 | mutex_lock(&con->ucsi->ppm_lock); | 715 | if (!con->partner) { |
| 716 | ret = -ENOTCONN; | ||
| 717 | goto out_unlock; | ||
| 718 | } | ||
| 511 | 719 | ||
| 512 | if ((con->status.partner_type == UCSI_CONSTAT_PARTNER_TYPE_DFP && | 720 | if ((con->status.partner_type == UCSI_CONSTAT_PARTNER_TYPE_DFP && |
| 513 | role == TYPEC_DEVICE) || | 721 | role == TYPEC_DEVICE) || |
| @@ -520,18 +728,14 @@ ucsi_dr_swap(const struct typec_capability *cap, enum typec_data_role role) | |||
| 520 | if (ret < 0) | 728 | if (ret < 0) |
| 521 | goto out_unlock; | 729 | goto out_unlock; |
| 522 | 730 | ||
| 523 | mutex_unlock(&con->ucsi->ppm_lock); | ||
| 524 | |||
| 525 | if (!wait_for_completion_timeout(&con->complete, | 731 | if (!wait_for_completion_timeout(&con->complete, |
| 526 | msecs_to_jiffies(UCSI_SWAP_TIMEOUT_MS))) | 732 | msecs_to_jiffies(UCSI_SWAP_TIMEOUT_MS))) |
| 527 | return -ETIMEDOUT; | 733 | ret = -ETIMEDOUT; |
| 528 | |||
| 529 | return 0; | ||
| 530 | 734 | ||
| 531 | out_unlock: | 735 | out_unlock: |
| 532 | mutex_unlock(&con->ucsi->ppm_lock); | 736 | mutex_unlock(&con->lock); |
| 533 | 737 | ||
| 534 | return ret; | 738 | return ret < 0 ? ret : 0; |
| 535 | } | 739 | } |
| 536 | 740 | ||
| 537 | static int | 741 | static int |
| @@ -541,10 +745,12 @@ ucsi_pr_swap(const struct typec_capability *cap, enum typec_role role) | |||
| 541 | struct ucsi_control ctrl; | 745 | struct ucsi_control ctrl; |
| 542 | int ret = 0; | 746 | int ret = 0; |
| 543 | 747 | ||
| 544 | if (!con->partner) | 748 | mutex_lock(&con->lock); |
| 545 | return -ENOTCONN; | ||
| 546 | 749 | ||
| 547 | mutex_lock(&con->ucsi->ppm_lock); | 750 | if (!con->partner) { |
| 751 | ret = -ENOTCONN; | ||
| 752 | goto out_unlock; | ||
| 753 | } | ||
| 548 | 754 | ||
| 549 | if (con->status.pwr_dir == role) | 755 | if (con->status.pwr_dir == role) |
| 550 | goto out_unlock; | 756 | goto out_unlock; |
| @@ -554,13 +760,11 @@ ucsi_pr_swap(const struct typec_capability *cap, enum typec_role role) | |||
| 554 | if (ret < 0) | 760 | if (ret < 0) |
| 555 | goto out_unlock; | 761 | goto out_unlock; |
| 556 | 762 | ||
| 557 | mutex_unlock(&con->ucsi->ppm_lock); | ||
| 558 | |||
| 559 | if (!wait_for_completion_timeout(&con->complete, | 763 | if (!wait_for_completion_timeout(&con->complete, |
| 560 | msecs_to_jiffies(UCSI_SWAP_TIMEOUT_MS))) | 764 | msecs_to_jiffies(UCSI_SWAP_TIMEOUT_MS))) { |
| 561 | return -ETIMEDOUT; | 765 | ret = -ETIMEDOUT; |
| 562 | 766 | goto out_unlock; | |
| 563 | mutex_lock(&con->ucsi->ppm_lock); | 767 | } |
| 564 | 768 | ||
| 565 | /* Something has gone wrong while swapping the role */ | 769 | /* Something has gone wrong while swapping the role */ |
| 566 | if (con->status.pwr_op_mode != UCSI_CONSTAT_PWR_OPMODE_PD) { | 770 | if (con->status.pwr_op_mode != UCSI_CONSTAT_PWR_OPMODE_PD) { |
| @@ -569,7 +773,7 @@ ucsi_pr_swap(const struct typec_capability *cap, enum typec_role role) | |||
| 569 | } | 773 | } |
| 570 | 774 | ||
| 571 | out_unlock: | 775 | out_unlock: |
| 572 | mutex_unlock(&con->ucsi->ppm_lock); | 776 | mutex_unlock(&con->lock); |
| 573 | 777 | ||
| 574 | return ret; | 778 | return ret; |
| 575 | } | 779 | } |
| @@ -595,6 +799,7 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) | |||
| 595 | 799 | ||
| 596 | INIT_WORK(&con->work, ucsi_connector_change); | 800 | INIT_WORK(&con->work, ucsi_connector_change); |
| 597 | init_completion(&con->complete); | 801 | init_completion(&con->complete); |
| 802 | mutex_init(&con->lock); | ||
| 598 | con->num = index + 1; | 803 | con->num = index + 1; |
| 599 | con->ucsi = ucsi; | 804 | con->ucsi = ucsi; |
| 600 | 805 | ||
| @@ -636,6 +841,12 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) | |||
| 636 | if (IS_ERR(con->port)) | 841 | if (IS_ERR(con->port)) |
| 637 | return PTR_ERR(con->port); | 842 | return PTR_ERR(con->port); |
| 638 | 843 | ||
| 844 | /* Alternate modes */ | ||
| 845 | ret = ucsi_register_altmodes(con, UCSI_RECIPIENT_CON); | ||
| 846 | if (ret) | ||
| 847 | dev_err(ucsi->dev, "con%d: failed to register alt modes\n", | ||
| 848 | con->num); | ||
| 849 | |||
| 639 | /* Get the status */ | 850 | /* Get the status */ |
| 640 | UCSI_CMD_GET_CONNECTOR_STATUS(ctrl, con->num); | 851 | UCSI_CMD_GET_CONNECTOR_STATUS(ctrl, con->num); |
| 641 | ret = ucsi_run_command(ucsi, &ctrl, &con->status, sizeof(con->status)); | 852 | ret = ucsi_run_command(ucsi, &ctrl, &con->status, sizeof(con->status)); |
| @@ -662,6 +873,16 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) | |||
| 662 | if (con->status.connected) | 873 | if (con->status.connected) |
| 663 | ucsi_register_partner(con); | 874 | ucsi_register_partner(con); |
| 664 | 875 | ||
| 876 | if (con->partner) { | ||
| 877 | ret = ucsi_register_altmodes(con, UCSI_RECIPIENT_SOP); | ||
| 878 | if (ret) | ||
| 879 | dev_err(ucsi->dev, | ||
| 880 | "con%d: failed to register alternate modes\n", | ||
| 881 | con->num); | ||
| 882 | else | ||
| 883 | ucsi_altmode_update_active(con); | ||
| 884 | } | ||
| 885 | |||
| 665 | trace_ucsi_register_port(con->num, &con->status); | 886 | trace_ucsi_register_port(con->num, &con->status); |
| 666 | 887 | ||
| 667 | return 0; | 888 | return 0; |
| @@ -730,6 +951,7 @@ static void ucsi_init(struct work_struct *work) | |||
| 730 | err_unregister: | 951 | err_unregister: |
| 731 | for (con = ucsi->connector; con->port; con++) { | 952 | for (con = ucsi->connector; con->port; con++) { |
| 732 | ucsi_unregister_partner(con); | 953 | ucsi_unregister_partner(con); |
| 954 | ucsi_unregister_altmodes(con, UCSI_RECIPIENT_CON); | ||
| 733 | typec_unregister_port(con->port); | 955 | typec_unregister_port(con->port); |
| 734 | con->port = NULL; | 956 | con->port = NULL; |
| 735 | } | 957 | } |
| @@ -788,17 +1010,15 @@ void ucsi_unregister_ppm(struct ucsi *ucsi) | |||
| 788 | /* Make sure that we are not in the middle of driver initialization */ | 1010 | /* Make sure that we are not in the middle of driver initialization */ |
| 789 | cancel_work_sync(&ucsi->work); | 1011 | cancel_work_sync(&ucsi->work); |
| 790 | 1012 | ||
| 791 | mutex_lock(&ucsi->ppm_lock); | ||
| 792 | |||
| 793 | /* Disable everything except command complete notification */ | 1013 | /* Disable everything except command complete notification */ |
| 794 | UCSI_CMD_SET_NTFY_ENABLE(ctrl, UCSI_ENABLE_NTFY_CMD_COMPLETE) | 1014 | UCSI_CMD_SET_NTFY_ENABLE(ctrl, UCSI_ENABLE_NTFY_CMD_COMPLETE) |
| 795 | ucsi_run_command(ucsi, &ctrl, NULL, 0); | 1015 | ucsi_send_command(ucsi, &ctrl, NULL, 0); |
| 796 | |||
| 797 | mutex_unlock(&ucsi->ppm_lock); | ||
| 798 | 1016 | ||
| 799 | for (i = 0; i < ucsi->cap.num_connectors; i++) { | 1017 | for (i = 0; i < ucsi->cap.num_connectors; i++) { |
| 800 | cancel_work_sync(&ucsi->connector[i].work); | 1018 | cancel_work_sync(&ucsi->connector[i].work); |
| 801 | ucsi_unregister_partner(&ucsi->connector[i]); | 1019 | ucsi_unregister_partner(&ucsi->connector[i]); |
| 1020 | ucsi_unregister_altmodes(&ucsi->connector[i], | ||
| 1021 | UCSI_RECIPIENT_CON); | ||
| 802 | typec_unregister_port(ucsi->connector[i].port); | 1022 | typec_unregister_port(ucsi->connector[i].port); |
| 803 | } | 1023 | } |
| 804 | 1024 | ||
diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h index 53b80f40a908..1e2981aef629 100644 --- a/drivers/usb/typec/ucsi/ucsi.h +++ b/drivers/usb/typec/ucsi/ucsi.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | #include <linux/bitops.h> | 6 | #include <linux/bitops.h> |
| 7 | #include <linux/device.h> | 7 | #include <linux/device.h> |
| 8 | #include <linux/types.h> | 8 | #include <linux/types.h> |
| 9 | #include <linux/usb/typec.h> | ||
| 9 | 10 | ||
| 10 | /* -------------------------------------------------------------------------- */ | 11 | /* -------------------------------------------------------------------------- */ |
| 11 | 12 | ||
| @@ -60,6 +61,20 @@ struct ucsi_uor_cmd { | |||
| 60 | u16:6; /* reserved */ | 61 | u16:6; /* reserved */ |
| 61 | } __packed; | 62 | } __packed; |
| 62 | 63 | ||
| 64 | /* Get Alternate Modes Command structure */ | ||
| 65 | struct ucsi_altmode_cmd { | ||
| 66 | u8 cmd; | ||
| 67 | u8 length; | ||
| 68 | u8 recipient; | ||
| 69 | #define UCSI_RECIPIENT_CON 0 | ||
| 70 | #define UCSI_RECIPIENT_SOP 1 | ||
| 71 | #define UCSI_RECIPIENT_SOP_P 2 | ||
| 72 | #define UCSI_RECIPIENT_SOP_PP 3 | ||
| 73 | u8 con_num; | ||
| 74 | u8 offset; | ||
| 75 | u8 num_altmodes; | ||
| 76 | } __packed; | ||
| 77 | |||
| 63 | struct ucsi_control { | 78 | struct ucsi_control { |
| 64 | union { | 79 | union { |
| 65 | u64 raw_cmd; | 80 | u64 raw_cmd; |
| @@ -67,6 +82,7 @@ struct ucsi_control { | |||
| 67 | struct ucsi_uor_cmd uor; | 82 | struct ucsi_uor_cmd uor; |
| 68 | struct ucsi_ack_cmd ack; | 83 | struct ucsi_ack_cmd ack; |
| 69 | struct ucsi_con_rst con_rst; | 84 | struct ucsi_con_rst con_rst; |
| 85 | struct ucsi_altmode_cmd alt; | ||
| 70 | }; | 86 | }; |
| 71 | }; | 87 | }; |
| 72 | 88 | ||
| @@ -112,6 +128,30 @@ struct ucsi_control { | |||
| 112 | (_ctrl_).cmd.data = _con_; \ | 128 | (_ctrl_).cmd.data = _con_; \ |
| 113 | } | 129 | } |
| 114 | 130 | ||
| 131 | /* Helper for preparing ucsi_control for GET_ALTERNATE_MODES command. */ | ||
| 132 | #define UCSI_CMD_GET_ALTERNATE_MODES(_ctrl_, _r_, _con_num_, _o_, _num_)\ | ||
| 133 | { \ | ||
| 134 | __UCSI_CMD((_ctrl_), UCSI_GET_ALTERNATE_MODES) \ | ||
| 135 | _ctrl_.alt.recipient = (_r_); \ | ||
| 136 | _ctrl_.alt.con_num = (_con_num_); \ | ||
| 137 | _ctrl_.alt.offset = (_o_); \ | ||
| 138 | _ctrl_.alt.num_altmodes = (_num_) - 1; \ | ||
| 139 | } | ||
| 140 | |||
| 141 | /* Helper for preparing ucsi_control for GET_CAM_SUPPORTED command. */ | ||
| 142 | #define UCSI_CMD_GET_CAM_SUPPORTED(_ctrl_, _con_) \ | ||
| 143 | { \ | ||
| 144 | __UCSI_CMD((_ctrl_), UCSI_GET_CAM_SUPPORTED) \ | ||
| 145 | _ctrl_.cmd.data = (_con_); \ | ||
| 146 | } | ||
| 147 | |||
| 148 | /* Helper for preparing ucsi_control for GET_CAM_SUPPORTED command. */ | ||
| 149 | #define UCSI_CMD_GET_CURRENT_CAM(_ctrl_, _con_) \ | ||
| 150 | { \ | ||
| 151 | __UCSI_CMD((_ctrl_), UCSI_GET_CURRENT_CAM) \ | ||
| 152 | _ctrl_.cmd.data = (_con_); \ | ||
| 153 | } | ||
| 154 | |||
| 115 | /* Helper for preparing ucsi_control for GET_CONNECTOR_STATUS command. */ | 155 | /* Helper for preparing ucsi_control for GET_CONNECTOR_STATUS command. */ |
| 116 | #define UCSI_CMD_GET_CONNECTOR_STATUS(_ctrl_, _con_) \ | 156 | #define UCSI_CMD_GET_CONNECTOR_STATUS(_ctrl_, _con_) \ |
| 117 | { \ | 157 | { \ |
| @@ -334,4 +374,82 @@ struct ucsi *ucsi_register_ppm(struct device *dev, struct ucsi_ppm *ppm); | |||
| 334 | void ucsi_unregister_ppm(struct ucsi *ucsi); | 374 | void ucsi_unregister_ppm(struct ucsi *ucsi); |
| 335 | void ucsi_notify(struct ucsi *ucsi); | 375 | void ucsi_notify(struct ucsi *ucsi); |
| 336 | 376 | ||
| 377 | /* -------------------------------------------------------------------------- */ | ||
| 378 | |||
| 379 | enum ucsi_status { | ||
| 380 | UCSI_IDLE = 0, | ||
| 381 | UCSI_BUSY, | ||
| 382 | UCSI_ERROR, | ||
| 383 | }; | ||
| 384 | |||
| 385 | struct ucsi { | ||
| 386 | struct device *dev; | ||
| 387 | struct ucsi_ppm *ppm; | ||
| 388 | |||
| 389 | enum ucsi_status status; | ||
| 390 | struct completion complete; | ||
| 391 | struct ucsi_capability cap; | ||
| 392 | struct ucsi_connector *connector; | ||
| 393 | |||
| 394 | struct work_struct work; | ||
| 395 | |||
| 396 | /* PPM Communication lock */ | ||
| 397 | struct mutex ppm_lock; | ||
| 398 | |||
| 399 | /* PPM communication flags */ | ||
| 400 | unsigned long flags; | ||
| 401 | #define EVENT_PENDING 0 | ||
| 402 | #define COMMAND_PENDING 1 | ||
| 403 | #define ACK_PENDING 2 | ||
| 404 | }; | ||
| 405 | |||
| 406 | #define UCSI_MAX_SVID 5 | ||
| 407 | #define UCSI_MAX_ALTMODES (UCSI_MAX_SVID * 6) | ||
| 408 | |||
| 409 | struct ucsi_connector { | ||
| 410 | int num; | ||
| 411 | |||
| 412 | struct ucsi *ucsi; | ||
| 413 | struct mutex lock; /* port lock */ | ||
| 414 | struct work_struct work; | ||
| 415 | struct completion complete; | ||
| 416 | |||
| 417 | struct typec_port *port; | ||
| 418 | struct typec_partner *partner; | ||
| 419 | |||
| 420 | struct typec_altmode *port_altmode[UCSI_MAX_ALTMODES]; | ||
| 421 | struct typec_altmode *partner_altmode[UCSI_MAX_ALTMODES]; | ||
| 422 | |||
| 423 | struct typec_capability typec_cap; | ||
| 424 | |||
| 425 | struct ucsi_connector_status status; | ||
| 426 | struct ucsi_connector_capability cap; | ||
| 427 | }; | ||
| 428 | |||
| 429 | int ucsi_send_command(struct ucsi *ucsi, struct ucsi_control *ctrl, | ||
| 430 | void *retval, size_t size); | ||
| 431 | |||
| 432 | void ucsi_altmode_update_active(struct ucsi_connector *con); | ||
| 433 | |||
| 434 | #if IS_ENABLED(CONFIG_TYPEC_DP_ALTMODE) | ||
| 435 | struct typec_altmode * | ||
| 436 | ucsi_register_displayport(struct ucsi_connector *con, | ||
| 437 | bool override, int offset, | ||
| 438 | struct typec_altmode_desc *desc); | ||
| 439 | |||
| 440 | void ucsi_displayport_remove_partner(struct typec_altmode *adev); | ||
| 441 | |||
| 442 | #else | ||
| 443 | static inline struct typec_altmode * | ||
| 444 | ucsi_register_displayport(struct ucsi_connector *con, | ||
| 445 | bool override, int offset, | ||
| 446 | struct typec_altmode_desc *desc) | ||
| 447 | { | ||
| 448 | return NULL; | ||
| 449 | } | ||
| 450 | |||
| 451 | static inline void | ||
| 452 | ucsi_displayport_remove_partner(struct typec_altmode *adev) { } | ||
| 453 | #endif /* CONFIG_TYPEC_DP_ALTMODE */ | ||
| 454 | |||
| 337 | #endif /* __DRIVER_USB_TYPEC_UCSI_H */ | 455 | #endif /* __DRIVER_USB_TYPEC_UCSI_H */ |
diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c index de8a43bdff68..9d46aa9e4e35 100644 --- a/drivers/usb/typec/ucsi/ucsi_ccg.c +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | */ | 9 | */ |
| 10 | #include <linux/acpi.h> | 10 | #include <linux/acpi.h> |
| 11 | #include <linux/delay.h> | 11 | #include <linux/delay.h> |
| 12 | #include <linux/firmware.h> | ||
| 12 | #include <linux/i2c.h> | 13 | #include <linux/i2c.h> |
| 13 | #include <linux/module.h> | 14 | #include <linux/module.h> |
| 14 | #include <linux/pci.h> | 15 | #include <linux/pci.h> |
| @@ -17,18 +18,172 @@ | |||
| 17 | #include <asm/unaligned.h> | 18 | #include <asm/unaligned.h> |
| 18 | #include "ucsi.h" | 19 | #include "ucsi.h" |
| 19 | 20 | ||
| 21 | enum enum_fw_mode { | ||
| 22 | BOOT, /* bootloader */ | ||
| 23 | FW1, /* FW partition-1 (contains secondary fw) */ | ||
| 24 | FW2, /* FW partition-2 (contains primary fw) */ | ||
| 25 | FW_INVALID, | ||
| 26 | }; | ||
| 27 | |||
| 28 | #define CCGX_RAB_DEVICE_MODE 0x0000 | ||
| 29 | #define CCGX_RAB_INTR_REG 0x0006 | ||
| 30 | #define DEV_INT BIT(0) | ||
| 31 | #define PORT0_INT BIT(1) | ||
| 32 | #define PORT1_INT BIT(2) | ||
| 33 | #define UCSI_READ_INT BIT(7) | ||
| 34 | #define CCGX_RAB_JUMP_TO_BOOT 0x0007 | ||
| 35 | #define TO_BOOT 'J' | ||
| 36 | #define TO_ALT_FW 'A' | ||
| 37 | #define CCGX_RAB_RESET_REQ 0x0008 | ||
| 38 | #define RESET_SIG 'R' | ||
| 39 | #define CMD_RESET_I2C 0x0 | ||
| 40 | #define CMD_RESET_DEV 0x1 | ||
| 41 | #define CCGX_RAB_ENTER_FLASHING 0x000A | ||
| 42 | #define FLASH_ENTER_SIG 'P' | ||
| 43 | #define CCGX_RAB_VALIDATE_FW 0x000B | ||
| 44 | #define CCGX_RAB_FLASH_ROW_RW 0x000C | ||
| 45 | #define FLASH_SIG 'F' | ||
| 46 | #define FLASH_RD_CMD 0x0 | ||
| 47 | #define FLASH_WR_CMD 0x1 | ||
| 48 | #define FLASH_FWCT1_WR_CMD 0x2 | ||
| 49 | #define FLASH_FWCT2_WR_CMD 0x3 | ||
| 50 | #define FLASH_FWCT_SIG_WR_CMD 0x4 | ||
| 51 | #define CCGX_RAB_READ_ALL_VER 0x0010 | ||
| 52 | #define CCGX_RAB_READ_FW2_VER 0x0020 | ||
| 53 | #define CCGX_RAB_UCSI_CONTROL 0x0039 | ||
| 54 | #define CCGX_RAB_UCSI_CONTROL_START BIT(0) | ||
| 55 | #define CCGX_RAB_UCSI_CONTROL_STOP BIT(1) | ||
| 56 | #define CCGX_RAB_UCSI_DATA_BLOCK(offset) (0xf000 | ((offset) & 0xff)) | ||
| 57 | #define REG_FLASH_RW_MEM 0x0200 | ||
| 58 | #define DEV_REG_IDX CCGX_RAB_DEVICE_MODE | ||
| 59 | #define CCGX_RAB_PDPORT_ENABLE 0x002C | ||
| 60 | #define PDPORT_1 BIT(0) | ||
| 61 | #define PDPORT_2 BIT(1) | ||
| 62 | #define CCGX_RAB_RESPONSE 0x007E | ||
| 63 | #define ASYNC_EVENT BIT(7) | ||
| 64 | |||
| 65 | /* CCGx events & async msg codes */ | ||
| 66 | #define RESET_COMPLETE 0x80 | ||
| 67 | #define EVENT_INDEX RESET_COMPLETE | ||
| 68 | #define PORT_CONNECT_DET 0x84 | ||
| 69 | #define PORT_DISCONNECT_DET 0x85 | ||
| 70 | #define ROLE_SWAP_COMPELETE 0x87 | ||
| 71 | |||
| 72 | /* ccg firmware */ | ||
| 73 | #define CYACD_LINE_SIZE 527 | ||
| 74 | #define CCG4_ROW_SIZE 256 | ||
| 75 | #define FW1_METADATA_ROW 0x1FF | ||
| 76 | #define FW2_METADATA_ROW 0x1FE | ||
| 77 | #define FW_CFG_TABLE_SIG_SIZE 256 | ||
| 78 | |||
| 79 | static int secondary_fw_min_ver = 41; | ||
| 80 | |||
| 81 | enum enum_flash_mode { | ||
| 82 | SECONDARY_BL, /* update secondary using bootloader */ | ||
| 83 | PRIMARY, /* update primary using secondary */ | ||
| 84 | SECONDARY, /* update secondary using primary */ | ||
| 85 | FLASH_NOT_NEEDED, /* update not required */ | ||
| 86 | FLASH_INVALID, | ||
| 87 | }; | ||
| 88 | |||
| 89 | static const char * const ccg_fw_names[] = { | ||
| 90 | "ccg_boot.cyacd", | ||
| 91 | "ccg_primary.cyacd", | ||
| 92 | "ccg_secondary.cyacd" | ||
| 93 | }; | ||
| 94 | |||
| 95 | struct ccg_dev_info { | ||
| 96 | #define CCG_DEVINFO_FWMODE_SHIFT (0) | ||
| 97 | #define CCG_DEVINFO_FWMODE_MASK (0x3 << CCG_DEVINFO_FWMODE_SHIFT) | ||
| 98 | #define CCG_DEVINFO_PDPORTS_SHIFT (2) | ||
| 99 | #define CCG_DEVINFO_PDPORTS_MASK (0x3 << CCG_DEVINFO_PDPORTS_SHIFT) | ||
| 100 | u8 mode; | ||
| 101 | u8 bl_mode; | ||
| 102 | __le16 silicon_id; | ||
| 103 | __le16 bl_last_row; | ||
| 104 | } __packed; | ||
| 105 | |||
| 106 | struct version_format { | ||
| 107 | __le16 build; | ||
| 108 | u8 patch; | ||
| 109 | u8 ver; | ||
| 110 | #define CCG_VERSION_MIN_SHIFT (0) | ||
| 111 | #define CCG_VERSION_MIN_MASK (0xf << CCG_VERSION_MIN_SHIFT) | ||
| 112 | #define CCG_VERSION_MAJ_SHIFT (4) | ||
| 113 | #define CCG_VERSION_MAJ_MASK (0xf << CCG_VERSION_MAJ_SHIFT) | ||
| 114 | } __packed; | ||
| 115 | |||
| 116 | struct version_info { | ||
| 117 | struct version_format base; | ||
| 118 | struct version_format app; | ||
| 119 | }; | ||
| 120 | |||
| 121 | struct fw_config_table { | ||
| 122 | u32 identity; | ||
| 123 | u16 table_size; | ||
| 124 | u8 fwct_version; | ||
| 125 | u8 is_key_change; | ||
| 126 | u8 guid[16]; | ||
| 127 | struct version_format base; | ||
| 128 | struct version_format app; | ||
| 129 | u8 primary_fw_digest[32]; | ||
| 130 | u32 key_exp_length; | ||
| 131 | u8 key_modulus[256]; | ||
| 132 | u8 key_exp[4]; | ||
| 133 | }; | ||
| 134 | |||
| 135 | /* CCGx response codes */ | ||
| 136 | enum ccg_resp_code { | ||
| 137 | CMD_NO_RESP = 0x00, | ||
| 138 | CMD_SUCCESS = 0x02, | ||
| 139 | FLASH_DATA_AVAILABLE = 0x03, | ||
| 140 | CMD_INVALID = 0x05, | ||
| 141 | FLASH_UPDATE_FAIL = 0x07, | ||
| 142 | INVALID_FW = 0x08, | ||
| 143 | INVALID_ARG = 0x09, | ||
| 144 | CMD_NOT_SUPPORT = 0x0A, | ||
| 145 | TRANSACTION_FAIL = 0x0C, | ||
| 146 | PD_CMD_FAIL = 0x0D, | ||
| 147 | UNDEF_ERROR = 0x0F, | ||
| 148 | INVALID_RESP = 0x10, | ||
| 149 | }; | ||
| 150 | |||
| 151 | #define CCG_EVENT_MAX (EVENT_INDEX + 43) | ||
| 152 | |||
| 153 | struct ccg_cmd { | ||
| 154 | u16 reg; | ||
| 155 | u32 data; | ||
| 156 | int len; | ||
| 157 | u32 delay; /* ms delay for cmd timeout */ | ||
| 158 | }; | ||
| 159 | |||
| 160 | struct ccg_resp { | ||
| 161 | u8 code; | ||
| 162 | u8 length; | ||
| 163 | }; | ||
| 164 | |||
| 20 | struct ucsi_ccg { | 165 | struct ucsi_ccg { |
| 21 | struct device *dev; | 166 | struct device *dev; |
| 22 | struct ucsi *ucsi; | 167 | struct ucsi *ucsi; |
| 23 | struct ucsi_ppm ppm; | 168 | struct ucsi_ppm ppm; |
| 24 | struct i2c_client *client; | 169 | struct i2c_client *client; |
| 25 | }; | 170 | struct ccg_dev_info info; |
| 171 | /* version info for boot, primary and secondary */ | ||
| 172 | struct version_info version[FW2 + 1]; | ||
| 173 | /* CCG HPI communication flags */ | ||
| 174 | unsigned long flags; | ||
| 175 | #define RESET_PENDING 0 | ||
| 176 | #define DEV_CMD_PENDING 1 | ||
| 177 | struct ccg_resp dev_resp; | ||
| 178 | u8 cmd_resp; | ||
| 179 | int port_num; | ||
| 180 | int irq; | ||
| 181 | struct work_struct work; | ||
| 182 | struct mutex lock; /* to sync between user and driver thread */ | ||
| 26 | 183 | ||
| 27 | #define CCGX_RAB_INTR_REG 0x06 | 184 | /* fw build with vendor information */ |
| 28 | #define CCGX_RAB_UCSI_CONTROL 0x39 | 185 | u16 fw_build; |
| 29 | #define CCGX_RAB_UCSI_CONTROL_START BIT(0) | 186 | }; |
| 30 | #define CCGX_RAB_UCSI_CONTROL_STOP BIT(1) | ||
| 31 | #define CCGX_RAB_UCSI_DATA_BLOCK(offset) (0xf000 | ((offset) & 0xff)) | ||
| 32 | 187 | ||
| 33 | static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len) | 188 | static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len) |
| 34 | { | 189 | { |
| @@ -220,6 +375,687 @@ static irqreturn_t ccg_irq_handler(int irq, void *data) | |||
| 220 | return IRQ_HANDLED; | 375 | return IRQ_HANDLED; |
| 221 | } | 376 | } |
| 222 | 377 | ||
| 378 | static int get_fw_info(struct ucsi_ccg *uc) | ||
| 379 | { | ||
| 380 | int err; | ||
| 381 | |||
| 382 | err = ccg_read(uc, CCGX_RAB_READ_ALL_VER, (u8 *)(&uc->version), | ||
| 383 | sizeof(uc->version)); | ||
| 384 | if (err < 0) | ||
| 385 | return err; | ||
| 386 | |||
| 387 | err = ccg_read(uc, CCGX_RAB_DEVICE_MODE, (u8 *)(&uc->info), | ||
| 388 | sizeof(uc->info)); | ||
| 389 | if (err < 0) | ||
| 390 | return err; | ||
| 391 | |||
| 392 | return 0; | ||
| 393 | } | ||
| 394 | |||
| 395 | static inline bool invalid_async_evt(int code) | ||
| 396 | { | ||
| 397 | return (code >= CCG_EVENT_MAX) || (code < EVENT_INDEX); | ||
| 398 | } | ||
| 399 | |||
| 400 | static void ccg_process_response(struct ucsi_ccg *uc) | ||
| 401 | { | ||
| 402 | struct device *dev = uc->dev; | ||
| 403 | |||
| 404 | if (uc->dev_resp.code & ASYNC_EVENT) { | ||
| 405 | if (uc->dev_resp.code == RESET_COMPLETE) { | ||
| 406 | if (test_bit(RESET_PENDING, &uc->flags)) | ||
| 407 | uc->cmd_resp = uc->dev_resp.code; | ||
| 408 | get_fw_info(uc); | ||
| 409 | } | ||
| 410 | if (invalid_async_evt(uc->dev_resp.code)) | ||
| 411 | dev_err(dev, "invalid async evt %d\n", | ||
| 412 | uc->dev_resp.code); | ||
| 413 | } else { | ||
| 414 | if (test_bit(DEV_CMD_PENDING, &uc->flags)) { | ||
| 415 | uc->cmd_resp = uc->dev_resp.code; | ||
| 416 | clear_bit(DEV_CMD_PENDING, &uc->flags); | ||
| 417 | } else { | ||
| 418 | dev_err(dev, "dev resp 0x%04x but no cmd pending\n", | ||
| 419 | uc->dev_resp.code); | ||
| 420 | } | ||
| 421 | } | ||
| 422 | } | ||
| 423 | |||
| 424 | static int ccg_read_response(struct ucsi_ccg *uc) | ||
| 425 | { | ||
| 426 | unsigned long target = jiffies + msecs_to_jiffies(1000); | ||
| 427 | struct device *dev = uc->dev; | ||
| 428 | u8 intval; | ||
| 429 | int status; | ||
| 430 | |||
| 431 | /* wait for interrupt status to get updated */ | ||
| 432 | do { | ||
| 433 | status = ccg_read(uc, CCGX_RAB_INTR_REG, &intval, | ||
| 434 | sizeof(intval)); | ||
| 435 | if (status < 0) | ||
| 436 | return status; | ||
| 437 | |||
| 438 | if (intval & DEV_INT) | ||
| 439 | break; | ||
| 440 | usleep_range(500, 600); | ||
| 441 | } while (time_is_after_jiffies(target)); | ||
| 442 | |||
| 443 | if (time_is_before_jiffies(target)) { | ||
| 444 | dev_err(dev, "response timeout error\n"); | ||
| 445 | return -ETIME; | ||
| 446 | } | ||
| 447 | |||
| 448 | status = ccg_read(uc, CCGX_RAB_RESPONSE, (u8 *)&uc->dev_resp, | ||
| 449 | sizeof(uc->dev_resp)); | ||
| 450 | if (status < 0) | ||
| 451 | return status; | ||
| 452 | |||
| 453 | status = ccg_write(uc, CCGX_RAB_INTR_REG, &intval, sizeof(intval)); | ||
| 454 | if (status < 0) | ||
| 455 | return status; | ||
| 456 | |||
| 457 | return 0; | ||
| 458 | } | ||
| 459 | |||
| 460 | /* Caller must hold uc->lock */ | ||
| 461 | static int ccg_send_command(struct ucsi_ccg *uc, struct ccg_cmd *cmd) | ||
| 462 | { | ||
| 463 | struct device *dev = uc->dev; | ||
| 464 | int ret; | ||
| 465 | |||
| 466 | switch (cmd->reg & 0xF000) { | ||
| 467 | case DEV_REG_IDX: | ||
| 468 | set_bit(DEV_CMD_PENDING, &uc->flags); | ||
| 469 | break; | ||
| 470 | default: | ||
| 471 | dev_err(dev, "invalid cmd register\n"); | ||
| 472 | break; | ||
| 473 | } | ||
| 474 | |||
| 475 | ret = ccg_write(uc, cmd->reg, (u8 *)&cmd->data, cmd->len); | ||
| 476 | if (ret < 0) | ||
| 477 | return ret; | ||
| 478 | |||
| 479 | msleep(cmd->delay); | ||
| 480 | |||
| 481 | ret = ccg_read_response(uc); | ||
| 482 | if (ret < 0) { | ||
| 483 | dev_err(dev, "response read error\n"); | ||
| 484 | switch (cmd->reg & 0xF000) { | ||
| 485 | case DEV_REG_IDX: | ||
| 486 | clear_bit(DEV_CMD_PENDING, &uc->flags); | ||
| 487 | break; | ||
| 488 | default: | ||
| 489 | dev_err(dev, "invalid cmd register\n"); | ||
| 490 | break; | ||
| 491 | } | ||
| 492 | return -EIO; | ||
| 493 | } | ||
| 494 | ccg_process_response(uc); | ||
| 495 | |||
| 496 | return uc->cmd_resp; | ||
| 497 | } | ||
| 498 | |||
| 499 | static int ccg_cmd_enter_flashing(struct ucsi_ccg *uc) | ||
| 500 | { | ||
| 501 | struct ccg_cmd cmd; | ||
| 502 | int ret; | ||
| 503 | |||
| 504 | cmd.reg = CCGX_RAB_ENTER_FLASHING; | ||
| 505 | cmd.data = FLASH_ENTER_SIG; | ||
| 506 | cmd.len = 1; | ||
| 507 | cmd.delay = 50; | ||
| 508 | |||
| 509 | mutex_lock(&uc->lock); | ||
| 510 | |||
| 511 | ret = ccg_send_command(uc, &cmd); | ||
| 512 | |||
| 513 | mutex_unlock(&uc->lock); | ||
| 514 | |||
| 515 | if (ret != CMD_SUCCESS) { | ||
| 516 | dev_err(uc->dev, "enter flashing failed ret=%d\n", ret); | ||
| 517 | return ret; | ||
| 518 | } | ||
| 519 | |||
| 520 | return 0; | ||
| 521 | } | ||
| 522 | |||
| 523 | static int ccg_cmd_reset(struct ucsi_ccg *uc) | ||
| 524 | { | ||
| 525 | struct ccg_cmd cmd; | ||
| 526 | u8 *p; | ||
| 527 | int ret; | ||
| 528 | |||
| 529 | p = (u8 *)&cmd.data; | ||
| 530 | cmd.reg = CCGX_RAB_RESET_REQ; | ||
| 531 | p[0] = RESET_SIG; | ||
| 532 | p[1] = CMD_RESET_DEV; | ||
| 533 | cmd.len = 2; | ||
| 534 | cmd.delay = 5000; | ||
| 535 | |||
| 536 | mutex_lock(&uc->lock); | ||
| 537 | |||
| 538 | set_bit(RESET_PENDING, &uc->flags); | ||
| 539 | |||
| 540 | ret = ccg_send_command(uc, &cmd); | ||
| 541 | if (ret != RESET_COMPLETE) | ||
| 542 | goto err_clear_flag; | ||
| 543 | |||
| 544 | ret = 0; | ||
| 545 | |||
| 546 | err_clear_flag: | ||
| 547 | clear_bit(RESET_PENDING, &uc->flags); | ||
| 548 | |||
| 549 | mutex_unlock(&uc->lock); | ||
| 550 | |||
| 551 | return ret; | ||
| 552 | } | ||
| 553 | |||
| 554 | static int ccg_cmd_port_control(struct ucsi_ccg *uc, bool enable) | ||
| 555 | { | ||
| 556 | struct ccg_cmd cmd; | ||
| 557 | int ret; | ||
| 558 | |||
| 559 | cmd.reg = CCGX_RAB_PDPORT_ENABLE; | ||
| 560 | if (enable) | ||
| 561 | cmd.data = (uc->port_num == 1) ? | ||
| 562 | PDPORT_1 : (PDPORT_1 | PDPORT_2); | ||
| 563 | else | ||
| 564 | cmd.data = 0x0; | ||
| 565 | cmd.len = 1; | ||
| 566 | cmd.delay = 10; | ||
| 567 | |||
| 568 | mutex_lock(&uc->lock); | ||
| 569 | |||
| 570 | ret = ccg_send_command(uc, &cmd); | ||
| 571 | |||
| 572 | mutex_unlock(&uc->lock); | ||
| 573 | |||
| 574 | if (ret != CMD_SUCCESS) { | ||
| 575 | dev_err(uc->dev, "port control failed ret=%d\n", ret); | ||
| 576 | return ret; | ||
| 577 | } | ||
| 578 | return 0; | ||
| 579 | } | ||
| 580 | |||
| 581 | static int ccg_cmd_jump_boot_mode(struct ucsi_ccg *uc, int bl_mode) | ||
| 582 | { | ||
| 583 | struct ccg_cmd cmd; | ||
| 584 | int ret; | ||
| 585 | |||
| 586 | cmd.reg = CCGX_RAB_JUMP_TO_BOOT; | ||
| 587 | |||
| 588 | if (bl_mode) | ||
| 589 | cmd.data = TO_BOOT; | ||
| 590 | else | ||
| 591 | cmd.data = TO_ALT_FW; | ||
| 592 | |||
| 593 | cmd.len = 1; | ||
| 594 | cmd.delay = 100; | ||
| 595 | |||
| 596 | mutex_lock(&uc->lock); | ||
| 597 | |||
| 598 | set_bit(RESET_PENDING, &uc->flags); | ||
| 599 | |||
| 600 | ret = ccg_send_command(uc, &cmd); | ||
| 601 | if (ret != RESET_COMPLETE) | ||
| 602 | goto err_clear_flag; | ||
| 603 | |||
| 604 | ret = 0; | ||
| 605 | |||
| 606 | err_clear_flag: | ||
| 607 | clear_bit(RESET_PENDING, &uc->flags); | ||
| 608 | |||
| 609 | mutex_unlock(&uc->lock); | ||
| 610 | |||
| 611 | return ret; | ||
| 612 | } | ||
| 613 | |||
| 614 | static int | ||
| 615 | ccg_cmd_write_flash_row(struct ucsi_ccg *uc, u16 row, | ||
| 616 | const void *data, u8 fcmd) | ||
| 617 | { | ||
| 618 | struct i2c_client *client = uc->client; | ||
| 619 | struct ccg_cmd cmd; | ||
| 620 | u8 buf[CCG4_ROW_SIZE + 2]; | ||
| 621 | u8 *p; | ||
| 622 | int ret; | ||
| 623 | |||
| 624 | /* Copy the data into the flash read/write memory. */ | ||
| 625 | put_unaligned_le16(REG_FLASH_RW_MEM, buf); | ||
| 626 | |||
| 627 | memcpy(buf + 2, data, CCG4_ROW_SIZE); | ||
| 628 | |||
| 629 | mutex_lock(&uc->lock); | ||
| 630 | |||
| 631 | ret = i2c_master_send(client, buf, CCG4_ROW_SIZE + 2); | ||
| 632 | if (ret != CCG4_ROW_SIZE + 2) { | ||
| 633 | dev_err(uc->dev, "REG_FLASH_RW_MEM write fail %d\n", ret); | ||
| 634 | mutex_unlock(&uc->lock); | ||
| 635 | return ret < 0 ? ret : -EIO; | ||
| 636 | } | ||
| 637 | |||
| 638 | /* Use the FLASH_ROW_READ_WRITE register to trigger */ | ||
| 639 | /* writing of data to the desired flash row */ | ||
| 640 | p = (u8 *)&cmd.data; | ||
| 641 | cmd.reg = CCGX_RAB_FLASH_ROW_RW; | ||
| 642 | p[0] = FLASH_SIG; | ||
| 643 | p[1] = fcmd; | ||
| 644 | put_unaligned_le16(row, &p[2]); | ||
| 645 | cmd.len = 4; | ||
| 646 | cmd.delay = 50; | ||
| 647 | if (fcmd == FLASH_FWCT_SIG_WR_CMD) | ||
| 648 | cmd.delay += 400; | ||
| 649 | if (row == 510) | ||
| 650 | cmd.delay += 220; | ||
| 651 | ret = ccg_send_command(uc, &cmd); | ||
| 652 | |||
| 653 | mutex_unlock(&uc->lock); | ||
| 654 | |||
| 655 | if (ret != CMD_SUCCESS) { | ||
| 656 | dev_err(uc->dev, "write flash row failed ret=%d\n", ret); | ||
| 657 | return ret; | ||
| 658 | } | ||
| 659 | |||
| 660 | return 0; | ||
| 661 | } | ||
| 662 | |||
| 663 | static int ccg_cmd_validate_fw(struct ucsi_ccg *uc, unsigned int fwid) | ||
| 664 | { | ||
| 665 | struct ccg_cmd cmd; | ||
| 666 | int ret; | ||
| 667 | |||
| 668 | cmd.reg = CCGX_RAB_VALIDATE_FW; | ||
| 669 | cmd.data = fwid; | ||
| 670 | cmd.len = 1; | ||
| 671 | cmd.delay = 500; | ||
| 672 | |||
| 673 | mutex_lock(&uc->lock); | ||
| 674 | |||
| 675 | ret = ccg_send_command(uc, &cmd); | ||
| 676 | |||
| 677 | mutex_unlock(&uc->lock); | ||
| 678 | |||
| 679 | if (ret != CMD_SUCCESS) | ||
| 680 | return ret; | ||
| 681 | |||
| 682 | return 0; | ||
| 683 | } | ||
| 684 | |||
| 685 | static bool ccg_check_vendor_version(struct ucsi_ccg *uc, | ||
| 686 | struct version_format *app, | ||
| 687 | struct fw_config_table *fw_cfg) | ||
| 688 | { | ||
| 689 | struct device *dev = uc->dev; | ||
| 690 | |||
| 691 | /* Check if the fw build is for supported vendors */ | ||
| 692 | if (le16_to_cpu(app->build) != uc->fw_build) { | ||
| 693 | dev_info(dev, "current fw is not from supported vendor\n"); | ||
| 694 | return false; | ||
| 695 | } | ||
| 696 | |||
| 697 | /* Check if the new fw build is for supported vendors */ | ||
| 698 | if (le16_to_cpu(fw_cfg->app.build) != uc->fw_build) { | ||
| 699 | dev_info(dev, "new fw is not from supported vendor\n"); | ||
| 700 | return false; | ||
| 701 | } | ||
| 702 | return true; | ||
| 703 | } | ||
| 704 | |||
| 705 | static bool ccg_check_fw_version(struct ucsi_ccg *uc, const char *fw_name, | ||
| 706 | struct version_format *app) | ||
| 707 | { | ||
| 708 | const struct firmware *fw = NULL; | ||
| 709 | struct device *dev = uc->dev; | ||
| 710 | struct fw_config_table fw_cfg; | ||
| 711 | u32 cur_version, new_version; | ||
| 712 | bool is_later = false; | ||
| 713 | |||
| 714 | if (request_firmware(&fw, fw_name, dev) != 0) { | ||
| 715 | dev_err(dev, "error: Failed to open cyacd file %s\n", fw_name); | ||
| 716 | return false; | ||
| 717 | } | ||
| 718 | |||
| 719 | /* | ||
| 720 | * check if signed fw | ||
| 721 | * last part of fw image is fw cfg table and signature | ||
| 722 | */ | ||
| 723 | if (fw->size < sizeof(fw_cfg) + FW_CFG_TABLE_SIG_SIZE) | ||
| 724 | goto out_release_firmware; | ||
| 725 | |||
| 726 | memcpy((uint8_t *)&fw_cfg, fw->data + fw->size - | ||
| 727 | sizeof(fw_cfg) - FW_CFG_TABLE_SIG_SIZE, sizeof(fw_cfg)); | ||
| 728 | |||
| 729 | if (fw_cfg.identity != ('F' | 'W' << 8 | 'C' << 16 | 'T' << 24)) { | ||
| 730 | dev_info(dev, "not a signed image\n"); | ||
| 731 | goto out_release_firmware; | ||
| 732 | } | ||
| 733 | |||
| 734 | /* compare input version with FWCT version */ | ||
| 735 | cur_version = le16_to_cpu(app->build) | app->patch << 16 | | ||
| 736 | app->ver << 24; | ||
| 737 | |||
| 738 | new_version = le16_to_cpu(fw_cfg.app.build) | fw_cfg.app.patch << 16 | | ||
| 739 | fw_cfg.app.ver << 24; | ||
| 740 | |||
| 741 | if (!ccg_check_vendor_version(uc, app, &fw_cfg)) | ||
| 742 | goto out_release_firmware; | ||
| 743 | |||
| 744 | if (new_version > cur_version) | ||
| 745 | is_later = true; | ||
| 746 | |||
| 747 | out_release_firmware: | ||
| 748 | release_firmware(fw); | ||
| 749 | return is_later; | ||
| 750 | } | ||
| 751 | |||
| 752 | static int ccg_fw_update_needed(struct ucsi_ccg *uc, | ||
| 753 | enum enum_flash_mode *mode) | ||
| 754 | { | ||
| 755 | struct device *dev = uc->dev; | ||
| 756 | int err; | ||
| 757 | struct version_info version[3]; | ||
| 758 | |||
| 759 | err = ccg_read(uc, CCGX_RAB_DEVICE_MODE, (u8 *)(&uc->info), | ||
| 760 | sizeof(uc->info)); | ||
| 761 | if (err) { | ||
| 762 | dev_err(dev, "read device mode failed\n"); | ||
| 763 | return err; | ||
| 764 | } | ||
| 765 | |||
| 766 | err = ccg_read(uc, CCGX_RAB_READ_ALL_VER, (u8 *)version, | ||
| 767 | sizeof(version)); | ||
| 768 | if (err) { | ||
| 769 | dev_err(dev, "read device mode failed\n"); | ||
| 770 | return err; | ||
| 771 | } | ||
| 772 | |||
| 773 | if (memcmp(&version[FW1], "\0\0\0\0\0\0\0\0", | ||
| 774 | sizeof(struct version_info)) == 0) { | ||
| 775 | dev_info(dev, "secondary fw is not flashed\n"); | ||
| 776 | *mode = SECONDARY_BL; | ||
| 777 | } else if (le16_to_cpu(version[FW1].base.build) < | ||
| 778 | secondary_fw_min_ver) { | ||
| 779 | dev_info(dev, "secondary fw version is too low (< %d)\n", | ||
| 780 | secondary_fw_min_ver); | ||
| 781 | *mode = SECONDARY; | ||
| 782 | } else if (memcmp(&version[FW2], "\0\0\0\0\0\0\0\0", | ||
| 783 | sizeof(struct version_info)) == 0) { | ||
| 784 | dev_info(dev, "primary fw is not flashed\n"); | ||
| 785 | *mode = PRIMARY; | ||
| 786 | } else if (ccg_check_fw_version(uc, ccg_fw_names[PRIMARY], | ||
| 787 | &version[FW2].app)) { | ||
| 788 | dev_info(dev, "found primary fw with later version\n"); | ||
| 789 | *mode = PRIMARY; | ||
| 790 | } else { | ||
| 791 | dev_info(dev, "secondary and primary fw are the latest\n"); | ||
| 792 | *mode = FLASH_NOT_NEEDED; | ||
| 793 | } | ||
| 794 | return 0; | ||
| 795 | } | ||
| 796 | |||
| 797 | static int do_flash(struct ucsi_ccg *uc, enum enum_flash_mode mode) | ||
| 798 | { | ||
| 799 | struct device *dev = uc->dev; | ||
| 800 | const struct firmware *fw = NULL; | ||
| 801 | const char *p, *s; | ||
| 802 | const char *eof; | ||
| 803 | int err, row, len, line_sz, line_cnt = 0; | ||
| 804 | unsigned long start_time = jiffies; | ||
| 805 | struct fw_config_table fw_cfg; | ||
| 806 | u8 fw_cfg_sig[FW_CFG_TABLE_SIG_SIZE]; | ||
| 807 | u8 *wr_buf; | ||
| 808 | |||
| 809 | err = request_firmware(&fw, ccg_fw_names[mode], dev); | ||
| 810 | if (err) { | ||
| 811 | dev_err(dev, "request %s failed err=%d\n", | ||
| 812 | ccg_fw_names[mode], err); | ||
| 813 | return err; | ||
| 814 | } | ||
| 815 | |||
| 816 | if (((uc->info.mode & CCG_DEVINFO_FWMODE_MASK) >> | ||
| 817 | CCG_DEVINFO_FWMODE_SHIFT) == FW2) { | ||
| 818 | err = ccg_cmd_port_control(uc, false); | ||
| 819 | if (err < 0) | ||
| 820 | goto release_fw; | ||
| 821 | err = ccg_cmd_jump_boot_mode(uc, 0); | ||
| 822 | if (err < 0) | ||
| 823 | goto release_fw; | ||
| 824 | } | ||
| 825 | |||
| 826 | eof = fw->data + fw->size; | ||
| 827 | |||
| 828 | /* | ||
| 829 | * check if signed fw | ||
| 830 | * last part of fw image is fw cfg table and signature | ||
| 831 | */ | ||
| 832 | if (fw->size < sizeof(fw_cfg) + sizeof(fw_cfg_sig)) | ||
| 833 | goto not_signed_fw; | ||
| 834 | |||
| 835 | memcpy((uint8_t *)&fw_cfg, fw->data + fw->size - | ||
| 836 | sizeof(fw_cfg) - sizeof(fw_cfg_sig), sizeof(fw_cfg)); | ||
| 837 | |||
| 838 | if (fw_cfg.identity != ('F' | ('W' << 8) | ('C' << 16) | ('T' << 24))) { | ||
| 839 | dev_info(dev, "not a signed image\n"); | ||
| 840 | goto not_signed_fw; | ||
| 841 | } | ||
| 842 | eof = fw->data + fw->size - sizeof(fw_cfg) - sizeof(fw_cfg_sig); | ||
| 843 | |||
| 844 | memcpy((uint8_t *)&fw_cfg_sig, | ||
| 845 | fw->data + fw->size - sizeof(fw_cfg_sig), sizeof(fw_cfg_sig)); | ||
| 846 | |||
| 847 | /* flash fw config table and signature first */ | ||
| 848 | err = ccg_cmd_write_flash_row(uc, 0, (u8 *)&fw_cfg, | ||
| 849 | FLASH_FWCT1_WR_CMD); | ||
| 850 | if (err) | ||
| 851 | goto release_fw; | ||
| 852 | |||
| 853 | err = ccg_cmd_write_flash_row(uc, 0, (u8 *)&fw_cfg + CCG4_ROW_SIZE, | ||
| 854 | FLASH_FWCT2_WR_CMD); | ||
| 855 | if (err) | ||
| 856 | goto release_fw; | ||
| 857 | |||
| 858 | err = ccg_cmd_write_flash_row(uc, 0, &fw_cfg_sig, | ||
| 859 | FLASH_FWCT_SIG_WR_CMD); | ||
| 860 | if (err) | ||
| 861 | goto release_fw; | ||
| 862 | |||
| 863 | not_signed_fw: | ||
| 864 | wr_buf = kzalloc(CCG4_ROW_SIZE + 4, GFP_KERNEL); | ||
| 865 | if (!wr_buf) | ||
| 866 | return -ENOMEM; | ||
| 867 | |||
| 868 | err = ccg_cmd_enter_flashing(uc); | ||
| 869 | if (err) | ||
| 870 | goto release_mem; | ||
| 871 | |||
| 872 | /***************************************************************** | ||
| 873 | * CCG firmware image (.cyacd) file line format | ||
| 874 | * | ||
| 875 | * :00rrrrllll[dd....]cc/r/n | ||
| 876 | * | ||
| 877 | * :00 header | ||
| 878 | * rrrr is row number to flash (4 char) | ||
| 879 | * llll is data len to flash (4 char) | ||
| 880 | * dd is a data field represents one byte of data (512 char) | ||
| 881 | * cc is checksum (2 char) | ||
| 882 | * \r\n newline | ||
| 883 | * | ||
| 884 | * Total length: 3 + 4 + 4 + 512 + 2 + 2 = 527 | ||
| 885 | * | ||
| 886 | *****************************************************************/ | ||
| 887 | |||
| 888 | p = strnchr(fw->data, fw->size, ':'); | ||
| 889 | while (p < eof) { | ||
| 890 | s = strnchr(p + 1, eof - p - 1, ':'); | ||
| 891 | |||
| 892 | if (!s) | ||
| 893 | s = eof; | ||
| 894 | |||
| 895 | line_sz = s - p; | ||
| 896 | |||
| 897 | if (line_sz != CYACD_LINE_SIZE) { | ||
| 898 | dev_err(dev, "Bad FW format line_sz=%d\n", line_sz); | ||
| 899 | err = -EINVAL; | ||
| 900 | goto release_mem; | ||
| 901 | } | ||
| 902 | |||
| 903 | if (hex2bin(wr_buf, p + 3, CCG4_ROW_SIZE + 4)) { | ||
| 904 | err = -EINVAL; | ||
| 905 | goto release_mem; | ||
| 906 | } | ||
| 907 | |||
| 908 | row = get_unaligned_be16(wr_buf); | ||
| 909 | len = get_unaligned_be16(&wr_buf[2]); | ||
| 910 | |||
| 911 | if (len != CCG4_ROW_SIZE) { | ||
| 912 | err = -EINVAL; | ||
| 913 | goto release_mem; | ||
| 914 | } | ||
| 915 | |||
| 916 | err = ccg_cmd_write_flash_row(uc, row, wr_buf + 4, | ||
| 917 | FLASH_WR_CMD); | ||
| 918 | if (err) | ||
| 919 | goto release_mem; | ||
| 920 | |||
| 921 | line_cnt++; | ||
| 922 | p = s; | ||
| 923 | } | ||
| 924 | |||
| 925 | dev_info(dev, "total %d row flashed. time: %dms\n", | ||
| 926 | line_cnt, jiffies_to_msecs(jiffies - start_time)); | ||
| 927 | |||
| 928 | err = ccg_cmd_validate_fw(uc, (mode == PRIMARY) ? FW2 : FW1); | ||
| 929 | if (err) | ||
| 930 | dev_err(dev, "%s validation failed err=%d\n", | ||
| 931 | (mode == PRIMARY) ? "FW2" : "FW1", err); | ||
| 932 | else | ||
| 933 | dev_info(dev, "%s validated\n", | ||
| 934 | (mode == PRIMARY) ? "FW2" : "FW1"); | ||
| 935 | |||
| 936 | err = ccg_cmd_port_control(uc, false); | ||
| 937 | if (err < 0) | ||
| 938 | goto release_mem; | ||
| 939 | |||
| 940 | err = ccg_cmd_reset(uc); | ||
| 941 | if (err < 0) | ||
| 942 | goto release_mem; | ||
| 943 | |||
| 944 | err = ccg_cmd_port_control(uc, true); | ||
| 945 | if (err < 0) | ||
| 946 | goto release_mem; | ||
| 947 | |||
| 948 | release_mem: | ||
| 949 | kfree(wr_buf); | ||
| 950 | |||
| 951 | release_fw: | ||
| 952 | release_firmware(fw); | ||
| 953 | return err; | ||
| 954 | } | ||
| 955 | |||
| 956 | /******************************************************************************* | ||
| 957 | * CCG4 has two copies of the firmware in addition to the bootloader. | ||
| 958 | * If the device is running FW1, FW2 can be updated with the new version. | ||
| 959 | * Dual firmware mode allows the CCG device to stay in a PD contract and support | ||
| 960 | * USB PD and Type-C functionality while a firmware update is in progress. | ||
| 961 | ******************************************************************************/ | ||
| 962 | static int ccg_fw_update(struct ucsi_ccg *uc, enum enum_flash_mode flash_mode) | ||
| 963 | { | ||
| 964 | int err; | ||
| 965 | |||
| 966 | while (flash_mode != FLASH_NOT_NEEDED) { | ||
| 967 | err = do_flash(uc, flash_mode); | ||
| 968 | if (err < 0) | ||
| 969 | return err; | ||
| 970 | err = ccg_fw_update_needed(uc, &flash_mode); | ||
| 971 | if (err < 0) | ||
| 972 | return err; | ||
| 973 | } | ||
| 974 | dev_info(uc->dev, "CCG FW update successful\n"); | ||
| 975 | |||
| 976 | return err; | ||
| 977 | } | ||
| 978 | |||
| 979 | static int ccg_restart(struct ucsi_ccg *uc) | ||
| 980 | { | ||
| 981 | struct device *dev = uc->dev; | ||
| 982 | int status; | ||
| 983 | |||
| 984 | status = ucsi_ccg_init(uc); | ||
| 985 | if (status < 0) { | ||
| 986 | dev_err(dev, "ucsi_ccg_start fail, err=%d\n", status); | ||
| 987 | return status; | ||
| 988 | } | ||
| 989 | |||
| 990 | status = request_threaded_irq(uc->irq, NULL, ccg_irq_handler, | ||
| 991 | IRQF_ONESHOT | IRQF_TRIGGER_HIGH, | ||
| 992 | dev_name(dev), uc); | ||
| 993 | if (status < 0) { | ||
| 994 | dev_err(dev, "request_threaded_irq failed - %d\n", status); | ||
| 995 | return status; | ||
| 996 | } | ||
| 997 | |||
| 998 | uc->ucsi = ucsi_register_ppm(dev, &uc->ppm); | ||
| 999 | if (IS_ERR(uc->ucsi)) { | ||
| 1000 | dev_err(uc->dev, "ucsi_register_ppm failed\n"); | ||
| 1001 | return PTR_ERR(uc->ucsi); | ||
| 1002 | } | ||
| 1003 | |||
| 1004 | return 0; | ||
| 1005 | } | ||
| 1006 | |||
| 1007 | static void ccg_update_firmware(struct work_struct *work) | ||
| 1008 | { | ||
| 1009 | struct ucsi_ccg *uc = container_of(work, struct ucsi_ccg, work); | ||
| 1010 | enum enum_flash_mode flash_mode; | ||
| 1011 | int status; | ||
| 1012 | |||
| 1013 | status = ccg_fw_update_needed(uc, &flash_mode); | ||
| 1014 | if (status < 0) | ||
| 1015 | return; | ||
| 1016 | |||
| 1017 | if (flash_mode != FLASH_NOT_NEEDED) { | ||
| 1018 | ucsi_unregister_ppm(uc->ucsi); | ||
| 1019 | free_irq(uc->irq, uc); | ||
| 1020 | |||
| 1021 | ccg_fw_update(uc, flash_mode); | ||
| 1022 | ccg_restart(uc); | ||
| 1023 | } | ||
| 1024 | } | ||
| 1025 | |||
| 1026 | static ssize_t do_flash_store(struct device *dev, | ||
| 1027 | struct device_attribute *attr, | ||
| 1028 | const char *buf, size_t n) | ||
| 1029 | { | ||
| 1030 | struct ucsi_ccg *uc = i2c_get_clientdata(to_i2c_client(dev)); | ||
| 1031 | bool flash; | ||
| 1032 | |||
| 1033 | if (kstrtobool(buf, &flash)) | ||
| 1034 | return -EINVAL; | ||
| 1035 | |||
| 1036 | if (!flash) | ||
| 1037 | return n; | ||
| 1038 | |||
| 1039 | if (uc->fw_build == 0x0) { | ||
| 1040 | dev_err(dev, "fail to flash FW due to missing FW build info\n"); | ||
| 1041 | return -EINVAL; | ||
| 1042 | } | ||
| 1043 | |||
| 1044 | schedule_work(&uc->work); | ||
| 1045 | return n; | ||
| 1046 | } | ||
| 1047 | |||
| 1048 | static DEVICE_ATTR_WO(do_flash); | ||
| 1049 | |||
| 1050 | static struct attribute *ucsi_ccg_sysfs_attrs[] = { | ||
| 1051 | &dev_attr_do_flash.attr, | ||
| 1052 | NULL, | ||
| 1053 | }; | ||
| 1054 | |||
| 1055 | static struct attribute_group ucsi_ccg_attr_group = { | ||
| 1056 | .attrs = ucsi_ccg_sysfs_attrs, | ||
| 1057 | }; | ||
| 1058 | |||
| 223 | static int ucsi_ccg_probe(struct i2c_client *client, | 1059 | static int ucsi_ccg_probe(struct i2c_client *client, |
| 224 | const struct i2c_device_id *id) | 1060 | const struct i2c_device_id *id) |
| 225 | { | 1061 | { |
| @@ -240,6 +1076,14 @@ static int ucsi_ccg_probe(struct i2c_client *client, | |||
| 240 | uc->ppm.sync = ucsi_ccg_sync; | 1076 | uc->ppm.sync = ucsi_ccg_sync; |
| 241 | uc->dev = dev; | 1077 | uc->dev = dev; |
| 242 | uc->client = client; | 1078 | uc->client = client; |
| 1079 | mutex_init(&uc->lock); | ||
| 1080 | INIT_WORK(&uc->work, ccg_update_firmware); | ||
| 1081 | |||
| 1082 | /* Only fail FW flashing when FW build information is not provided */ | ||
| 1083 | status = device_property_read_u16(dev, "ccgx,firmware-build", | ||
| 1084 | &uc->fw_build); | ||
| 1085 | if (status) | ||
| 1086 | dev_err(uc->dev, "failed to get FW build information\n"); | ||
| 243 | 1087 | ||
| 244 | /* reset ccg device and initialize ucsi */ | 1088 | /* reset ccg device and initialize ucsi */ |
| 245 | status = ucsi_ccg_init(uc); | 1089 | status = ucsi_ccg_init(uc); |
| @@ -248,15 +1092,27 @@ static int ucsi_ccg_probe(struct i2c_client *client, | |||
| 248 | return status; | 1092 | return status; |
| 249 | } | 1093 | } |
| 250 | 1094 | ||
| 251 | status = devm_request_threaded_irq(dev, client->irq, NULL, | 1095 | status = get_fw_info(uc); |
| 252 | ccg_irq_handler, | 1096 | if (status < 0) { |
| 253 | IRQF_ONESHOT | IRQF_TRIGGER_HIGH, | 1097 | dev_err(uc->dev, "get_fw_info failed - %d\n", status); |
| 254 | dev_name(dev), uc); | 1098 | return status; |
| 1099 | } | ||
| 1100 | |||
| 1101 | uc->port_num = 1; | ||
| 1102 | |||
| 1103 | if (uc->info.mode & CCG_DEVINFO_PDPORTS_MASK) | ||
| 1104 | uc->port_num++; | ||
| 1105 | |||
| 1106 | status = request_threaded_irq(client->irq, NULL, ccg_irq_handler, | ||
| 1107 | IRQF_ONESHOT | IRQF_TRIGGER_HIGH, | ||
| 1108 | dev_name(dev), uc); | ||
| 255 | if (status < 0) { | 1109 | if (status < 0) { |
| 256 | dev_err(uc->dev, "request_threaded_irq failed - %d\n", status); | 1110 | dev_err(uc->dev, "request_threaded_irq failed - %d\n", status); |
| 257 | return status; | 1111 | return status; |
| 258 | } | 1112 | } |
| 259 | 1113 | ||
| 1114 | uc->irq = client->irq; | ||
| 1115 | |||
| 260 | uc->ucsi = ucsi_register_ppm(dev, &uc->ppm); | 1116 | uc->ucsi = ucsi_register_ppm(dev, &uc->ppm); |
| 261 | if (IS_ERR(uc->ucsi)) { | 1117 | if (IS_ERR(uc->ucsi)) { |
| 262 | dev_err(uc->dev, "ucsi_register_ppm failed\n"); | 1118 | dev_err(uc->dev, "ucsi_register_ppm failed\n"); |
| @@ -273,6 +1129,11 @@ static int ucsi_ccg_probe(struct i2c_client *client, | |||
| 273 | } | 1129 | } |
| 274 | 1130 | ||
| 275 | i2c_set_clientdata(client, uc); | 1131 | i2c_set_clientdata(client, uc); |
| 1132 | |||
| 1133 | status = sysfs_create_group(&uc->dev->kobj, &ucsi_ccg_attr_group); | ||
| 1134 | if (status) | ||
| 1135 | dev_err(uc->dev, "cannot create sysfs group: %d\n", status); | ||
| 1136 | |||
| 276 | return 0; | 1137 | return 0; |
| 277 | } | 1138 | } |
| 278 | 1139 | ||
| @@ -280,7 +1141,10 @@ static int ucsi_ccg_remove(struct i2c_client *client) | |||
| 280 | { | 1141 | { |
| 281 | struct ucsi_ccg *uc = i2c_get_clientdata(client); | 1142 | struct ucsi_ccg *uc = i2c_get_clientdata(client); |
| 282 | 1143 | ||
| 1144 | cancel_work_sync(&uc->work); | ||
| 283 | ucsi_unregister_ppm(uc->ucsi); | 1145 | ucsi_unregister_ppm(uc->ucsi); |
| 1146 | free_irq(uc->irq, uc); | ||
| 1147 | sysfs_remove_group(&uc->dev->kobj, &ucsi_ccg_attr_group); | ||
| 284 | 1148 | ||
| 285 | return 0; | 1149 | return 0; |
| 286 | } | 1150 | } |
diff --git a/drivers/usb/usbip/stub_rx.c b/drivers/usb/usbip/stub_rx.c index dbfb2f24d71e..b0a855acafa3 100644 --- a/drivers/usb/usbip/stub_rx.c +++ b/drivers/usb/usbip/stub_rx.c | |||
| @@ -17,9 +17,9 @@ static int is_clear_halt_cmd(struct urb *urb) | |||
| 17 | 17 | ||
| 18 | req = (struct usb_ctrlrequest *) urb->setup_packet; | 18 | req = (struct usb_ctrlrequest *) urb->setup_packet; |
| 19 | 19 | ||
| 20 | return (req->bRequest == USB_REQ_CLEAR_FEATURE) && | 20 | return (req->bRequest == USB_REQ_CLEAR_FEATURE) && |
| 21 | (req->bRequestType == USB_RECIP_ENDPOINT) && | 21 | (req->bRequestType == USB_RECIP_ENDPOINT) && |
| 22 | (req->wValue == USB_ENDPOINT_HALT); | 22 | (req->wValue == USB_ENDPOINT_HALT); |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | static int is_set_interface_cmd(struct urb *urb) | 25 | static int is_set_interface_cmd(struct urb *urb) |
diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c index f46ee1fefe02..000ab7225717 100644 --- a/drivers/usb/usbip/vhci_hcd.c +++ b/drivers/usb/usbip/vhci_hcd.c | |||
| @@ -508,6 +508,7 @@ static int vhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
| 508 | case USB_PORT_FEAT_U1_TIMEOUT: | 508 | case USB_PORT_FEAT_U1_TIMEOUT: |
| 509 | usbip_dbg_vhci_rh( | 509 | usbip_dbg_vhci_rh( |
| 510 | " SetPortFeature: USB_PORT_FEAT_U1_TIMEOUT\n"); | 510 | " SetPortFeature: USB_PORT_FEAT_U1_TIMEOUT\n"); |
| 511 | /* Fall through */ | ||
| 511 | case USB_PORT_FEAT_U2_TIMEOUT: | 512 | case USB_PORT_FEAT_U2_TIMEOUT: |
| 512 | usbip_dbg_vhci_rh( | 513 | usbip_dbg_vhci_rh( |
| 513 | " SetPortFeature: USB_PORT_FEAT_U2_TIMEOUT\n"); | 514 | " SetPortFeature: USB_PORT_FEAT_U2_TIMEOUT\n"); |
| @@ -654,15 +655,9 @@ error: | |||
| 654 | static void vhci_tx_urb(struct urb *urb, struct vhci_device *vdev) | 655 | static void vhci_tx_urb(struct urb *urb, struct vhci_device *vdev) |
| 655 | { | 656 | { |
| 656 | struct vhci_priv *priv; | 657 | struct vhci_priv *priv; |
| 657 | struct vhci_hcd *vhci_hcd; | 658 | struct vhci_hcd *vhci_hcd = vdev_to_vhci_hcd(vdev); |
| 658 | unsigned long flags; | 659 | unsigned long flags; |
| 659 | 660 | ||
| 660 | if (!vdev) { | ||
| 661 | pr_err("could not get virtual device"); | ||
| 662 | return; | ||
| 663 | } | ||
| 664 | vhci_hcd = vdev_to_vhci_hcd(vdev); | ||
| 665 | |||
| 666 | priv = kzalloc(sizeof(struct vhci_priv), GFP_ATOMIC); | 661 | priv = kzalloc(sizeof(struct vhci_priv), GFP_ATOMIC); |
| 667 | if (!priv) { | 662 | if (!priv) { |
| 668 | usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_MALLOC); | 663 | usbip_event_add(&vdev->ud, VDEV_EVENT_ERROR_MALLOC); |
diff --git a/include/dt-bindings/phy/phy-am654-serdes.h b/include/dt-bindings/phy/phy-am654-serdes.h new file mode 100644 index 000000000000..e8d901729ed9 --- /dev/null +++ b/include/dt-bindings/phy/phy-am654-serdes.h | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
| 2 | /* | ||
| 3 | * This header provides constants for AM654 SERDES. | ||
| 4 | */ | ||
| 5 | |||
| 6 | #ifndef _DT_BINDINGS_AM654_SERDES | ||
| 7 | #define _DT_BINDINGS_AM654_SERDES | ||
| 8 | |||
| 9 | #define AM654_SERDES_CMU_REFCLK 0 | ||
| 10 | #define AM654_SERDES_LO_REFCLK 1 | ||
| 11 | #define AM654_SERDES_RO_REFCLK 2 | ||
| 12 | |||
| 13 | #endif /* _DT_BINDINGS_AM654_SERDES */ | ||
diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h index 3f350e2749fe..ef13aea1d370 100644 --- a/include/linux/phy/phy.h +++ b/include/linux/phy/phy.h | |||
| @@ -64,6 +64,7 @@ union phy_configure_opts { | |||
| 64 | * @set_mode: set the mode of the phy | 64 | * @set_mode: set the mode of the phy |
| 65 | * @reset: resetting the phy | 65 | * @reset: resetting the phy |
| 66 | * @calibrate: calibrate the phy | 66 | * @calibrate: calibrate the phy |
| 67 | * @release: ops to be performed while the consumer relinquishes the PHY | ||
| 67 | * @owner: the module owner containing the ops | 68 | * @owner: the module owner containing the ops |
| 68 | */ | 69 | */ |
| 69 | struct phy_ops { | 70 | struct phy_ops { |
| @@ -105,6 +106,7 @@ struct phy_ops { | |||
| 105 | union phy_configure_opts *opts); | 106 | union phy_configure_opts *opts); |
| 106 | int (*reset)(struct phy *phy); | 107 | int (*reset)(struct phy *phy); |
| 107 | int (*calibrate)(struct phy *phy); | 108 | int (*calibrate)(struct phy *phy); |
| 109 | void (*release)(struct phy *phy); | ||
| 108 | struct module *owner; | 110 | struct module *owner; |
| 109 | }; | 111 | }; |
| 110 | 112 | ||
diff --git a/include/linux/usb.h b/include/linux/usb.h index ff010d1fd1c7..ae82d9d1112b 100644 --- a/include/linux/usb.h +++ b/include/linux/usb.h | |||
| @@ -1543,10 +1543,10 @@ typedef void (*usb_complete_t)(struct urb *); | |||
| 1543 | struct urb { | 1543 | struct urb { |
| 1544 | /* private: usb core and host controller only fields in the urb */ | 1544 | /* private: usb core and host controller only fields in the urb */ |
| 1545 | struct kref kref; /* reference count of the URB */ | 1545 | struct kref kref; /* reference count of the URB */ |
| 1546 | int unlinked; /* unlink error code */ | ||
| 1546 | void *hcpriv; /* private data for host controller */ | 1547 | void *hcpriv; /* private data for host controller */ |
| 1547 | atomic_t use_count; /* concurrent submissions counter */ | 1548 | atomic_t use_count; /* concurrent submissions counter */ |
| 1548 | atomic_t reject; /* submissions will fail */ | 1549 | atomic_t reject; /* submissions will fail */ |
| 1549 | int unlinked; /* unlink error code */ | ||
| 1550 | 1550 | ||
| 1551 | /* public: documented fields in the urb that can be used by drivers */ | 1551 | /* public: documented fields in the urb that can be used by drivers */ |
| 1552 | struct list_head urb_list; /* list head for use by the urb's | 1552 | struct list_head urb_list; /* list head for use by the urb's |
diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h index 523aa088f6ab..da82606be605 100644 --- a/include/linux/usb/ch9.h +++ b/include/linux/usb/ch9.h | |||
| @@ -37,6 +37,14 @@ | |||
| 37 | #include <uapi/linux/usb/ch9.h> | 37 | #include <uapi/linux/usb/ch9.h> |
| 38 | 38 | ||
| 39 | /** | 39 | /** |
| 40 | * usb_ep_type_string() - Returns human readable-name of the endpoint type. | ||
| 41 | * @ep_type: The endpoint type to return human-readable name for. If it's not | ||
| 42 | * any of the types: USB_ENDPOINT_XFER_{CONTROL, ISOC, BULK, INT}, | ||
| 43 | * usually got by usb_endpoint_type(), the string 'unknown' will be returned. | ||
| 44 | */ | ||
| 45 | extern const char *usb_ep_type_string(int ep_type); | ||
| 46 | |||
| 47 | /** | ||
| 40 | * usb_speed_string() - Returns human readable-name of the speed. | 48 | * usb_speed_string() - Returns human readable-name of the speed. |
| 41 | * @speed: The speed to return human-readable name for. If it's not | 49 | * @speed: The speed to return human-readable name for. If it's not |
| 42 | * any of the speeds defined in usb_device_speed enum, string for | 50 | * any of the speeds defined in usb_device_speed enum, string for |
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index 695931b03684..bb57b5af4700 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h | |||
| @@ -98,6 +98,7 @@ struct usb_hcd { | |||
| 98 | #ifdef CONFIG_PM | 98 | #ifdef CONFIG_PM |
| 99 | struct work_struct wakeup_work; /* for remote wakeup */ | 99 | struct work_struct wakeup_work; /* for remote wakeup */ |
| 100 | #endif | 100 | #endif |
| 101 | struct work_struct died_work; /* for when the device dies */ | ||
| 101 | 102 | ||
| 102 | /* | 103 | /* |
| 103 | * hardware info/state | 104 | * hardware info/state |
| @@ -652,11 +653,16 @@ extern wait_queue_head_t usb_kill_urb_queue; | |||
| 652 | #define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN)) | 653 | #define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN)) |
| 653 | 654 | ||
| 654 | #ifdef CONFIG_PM | 655 | #ifdef CONFIG_PM |
| 656 | extern unsigned usb_wakeup_enabled_descendants(struct usb_device *udev); | ||
| 655 | extern void usb_root_hub_lost_power(struct usb_device *rhdev); | 657 | extern void usb_root_hub_lost_power(struct usb_device *rhdev); |
| 656 | extern int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg); | 658 | extern int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg); |
| 657 | extern int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg); | 659 | extern int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg); |
| 658 | extern void usb_hcd_resume_root_hub(struct usb_hcd *hcd); | 660 | extern void usb_hcd_resume_root_hub(struct usb_hcd *hcd); |
| 659 | #else | 661 | #else |
| 662 | static inline unsigned usb_wakeup_enabled_descendants(struct usb_device *udev) | ||
| 663 | { | ||
| 664 | return 0; | ||
| 665 | } | ||
| 660 | static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd) | 666 | static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd) |
| 661 | { | 667 | { |
| 662 | return; | 668 | return; |
diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index 1c19f77ed541..14cac4a1ae8f 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h | |||
| @@ -23,11 +23,9 @@ | |||
| 23 | /* The maximum number of ports one device can grab at once */ | 23 | /* The maximum number of ports one device can grab at once */ |
| 24 | #define MAX_NUM_PORTS 16 | 24 | #define MAX_NUM_PORTS 16 |
| 25 | 25 | ||
| 26 | /* parity check flag */ | ||
| 27 | #define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) | ||
| 28 | |||
| 29 | /* USB serial flags */ | 26 | /* USB serial flags */ |
| 30 | #define USB_SERIAL_WRITE_BUSY 0 | 27 | #define USB_SERIAL_WRITE_BUSY 0 |
| 28 | #define USB_SERIAL_THROTTLED 1 | ||
| 31 | 29 | ||
| 32 | /** | 30 | /** |
| 33 | * usb_serial_port: structure for the specific ports of a device. | 31 | * usb_serial_port: structure for the specific ports of a device. |
| @@ -67,8 +65,6 @@ | |||
| 67 | * @flags: usb serial port flags | 65 | * @flags: usb serial port flags |
| 68 | * @write_wait: a wait_queue_head_t used by the port. | 66 | * @write_wait: a wait_queue_head_t used by the port. |
| 69 | * @work: work queue entry for the line discipline waking up. | 67 | * @work: work queue entry for the line discipline waking up. |
| 70 | * @throttled: nonzero if the read urb is inactive to throttle the device | ||
| 71 | * @throttle_req: nonzero if the tty wants to throttle us | ||
| 72 | * @dev: pointer to the serial device | 68 | * @dev: pointer to the serial device |
| 73 | * | 69 | * |
| 74 | * This structure is used by the usb-serial core and drivers for the specific | 70 | * This structure is used by the usb-serial core and drivers for the specific |
| @@ -115,8 +111,6 @@ struct usb_serial_port { | |||
| 115 | unsigned long flags; | 111 | unsigned long flags; |
| 116 | wait_queue_head_t write_wait; | 112 | wait_queue_head_t write_wait; |
| 117 | struct work_struct work; | 113 | struct work_struct work; |
| 118 | char throttled; | ||
| 119 | char throttle_req; | ||
| 120 | unsigned long sysrq; /* sysrq timeout */ | 114 | unsigned long sysrq; /* sysrq timeout */ |
| 121 | struct device dev; | 115 | struct device dev; |
| 122 | }; | 116 | }; |
diff --git a/include/linux/usb/tcpm.h b/include/linux/usb/tcpm.h index 0c532ca3f079..36a15dcadc53 100644 --- a/include/linux/usb/tcpm.h +++ b/include/linux/usb/tcpm.h | |||
| @@ -121,10 +121,10 @@ struct tcpc_config { | |||
| 121 | * with partner. | 121 | * with partner. |
| 122 | * @set_pd_rx: Called to enable or disable reception of PD messages | 122 | * @set_pd_rx: Called to enable or disable reception of PD messages |
| 123 | * @set_roles: Called to set power and data roles | 123 | * @set_roles: Called to set power and data roles |
| 124 | * @start_drp_toggling: | 124 | * @start_toggling: |
| 125 | * Optional; if supported by hardware, called to start DRP | 125 | * Optional; if supported by hardware, called to start dual-role |
| 126 | * toggling. DRP toggling is stopped automatically if | 126 | * toggling or single-role connection detection. Toggling stops |
| 127 | * a connection is established. | 127 | * automatically if a connection is established. |
| 128 | * @try_role: Optional; called to set a preferred role | 128 | * @try_role: Optional; called to set a preferred role |
| 129 | * @pd_transmit:Called to transmit PD message | 129 | * @pd_transmit:Called to transmit PD message |
| 130 | * @mux: Pointer to multiplexer data | 130 | * @mux: Pointer to multiplexer data |
| @@ -147,8 +147,9 @@ struct tcpc_dev { | |||
| 147 | int (*set_pd_rx)(struct tcpc_dev *dev, bool on); | 147 | int (*set_pd_rx)(struct tcpc_dev *dev, bool on); |
| 148 | int (*set_roles)(struct tcpc_dev *dev, bool attached, | 148 | int (*set_roles)(struct tcpc_dev *dev, bool attached, |
| 149 | enum typec_role role, enum typec_data_role data); | 149 | enum typec_role role, enum typec_data_role data); |
| 150 | int (*start_drp_toggling)(struct tcpc_dev *dev, | 150 | int (*start_toggling)(struct tcpc_dev *dev, |
| 151 | enum typec_cc_status cc); | 151 | enum typec_port_type port_type, |
| 152 | enum typec_cc_status cc); | ||
| 152 | int (*try_role)(struct tcpc_dev *dev, int role); | 153 | int (*try_role)(struct tcpc_dev *dev, int role); |
| 153 | int (*pd_transmit)(struct tcpc_dev *dev, enum tcpm_transmit_type type, | 154 | int (*pd_transmit)(struct tcpc_dev *dev, enum tcpm_transmit_type type, |
| 154 | const struct pd_message *msg); | 155 | const struct pd_message *msg); |
diff --git a/include/linux/usb/typec_dp.h b/include/linux/usb/typec_dp.h index 7fa12ef8d09a..fc4c7edb2e8a 100644 --- a/include/linux/usb/typec_dp.h +++ b/include/linux/usb/typec_dp.h | |||
| @@ -5,6 +5,11 @@ | |||
| 5 | #include <linux/usb/typec_altmode.h> | 5 | #include <linux/usb/typec_altmode.h> |
| 6 | 6 | ||
| 7 | #define USB_TYPEC_DP_SID 0xff01 | 7 | #define USB_TYPEC_DP_SID 0xff01 |
| 8 | /* USB IF has not assigned a Standard ID (SID) for VirtualLink, | ||
| 9 | * so the manufacturers of VirtualLink adapters use their Vendor | ||
| 10 | * IDs as the SVID. | ||
| 11 | */ | ||
| 12 | #define USB_TYPEC_NVIDIA_VLINK_SID 0x955 /* NVIDIA VirtualLink */ | ||
| 8 | #define USB_TYPEC_DP_MODE 1 | 13 | #define USB_TYPEC_DP_MODE 1 |
| 9 | 14 | ||
| 10 | /* | 15 | /* |
