mirror of
https://github.com/torvalds/linux.git
synced 2024-11-27 22:51:35 +00:00
phy-for-5.18
- New support: - Mediatek tphy support for MT8186 - Qualcomm usb phy support for sc8180x and sc8280xp - Qualcomm ufs phy support for sc8180x and sc8280xp - Qualcomm usb phy support for MSM8953 - Cadence D-Phy Rx support - Sun4i support for USB phy - Rockchip naneng combo phy support for RK3568 - Qualcomm eDP PHY for sc7280 - Updates: - wake on support for Synopsis XHCI controllers - Yamilify Qualcomm USB HS phy binding - Charger detection support for TI tusb1210 -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE+vs47OPLdNbVcHzyfBQHDyUjg0cFAmIiS0UACgkQfBQHDyUj g0fpBhAAnopGBDvSqj4caFh8u4gWhtHPqOj/7rHKfCTXYyUWjgSqoDTfgBC+jAhd EDUBoQf0RpxWUdv5WKoS8c2ldI9synz0HmeSSxkUZOE8zwsQ7G248zz9o7cIuBOd 19mZnRVhLfNfmiwFEQcOHGslI2r0JjIE6JWlRn0P32pizSOeFVXtxAA0z1HvDK5O iKD/taMMvRQ7PWk4V25kluLtFHe5FwlHd8D68Xb8m7CdIARqxDr8x89VcQ2xp5SN KcN4fL5CdX5Db5EaSa47zoNRjBg+4STWIEvvSGqaTFYaIr3oDb8t5q5/IqoTQoFu qBC0fKRv0f95DxK3w1eE1471edS6piVGCEpj4gC5cSbdkZHuMg//qyiDVvGsWX1j y7/fprKxMzFIieeUvo5bYyFRG8k92KcYLiiH11TirY4n3GvBIZXkCfsAqL0nunvq OCq0WIu38qZn9mKTbsSGVqDvlxhGlJQ/AvozapePFMiO9XzVw8lYXeRKNrtbVLNS HlqmnPMFEUtM3VEE8pzjNR6w+/Ru5YDAhYpwzVsyroLIiLsQm0Q7ABE3UZ+QW3HE mnUvrA9HqcFaIg8HdwEOgw5gPTP6xrnhid/gXr5wqwmxXQ14YUgo9ry3djDdv/kO WjqrjF0kMgHDadNzUMpD66GOfKCWNO8ZLVlCxPVEceBemPhsyyQ= =8baK -----END PGP SIGNATURE----- Merge tag 'phy-for-5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy into char-misc-next Vinod writes: phy-for-5.18 - New support: - Mediatek tphy support for MT8186 - Qualcomm usb phy support for sc8180x and sc8280xp - Qualcomm ufs phy support for sc8180x and sc8280xp - Qualcomm usb phy support for MSM8953 - Cadence D-Phy Rx support - Sun4i support for USB phy - Rockchip naneng combo phy support for RK3568 - Qualcomm eDP PHY for sc7280 - Updates: - wake on support for Synopsis XHCI controllers - Yamilify Qualcomm USB HS phy binding - Charger detection support for TI tusb1210 * tag 'phy-for-5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/phy/linux-phy: (53 commits) phy: qcom-qmp: add sc8280xp UFS PHY dt-bindings: phy: qcom,qmp: add sc8180x and sc8280xp ufs compatibles phy: qcom-snps: Add sc8280xp support dt-bindings: phy: qcom,usb-snps-femto-v2: Add sc8180x and sc8280xp dt-bindings: Revert "dt-bindings: soc: grf: add naneng combo phy register compatible" phy: dt-bindings: Add Cadence D-PHY Rx bindings phy: dt-bindings: cdns,dphy: add power-domains property phy: dt-bindings: Convert Cadence DPHY binding to YAML phy: cadence: Add Cadence D-PHY Rx driver dt-bindings: phy: renesas,usb2-phy: Document RZ/V2L phy bindings Revert "PCI: aardvark: Fix initialization with old Marvell's Arm Trusted Firmware" Revert "usb: host: xhci: mvebu: make USB 3.0 PHY optional for Armada 3720" Revert "ata: ahci: mvebu: Make SATA PHY optional for Armada 3720" phy: marvell: phy-mvebu-a3700-comphy: Add native kernel implementation phy: marvell: phy-mvebu-a3700-comphy: Remove port from driver configuration phy: phy-brcm-usb: fixup BCM4908 support dt-bindings: phy: mediatek,tphy: Add compatible for MT8192 phy: ti: tusb1210: Add charger detection phy: ti: tusb1210: Add a delay between power-on and restoring the phy-parameters phy: ti: tusb1210: Drop tusb->vendor_specific2 != 0 check from tusb1210_power_on() ...
This commit is contained in:
commit
9edcfaa349
@ -15,7 +15,9 @@ properties:
|
||||
const: 1
|
||||
|
||||
compatible:
|
||||
const: allwinner,sun50i-a64-usb-phy
|
||||
enum:
|
||||
- allwinner,sun20i-d1-usb-phy
|
||||
- allwinner,sun50i-a64-usb-phy
|
||||
|
||||
reg:
|
||||
items:
|
||||
|
42
Documentation/devicetree/bindings/phy/cdns,dphy-rx.yaml
Normal file
42
Documentation/devicetree/bindings/phy/cdns,dphy-rx.yaml
Normal file
@ -0,0 +1,42 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/cdns,dphy-rx.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Cadence DPHY Rx Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Pratyush Yadav <p.yadav@ti.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: cdns,dphy-rx
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#phy-cells":
|
||||
const: 0
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- "#phy-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/soc/ti,sci_pm_domain.h>
|
||||
|
||||
dphy0: phy@4580000 {
|
||||
compatible = "cdns,dphy-rx";
|
||||
reg = <0x4580000 0x1100>;
|
||||
#phy-cells = <0>;
|
||||
power-domains = <&k3_pds 147 TI_SCI_PD_EXCLUSIVE>;
|
||||
};
|
@ -1,20 +0,0 @@
|
||||
Cadence DPHY
|
||||
============
|
||||
|
||||
Cadence DPHY block.
|
||||
|
||||
Required properties:
|
||||
- compatible: should be set to "cdns,dphy".
|
||||
- reg: physical base address and length of the DPHY registers.
|
||||
- clocks: DPHY reference clocks.
|
||||
- clock-names: must contain "psm" and "pll_ref".
|
||||
- #phy-cells: must be set to 0.
|
||||
|
||||
Example:
|
||||
dphy0: dphy@fd0e0000{
|
||||
compatible = "cdns,dphy";
|
||||
reg = <0x0 0xfd0e0000 0x0 0x1000>;
|
||||
clocks = <&psm_clk>, <&pll_ref_clk>;
|
||||
clock-names = "psm", "pll_ref";
|
||||
#phy-cells = <0>;
|
||||
};
|
56
Documentation/devicetree/bindings/phy/cdns,dphy.yaml
Normal file
56
Documentation/devicetree/bindings/phy/cdns,dphy.yaml
Normal file
@ -0,0 +1,56 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/cdns,dphy.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Cadence DPHY Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Pratyush Yadav <p.yadav@ti.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: cdns,dphy
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: PMA state machine clock
|
||||
- description: PLL reference clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: psm
|
||||
- const: pll_ref
|
||||
|
||||
"#phy-cells":
|
||||
const: 0
|
||||
|
||||
power-domains:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- "#phy-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/soc/ti,sci_pm_domain.h>
|
||||
|
||||
dphy0: phy@fd0e0000{
|
||||
compatible = "cdns,dphy";
|
||||
reg = <0xfd0e0000 0x1000>;
|
||||
clocks = <&psm_clk>, <&pll_ref_clk>;
|
||||
clock-names = "psm", "pll_ref";
|
||||
power-domains = <&k3_pds 147 TI_SCI_PD_EXCLUSIVE>;
|
||||
#phy-cells = <0>;
|
||||
};
|
@ -80,6 +80,8 @@ properties:
|
||||
- mediatek,mt2712-tphy
|
||||
- mediatek,mt7629-tphy
|
||||
- mediatek,mt8183-tphy
|
||||
- mediatek,mt8186-tphy
|
||||
- mediatek,mt8192-tphy
|
||||
- const: mediatek,generic-tphy-v2
|
||||
- items:
|
||||
- enum:
|
||||
|
@ -0,0 +1,109 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/phy-rockchip-naneng-combphy.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Rockchip SoC Naneng Combo Phy Device Tree Bindings
|
||||
|
||||
maintainers:
|
||||
- Heiko Stuebner <heiko@sntech.de>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- rockchip,rk3568-naneng-combphy
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: reference clock
|
||||
- description: apb clock
|
||||
- description: pipe clock
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: ref
|
||||
- const: apb
|
||||
- const: pipe
|
||||
|
||||
resets:
|
||||
items:
|
||||
- description: exclusive PHY reset line
|
||||
|
||||
rockchip,enable-ssc:
|
||||
type: boolean
|
||||
description:
|
||||
The option SSC can be enabled for U3, SATA and PCIE.
|
||||
Most commercially available platforms use SSC to reduce EMI.
|
||||
|
||||
rockchip,ext-refclk:
|
||||
type: boolean
|
||||
description:
|
||||
Many PCIe connections, especially backplane connections,
|
||||
require a synchronous reference clock between the two link partners.
|
||||
To achieve this a common clock source, referred to as REFCLK in
|
||||
the PCI Express Card Electromechanical Specification,
|
||||
should be used by both ends of the PCIe link.
|
||||
In PCIe mode one can choose to use an internal or an external reference
|
||||
clock.
|
||||
By default the internal clock is selected. The PCIe PHY provides a 100MHz
|
||||
differential clock output(optional with SSC) for system applications.
|
||||
When selecting this option an externally 100MHz differential
|
||||
reference clock needs to be provided to the PCIe PHY.
|
||||
|
||||
rockchip,pipe-grf:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
Some additional phy settings are accessed through GRF regs.
|
||||
|
||||
rockchip,pipe-phy-grf:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
Some additional pipe settings are accessed through GRF regs.
|
||||
|
||||
"#phy-cells":
|
||||
const: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
- clock-names
|
||||
- resets
|
||||
- rockchip,pipe-grf
|
||||
- rockchip,pipe-phy-grf
|
||||
- "#phy-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/rk3568-cru.h>
|
||||
|
||||
pipegrf: syscon@fdc50000 {
|
||||
compatible = "rockchip,rk3568-pipe-grf", "syscon";
|
||||
reg = <0xfdc50000 0x1000>;
|
||||
};
|
||||
|
||||
pipe_phy_grf0: syscon@fdc70000 {
|
||||
compatible = "rockchip,rk3568-pipe-phy-grf", "syscon";
|
||||
reg = <0xfdc70000 0x1000>;
|
||||
};
|
||||
|
||||
combphy0: phy@fe820000 {
|
||||
compatible = "rockchip,rk3568-naneng-combphy";
|
||||
reg = <0xfe820000 0x100>;
|
||||
clocks = <&pmucru CLK_PCIEPHY0_REF>,
|
||||
<&cru PCLK_PIPEPHY0>,
|
||||
<&cru PCLK_PIPE>;
|
||||
clock-names = "ref", "apb", "pipe";
|
||||
assigned-clocks = <&pmucru CLK_PCIEPHY0_REF>;
|
||||
assigned-clock-rates = <100000000>;
|
||||
resets = <&cru SRST_PIPEPHY0>;
|
||||
rockchip,pipe-grf = <&pipegrf>;
|
||||
rockchip,pipe-phy-grf = <&pipe_phy_grf0>;
|
||||
#phy-cells = <1>;
|
||||
};
|
@ -16,7 +16,9 @@ description:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: qcom,sc8180x-edp-phy
|
||||
enum:
|
||||
- qcom,sc7280-edp-phy
|
||||
- qcom,sc8180x-edp-phy
|
||||
|
||||
reg:
|
||||
items:
|
||||
|
@ -32,6 +32,7 @@ properties:
|
||||
- qcom,sc8180x-qmp-pcie-phy
|
||||
- qcom,sc8180x-qmp-ufs-phy
|
||||
- qcom,sc8180x-qmp-usb3-phy
|
||||
- qcom,sc8280xp-qmp-ufs-phy
|
||||
- qcom,sdm845-qhp-pcie-phy
|
||||
- qcom,sdm845-qmp-pcie-phy
|
||||
- qcom,sdm845-qmp-ufs-phy
|
||||
@ -280,6 +281,8 @@ allOf:
|
||||
- qcom,sdm845-qmp-ufs-phy
|
||||
- qcom,sm8150-qmp-ufs-phy
|
||||
- qcom,sm8250-qmp-ufs-phy
|
||||
- qcom,sc8180x-qmp-ufs-phy
|
||||
- qcom,sc8280xp-qmp-ufs-phy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
|
@ -19,6 +19,7 @@ properties:
|
||||
- items:
|
||||
- enum:
|
||||
- qcom,ipq8074-qusb2-phy
|
||||
- qcom,msm8953-qusb2-phy
|
||||
- qcom,msm8996-qusb2-phy
|
||||
- qcom,msm8998-qusb2-phy
|
||||
- qcom,qcm2290-qusb2-phy
|
||||
|
@ -1,84 +0,0 @@
|
||||
Qualcomm's USB HS PHY
|
||||
|
||||
PROPERTIES
|
||||
|
||||
- compatible:
|
||||
Usage: required
|
||||
Value type: <string>
|
||||
Definition: Should contain "qcom,usb-hs-phy" and more specifically one of the
|
||||
following:
|
||||
|
||||
"qcom,usb-hs-phy-apq8064"
|
||||
"qcom,usb-hs-phy-msm8916"
|
||||
"qcom,usb-hs-phy-msm8974"
|
||||
|
||||
- #phy-cells:
|
||||
Usage: required
|
||||
Value type: <u32>
|
||||
Definition: Should contain 0
|
||||
|
||||
- clocks:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: Should contain clock specifier for the reference and sleep
|
||||
clocks
|
||||
|
||||
- clock-names:
|
||||
Usage: required
|
||||
Value type: <stringlist>
|
||||
Definition: Should contain "ref" and "sleep" for the reference and sleep
|
||||
clocks respectively
|
||||
|
||||
- resets:
|
||||
Usage: required
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: Should contain the phy and POR resets
|
||||
|
||||
- reset-names:
|
||||
Usage: required
|
||||
Value type: <stringlist>
|
||||
Definition: Should contain "phy" and "por" for the phy and POR resets
|
||||
respectively
|
||||
|
||||
- v3p3-supply:
|
||||
Usage: required
|
||||
Value type: <phandle>
|
||||
Definition: Should contain a reference to the 3.3V supply
|
||||
|
||||
- v1p8-supply:
|
||||
Usage: required
|
||||
Value type: <phandle>
|
||||
Definition: Should contain a reference to the 1.8V supply
|
||||
|
||||
- extcon:
|
||||
Usage: optional
|
||||
Value type: <prop-encoded-array>
|
||||
Definition: Should contain the vbus extcon
|
||||
|
||||
- qcom,init-seq:
|
||||
Usage: optional
|
||||
Value type: <u8 array>
|
||||
Definition: Should contain a sequence of ULPI address and value pairs to
|
||||
program into the ULPI_EXT_VENDOR_SPECIFIC area. This is related
|
||||
to Device Mode Eye Diagram test. The addresses are offsets
|
||||
from the ULPI_EXT_VENDOR_SPECIFIC address, for example,
|
||||
<0x1 0x53> would mean "write the value 0x53 to address 0x81".
|
||||
|
||||
EXAMPLE
|
||||
|
||||
otg: usb-controller {
|
||||
ulpi {
|
||||
phy {
|
||||
compatible = "qcom,usb-hs-phy-msm8974", "qcom,usb-hs-phy";
|
||||
#phy-cells = <0>;
|
||||
clocks = <&xo_board>, <&gcc GCC_USB2A_PHY_SLEEP_CLK>;
|
||||
clock-names = "ref", "sleep";
|
||||
resets = <&gcc GCC_USB2A_PHY_BCR>, <&otg 0>;
|
||||
reset-names = "phy", "por";
|
||||
v3p3-supply = <&pm8941_l24>;
|
||||
v1p8-supply = <&pm8941_l6>;
|
||||
extcon = <&smbb>;
|
||||
qcom,init-seq = /bits/ 8 <0x1 0x63>;
|
||||
};
|
||||
};
|
||||
};
|
108
Documentation/devicetree/bindings/phy/qcom,usb-hs-phy.yaml
Normal file
108
Documentation/devicetree/bindings/phy/qcom,usb-hs-phy.yaml
Normal file
@ -0,0 +1,108 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/qcom,usb-hs-phy.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Qualcomm's USB HS PHY binding description
|
||||
|
||||
maintainers:
|
||||
- Bjorn Andersson <bjorn.andersson@linaro.org>
|
||||
|
||||
if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: qcom,usb-hs-phy-apq8064
|
||||
then:
|
||||
properties:
|
||||
resets:
|
||||
maxItems: 1
|
||||
|
||||
reset-names:
|
||||
const: por
|
||||
|
||||
else:
|
||||
properties:
|
||||
resets:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
|
||||
reset-names:
|
||||
items:
|
||||
- const: phy
|
||||
- const: por
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- qcom,usb-hs-phy-apq8064
|
||||
- qcom,usb-hs-phy-msm8916
|
||||
- qcom,usb-hs-phy-msm8974
|
||||
- const: qcom,usb-hs-phy
|
||||
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
|
||||
clock-names:
|
||||
maxItems: 2
|
||||
contains:
|
||||
items:
|
||||
- const: ref
|
||||
- const: sleep
|
||||
|
||||
resets: true
|
||||
|
||||
reset-names: true
|
||||
|
||||
v1p8-supply: true
|
||||
|
||||
v3p3-supply: true
|
||||
|
||||
extcon: true
|
||||
|
||||
"#phy-cells":
|
||||
const: 0
|
||||
|
||||
qcom,init-seq:
|
||||
$ref: /schemas/types.yaml#/definitions/uint8-matrix
|
||||
description: >
|
||||
Sequence of ULPI address and value pairs to
|
||||
program into the ULPI_EXT_VENDOR_SPECIFIC area.
|
||||
This is related to Device Mode Eye Diagram test.
|
||||
maxItems: 32 # no hard limit
|
||||
items:
|
||||
items:
|
||||
- description: >
|
||||
the address is offset from the ULPI_EXT_VENDOR_SPECIFIC address
|
||||
- description: value
|
||||
|
||||
required:
|
||||
- clocks
|
||||
- clock-names
|
||||
- resets
|
||||
- reset-names
|
||||
- "#phy-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
otg: usb-controller {
|
||||
ulpi {
|
||||
phy {
|
||||
compatible = "qcom,usb-hs-phy-msm8974", "qcom,usb-hs-phy";
|
||||
#phy-cells = <0>;
|
||||
clocks = <&clk 0>, <&clk 258>;
|
||||
clock-names = "ref", "sleep";
|
||||
resets = <&gcc 10>, <&otg 0>;
|
||||
reset-names = "phy", "por";
|
||||
v3p3-supply = <&pm8941_l24>;
|
||||
v1p8-supply = <&pm8941_l6>;
|
||||
extcon = <&smbb>;
|
||||
qcom,init-seq = /bits/ 8 <0x1 0x63>;
|
||||
};
|
||||
};
|
||||
};
|
@ -15,8 +15,11 @@ description: |
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- qcom,usb-snps-hs-5nm-phy
|
||||
- qcom,usb-snps-hs-7nm-phy
|
||||
- qcom,sc7280-usb-hs-phy
|
||||
- qcom,sc8180x-usb-hs-phy
|
||||
- qcom,sc8280xp-usb-hs-phy
|
||||
- qcom,sm8150-usb-hs-phy
|
||||
- qcom,sm8250-usb-hs-phy
|
||||
- qcom,sm8350-usb-hs-phy
|
||||
|
@ -33,7 +33,8 @@ properties:
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,usb2-phy-r9a07g044 # RZ/G2{L,LC}
|
||||
- const: renesas,rzg2l-usb2-phy # RZ/G2L family
|
||||
- renesas,usb2-phy-r9a07g054 # RZ/V2L
|
||||
- const: renesas,rzg2l-usb2-phy
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -0,0 +1,41 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/samsung,dp-video-phy.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Samsung Exynos SoC DisplayPort PHY
|
||||
|
||||
maintainers:
|
||||
- Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
|
||||
- Marek Szyprowski <m.szyprowski@samsung.com>
|
||||
- Sylwester Nawrocki <s.nawrocki@samsung.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- samsung,exynos5250-dp-video-phy
|
||||
- samsung,exynos5420-dp-video-phy
|
||||
|
||||
"#phy-cells":
|
||||
const: 0
|
||||
|
||||
samsung,pmu-syscon:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
Phandle to PMU system controller interface.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- "#phy-cells"
|
||||
- samsung,pmu-syscon
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
phy {
|
||||
compatible = "samsung,exynos5420-dp-video-phy";
|
||||
samsung,pmu-syscon = <&pmu_system_controller>;
|
||||
#phy-cells = <0>;
|
||||
};
|
@ -0,0 +1,64 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/samsung,exynos5250-sata-phy.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Samsung Exynos5250 SoC SATA PHY
|
||||
|
||||
maintainers:
|
||||
- Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
|
||||
- Marek Szyprowski <m.szyprowski@samsung.com>
|
||||
- Sylwester Nawrocki <s.nawrocki@samsung.com>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: samsung,exynos5250-sata-phy
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: sata_phyctrl
|
||||
|
||||
"#phy-cells":
|
||||
const: 0
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
samsung,syscon-phandle:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
Phandle to PMU system controller interface.
|
||||
|
||||
samsung,exynos-sataphy-i2c-phandle:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
Phandle to I2C SATA interface.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- clocks
|
||||
- clock-names
|
||||
- "#phy-cells"
|
||||
- reg
|
||||
- samsung,syscon-phandle
|
||||
- samsung,exynos-sataphy-i2c-phandle
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/exynos5250.h>
|
||||
|
||||
phy@12170000 {
|
||||
compatible = "samsung,exynos5250-sata-phy";
|
||||
reg = <0x12170000 0x1ff>;
|
||||
clocks = <&clock CLK_SATA_PHYCTRL>;
|
||||
clock-names = "sata_phyctrl";
|
||||
#phy-cells = <0>;
|
||||
samsung,syscon-phandle = <&pmu_system_controller>;
|
||||
samsung,exynos-sataphy-i2c-phandle = <&sata_phy_i2c>;
|
||||
};
|
@ -0,0 +1,113 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/samsung,mipi-video-phy.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Samsung S5P/Exynos SoC MIPI CSIS/DSIM DPHY
|
||||
|
||||
maintainers:
|
||||
- Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
|
||||
- Marek Szyprowski <m.szyprowski@samsung.com>
|
||||
- Sylwester Nawrocki <s.nawrocki@samsung.com>
|
||||
|
||||
description: |
|
||||
For samsung,s5pv210-mipi-video-phy compatible PHYs the second cell in the
|
||||
PHY specifier identifies the PHY and its meaning is as follows::
|
||||
0 - MIPI CSIS 0,
|
||||
1 - MIPI DSIM 0,
|
||||
2 - MIPI CSIS 1,
|
||||
3 - MIPI DSIM 1.
|
||||
|
||||
samsung,exynos5420-mipi-video-phy and samsung,exynos5433-mipi-video-phy
|
||||
support additional fifth PHY::
|
||||
4 - MIPI CSIS 2.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- samsung,s5pv210-mipi-video-phy
|
||||
- samsung,exynos5420-mipi-video-phy
|
||||
- samsung,exynos5433-mipi-video-phy
|
||||
|
||||
"#phy-cells":
|
||||
const: 1
|
||||
|
||||
syscon:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
Phandle to PMU system controller interface, valid only for
|
||||
samsung,s5pv210-mipi-video-phy and samsung,exynos5420-mipi-video-phy.
|
||||
|
||||
samsung,pmu-syscon:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
Phandle to PMU system controller interface, valid for
|
||||
samsung,exynos5433-mipi-video-phy.
|
||||
|
||||
samsung,disp-sysreg:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
Phandle to DISP system controller interface, valid for
|
||||
samsung,exynos5433-mipi-video-phy.
|
||||
|
||||
samsung,cam0-sysreg:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
Phandle to CAM0 system controller interface, valid for
|
||||
samsung,exynos5433-mipi-video-phy.
|
||||
|
||||
samsung,cam1-sysreg:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
Phandle to CAM1 system controller interface, valid for
|
||||
samsung,exynos5433-mipi-video-phy.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- "#phy-cells"
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- samsung,s5pv210-mipi-video-phy
|
||||
- samsung,exynos5420-mipi-video-phy
|
||||
then:
|
||||
properties:
|
||||
samsung,pmu-syscon: false
|
||||
samsung,disp-sysreg: false
|
||||
samsung,cam0-sysreg: false
|
||||
samsung,cam1-sysreg: false
|
||||
required:
|
||||
- syscon
|
||||
else:
|
||||
properties:
|
||||
syscon: false
|
||||
required:
|
||||
- samsung,pmu-syscon
|
||||
- samsung,disp-sysreg
|
||||
- samsung,cam0-sysreg
|
||||
- samsung,cam1-sysreg
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
phy {
|
||||
compatible = "samsung,exynos5433-mipi-video-phy";
|
||||
#phy-cells = <1>;
|
||||
samsung,pmu-syscon = <&pmu_system_controller>;
|
||||
samsung,cam0-sysreg = <&syscon_cam0>;
|
||||
samsung,cam1-sysreg = <&syscon_cam1>;
|
||||
samsung,disp-sysreg = <&syscon_disp>;
|
||||
};
|
||||
|
||||
- |
|
||||
phy {
|
||||
compatible = "samsung,s5pv210-mipi-video-phy";
|
||||
syscon = <&pmu_system_controller>;
|
||||
#phy-cells = <1>;
|
||||
};
|
102
Documentation/devicetree/bindings/phy/samsung,usb2-phy.yaml
Normal file
102
Documentation/devicetree/bindings/phy/samsung,usb2-phy.yaml
Normal file
@ -0,0 +1,102 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/samsung,usb2-phy.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Samsung S5P/Exynos SoC USB 2.0 PHY
|
||||
|
||||
maintainers:
|
||||
- Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
|
||||
- Marek Szyprowski <m.szyprowski@samsung.com>
|
||||
- Sylwester Nawrocki <s.nawrocki@samsung.com>
|
||||
|
||||
description: |
|
||||
The first phandle argument in the PHY specifier identifies the PHY, its
|
||||
meaning is compatible dependent. For the currently supported SoCs (Exynos4210
|
||||
and Exynos4212) it is as follows::
|
||||
0 - USB device ("device"),
|
||||
1 - USB host ("host"),
|
||||
2 - HSIC0 ("hsic0"),
|
||||
3 - HSIC1 ("hsic1"),
|
||||
Exynos3250 has only USB device phy available as phy 0.
|
||||
|
||||
Exynos4210 and Exynos4212 use mode switching and require that mode switch
|
||||
register is supplied.
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- samsung,exynos3250-usb2-phy
|
||||
- samsung,exynos4210-usb2-phy
|
||||
- samsung,exynos4x12-usb2-phy
|
||||
- samsung,exynos5250-usb2-phy
|
||||
- samsung,exynos5420-usb2-phy
|
||||
- samsung,s5pv210-usb2-phy
|
||||
|
||||
clocks:
|
||||
items:
|
||||
- description: PHY module gate clock.
|
||||
- description: Reference rate clock of PHY module.
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: phy
|
||||
- const: ref
|
||||
|
||||
"#phy-cells":
|
||||
const: 1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
samsung,pmureg-phandle:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
Phandle to PMU system controller interface.
|
||||
|
||||
samsung,sysreg-phandle:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
Phandle to system registers interface.
|
||||
|
||||
vbus-supply:
|
||||
description:
|
||||
VBUS power source.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- clocks
|
||||
- clock-names
|
||||
- "#phy-cells"
|
||||
- reg
|
||||
- samsung,pmureg-phandle
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- samsung,exynos4x12-usb2-phy
|
||||
- samsung,exynos5250-usb2-phy
|
||||
- samsung,exynos5420-usb2-phy
|
||||
then:
|
||||
required:
|
||||
- samsung,sysreg-phandle
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/exynos5420.h>
|
||||
|
||||
phy@12130000 {
|
||||
compatible = "samsung,exynos5420-usb2-phy";
|
||||
reg = <0x12130000 0x100>;
|
||||
#phy-cells = <1>;
|
||||
clocks = <&clock CLK_USBH20>, <&clock CLK_SCLK_USBPHY300>;
|
||||
clock-names = "phy", "ref";
|
||||
samsung,sysreg-phandle = <&sysreg_system_controller>;
|
||||
samsung,pmureg-phandle = <&pmu_system_controller>;
|
||||
};
|
126
Documentation/devicetree/bindings/phy/samsung,usb3-drd-phy.yaml
Normal file
126
Documentation/devicetree/bindings/phy/samsung,usb3-drd-phy.yaml
Normal file
@ -0,0 +1,126 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/phy/samsung,usb3-drd-phy.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Samsung Exynos SoC USB 3.0 DRD PHY USB 2.0 PHY
|
||||
|
||||
maintainers:
|
||||
- Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
|
||||
- Marek Szyprowski <m.szyprowski@samsung.com>
|
||||
- Sylwester Nawrocki <s.nawrocki@samsung.com>
|
||||
|
||||
description: |
|
||||
For samsung,exynos5250-usbdrd-phy and samsung,exynos5420-usbdrd-phy
|
||||
compatible PHYs, the second cell in the PHY specifier identifies the
|
||||
PHY id, which is interpreted as follows::
|
||||
0 - UTMI+ type phy,
|
||||
1 - PIPE3 type phy.
|
||||
|
||||
For SoCs like Exynos5420 having multiple USB 3.0 DRD PHY controllers,
|
||||
'usbdrd_phy' nodes should have numbered alias in the aliases node, in the
|
||||
form of usbdrdphyN, N = 0, 1... (depending on number of controllers).
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- samsung,exynos5250-usbdrd-phy
|
||||
- samsung,exynos5420-usbdrd-phy
|
||||
- samsung,exynos5433-usbdrd-phy
|
||||
- samsung,exynos7-usbdrd-phy
|
||||
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 5
|
||||
|
||||
clock-names:
|
||||
minItems: 2
|
||||
maxItems: 5
|
||||
description: |
|
||||
At least two clocks::
|
||||
- Main PHY clock (same as USB DRD controller i.e. DWC3 IP clock), used
|
||||
for register access.
|
||||
- PHY reference clock (usually crystal clock), used for PHY operations,
|
||||
associated by phy name. It is used to determine bit values for clock
|
||||
settings register. For Exynos5420 this is given as 'sclk_usbphy30'
|
||||
in the CMU.
|
||||
|
||||
"#phy-cells":
|
||||
const: 1
|
||||
|
||||
port:
|
||||
$ref: /schemas/graph.yaml#/properties/port
|
||||
description:
|
||||
Any connector to the data bus of this controller should be modelled using
|
||||
the OF graph bindings specified.
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
samsung,pmu-syscon:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
Phandle to PMU system controller interface.
|
||||
|
||||
vbus-supply:
|
||||
description:
|
||||
VBUS power source.
|
||||
|
||||
vbus-boost-supply:
|
||||
description:
|
||||
VBUS Boost 5V power source.
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- clocks
|
||||
- clock-names
|
||||
- "#phy-cells"
|
||||
- reg
|
||||
- samsung,pmu-syscon
|
||||
|
||||
allOf:
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- samsung,exynos5433-usbdrd-phy
|
||||
- samsung,exynos7-usbdrd-phy
|
||||
then:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 5
|
||||
maxItems: 5
|
||||
clock-names:
|
||||
items:
|
||||
- const: phy
|
||||
- const: ref
|
||||
- const: phy_utmi
|
||||
- const: phy_pipe
|
||||
- const: itp
|
||||
else:
|
||||
properties:
|
||||
clocks:
|
||||
minItems: 2
|
||||
maxItems: 2
|
||||
clock-names:
|
||||
items:
|
||||
- const: phy
|
||||
- const: ref
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/exynos5420.h>
|
||||
|
||||
phy@12100000 {
|
||||
compatible = "samsung,exynos5420-usbdrd-phy";
|
||||
reg = <0x12100000 0x100>;
|
||||
#phy-cells = <1>;
|
||||
clocks = <&clock CLK_USBD300>, <&clock CLK_SCLK_USBPHY300>;
|
||||
clock-names = "phy", "ref";
|
||||
samsung,pmu-syscon = <&pmu_system_controller>;
|
||||
vbus-supply = <&usb300_vbus_reg>;
|
||||
};
|
@ -1,210 +0,0 @@
|
||||
Samsung S5P/Exynos SoC series MIPI CSIS/DSIM DPHY
|
||||
-------------------------------------------------
|
||||
|
||||
Required properties:
|
||||
- compatible : should be one of the listed compatibles:
|
||||
- "samsung,s5pv210-mipi-video-phy"
|
||||
- "samsung,exynos5420-mipi-video-phy"
|
||||
- "samsung,exynos5433-mipi-video-phy"
|
||||
- #phy-cells : from the generic phy bindings, must be 1;
|
||||
|
||||
In case of s5pv210 and exynos5420 compatible PHYs:
|
||||
- syscon - phandle to the PMU system controller
|
||||
|
||||
In case of exynos5433 compatible PHY:
|
||||
- samsung,pmu-syscon - phandle to the PMU system controller
|
||||
- samsung,disp-sysreg - phandle to the DISP system registers controller
|
||||
- samsung,cam0-sysreg - phandle to the CAM0 system registers controller
|
||||
- samsung,cam1-sysreg - phandle to the CAM1 system registers controller
|
||||
|
||||
For "samsung,s5pv210-mipi-video-phy" compatible PHYs the second cell in
|
||||
the PHY specifier identifies the PHY and its meaning is as follows:
|
||||
0 - MIPI CSIS 0,
|
||||
1 - MIPI DSIM 0,
|
||||
2 - MIPI CSIS 1,
|
||||
3 - MIPI DSIM 1.
|
||||
"samsung,exynos5420-mipi-video-phy" and "samsung,exynos5433-mipi-video-phy"
|
||||
supports additional fifth PHY:
|
||||
4 - MIPI CSIS 2.
|
||||
|
||||
Samsung Exynos SoC series Display Port PHY
|
||||
-------------------------------------------------
|
||||
|
||||
Required properties:
|
||||
- compatible : should be one of the following supported values:
|
||||
- "samsung,exynos5250-dp-video-phy"
|
||||
- "samsung,exynos5420-dp-video-phy"
|
||||
- samsung,pmu-syscon: phandle for PMU system controller interface, used to
|
||||
control pmu registers for power isolation.
|
||||
- #phy-cells : from the generic PHY bindings, must be 0;
|
||||
|
||||
Samsung S5P/Exynos SoC series USB PHY
|
||||
-------------------------------------------------
|
||||
|
||||
Required properties:
|
||||
- compatible : should be one of the listed compatibles:
|
||||
- "samsung,exynos3250-usb2-phy"
|
||||
- "samsung,exynos4210-usb2-phy"
|
||||
- "samsung,exynos4x12-usb2-phy"
|
||||
- "samsung,exynos5250-usb2-phy"
|
||||
- "samsung,exynos5420-usb2-phy"
|
||||
- "samsung,s5pv210-usb2-phy"
|
||||
- reg : a list of registers used by phy driver
|
||||
- first and obligatory is the location of phy modules registers
|
||||
- samsung,sysreg-phandle - handle to syscon used to control the system registers
|
||||
- samsung,pmureg-phandle - handle to syscon used to control PMU registers
|
||||
- #phy-cells : from the generic phy bindings, must be 1;
|
||||
- clocks and clock-names:
|
||||
- the "phy" clock is required by the phy module, used as a gate
|
||||
- the "ref" clock is used to get the rate of the clock provided to the
|
||||
PHY module
|
||||
|
||||
Optional properties:
|
||||
- vbus-supply: power-supply phandle for vbus power source
|
||||
|
||||
The first phandle argument in the PHY specifier identifies the PHY, its
|
||||
meaning is compatible dependent. For the currently supported SoCs (Exynos 4210
|
||||
and Exynos 4212) it is as follows:
|
||||
0 - USB device ("device"),
|
||||
1 - USB host ("host"),
|
||||
2 - HSIC0 ("hsic0"),
|
||||
3 - HSIC1 ("hsic1"),
|
||||
Exynos3250 has only USB device phy available as phy 0.
|
||||
|
||||
Exynos 4210 and Exynos 4212 use mode switching and require that mode switch
|
||||
register is supplied.
|
||||
|
||||
Example:
|
||||
|
||||
For Exynos 4412 (compatible with Exynos 4212):
|
||||
|
||||
usbphy: phy@125b0000 {
|
||||
compatible = "samsung,exynos4x12-usb2-phy";
|
||||
reg = <0x125b0000 0x100>;
|
||||
clocks = <&clock 305>, <&clock 2>;
|
||||
clock-names = "phy", "ref";
|
||||
#phy-cells = <1>;
|
||||
samsung,sysreg-phandle = <&sys_reg>;
|
||||
samsung,pmureg-phandle = <&pmu_reg>;
|
||||
};
|
||||
|
||||
Then the PHY can be used in other nodes such as:
|
||||
|
||||
phy-consumer@12340000 {
|
||||
phys = <&usbphy 2>;
|
||||
phy-names = "phy";
|
||||
};
|
||||
|
||||
Refer to DT bindings documentation of particular PHY consumer devices for more
|
||||
information about required PHYs and the way of specification.
|
||||
|
||||
Samsung SATA PHY Controller
|
||||
---------------------------
|
||||
|
||||
SATA PHY nodes are defined to describe on-chip SATA Physical layer controllers.
|
||||
Each SATA PHY controller should have its own node.
|
||||
|
||||
Required properties:
|
||||
- compatible : compatible list, contains "samsung,exynos5250-sata-phy"
|
||||
- reg : offset and length of the SATA PHY register set;
|
||||
- #phy-cells : must be zero
|
||||
- clocks : must be exactly one entry
|
||||
- clock-names : must be "sata_phyctrl"
|
||||
- samsung,exynos-sataphy-i2c-phandle : a phandle to the I2C device, no arguments
|
||||
- samsung,syscon-phandle : a phandle to the PMU system controller, no arguments
|
||||
|
||||
Example:
|
||||
sata_phy: sata-phy@12170000 {
|
||||
compatible = "samsung,exynos5250-sata-phy";
|
||||
reg = <0x12170000 0x1ff>;
|
||||
clocks = <&clock 287>;
|
||||
clock-names = "sata_phyctrl";
|
||||
#phy-cells = <0>;
|
||||
samsung,exynos-sataphy-i2c-phandle = <&sata_phy_i2c>;
|
||||
samsung,syscon-phandle = <&pmu_syscon>;
|
||||
};
|
||||
|
||||
Device-Tree bindings for sataphy i2c client driver
|
||||
--------------------------------------------------
|
||||
|
||||
Required properties:
|
||||
compatible: Should be "samsung,exynos-sataphy-i2c"
|
||||
- reg: I2C address of the sataphy i2c device.
|
||||
|
||||
Example:
|
||||
|
||||
sata_phy_i2c:sata-phy@38 {
|
||||
compatible = "samsung,exynos-sataphy-i2c";
|
||||
reg = <0x38>;
|
||||
};
|
||||
|
||||
Samsung Exynos5 SoC series USB DRD PHY controller
|
||||
--------------------------------------------------
|
||||
|
||||
Required properties:
|
||||
- compatible : Should be set to one of the following supported values:
|
||||
- "samsung,exynos5250-usbdrd-phy" - for exynos5250 SoC,
|
||||
- "samsung,exynos5420-usbdrd-phy" - for exynos5420 SoC.
|
||||
- "samsung,exynos5433-usbdrd-phy" - for exynos5433 SoC.
|
||||
- "samsung,exynos7-usbdrd-phy" - for exynos7 SoC.
|
||||
- reg : Register offset and length of USB DRD PHY register set;
|
||||
- clocks: Clock IDs array as required by the controller
|
||||
- clock-names: names of clocks correseponding to IDs in the clock property;
|
||||
Required clocks:
|
||||
- phy: main PHY clock (same as USB DRD controller i.e. DWC3 IP clock),
|
||||
used for register access.
|
||||
- ref: PHY's reference clock (usually crystal clock), used for
|
||||
PHY operations, associated by phy name. It is used to
|
||||
determine bit values for clock settings register.
|
||||
For Exynos5420 this is given as 'sclk_usbphy30' in CMU.
|
||||
- optional clocks: Exynos5433 & Exynos7 SoC has now following additional
|
||||
gate clocks available:
|
||||
- phy_pipe: for PIPE3 phy
|
||||
- phy_utmi: for UTMI+ phy
|
||||
- itp: for ITP generation
|
||||
- samsung,pmu-syscon: phandle for PMU system controller interface, used to
|
||||
control pmu registers for power isolation.
|
||||
- #phy-cells : from the generic PHY bindings, must be 1;
|
||||
|
||||
For "samsung,exynos5250-usbdrd-phy" and "samsung,exynos5420-usbdrd-phy"
|
||||
compatible PHYs, the second cell in the PHY specifier identifies the
|
||||
PHY id, which is interpreted as follows:
|
||||
0 - UTMI+ type phy,
|
||||
1 - PIPE3 type phy,
|
||||
|
||||
Example:
|
||||
usbdrd_phy: usbphy@12100000 {
|
||||
compatible = "samsung,exynos5250-usbdrd-phy";
|
||||
reg = <0x12100000 0x100>;
|
||||
clocks = <&clock 286>, <&clock 1>;
|
||||
clock-names = "phy", "ref";
|
||||
samsung,pmu-syscon = <&pmu_system_controller>;
|
||||
#phy-cells = <1>;
|
||||
};
|
||||
|
||||
- aliases: For SoCs like Exynos5420 having multiple USB 3.0 DRD PHY controllers,
|
||||
'usbdrd_phy' nodes should have numbered alias in the aliases node,
|
||||
in the form of usbdrdphyN, N = 0, 1... (depending on number of
|
||||
controllers).
|
||||
Example:
|
||||
aliases {
|
||||
usbdrdphy0 = &usb3_phy0;
|
||||
usbdrdphy1 = &usb3_phy1;
|
||||
};
|
||||
|
||||
Samsung Exynos SoC series PCIe PHY controller
|
||||
--------------------------------------------------
|
||||
Required properties:
|
||||
- compatible : Should be set to "samsung,exynos5440-pcie-phy"
|
||||
- #phy-cells : Must be zero
|
||||
- reg : a register used by phy driver.
|
||||
- First is for phy register, second is for block register.
|
||||
- reg-names : Must be set to "phy" and "block".
|
||||
|
||||
Example:
|
||||
pcie_phy0: pcie-phy@270000 {
|
||||
#phy-cells = <0>;
|
||||
compatible = "samsung,exynos5440-pcie-phy";
|
||||
reg = <0x270000 0x1000>, <0x271000 0x40>;
|
||||
reg-names = "phy", "block";
|
||||
};
|
@ -283,6 +283,8 @@ properties:
|
||||
- renesas,isl29501
|
||||
# S524AD0XF1 (128K/256K-bit Serial EEPROM for Low Power)
|
||||
- samsung,24ad0xd1
|
||||
# Samsung Exynos SoC SATA PHY I2C device
|
||||
- samsung,exynos-sataphy-i2c
|
||||
# Sensirion low power multi-pixel gas sensor with I2C interface
|
||||
- sensirion,sgpc3
|
||||
# Sensirion multi-pixel gas sensor with I2C interface
|
||||
|
@ -17182,7 +17182,7 @@ SAMSUNG USB2 PHY DRIVER
|
||||
M: Sylwester Nawrocki <s.nawrocki@samsung.com>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/devicetree/bindings/phy/samsung-phy.txt
|
||||
F: Documentation/devicetree/bindings/phy/samsung,usb2-phy.yaml
|
||||
F: Documentation/driver-api/phy/samsung-usb2.rst
|
||||
F: drivers/phy/samsung/phy-exynos4210-usb2.c
|
||||
F: drivers/phy/samsung/phy-exynos4x12-usb2.c
|
||||
|
@ -240,8 +240,6 @@ enum {
|
||||
as default lpm_policy */
|
||||
AHCI_HFLAG_SUSPEND_PHYS = (1 << 26), /* handle PHYs during
|
||||
suspend/resume */
|
||||
AHCI_HFLAG_IGN_NOTSUPP_POWER_ON = (1 << 27), /* ignore -EOPNOTSUPP
|
||||
from phy_power_on() */
|
||||
AHCI_HFLAG_NO_SXS = (1 << 28), /* SXS not supported */
|
||||
|
||||
/* ap->flags bits */
|
||||
|
@ -227,7 +227,7 @@ static const struct ahci_mvebu_plat_data ahci_mvebu_armada_380_plat_data = {
|
||||
|
||||
static const struct ahci_mvebu_plat_data ahci_mvebu_armada_3700_plat_data = {
|
||||
.plat_config = ahci_mvebu_armada_3700_config,
|
||||
.flags = AHCI_HFLAG_SUSPEND_PHYS | AHCI_HFLAG_IGN_NOTSUPP_POWER_ON,
|
||||
.flags = AHCI_HFLAG_SUSPEND_PHYS,
|
||||
};
|
||||
|
||||
static const struct of_device_id ahci_mvebu_of_match[] = {
|
||||
|
@ -59,7 +59,7 @@ int ahci_platform_enable_phys(struct ahci_host_priv *hpriv)
|
||||
}
|
||||
|
||||
rc = phy_power_on(hpriv->phys[i]);
|
||||
if (rc && !(rc == -EOPNOTSUPP && (hpriv->flags & AHCI_HFLAG_IGN_NOTSUPP_POWER_ON))) {
|
||||
if (rc) {
|
||||
phy_exit(hpriv->phys[i]);
|
||||
goto disable_phys;
|
||||
}
|
||||
|
@ -1482,9 +1482,7 @@ static int advk_pcie_enable_phy(struct advk_pcie *pcie)
|
||||
}
|
||||
|
||||
ret = phy_power_on(pcie->phy);
|
||||
if (ret == -EOPNOTSUPP) {
|
||||
dev_warn(&pcie->pdev->dev, "PHY unsupported by firmware\n");
|
||||
} else if (ret) {
|
||||
if (ret) {
|
||||
phy_exit(pcie->phy);
|
||||
return ret;
|
||||
}
|
||||
|
@ -43,7 +43,7 @@
|
||||
#define REG_PHYCTL_A33 0x10
|
||||
#define REG_PHY_OTGCTL 0x20
|
||||
|
||||
#define REG_PMU_UNK1 0x10
|
||||
#define REG_HCI_PHY_CTL 0x10
|
||||
|
||||
#define PHYCTL_DATA BIT(7)
|
||||
|
||||
@ -82,6 +82,7 @@
|
||||
/* A83T specific control bits for PHY0 */
|
||||
#define PHY_CTL_VBUSVLDEXT BIT(5)
|
||||
#define PHY_CTL_SIDDQ BIT(3)
|
||||
#define PHY_CTL_H3_SIDDQ BIT(1)
|
||||
|
||||
/* A83T specific control bits for PHY2 HSIC */
|
||||
#define SUNXI_EHCI_HS_FORCE BIT(20)
|
||||
@ -115,9 +116,9 @@ struct sun4i_usb_phy_cfg {
|
||||
int hsic_index;
|
||||
enum sun4i_usb_phy_type type;
|
||||
u32 disc_thresh;
|
||||
u32 hci_phy_ctl_clear;
|
||||
u8 phyctl_offset;
|
||||
bool dedicated_clocks;
|
||||
bool enable_pmu_unk1;
|
||||
bool phy0_dual_route;
|
||||
int missing_phys;
|
||||
};
|
||||
@ -288,6 +289,12 @@ static int sun4i_usb_phy_init(struct phy *_phy)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (phy->pmu && data->cfg->hci_phy_ctl_clear) {
|
||||
val = readl(phy->pmu + REG_HCI_PHY_CTL);
|
||||
val &= ~data->cfg->hci_phy_ctl_clear;
|
||||
writel(val, phy->pmu + REG_HCI_PHY_CTL);
|
||||
}
|
||||
|
||||
if (data->cfg->type == sun8i_a83t_phy ||
|
||||
data->cfg->type == sun50i_h6_phy) {
|
||||
if (phy->index == 0) {
|
||||
@ -297,11 +304,6 @@ static int sun4i_usb_phy_init(struct phy *_phy)
|
||||
writel(val, data->base + data->cfg->phyctl_offset);
|
||||
}
|
||||
} else {
|
||||
if (phy->pmu && data->cfg->enable_pmu_unk1) {
|
||||
val = readl(phy->pmu + REG_PMU_UNK1);
|
||||
writel(val & ~2, phy->pmu + REG_PMU_UNK1);
|
||||
}
|
||||
|
||||
/* Enable USB 45 Ohm resistor calibration */
|
||||
if (phy->index == 0)
|
||||
sun4i_usb_phy_write(phy, PHY_RES45_CAL_EN, 0x01, 1);
|
||||
@ -863,7 +865,6 @@ static const struct sun4i_usb_phy_cfg sun4i_a10_cfg = {
|
||||
.disc_thresh = 3,
|
||||
.phyctl_offset = REG_PHYCTL_A10,
|
||||
.dedicated_clocks = false,
|
||||
.enable_pmu_unk1 = false,
|
||||
};
|
||||
|
||||
static const struct sun4i_usb_phy_cfg sun5i_a13_cfg = {
|
||||
@ -872,7 +873,6 @@ static const struct sun4i_usb_phy_cfg sun5i_a13_cfg = {
|
||||
.disc_thresh = 2,
|
||||
.phyctl_offset = REG_PHYCTL_A10,
|
||||
.dedicated_clocks = false,
|
||||
.enable_pmu_unk1 = false,
|
||||
};
|
||||
|
||||
static const struct sun4i_usb_phy_cfg sun6i_a31_cfg = {
|
||||
@ -881,7 +881,6 @@ static const struct sun4i_usb_phy_cfg sun6i_a31_cfg = {
|
||||
.disc_thresh = 3,
|
||||
.phyctl_offset = REG_PHYCTL_A10,
|
||||
.dedicated_clocks = true,
|
||||
.enable_pmu_unk1 = false,
|
||||
};
|
||||
|
||||
static const struct sun4i_usb_phy_cfg sun7i_a20_cfg = {
|
||||
@ -890,7 +889,6 @@ static const struct sun4i_usb_phy_cfg sun7i_a20_cfg = {
|
||||
.disc_thresh = 2,
|
||||
.phyctl_offset = REG_PHYCTL_A10,
|
||||
.dedicated_clocks = false,
|
||||
.enable_pmu_unk1 = false,
|
||||
};
|
||||
|
||||
static const struct sun4i_usb_phy_cfg sun8i_a23_cfg = {
|
||||
@ -899,7 +897,6 @@ static const struct sun4i_usb_phy_cfg sun8i_a23_cfg = {
|
||||
.disc_thresh = 3,
|
||||
.phyctl_offset = REG_PHYCTL_A10,
|
||||
.dedicated_clocks = true,
|
||||
.enable_pmu_unk1 = false,
|
||||
};
|
||||
|
||||
static const struct sun4i_usb_phy_cfg sun8i_a33_cfg = {
|
||||
@ -908,7 +905,6 @@ static const struct sun4i_usb_phy_cfg sun8i_a33_cfg = {
|
||||
.disc_thresh = 3,
|
||||
.phyctl_offset = REG_PHYCTL_A33,
|
||||
.dedicated_clocks = true,
|
||||
.enable_pmu_unk1 = false,
|
||||
};
|
||||
|
||||
static const struct sun4i_usb_phy_cfg sun8i_a83t_cfg = {
|
||||
@ -925,7 +921,7 @@ static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = {
|
||||
.disc_thresh = 3,
|
||||
.phyctl_offset = REG_PHYCTL_A33,
|
||||
.dedicated_clocks = true,
|
||||
.enable_pmu_unk1 = true,
|
||||
.hci_phy_ctl_clear = PHY_CTL_H3_SIDDQ,
|
||||
.phy0_dual_route = true,
|
||||
};
|
||||
|
||||
@ -935,7 +931,7 @@ static const struct sun4i_usb_phy_cfg sun8i_r40_cfg = {
|
||||
.disc_thresh = 3,
|
||||
.phyctl_offset = REG_PHYCTL_A33,
|
||||
.dedicated_clocks = true,
|
||||
.enable_pmu_unk1 = true,
|
||||
.hci_phy_ctl_clear = PHY_CTL_H3_SIDDQ,
|
||||
.phy0_dual_route = true,
|
||||
};
|
||||
|
||||
@ -945,7 +941,16 @@ static const struct sun4i_usb_phy_cfg sun8i_v3s_cfg = {
|
||||
.disc_thresh = 3,
|
||||
.phyctl_offset = REG_PHYCTL_A33,
|
||||
.dedicated_clocks = true,
|
||||
.enable_pmu_unk1 = true,
|
||||
.hci_phy_ctl_clear = PHY_CTL_H3_SIDDQ,
|
||||
.phy0_dual_route = true,
|
||||
};
|
||||
|
||||
static const struct sun4i_usb_phy_cfg sun20i_d1_cfg = {
|
||||
.num_phys = 2,
|
||||
.type = sun50i_h6_phy,
|
||||
.phyctl_offset = REG_PHYCTL_A33,
|
||||
.dedicated_clocks = true,
|
||||
.hci_phy_ctl_clear = PHY_CTL_SIDDQ,
|
||||
.phy0_dual_route = true,
|
||||
};
|
||||
|
||||
@ -955,14 +960,13 @@ static const struct sun4i_usb_phy_cfg sun50i_a64_cfg = {
|
||||
.disc_thresh = 3,
|
||||
.phyctl_offset = REG_PHYCTL_A33,
|
||||
.dedicated_clocks = true,
|
||||
.enable_pmu_unk1 = true,
|
||||
.hci_phy_ctl_clear = PHY_CTL_H3_SIDDQ,
|
||||
.phy0_dual_route = true,
|
||||
};
|
||||
|
||||
static const struct sun4i_usb_phy_cfg sun50i_h6_cfg = {
|
||||
.num_phys = 4,
|
||||
.type = sun50i_h6_phy,
|
||||
.disc_thresh = 3,
|
||||
.phyctl_offset = REG_PHYCTL_A33,
|
||||
.dedicated_clocks = true,
|
||||
.phy0_dual_route = true,
|
||||
@ -980,6 +984,7 @@ static const struct of_device_id sun4i_usb_phy_of_match[] = {
|
||||
{ .compatible = "allwinner,sun8i-h3-usb-phy", .data = &sun8i_h3_cfg },
|
||||
{ .compatible = "allwinner,sun8i-r40-usb-phy", .data = &sun8i_r40_cfg },
|
||||
{ .compatible = "allwinner,sun8i-v3s-usb-phy", .data = &sun8i_v3s_cfg },
|
||||
{ .compatible = "allwinner,sun20i-d1-usb-phy", .data = &sun20i_d1_cfg },
|
||||
{ .compatible = "allwinner,sun50i-a64-usb-phy",
|
||||
.data = &sun50i_a64_cfg},
|
||||
{ .compatible = "allwinner,sun50i-h6-usb-phy", .data = &sun50i_h6_cfg },
|
||||
|
@ -114,8 +114,10 @@ static int phy_meson_gxl_usb2_init(struct phy *phy)
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(priv->clk);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
reset_control_rearm(priv->reset);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -125,6 +127,7 @@ static int phy_meson_gxl_usb2_exit(struct phy *phy)
|
||||
struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy);
|
||||
|
||||
clk_disable_unprepare(priv->clk);
|
||||
reset_control_rearm(priv->reset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -154,6 +154,7 @@ static int phy_meson8b_usb2_power_on(struct phy *phy)
|
||||
ret = clk_prepare_enable(priv->clk_usb_general);
|
||||
if (ret) {
|
||||
dev_err(&phy->dev, "Failed to enable USB general clock\n");
|
||||
reset_control_rearm(priv->reset);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -161,6 +162,7 @@ static int phy_meson8b_usb2_power_on(struct phy *phy)
|
||||
if (ret) {
|
||||
dev_err(&phy->dev, "Failed to enable USB DDR clock\n");
|
||||
clk_disable_unprepare(priv->clk_usb_general);
|
||||
reset_control_rearm(priv->reset);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -199,6 +201,7 @@ static int phy_meson8b_usb2_power_on(struct phy *phy)
|
||||
dev_warn(&phy->dev, "USB ID detect failed!\n");
|
||||
clk_disable_unprepare(priv->clk_usb);
|
||||
clk_disable_unprepare(priv->clk_usb_general);
|
||||
reset_control_rearm(priv->reset);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
@ -218,6 +221,7 @@ static int phy_meson8b_usb2_power_off(struct phy *phy)
|
||||
|
||||
clk_disable_unprepare(priv->clk_usb);
|
||||
clk_disable_unprepare(priv->clk_usb_general);
|
||||
reset_control_rearm(priv->reset);
|
||||
|
||||
/* power off the PHY by putting it into reset mode */
|
||||
regmap_update_bits(priv->regmap, REG_CTRL, REG_CTRL_POWER_ON_RESET,
|
||||
@ -265,8 +269,9 @@ static int phy_meson8b_usb2_probe(struct platform_device *pdev)
|
||||
return PTR_ERR(priv->clk_usb);
|
||||
|
||||
priv->reset = devm_reset_control_get_optional_shared(&pdev->dev, NULL);
|
||||
if (PTR_ERR(priv->reset) == -EPROBE_DEFER)
|
||||
return PTR_ERR(priv->reset);
|
||||
if (IS_ERR(priv->reset))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(priv->reset),
|
||||
"Failed to get the reset line");
|
||||
|
||||
priv->dr_mode = of_usb_get_dr_mode_by_phy(pdev->dev.of_node, -1);
|
||||
if (priv->dr_mode == USB_DR_MODE_UNKNOWN) {
|
||||
|
@ -47,6 +47,8 @@
|
||||
#define USB_CTRL_USB_PM_SOFT_RESET_MASK 0x40000000
|
||||
#define USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK 0x00800000
|
||||
#define USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK 0x00400000
|
||||
#define USB_CTRL_USB_PM_XHC_PME_EN_MASK 0x00000010
|
||||
#define USB_CTRL_USB_PM_XHC_S2_CLK_SWITCH_EN_MASK 0x00000008
|
||||
#define USB_CTRL_USB_PM_STATUS 0x08
|
||||
#define USB_CTRL_USB_DEVICE_CTL1 0x10
|
||||
#define USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK 0x00000003
|
||||
@ -190,10 +192,6 @@ static void usb_init_common(struct brcm_usb_init_params *params)
|
||||
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
USB_CTRL_UNSET(ctrl, USB_PM, USB_PWRDN);
|
||||
/* 1 millisecond - for USB clocks to settle down */
|
||||
usleep_range(1000, 2000);
|
||||
|
||||
if (USB_CTRL_MASK(USB_DEVICE_CTL1, PORT_MODE)) {
|
||||
reg = brcm_usb_readl(USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
|
||||
reg &= ~USB_CTRL_MASK(USB_DEVICE_CTL1, PORT_MODE);
|
||||
@ -222,6 +220,17 @@ static void usb_wake_enable_7211b0(struct brcm_usb_init_params *params,
|
||||
USB_CTRL_UNSET(ctrl, CTLR_CSHCR, ctl_pme_en);
|
||||
}
|
||||
|
||||
static void usb_wake_enable_7216(struct brcm_usb_init_params *params,
|
||||
bool enable)
|
||||
{
|
||||
void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
|
||||
|
||||
if (enable)
|
||||
USB_CTRL_SET(ctrl, USB_PM, XHC_PME_EN);
|
||||
else
|
||||
USB_CTRL_UNSET(ctrl, USB_PM, XHC_PME_EN);
|
||||
}
|
||||
|
||||
static void usb_init_common_7211b0(struct brcm_usb_init_params *params)
|
||||
{
|
||||
void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
|
||||
@ -295,6 +304,20 @@ static void usb_init_common_7211b0(struct brcm_usb_init_params *params)
|
||||
usb2_eye_fix_7211b0(params);
|
||||
}
|
||||
|
||||
static void usb_init_common_7216(struct brcm_usb_init_params *params)
|
||||
{
|
||||
void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
|
||||
|
||||
USB_CTRL_UNSET(ctrl, USB_PM, XHC_S2_CLK_SWITCH_EN);
|
||||
USB_CTRL_UNSET(ctrl, USB_PM, USB_PWRDN);
|
||||
|
||||
/* 1 millisecond - for USB clocks to settle down */
|
||||
usleep_range(1000, 2000);
|
||||
|
||||
usb_wake_enable_7216(params, false);
|
||||
usb_init_common(params);
|
||||
}
|
||||
|
||||
static void usb_init_xhci(struct brcm_usb_init_params *params)
|
||||
{
|
||||
pr_debug("%s\n", __func__);
|
||||
@ -302,14 +325,20 @@ static void usb_init_xhci(struct brcm_usb_init_params *params)
|
||||
xhci_soft_reset(params, 0);
|
||||
}
|
||||
|
||||
static void usb_uninit_common(struct brcm_usb_init_params *params)
|
||||
static void usb_uninit_common_7216(struct brcm_usb_init_params *params)
|
||||
{
|
||||
void __iomem *ctrl = params->regs[BRCM_REGS_CTRL];
|
||||
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
USB_CTRL_SET(ctrl, USB_PM, USB_PWRDN);
|
||||
if (!params->wake_enabled) {
|
||||
USB_CTRL_SET(ctrl, USB_PM, USB_PWRDN);
|
||||
|
||||
/* Switch to using slower clock during suspend to save power */
|
||||
USB_CTRL_SET(ctrl, USB_PM, XHC_S2_CLK_SWITCH_EN);
|
||||
} else {
|
||||
usb_wake_enable_7216(params, true);
|
||||
}
|
||||
}
|
||||
|
||||
static void usb_uninit_common_7211b0(struct brcm_usb_init_params *params)
|
||||
@ -371,9 +400,9 @@ static void usb_set_dual_select(struct brcm_usb_init_params *params, int mode)
|
||||
|
||||
static const struct brcm_usb_init_ops bcm7216_ops = {
|
||||
.init_ipp = usb_init_ipp,
|
||||
.init_common = usb_init_common,
|
||||
.init_common = usb_init_common_7216,
|
||||
.init_xhci = usb_init_xhci,
|
||||
.uninit_common = usb_uninit_common,
|
||||
.uninit_common = usb_uninit_common_7216,
|
||||
.uninit_xhci = usb_uninit_xhci,
|
||||
.get_dual_select = usb_get_dual_select,
|
||||
.set_dual_select = usb_set_dual_select,
|
||||
@ -396,6 +425,7 @@ void brcm_usb_dvr_init_7216(struct brcm_usb_init_params *params)
|
||||
|
||||
params->family_name = "7216";
|
||||
params->ops = &bcm7216_ops;
|
||||
params->suspend_with_clocks = true;
|
||||
}
|
||||
|
||||
void brcm_usb_dvr_init_7211b0(struct brcm_usb_init_params *params)
|
||||
|
@ -79,6 +79,7 @@
|
||||
|
||||
enum brcm_family_type {
|
||||
BRCM_FAMILY_3390A0,
|
||||
BRCM_FAMILY_4908,
|
||||
BRCM_FAMILY_7250B0,
|
||||
BRCM_FAMILY_7271A0,
|
||||
BRCM_FAMILY_7364A0,
|
||||
@ -96,6 +97,7 @@ enum brcm_family_type {
|
||||
|
||||
static const char *family_names[BRCM_FAMILY_COUNT] = {
|
||||
USB_BRCM_FAMILY(3390A0),
|
||||
USB_BRCM_FAMILY(4908),
|
||||
USB_BRCM_FAMILY(7250B0),
|
||||
USB_BRCM_FAMILY(7271A0),
|
||||
USB_BRCM_FAMILY(7364A0),
|
||||
@ -203,6 +205,27 @@ usb_reg_bits_map_table[BRCM_FAMILY_COUNT][USB_CTRL_SELECTOR_COUNT] = {
|
||||
USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK,
|
||||
ENDIAN_SETTINGS, /* USB_CTRL_SETUP ENDIAN bits */
|
||||
},
|
||||
/* 4908 */
|
||||
[BRCM_FAMILY_4908] = {
|
||||
0, /* USB_CTRL_SETUP_SCB1_EN_MASK */
|
||||
0, /* USB_CTRL_SETUP_SCB2_EN_MASK */
|
||||
0, /* USB_CTRL_SETUP_SS_EHCI64BIT_EN_MASK */
|
||||
0, /* USB_CTRL_SETUP_STRAP_IPP_SEL_MASK */
|
||||
0, /* USB_CTRL_SETUP_OC3_DISABLE_MASK */
|
||||
0, /* USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK */
|
||||
0, /* USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK */
|
||||
USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK,
|
||||
USB_CTRL_USB_PM_USB_PWRDN_MASK,
|
||||
0, /* USB_CTRL_USB30_CTL1_XHC_SOFT_RESETB_MASK */
|
||||
0, /* USB_CTRL_USB30_CTL1_USB3_IOC_MASK */
|
||||
0, /* USB_CTRL_USB30_CTL1_USB3_IPP_MASK */
|
||||
0, /* USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK */
|
||||
0, /* USB_CTRL_USB_PM_SOFT_RESET_MASK */
|
||||
0, /* USB_CTRL_SETUP_CC_DRD_MODE_ENABLE_MASK */
|
||||
0, /* USB_CTRL_SETUP_STRAP_CC_DRD_MODE_ENABLE_SEL_MASK */
|
||||
0, /* USB_CTRL_USB_PM_USB20_HC_RESETB_VAR_MASK */
|
||||
0, /* USB_CTRL_SETUP ENDIAN bits */
|
||||
},
|
||||
/* 7250b0 */
|
||||
[BRCM_FAMILY_7250B0] = {
|
||||
USB_CTRL_SETUP_SCB1_EN_MASK,
|
||||
@ -559,6 +582,7 @@ static void brcmusb_usb3_pll_54mhz(struct brcm_usb_init_params *params)
|
||||
*/
|
||||
switch (params->selected_family) {
|
||||
case BRCM_FAMILY_3390A0:
|
||||
case BRCM_FAMILY_4908:
|
||||
case BRCM_FAMILY_7250B0:
|
||||
case BRCM_FAMILY_7366C0:
|
||||
case BRCM_FAMILY_74371A0:
|
||||
@ -1004,6 +1028,18 @@ static const struct brcm_usb_init_ops bcm7445_ops = {
|
||||
.set_dual_select = usb_set_dual_select,
|
||||
};
|
||||
|
||||
void brcm_usb_dvr_init_4908(struct brcm_usb_init_params *params)
|
||||
{
|
||||
int fam;
|
||||
|
||||
fam = BRCM_FAMILY_4908;
|
||||
params->selected_family = fam;
|
||||
params->usb_reg_bits_map =
|
||||
&usb_reg_bits_map_table[fam][0];
|
||||
params->family_name = family_names[fam];
|
||||
params->ops = &bcm7445_ops;
|
||||
}
|
||||
|
||||
void brcm_usb_dvr_init_7445(struct brcm_usb_init_params *params)
|
||||
{
|
||||
int fam;
|
||||
|
@ -64,6 +64,7 @@ struct brcm_usb_init_params {
|
||||
bool suspend_with_clocks;
|
||||
};
|
||||
|
||||
void brcm_usb_dvr_init_4908(struct brcm_usb_init_params *params);
|
||||
void brcm_usb_dvr_init_7445(struct brcm_usb_init_params *params);
|
||||
void brcm_usb_dvr_init_7216(struct brcm_usb_init_params *params);
|
||||
void brcm_usb_dvr_init_7211b0(struct brcm_usb_init_params *params);
|
||||
|
@ -283,6 +283,15 @@ static const struct attribute_group brcm_usb_phy_group = {
|
||||
.attrs = brcm_usb_phy_attrs,
|
||||
};
|
||||
|
||||
static const struct match_chip_info chip_info_4908 = {
|
||||
.init_func = &brcm_usb_dvr_init_4908,
|
||||
.required_regs = {
|
||||
BRCM_REGS_CTRL,
|
||||
BRCM_REGS_XHCI_EC,
|
||||
-1,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct match_chip_info chip_info_7216 = {
|
||||
.init_func = &brcm_usb_dvr_init_7216,
|
||||
.required_regs = {
|
||||
@ -318,7 +327,7 @@ static const struct match_chip_info chip_info_7445 = {
|
||||
static const struct of_device_id brcm_usb_dt_ids[] = {
|
||||
{
|
||||
.compatible = "brcm,bcm4908-usb-phy",
|
||||
.data = &chip_info_7445,
|
||||
.data = &chip_info_4908,
|
||||
},
|
||||
{
|
||||
.compatible = "brcm,bcm7216-usb-phy",
|
||||
|
@ -22,6 +22,14 @@ config PHY_CADENCE_DPHY
|
||||
system. If M is selected, the module will be called
|
||||
cdns-dphy.
|
||||
|
||||
config PHY_CADENCE_DPHY_RX
|
||||
tristate "Cadence D-PHY Rx Support"
|
||||
depends on HAS_IOMEM && OF
|
||||
select GENERIC_PHY
|
||||
select GENERIC_PHY_MIPI_DPHY
|
||||
help
|
||||
Support for Cadence D-PHY in Rx configuration.
|
||||
|
||||
config PHY_CADENCE_SIERRA
|
||||
tristate "Cadence Sierra PHY Driver"
|
||||
depends on OF && HAS_IOMEM && RESET_CONTROLLER
|
||||
|
@ -1,5 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
obj-$(CONFIG_PHY_CADENCE_TORRENT) += phy-cadence-torrent.o
|
||||
obj-$(CONFIG_PHY_CADENCE_DPHY) += cdns-dphy.o
|
||||
obj-$(CONFIG_PHY_CADENCE_DPHY_RX) += cdns-dphy-rx.o
|
||||
obj-$(CONFIG_PHY_CADENCE_SIERRA) += phy-cadence-sierra.o
|
||||
obj-$(CONFIG_PHY_CADENCE_SALVO) += phy-cadence-salvo.o
|
||||
|
255
drivers/phy/cadence/cdns-dphy-rx.c
Normal file
255
drivers/phy/cadence/cdns-dphy-rx.c
Normal file
@ -0,0 +1,255 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (C) 2022 Texas Instruments Incorporated - https://www.ti.com/
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/phy/phy-mipi-dphy.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define DPHY_PMA_CMN(reg) (reg)
|
||||
#define DPHY_PCS(reg) (0xb00 + (reg))
|
||||
#define DPHY_ISO(reg) (0xc00 + (reg))
|
||||
|
||||
#define DPHY_CMN_SSM DPHY_PMA_CMN(0x20)
|
||||
#define DPHY_CMN_RX_MODE_EN BIT(10)
|
||||
#define DPHY_CMN_RX_BANDGAP_TIMER_MASK GENMASK(8, 1)
|
||||
#define DPHY_CMN_SSM_EN BIT(0)
|
||||
|
||||
#define DPHY_CMN_RX_BANDGAP_TIMER 0x14
|
||||
|
||||
#define DPHY_BAND_CFG DPHY_PCS(0x0)
|
||||
#define DPHY_BAND_CFG_RIGHT_BAND GENMASK(9, 5)
|
||||
#define DPHY_BAND_CFG_LEFT_BAND GENMASK(4, 0)
|
||||
|
||||
#define DPHY_POWER_ISLAND_EN_DATA DPHY_PCS(0x8)
|
||||
#define DPHY_POWER_ISLAND_EN_DATA_VAL 0xaaaaaaaa
|
||||
|
||||
#define DPHY_POWER_ISLAND_EN_CLK DPHY_PCS(0xc)
|
||||
#define DPHY_POWER_ISLAND_EN_CLK_VAL 0xaa
|
||||
|
||||
#define DPHY_ISO_CL_CTRL_L DPHY_ISO(0x10)
|
||||
#define DPHY_ISO_DL_CTRL_L0 DPHY_ISO(0x14)
|
||||
#define DPHY_ISO_DL_CTRL_L1 DPHY_ISO(0x20)
|
||||
#define DPHY_ISO_DL_CTRL_L2 DPHY_ISO(0x30)
|
||||
#define DPHY_ISO_DL_CTRL_L3 DPHY_ISO(0x3c)
|
||||
|
||||
#define DPHY_ISO_LANE_READY_BIT 0
|
||||
#define DPHY_ISO_LANE_READY_TIMEOUT_MS 100UL
|
||||
|
||||
#define DPHY_LANES_MIN 1
|
||||
#define DPHY_LANES_MAX 4
|
||||
|
||||
struct cdns_dphy_rx {
|
||||
void __iomem *regs;
|
||||
struct device *dev;
|
||||
struct phy *phy;
|
||||
};
|
||||
|
||||
struct cdns_dphy_rx_band {
|
||||
/* Rates are in Mbps. */
|
||||
unsigned int min_rate;
|
||||
unsigned int max_rate;
|
||||
};
|
||||
|
||||
/* Order of bands is important since the index is the band number. */
|
||||
static const struct cdns_dphy_rx_band bands[] = {
|
||||
{ 80, 100 }, { 100, 120 }, { 120, 160 }, { 160, 200 }, { 200, 240 },
|
||||
{ 240, 280 }, { 280, 320 }, { 320, 360 }, { 360, 400 }, { 400, 480 },
|
||||
{ 480, 560 }, { 560, 640 }, { 640, 720 }, { 720, 800 }, { 800, 880 },
|
||||
{ 880, 1040 }, { 1040, 1200 }, { 1200, 1350 }, { 1350, 1500 },
|
||||
{ 1500, 1750 }, { 1750, 2000 }, { 2000, 2250 }, { 2250, 2500 }
|
||||
};
|
||||
|
||||
static int cdns_dphy_rx_power_on(struct phy *phy)
|
||||
{
|
||||
struct cdns_dphy_rx *dphy = phy_get_drvdata(phy);
|
||||
|
||||
/* Start RX state machine. */
|
||||
writel(DPHY_CMN_SSM_EN | DPHY_CMN_RX_MODE_EN |
|
||||
FIELD_PREP(DPHY_CMN_RX_BANDGAP_TIMER_MASK,
|
||||
DPHY_CMN_RX_BANDGAP_TIMER),
|
||||
dphy->regs + DPHY_CMN_SSM);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdns_dphy_rx_power_off(struct phy *phy)
|
||||
{
|
||||
struct cdns_dphy_rx *dphy = phy_get_drvdata(phy);
|
||||
|
||||
writel(0, dphy->regs + DPHY_CMN_SSM);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdns_dphy_rx_get_band_ctrl(unsigned long hs_clk_rate)
|
||||
{
|
||||
unsigned int rate, i;
|
||||
|
||||
rate = hs_clk_rate / 1000000UL;
|
||||
/* Since CSI-2 clock is DDR, the bit rate is twice the clock rate. */
|
||||
rate *= 2;
|
||||
|
||||
if (rate < bands[0].min_rate)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(bands); i++)
|
||||
if (rate < bands[i].max_rate)
|
||||
return i;
|
||||
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int cdns_dphy_rx_wait_for_bit(void __iomem *addr,
|
||||
unsigned int bit)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
return readl_relaxed_poll_timeout(addr, val, val & BIT(bit), 10,
|
||||
DPHY_ISO_LANE_READY_TIMEOUT_MS * 1000);
|
||||
}
|
||||
|
||||
static int cdns_dphy_rx_wait_lane_ready(struct cdns_dphy_rx *dphy,
|
||||
unsigned int lanes)
|
||||
{
|
||||
static const u32 data_lane_ctrl[] = {DPHY_ISO_DL_CTRL_L0,
|
||||
DPHY_ISO_DL_CTRL_L1,
|
||||
DPHY_ISO_DL_CTRL_L2,
|
||||
DPHY_ISO_DL_CTRL_L3};
|
||||
void __iomem *reg = dphy->regs;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
/* Clock lane */
|
||||
ret = cdns_dphy_rx_wait_for_bit(reg + DPHY_ISO_CL_CTRL_L,
|
||||
DPHY_ISO_LANE_READY_BIT);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < lanes; i++) {
|
||||
ret = cdns_dphy_rx_wait_for_bit(reg + data_lane_ctrl[i],
|
||||
DPHY_ISO_LANE_READY_BIT);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdns_dphy_rx_configure(struct phy *phy,
|
||||
union phy_configure_opts *opts)
|
||||
{
|
||||
struct cdns_dphy_rx *dphy = phy_get_drvdata(phy);
|
||||
unsigned int reg, lanes = opts->mipi_dphy.lanes;
|
||||
int band_ctrl, ret;
|
||||
|
||||
/* Data lanes. Minimum one lane is mandatory. */
|
||||
if (lanes < DPHY_LANES_MIN || lanes > DPHY_LANES_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
band_ctrl = cdns_dphy_rx_get_band_ctrl(opts->mipi_dphy.hs_clk_rate);
|
||||
if (band_ctrl < 0)
|
||||
return band_ctrl;
|
||||
|
||||
reg = FIELD_PREP(DPHY_BAND_CFG_LEFT_BAND, band_ctrl) |
|
||||
FIELD_PREP(DPHY_BAND_CFG_RIGHT_BAND, band_ctrl);
|
||||
writel(reg, dphy->regs + DPHY_BAND_CFG);
|
||||
|
||||
/*
|
||||
* Set the required power island phase 2 time. This is mandated by DPHY
|
||||
* specs.
|
||||
*/
|
||||
reg = DPHY_POWER_ISLAND_EN_DATA_VAL;
|
||||
writel(reg, dphy->regs + DPHY_POWER_ISLAND_EN_DATA);
|
||||
reg = DPHY_POWER_ISLAND_EN_CLK_VAL;
|
||||
writel(reg, dphy->regs + DPHY_POWER_ISLAND_EN_CLK);
|
||||
|
||||
ret = cdns_dphy_rx_wait_lane_ready(dphy, lanes);
|
||||
if (ret) {
|
||||
dev_err(dphy->dev, "DPHY wait for lane ready timeout\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdns_dphy_rx_validate(struct phy *phy, enum phy_mode mode,
|
||||
int submode, union phy_configure_opts *opts)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (mode != PHY_MODE_MIPI_DPHY)
|
||||
return -EINVAL;
|
||||
|
||||
ret = cdns_dphy_rx_get_band_ctrl(opts->mipi_dphy.hs_clk_rate);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return phy_mipi_dphy_config_validate(&opts->mipi_dphy);
|
||||
}
|
||||
|
||||
static const struct phy_ops cdns_dphy_rx_ops = {
|
||||
.power_on = cdns_dphy_rx_power_on,
|
||||
.power_off = cdns_dphy_rx_power_off,
|
||||
.configure = cdns_dphy_rx_configure,
|
||||
.validate = cdns_dphy_rx_validate,
|
||||
};
|
||||
|
||||
static int cdns_dphy_rx_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct phy_provider *provider;
|
||||
struct cdns_dphy_rx *dphy;
|
||||
|
||||
dphy = devm_kzalloc(dev, sizeof(*dphy), GFP_KERNEL);
|
||||
if (!dphy)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_set_drvdata(dev, dphy);
|
||||
dphy->dev = dev;
|
||||
|
||||
dphy->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(dphy->regs))
|
||||
return PTR_ERR(dphy->regs);
|
||||
|
||||
dphy->phy = devm_phy_create(dev, NULL, &cdns_dphy_rx_ops);
|
||||
if (IS_ERR(dphy->phy)) {
|
||||
dev_err(dev, "Failed to create PHY: %ld\n", PTR_ERR(dphy->phy));
|
||||
return PTR_ERR(dphy->phy);
|
||||
}
|
||||
|
||||
phy_set_drvdata(dphy->phy, dphy);
|
||||
provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
|
||||
if (IS_ERR(provider)) {
|
||||
dev_err(dev, "Failed to register PHY provider: %ld\n",
|
||||
PTR_ERR(provider));
|
||||
return PTR_ERR(provider);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id cdns_dphy_rx_of_match[] = {
|
||||
{ .compatible = "cdns,dphy-rx" },
|
||||
{ /* sentinel */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, cdns_dphy_rx_of_match);
|
||||
|
||||
static struct platform_driver cdns_dphy_rx_platform_driver = {
|
||||
.probe = cdns_dphy_rx_probe,
|
||||
.driver = {
|
||||
.name = "cdns-mipi-dphy-rx",
|
||||
.of_match_table = cdns_dphy_rx_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(cdns_dphy_rx_platform_driver);
|
||||
|
||||
MODULE_AUTHOR("Pratyush Yadav <p.yadav@ti.com>");
|
||||
MODULE_DESCRIPTION("Cadence D-PHY Rx Driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -263,14 +263,9 @@ static int cdns_salvo_phy_probe(struct platform_device *pdev)
|
||||
struct phy_provider *phy_provider;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct cdns_salvo_phy *salvo_phy;
|
||||
const struct of_device_id *match;
|
||||
struct cdns_salvo_data *data;
|
||||
|
||||
match = of_match_device(cdns_salvo_phy_of_match, dev);
|
||||
if (!match)
|
||||
return -EINVAL;
|
||||
|
||||
data = (struct cdns_salvo_data *)match->data;
|
||||
data = (struct cdns_salvo_data *)of_device_get_match_data(dev);
|
||||
salvo_phy = devm_kzalloc(dev, sizeof(*salvo_phy), GFP_KERNEL);
|
||||
if (!salvo_phy)
|
||||
return -ENOMEM;
|
||||
|
@ -370,6 +370,7 @@ struct cdns_sierra_phy {
|
||||
int nsubnodes;
|
||||
u32 num_lanes;
|
||||
bool autoconf;
|
||||
int already_configured;
|
||||
struct clk_onecell_data clk_data;
|
||||
struct clk *output_clks[CDNS_SIERRA_OUTPUT_CLOCKS];
|
||||
};
|
||||
@ -517,7 +518,7 @@ static int cdns_sierra_phy_init(struct phy *gphy)
|
||||
int i, j;
|
||||
|
||||
/* Initialise the PHY registers, unless auto configured */
|
||||
if (phy->autoconf || phy->nsubnodes > 1)
|
||||
if (phy->autoconf || phy->already_configured || phy->nsubnodes > 1)
|
||||
return 0;
|
||||
|
||||
clk_set_rate(phy->input_clks[CMN_REFCLK_DIG_DIV], 25000000);
|
||||
@ -646,6 +647,18 @@ static const struct phy_ops ops = {
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int cdns_sierra_noop_phy_on(struct phy *gphy)
|
||||
{
|
||||
usleep_range(5000, 10000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct phy_ops noop_ops = {
|
||||
.power_on = cdns_sierra_noop_phy_on,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static u8 cdns_sierra_pll_mux_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct cdns_sierra_pll_mux *mux = to_cdns_sierra_pll_mux(hw);
|
||||
@ -1118,13 +1131,6 @@ static int cdns_sierra_phy_get_clocks(struct cdns_sierra_phy *sp,
|
||||
struct clk *clk;
|
||||
int ret;
|
||||
|
||||
clk = devm_clk_get_optional(dev, "phy_clk");
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(dev, "failed to get clock phy_clk\n");
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
sp->input_clks[PHY_CLK] = clk;
|
||||
|
||||
clk = devm_clk_get_optional(dev, "cmn_refclk_dig_div");
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(dev, "cmn_refclk_dig_div clock not found\n");
|
||||
@ -1160,17 +1166,33 @@ static int cdns_sierra_phy_get_clocks(struct cdns_sierra_phy *sp,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdns_sierra_phy_enable_clocks(struct cdns_sierra_phy *sp)
|
||||
static int cdns_sierra_phy_clk(struct cdns_sierra_phy *sp)
|
||||
{
|
||||
struct device *dev = sp->dev;
|
||||
struct clk *clk;
|
||||
int ret;
|
||||
|
||||
clk = devm_clk_get_optional(dev, "phy_clk");
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(dev, "failed to get clock phy_clk\n");
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
sp->input_clks[PHY_CLK] = clk;
|
||||
|
||||
ret = clk_prepare_enable(sp->input_clks[PHY_CLK]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdns_sierra_phy_enable_clocks(struct cdns_sierra_phy *sp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(sp->output_clks[CDNS_SIERRA_PLL_CMNLC]);
|
||||
if (ret)
|
||||
goto err_pll_cmnlc;
|
||||
return ret;
|
||||
|
||||
ret = clk_prepare_enable(sp->output_clks[CDNS_SIERRA_PLL_CMNLC1]);
|
||||
if (ret)
|
||||
@ -1181,9 +1203,6 @@ static int cdns_sierra_phy_enable_clocks(struct cdns_sierra_phy *sp)
|
||||
err_pll_cmnlc1:
|
||||
clk_disable_unprepare(sp->output_clks[CDNS_SIERRA_PLL_CMNLC]);
|
||||
|
||||
err_pll_cmnlc:
|
||||
clk_disable_unprepare(sp->input_clks[PHY_CLK]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1191,7 +1210,8 @@ static void cdns_sierra_phy_disable_clocks(struct cdns_sierra_phy *sp)
|
||||
{
|
||||
clk_disable_unprepare(sp->output_clks[CDNS_SIERRA_PLL_CMNLC1]);
|
||||
clk_disable_unprepare(sp->output_clks[CDNS_SIERRA_PLL_CMNLC]);
|
||||
clk_disable_unprepare(sp->input_clks[PHY_CLK]);
|
||||
if (!sp->already_configured)
|
||||
clk_disable_unprepare(sp->input_clks[PHY_CLK]);
|
||||
}
|
||||
|
||||
static int cdns_sierra_phy_get_resets(struct cdns_sierra_phy *sp,
|
||||
@ -1382,22 +1402,30 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = cdns_sierra_phy_get_resets(sp, dev);
|
||||
if (ret)
|
||||
goto unregister_clk;
|
||||
|
||||
ret = cdns_sierra_phy_enable_clocks(sp);
|
||||
if (ret)
|
||||
goto unregister_clk;
|
||||
|
||||
/* Enable APB */
|
||||
reset_control_deassert(sp->apb_rst);
|
||||
regmap_field_read(sp->pma_cmn_ready, &sp->already_configured);
|
||||
|
||||
if (!sp->already_configured) {
|
||||
ret = cdns_sierra_phy_clk(sp);
|
||||
if (ret)
|
||||
goto clk_disable;
|
||||
|
||||
ret = cdns_sierra_phy_get_resets(sp, dev);
|
||||
if (ret)
|
||||
goto clk_disable;
|
||||
|
||||
/* Enable APB */
|
||||
reset_control_deassert(sp->apb_rst);
|
||||
}
|
||||
|
||||
/* Check that PHY is present */
|
||||
regmap_field_read(sp->macro_id_type, &id_value);
|
||||
if (sp->init_data->id_value != id_value) {
|
||||
ret = -EINVAL;
|
||||
goto clk_disable;
|
||||
goto ctrl_assert;
|
||||
}
|
||||
|
||||
sp->autoconf = of_property_read_bool(dn, "cdns,autoconf");
|
||||
@ -1433,8 +1461,10 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev)
|
||||
|
||||
sp->num_lanes += sp->phys[node].num_lanes;
|
||||
|
||||
gphy = devm_phy_create(dev, child, &ops);
|
||||
|
||||
if (!sp->already_configured)
|
||||
gphy = devm_phy_create(dev, child, &ops);
|
||||
else
|
||||
gphy = devm_phy_create(dev, child, &noop_ops);
|
||||
if (IS_ERR(gphy)) {
|
||||
ret = PTR_ERR(gphy);
|
||||
of_node_put(child);
|
||||
@ -1455,7 +1485,7 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
/* If more than one subnode, configure the PHY as multilink */
|
||||
if (!sp->autoconf && sp->nsubnodes > 1) {
|
||||
if (!sp->already_configured && !sp->autoconf && sp->nsubnodes > 1) {
|
||||
ret = cdns_sierra_phy_configure_multilink(sp);
|
||||
if (ret)
|
||||
goto put_control;
|
||||
@ -1473,9 +1503,11 @@ static int cdns_sierra_phy_probe(struct platform_device *pdev)
|
||||
put_control:
|
||||
while (--node >= 0)
|
||||
reset_control_put(sp->phys[node].lnk_rst);
|
||||
ctrl_assert:
|
||||
if (!sp->already_configured)
|
||||
reset_control_assert(sp->apb_rst);
|
||||
clk_disable:
|
||||
cdns_sierra_phy_disable_clocks(sp);
|
||||
reset_control_assert(sp->apb_rst);
|
||||
unregister_clk:
|
||||
cdns_sierra_clk_unregister(sp);
|
||||
return ret;
|
||||
|
@ -1,4 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
if (ARCH_MXC && ARM64) || COMPILE_TEST
|
||||
|
||||
config PHY_FSL_IMX8MQ_USB
|
||||
tristate "Freescale i.MX8M USB3 PHY"
|
||||
depends on OF && HAS_IOMEM
|
||||
@ -22,3 +25,5 @@ config PHY_FSL_IMX8M_PCIE
|
||||
help
|
||||
Enable this to add support for the PCIE PHY as found on
|
||||
i.MX8M family of SOCs.
|
||||
|
||||
endif
|
||||
|
@ -5,9 +5,9 @@
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/mfd/syscon/imx7-iomuxc-gpr.h>
|
||||
#include <linux/module.h>
|
||||
@ -15,6 +15,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/reset.h>
|
||||
|
||||
#include <dt-bindings/phy/phy-imx8-pcie.h>
|
||||
|
||||
#define IMX8MM_PCIE_PHY_CMN_REG061 0x184
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -64,10 +64,10 @@ int phy_mipi_dphy_get_default_config(unsigned long pixel_clock,
|
||||
cfg->hs_trail = max(4 * 8 * ui, 60000 + 4 * 4 * ui);
|
||||
|
||||
cfg->init = 100;
|
||||
cfg->lpx = 60000;
|
||||
cfg->lpx = 50000;
|
||||
cfg->ta_get = 5 * cfg->lpx;
|
||||
cfg->ta_go = 4 * cfg->lpx;
|
||||
cfg->ta_sure = 2 * cfg->lpx;
|
||||
cfg->ta_sure = cfg->lpx;
|
||||
cfg->wakeup = 1000;
|
||||
|
||||
cfg->hs_clk_rate = hs_clk_rate;
|
||||
|
@ -335,9 +335,11 @@ static int qcom_edp_phy_power_on(struct phy *phy)
|
||||
writel(0x00, edp->tx0 + TXn_LANE_MODE_1);
|
||||
writel(0x00, edp->tx1 + TXn_LANE_MODE_1);
|
||||
|
||||
ret = qcom_edp_configure_ssc(edp);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (edp->dp_opts.ssc) {
|
||||
ret = qcom_edp_configure_ssc(edp);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = qcom_edp_configure_pll(edp);
|
||||
if (ret)
|
||||
@ -654,6 +656,7 @@ static int qcom_edp_phy_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
static const struct of_device_id qcom_edp_phy_match_table[] = {
|
||||
{ .compatible = "qcom,sc7280-edp-phy" },
|
||||
{ .compatible = "qcom,sc8180x-edp-phy" },
|
||||
{ }
|
||||
};
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/bitfield.h>
|
||||
|
||||
/* USB QSCRATCH Hardware registers */
|
||||
#define QSCRATCH_GENERAL_CFG (0x08)
|
||||
@ -74,20 +75,20 @@
|
||||
PHY_PARAM_CTRL1_LOS_BIAS_MASK)
|
||||
|
||||
#define PHY_PARAM_CTRL1_TX_FULL_SWING(x) \
|
||||
(((x) << 20) & PHY_PARAM_CTRL1_TX_FULL_SWING_MASK)
|
||||
FIELD_PREP(PHY_PARAM_CTRL1_TX_FULL_SWING_MASK, (x))
|
||||
#define PHY_PARAM_CTRL1_TX_DEEMPH_6DB(x) \
|
||||
(((x) << 14) & PHY_PARAM_CTRL1_TX_DEEMPH_6DB_MASK)
|
||||
FIELD_PREP(PHY_PARAM_CTRL1_TX_DEEMPH_6DB_MASK, (x))
|
||||
#define PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB(x) \
|
||||
(((x) << 8) & PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB_MASK)
|
||||
FIELD_PREP(PHY_PARAM_CTRL1_TX_DEEMPH_3_5DB_MASK, x)
|
||||
#define PHY_PARAM_CTRL1_LOS_BIAS(x) \
|
||||
(((x) << 3) & PHY_PARAM_CTRL1_LOS_BIAS_MASK)
|
||||
FIELD_PREP(PHY_PARAM_CTRL1_LOS_BIAS_MASK, (x))
|
||||
|
||||
/* RX OVRD IN HI bits */
|
||||
#define RX_OVRD_IN_HI_RX_RESET_OVRD BIT(13)
|
||||
#define RX_OVRD_IN_HI_RX_RX_RESET BIT(12)
|
||||
#define RX_OVRD_IN_HI_RX_EQ_OVRD BIT(11)
|
||||
#define RX_OVRD_IN_HI_RX_EQ_MASK GENMASK(10, 7)
|
||||
#define RX_OVRD_IN_HI_RX_EQ(x) ((x) << 8)
|
||||
#define RX_OVRD_IN_HI_RX_EQ(x) FIELD_PREP(RX_OVRD_IN_HI_RX_EQ_MASK, (x))
|
||||
#define RX_OVRD_IN_HI_RX_EQ_EN_OVRD BIT(7)
|
||||
#define RX_OVRD_IN_HI_RX_EQ_EN BIT(6)
|
||||
#define RX_OVRD_IN_HI_RX_LOS_FILTER_OVRD BIT(5)
|
||||
@ -111,6 +112,9 @@
|
||||
#define SS_CR_READ_REG BIT(0)
|
||||
#define SS_CR_WRITE_REG BIT(0)
|
||||
|
||||
#define LATCH_SLEEP 40
|
||||
#define LATCH_TIMEOUT 100
|
||||
|
||||
struct usb_phy {
|
||||
void __iomem *base;
|
||||
struct device *dev;
|
||||
@ -156,19 +160,9 @@ static inline void usb_phy_write_readback(struct usb_phy *phy_dwc3,
|
||||
|
||||
static int wait_for_latch(void __iomem *addr)
|
||||
{
|
||||
u32 retry = 10;
|
||||
u32 val;
|
||||
|
||||
while (true) {
|
||||
if (!readl(addr))
|
||||
break;
|
||||
|
||||
if (--retry == 0)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
usleep_range(10, 20);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return readl_poll_timeout(addr, val, !val, LATCH_SLEEP, LATCH_TIMEOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -5977,6 +5977,9 @@ static const struct of_device_id qcom_qmp_phy_of_match_table[] = {
|
||||
}, {
|
||||
.compatible = "qcom,sc8180x-qmp-ufs-phy",
|
||||
.data = &sm8150_ufsphy_cfg,
|
||||
}, {
|
||||
.compatible = "qcom,sc8280xp-qmp-ufs-phy",
|
||||
.data = &sm8350_ufsphy_cfg,
|
||||
}, {
|
||||
.compatible = "qcom,sc8180x-qmp-usb3-phy",
|
||||
.data = &sm8150_usb3phy_cfg,
|
||||
|
@ -911,6 +911,9 @@ static const struct of_device_id qusb2_phy_of_match_table[] = {
|
||||
}, {
|
||||
.compatible = "qcom,ipq8074-qusb2-phy",
|
||||
.data = &msm8996_phy_cfg,
|
||||
}, {
|
||||
.compatible = "qcom,msm8953-qusb2-phy",
|
||||
.data = &msm8996_phy_cfg,
|
||||
}, {
|
||||
.compatible = "qcom,msm8996-qusb2-phy",
|
||||
.data = &msm8996_phy_cfg,
|
||||
|
@ -32,6 +32,7 @@
|
||||
#define POR BIT(1)
|
||||
|
||||
#define USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON0 (0x54)
|
||||
#define SIDDQ BIT(2)
|
||||
#define RETENABLEN BIT(3)
|
||||
#define FSEL_MASK GENMASK(6, 4)
|
||||
#define FSEL_DEFAULT (0x3 << 4)
|
||||
@ -233,6 +234,9 @@ static int qcom_snps_hsphy_init(struct phy *phy)
|
||||
qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_UTMI_CTRL0,
|
||||
SLEEPM, SLEEPM);
|
||||
|
||||
qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON0,
|
||||
SIDDQ, 0);
|
||||
|
||||
qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_UTMI_CTRL5,
|
||||
POR, 0);
|
||||
|
||||
@ -275,6 +279,7 @@ static const struct phy_ops qcom_snps_hsphy_gen_ops = {
|
||||
|
||||
static const struct of_device_id qcom_snps_hsphy_of_match_table[] = {
|
||||
{ .compatible = "qcom,sm8150-usb-hs-phy", },
|
||||
{ .compatible = "qcom,usb-snps-hs-5nm-phy", },
|
||||
{ .compatible = "qcom,usb-snps-hs-7nm-phy", },
|
||||
{ .compatible = "qcom,usb-snps-femto-v2-phy", },
|
||||
{ }
|
||||
|
@ -66,6 +66,14 @@ config PHY_ROCKCHIP_INNO_DSIDPHY
|
||||
Enable this to support the Rockchip MIPI/LVDS/TTL PHY with
|
||||
Innosilicon IP block.
|
||||
|
||||
config PHY_ROCKCHIP_NANENG_COMBO_PHY
|
||||
tristate "Rockchip NANENG COMBO PHY Driver"
|
||||
depends on ARCH_ROCKCHIP && OF
|
||||
select GENERIC_PHY
|
||||
help
|
||||
Enable this to support the Rockchip PCIe/USB3.0/SATA/QSGMII
|
||||
combo PHY with NaNeng IP block.
|
||||
|
||||
config PHY_ROCKCHIP_PCIE
|
||||
tristate "Rockchip PCIe PHY Driver"
|
||||
depends on (ARCH_ROCKCHIP && OF) || COMPILE_TEST
|
||||
|
@ -6,6 +6,7 @@ obj-$(CONFIG_PHY_ROCKCHIP_INNO_CSIDPHY) += phy-rockchip-inno-csidphy.o
|
||||
obj-$(CONFIG_PHY_ROCKCHIP_INNO_DSIDPHY) += phy-rockchip-inno-dsidphy.o
|
||||
obj-$(CONFIG_PHY_ROCKCHIP_INNO_HDMI) += phy-rockchip-inno-hdmi.o
|
||||
obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2) += phy-rockchip-inno-usb2.o
|
||||
obj-$(CONFIG_PHY_ROCKCHIP_NANENG_COMBO_PHY) += phy-rockchip-naneng-combphy.o
|
||||
obj-$(CONFIG_PHY_ROCKCHIP_PCIE) += phy-rockchip-pcie.o
|
||||
obj-$(CONFIG_PHY_ROCKCHIP_TYPEC) += phy-rockchip-typec.o
|
||||
obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o
|
||||
|
581
drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
Normal file
581
drivers/phy/rockchip/phy-rockchip-naneng-combphy.c
Normal file
@ -0,0 +1,581 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Rockchip PIPE USB3.0 PCIE SATA Combo Phy driver
|
||||
*
|
||||
* Copyright (C) 2021 Rockchip Electronics Co., Ltd.
|
||||
*/
|
||||
|
||||
#include <dt-bindings/phy/phy.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/units.h>
|
||||
|
||||
#define BIT_WRITEABLE_SHIFT 16
|
||||
#define REF_CLOCK_24MHz (24 * HZ_PER_MHZ)
|
||||
#define REF_CLOCK_25MHz (25 * HZ_PER_MHZ)
|
||||
#define REF_CLOCK_100MHz (100 * HZ_PER_MHZ)
|
||||
|
||||
/* COMBO PHY REG */
|
||||
#define PHYREG6 0x14
|
||||
#define PHYREG6_PLL_DIV_MASK GENMASK(7, 6)
|
||||
#define PHYREG6_PLL_DIV_SHIFT 6
|
||||
#define PHYREG6_PLL_DIV_2 1
|
||||
|
||||
#define PHYREG7 0x18
|
||||
#define PHYREG7_TX_RTERM_MASK GENMASK(7, 4)
|
||||
#define PHYREG7_TX_RTERM_SHIFT 4
|
||||
#define PHYREG7_TX_RTERM_50OHM 8
|
||||
#define PHYREG7_RX_RTERM_MASK GENMASK(3, 0)
|
||||
#define PHYREG7_RX_RTERM_SHIFT 0
|
||||
#define PHYREG7_RX_RTERM_44OHM 15
|
||||
|
||||
#define PHYREG8 0x1C
|
||||
#define PHYREG8_SSC_EN BIT(4)
|
||||
|
||||
#define PHYREG11 0x28
|
||||
#define PHYREG11_SU_TRIM_0_7 0xF0
|
||||
|
||||
#define PHYREG12 0x2C
|
||||
#define PHYREG12_PLL_LPF_ADJ_VALUE 4
|
||||
|
||||
#define PHYREG13 0x30
|
||||
#define PHYREG13_RESISTER_MASK GENMASK(5, 4)
|
||||
#define PHYREG13_RESISTER_SHIFT 0x4
|
||||
#define PHYREG13_RESISTER_HIGH_Z 3
|
||||
#define PHYREG13_CKRCV_AMP0 BIT(7)
|
||||
|
||||
#define PHYREG14 0x34
|
||||
#define PHYREG14_CKRCV_AMP1 BIT(0)
|
||||
|
||||
#define PHYREG15 0x38
|
||||
#define PHYREG15_CTLE_EN BIT(0)
|
||||
#define PHYREG15_SSC_CNT_MASK GENMASK(7, 6)
|
||||
#define PHYREG15_SSC_CNT_SHIFT 6
|
||||
#define PHYREG15_SSC_CNT_VALUE 1
|
||||
|
||||
#define PHYREG16 0x3C
|
||||
#define PHYREG16_SSC_CNT_VALUE 0x5f
|
||||
|
||||
#define PHYREG18 0x44
|
||||
#define PHYREG18_PLL_LOOP 0x32
|
||||
|
||||
#define PHYREG32 0x7C
|
||||
#define PHYREG32_SSC_MASK GENMASK(7, 4)
|
||||
#define PHYREG32_SSC_DIR_SHIFT 4
|
||||
#define PHYREG32_SSC_UPWARD 0
|
||||
#define PHYREG32_SSC_DOWNWARD 1
|
||||
#define PHYREG32_SSC_OFFSET_SHIFT 6
|
||||
#define PHYREG32_SSC_OFFSET_500PPM 1
|
||||
|
||||
#define PHYREG33 0x80
|
||||
#define PHYREG33_PLL_KVCO_MASK GENMASK(4, 2)
|
||||
#define PHYREG33_PLL_KVCO_SHIFT 2
|
||||
#define PHYREG33_PLL_KVCO_VALUE 2
|
||||
|
||||
struct rockchip_combphy_priv;
|
||||
|
||||
struct combphy_reg {
|
||||
u16 offset;
|
||||
u16 bitend;
|
||||
u16 bitstart;
|
||||
u16 disable;
|
||||
u16 enable;
|
||||
};
|
||||
|
||||
struct rockchip_combphy_grfcfg {
|
||||
struct combphy_reg pcie_mode_set;
|
||||
struct combphy_reg usb_mode_set;
|
||||
struct combphy_reg sgmii_mode_set;
|
||||
struct combphy_reg qsgmii_mode_set;
|
||||
struct combphy_reg pipe_rxterm_set;
|
||||
struct combphy_reg pipe_txelec_set;
|
||||
struct combphy_reg pipe_txcomp_set;
|
||||
struct combphy_reg pipe_clk_25m;
|
||||
struct combphy_reg pipe_clk_100m;
|
||||
struct combphy_reg pipe_phymode_sel;
|
||||
struct combphy_reg pipe_rate_sel;
|
||||
struct combphy_reg pipe_rxterm_sel;
|
||||
struct combphy_reg pipe_txelec_sel;
|
||||
struct combphy_reg pipe_txcomp_sel;
|
||||
struct combphy_reg pipe_clk_ext;
|
||||
struct combphy_reg pipe_sel_usb;
|
||||
struct combphy_reg pipe_sel_qsgmii;
|
||||
struct combphy_reg pipe_phy_status;
|
||||
struct combphy_reg con0_for_pcie;
|
||||
struct combphy_reg con1_for_pcie;
|
||||
struct combphy_reg con2_for_pcie;
|
||||
struct combphy_reg con3_for_pcie;
|
||||
struct combphy_reg con0_for_sata;
|
||||
struct combphy_reg con1_for_sata;
|
||||
struct combphy_reg con2_for_sata;
|
||||
struct combphy_reg con3_for_sata;
|
||||
struct combphy_reg pipe_con0_for_sata;
|
||||
struct combphy_reg pipe_xpcs_phy_ready;
|
||||
};
|
||||
|
||||
struct rockchip_combphy_cfg {
|
||||
const struct rockchip_combphy_grfcfg *grfcfg;
|
||||
int (*combphy_cfg)(struct rockchip_combphy_priv *priv);
|
||||
};
|
||||
|
||||
struct rockchip_combphy_priv {
|
||||
u8 type;
|
||||
void __iomem *mmio;
|
||||
int num_clks;
|
||||
struct clk_bulk_data *clks;
|
||||
struct device *dev;
|
||||
struct regmap *pipe_grf;
|
||||
struct regmap *phy_grf;
|
||||
struct phy *phy;
|
||||
struct reset_control *phy_rst;
|
||||
const struct rockchip_combphy_cfg *cfg;
|
||||
bool enable_ssc;
|
||||
bool ext_refclk;
|
||||
struct clk *refclk;
|
||||
};
|
||||
|
||||
static void rockchip_combphy_updatel(struct rockchip_combphy_priv *priv,
|
||||
int mask, int val, int reg)
|
||||
{
|
||||
unsigned int temp;
|
||||
|
||||
temp = readl(priv->mmio + reg);
|
||||
temp = (temp & ~(mask)) | val;
|
||||
writel(temp, priv->mmio + reg);
|
||||
}
|
||||
|
||||
static int rockchip_combphy_param_write(struct regmap *base,
|
||||
const struct combphy_reg *reg, bool en)
|
||||
{
|
||||
u32 val, mask, tmp;
|
||||
|
||||
tmp = en ? reg->enable : reg->disable;
|
||||
mask = GENMASK(reg->bitend, reg->bitstart);
|
||||
val = (tmp << reg->bitstart) | (mask << BIT_WRITEABLE_SHIFT);
|
||||
|
||||
return regmap_write(base, reg->offset, val);
|
||||
}
|
||||
|
||||
static u32 rockchip_combphy_is_ready(struct rockchip_combphy_priv *priv)
|
||||
{
|
||||
const struct rockchip_combphy_grfcfg *cfg = priv->cfg->grfcfg;
|
||||
u32 mask, val;
|
||||
|
||||
mask = GENMASK(cfg->pipe_phy_status.bitend,
|
||||
cfg->pipe_phy_status.bitstart);
|
||||
|
||||
regmap_read(priv->phy_grf, cfg->pipe_phy_status.offset, &val);
|
||||
val = (val & mask) >> cfg->pipe_phy_status.bitstart;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static int rockchip_combphy_init(struct phy *phy)
|
||||
{
|
||||
struct rockchip_combphy_priv *priv = phy_get_drvdata(phy);
|
||||
const struct rockchip_combphy_grfcfg *cfg = priv->cfg->grfcfg;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
ret = clk_bulk_prepare_enable(priv->num_clks, priv->clks);
|
||||
if (ret) {
|
||||
dev_err(priv->dev, "failed to enable clks\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (priv->type) {
|
||||
case PHY_TYPE_PCIE:
|
||||
case PHY_TYPE_USB3:
|
||||
case PHY_TYPE_SATA:
|
||||
case PHY_TYPE_SGMII:
|
||||
case PHY_TYPE_QSGMII:
|
||||
if (priv->cfg->combphy_cfg)
|
||||
ret = priv->cfg->combphy_cfg(priv);
|
||||
break;
|
||||
default:
|
||||
dev_err(priv->dev, "incompatible PHY type\n");
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
dev_err(priv->dev, "failed to init phy for phy type %x\n", priv->type);
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
ret = reset_control_deassert(priv->phy_rst);
|
||||
if (ret)
|
||||
goto err_clk;
|
||||
|
||||
if (priv->type == PHY_TYPE_USB3) {
|
||||
ret = readx_poll_timeout_atomic(rockchip_combphy_is_ready,
|
||||
priv, val,
|
||||
val == cfg->pipe_phy_status.enable,
|
||||
10, 1000);
|
||||
if (ret)
|
||||
dev_warn(priv->dev, "wait phy status ready timeout\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_clk:
|
||||
clk_bulk_disable_unprepare(priv->num_clks, priv->clks);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rockchip_combphy_exit(struct phy *phy)
|
||||
{
|
||||
struct rockchip_combphy_priv *priv = phy_get_drvdata(phy);
|
||||
|
||||
clk_bulk_disable_unprepare(priv->num_clks, priv->clks);
|
||||
reset_control_assert(priv->phy_rst);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct phy_ops rochchip_combphy_ops = {
|
||||
.init = rockchip_combphy_init,
|
||||
.exit = rockchip_combphy_exit,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static struct phy *rockchip_combphy_xlate(struct device *dev, struct of_phandle_args *args)
|
||||
{
|
||||
struct rockchip_combphy_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
if (args->args_count != 1) {
|
||||
dev_err(dev, "invalid number of arguments\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
if (priv->type != PHY_NONE && priv->type != args->args[0])
|
||||
dev_warn(dev, "phy type select %d overwriting type %d\n",
|
||||
args->args[0], priv->type);
|
||||
|
||||
priv->type = args->args[0];
|
||||
|
||||
return priv->phy;
|
||||
}
|
||||
|
||||
static int rockchip_combphy_parse_dt(struct device *dev, struct rockchip_combphy_priv *priv)
|
||||
{
|
||||
int i;
|
||||
|
||||
priv->num_clks = devm_clk_bulk_get_all(dev, &priv->clks);
|
||||
if (priv->num_clks < 1)
|
||||
return -EINVAL;
|
||||
|
||||
priv->refclk = NULL;
|
||||
for (i = 0; i < priv->num_clks; i++) {
|
||||
if (!strncmp(priv->clks[i].id, "ref", 3)) {
|
||||
priv->refclk = priv->clks[i].clk;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!priv->refclk) {
|
||||
dev_err(dev, "no refclk found\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
priv->pipe_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,pipe-grf");
|
||||
if (IS_ERR(priv->pipe_grf)) {
|
||||
dev_err(dev, "failed to find peri_ctrl pipe-grf regmap\n");
|
||||
return PTR_ERR(priv->pipe_grf);
|
||||
}
|
||||
|
||||
priv->phy_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,pipe-phy-grf");
|
||||
if (IS_ERR(priv->phy_grf)) {
|
||||
dev_err(dev, "failed to find peri_ctrl pipe-phy-grf regmap\n");
|
||||
return PTR_ERR(priv->phy_grf);
|
||||
}
|
||||
|
||||
priv->enable_ssc = device_property_present(dev, "rockchip,enable-ssc");
|
||||
|
||||
priv->ext_refclk = device_property_present(dev, "rockchip,ext-refclk");
|
||||
|
||||
priv->phy_rst = devm_reset_control_array_get_exclusive(dev);
|
||||
if (IS_ERR(priv->phy_rst))
|
||||
return dev_err_probe(dev, PTR_ERR(priv->phy_rst), "failed to get phy reset\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rockchip_combphy_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct phy_provider *phy_provider;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct rockchip_combphy_priv *priv;
|
||||
const struct rockchip_combphy_cfg *phy_cfg;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
phy_cfg = of_device_get_match_data(dev);
|
||||
if (!phy_cfg) {
|
||||
dev_err(dev, "no OF match data provided\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->mmio = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
|
||||
if (IS_ERR(priv->mmio)) {
|
||||
ret = PTR_ERR(priv->mmio);
|
||||
return ret;
|
||||
}
|
||||
|
||||
priv->dev = dev;
|
||||
priv->type = PHY_NONE;
|
||||
priv->cfg = phy_cfg;
|
||||
|
||||
ret = rockchip_combphy_parse_dt(dev, priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = reset_control_assert(priv->phy_rst);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to reset phy\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
priv->phy = devm_phy_create(dev, NULL, &rochchip_combphy_ops);
|
||||
if (IS_ERR(priv->phy)) {
|
||||
dev_err(dev, "failed to create combphy\n");
|
||||
return PTR_ERR(priv->phy);
|
||||
}
|
||||
|
||||
dev_set_drvdata(dev, priv);
|
||||
phy_set_drvdata(priv->phy, priv);
|
||||
|
||||
phy_provider = devm_of_phy_provider_register(dev, rockchip_combphy_xlate);
|
||||
|
||||
return PTR_ERR_OR_ZERO(phy_provider);
|
||||
}
|
||||
|
||||
static int rk3568_combphy_cfg(struct rockchip_combphy_priv *priv)
|
||||
{
|
||||
const struct rockchip_combphy_grfcfg *cfg = priv->cfg->grfcfg;
|
||||
unsigned long rate;
|
||||
u32 val;
|
||||
|
||||
switch (priv->type) {
|
||||
case PHY_TYPE_PCIE:
|
||||
/* Set SSC downward spread spectrum. */
|
||||
rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK,
|
||||
PHYREG32_SSC_DOWNWARD << PHYREG32_SSC_DIR_SHIFT,
|
||||
PHYREG32);
|
||||
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->con0_for_pcie, true);
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->con1_for_pcie, true);
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->con2_for_pcie, true);
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->con3_for_pcie, true);
|
||||
break;
|
||||
|
||||
case PHY_TYPE_USB3:
|
||||
/* Set SSC downward spread spectrum. */
|
||||
rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK,
|
||||
PHYREG32_SSC_DOWNWARD << PHYREG32_SSC_DIR_SHIFT,
|
||||
PHYREG32);
|
||||
|
||||
/* Enable adaptive CTLE for USB3.0 Rx. */
|
||||
val = readl(priv->mmio + PHYREG15);
|
||||
val |= PHYREG15_CTLE_EN;
|
||||
writel(val, priv->mmio + PHYREG15);
|
||||
|
||||
/* Set PLL KVCO fine tuning signals. */
|
||||
rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK,
|
||||
PHYREG33_PLL_KVCO_VALUE << PHYREG33_PLL_KVCO_SHIFT,
|
||||
PHYREG33);
|
||||
|
||||
/* Enable controlling random jitter. */
|
||||
writel(PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + PHYREG12);
|
||||
|
||||
/* Set PLL input clock divider 1/2. */
|
||||
rockchip_combphy_updatel(priv, PHYREG6_PLL_DIV_MASK,
|
||||
PHYREG6_PLL_DIV_2 << PHYREG6_PLL_DIV_SHIFT,
|
||||
PHYREG6);
|
||||
|
||||
writel(PHYREG18_PLL_LOOP, priv->mmio + PHYREG18);
|
||||
writel(PHYREG11_SU_TRIM_0_7, priv->mmio + PHYREG11);
|
||||
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_sel_usb, true);
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txcomp_sel, false);
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_txelec_sel, false);
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->usb_mode_set, true);
|
||||
break;
|
||||
|
||||
case PHY_TYPE_SATA:
|
||||
/* Enable adaptive CTLE for SATA Rx. */
|
||||
val = readl(priv->mmio + PHYREG15);
|
||||
val |= PHYREG15_CTLE_EN;
|
||||
writel(val, priv->mmio + PHYREG15);
|
||||
/*
|
||||
* Set tx_rterm=50ohm and rx_rterm=44ohm for SATA.
|
||||
* 0: 60ohm, 8: 50ohm 15: 44ohm (by step abort 1ohm)
|
||||
*/
|
||||
val = PHYREG7_TX_RTERM_50OHM << PHYREG7_TX_RTERM_SHIFT;
|
||||
val |= PHYREG7_RX_RTERM_44OHM << PHYREG7_RX_RTERM_SHIFT;
|
||||
writel(val, priv->mmio + PHYREG7);
|
||||
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->con0_for_sata, true);
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->con1_for_sata, true);
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->con2_for_sata, true);
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->con3_for_sata, true);
|
||||
rockchip_combphy_param_write(priv->pipe_grf, &cfg->pipe_con0_for_sata, true);
|
||||
break;
|
||||
|
||||
case PHY_TYPE_SGMII:
|
||||
rockchip_combphy_param_write(priv->pipe_grf, &cfg->pipe_xpcs_phy_ready, true);
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_phymode_sel, true);
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_sel_qsgmii, true);
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->sgmii_mode_set, true);
|
||||
break;
|
||||
|
||||
case PHY_TYPE_QSGMII:
|
||||
rockchip_combphy_param_write(priv->pipe_grf, &cfg->pipe_xpcs_phy_ready, true);
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_phymode_sel, true);
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_rate_sel, true);
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_sel_qsgmii, true);
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->qsgmii_mode_set, true);
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(priv->dev, "incompatible PHY type\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rate = clk_get_rate(priv->refclk);
|
||||
|
||||
switch (rate) {
|
||||
case REF_CLOCK_24MHz:
|
||||
if (priv->type == PHY_TYPE_USB3 || priv->type == PHY_TYPE_SATA) {
|
||||
/* Set ssc_cnt[9:0]=0101111101 & 31.5KHz. */
|
||||
val = PHYREG15_SSC_CNT_VALUE << PHYREG15_SSC_CNT_SHIFT;
|
||||
rockchip_combphy_updatel(priv, PHYREG15_SSC_CNT_MASK,
|
||||
val, PHYREG15);
|
||||
|
||||
writel(PHYREG16_SSC_CNT_VALUE, priv->mmio + PHYREG16);
|
||||
}
|
||||
break;
|
||||
|
||||
case REF_CLOCK_25MHz:
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_25m, true);
|
||||
break;
|
||||
|
||||
case REF_CLOCK_100MHz:
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_100m, true);
|
||||
if (priv->type == PHY_TYPE_PCIE) {
|
||||
/* PLL KVCO fine tuning. */
|
||||
val = PHYREG33_PLL_KVCO_VALUE << PHYREG33_PLL_KVCO_SHIFT;
|
||||
rockchip_combphy_updatel(priv, PHYREG33_PLL_KVCO_MASK,
|
||||
val, PHYREG33);
|
||||
|
||||
/* Enable controlling random jitter. */
|
||||
writel(PHYREG12_PLL_LPF_ADJ_VALUE, priv->mmio + PHYREG12);
|
||||
|
||||
val = PHYREG6_PLL_DIV_2 << PHYREG6_PLL_DIV_SHIFT;
|
||||
rockchip_combphy_updatel(priv, PHYREG6_PLL_DIV_MASK,
|
||||
val, PHYREG6);
|
||||
|
||||
writel(PHYREG18_PLL_LOOP, priv->mmio + PHYREG18);
|
||||
writel(PHYREG11_SU_TRIM_0_7, priv->mmio + PHYREG11);
|
||||
} else if (priv->type == PHY_TYPE_SATA) {
|
||||
/* downward spread spectrum +500ppm */
|
||||
val = PHYREG32_SSC_DOWNWARD << PHYREG32_SSC_DIR_SHIFT;
|
||||
val |= PHYREG32_SSC_OFFSET_500PPM << PHYREG32_SSC_OFFSET_SHIFT;
|
||||
rockchip_combphy_updatel(priv, PHYREG32_SSC_MASK, val, PHYREG32);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(priv->dev, "unsupported rate: %lu\n", rate);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (priv->ext_refclk) {
|
||||
rockchip_combphy_param_write(priv->phy_grf, &cfg->pipe_clk_ext, true);
|
||||
if (priv->type == PHY_TYPE_PCIE && rate == REF_CLOCK_100MHz) {
|
||||
val = PHYREG13_RESISTER_HIGH_Z << PHYREG13_RESISTER_SHIFT;
|
||||
val |= PHYREG13_CKRCV_AMP0;
|
||||
rockchip_combphy_updatel(priv, PHYREG13_RESISTER_MASK, val, PHYREG13);
|
||||
|
||||
val = readl(priv->mmio + PHYREG14);
|
||||
val |= PHYREG14_CKRCV_AMP1;
|
||||
writel(val, priv->mmio + PHYREG14);
|
||||
}
|
||||
}
|
||||
|
||||
if (priv->enable_ssc) {
|
||||
val = readl(priv->mmio + PHYREG8);
|
||||
val |= PHYREG8_SSC_EN;
|
||||
writel(val, priv->mmio + PHYREG8);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct rockchip_combphy_grfcfg rk3568_combphy_grfcfgs = {
|
||||
/* pipe-phy-grf */
|
||||
.pcie_mode_set = { 0x0000, 5, 0, 0x00, 0x11 },
|
||||
.usb_mode_set = { 0x0000, 5, 0, 0x00, 0x04 },
|
||||
.sgmii_mode_set = { 0x0000, 5, 0, 0x00, 0x01 },
|
||||
.qsgmii_mode_set = { 0x0000, 5, 0, 0x00, 0x21 },
|
||||
.pipe_rxterm_set = { 0x0000, 12, 12, 0x00, 0x01 },
|
||||
.pipe_txelec_set = { 0x0004, 1, 1, 0x00, 0x01 },
|
||||
.pipe_txcomp_set = { 0x0004, 4, 4, 0x00, 0x01 },
|
||||
.pipe_clk_25m = { 0x0004, 14, 13, 0x00, 0x01 },
|
||||
.pipe_clk_100m = { 0x0004, 14, 13, 0x00, 0x02 },
|
||||
.pipe_phymode_sel = { 0x0008, 1, 1, 0x00, 0x01 },
|
||||
.pipe_rate_sel = { 0x0008, 2, 2, 0x00, 0x01 },
|
||||
.pipe_rxterm_sel = { 0x0008, 8, 8, 0x00, 0x01 },
|
||||
.pipe_txelec_sel = { 0x0008, 12, 12, 0x00, 0x01 },
|
||||
.pipe_txcomp_sel = { 0x0008, 15, 15, 0x00, 0x01 },
|
||||
.pipe_clk_ext = { 0x000c, 9, 8, 0x02, 0x01 },
|
||||
.pipe_sel_usb = { 0x000c, 14, 13, 0x00, 0x01 },
|
||||
.pipe_sel_qsgmii = { 0x000c, 15, 13, 0x00, 0x07 },
|
||||
.pipe_phy_status = { 0x0034, 6, 6, 0x01, 0x00 },
|
||||
.con0_for_pcie = { 0x0000, 15, 0, 0x00, 0x1000 },
|
||||
.con1_for_pcie = { 0x0004, 15, 0, 0x00, 0x0000 },
|
||||
.con2_for_pcie = { 0x0008, 15, 0, 0x00, 0x0101 },
|
||||
.con3_for_pcie = { 0x000c, 15, 0, 0x00, 0x0200 },
|
||||
.con0_for_sata = { 0x0000, 15, 0, 0x00, 0x0119 },
|
||||
.con1_for_sata = { 0x0004, 15, 0, 0x00, 0x0040 },
|
||||
.con2_for_sata = { 0x0008, 15, 0, 0x00, 0x80c3 },
|
||||
.con3_for_sata = { 0x000c, 15, 0, 0x00, 0x4407 },
|
||||
/* pipe-grf */
|
||||
.pipe_con0_for_sata = { 0x0000, 15, 0, 0x00, 0x2220 },
|
||||
.pipe_xpcs_phy_ready = { 0x0040, 2, 2, 0x00, 0x01 },
|
||||
};
|
||||
|
||||
static const struct rockchip_combphy_cfg rk3568_combphy_cfgs = {
|
||||
.grfcfg = &rk3568_combphy_grfcfgs,
|
||||
.combphy_cfg = rk3568_combphy_cfg,
|
||||
};
|
||||
|
||||
static const struct of_device_id rockchip_combphy_of_match[] = {
|
||||
{
|
||||
.compatible = "rockchip,rk3568-naneng-combphy",
|
||||
.data = &rk3568_combphy_cfgs,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rockchip_combphy_of_match);
|
||||
|
||||
static struct platform_driver rockchip_combphy_driver = {
|
||||
.probe = rockchip_combphy_probe,
|
||||
.driver = {
|
||||
.name = "rockchip-naneng-combphy",
|
||||
.of_match_table = rockchip_combphy_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(rockchip_combphy_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Rockchip NANENG COMBPHY driver");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -8,24 +8,93 @@
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/ulpi/driver.h>
|
||||
#include <linux/ulpi/regs.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/phy/ulpi_phy.h>
|
||||
#include <linux/power_supply.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#define TUSB1210_VENDOR_SPECIFIC2 0x80
|
||||
#define TUSB1210_VENDOR_SPECIFIC2_IHSTX_MASK GENMASK(3, 0)
|
||||
#define TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_MASK GENMASK(5, 4)
|
||||
#define TUSB1210_VENDOR_SPECIFIC2_DP_MASK BIT(6)
|
||||
#define TUSB1211_POWER_CONTROL 0x3d
|
||||
#define TUSB1211_POWER_CONTROL_SET 0x3e
|
||||
#define TUSB1211_POWER_CONTROL_CLEAR 0x3f
|
||||
#define TUSB1211_POWER_CONTROL_SW_CONTROL BIT(0)
|
||||
#define TUSB1211_POWER_CONTROL_DET_COMP BIT(1)
|
||||
#define TUSB1211_POWER_CONTROL_DP_VSRC_EN BIT(6)
|
||||
|
||||
#define TUSB1210_VENDOR_SPECIFIC2 0x80
|
||||
#define TUSB1210_VENDOR_SPECIFIC2_IHSTX_MASK GENMASK(3, 0)
|
||||
#define TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_MASK GENMASK(5, 4)
|
||||
#define TUSB1210_VENDOR_SPECIFIC2_DP_MASK BIT(6)
|
||||
|
||||
#define TUSB1211_VENDOR_SPECIFIC3 0x85
|
||||
#define TUSB1211_VENDOR_SPECIFIC3_SET 0x86
|
||||
#define TUSB1211_VENDOR_SPECIFIC3_CLEAR 0x87
|
||||
#define TUSB1211_VENDOR_SPECIFIC3_SW_USB_DET BIT(4)
|
||||
#define TUSB1211_VENDOR_SPECIFIC3_CHGD_IDP_SRC_EN BIT(6)
|
||||
|
||||
#define TUSB1210_RESET_TIME_MS 50
|
||||
|
||||
#define TUSB1210_CHG_DET_MAX_RETRIES 5
|
||||
|
||||
/* TUSB1210 charger detection work states */
|
||||
enum tusb1210_chg_det_state {
|
||||
TUSB1210_CHG_DET_CONNECTING,
|
||||
TUSB1210_CHG_DET_START_DET,
|
||||
TUSB1210_CHG_DET_READ_DET,
|
||||
TUSB1210_CHG_DET_FINISH_DET,
|
||||
TUSB1210_CHG_DET_CONNECTED,
|
||||
TUSB1210_CHG_DET_DISCONNECTING,
|
||||
TUSB1210_CHG_DET_DISCONNECTING_DONE,
|
||||
TUSB1210_CHG_DET_DISCONNECTED,
|
||||
};
|
||||
|
||||
struct tusb1210 {
|
||||
struct ulpi *ulpi;
|
||||
struct phy *phy;
|
||||
struct gpio_desc *gpio_reset;
|
||||
struct gpio_desc *gpio_cs;
|
||||
u8 otg_ctrl;
|
||||
u8 vendor_specific2;
|
||||
#ifdef CONFIG_POWER_SUPPLY
|
||||
enum power_supply_usb_type chg_type;
|
||||
enum tusb1210_chg_det_state chg_det_state;
|
||||
int chg_det_retries;
|
||||
struct delayed_work chg_det_work;
|
||||
struct notifier_block psy_nb;
|
||||
struct power_supply *psy;
|
||||
struct power_supply *charger;
|
||||
#endif
|
||||
};
|
||||
|
||||
static int tusb1210_ulpi_write(struct tusb1210 *tusb, u8 reg, u8 val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ulpi_write(tusb->ulpi, reg, val);
|
||||
if (ret)
|
||||
dev_err(&tusb->ulpi->dev, "error %d writing val 0x%02x to reg 0x%02x\n",
|
||||
ret, val, reg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tusb1210_ulpi_read(struct tusb1210 *tusb, u8 reg, u8 *val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ulpi_read(tusb->ulpi, reg);
|
||||
if (ret >= 0) {
|
||||
*val = ret;
|
||||
ret = 0;
|
||||
} else {
|
||||
dev_err(&tusb->ulpi->dev, "error %d reading reg 0x%02x\n", ret, reg);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tusb1210_power_on(struct phy *phy)
|
||||
{
|
||||
struct tusb1210 *tusb = phy_get_drvdata(phy);
|
||||
@ -33,12 +102,11 @@ static int tusb1210_power_on(struct phy *phy)
|
||||
gpiod_set_value_cansleep(tusb->gpio_reset, 1);
|
||||
gpiod_set_value_cansleep(tusb->gpio_cs, 1);
|
||||
|
||||
/* Restore the optional eye diagram optimization value */
|
||||
if (tusb->vendor_specific2)
|
||||
ulpi_write(tusb->ulpi, TUSB1210_VENDOR_SPECIFIC2,
|
||||
tusb->vendor_specific2);
|
||||
msleep(TUSB1210_RESET_TIME_MS);
|
||||
|
||||
return 0;
|
||||
/* Restore the optional eye diagram optimization value */
|
||||
return tusb1210_ulpi_write(tusb, TUSB1210_VENDOR_SPECIFIC2,
|
||||
tusb->vendor_specific2);
|
||||
}
|
||||
|
||||
static int tusb1210_power_off(struct phy *phy)
|
||||
@ -55,35 +123,357 @@ static int tusb1210_set_mode(struct phy *phy, enum phy_mode mode, int submode)
|
||||
{
|
||||
struct tusb1210 *tusb = phy_get_drvdata(phy);
|
||||
int ret;
|
||||
u8 reg;
|
||||
|
||||
ret = ulpi_read(tusb->ulpi, ULPI_OTG_CTRL);
|
||||
ret = tusb1210_ulpi_read(tusb, ULPI_OTG_CTRL, ®);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
switch (mode) {
|
||||
case PHY_MODE_USB_HOST:
|
||||
ret |= (ULPI_OTG_CTRL_DRVVBUS_EXT
|
||||
reg |= (ULPI_OTG_CTRL_DRVVBUS_EXT
|
||||
| ULPI_OTG_CTRL_ID_PULLUP
|
||||
| ULPI_OTG_CTRL_DP_PULLDOWN
|
||||
| ULPI_OTG_CTRL_DM_PULLDOWN);
|
||||
ulpi_write(tusb->ulpi, ULPI_OTG_CTRL, ret);
|
||||
ret |= ULPI_OTG_CTRL_DRVVBUS;
|
||||
tusb1210_ulpi_write(tusb, ULPI_OTG_CTRL, reg);
|
||||
reg |= ULPI_OTG_CTRL_DRVVBUS;
|
||||
break;
|
||||
case PHY_MODE_USB_DEVICE:
|
||||
ret &= ~(ULPI_OTG_CTRL_DRVVBUS
|
||||
reg &= ~(ULPI_OTG_CTRL_DRVVBUS
|
||||
| ULPI_OTG_CTRL_DP_PULLDOWN
|
||||
| ULPI_OTG_CTRL_DM_PULLDOWN);
|
||||
ulpi_write(tusb->ulpi, ULPI_OTG_CTRL, ret);
|
||||
ret &= ~ULPI_OTG_CTRL_DRVVBUS_EXT;
|
||||
tusb1210_ulpi_write(tusb, ULPI_OTG_CTRL, reg);
|
||||
reg &= ~ULPI_OTG_CTRL_DRVVBUS_EXT;
|
||||
break;
|
||||
default:
|
||||
/* nothing */
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ulpi_write(tusb->ulpi, ULPI_OTG_CTRL, ret);
|
||||
tusb->otg_ctrl = reg;
|
||||
return tusb1210_ulpi_write(tusb, ULPI_OTG_CTRL, reg);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_POWER_SUPPLY
|
||||
const char * const tusb1210_chg_det_states[] = {
|
||||
"CHG_DET_CONNECTING",
|
||||
"CHG_DET_START_DET",
|
||||
"CHG_DET_READ_DET",
|
||||
"CHG_DET_FINISH_DET",
|
||||
"CHG_DET_CONNECTED",
|
||||
"CHG_DET_DISCONNECTING",
|
||||
"CHG_DET_DISCONNECTING_DONE",
|
||||
"CHG_DET_DISCONNECTED",
|
||||
};
|
||||
|
||||
static void tusb1210_reset(struct tusb1210 *tusb)
|
||||
{
|
||||
gpiod_set_value_cansleep(tusb->gpio_reset, 0);
|
||||
usleep_range(200, 500);
|
||||
gpiod_set_value_cansleep(tusb->gpio_reset, 1);
|
||||
}
|
||||
|
||||
static void tusb1210_chg_det_set_type(struct tusb1210 *tusb,
|
||||
enum power_supply_usb_type type)
|
||||
{
|
||||
dev_dbg(&tusb->ulpi->dev, "charger type: %d\n", type);
|
||||
tusb->chg_type = type;
|
||||
tusb->chg_det_retries = 0;
|
||||
power_supply_changed(tusb->psy);
|
||||
}
|
||||
|
||||
static void tusb1210_chg_det_set_state(struct tusb1210 *tusb,
|
||||
enum tusb1210_chg_det_state new_state,
|
||||
int delay_ms)
|
||||
{
|
||||
if (delay_ms)
|
||||
dev_dbg(&tusb->ulpi->dev, "chg_det new state %s in %d ms\n",
|
||||
tusb1210_chg_det_states[new_state], delay_ms);
|
||||
|
||||
tusb->chg_det_state = new_state;
|
||||
mod_delayed_work(system_long_wq, &tusb->chg_det_work,
|
||||
msecs_to_jiffies(delay_ms));
|
||||
}
|
||||
|
||||
static void tusb1210_chg_det_handle_ulpi_error(struct tusb1210 *tusb)
|
||||
{
|
||||
tusb1210_reset(tusb);
|
||||
if (tusb->chg_det_retries < TUSB1210_CHG_DET_MAX_RETRIES) {
|
||||
tusb->chg_det_retries++;
|
||||
tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_START_DET,
|
||||
TUSB1210_RESET_TIME_MS);
|
||||
} else {
|
||||
tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_FINISH_DET,
|
||||
TUSB1210_RESET_TIME_MS);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Boards using a TUSB121x for charger-detection have 3 power_supply class devs:
|
||||
*
|
||||
* tusb1211-charger-detect(1) -> charger -> fuel-gauge
|
||||
*
|
||||
* To determine if an USB charger is connected to the board, the online prop of
|
||||
* the charger psy needs to be read. Since the tusb1211-charger-detect psy is
|
||||
* the start of the supplier -> supplied-to chain, power_supply_am_i_supplied()
|
||||
* cannot be used here.
|
||||
*
|
||||
* Instead, below is a list of the power_supply names of known chargers for
|
||||
* these boards and the charger psy is looked up by name from this list.
|
||||
*
|
||||
* (1) modelling the external USB charger
|
||||
*/
|
||||
static const char * const tusb1210_chargers[] = {
|
||||
"bq24190-charger",
|
||||
};
|
||||
|
||||
static bool tusb1210_get_online(struct tusb1210 *tusb)
|
||||
{
|
||||
union power_supply_propval val;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(tusb1210_chargers) && !tusb->charger; i++)
|
||||
tusb->charger = power_supply_get_by_name(tusb1210_chargers[i]);
|
||||
|
||||
if (!tusb->charger)
|
||||
return false;
|
||||
|
||||
if (power_supply_get_property(tusb->charger, POWER_SUPPLY_PROP_ONLINE, &val))
|
||||
return false;
|
||||
|
||||
return val.intval;
|
||||
}
|
||||
|
||||
static void tusb1210_chg_det_work(struct work_struct *work)
|
||||
{
|
||||
struct tusb1210 *tusb = container_of(work, struct tusb1210, chg_det_work.work);
|
||||
bool vbus_present = tusb1210_get_online(tusb);
|
||||
int ret;
|
||||
u8 val;
|
||||
|
||||
dev_dbg(&tusb->ulpi->dev, "chg_det state %s vbus_present %d\n",
|
||||
tusb1210_chg_det_states[tusb->chg_det_state], vbus_present);
|
||||
|
||||
switch (tusb->chg_det_state) {
|
||||
case TUSB1210_CHG_DET_CONNECTING:
|
||||
tusb->chg_type = POWER_SUPPLY_USB_TYPE_UNKNOWN;
|
||||
tusb->chg_det_retries = 0;
|
||||
/* Power on USB controller for ulpi_read()/_write() */
|
||||
ret = pm_runtime_resume_and_get(tusb->ulpi->dev.parent);
|
||||
if (ret < 0) {
|
||||
dev_err(&tusb->ulpi->dev, "error %d runtime-resuming\n", ret);
|
||||
/* Should never happen, skip charger detection */
|
||||
tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_CONNECTED, 0);
|
||||
return;
|
||||
}
|
||||
tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_START_DET, 0);
|
||||
break;
|
||||
case TUSB1210_CHG_DET_START_DET:
|
||||
/*
|
||||
* Use the builtin charger detection FSM to keep things simple.
|
||||
* This only detects DCP / SDP. This is good enough for the few
|
||||
* boards which actually rely on the phy for charger detection.
|
||||
*/
|
||||
mutex_lock(&tusb->phy->mutex);
|
||||
ret = tusb1210_ulpi_write(tusb, TUSB1211_VENDOR_SPECIFIC3_SET,
|
||||
TUSB1211_VENDOR_SPECIFIC3_SW_USB_DET);
|
||||
mutex_unlock(&tusb->phy->mutex);
|
||||
if (ret) {
|
||||
tusb1210_chg_det_handle_ulpi_error(tusb);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Wait 400 ms for the charger detection FSM to finish */
|
||||
tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_READ_DET, 400);
|
||||
break;
|
||||
case TUSB1210_CHG_DET_READ_DET:
|
||||
mutex_lock(&tusb->phy->mutex);
|
||||
ret = tusb1210_ulpi_read(tusb, TUSB1211_POWER_CONTROL, &val);
|
||||
mutex_unlock(&tusb->phy->mutex);
|
||||
if (ret) {
|
||||
tusb1210_chg_det_handle_ulpi_error(tusb);
|
||||
break;
|
||||
}
|
||||
|
||||
if (val & TUSB1211_POWER_CONTROL_DET_COMP)
|
||||
tusb1210_chg_det_set_type(tusb, POWER_SUPPLY_USB_TYPE_DCP);
|
||||
else
|
||||
tusb1210_chg_det_set_type(tusb, POWER_SUPPLY_USB_TYPE_SDP);
|
||||
|
||||
tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_FINISH_DET, 0);
|
||||
break;
|
||||
case TUSB1210_CHG_DET_FINISH_DET:
|
||||
mutex_lock(&tusb->phy->mutex);
|
||||
|
||||
/* Set SW_CONTROL to stop the charger-det FSM */
|
||||
ret = tusb1210_ulpi_write(tusb, TUSB1211_POWER_CONTROL_SET,
|
||||
TUSB1211_POWER_CONTROL_SW_CONTROL);
|
||||
|
||||
/* Clear DP_VSRC_EN which may have been enabled by the charger-det FSM */
|
||||
ret |= tusb1210_ulpi_write(tusb, TUSB1211_POWER_CONTROL_CLEAR,
|
||||
TUSB1211_POWER_CONTROL_DP_VSRC_EN);
|
||||
|
||||
/* Clear CHGD_IDP_SRC_EN (may have been enabled by the charger-det FSM) */
|
||||
ret |= tusb1210_ulpi_write(tusb, TUSB1211_VENDOR_SPECIFIC3_CLEAR,
|
||||
TUSB1211_VENDOR_SPECIFIC3_CHGD_IDP_SRC_EN);
|
||||
|
||||
/* If any of the above fails reset the phy */
|
||||
if (ret) {
|
||||
tusb1210_reset(tusb);
|
||||
msleep(TUSB1210_RESET_TIME_MS);
|
||||
}
|
||||
|
||||
/* Restore phy-parameters and OTG_CTRL register */
|
||||
tusb1210_ulpi_write(tusb, ULPI_OTG_CTRL, tusb->otg_ctrl);
|
||||
tusb1210_ulpi_write(tusb, TUSB1210_VENDOR_SPECIFIC2,
|
||||
tusb->vendor_specific2);
|
||||
|
||||
mutex_unlock(&tusb->phy->mutex);
|
||||
|
||||
pm_runtime_put(tusb->ulpi->dev.parent);
|
||||
tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_CONNECTED, 0);
|
||||
break;
|
||||
case TUSB1210_CHG_DET_CONNECTED:
|
||||
if (!vbus_present)
|
||||
tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_DISCONNECTING, 0);
|
||||
break;
|
||||
case TUSB1210_CHG_DET_DISCONNECTING:
|
||||
/*
|
||||
* The phy seems to take approx. 600ms longer then the charger
|
||||
* chip (which is used to get vbus_present) to determine Vbus
|
||||
* session end. Wait 800ms to ensure the phy has detected and
|
||||
* signalled Vbus session end.
|
||||
*/
|
||||
tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_DISCONNECTING_DONE, 800);
|
||||
break;
|
||||
case TUSB1210_CHG_DET_DISCONNECTING_DONE:
|
||||
/*
|
||||
* The phy often stops reacting to ulpi_read()/_write requests
|
||||
* after a Vbus-session end. Reset it to work around this.
|
||||
*/
|
||||
tusb1210_reset(tusb);
|
||||
tusb1210_chg_det_set_type(tusb, POWER_SUPPLY_USB_TYPE_UNKNOWN);
|
||||
tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_DISCONNECTED, 0);
|
||||
break;
|
||||
case TUSB1210_CHG_DET_DISCONNECTED:
|
||||
if (vbus_present)
|
||||
tusb1210_chg_det_set_state(tusb, TUSB1210_CHG_DET_CONNECTING, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int tusb1210_psy_notifier(struct notifier_block *nb,
|
||||
unsigned long event, void *ptr)
|
||||
{
|
||||
struct tusb1210 *tusb = container_of(nb, struct tusb1210, psy_nb);
|
||||
struct power_supply *psy = ptr;
|
||||
|
||||
if (psy != tusb->psy && psy->desc->type == POWER_SUPPLY_TYPE_USB)
|
||||
queue_delayed_work(system_long_wq, &tusb->chg_det_work, 0);
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static int tusb1210_psy_get_prop(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
{
|
||||
struct tusb1210 *tusb = power_supply_get_drvdata(psy);
|
||||
|
||||
switch (psp) {
|
||||
case POWER_SUPPLY_PROP_ONLINE:
|
||||
val->intval = tusb1210_get_online(tusb);
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_USB_TYPE:
|
||||
val->intval = tusb->chg_type;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_CURRENT_MAX:
|
||||
if (tusb->chg_type == POWER_SUPPLY_USB_TYPE_DCP)
|
||||
val->intval = 2000000;
|
||||
else
|
||||
val->intval = 500000;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const enum power_supply_usb_type tusb1210_psy_usb_types[] = {
|
||||
POWER_SUPPLY_USB_TYPE_SDP,
|
||||
POWER_SUPPLY_USB_TYPE_DCP,
|
||||
POWER_SUPPLY_USB_TYPE_UNKNOWN,
|
||||
};
|
||||
|
||||
static const enum power_supply_property tusb1210_psy_props[] = {
|
||||
POWER_SUPPLY_PROP_ONLINE,
|
||||
POWER_SUPPLY_PROP_USB_TYPE,
|
||||
POWER_SUPPLY_PROP_CURRENT_MAX,
|
||||
};
|
||||
|
||||
static const struct power_supply_desc tusb1210_psy_desc = {
|
||||
.name = "tusb1211-charger-detect",
|
||||
.type = POWER_SUPPLY_TYPE_USB,
|
||||
.usb_types = tusb1210_psy_usb_types,
|
||||
.num_usb_types = ARRAY_SIZE(tusb1210_psy_usb_types),
|
||||
.properties = tusb1210_psy_props,
|
||||
.num_properties = ARRAY_SIZE(tusb1210_psy_props),
|
||||
.get_property = tusb1210_psy_get_prop,
|
||||
};
|
||||
|
||||
/* Setup charger detection if requested, on errors continue without chg-det */
|
||||
static void tusb1210_probe_charger_detect(struct tusb1210 *tusb)
|
||||
{
|
||||
struct power_supply_config psy_cfg = { .drv_data = tusb };
|
||||
struct device *dev = &tusb->ulpi->dev;
|
||||
int ret;
|
||||
|
||||
if (!device_property_read_bool(dev->parent, "linux,phy_charger_detect"))
|
||||
return;
|
||||
|
||||
if (tusb->ulpi->id.product != 0x1508) {
|
||||
dev_err(dev, "error charger detection is only supported on the TUSB1211\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = tusb1210_ulpi_read(tusb, ULPI_OTG_CTRL, &tusb->otg_ctrl);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
tusb->psy = power_supply_register(dev, &tusb1210_psy_desc, &psy_cfg);
|
||||
if (IS_ERR(tusb->psy))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Delay initial run by 2 seconds to allow the charger driver,
|
||||
* which is used to determine vbus_present, to load.
|
||||
*/
|
||||
tusb->chg_det_state = TUSB1210_CHG_DET_DISCONNECTED;
|
||||
INIT_DELAYED_WORK(&tusb->chg_det_work, tusb1210_chg_det_work);
|
||||
queue_delayed_work(system_long_wq, &tusb->chg_det_work, 2 * HZ);
|
||||
|
||||
tusb->psy_nb.notifier_call = tusb1210_psy_notifier;
|
||||
power_supply_reg_notifier(&tusb->psy_nb);
|
||||
}
|
||||
|
||||
static void tusb1210_remove_charger_detect(struct tusb1210 *tusb)
|
||||
{
|
||||
|
||||
if (!IS_ERR_OR_NULL(tusb->psy)) {
|
||||
power_supply_unreg_notifier(&tusb->psy_nb);
|
||||
cancel_delayed_work_sync(&tusb->chg_det_work);
|
||||
power_supply_unregister(tusb->psy);
|
||||
}
|
||||
|
||||
if (tusb->charger)
|
||||
power_supply_put(tusb->charger);
|
||||
}
|
||||
#else
|
||||
static void tusb1210_probe_charger_detect(struct tusb1210 *tusb) { }
|
||||
static void tusb1210_remove_charger_detect(struct tusb1210 *tusb) { }
|
||||
#endif
|
||||
|
||||
static const struct phy_ops phy_ops = {
|
||||
.power_on = tusb1210_power_on,
|
||||
.power_off = tusb1210_power_off,
|
||||
@ -95,11 +485,14 @@ static int tusb1210_probe(struct ulpi *ulpi)
|
||||
{
|
||||
struct tusb1210 *tusb;
|
||||
u8 val, reg;
|
||||
int ret;
|
||||
|
||||
tusb = devm_kzalloc(&ulpi->dev, sizeof(*tusb), GFP_KERNEL);
|
||||
if (!tusb)
|
||||
return -ENOMEM;
|
||||
|
||||
tusb->ulpi = ulpi;
|
||||
|
||||
tusb->gpio_reset = devm_gpiod_get_optional(&ulpi->dev, "reset",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(tusb->gpio_reset))
|
||||
@ -119,7 +512,9 @@ static int tusb1210_probe(struct ulpi *ulpi)
|
||||
* diagram optimization and DP/DM swap.
|
||||
*/
|
||||
|
||||
reg = ulpi_read(ulpi, TUSB1210_VENDOR_SPECIFIC2);
|
||||
ret = tusb1210_ulpi_read(tusb, TUSB1210_VENDOR_SPECIFIC2, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* High speed output drive strength configuration */
|
||||
if (!device_property_read_u8(&ulpi->dev, "ihstx", &val))
|
||||
@ -133,15 +528,18 @@ static int tusb1210_probe(struct ulpi *ulpi)
|
||||
if (!device_property_read_u8(&ulpi->dev, "datapolarity", &val))
|
||||
u8p_replace_bits(®, val, (u8)TUSB1210_VENDOR_SPECIFIC2_DP_MASK);
|
||||
|
||||
ulpi_write(ulpi, TUSB1210_VENDOR_SPECIFIC2, reg);
|
||||
ret = tusb1210_ulpi_write(tusb, TUSB1210_VENDOR_SPECIFIC2, reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
tusb->vendor_specific2 = reg;
|
||||
|
||||
tusb1210_probe_charger_detect(tusb);
|
||||
|
||||
tusb->phy = ulpi_phy_create(ulpi, &phy_ops);
|
||||
if (IS_ERR(tusb->phy))
|
||||
return PTR_ERR(tusb->phy);
|
||||
|
||||
tusb->ulpi = ulpi;
|
||||
|
||||
phy_set_drvdata(tusb->phy, tusb);
|
||||
ulpi_set_drvdata(ulpi, tusb);
|
||||
return 0;
|
||||
@ -152,6 +550,7 @@ static void tusb1210_remove(struct ulpi *ulpi)
|
||||
struct tusb1210 *tusb = ulpi_get_drvdata(ulpi);
|
||||
|
||||
ulpi_phy_destroy(ulpi, tusb->phy);
|
||||
tusb1210_remove_charger_detect(tusb);
|
||||
}
|
||||
|
||||
#define TI_VENDOR_ID 0x0451
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include <linux/mbus.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/phy/phy.h>
|
||||
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
@ -75,47 +74,6 @@ int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xhci_mvebu_a3700_plat_setup(struct usb_hcd *hcd)
|
||||
{
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
struct device *dev = hcd->self.controller;
|
||||
struct phy *phy;
|
||||
int ret;
|
||||
|
||||
/* Old bindings miss the PHY handle */
|
||||
phy = of_phy_get(dev->of_node, "usb3-phy");
|
||||
if (IS_ERR(phy) && PTR_ERR(phy) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
else if (IS_ERR(phy))
|
||||
goto phy_out;
|
||||
|
||||
ret = phy_init(phy);
|
||||
if (ret)
|
||||
goto phy_put;
|
||||
|
||||
ret = phy_set_mode(phy, PHY_MODE_USB_HOST_SS);
|
||||
if (ret)
|
||||
goto phy_exit;
|
||||
|
||||
ret = phy_power_on(phy);
|
||||
if (ret == -EOPNOTSUPP) {
|
||||
/* Skip initializatin of XHCI PHY when it is unsupported by firmware */
|
||||
dev_warn(dev, "PHY unsupported by firmware\n");
|
||||
xhci->quirks |= XHCI_SKIP_PHY_INIT;
|
||||
}
|
||||
if (ret)
|
||||
goto phy_exit;
|
||||
|
||||
phy_power_off(phy);
|
||||
phy_exit:
|
||||
phy_exit(phy);
|
||||
phy_put:
|
||||
of_phy_put(phy);
|
||||
phy_out:
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd)
|
||||
{
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
|
@ -12,7 +12,6 @@ struct usb_hcd;
|
||||
|
||||
#if IS_ENABLED(CONFIG_USB_XHCI_MVEBU)
|
||||
int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd);
|
||||
int xhci_mvebu_a3700_plat_setup(struct usb_hcd *hcd);
|
||||
int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd);
|
||||
#else
|
||||
static inline int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd)
|
||||
@ -20,11 +19,6 @@ static inline int xhci_mvebu_mbus_init_quirk(struct usb_hcd *hcd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int xhci_mvebu_a3700_plat_setup(struct usb_hcd *hcd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int xhci_mvebu_a3700_init_quirk(struct usb_hcd *hcd)
|
||||
{
|
||||
return 0;
|
||||
|
@ -44,16 +44,6 @@ static void xhci_priv_plat_start(struct usb_hcd *hcd)
|
||||
priv->plat_start(hcd);
|
||||
}
|
||||
|
||||
static int xhci_priv_plat_setup(struct usb_hcd *hcd)
|
||||
{
|
||||
struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
|
||||
|
||||
if (!priv->plat_setup)
|
||||
return 0;
|
||||
|
||||
return priv->plat_setup(hcd);
|
||||
}
|
||||
|
||||
static int xhci_priv_init_quirk(struct usb_hcd *hcd)
|
||||
{
|
||||
struct xhci_plat_priv *priv = hcd_to_xhci_priv(hcd);
|
||||
@ -121,7 +111,6 @@ static const struct xhci_plat_priv xhci_plat_marvell_armada = {
|
||||
};
|
||||
|
||||
static const struct xhci_plat_priv xhci_plat_marvell_armada3700 = {
|
||||
.plat_setup = xhci_mvebu_a3700_plat_setup,
|
||||
.init_quirk = xhci_mvebu_a3700_init_quirk,
|
||||
};
|
||||
|
||||
@ -341,14 +330,7 @@ static int xhci_plat_probe(struct platform_device *pdev)
|
||||
|
||||
hcd->tpl_support = of_usb_host_tpl_support(sysdev->of_node);
|
||||
xhci->shared_hcd->tpl_support = hcd->tpl_support;
|
||||
|
||||
if (priv) {
|
||||
ret = xhci_priv_plat_setup(hcd);
|
||||
if (ret)
|
||||
goto disable_usb_phy;
|
||||
}
|
||||
|
||||
if ((xhci->quirks & XHCI_SKIP_PHY_INIT) || (priv && (priv->quirks & XHCI_SKIP_PHY_INIT)))
|
||||
if (priv && (priv->quirks & XHCI_SKIP_PHY_INIT))
|
||||
hcd->skip_phy_initialization = 1;
|
||||
|
||||
if (priv && (priv->quirks & XHCI_SG_TRB_CACHE_SIZE_QUIRK))
|
||||
|
@ -13,7 +13,6 @@
|
||||
struct xhci_plat_priv {
|
||||
const char *firmware_name;
|
||||
unsigned long long quirks;
|
||||
int (*plat_setup)(struct usb_hcd *);
|
||||
void (*plat_start)(struct usb_hcd *);
|
||||
int (*init_quirk)(struct usb_hcd *);
|
||||
int (*suspend_quirk)(struct usb_hcd *);
|
||||
|
Loading…
Reference in New Issue
Block a user