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 | /* |