Commit 85a09bf4 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge tag 'phy-for-4.17' of...

Merge tag 'phy-for-4.17' of git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux-phy into usb-next

Kishon writes:

phy: for 4.17

 *) Add USB PHY driver for MDM6600 on Droid
 *) Add USB PHY driver for STM32 USB PHY Controller
 *) Add inno-usb2-phy driver for hi3798cv200 SoC
 *) Add combo phy driver (SATA/USB/PCIE) for HiSilicon STB SoCs
 *) Add USB3 PHY driver for Meson GXL and GXM
 *) Add support for R8A77965 Gen3 USB 2.0 PHY in phy-rcar-gen3-usb2 driver
 *) Add support for qualcomm QUSB2 V2 and QMP V3 USB3 PHY in phy-qcom-qusb2
    and phy-qcom-qmp PHY driver respectively
 *) Add support for runtime PM in phy-qcom-qusb2 and phy-qcom-qmp PHY drivers
 *) Add support for Allwinner R40 USB PHY in sun4i-usb PHY driver
 *) Add support in rockchip-typec PHY driver to make extcon optional and
    fallback to working in host mode if extcon is missing
 *) Add support in rockchip-typec PHY driver to mux PHYs connected to DP
 *) Add support to configure slew rate parameters in phy-mtk-tphy PHY driver
 *) Add workaround for missing Vbus det interrupts on Allwinner A23/A33
 *) Add USB speed related PHY modes in phy core
 *) Fix PHY 'structure' documentation
 *) Force rockchip-typec PHY to USB2 if DP-only mode is used
 *) Fix phy-qcom-qusb2 and phy-qcom-qmp PHY drivers to follow PHY reset and
    initialization sequence as per hardware programming manual
 *) Fix Marvell BG2CD SoC USB failure in phy-berlin-usb driver
 *) Minor fixes in lpc18xx-usb-otg, xusb-tegra210 and phy-rockchip-emmc PHY
    drivers
Signed-off-by: default avatarKishon Vijay Abraham I <kishon@ti.com>
parents a8f25c36 e7f4da4c
...@@ -74,6 +74,29 @@ Example: ...@@ -74,6 +74,29 @@ Example:
reboot-offset = <0x4>; reboot-offset = <0x4>;
}; };
-----------------------------------------------------------------------
Hisilicon Hi3798CV200 Peripheral Controller
The Hi3798CV200 Peripheral Controller controls peripherals, queries
their status, and configures some functions of peripherals.
Required properties:
- compatible: Should contain "hisilicon,hi3798cv200-perictrl", "syscon"
and "simple-mfd".
- reg: Register address and size of Peripheral Controller.
- #address-cells: Should be 1.
- #size-cells: Should be 1.
Examples:
perictrl: peripheral-controller@8a20000 {
compatible = "hisilicon,hi3798cv200-perictrl", "syscon",
"simple-mfd";
reg = <0x8a20000 0x1000>;
#address-cells = <1>;
#size-cells = <1>;
};
----------------------------------------------------------------------- -----------------------------------------------------------------------
Hisilicon Hi6220 system controller Hisilicon Hi6220 system controller
......
...@@ -6,6 +6,10 @@ Required properties: ...@@ -6,6 +6,10 @@ Required properties:
- #phys-cells: must be 0 (see phy-bindings.txt in this directory) - #phys-cells: must be 0 (see phy-bindings.txt in this directory)
Optional properties: Optional properties:
- clocks: a phandle to the clock of this PHY
- clock-names: must be "phy"
- resets: a phandle to the reset line of this PHY
- reset-names: must be "phy"
- phy-supply: see phy-bindings.txt in this directory - phy-supply: see phy-bindings.txt in this directory
......
* Amlogic Meson GXL and GXM USB3 PHY and OTG detection binding
Required properties:
- compatible: Should be "amlogic,meson-gxl-usb3-phy"
- #phys-cells: must be 0 (see phy-bindings.txt in this directory)
- reg: The base address and length of the registers
- interrupts: the interrupt specifier for the OTG detection
- clocks: phandles to the clocks for
- the USB3 PHY
- and peripheral mode/OTG detection
- clock-names: must contain "phy" and "peripheral"
- resets: phandle to the reset lines for:
- the USB3 PHY and
- peripheral mode/OTG detection
- reset-names: must contain "phy" and "peripheral"
Optional properties:
- phy-supply: see phy-bindings.txt in this directory
Example:
usb3_phy0: phy@78080 {
compatible = "amlogic,meson-gxl-usb3-phy";
#phy-cells = <0>;
reg = <0x0 0x78080 0x0 0x20>;
interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&clkc CLKID_USB_OTG>, <&clkc_AO CLKID_AO_CEC_32K>;
clock-names = "phy", "peripheral";
resets = <&reset RESET_USB_OTG>, <&reset RESET_USB_OTG>;
reset-names = "phy", "peripheral";
};
HiSilicon STB PCIE/SATA/USB3 PHY
Required properties:
- compatible: Should be "hisilicon,hi3798cv200-combphy"
- reg: Should be the address space for COMBPHY configuration and state
registers in peripheral controller, e.g. PERI_COMBPHY0_CFG and
PERI_COMBPHY0_STATE for COMBPHY0 Hi3798CV200 SoC.
- #phy-cells: Should be 1. The cell number is used to select the phy mode
as defined in <dt-bindings/phy/phy.h>.
- clocks: The phandle to clock provider and clock specifier pair.
- resets: The phandle to reset controller and reset specifier pair.
Refer to phy/phy-bindings.txt for the generic PHY binding properties.
Optional properties:
- hisilicon,fixed-mode: If the phy device doesn't support mode select
but a fixed mode setting, the property should be present to specify
the particular mode.
- hisilicon,mode-select-bits: If the phy device support mode select,
this property should be present to specify the register bits in
peripheral controller, as a 3 integers tuple:
<register_offset bit_shift bit_mask>.
Notes:
- Between hisilicon,fixed-mode and hisilicon,mode-select-bits, one and only
one of them should be present.
- The device node should be a child of peripheral controller that contains
COMBPHY configuration/state and PERI_CTRL register used to select PHY mode.
Refer to arm/hisilicon/hisilicon.txt for the parent peripheral controller
bindings.
Examples:
perictrl: peripheral-controller@8a20000 {
compatible = "hisilicon,hi3798cv200-perictrl", "syscon",
"simple-mfd";
reg = <0x8a20000 0x1000>;
#address-cells = <1>;
#size-cells = <1>;
ranges = <0x0 0x8a20000 0x1000>;
combphy0: phy@850 {
compatible = "hisilicon,hi3798cv200-combphy";
reg = <0x850 0x8>;
#phy-cells = <1>;
clocks = <&crg HISTB_COMBPHY0_CLK>;
resets = <&crg 0x188 4>;
hisilicon,fixed-mode = <PHY_TYPE_USB3>;
};
combphy1: phy@858 {
compatible = "hisilicon,hi3798cv200-combphy";
reg = <0x858 0x8>;
#phy-cells = <1>;
clocks = <&crg HISTB_COMBPHY1_CLK>;
resets = <&crg 0x188 12>;
hisilicon,mode-select-bits = <0x0008 11 (0x3 << 11)>;
};
};
Device tree bindings for HiSilicon INNO USB2 PHY
Required properties:
- compatible: Should be one of the following strings:
"hisilicon,inno-usb2-phy",
"hisilicon,hi3798cv200-usb2-phy".
- reg: Should be the address space for PHY configuration register in peripheral
controller, e.g. PERI_USB0 for USB 2.0 PHY01 on Hi3798CV200 SoC.
- clocks: The phandle and clock specifier pair for INNO USB2 PHY device
reference clock.
- resets: The phandle and reset specifier pair for INNO USB2 PHY device reset
signal.
- #address-cells: Must be 1.
- #size-cells: Must be 0.
The INNO USB2 PHY device should be a child node of peripheral controller that
contains the PHY configuration register, and each device suppports up to 2 PHY
ports which are represented as child nodes of INNO USB2 PHY device.
Required properties for PHY port node:
- reg: The PHY port instance number.
- #phy-cells: Defined by generic PHY bindings. Must be 0.
- resets: The phandle and reset specifier pair for PHY port reset signal.
Refer to phy/phy-bindings.txt for the generic PHY binding properties
Example:
perictrl: peripheral-controller@8a20000 {
compatible = "hisilicon,hi3798cv200-perictrl", "simple-mfd";
reg = <0x8a20000 0x1000>;
#address-cells = <1>;
#size-cells = <1>;
ranges = <0x0 0x8a20000 0x1000>;
usb2_phy1: usb2-phy@120 {
compatible = "hisilicon,hi3798cv200-usb2-phy";
reg = <0x120 0x4>;
clocks = <&crg HISTB_USB2_PHY1_REF_CLK>;
resets = <&crg 0xbc 4>;
#address-cells = <1>;
#size-cells = <0>;
usb2_phy1_port0: phy@0 {
reg = <0>;
#phy-cells = <0>;
resets = <&crg 0xbc 8>;
};
usb2_phy1_port1: phy@1 {
reg = <1>;
#phy-cells = <0>;
resets = <&crg 0xbc 9>;
};
};
usb2_phy2: usb2-phy@124 {
compatible = "hisilicon,hi3798cv200-usb2-phy";
reg = <0x124 0x4>;
clocks = <&crg HISTB_USB2_PHY2_REF_CLK>;
resets = <&crg 0xbc 6>;
#address-cells = <1>;
#size-cells = <0>;
usb2_phy2_port0: phy@0 {
reg = <0>;
#phy-cells = <0>;
resets = <&crg 0xbc 10>;
};
};
};
Device tree binding documentation for Motorola Mapphone MDM6600 USB PHY
Required properties:
- compatible Must be "motorola,mapphone-mdm6600"
- enable-gpios GPIO to enable the USB PHY
- power-gpios GPIO to power on the device
- reset-gpios GPIO to reset the device
- motorola,mode-gpios Two GPIOs to configure MDM6600 USB start-up mode for
normal mode versus USB flashing mode
- motorola,cmd-gpios Three GPIOs to control the power state of the MDM6600
- motorola,status-gpios Three GPIOs to read the power state of the MDM6600
Example:
usb-phy {
compatible = "motorola,mapphone-mdm6600";
enable-gpios = <&gpio3 31 GPIO_ACTIVE_LOW>;
power-gpios = <&gpio2 22 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio2 17 GPIO_ACTIVE_HIGH>;
motorola,mode-gpios = <&gpio5 20 GPIO_ACTIVE_HIGH>,
<&gpio5 21 GPIO_ACTIVE_HIGH>;
motorola,cmd-gpios = <&gpio4 7 GPIO_ACTIVE_HIGH>,
<&gpio4 8 GPIO_ACTIVE_HIGH>,
<&gpio5 14 GPIO_ACTIVE_HIGH>;
motorola,status-gpios = <&gpio2 20 GPIO_ACTIVE_HIGH>,
<&gpio2 21 GPIO_ACTIVE_HIGH>,
<&gpio2 23 GPIO_ACTIVE_HIGH>;
#phy-cells = <0>;
};
...@@ -27,6 +27,10 @@ Optional properties (controller (parent) node): ...@@ -27,6 +27,10 @@ Optional properties (controller (parent) node):
- reg : offset and length of register shared by multiple ports, - reg : offset and length of register shared by multiple ports,
exclude port's private register. It is needed on mt2701 exclude port's private register. It is needed on mt2701
and mt8173, but not on mt2712. and mt8173, but not on mt2712.
- mediatek,src-ref-clk-mhz : frequency of reference clock for slew rate
calibrate
- mediatek,src-coef : coefficient for slew rate calibrate, depends on
SoC process
Required properties (port (child) node): Required properties (port (child) node):
- reg : address and length of the register set for the port. - reg : address and length of the register set for the port.
......
...@@ -14,25 +14,9 @@ Required properties: ...@@ -14,25 +14,9 @@ Required properties:
- resets : a list of phandle + reset specifier pairs - resets : a list of phandle + reset specifier pairs
- reset-names : string reset name, must be: - reset-names : string reset name, must be:
"uphy", "uphy-pipe", "uphy-tcphy" "uphy", "uphy-pipe", "uphy-tcphy"
- extcon : extcon specifier for the Power Delivery
Note, there are 2 type-c phys for RK3399, and they are almost identical, except Optional properties:
these registers(description below), every register node contains 3 sections: - extcon : extcon specifier for the Power Delivery
offset, enable bit, write mask bit.
- rockchip,typec-conn-dir : the register of type-c connector direction,
for type-c phy0, it must be <0xe580 0 16>;
for type-c phy1, it must be <0xe58c 0 16>;
- rockchip,usb3tousb2-en : the register of type-c force usb3 to usb2 enable
control.
for type-c phy0, it must be <0xe580 3 19>;
for type-c phy1, it must be <0xe58c 3 19>;
- rockchip,external-psm : the register of type-c phy external psm clock
selection.
for type-c phy0, it must be <0xe588 14 30>;
for type-c phy1, it must be <0xe594 14 30>;
- rockchip,pipe-status : the register of type-c phy pipe status.
for type-c phy0, it must be <0xe5c0 0 0>;
for type-c phy1, it must be <0xe5c0 16 16>;
Required nodes : a sub-node is required for each port the phy provides. Required nodes : a sub-node is required for each port the phy provides.
The sub-node name is used to identify dp or usb3 port, The sub-node name is used to identify dp or usb3 port,
...@@ -43,6 +27,13 @@ Required nodes : a sub-node is required for each port the phy provides. ...@@ -43,6 +27,13 @@ Required nodes : a sub-node is required for each port the phy provides.
Required properties (port (child) node): Required properties (port (child) node):
- #phy-cells : must be 0, See ./phy-bindings.txt for details. - #phy-cells : must be 0, See ./phy-bindings.txt for details.
Deprecated properties, do not use in new device tree sources, these
properties are determined by the compatible value:
- rockchip,typec-conn-dir
- rockchip,usb3tousb2-en
- rockchip,external-psm
- rockchip,pipe-status
Example: Example:
tcphy0: phy@ff7c0000 { tcphy0: phy@ff7c0000 {
compatible = "rockchip,rk3399-typec-phy"; compatible = "rockchip,rk3399-typec-phy";
...@@ -58,10 +49,6 @@ Example: ...@@ -58,10 +49,6 @@ Example:
<&cru SRST_UPHY0_PIPE_L00>, <&cru SRST_UPHY0_PIPE_L00>,
<&cru SRST_P_UPHY0_TCPHY>; <&cru SRST_P_UPHY0_TCPHY>;
reset-names = "uphy", "uphy-pipe", "uphy-tcphy"; reset-names = "uphy", "uphy-pipe", "uphy-tcphy";
rockchip,typec-conn-dir = <0xe580 0 16>;
rockchip,usb3tousb2-en = <0xe580 3 19>;
rockchip,external-psm = <0xe588 14 30>;
rockchip,pipe-status = <0xe5c0 0 0>;
tcphy0_dp: dp-port { tcphy0_dp: dp-port {
#phy-cells = <0>; #phy-cells = <0>;
...@@ -86,10 +73,6 @@ Example: ...@@ -86,10 +73,6 @@ Example:
<&cru SRST_UPHY1_PIPE_L00>, <&cru SRST_UPHY1_PIPE_L00>,
<&cru SRST_P_UPHY1_TCPHY>; <&cru SRST_P_UPHY1_TCPHY>;
reset-names = "uphy", "uphy-pipe", "uphy-tcphy"; reset-names = "uphy", "uphy-pipe", "uphy-tcphy";
rockchip,typec-conn-dir = <0xe58c 0 16>;
rockchip,usb3tousb2-en = <0xe58c 3 19>;
rockchip,external-psm = <0xe594 14 30>;
rockchip,pipe-status = <0xe5c0 16 16>;
tcphy1_dp: dp-port { tcphy1_dp: dp-port {
#phy-cells = <0>; #phy-cells = <0>;
......
STMicroelectronics STM32 USB HS PHY controller
The STM32 USBPHYC block contains a dual port High Speed UTMI+ PHY and a UTMI
switch. It controls PHY configuration and status, and the UTMI+ switch that
selects either OTG or HOST controller for the second PHY port. It also sets
PLL configuration.
USBPHYC
|_ PLL
|
|_ PHY port#1 _________________ HOST controller
| _ |
| / 1|________________|
|_ PHY port#2 ----| |________________
| \_0| |
|_ UTMI switch_______| OTG controller
Phy provider node
=================
Required properties:
- compatible: must be "st,stm32mp1-usbphyc"
- reg: address and length of the usb phy control register set
- clocks: phandle + clock specifier for the PLL phy clock
- #address-cells: number of address cells for phys sub-nodes, must be <1>
- #size-cells: number of size cells for phys sub-nodes, must be <0>
Optional properties:
- assigned-clocks: phandle + clock specifier for the PLL phy clock
- assigned-clock-parents: the PLL phy clock parent
- resets: phandle + reset specifier
Required nodes: one sub-node per port the controller provides.
Phy sub-nodes
==============
Required properties:
- reg: phy port index
- phy-supply: phandle to the regulator providing 3V3 power to the PHY,
see phy-bindings.txt in the same directory.
- vdda1v1-supply: phandle to the regulator providing 1V1 power to the PHY
- vdda1v8-supply: phandle to the regulator providing 1V8 power to the PHY
- #phy-cells: see phy-bindings.txt in the same directory, must be <0> for PHY
port#1 and must be <1> for PHY port#2, to select USB controller
Example:
usbphyc: usb-phy@5a006000 {
compatible = "st,stm32mp1-usbphyc";
reg = <0x5a006000 0x1000>;
clocks = <&rcc_clk USBPHY_K>;
resets = <&rcc_rst USBPHY_R>;
#address-cells = <1>;
#size-cells = <0>;
usbphyc_port0: usb-phy@0 {
reg = <0>;
phy-supply = <&vdd_usb>;
vdda1v1-supply = <&reg11>;
vdda1v8-supply = <&reg18>
#phy-cells = <0>;
};
usbphyc_port1: usb-phy@1 {
reg = <1>;
phy-supply = <&vdd_usb>;
vdda1v1-supply = <&reg11>;
vdda1v8-supply = <&reg18>
#phy-cells = <1>;
};
};
...@@ -8,7 +8,8 @@ Required properties: ...@@ -8,7 +8,8 @@ Required properties:
- compatible: compatible list, contains: - compatible: compatible list, contains:
"qcom,ipq8074-qmp-pcie-phy" for PCIe phy on IPQ8074 "qcom,ipq8074-qmp-pcie-phy" for PCIe phy on IPQ8074
"qcom,msm8996-qmp-pcie-phy" for 14nm PCIe phy on msm8996, "qcom,msm8996-qmp-pcie-phy" for 14nm PCIe phy on msm8996,
"qcom,msm8996-qmp-usb3-phy" for 14nm USB3 phy on msm8996. "qcom,msm8996-qmp-usb3-phy" for 14nm USB3 phy on msm8996,
"qcom,qmp-v3-usb3-phy" for USB3 QMP V3 phy.
- reg: offset and length of register set for PHY's common serdes block. - reg: offset and length of register set for PHY's common serdes block.
...@@ -25,10 +26,13 @@ Required properties: ...@@ -25,10 +26,13 @@ Required properties:
- clock-names: "cfg_ahb" for phy config clock, - clock-names: "cfg_ahb" for phy config clock,
"aux" for phy aux clock, "aux" for phy aux clock,
"ref" for 19.2 MHz ref clk, "ref" for 19.2 MHz ref clk,
"com_aux" for phy common block aux clock,
For "qcom,msm8996-qmp-pcie-phy" must contain: For "qcom,msm8996-qmp-pcie-phy" must contain:
"aux", "cfg_ahb", "ref". "aux", "cfg_ahb", "ref".
For "qcom,msm8996-qmp-usb3-phy" must contain: For "qcom,msm8996-qmp-usb3-phy" must contain:
"aux", "cfg_ahb", "ref". "aux", "cfg_ahb", "ref".
For "qcom,qmp-v3-usb3-phy" must contain:
"aux", "cfg_ahb", "ref", "com_aux".
- resets: a list of phandles and reset controller specifier pairs, - resets: a list of phandles and reset controller specifier pairs,
one for each entry in reset-names. one for each entry in reset-names.
......
...@@ -4,7 +4,10 @@ Qualcomm QUSB2 phy controller ...@@ -4,7 +4,10 @@ Qualcomm QUSB2 phy controller
QUSB2 controller supports LS/FS/HS usb connectivity on Qualcomm chipsets. QUSB2 controller supports LS/FS/HS usb connectivity on Qualcomm chipsets.
Required properties: Required properties:
- compatible: compatible list, contains "qcom,msm8996-qusb2-phy". - compatible: compatible list, contains
"qcom,msm8996-qusb2-phy" for 14nm PHY on msm8996,
"qcom,qusb2-v2-phy" for QUSB2 V2 PHY.
- reg: offset and length of the PHY register set. - reg: offset and length of the PHY register set.
- #phy-cells: must be 0. - #phy-cells: must be 0.
......
...@@ -8,6 +8,8 @@ Required properties: ...@@ -8,6 +8,8 @@ Required properties:
SoC. SoC.
"renesas,usb2-phy-r8a7796" if the device is a part of an R8A7796 "renesas,usb2-phy-r8a7796" if the device is a part of an R8A7796
SoC. SoC.
"renesas,usb2-phy-r8a77965" if the device is a part of an
R8A77965 SoC.
"renesas,usb2-phy-r8a77995" if the device is a part of an "renesas,usb2-phy-r8a77995" if the device is a part of an
R8A77995 SoC. R8A77995 SoC.
"renesas,rcar-gen3-usb2-phy" for a generic R-Car Gen3 compatible device. "renesas,rcar-gen3-usb2-phy" for a generic R-Car Gen3 compatible device.
......
...@@ -11,6 +11,8 @@ Required properties: ...@@ -11,6 +11,8 @@ Required properties:
SoC. SoC.
"renesas,r8a7796-usb3-phy" if the device is a part of an R8A7796 "renesas,r8a7796-usb3-phy" if the device is a part of an R8A7796
SoC. SoC.
"renesas,r8a77965-usb3-phy" if the device is a part of an
R8A77965 SoC.
"renesas,rcar-gen3-usb3-phy" for a generic R-Car Gen3 compatible "renesas,rcar-gen3-usb3-phy" for a generic R-Car Gen3 compatible
device. device.
......
...@@ -11,6 +11,7 @@ Required properties: ...@@ -11,6 +11,7 @@ Required properties:
* allwinner,sun8i-a33-usb-phy * allwinner,sun8i-a33-usb-phy
* allwinner,sun8i-a83t-usb-phy * allwinner,sun8i-a83t-usb-phy
* allwinner,sun8i-h3-usb-phy * allwinner,sun8i-h3-usb-phy
* allwinner,sun8i-r40-usb-phy
* allwinner,sun8i-v3s-usb-phy * allwinner,sun8i-v3s-usb-phy
* allwinner,sun50i-a64-usb-phy * allwinner,sun50i-a64-usb-phy
- reg : a list of offset + length pairs - reg : a list of offset + length pairs
......
...@@ -112,6 +112,7 @@ enum sun4i_usb_phy_type { ...@@ -112,6 +112,7 @@ enum sun4i_usb_phy_type {
sun8i_a33_phy, sun8i_a33_phy,
sun8i_a83t_phy, sun8i_a83t_phy,
sun8i_h3_phy, sun8i_h3_phy,
sun8i_r40_phy,
sun8i_v3s_phy, sun8i_v3s_phy,
sun50i_a64_phy, sun50i_a64_phy,
}; };
...@@ -410,11 +411,13 @@ static bool sun4i_usb_phy0_poll(struct sun4i_usb_phy_data *data) ...@@ -410,11 +411,13 @@ static bool sun4i_usb_phy0_poll(struct sun4i_usb_phy_data *data)
return true; return true;
/* /*
* The A31 companion pmic (axp221) does not generate vbus change * The A31/A23/A33 companion pmics (AXP221/AXP223) do not
* interrupts when the board is driving vbus, so we must poll * generate vbus change interrupts when the board is driving
* vbus using the N_VBUSEN pin on the pmic, so we must poll
* when using the pmic for vbus-det _and_ we're driving vbus. * when using the pmic for vbus-det _and_ we're driving vbus.
*/ */
if (data->cfg->type == sun6i_a31_phy && if ((data->cfg->type == sun6i_a31_phy ||
data->cfg->type == sun8i_a33_phy) &&
data->vbus_power_supply && data->phys[0].regulator_on) data->vbus_power_supply && data->phys[0].regulator_on)
return true; return true;
...@@ -885,7 +888,7 @@ static const struct sun4i_usb_phy_cfg sun7i_a20_cfg = { ...@@ -885,7 +888,7 @@ static const struct sun4i_usb_phy_cfg sun7i_a20_cfg = {
static const struct sun4i_usb_phy_cfg sun8i_a23_cfg = { static const struct sun4i_usb_phy_cfg sun8i_a23_cfg = {
.num_phys = 2, .num_phys = 2,
.type = sun4i_a10_phy, .type = sun6i_a31_phy,
.disc_thresh = 3, .disc_thresh = 3,
.phyctl_offset = REG_PHYCTL_A10, .phyctl_offset = REG_PHYCTL_A10,
.dedicated_clocks = true, .dedicated_clocks = true,
...@@ -919,6 +922,16 @@ static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = { ...@@ -919,6 +922,16 @@ static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = {
.phy0_dual_route = true, .phy0_dual_route = true,
}; };
static const struct sun4i_usb_phy_cfg sun8i_r40_cfg = {
.num_phys = 3,
.type = sun8i_r40_phy,
.disc_thresh = 3,
.phyctl_offset = REG_PHYCTL_A33,
.dedicated_clocks = true,
.enable_pmu_unk1 = true,
.phy0_dual_route = true,
};
static const struct sun4i_usb_phy_cfg sun8i_v3s_cfg = { static const struct sun4i_usb_phy_cfg sun8i_v3s_cfg = {
.num_phys = 1, .num_phys = 1,
.type = sun8i_v3s_phy, .type = sun8i_v3s_phy,
...@@ -948,6 +961,7 @@ static const struct of_device_id sun4i_usb_phy_of_match[] = { ...@@ -948,6 +961,7 @@ static const struct of_device_id sun4i_usb_phy_of_match[] = {
{ .compatible = "allwinner,sun8i-a33-usb-phy", .data = &sun8i_a33_cfg }, { .compatible = "allwinner,sun8i-a33-usb-phy", .data = &sun8i_a33_cfg },
{ .compatible = "allwinner,sun8i-a83t-usb-phy", .data = &sun8i_a83t_cfg }, { .compatible = "allwinner,sun8i-a83t-usb-phy", .data = &sun8i_a83t_cfg },
{ .compatible = "allwinner,sun8i-h3-usb-phy", .data = &sun8i_h3_cfg }, { .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,sun8i-v3s-usb-phy", .data = &sun8i_v3s_cfg },
{ .compatible = "allwinner,sun50i-a64-usb-phy", { .compatible = "allwinner,sun50i-a64-usb-phy",
.data = &sun50i_a64_cfg}, .data = &sun50i_a64_cfg},
......
...@@ -18,10 +18,21 @@ config PHY_MESON_GXL_USB2 ...@@ -18,10 +18,21 @@ config PHY_MESON_GXL_USB2
default ARCH_MESON default ARCH_MESON
depends on OF && (ARCH_MESON || COMPILE_TEST) depends on OF && (ARCH_MESON || COMPILE_TEST)
depends on USB_SUPPORT depends on USB_SUPPORT
select USB_COMMON
select GENERIC_PHY select GENERIC_PHY
select REGMAP_MMIO select REGMAP_MMIO
help help
Enable this to support the Meson USB2 PHYs found in Meson Enable this to support the Meson USB2 PHYs found in Meson
GXL and GXM SoCs. GXL and GXM SoCs.
If unsure, say N. If unsure, say N.
config PHY_MESON_GXL_USB3
tristate "Meson GXL and GXM USB3 PHY drivers"
default ARCH_MESON
depends on OF && (ARCH_MESON || COMPILE_TEST)
depends on USB_SUPPORT
select GENERIC_PHY
select REGMAP_MMIO
help
Enable this to support the Meson USB3 PHY and OTG detection
IP block found in Meson GXL and GXM SoCs.
If unsure, say N.
obj-$(CONFIG_PHY_MESON8B_USB2) += phy-meson8b-usb2.o obj-$(CONFIG_PHY_MESON8B_USB2) += phy-meson8b-usb2.o
obj-$(CONFIG_PHY_MESON_GXL_USB2) += phy-meson-gxl-usb2.o obj-$(CONFIG_PHY_MESON_GXL_USB2) += phy-meson-gxl-usb2.o
obj-$(CONFIG_PHY_MESON_GXL_USB3) += phy-meson-gxl-usb3.o
...@@ -11,14 +11,15 @@ ...@@ -11,14 +11,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <linux/clk.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/reset.h>
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/usb/of.h>
/* bits [31:27] are read-only */ /* bits [31:27] are read-only */
#define U2P_R0 0x0 #define U2P_R0 0x0
...@@ -70,12 +71,11 @@ ...@@ -70,12 +71,11 @@
/* bits [31:14] are read-only */ /* bits [31:14] are read-only */
#define U2P_R2 0x8 #define U2P_R2 0x8
#define U2P_R2_DATA_IN_MASK GENMASK(3, 0) #define U2P_R2_TESTDATA_IN_MASK GENMASK(7, 0)
#define U2P_R2_DATA_IN_EN_MASK GENMASK(7, 4) #define U2P_R2_TESTADDR_MASK GENMASK(11, 8)
#define U2P_R2_ADDR_MASK GENMASK(11, 8) #define U2P_R2_TESTDATA_OUT_SEL BIT(12)
#define U2P_R2_DATA_OUT_SEL BIT(12) #define U2P_R2_TESTCLK BIT(13)
#define U2P_R2_CLK BIT(13) #define U2P_R2_TESTDATA_OUT_MASK GENMASK(17, 14)
#define U2P_R2_DATA_OUT_MASK GENMASK(17, 14)
#define U2P_R2_ACA_PIN_RANGE_C BIT(18) #define U2P_R2_ACA_PIN_RANGE_C BIT(18)
#define U2P_R2_ACA_PIN_RANGE_B BIT(19) #define U2P_R2_ACA_PIN_RANGE_B BIT(19)
#define U2P_R2_ACA_PIN_RANGE_A BIT(20) #define U2P_R2_ACA_PIN_RANGE_A BIT(20)
...@@ -99,6 +99,8 @@ struct phy_meson_gxl_usb2_priv { ...@@ -99,6 +99,8 @@ struct phy_meson_gxl_usb2_priv {
struct regmap *regmap; struct regmap *regmap;
enum phy_mode mode; enum phy_mode mode;
int is_enabled; int is_enabled;
struct clk *clk;
struct reset_control *reset;
}; };
static const struct regmap_config phy_meson_gxl_usb2_regmap_conf = { static const struct regmap_config phy_meson_gxl_usb2_regmap_conf = {
...@@ -108,6 +110,31 @@ static const struct regmap_config phy_meson_gxl_usb2_regmap_conf = { ...@@ -108,6 +110,31 @@ static const struct regmap_config phy_meson_gxl_usb2_regmap_conf = {
.max_register = U2P_R3, .max_register = U2P_R3,
}; };
static int phy_meson_gxl_usb2_init(struct phy *phy)
{
struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy);
int ret;
ret = reset_control_reset(priv->reset);
if (ret)
return ret;
ret = clk_prepare_enable(priv->clk);
if (ret)
return ret;
return 0;
}
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);
return 0;
}
static int phy_meson_gxl_usb2_reset(struct phy *phy) static int phy_meson_gxl_usb2_reset(struct phy *phy)
{ {
struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy); struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy);
...@@ -195,6 +222,8 @@ static int phy_meson_gxl_usb2_power_on(struct phy *phy) ...@@ -195,6 +222,8 @@ static int phy_meson_gxl_usb2_power_on(struct phy *phy)
} }
static const struct phy_ops phy_meson_gxl_usb2_ops = { static const struct phy_ops phy_meson_gxl_usb2_ops = {
.init = phy_meson_gxl_usb2_init,
.exit = phy_meson_gxl_usb2_exit,
.power_on = phy_meson_gxl_usb2_power_on, .power_on = phy_meson_gxl_usb2_power_on,
.power_off = phy_meson_gxl_usb2_power_off, .power_off = phy_meson_gxl_usb2_power_off,
.set_mode = phy_meson_gxl_usb2_set_mode, .set_mode = phy_meson_gxl_usb2_set_mode,
...@@ -210,6 +239,7 @@ static int phy_meson_gxl_usb2_probe(struct platform_device *pdev) ...@@ -210,6 +239,7 @@ static int phy_meson_gxl_usb2_probe(struct platform_device *pdev)
struct phy_meson_gxl_usb2_priv *priv; struct phy_meson_gxl_usb2_priv *priv;
struct phy *phy; struct phy *phy;
void __iomem *base; void __iomem *base;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv) if (!priv)
...@@ -222,28 +252,34 @@ static int phy_meson_gxl_usb2_probe(struct platform_device *pdev) ...@@ -222,28 +252,34 @@ static int phy_meson_gxl_usb2_probe(struct platform_device *pdev)
if (IS_ERR(base)) if (IS_ERR(base))
return PTR_ERR(base); return PTR_ERR(base);
switch (of_usb_get_dr_mode_by_phy(dev->of_node, -1)) { /* start in host mode */
case USB_DR_MODE_PERIPHERAL: priv->mode = PHY_MODE_USB_HOST;
priv->mode = PHY_MODE_USB_DEVICE;
break;
case USB_DR_MODE_OTG:
priv->mode = PHY_MODE_USB_OTG;
break;
case USB_DR_MODE_HOST:
default:
priv->mode = PHY_MODE_USB_HOST;
break;
}
priv->regmap = devm_regmap_init_mmio(dev, base, priv->regmap = devm_regmap_init_mmio(dev, base,
&phy_meson_gxl_usb2_regmap_conf); &phy_meson_gxl_usb2_regmap_conf);
if (IS_ERR(priv->regmap)) if (IS_ERR(priv->regmap))
return PTR_ERR(priv->regmap); return PTR_ERR(priv->regmap);
priv->clk = devm_clk_get(dev, "phy");
if (IS_ERR(priv->clk)) {
ret = PTR_ERR(priv->clk);
if (ret == -ENOENT)
priv->clk = NULL;
else
return ret;
}
priv->reset = devm_reset_control_get_optional_shared(dev, "phy");
if (IS_ERR(priv->reset))
return PTR_ERR(priv->reset);
phy = devm_phy_create(dev, NULL, &phy_meson_gxl_usb2_ops); phy = devm_phy_create(dev, NULL, &phy_meson_gxl_usb2_ops);
if (IS_ERR(phy)) { if (IS_ERR(phy)) {
dev_err(dev, "failed to create PHY\n"); ret = PTR_ERR(phy);
return PTR_ERR(phy); if (ret != -EPROBE_DEFER)
dev_err(dev, "failed to create PHY\n");
return ret;
} }
phy_set_drvdata(phy, priv); phy_set_drvdata(phy, priv);
......
// SPDX-License-Identifier: GPL-2.0
/*
* Meson GXL USB3 PHY and OTG mode detection driver
*
* Copyright (C) 2018 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
*/
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/phy/phy.h>
#include <linux/regmap.h>
#include <linux/reset.h>
#include <linux/platform_device.h>
#define USB_R0 0x00
#define USB_R0_P30_FSEL_MASK GENMASK(5, 0)
#define USB_R0_P30_PHY_RESET BIT(6)
#define USB_R0_P30_TEST_POWERDOWN_HSP BIT(7)
#define USB_R0_P30_TEST_POWERDOWN_SSP BIT(8)
#define USB_R0_P30_ACJT_LEVEL_MASK GENMASK(13, 9)
#define USB_R0_P30_TX_BOOST_LEVEL_MASK GENMASK(16, 14)
#define USB_R0_P30_LANE0_TX2RX_LOOPBACK BIT(17)
#define USB_R0_P30_LANE0_EXT_PCLK_REQ BIT(18)
#define USB_R0_P30_PCS_RX_LOS_MASK_VAL_MASK GENMASK(28, 19)
#define USB_R0_U2D_SS_SCALEDOWN_MODE_MASK GENMASK(30, 29)
#define USB_R0_U2D_ACT BIT(31)
#define USB_R1 0x04
#define USB_R1_U3H_BIGENDIAN_GS BIT(0)
#define USB_R1_U3H_PME_ENABLE BIT(1)
#define USB_R1_U3H_HUB_PORT_OVERCURRENT_MASK GENMASK(6, 2)
#define USB_R1_U3H_HUB_PORT_PERM_ATTACH_MASK GENMASK(11, 7)
#define USB_R1_U3H_HOST_U2_PORT_DISABLE_MASK GENMASK(15, 12)
#define USB_R1_U3H_HOST_U3_PORT_DISABLE BIT(16)
#define USB_R1_U3H_HOST_PORT_POWER_CONTROL_PRESENT BIT(17)
#define USB_R1_U3H_HOST_MSI_ENABLE BIT(18)
#define USB_R1_U3H_FLADJ_30MHZ_REG_MASK GENMASK(24, 19)
#define USB_R1_P30_PCS_TX_SWING_FULL_MASK GENMASK(31, 25)
#define USB_R2 0x08
#define USB_R2_P30_CR_DATA_IN_MASK GENMASK(15, 0)
#define USB_R2_P30_CR_READ BIT(16)
#define USB_R2_P30_CR_WRITE BIT(17)
#define USB_R2_P30_CR_CAP_ADDR BIT(18)
#define USB_R2_P30_CR_CAP_DATA BIT(19)
#define USB_R2_P30_PCS_TX_DEEMPH_3P5DB_MASK GENMASK(25, 20)
#define USB_R2_P30_PCS_TX_DEEMPH_6DB_MASK GENMASK(31, 26)
#define USB_R3 0x0c
#define USB_R3_P30_SSC_ENABLE BIT(0)
#define USB_R3_P30_SSC_RANGE_MASK GENMASK(3, 1)
#define USB_R3_P30_SSC_REF_CLK_SEL_MASK GENMASK(12, 4)
#define USB_R3_P30_REF_SSP_EN BIT(13)
#define USB_R3_P30_LOS_BIAS_MASK GENMASK(18, 16)
#define USB_R3_P30_LOS_LEVEL_MASK GENMASK(23, 19)
#define USB_R3_P30_MPLL_MULTIPLIER_MASK GENMASK(30, 24)
#define USB_R4 0x10
#define USB_R4_P21_PORT_RESET_0 BIT(0)
#define USB_R4_P21_SLEEP_M0 BIT(1)
#define USB_R4_MEM_PD_MASK GENMASK(3, 2)
#define USB_R4_P21_ONLY BIT(4)
#define USB_R5 0x14
#define USB_R5_ID_DIG_SYNC BIT(0)
#define USB_R5_ID_DIG_REG BIT(1)
#define USB_R5_ID_DIG_CFG_MASK GENMASK(3, 2)
#define USB_R5_ID_DIG_EN_0 BIT(4)
#define USB_R5_ID_DIG_EN_1 BIT(5)
#define USB_R5_ID_DIG_CURR BIT(6)
#define USB_R5_ID_DIG_IRQ BIT(7)
#define USB_R5_ID_DIG_TH_MASK GENMASK(15, 8)
#define USB_R5_ID_DIG_CNT_MASK GENMASK(23, 16)
/* read-only register */
#define USB_R6 0x18
#define USB_R6_P30_CR_DATA_OUT_MASK GENMASK(15, 0)
#define USB_R6_P30_CR_ACK BIT(16)
struct phy_meson_gxl_usb3_priv {
struct regmap *regmap;
enum phy_mode mode;
struct clk *clk_phy;
struct clk *clk_peripheral;
struct reset_control *reset;
};
static const struct regmap_config phy_meson_gxl_usb3_regmap_conf = {
.reg_bits = 8,
.val_bits = 32,
.reg_stride = 4,
.max_register = USB_R6,
};
static int phy_meson_gxl_usb3_power_on(struct phy *phy)
{
struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_0,
USB_R5_ID_DIG_EN_0);
regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_1,
USB_R5_ID_DIG_EN_1);
regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_TH_MASK,
FIELD_PREP(USB_R5_ID_DIG_TH_MASK, 0xff));
return 0;
}
static int phy_meson_gxl_usb3_power_off(struct phy *phy)
{
struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_0, 0);
regmap_update_bits(priv->regmap, USB_R5, USB_R5_ID_DIG_EN_1, 0);
return 0;
}
static int phy_meson_gxl_usb3_set_mode(struct phy *phy, enum phy_mode mode)
{
struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
switch (mode) {
case PHY_MODE_USB_HOST:
regmap_update_bits(priv->regmap, USB_R0, USB_R0_U2D_ACT, 0);
regmap_update_bits(priv->regmap, USB_R4, USB_R4_P21_SLEEP_M0,
0);
break;
case PHY_MODE_USB_DEVICE:
regmap_update_bits(priv->regmap, USB_R0, USB_R0_U2D_ACT,
USB_R0_U2D_ACT);
regmap_update_bits(priv->regmap, USB_R4, USB_R4_P21_SLEEP_M0,
USB_R4_P21_SLEEP_M0);
break;
default:
dev_err(&phy->dev, "unsupported PHY mode %d\n", mode);
return -EINVAL;
}
priv->mode = mode;
return 0;
}
static int phy_meson_gxl_usb3_init(struct phy *phy)
{
struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
int ret;
ret = reset_control_reset(priv->reset);
if (ret)
goto err;
ret = clk_prepare_enable(priv->clk_phy);
if (ret)
goto err;
ret = clk_prepare_enable(priv->clk_peripheral);
if (ret)
goto err_disable_clk_phy;
ret = phy_meson_gxl_usb3_set_mode(phy, priv->mode);
if (ret)
goto err_disable_clk_peripheral;
regmap_update_bits(priv->regmap, USB_R1,
USB_R1_U3H_FLADJ_30MHZ_REG_MASK,
FIELD_PREP(USB_R1_U3H_FLADJ_30MHZ_REG_MASK, 0x20));
return 0;
err_disable_clk_peripheral:
clk_disable_unprepare(priv->clk_peripheral);
err_disable_clk_phy:
clk_disable_unprepare(priv->clk_phy);
err:
return ret;
}
static int phy_meson_gxl_usb3_exit(struct phy *phy)
{
struct phy_meson_gxl_usb3_priv *priv = phy_get_drvdata(phy);
clk_disable_unprepare(priv->clk_peripheral);
clk_disable_unprepare(priv->clk_phy);
return 0;
}
static const struct phy_ops phy_meson_gxl_usb3_ops = {
.power_on = phy_meson_gxl_usb3_power_on,
.power_off = phy_meson_gxl_usb3_power_off,
.set_mode = phy_meson_gxl_usb3_set_mode,
.init = phy_meson_gxl_usb3_init,
.exit = phy_meson_gxl_usb3_exit,
.owner = THIS_MODULE,
};
static int phy_meson_gxl_usb3_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct phy_meson_gxl_usb3_priv *priv;
struct resource *res;
struct phy *phy;
struct phy_provider *phy_provider;
void __iomem *base;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
priv->regmap = devm_regmap_init_mmio(dev, base,
&phy_meson_gxl_usb3_regmap_conf);
if (IS_ERR(priv->regmap))
return PTR_ERR(priv->regmap);
priv->clk_phy = devm_clk_get(dev, "phy");
if (IS_ERR(priv->clk_phy))
return PTR_ERR(priv->clk_phy);
priv->clk_peripheral = devm_clk_get(dev, "peripheral");
if (IS_ERR(priv->clk_peripheral))
return PTR_ERR(priv->clk_peripheral);
priv->reset = devm_reset_control_array_get_shared(dev);
if (IS_ERR(priv->reset))
return PTR_ERR(priv->reset);
/*
* default to host mode as hardware defaults and/or boot-loader
* behavior can result in this PHY starting up in device mode. this
* default and the initialization in phy_meson_gxl_usb3_init ensure
* that we reproducibly start in a known mode on all devices.
*/
priv->mode = PHY_MODE_USB_HOST;
phy = devm_phy_create(dev, np, &phy_meson_gxl_usb3_ops);
if (IS_ERR(phy)) {
ret = PTR_ERR(phy);
if (ret != -EPROBE_DEFER)
dev_err(dev, "failed to create PHY\n");
return ret;
}
phy_set_drvdata(phy, priv);
phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
return PTR_ERR_OR_ZERO(phy_provider);
}
static const struct of_device_id phy_meson_gxl_usb3_of_match[] = {
{ .compatible = "amlogic,meson-gxl-usb3-phy", },
{ },
};
MODULE_DEVICE_TABLE(of, phy_meson_gxl_usb3_of_match);
static struct platform_driver phy_meson_gxl_usb3_driver = {
.probe = phy_meson_gxl_usb3_probe,
.driver = {
.name = "phy-meson-gxl-usb3",
.of_match_table = phy_meson_gxl_usb3_of_match,
},
};
module_platform_driver(phy_meson_gxl_usb3_driver);
MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>");
MODULE_DESCRIPTION("Meson GXL USB3 PHY and OTG detection driver");
MODULE_LICENSE("GPL v2");
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
config PHY_HI6220_USB config PHY_HI6220_USB
tristate "hi6220 USB PHY support" tristate "hi6220 USB PHY support"
depends on (ARCH_HISI && ARM64) || COMPILE_TEST depends on (ARCH_HISI && ARM64) || COMPILE_TEST
depends on HAS_IOMEM
select GENERIC_PHY select GENERIC_PHY
select MFD_SYSCON select MFD_SYSCON
help help
...@@ -11,6 +12,25 @@ config PHY_HI6220_USB ...@@ -11,6 +12,25 @@ config PHY_HI6220_USB
To compile this driver as a module, choose M here. To compile this driver as a module, choose M here.
config PHY_HISTB_COMBPHY
tristate "HiSilicon STB SoCs COMBPHY support"
depends on (ARCH_HISI && ARM64) || COMPILE_TEST
select GENERIC_PHY
select MFD_SYSCON
help
Enable this to support the HISILICON STB SoCs COMBPHY.
If unsure, say N.
config PHY_HISI_INNO_USB2
tristate "HiSilicon INNO USB2 PHY support"
depends on (ARCH_HISI && ARM64) || COMPILE_TEST
select GENERIC_PHY
select MFD_SYSCON
help
Support for INNO USB2 PHY on HiSilicon SoCs. This Phy supports
USB 1.5Mb/s, USB 12Mb/s, USB 480Mb/s speeds. It supports one
USB host port to accept one USB device.
config PHY_HIX5HD2_SATA config PHY_HIX5HD2_SATA
tristate "HIX5HD2 SATA PHY Driver" tristate "HIX5HD2 SATA PHY Driver"
depends on ARCH_HIX5HD2 && OF && HAS_IOMEM depends on ARCH_HIX5HD2 && OF && HAS_IOMEM
......
obj-$(CONFIG_PHY_HI6220_USB) += phy-hi6220-usb.o obj-$(CONFIG_PHY_HI6220_USB) += phy-hi6220-usb.o
obj-$(CONFIG_PHY_HISTB_COMBPHY) += phy-histb-combphy.o
obj-$(CONFIG_PHY_HISI_INNO_USB2) += phy-hisi-inno-usb2.o
obj-$(CONFIG_PHY_HIX5HD2_SATA) += phy-hix5hd2-sata.o obj-$(CONFIG_PHY_HIX5HD2_SATA) += phy-hix5hd2-sata.o
/*
* HiSilicon INNO USB2 PHY Driver.
*
* Copyright (c) 2016-2017 HiSilicon Technologies Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/phy/phy.h>
#include <linux/reset.h>
#define INNO_PHY_PORT_NUM 2
#define REF_CLK_STABLE_TIME 100 /* unit:us */
#define UTMI_CLK_STABLE_TIME 200 /* unit:us */
#define TEST_CLK_STABLE_TIME 2 /* unit:ms */
#define PHY_CLK_STABLE_TIME 2 /* unit:ms */
#define UTMI_RST_COMPLETE_TIME 2 /* unit:ms */
#define POR_RST_COMPLETE_TIME 300 /* unit:us */
#define PHY_TEST_DATA GENMASK(7, 0)
#define PHY_TEST_ADDR GENMASK(15, 8)
#define PHY_TEST_PORT GENMASK(18, 16)
#define PHY_TEST_WREN BIT(21)
#define PHY_TEST_CLK BIT(22) /* rising edge active */
#define PHY_TEST_RST BIT(23) /* low active */
#define PHY_CLK_ENABLE BIT(2)
struct hisi_inno_phy_port {
struct reset_control *utmi_rst;
struct hisi_inno_phy_priv *priv;
};
struct hisi_inno_phy_priv {
void __iomem *mmio;
struct clk *ref_clk;
struct reset_control *por_rst;
struct hisi_inno_phy_port ports[INNO_PHY_PORT_NUM];
};
static void hisi_inno_phy_write_reg(struct hisi_inno_phy_priv *priv,
u8 port, u32 addr, u32 data)
{
void __iomem *reg = priv->mmio;
u32 val;
val = (data & PHY_TEST_DATA) |
((addr << 8) & PHY_TEST_ADDR) |
((port << 16) & PHY_TEST_PORT) |
PHY_TEST_WREN | PHY_TEST_RST;
writel(val, reg);
val |= PHY_TEST_CLK;
writel(val, reg);
val &= ~PHY_TEST_CLK;
writel(val, reg);
}
static void hisi_inno_phy_setup(struct hisi_inno_phy_priv *priv)
{
/* The phy clk is controlled by the port0 register 0x06. */
hisi_inno_phy_write_reg(priv, 0, 0x06, PHY_CLK_ENABLE);
msleep(PHY_CLK_STABLE_TIME);
}
static int hisi_inno_phy_init(struct phy *phy)
{
struct hisi_inno_phy_port *port = phy_get_drvdata(phy);
struct hisi_inno_phy_priv *priv = port->priv;
int ret;
ret = clk_prepare_enable(priv->ref_clk);
if (ret)
return ret;
udelay(REF_CLK_STABLE_TIME);
reset_control_deassert(priv->por_rst);
udelay(POR_RST_COMPLETE_TIME);
/* Set up phy registers */
hisi_inno_phy_setup(priv);
reset_control_deassert(port->utmi_rst);
udelay(UTMI_RST_COMPLETE_TIME);
return 0;
}
static int hisi_inno_phy_exit(struct phy *phy)
{
struct hisi_inno_phy_port *port = phy_get_drvdata(phy);
struct hisi_inno_phy_priv *priv = port->priv;
reset_control_assert(port->utmi_rst);
reset_control_assert(priv->por_rst);
clk_disable_unprepare(priv->ref_clk);
return 0;
}
static const struct phy_ops hisi_inno_phy_ops = {
.init = hisi_inno_phy_init,
.exit = hisi_inno_phy_exit,
.owner = THIS_MODULE,
};
static int hisi_inno_phy_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct hisi_inno_phy_priv *priv;
struct phy_provider *provider;
struct device_node *child;
struct resource *res;
int i = 0;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->mmio = devm_ioremap_resource(dev, res);
if (IS_ERR(priv->mmio)) {
ret = PTR_ERR(priv->mmio);
return ret;
}
priv->ref_clk = devm_clk_get(dev, NULL);
if (IS_ERR(priv->ref_clk))
return PTR_ERR(priv->ref_clk);
priv->por_rst = devm_reset_control_get_exclusive(dev, NULL);
if (IS_ERR(priv->por_rst))
return PTR_ERR(priv->por_rst);
for_each_child_of_node(np, child) {
struct reset_control *rst;
struct phy *phy;
rst = of_reset_control_get_exclusive(child, NULL);
if (IS_ERR(rst))
return PTR_ERR(rst);
priv->ports[i].utmi_rst = rst;
priv->ports[i].priv = priv;
phy = devm_phy_create(dev, child, &hisi_inno_phy_ops);
if (IS_ERR(phy))
return PTR_ERR(phy);
phy_set_bus_width(phy, 8);
phy_set_drvdata(phy, &priv->ports[i]);
i++;
if (i > INNO_PHY_PORT_NUM) {
dev_warn(dev, "Support %d ports in maximum\n", i);
break;
}
}
provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
return PTR_ERR_OR_ZERO(provider);
}
static const struct of_device_id hisi_inno_phy_of_match[] = {
{ .compatible = "hisilicon,inno-usb2-phy", },
{ .compatible = "hisilicon,hi3798cv200-usb2-phy", },
{ },
};
MODULE_DEVICE_TABLE(of, hisi_inno_phy_of_match);
static struct platform_driver hisi_inno_phy_driver = {
.probe = hisi_inno_phy_probe,
.driver = {
.name = "hisi-inno-phy",
.of_match_table = hisi_inno_phy_of_match,
}
};
module_platform_driver(hisi_inno_phy_driver);
MODULE_DESCRIPTION("HiSilicon INNO USB2 PHY Driver");
MODULE_LICENSE("GPL v2");
/*
* COMBPHY driver for HiSilicon STB SoCs
*
* Copyright (C) 2016-2017 HiSilicon Co., Ltd. http://www.hisilicon.com
*
* Authors: Jianguo Sun <sunjianguo1@huawei.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/phy/phy.h>
#include <linux/regmap.h>
#include <linux/reset.h>
#include <dt-bindings/phy/phy.h>
#define COMBPHY_MODE_PCIE 0
#define COMBPHY_MODE_USB3 1
#define COMBPHY_MODE_SATA 2
#define COMBPHY_CFG_REG 0x0
#define COMBPHY_BYPASS_CODEC BIT(31)
#define COMBPHY_TEST_WRITE BIT(24)
#define COMBPHY_TEST_DATA_SHIFT 20
#define COMBPHY_TEST_DATA_MASK GENMASK(23, 20)
#define COMBPHY_TEST_ADDR_SHIFT 12
#define COMBPHY_TEST_ADDR_MASK GENMASK(16, 12)
#define COMBPHY_CLKREF_OUT_OEN BIT(0)
struct histb_combphy_mode {
int fixed;
int select;
u32 reg;
u32 shift;
u32 mask;
};
struct histb_combphy_priv {
void __iomem *mmio;
struct regmap *syscon;
struct reset_control *por_rst;
struct clk *ref_clk;
struct phy *phy;
struct histb_combphy_mode mode;
};
static void nano_register_write(struct histb_combphy_priv *priv,
u32 addr, u32 data)
{
void __iomem *reg = priv->mmio + COMBPHY_CFG_REG;
u32 val;
/* Set up address and data for the write */
val = readl(reg);
val &= ~COMBPHY_TEST_ADDR_MASK;
val |= addr << COMBPHY_TEST_ADDR_SHIFT;
val &= ~COMBPHY_TEST_DATA_MASK;
val |= data << COMBPHY_TEST_DATA_SHIFT;
writel(val, reg);
/* Flip strobe control to trigger the write */
val &= ~COMBPHY_TEST_WRITE;
writel(val, reg);
val |= COMBPHY_TEST_WRITE;
writel(val, reg);
}
static int is_mode_fixed(struct histb_combphy_mode *mode)
{
return (mode->fixed != PHY_NONE) ? true : false;
}
static int histb_combphy_set_mode(struct histb_combphy_priv *priv)
{
struct histb_combphy_mode *mode = &priv->mode;
struct regmap *syscon = priv->syscon;
u32 hw_sel;
if (is_mode_fixed(mode))
return 0;
switch (mode->select) {
case PHY_TYPE_SATA:
hw_sel = COMBPHY_MODE_SATA;
break;
case PHY_TYPE_PCIE:
hw_sel = COMBPHY_MODE_PCIE;
break;
case PHY_TYPE_USB3:
hw_sel = COMBPHY_MODE_USB3;
break;
default:
return -EINVAL;
}
return regmap_update_bits(syscon, mode->reg, mode->mask,
hw_sel << mode->shift);
}
static int histb_combphy_init(struct phy *phy)
{
struct histb_combphy_priv *priv = phy_get_drvdata(phy);
u32 val;
int ret;
ret = histb_combphy_set_mode(priv);
if (ret)
return ret;
/* Clear bypass bit to enable encoding/decoding */
val = readl(priv->mmio + COMBPHY_CFG_REG);
val &= ~COMBPHY_BYPASS_CODEC;
writel(val, priv->mmio + COMBPHY_CFG_REG);
ret = clk_prepare_enable(priv->ref_clk);
if (ret)
return ret;
reset_control_deassert(priv->por_rst);
/* Enable EP clock */
val = readl(priv->mmio + COMBPHY_CFG_REG);
val |= COMBPHY_CLKREF_OUT_OEN;
writel(val, priv->mmio + COMBPHY_CFG_REG);
/* Need to wait for EP clock stable */
mdelay(5);
/* Configure nano phy registers as suggested by vendor */
nano_register_write(priv, 0x1, 0x8);
nano_register_write(priv, 0xc, 0x9);
nano_register_write(priv, 0x1a, 0x4);
return 0;
}
static int histb_combphy_exit(struct phy *phy)
{
struct histb_combphy_priv *priv = phy_get_drvdata(phy);
u32 val;
/* Disable EP clock */
val = readl(priv->mmio + COMBPHY_CFG_REG);
val &= ~COMBPHY_CLKREF_OUT_OEN;
writel(val, priv->mmio + COMBPHY_CFG_REG);
reset_control_assert(priv->por_rst);
clk_disable_unprepare(priv->ref_clk);
return 0;
}
static const struct phy_ops histb_combphy_ops = {
.init = histb_combphy_init,
.exit = histb_combphy_exit,
.owner = THIS_MODULE,
};
static struct phy *histb_combphy_xlate(struct device *dev,
struct of_phandle_args *args)
{
struct histb_combphy_priv *priv = dev_get_drvdata(dev);
struct histb_combphy_mode *mode = &priv->mode;
if (args->args_count < 1) {
dev_err(dev, "invalid number of arguments\n");
return ERR_PTR(-EINVAL);
}
mode->select = args->args[0];
if (mode->select < PHY_TYPE_SATA || mode->select > PHY_TYPE_USB3) {
dev_err(dev, "invalid phy mode select argument\n");
return ERR_PTR(-EINVAL);
}
if (is_mode_fixed(mode) && mode->select != mode->fixed) {
dev_err(dev, "mode select %d mismatch fixed phy mode %d\n",
mode->select, mode->fixed);
return ERR_PTR(-EINVAL);
}
return priv->phy;
}
static int histb_combphy_probe(struct platform_device *pdev)
{
struct phy_provider *phy_provider;
struct device *dev = &pdev->dev;
struct histb_combphy_priv *priv;
struct device_node *np = dev->of_node;
struct histb_combphy_mode *mode;
struct resource *res;
u32 vals[3];
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv->mmio = devm_ioremap_resource(dev, res);
if (IS_ERR(priv->mmio)) {
ret = PTR_ERR(priv->mmio);
return ret;
}
priv->syscon = syscon_node_to_regmap(np->parent);
if (IS_ERR(priv->syscon)) {
dev_err(dev, "failed to find peri_ctrl syscon regmap\n");
return PTR_ERR(priv->syscon);
}
mode = &priv->mode;
mode->fixed = PHY_NONE;
ret = of_property_read_u32(np, "hisilicon,fixed-mode", &mode->fixed);
if (ret == 0)
dev_dbg(dev, "found fixed phy mode %d\n", mode->fixed);
ret = of_property_read_u32_array(np, "hisilicon,mode-select-bits",
vals, ARRAY_SIZE(vals));
if (ret == 0) {
if (is_mode_fixed(mode)) {
dev_err(dev, "found select bits for fixed mode phy\n");
return -EINVAL;
}
mode->reg = vals[0];
mode->shift = vals[1];
mode->mask = vals[2];
dev_dbg(dev, "found mode select bits\n");
} else {
if (!is_mode_fixed(mode)) {
dev_err(dev, "no valid select bits found for non-fixed phy\n");
return -ENODEV;
}
}
priv->ref_clk = devm_clk_get(dev, NULL);
if (IS_ERR(priv->ref_clk)) {
dev_err(dev, "failed to find ref clock\n");
return PTR_ERR(priv->ref_clk);
}
priv->por_rst = devm_reset_control_get(dev, NULL);
if (IS_ERR(priv->por_rst)) {
dev_err(dev, "failed to get poweron reset\n");
return PTR_ERR(priv->por_rst);
}
priv->phy = devm_phy_create(dev, NULL, &histb_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, histb_combphy_xlate);
return PTR_ERR_OR_ZERO(phy_provider);
}
static const struct of_device_id histb_combphy_of_match[] = {
{ .compatible = "hisilicon,hi3798cv200-combphy" },
{ },
};
MODULE_DEVICE_TABLE(of, histb_combphy_of_match);
static struct platform_driver histb_combphy_driver = {
.probe = histb_combphy_probe,
.driver = {
.name = "combphy",
.of_match_table = histb_combphy_of_match,
},
};
module_platform_driver(histb_combphy_driver);
MODULE_DESCRIPTION("HiSilicon STB COMBPHY driver");
MODULE_LICENSE("GPL v2");
...@@ -127,7 +127,7 @@ static int phy_berlin_usb_power_on(struct phy *phy) ...@@ -127,7 +127,7 @@ static int phy_berlin_usb_power_on(struct phy *phy)
writel(V2I_VCO_RATIO(0x5) | R_ROTATE_0 | ANA_TEST_DC_CTRL(0x5), writel(V2I_VCO_RATIO(0x5) | R_ROTATE_0 | ANA_TEST_DC_CTRL(0x5),
priv->base + USB_PHY_ANALOG); priv->base + USB_PHY_ANALOG);
writel(PHASE_FREEZE_DLY_4_CL | ACK_LENGTH_16_CL | SQ_LENGTH_12 | writel(PHASE_FREEZE_DLY_4_CL | ACK_LENGTH_16_CL | SQ_LENGTH_12 |
DISCON_THRESHOLD_260 | SQ_THRESHOLD(0xa) | LPF_COEF(0x2) | DISCON_THRESHOLD_270 | SQ_THRESHOLD(0xa) | LPF_COEF(0x2) |
INTPL_CUR_30, priv->base + USB_PHY_RX_CTRL); INTPL_CUR_30, priv->base + USB_PHY_RX_CTRL);
writel(TX_VDD12_13 | TX_OUT_AMP(0x3), priv->base + USB_PHY_TX_CTRL1); writel(TX_VDD12_13 | TX_OUT_AMP(0x3), priv->base + USB_PHY_TX_CTRL1);
......
...@@ -306,6 +306,8 @@ struct mtk_tphy { ...@@ -306,6 +306,8 @@ struct mtk_tphy {
const struct mtk_phy_pdata *pdata; const struct mtk_phy_pdata *pdata;
struct mtk_phy_instance **phys; struct mtk_phy_instance **phys;
int nphys; int nphys;
int src_ref_clk; /* MHZ, reference clock for slew rate calibrate */
int src_coef; /* coefficient for slew rate calibrate */
}; };
static void hs_slew_rate_calibrate(struct mtk_tphy *tphy, static void hs_slew_rate_calibrate(struct mtk_tphy *tphy,
...@@ -360,16 +362,17 @@ static void hs_slew_rate_calibrate(struct mtk_tphy *tphy, ...@@ -360,16 +362,17 @@ static void hs_slew_rate_calibrate(struct mtk_tphy *tphy,
writel(tmp, fmreg + U3P_U2FREQ_FMMONR1); writel(tmp, fmreg + U3P_U2FREQ_FMMONR1);
if (fm_out) { if (fm_out) {
/* ( 1024 / FM_OUT ) x reference clock frequency x 0.028 */ /* ( 1024 / FM_OUT ) x reference clock frequency x coef */
tmp = U3P_FM_DET_CYCLE_CNT * U3P_REF_CLK * U3P_SLEW_RATE_COEF; tmp = tphy->src_ref_clk * tphy->src_coef;
tmp /= fm_out; tmp = (tmp * U3P_FM_DET_CYCLE_CNT) / fm_out;
calibration_val = DIV_ROUND_CLOSEST(tmp, U3P_SR_COEF_DIVISOR); calibration_val = DIV_ROUND_CLOSEST(tmp, U3P_SR_COEF_DIVISOR);
} else { } else {
/* if FM detection fail, set default value */ /* if FM detection fail, set default value */
calibration_val = 4; calibration_val = 4;
} }
dev_dbg(tphy->dev, "phy:%d, fm_out:%d, calib:%d\n", dev_dbg(tphy->dev, "phy:%d, fm_out:%d, calib:%d (clk:%d, coef:%d)\n",
instance->index, fm_out, calibration_val); instance->index, fm_out, calibration_val,
tphy->src_ref_clk, tphy->src_coef);
/* set HS slew rate */ /* set HS slew rate */
tmp = readl(com + U3P_USBPHYACR5); tmp = readl(com + U3P_USBPHYACR5);
...@@ -688,8 +691,7 @@ static void pcie_phy_instance_power_on(struct mtk_tphy *tphy, ...@@ -688,8 +691,7 @@ static void pcie_phy_instance_power_on(struct mtk_tphy *tphy,
u32 tmp; u32 tmp;
tmp = readl(bank->chip + U3P_U3_CHIP_GPIO_CTLD); tmp = readl(bank->chip + U3P_U3_CHIP_GPIO_CTLD);
tmp &= ~(P3C_FORCE_IP_SW_RST | P3C_MCU_BUS_CK_GATE_EN | tmp &= ~(P3C_FORCE_IP_SW_RST | P3C_REG_IP_SW_RST);
P3C_REG_IP_SW_RST);
writel(tmp, bank->chip + U3P_U3_CHIP_GPIO_CTLD); writel(tmp, bank->chip + U3P_U3_CHIP_GPIO_CTLD);
tmp = readl(bank->chip + U3P_U3_CHIP_GPIO_CTLE); tmp = readl(bank->chip + U3P_U3_CHIP_GPIO_CTLE);
...@@ -1042,6 +1044,13 @@ static int mtk_tphy_probe(struct platform_device *pdev) ...@@ -1042,6 +1044,13 @@ static int mtk_tphy_probe(struct platform_device *pdev)
tphy->u3phya_ref = NULL; tphy->u3phya_ref = NULL;
} }
tphy->src_ref_clk = U3P_REF_CLK;
tphy->src_coef = U3P_SLEW_RATE_COEF;
/* update parameters of slew rate calibrate if exist */
device_property_read_u32(dev, "mediatek,src-ref-clk-mhz",
&tphy->src_ref_clk);
device_property_read_u32(dev, "mediatek,src-coef", &tphy->src_coef);
port = 0; port = 0;
for_each_child_of_node(np, child_np) { for_each_child_of_node(np, child_np) {
struct mtk_phy_instance *instance; struct mtk_phy_instance *instance;
......
...@@ -10,3 +10,11 @@ config PHY_CPCAP_USB ...@@ -10,3 +10,11 @@ config PHY_CPCAP_USB
help help
Enable this for USB to work on Motorola phones and tablets Enable this for USB to work on Motorola phones and tablets
such as Droid 4. such as Droid 4.
config PHY_MAPPHONE_MDM6600
tristate "Motorola Mapphone MDM6600 modem USB PHY driver"
depends on OF && USB_SUPPORT
select GENERIC_PHY
help
Enable this for MDM6600 USB modem to work on Motorola phones
and tablets such as Droid 4.
...@@ -3,3 +3,4 @@ ...@@ -3,3 +3,4 @@
# #
obj-$(CONFIG_PHY_CPCAP_USB) += phy-cpcap-usb.o obj-$(CONFIG_PHY_CPCAP_USB) += phy-cpcap-usb.o
obj-$(CONFIG_PHY_MAPPHONE_MDM6600) += phy-mapphone-mdm6600.o
This diff is collapsed.
...@@ -351,6 +351,8 @@ int phy_set_mode(struct phy *phy, enum phy_mode mode) ...@@ -351,6 +351,8 @@ int phy_set_mode(struct phy *phy, enum phy_mode mode)
mutex_lock(&phy->mutex); mutex_lock(&phy->mutex);
ret = phy->ops->set_mode(phy, mode); ret = phy->ops->set_mode(phy, mode);
if (!ret)
phy->attrs.mode = mode;
mutex_unlock(&phy->mutex); mutex_unlock(&phy->mutex);
return ret; return ret;
......
...@@ -60,8 +60,14 @@ static int lpc18xx_usb_otg_phy_power_on(struct phy *phy) ...@@ -60,8 +60,14 @@ static int lpc18xx_usb_otg_phy_power_on(struct phy *phy)
return ret; return ret;
/* The bit in CREG is cleared to enable the PHY */ /* The bit in CREG is cleared to enable the PHY */
return regmap_update_bits(lpc->reg, LPC18XX_CREG_CREG0, ret = regmap_update_bits(lpc->reg, LPC18XX_CREG_CREG0,
LPC18XX_CREG_CREG0_USB0PHY, 0); LPC18XX_CREG_CREG0_USB0PHY, 0);
if (ret) {
clk_disable(lpc->clk);
return ret;
}
return 0;
} }
static int lpc18xx_usb_otg_phy_power_off(struct phy *phy) static int lpc18xx_usb_otg_phy_power_off(struct phy *phy)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
config PHY_RALINK_USB config PHY_RALINK_USB
tristate "Ralink USB PHY driver" tristate "Ralink USB PHY driver"
depends on RALINK || COMPILE_TEST depends on RALINK || COMPILE_TEST
depends on HAS_IOMEM
select GENERIC_PHY select GENERIC_PHY
select MFD_SYSCON select MFD_SYSCON
help help
......
...@@ -396,6 +396,10 @@ static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = { ...@@ -396,6 +396,10 @@ static const struct of_device_id rcar_gen3_phy_usb2_match_table[] = {
.compatible = "renesas,usb2-phy-r8a7796", .compatible = "renesas,usb2-phy-r8a7796",
.data = (void *)RCAR_GEN3_PHY_HAS_DEDICATED_PINS, .data = (void *)RCAR_GEN3_PHY_HAS_DEDICATED_PINS,
}, },
{
.compatible = "renesas,usb2-phy-r8a77965",
.data = (void *)RCAR_GEN3_PHY_HAS_DEDICATED_PINS,
},
{ {
.compatible = "renesas,rcar-gen3-usb2-phy", .compatible = "renesas,rcar-gen3-usb2-phy",
}, },
......
...@@ -29,6 +29,7 @@ config PHY_ROCKCHIP_INNO_USB2 ...@@ -29,6 +29,7 @@ config PHY_ROCKCHIP_INNO_USB2
config PHY_ROCKCHIP_PCIE config PHY_ROCKCHIP_PCIE
tristate "Rockchip PCIe PHY Driver" tristate "Rockchip PCIe PHY Driver"
depends on (ARCH_ROCKCHIP && OF) || COMPILE_TEST depends on (ARCH_ROCKCHIP && OF) || COMPILE_TEST
depends on HAS_IOMEM
select GENERIC_PHY select GENERIC_PHY
select MFD_SYSCON select MFD_SYSCON
help help
......
...@@ -76,6 +76,13 @@ ...@@ -76,6 +76,13 @@
#define PHYCTRL_OTAPDLYSEL_MASK 0xf #define PHYCTRL_OTAPDLYSEL_MASK 0xf
#define PHYCTRL_OTAPDLYSEL_SHIFT 0x7 #define PHYCTRL_OTAPDLYSEL_SHIFT 0x7
#define PHYCTRL_IS_CALDONE(x) \
((((x) >> PHYCTRL_CALDONE_SHIFT) & \
PHYCTRL_CALDONE_MASK) == PHYCTRL_CALDONE_DONE)
#define PHYCTRL_IS_DLLRDY(x) \
((((x) >> PHYCTRL_DLLRDY_SHIFT) & \
PHYCTRL_DLLRDY_MASK) == PHYCTRL_DLLRDY_DONE)
struct rockchip_emmc_phy { struct rockchip_emmc_phy {
unsigned int reg_offset; unsigned int reg_offset;
struct regmap *reg_base; struct regmap *reg_base;
...@@ -89,7 +96,7 @@ static int rockchip_emmc_phy_power(struct phy *phy, bool on_off) ...@@ -89,7 +96,7 @@ static int rockchip_emmc_phy_power(struct phy *phy, bool on_off)
unsigned int dllrdy; unsigned int dllrdy;
unsigned int freqsel = PHYCTRL_FREQSEL_200M; unsigned int freqsel = PHYCTRL_FREQSEL_200M;
unsigned long rate; unsigned long rate;
unsigned long timeout; int ret;
/* /*
* Keep phyctrl_pdb and phyctrl_endll low to allow * Keep phyctrl_pdb and phyctrl_endll low to allow
...@@ -160,17 +167,19 @@ static int rockchip_emmc_phy_power(struct phy *phy, bool on_off) ...@@ -160,17 +167,19 @@ static int rockchip_emmc_phy_power(struct phy *phy, bool on_off)
PHYCTRL_PDB_SHIFT)); PHYCTRL_PDB_SHIFT));
/* /*
* According to the user manual, it asks driver to * According to the user manual, it asks driver to wait 5us for
* wait 5us for calpad busy trimming * calpad busy trimming. However it is documented that this value is
* PVT(A.K.A process,voltage and temperature) relevant, so some
* failure cases are found which indicates we should be more tolerant
* to calpad busy trimming.
*/ */
udelay(5); ret = regmap_read_poll_timeout(rk_phy->reg_base,
regmap_read(rk_phy->reg_base, rk_phy->reg_offset + GRF_EMMCPHY_STATUS,
rk_phy->reg_offset + GRF_EMMCPHY_STATUS, caldone, PHYCTRL_IS_CALDONE(caldone),
&caldone); 0, 50);
caldone = (caldone >> PHYCTRL_CALDONE_SHIFT) & PHYCTRL_CALDONE_MASK; if (ret) {
if (caldone != PHYCTRL_CALDONE_DONE) { pr_err("%s: caldone failed, ret=%d\n", __func__, ret);
pr_err("rockchip_emmc_phy_power: caldone timeout.\n"); return ret;
return -ETIMEDOUT;
} }
/* Set the frequency of the DLL operation */ /* Set the frequency of the DLL operation */
...@@ -210,28 +219,15 @@ static int rockchip_emmc_phy_power(struct phy *phy, bool on_off) ...@@ -210,28 +219,15 @@ static int rockchip_emmc_phy_power(struct phy *phy, bool on_off)
* NOTE: There appear to be corner cases where the DLL seems to take * NOTE: There appear to be corner cases where the DLL seems to take
* extra long to lock for reasons that aren't understood. In some * extra long to lock for reasons that aren't understood. In some
* extreme cases we've seen it take up to over 10ms (!). We'll be * extreme cases we've seen it take up to over 10ms (!). We'll be
* generous and give it 50ms. We still busy wait here because: * generous and give it 50ms.
* - In most cases it should be super fast.
* - This is not called lots during normal operation so it shouldn't
* be a power or performance problem to busy wait. We expect it
* only at boot / resume. In both cases, eMMC is probably on the
* critical path so busy waiting a little extra time should be OK.
*/ */
timeout = jiffies + msecs_to_jiffies(50); ret = regmap_read_poll_timeout(rk_phy->reg_base,
do { rk_phy->reg_offset + GRF_EMMCPHY_STATUS,
udelay(1); dllrdy, PHYCTRL_IS_DLLRDY(dllrdy),
0, 50 * USEC_PER_MSEC);
regmap_read(rk_phy->reg_base, if (ret) {
rk_phy->reg_offset + GRF_EMMCPHY_STATUS, pr_err("%s: dllrdy failed. ret=%d\n", __func__, ret);
&dllrdy); return ret;
dllrdy = (dllrdy >> PHYCTRL_DLLRDY_SHIFT) & PHYCTRL_DLLRDY_MASK;
if (dllrdy == PHYCTRL_DLLRDY_DONE)
break;
} while (!time_after(jiffies, timeout));
if (dllrdy != PHYCTRL_DLLRDY_DONE) {
pr_err("rockchip_emmc_phy_power: dllrdy timeout.\n");
return -ETIMEDOUT;
} }
return 0; return 0;
......
...@@ -355,11 +355,26 @@ struct usb3phy_reg { ...@@ -355,11 +355,26 @@ struct usb3phy_reg {
u32 write_enable; u32 write_enable;
}; };
/**
* struct rockchip_usb3phy_port_cfg: usb3-phy port configuration.
* @reg: the base address for usb3-phy config.
* @typec_conn_dir: the register of type-c connector direction.
* @usb3tousb2_en: the register of type-c force usb2 to usb2 enable.
* @external_psm: the register of type-c phy external psm clock.
* @pipe_status: the register of type-c phy pipe status.
* @usb3_host_disable: the register of type-c usb3 host disable.
* @usb3_host_port: the register of type-c usb3 host port.
* @uphy_dp_sel: the register of type-c phy DP select control.
*/
struct rockchip_usb3phy_port_cfg { struct rockchip_usb3phy_port_cfg {
unsigned int reg;
struct usb3phy_reg typec_conn_dir; struct usb3phy_reg typec_conn_dir;
struct usb3phy_reg usb3tousb2_en; struct usb3phy_reg usb3tousb2_en;
struct usb3phy_reg external_psm; struct usb3phy_reg external_psm;
struct usb3phy_reg pipe_status; struct usb3phy_reg pipe_status;
struct usb3phy_reg usb3_host_disable;
struct usb3phy_reg usb3_host_port;
struct usb3phy_reg uphy_dp_sel;
}; };
struct rockchip_typec_phy { struct rockchip_typec_phy {
...@@ -372,7 +387,7 @@ struct rockchip_typec_phy { ...@@ -372,7 +387,7 @@ struct rockchip_typec_phy {
struct reset_control *uphy_rst; struct reset_control *uphy_rst;
struct reset_control *pipe_rst; struct reset_control *pipe_rst;
struct reset_control *tcphy_rst; struct reset_control *tcphy_rst;
struct rockchip_usb3phy_port_cfg port_cfgs; const struct rockchip_usb3phy_port_cfg *port_cfgs;
/* mutex to protect access to individual PHYs */ /* mutex to protect access to individual PHYs */
struct mutex lock; struct mutex lock;
...@@ -424,6 +439,30 @@ struct phy_reg dp_pll_cfg[] = { ...@@ -424,6 +439,30 @@ struct phy_reg dp_pll_cfg[] = {
{ 0x4, CMN_DIAG_PLL1_INCLK_CTRL }, { 0x4, CMN_DIAG_PLL1_INCLK_CTRL },
}; };
static const struct rockchip_usb3phy_port_cfg rk3399_usb3phy_port_cfgs[] = {
{
.reg = 0xff7c0000,
.typec_conn_dir = { 0xe580, 0, 16 },
.usb3tousb2_en = { 0xe580, 3, 19 },
.external_psm = { 0xe588, 14, 30 },
.pipe_status = { 0xe5c0, 0, 0 },
.usb3_host_disable = { 0x2434, 0, 16 },
.usb3_host_port = { 0x2434, 12, 28 },
.uphy_dp_sel = { 0x6268, 19, 19 },
},
{
.reg = 0xff800000,
.typec_conn_dir = { 0xe58c, 0, 16 },
.usb3tousb2_en = { 0xe58c, 3, 19 },
.external_psm = { 0xe594, 14, 30 },
.pipe_status = { 0xe5c0, 16, 16 },
.usb3_host_disable = { 0x2444, 0, 16 },
.usb3_host_port = { 0x2444, 12, 28 },
.uphy_dp_sel = { 0x6268, 3, 19 },
},
{ /* sentinel */ }
};
static void tcphy_cfg_24m(struct rockchip_typec_phy *tcphy) static void tcphy_cfg_24m(struct rockchip_typec_phy *tcphy)
{ {
u32 i, rdata; u32 i, rdata;
...@@ -691,7 +730,7 @@ static void tcphy_dp_aux_calibration(struct rockchip_typec_phy *tcphy) ...@@ -691,7 +730,7 @@ static void tcphy_dp_aux_calibration(struct rockchip_typec_phy *tcphy)
static int tcphy_phy_init(struct rockchip_typec_phy *tcphy, u8 mode) static int tcphy_phy_init(struct rockchip_typec_phy *tcphy, u8 mode)
{ {
struct rockchip_usb3phy_port_cfg *cfg = &tcphy->port_cfgs; const struct rockchip_usb3phy_port_cfg *cfg = tcphy->port_cfgs;
int ret, i; int ret, i;
u32 val; u32 val;
...@@ -782,6 +821,9 @@ static int tcphy_get_mode(struct rockchip_typec_phy *tcphy) ...@@ -782,6 +821,9 @@ static int tcphy_get_mode(struct rockchip_typec_phy *tcphy)
u8 mode; u8 mode;
int ret; int ret;
if (!edev)
return MODE_DFP_USB;
ufp = extcon_get_state(edev, EXTCON_USB); ufp = extcon_get_state(edev, EXTCON_USB);
dp = extcon_get_state(edev, EXTCON_DISP_DP); dp = extcon_get_state(edev, EXTCON_DISP_DP);
...@@ -818,10 +860,22 @@ static int tcphy_get_mode(struct rockchip_typec_phy *tcphy) ...@@ -818,10 +860,22 @@ static int tcphy_get_mode(struct rockchip_typec_phy *tcphy)
return mode; return mode;
} }
static int tcphy_cfg_usb3_to_usb2_only(struct rockchip_typec_phy *tcphy,
bool value)
{
const struct rockchip_usb3phy_port_cfg *cfg = tcphy->port_cfgs;
property_enable(tcphy, &cfg->usb3tousb2_en, value);
property_enable(tcphy, &cfg->usb3_host_disable, value);
property_enable(tcphy, &cfg->usb3_host_port, !value);
return 0;
}
static int rockchip_usb3_phy_power_on(struct phy *phy) static int rockchip_usb3_phy_power_on(struct phy *phy)
{ {
struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy); struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy);
struct rockchip_usb3phy_port_cfg *cfg = &tcphy->port_cfgs; const struct rockchip_usb3phy_port_cfg *cfg = tcphy->port_cfgs;
const struct usb3phy_reg *reg = &cfg->pipe_status; const struct usb3phy_reg *reg = &cfg->pipe_status;
int timeout, new_mode, ret = 0; int timeout, new_mode, ret = 0;
u32 val; u32 val;
...@@ -835,8 +889,10 @@ static int rockchip_usb3_phy_power_on(struct phy *phy) ...@@ -835,8 +889,10 @@ static int rockchip_usb3_phy_power_on(struct phy *phy)
} }
/* DP-only mode; fall back to USB2 */ /* DP-only mode; fall back to USB2 */
if (!(new_mode & (MODE_DFP_USB | MODE_UFP_USB))) if (!(new_mode & (MODE_DFP_USB | MODE_UFP_USB))) {
tcphy_cfg_usb3_to_usb2_only(tcphy, true);
goto unlock_ret; goto unlock_ret;
}
if (tcphy->mode == new_mode) if (tcphy->mode == new_mode)
goto unlock_ret; goto unlock_ret;
...@@ -852,6 +908,9 @@ static int rockchip_usb3_phy_power_on(struct phy *phy) ...@@ -852,6 +908,9 @@ static int rockchip_usb3_phy_power_on(struct phy *phy)
regmap_read(tcphy->grf_regs, reg->offset, &val); regmap_read(tcphy->grf_regs, reg->offset, &val);
if (!(val & BIT(reg->enable_bit))) { if (!(val & BIT(reg->enable_bit))) {
tcphy->mode |= new_mode & (MODE_DFP_USB | MODE_UFP_USB); tcphy->mode |= new_mode & (MODE_DFP_USB | MODE_UFP_USB);
/* enable usb3 host */
tcphy_cfg_usb3_to_usb2_only(tcphy, false);
goto unlock_ret; goto unlock_ret;
} }
usleep_range(10, 20); usleep_range(10, 20);
...@@ -872,6 +931,7 @@ static int rockchip_usb3_phy_power_off(struct phy *phy) ...@@ -872,6 +931,7 @@ static int rockchip_usb3_phy_power_off(struct phy *phy)
struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy); struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy);
mutex_lock(&tcphy->lock); mutex_lock(&tcphy->lock);
tcphy_cfg_usb3_to_usb2_only(tcphy, false);
if (tcphy->mode == MODE_DISCONNECT) if (tcphy->mode == MODE_DISCONNECT)
goto unlock; goto unlock;
...@@ -894,6 +954,7 @@ static const struct phy_ops rockchip_usb3_phy_ops = { ...@@ -894,6 +954,7 @@ static const struct phy_ops rockchip_usb3_phy_ops = {
static int rockchip_dp_phy_power_on(struct phy *phy) static int rockchip_dp_phy_power_on(struct phy *phy)
{ {
struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy); struct rockchip_typec_phy *tcphy = phy_get_drvdata(phy);
const struct rockchip_usb3phy_port_cfg *cfg = tcphy->port_cfgs;
int new_mode, ret = 0; int new_mode, ret = 0;
u32 val; u32 val;
...@@ -926,6 +987,8 @@ static int rockchip_dp_phy_power_on(struct phy *phy) ...@@ -926,6 +987,8 @@ static int rockchip_dp_phy_power_on(struct phy *phy)
if (ret) if (ret)
goto unlock_ret; goto unlock_ret;
property_enable(tcphy, &cfg->uphy_dp_sel, 1);
ret = readx_poll_timeout(readl, tcphy->base + DP_MODE_CTL, ret = readx_poll_timeout(readl, tcphy->base + DP_MODE_CTL,
val, val & DP_MODE_A2, 1000, val, val & DP_MODE_A2, 1000,
PHY_MODE_SET_TIMEOUT); PHY_MODE_SET_TIMEOUT);
...@@ -984,51 +1047,9 @@ static const struct phy_ops rockchip_dp_phy_ops = { ...@@ -984,51 +1047,9 @@ static const struct phy_ops rockchip_dp_phy_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
}; };
static int tcphy_get_param(struct device *dev,
struct usb3phy_reg *reg,
const char *name)
{
u32 buffer[3];
int ret;
ret = of_property_read_u32_array(dev->of_node, name, buffer, 3);
if (ret) {
dev_err(dev, "Can not parse %s\n", name);
return ret;
}
reg->offset = buffer[0];
reg->enable_bit = buffer[1];
reg->write_enable = buffer[2];
return 0;
}
static int tcphy_parse_dt(struct rockchip_typec_phy *tcphy, static int tcphy_parse_dt(struct rockchip_typec_phy *tcphy,
struct device *dev) struct device *dev)
{ {
struct rockchip_usb3phy_port_cfg *cfg = &tcphy->port_cfgs;
int ret;
ret = tcphy_get_param(dev, &cfg->typec_conn_dir,
"rockchip,typec-conn-dir");
if (ret)
return ret;
ret = tcphy_get_param(dev, &cfg->usb3tousb2_en,
"rockchip,usb3tousb2-en");
if (ret)
return ret;
ret = tcphy_get_param(dev, &cfg->external_psm,
"rockchip,external-psm");
if (ret)
return ret;
ret = tcphy_get_param(dev, &cfg->pipe_status,
"rockchip,pipe-status");
if (ret)
return ret;
tcphy->grf_regs = syscon_regmap_lookup_by_phandle(dev->of_node, tcphy->grf_regs = syscon_regmap_lookup_by_phandle(dev->of_node,
"rockchip,grf"); "rockchip,grf");
if (IS_ERR(tcphy->grf_regs)) { if (IS_ERR(tcphy->grf_regs)) {
...@@ -1071,7 +1092,7 @@ static int tcphy_parse_dt(struct rockchip_typec_phy *tcphy, ...@@ -1071,7 +1092,7 @@ static int tcphy_parse_dt(struct rockchip_typec_phy *tcphy,
static void typec_phy_pre_init(struct rockchip_typec_phy *tcphy) static void typec_phy_pre_init(struct rockchip_typec_phy *tcphy)
{ {
struct rockchip_usb3phy_port_cfg *cfg = &tcphy->port_cfgs; const struct rockchip_usb3phy_port_cfg *cfg = tcphy->port_cfgs;
reset_control_assert(tcphy->tcphy_rst); reset_control_assert(tcphy->tcphy_rst);
reset_control_assert(tcphy->uphy_rst); reset_control_assert(tcphy->uphy_rst);
...@@ -1092,17 +1113,43 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev) ...@@ -1092,17 +1113,43 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev)
struct rockchip_typec_phy *tcphy; struct rockchip_typec_phy *tcphy;
struct phy_provider *phy_provider; struct phy_provider *phy_provider;
struct resource *res; struct resource *res;
int ret; const struct rockchip_usb3phy_port_cfg *phy_cfgs;
const struct of_device_id *match;
int index, ret;
tcphy = devm_kzalloc(dev, sizeof(*tcphy), GFP_KERNEL); tcphy = devm_kzalloc(dev, sizeof(*tcphy), GFP_KERNEL);
if (!tcphy) if (!tcphy)
return -ENOMEM; return -ENOMEM;
match = of_match_device(dev->driver->of_match_table, dev);
if (!match || !match->data) {
dev_err(dev, "phy configs are not assigned!\n");
return -EINVAL;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
tcphy->base = devm_ioremap_resource(dev, res); tcphy->base = devm_ioremap_resource(dev, res);
if (IS_ERR(tcphy->base)) if (IS_ERR(tcphy->base))
return PTR_ERR(tcphy->base); return PTR_ERR(tcphy->base);
phy_cfgs = match->data;
/* find out a proper config which can be matched with dt. */
index = 0;
while (phy_cfgs[index].reg) {
if (phy_cfgs[index].reg == res->start) {
tcphy->port_cfgs = &phy_cfgs[index];
break;
}
++index;
}
if (!tcphy->port_cfgs) {
dev_err(dev, "no phy-config can be matched with %s node\n",
np->name);
return -EINVAL;
}
ret = tcphy_parse_dt(tcphy, dev); ret = tcphy_parse_dt(tcphy, dev);
if (ret) if (ret)
return ret; return ret;
...@@ -1115,9 +1162,13 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev) ...@@ -1115,9 +1162,13 @@ static int rockchip_typec_phy_probe(struct platform_device *pdev)
tcphy->extcon = extcon_get_edev_by_phandle(dev, 0); tcphy->extcon = extcon_get_edev_by_phandle(dev, 0);
if (IS_ERR(tcphy->extcon)) { if (IS_ERR(tcphy->extcon)) {
if (PTR_ERR(tcphy->extcon) != -EPROBE_DEFER) if (PTR_ERR(tcphy->extcon) == -ENODEV) {
dev_err(dev, "Invalid or missing extcon\n"); tcphy->extcon = NULL;
return PTR_ERR(tcphy->extcon); } else {
if (PTR_ERR(tcphy->extcon) != -EPROBE_DEFER)
dev_err(dev, "Invalid or missing extcon\n");
return PTR_ERR(tcphy->extcon);
}
} }
pm_runtime_enable(dev); pm_runtime_enable(dev);
...@@ -1162,8 +1213,11 @@ static int rockchip_typec_phy_remove(struct platform_device *pdev) ...@@ -1162,8 +1213,11 @@ static int rockchip_typec_phy_remove(struct platform_device *pdev)
} }
static const struct of_device_id rockchip_typec_phy_dt_ids[] = { static const struct of_device_id rockchip_typec_phy_dt_ids[] = {
{ .compatible = "rockchip,rk3399-typec-phy" }, {
{} .compatible = "rockchip,rk3399-typec-phy",
.data = &rk3399_usb3phy_port_cfgs
},
{ /* sentinel */ }
}; };
MODULE_DEVICE_TABLE(of, rockchip_typec_phy_dt_ids); MODULE_DEVICE_TABLE(of, rockchip_typec_phy_dt_ids);
......
...@@ -49,7 +49,7 @@ config PHY_EXYNOS4210_USB2 ...@@ -49,7 +49,7 @@ config PHY_EXYNOS4210_USB2
config PHY_EXYNOS4X12_USB2 config PHY_EXYNOS4X12_USB2
bool bool
depends on PHY_SAMSUNG_USB2 depends on PHY_SAMSUNG_USB2
default SOC_EXYNOS3250 || SOC_EXYNOS4212 || SOC_EXYNOS4412 default SOC_EXYNOS3250 || SOC_EXYNOS4412
config PHY_EXYNOS5250_USB2 config PHY_EXYNOS5250_USB2
bool bool
......
...@@ -31,3 +31,17 @@ config PHY_STIH407_USB ...@@ -31,3 +31,17 @@ config PHY_STIH407_USB
help help
Enable this support to enable the picoPHY device used by USB2 Enable this support to enable the picoPHY device used by USB2
and USB3 controllers on STMicroelectronics STiH407 SoC families. and USB3 controllers on STMicroelectronics STiH407 SoC families.
config PHY_STM32_USBPHYC
tristate "STMicroelectronics STM32 USB HS PHY Controller driver"
depends on ARCH_STM32 || COMPILE_TEST
select GENERIC_PHY
help
Enable this to support the High-Speed USB transceivers that are part
of some STMicroelectronics STM32 SoCs.
This driver controls the entire USB PHY block: the USB PHY controller
(USBPHYC) and the two 8-bit wide UTMI+ interfaces. First interface is
used by an HS USB Host controller, and the second one is shared
between an HS USB OTG controller and an HS USB Host controller,
selected by a USB switch.
...@@ -2,3 +2,4 @@ obj-$(CONFIG_PHY_MIPHY28LP) += phy-miphy28lp.o ...@@ -2,3 +2,4 @@ obj-$(CONFIG_PHY_MIPHY28LP) += phy-miphy28lp.o
obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY) += phy-spear1310-miphy.o obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY) += phy-spear1310-miphy.o
obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY) += phy-spear1340-miphy.o obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY) += phy-spear1340-miphy.o
obj-$(CONFIG_PHY_STIH407_USB) += phy-stih407-usb.o obj-$(CONFIG_PHY_STIH407_USB) += phy-stih407-usb.o
obj-$(CONFIG_PHY_STM32_USBPHYC) += phy-stm32-usbphyc.o
This diff is collapsed.
...@@ -169,6 +169,7 @@ ...@@ -169,6 +169,7 @@
#define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_EN (1 << 0) #define XUSB_PADCTL_UPHY_PLL_CTL2_CAL_EN (1 << 0)
#define XUSB_PADCTL_UPHY_PLL_P0_CTL4 0x36c #define XUSB_PADCTL_UPHY_PLL_P0_CTL4 0x36c
#define XUSB_PADCTL_UPHY_PLL_CTL4_XDIGCLK_EN (1 << 19)
#define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_EN (1 << 15) #define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_EN (1 << 15)
#define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT 12 #define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT 12
#define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_MASK 0x3 #define XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_MASK 0x3
...@@ -537,11 +538,8 @@ static int tegra210_sata_uphy_enable(struct tegra_xusb_padctl *padctl, bool usb) ...@@ -537,11 +538,8 @@ static int tegra210_sata_uphy_enable(struct tegra_xusb_padctl *padctl, bool usb)
value |= (XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SATA_VAL << value |= (XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SATA_VAL <<
XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT); XUSB_PADCTL_UPHY_PLL_CTL4_TXCLKREF_SEL_SHIFT);
/* XXX PLL0_XDIGCLK_EN */ value &= ~XUSB_PADCTL_UPHY_PLL_CTL4_XDIGCLK_EN;
/*
value &= ~(1 << 19);
padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL4); padctl_writel(padctl, value, XUSB_PADCTL_UPHY_PLL_S0_CTL4);
*/
value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1); value = padctl_readl(padctl, XUSB_PADCTL_UPHY_PLL_S0_CTL1);
value &= ~((XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_MASK << value &= ~((XUSB_PADCTL_UPHY_PLL_CTL1_FREQ_MDIV_MASK <<
......
...@@ -418,7 +418,7 @@ tegra_xusb_port_find_lane(struct tegra_xusb_port *port, ...@@ -418,7 +418,7 @@ tegra_xusb_port_find_lane(struct tegra_xusb_port *port,
{ {
struct tegra_xusb_lane *lane, *match = ERR_PTR(-ENODEV); struct tegra_xusb_lane *lane, *match = ERR_PTR(-ENODEV);
for (map = map; map->type; map++) { for (; map->type; map++) {
if (port->index != map->port) if (port->index != map->port)
continue; continue;
......
...@@ -25,7 +25,15 @@ struct phy; ...@@ -25,7 +25,15 @@ struct phy;
enum phy_mode { enum phy_mode {
PHY_MODE_INVALID, PHY_MODE_INVALID,
PHY_MODE_USB_HOST, PHY_MODE_USB_HOST,
PHY_MODE_USB_HOST_LS,
PHY_MODE_USB_HOST_FS,
PHY_MODE_USB_HOST_HS,
PHY_MODE_USB_HOST_SS,
PHY_MODE_USB_DEVICE, PHY_MODE_USB_DEVICE,
PHY_MODE_USB_DEVICE_LS,
PHY_MODE_USB_DEVICE_FS,
PHY_MODE_USB_DEVICE_HS,
PHY_MODE_USB_DEVICE_SS,
PHY_MODE_USB_OTG, PHY_MODE_USB_OTG,
PHY_MODE_SGMII, PHY_MODE_SGMII,
PHY_MODE_10GKR, PHY_MODE_10GKR,
...@@ -61,6 +69,7 @@ struct phy_ops { ...@@ -61,6 +69,7 @@ struct phy_ops {
*/ */
struct phy_attrs { struct phy_attrs {
u32 bus_width; u32 bus_width;
enum phy_mode mode;
}; };
/** /**
...@@ -72,7 +81,8 @@ struct phy_attrs { ...@@ -72,7 +81,8 @@ struct phy_attrs {
* @mutex: mutex to protect phy_ops * @mutex: mutex to protect phy_ops
* @init_count: used to protect when the PHY is used by multiple consumers * @init_count: used to protect when the PHY is used by multiple consumers
* @power_count: used to protect when the PHY is used by multiple consumers * @power_count: used to protect when the PHY is used by multiple consumers
* @phy_attrs: used to specify PHY specific attributes * @attrs: used to specify PHY specific attributes
* @pwr: power regulator associated with the phy
*/ */
struct phy { struct phy {
struct device dev; struct device dev;
...@@ -88,9 +98,10 @@ struct phy { ...@@ -88,9 +98,10 @@ struct phy {
/** /**
* struct phy_provider - represents the phy provider * struct phy_provider - represents the phy provider
* @dev: phy provider device * @dev: phy provider device
* @children: can be used to override the default (dev->of_node) child node
* @owner: the module owner having of_xlate * @owner: the module owner having of_xlate
* @of_xlate: function pointer to obtain phy instance from phy pointer
* @list: to maintain a linked list of PHY providers * @list: to maintain a linked list of PHY providers
* @of_xlate: function pointer to obtain phy instance from phy pointer
*/ */
struct phy_provider { struct phy_provider {
struct device *dev; struct device *dev;
...@@ -101,6 +112,13 @@ struct phy_provider { ...@@ -101,6 +112,13 @@ struct phy_provider {
struct of_phandle_args *args); struct of_phandle_args *args);
}; };
/**
* struct phy_lookup - PHY association in list of phys managed by the phy driver
* @node: list node
* @dev_id: the device of the association
* @con_id: connection ID string on device
* @phy: the phy of the association
*/
struct phy_lookup { struct phy_lookup {
struct list_head node; struct list_head node;
const char *dev_id; const char *dev_id;
...@@ -144,6 +162,10 @@ int phy_exit(struct phy *phy); ...@@ -144,6 +162,10 @@ int phy_exit(struct phy *phy);
int phy_power_on(struct phy *phy); int phy_power_on(struct phy *phy);
int phy_power_off(struct phy *phy); int phy_power_off(struct phy *phy);
int phy_set_mode(struct phy *phy, enum phy_mode mode); int phy_set_mode(struct phy *phy, enum phy_mode mode);
static inline enum phy_mode phy_get_mode(struct phy *phy)
{
return phy->attrs.mode;
}
int phy_reset(struct phy *phy); int phy_reset(struct phy *phy);
int phy_calibrate(struct phy *phy); int phy_calibrate(struct phy *phy);
static inline int phy_get_bus_width(struct phy *phy) static inline int phy_get_bus_width(struct phy *phy)
...@@ -260,6 +282,11 @@ static inline int phy_set_mode(struct phy *phy, enum phy_mode mode) ...@@ -260,6 +282,11 @@ static inline int phy_set_mode(struct phy *phy, enum phy_mode mode)
return -ENOSYS; return -ENOSYS;
} }
static inline enum phy_mode phy_get_mode(struct phy *phy)
{
return PHY_MODE_INVALID;
}
static inline int phy_reset(struct phy *phy) static inline int phy_reset(struct phy *phy)
{ {
if (!phy) if (!phy)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment