diff --git a/Documentation/devicetree/bindings/phy/bcm-ns-usb3-phy.txt b/Documentation/devicetree/bindings/phy/bcm-ns-usb3-phy.txt index 09aeba94538d..32f057260351 100644 --- a/Documentation/devicetree/bindings/phy/bcm-ns-usb3-phy.txt +++ b/Documentation/devicetree/bindings/phy/bcm-ns-usb3-phy.txt @@ -3,9 +3,10 @@ Driver for Broadcom Northstar USB 3.0 PHY Required properties: - compatible: one of: "brcm,ns-ax-usb3-phy", "brcm,ns-bx-usb3-phy". -- reg: register mappings for DMP (Device Management Plugin) and ChipCommon B - MMI. -- reg-names: "dmp" and "ccb-mii" +- reg: address of MDIO bus device +- usb3-dmp-syscon: phandle to syscon with DMP (Device Management Plugin) + registers +- #phy-cells: must be 0 Initialization of USB 3.0 PHY depends on Northstar version. There are currently three known series: Ax, Bx and Cx. @@ -15,9 +16,19 @@ Known B1: BCM4707 rev 6 Known C0: BCM47094 rev 0 Example: - usb3-phy { - compatible = "brcm,ns-ax-usb3-phy"; - reg = <0x18105000 0x1000>, <0x18003000 0x1000>; - reg-names = "dmp", "ccb-mii"; - #phy-cells = <0>; + mdio: mdio@0 { + reg = <0x0>; + #size-cells = <1>; + #address-cells = <0>; + + usb3-phy@10 { + compatible = "brcm,ns-ax-usb3-phy"; + reg = <0x10>; + usb3-dmp-syscon = <&usb3_dmp>; + #phy-cells = <0>; + }; + }; + + usb3_dmp: syscon@18105000 { + reg = <0x18105000 0x1000>; }; diff --git a/Documentation/devicetree/bindings/phy/brcm,ns2-drd-phy.txt b/Documentation/devicetree/bindings/phy/brcm,ns2-drd-phy.txt new file mode 100644 index 000000000000..04f063aa7883 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/brcm,ns2-drd-phy.txt @@ -0,0 +1,30 @@ +BROADCOM NORTHSTAR2 USB2 (DUAL ROLE DEVICE) PHY + +Required properties: + - compatible: brcm,ns2-drd-phy + - reg: offset and length of the NS2 PHY related registers. + - reg-names + The below registers must be provided. + icfg - for DRD ICFG configurations + rst-ctrl - for DRD IDM reset + crmu-ctrl - for CRMU core vdd, PHY and PHY PLL reset + usb2-strap - for port over current polarity reversal + - #phy-cells: Must be 0. No args required. + - vbus-gpios: vbus gpio binding + - id-gpios: id gpio binding + +Refer to phy/phy-bindings.txt for the generic PHY binding properties + +Example: + usbdrd_phy: phy@66000960 { + #phy-cells = <0>; + compatible = "brcm,ns2-drd-phy"; + reg = <0x66000960 0x24>, + <0x67012800 0x4>, + <0x6501d148 0x4>, + <0x664d0700 0x4>; + reg-names = "icfg", "rst-ctrl", + "crmu-ctrl", "usb2-strap"; + id-gpios = <&gpio_g 30 0>; + vbus-gpios = <&gpio_g 31 0>; + }; diff --git a/Documentation/devicetree/bindings/phy/brcm-sata-phy.txt b/Documentation/devicetree/bindings/phy/brcm-sata-phy.txt index 6ccce09d8bbf..97977cd29a98 100644 --- a/Documentation/devicetree/bindings/phy/brcm-sata-phy.txt +++ b/Documentation/devicetree/bindings/phy/brcm-sata-phy.txt @@ -7,12 +7,13 @@ Required properties: "brcm,iproc-ns2-sata-phy" "brcm,iproc-nsp-sata-phy" "brcm,phy-sata3" + "brcm,iproc-sr-sata-phy" - address-cells: should be 1 - size-cells: should be 0 - reg: register ranges for the PHY PCB interface - reg-names: should be "phy" and "phy-ctrl" The "phy-ctrl" registers are only required for - "brcm,iproc-ns2-sata-phy". + "brcm,iproc-ns2-sata-phy" and "brcm,iproc-sr-sata-phy". Sub-nodes: Each port's PHY should be represented as a sub-node. @@ -23,8 +24,8 @@ Sub-nodes required properties: Sub-nodes optional properties: - brcm,enable-ssc: use spread spectrum clocking (SSC) on this port - This property is not applicable for "brcm,iproc-ns2-sata-phy" and - "brcm,iproc-nsp-sata-phy". + This property is not applicable for "brcm,iproc-ns2-sata-phy", + "brcm,iproc-nsp-sata-phy" and "brcm,iproc-sr-sata-phy". Example: sata-phy@f0458100 { diff --git a/Documentation/devicetree/bindings/phy/meson-gxl-usb2-phy.txt b/Documentation/devicetree/bindings/phy/meson-gxl-usb2-phy.txt new file mode 100644 index 000000000000..a105494a0fc9 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/meson-gxl-usb2-phy.txt @@ -0,0 +1,17 @@ +* Amlogic Meson GXL and GXM USB2 PHY binding + +Required properties: +- compatible: Should be "amlogic,meson-gxl-usb2-phy" +- reg: The base address and length of the registers +- #phys-cells: must be 0 (see phy-bindings.txt in this directory) + +Optional properties: +- phy-supply: see phy-bindings.txt in this directory + + +Example: + usb2_phy0: phy@78000 { + compatible = "amlogic,meson-gxl-usb2-phy"; + #phy-cells = <0>; + reg = <0x0 0x78000 0x0 0x20>; + }; diff --git a/Documentation/devicetree/bindings/phy/meson8b-usb2-phy.txt b/Documentation/devicetree/bindings/phy/meson8b-usb2-phy.txt index 5fa73b9d20f5..d81d73aea608 100644 --- a/Documentation/devicetree/bindings/phy/meson8b-usb2-phy.txt +++ b/Documentation/devicetree/bindings/phy/meson8b-usb2-phy.txt @@ -1,7 +1,8 @@ -* Amlogic Meson8b and GXBB USB2 PHY +* Amlogic Meson8, Meson8b and GXBB USB2 PHY Required properties: - compatible: Depending on the platform this should be one of: + "amlogic,meson8-usb2-phy" "amlogic,meson8b-usb2-phy" "amlogic,meson-gxbb-usb2-phy" - reg: The base address and length of the registers diff --git a/Documentation/devicetree/bindings/phy/phy-cpcap-usb.txt b/Documentation/devicetree/bindings/phy/phy-cpcap-usb.txt new file mode 100644 index 000000000000..2eb9b2b69037 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/phy-cpcap-usb.txt @@ -0,0 +1,40 @@ +Motorola CPCAP PMIC USB PHY binding + +Required properties: +compatible: Shall be either "motorola,cpcap-usb-phy" or + "motorola,mapphone-cpcap-usb-phy" +#phy-cells: Shall be 0 +interrupts: CPCAP PMIC interrupts used by the USB PHY +interrupt-names: Interrupt names +io-channels: IIO ADC channels used by the USB PHY +io-channel-names: IIO ADC channel names +vusb-supply: Regulator for the PHY + +Optional properties: +pinctrl: Optional alternate pin modes for the PHY +pinctrl-names: Names for optional pin modes +mode-gpios: Optional GPIOs for configuring alternate modes + +Example: +cpcap_usb2_phy: phy { + compatible = "motorola,mapphone-cpcap-usb-phy"; + pinctrl-0 = <&usb_gpio_mux_sel1 &usb_gpio_mux_sel2>; + pinctrl-1 = <&usb_ulpi_pins>; + pinctrl-2 = <&usb_utmi_pins>; + pinctrl-3 = <&uart3_pins>; + pinctrl-names = "default", "ulpi", "utmi", "uart"; + #phy-cells = <0>; + interrupts-extended = < + &cpcap 15 0 &cpcap 14 0 &cpcap 28 0 &cpcap 19 0 + &cpcap 18 0 &cpcap 17 0 &cpcap 16 0 &cpcap 49 0 + &cpcap 48 1 + >; + interrupt-names = + "id_ground", "id_float", "se0conn", "vbusvld", + "sessvld", "sessend", "se1", "dm", "dp"; + mode-gpios = <&gpio2 28 GPIO_ACTIVE_HIGH + &gpio1 0 GPIO_ACTIVE_HIGH>; + io-channels = <&cpcap_adc 2>, <&cpcap_adc 7>; + io-channel-names = "vbus", "id"; + vusb-supply = <&vusb>; +}; diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt index e71a8d23f4a8..84d59b0db8df 100644 --- a/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt @@ -2,6 +2,7 @@ ROCKCHIP USB2.0 PHY WITH INNO IP BLOCK Required properties (phy (parent) node): - compatible : should be one of the listed compatibles: + * "rockchip,rk3228-usb2phy" * "rockchip,rk3328-usb2phy" * "rockchip,rk3366-usb2phy" * "rockchip,rk3399-usb2phy" diff --git a/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb3.txt b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb3.txt new file mode 100644 index 000000000000..f94cea48f6b1 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/rcar-gen3-phy-usb3.txt @@ -0,0 +1,46 @@ +* Renesas R-Car generation 3 USB 3.0 PHY + +This file provides information on what the device node for the R-Car generation +3 USB 3.0 PHY contains. +If you want to enable spread spectrum clock (ssc), you should use USB_EXTAL +instead of USB3_CLK. However, if you don't want to these features, you don't +need this driver. + +Required properties: +- compatible: "renesas,r8a7795-usb3-phy" if the device is a part of an R8A7795 + SoC. + "renesas,r8a7796-usb3-phy" if the device is a part of an R8A7796 + SoC. + "renesas,rcar-gen3-usb3-phy" for a generic R-Car Gen3 compatible + device. + + When compatible with the generic version, nodes must list the + SoC-specific version corresponding to the platform first + followed by the generic version. + +- reg: offset and length of the USB 3.0 PHY register block. +- clocks: A list of phandles and clock-specifier pairs. +- clock-names: Name of the clocks. + - The funcional clock must be "usb3-if". + - The usb3's external clock must be "usb3s_clk". + - The usb2's external clock must be "usb_extal". If you want to use the ssc, + the clock-frequency must not be 0. +- #phy-cells: see phy-bindings.txt in the same directory, must be <0>. + +Optional properties: +- renesas,ssc-range: Enable/disable spread spectrum clock (ssc) by using + the following values as u32: + - 0 (or the property doesn't exist): disable the ssc + - 4980: enable the ssc as -4980 ppm + - 4492: enable the ssc as -4492 ppm + - 4003: enable the ssc as -4003 ppm + +Example (R-Car H3): + + usb-phy@e65ee000 { + compatible = "renesas,r8a7795-usb3-phy", + "renesas,rcar-gen3-usb3-phy"; + reg = <0 0xe65ee000 0 0x90>; + clocks = <&cpg CPG_MOD 328>, <&usb3s0_clk>, <&usb_extal>; + clock-names = "usb3-if", "usb3s_clk", "usb_extal"; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 09b5ab6a8a5c..42c3f0c0afc9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1843,8 +1843,8 @@ F: drivers/i2c/busses/i2c-st.c F: drivers/media/rc/st_rc.c F: drivers/media/platform/sti/c8sectpfe/ F: drivers/mmc/host/sdhci-st.c -F: drivers/phy/phy-miphy28lp.c -F: drivers/phy/phy-stih407-usb.c +F: drivers/phy/st/phy-miphy28lp.c +F: drivers/phy/st/phy-stih407-usb.c F: drivers/pinctrl/pinctrl-st.c F: drivers/remoteproc/st_remoteproc.c F: drivers/remoteproc/st_slim_rproc.c @@ -10831,11 +10831,11 @@ L: linux-iio@vger.kernel.org S: Supported F: drivers/iio/adc/rcar_gyro_adc.c -RENESAS USB2 PHY DRIVER +RENESAS USB PHY DRIVER M: Yoshihiro Shimoda L: linux-renesas-soc@vger.kernel.org S: Maintained -F: drivers/phy/phy-rcar-gen3-usb2.c +F: drivers/phy/renesas/phy-rcar-gen3-usb*.c RESET CONTROLLER FRAMEWORK M: Philipp Zabel @@ -11237,12 +11237,12 @@ L: linux-kernel@vger.kernel.org S: Supported F: Documentation/devicetree/bindings/phy/samsung-phy.txt F: Documentation/phy/samsung-usb2.txt -F: drivers/phy/phy-exynos4210-usb2.c -F: drivers/phy/phy-exynos4x12-usb2.c -F: drivers/phy/phy-exynos5250-usb2.c -F: drivers/phy/phy-s5pv210-usb2.c -F: drivers/phy/phy-samsung-usb2.c -F: drivers/phy/phy-samsung-usb2.h +F: drivers/phy/samsung/phy-exynos4210-usb2.c +F: drivers/phy/samsung/phy-exynos4x12-usb2.c +F: drivers/phy/samsung/phy-exynos5250-usb2.c +F: drivers/phy/samsung/phy-s5pv210-usb2.c +F: drivers/phy/samsung/phy-samsung-usb2.c +F: drivers/phy/samsung/phy-samsung-usb2.h SERIAL DRIVERS M: Greg Kroah-Hartman diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index afaf7b643eeb..c1807d4a0079 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -15,73 +15,6 @@ config GENERIC_PHY phy users can obtain reference to the PHY. All the users of this framework should select this config. -config PHY_BCM_NS_USB2 - tristate "Broadcom Northstar USB 2.0 PHY Driver" - depends on ARCH_BCM_IPROC || COMPILE_TEST - depends on HAS_IOMEM && OF - select GENERIC_PHY - help - Enable this to support Broadcom USB 2.0 PHY connected to the USB - controller on Northstar family. - -config PHY_BCM_NS_USB3 - tristate "Broadcom Northstar USB 3.0 PHY Driver" - depends on ARCH_BCM_IPROC || COMPILE_TEST - depends on HAS_IOMEM && OF - select GENERIC_PHY - help - Enable this to support Broadcom USB 3.0 PHY connected to the USB - controller on Northstar family. - -config PHY_BERLIN_USB - tristate "Marvell Berlin USB PHY Driver" - depends on ARCH_BERLIN && RESET_CONTROLLER && HAS_IOMEM && OF - select GENERIC_PHY - help - Enable this to support the USB PHY on Marvell Berlin SoCs. - -config PHY_BERLIN_SATA - tristate "Marvell Berlin SATA PHY driver" - depends on ARCH_BERLIN && HAS_IOMEM && OF - select GENERIC_PHY - help - Enable this to support the SATA PHY on Marvell Berlin SoCs. - -config ARMADA375_USBCLUSTER_PHY - def_bool y - depends on MACH_ARMADA_375 || COMPILE_TEST - depends on OF && HAS_IOMEM - select GENERIC_PHY - -config PHY_DA8XX_USB - tristate "TI DA8xx USB PHY Driver" - depends on ARCH_DAVINCI_DA8XX - select GENERIC_PHY - select MFD_SYSCON - help - Enable this to support the USB PHY on DA8xx SoCs. - - This driver controls both the USB 1.1 PHY and the USB 2.0 PHY. - -config PHY_DM816X_USB - tristate "TI dm816x USB PHY driver" - depends on ARCH_OMAP2PLUS - depends on USB_SUPPORT - select GENERIC_PHY - select USB_PHY - help - Enable this for dm816x USB to work. - -config PHY_EXYNOS_MIPI_VIDEO - tristate "S5P/EXYNOS SoC series MIPI CSI-2/DSI PHY driver" - depends on HAS_IOMEM - depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST - select GENERIC_PHY - default y if ARCH_S5PV210 || ARCH_EXYNOS - help - Support for MIPI CSI-2 and MIPI DSI DPHY found on Samsung S5P - and EXYNOS SoCs. - config PHY_LPC18XX_USB_OTG tristate "NXP LPC18xx/43xx SoC USB OTG PHY driver" depends on OF && (ARCH_LPC18XX || COMPILE_TEST) @@ -93,146 +26,6 @@ config PHY_LPC18XX_USB_OTG This driver is need for USB0 support on LPC18xx/43xx and takes care of enabling and clock setup. -config PHY_PXA_28NM_HSIC - tristate "Marvell USB HSIC 28nm PHY Driver" - depends on HAS_IOMEM - select GENERIC_PHY - help - Enable this to support Marvell USB HSIC PHY driver for Marvell - SoC. This driver will do the PHY initialization and shutdown. - The PHY driver will be used by Marvell ehci driver. - - To compile this driver as a module, choose M here. - -config PHY_PXA_28NM_USB2 - tristate "Marvell USB 2.0 28nm PHY Driver" - depends on HAS_IOMEM - select GENERIC_PHY - help - Enable this to support Marvell USB 2.0 PHY driver for Marvell - SoC. This driver will do the PHY initialization and shutdown. - The PHY driver will be used by Marvell udc/ehci/otg driver. - - To compile this driver as a module, choose M here. - -config PHY_MVEBU_SATA - def_bool y - depends on ARCH_DOVE || MACH_DOVE || MACH_KIRKWOOD - depends on OF - select GENERIC_PHY - -config PHY_MIPHY28LP - tristate "STMicroelectronics MIPHY28LP PHY driver for STiH407" - depends on ARCH_STI - select GENERIC_PHY - help - Enable this to support the miphy transceiver (for SATA/PCIE/USB3) - that is part of STMicroelectronics STiH407 SoC. - -config PHY_RCAR_GEN2 - tristate "Renesas R-Car generation 2 USB PHY driver" - depends on ARCH_RENESAS - depends on GENERIC_PHY - help - Support for USB PHY found on Renesas R-Car generation 2 SoCs. - -config PHY_RCAR_GEN3_USB2 - tristate "Renesas R-Car generation 3 USB 2.0 PHY driver" - depends on ARCH_RENESAS - depends on EXTCON - select GENERIC_PHY - help - Support for USB 2.0 PHY found on Renesas R-Car generation 3 SoCs. - -config OMAP_CONTROL_PHY - tristate "OMAP CONTROL PHY Driver" - depends on ARCH_OMAP2PLUS || COMPILE_TEST - help - Enable this to add support for the PHY part present in the control - module. This driver has API to power on the USB2 PHY and to write to - the mailbox. The mailbox is present only in omap4 and the register to - power on the USB2 PHY is present in OMAP4 and OMAP5. OMAP5 has an - additional register to power on USB3 PHY/SATA PHY/PCIE PHY - (PIPE3 PHY). - -config OMAP_USB2 - tristate "OMAP USB2 PHY Driver" - depends on ARCH_OMAP2PLUS - depends on USB_SUPPORT - select GENERIC_PHY - select USB_PHY - select OMAP_CONTROL_PHY - depends on OMAP_OCP2SCP - help - Enable this to support the transceiver that is part of SOC. This - driver takes care of all the PHY functionality apart from comparator. - The USB OTG controller communicates with the comparator using this - driver. - -config TI_PIPE3 - tristate "TI PIPE3 PHY Driver" - depends on ARCH_OMAP2PLUS || COMPILE_TEST - select GENERIC_PHY - select OMAP_CONTROL_PHY - depends on OMAP_OCP2SCP - help - Enable this to support the PIPE3 PHY that is part of TI SOCs. This - driver takes care of all the PHY functionality apart from comparator. - This driver interacts with the "OMAP Control PHY Driver" to power - on/off the PHY. - -config TWL4030_USB - tristate "TWL4030 USB Transceiver Driver" - depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS - depends on USB_SUPPORT - depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't 'y' - select GENERIC_PHY - select USB_PHY - help - Enable this to support the USB OTG transceiver on TWL4030 - family chips (including the TWL5030 and TPS659x0 devices). - This transceiver supports high and full speed devices plus, - in host mode, low speed. - -config PHY_EXYNOS_DP_VIDEO - tristate "EXYNOS SoC series Display Port PHY driver" - depends on OF - depends on ARCH_EXYNOS || COMPILE_TEST - default ARCH_EXYNOS - select GENERIC_PHY - help - Support for Display Port PHY found on Samsung EXYNOS SoCs. - -config BCM_KONA_USB2_PHY - tristate "Broadcom Kona USB2 PHY Driver" - depends on HAS_IOMEM - select GENERIC_PHY - help - Enable this to support the Broadcom Kona USB 2.0 PHY. - -config PHY_EXYNOS5250_SATA - tristate "Exynos5250 Sata SerDes/PHY driver" - depends on SOC_EXYNOS5250 - depends on HAS_IOMEM - depends on OF - select GENERIC_PHY - select I2C - select I2C_S3C2410 - select MFD_SYSCON - help - Enable this to support SATA SerDes/Phy found on Samsung's - Exynos5250 based SoCs.This SerDes/Phy supports SATA 1.5 Gb/s, - SATA 3.0 Gb/s, SATA 6.0 Gb/s speeds. It supports one SATA host - port to accept one SATA device. - -config PHY_HIX5HD2_SATA - tristate "HIX5HD2 SATA PHY Driver" - depends on ARCH_HIX5HD2 && OF && HAS_IOMEM - select GENERIC_PHY - select MFD_SYSCON - help - Support for SATA PHY on Hisilicon hix5hd2 Soc. - config PHY_MT65XX_USB3 tristate "Mediatek USB3.0 PHY Driver" depends on ARCH_MEDIATEK && OF @@ -241,104 +34,6 @@ config PHY_MT65XX_USB3 Say 'Y' here to add support for Mediatek USB3.0 PHY driver, it supports multiple usb2.0 and usb3.0 ports. -config PHY_HI6220_USB - tristate "hi6220 USB PHY support" - depends on (ARCH_HISI && ARM64) || COMPILE_TEST - select GENERIC_PHY - select MFD_SYSCON - help - Enable this to support the HISILICON HI6220 USB PHY. - - To compile this driver as a module, choose M here. - -config PHY_SUN4I_USB - tristate "Allwinner sunxi SoC USB PHY driver" - depends on ARCH_SUNXI && HAS_IOMEM && OF - depends on RESET_CONTROLLER - depends on EXTCON - depends on POWER_SUPPLY - depends on USB_SUPPORT - select GENERIC_PHY - select USB_COMMON - help - Enable this to support the transceiver that is part of Allwinner - sunxi SoCs. - - This driver controls the entire USB PHY block, both the USB OTG - parts, as well as the 2 regular USB 2 host PHYs. - -config PHY_SUN9I_USB - tristate "Allwinner sun9i SoC USB PHY driver" - depends on ARCH_SUNXI && HAS_IOMEM && OF - depends on RESET_CONTROLLER - depends on USB_SUPPORT - select USB_COMMON - select GENERIC_PHY - help - Enable this to support the transceiver that is part of Allwinner - sun9i SoCs. - - This driver controls each individual USB 2 host PHY. - -config PHY_SAMSUNG_USB2 - tristate "Samsung USB 2.0 PHY driver" - depends on HAS_IOMEM - depends on USB_EHCI_EXYNOS || USB_OHCI_EXYNOS || USB_DWC2 - select GENERIC_PHY - select MFD_SYSCON - default ARCH_EXYNOS - help - Enable this to support the Samsung USB 2.0 PHY driver for Samsung - SoCs. This driver provides the interface for USB 2.0 PHY. Support - for particular PHYs will be enabled based on the SoC type in addition - to this driver. - -config PHY_S5PV210_USB2 - bool "Support for S5PV210" - depends on PHY_SAMSUNG_USB2 - depends on ARCH_S5PV210 - help - Enable USB PHY support for S5PV210. This option requires that Samsung - USB 2.0 PHY driver is enabled and means that support for this - particular SoC is compiled in the driver. In case of S5PV210 two phys - are available - device and host. - -config PHY_EXYNOS4210_USB2 - bool - depends on PHY_SAMSUNG_USB2 - default CPU_EXYNOS4210 - -config PHY_EXYNOS4X12_USB2 - bool - depends on PHY_SAMSUNG_USB2 - default SOC_EXYNOS3250 || SOC_EXYNOS4212 || SOC_EXYNOS4412 - -config PHY_EXYNOS5250_USB2 - bool - depends on PHY_SAMSUNG_USB2 - default SOC_EXYNOS5250 || SOC_EXYNOS5420 - -config PHY_EXYNOS5_USBDRD - tristate "Exynos5 SoC series USB DRD PHY driver" - depends on ARCH_EXYNOS && OF - depends on HAS_IOMEM - depends on USB_DWC3_EXYNOS - select GENERIC_PHY - select MFD_SYSCON - default y - help - Enable USB DRD PHY support for Exynos 5 SoC series. - This driver provides PHY interface for USB 3.0 DRD controller - present on Exynos5 SoC series. - -config PHY_EXYNOS_PCIE - bool "Exynos PCIe PHY driver" - depends on OF && (ARCH_EXYNOS || COMPILE_TEST) - select GENERIC_PHY - help - Enable PCIe PHY support for Exynos SoC series. - This driver provides PHY interface for Exynos PCIe controller. - config PHY_PISTACHIO_USB tristate "IMG Pistachio USB2.0 PHY driver" depends on MACH_PISTACHIO @@ -346,83 +41,6 @@ config PHY_PISTACHIO_USB help Enable this to support the USB2.0 PHY on the IMG Pistachio SoC. -config PHY_QCOM_APQ8064_SATA - tristate "Qualcomm APQ8064 SATA SerDes/PHY driver" - depends on ARCH_QCOM - depends on HAS_IOMEM - depends on OF - select GENERIC_PHY - -config PHY_QCOM_IPQ806X_SATA - tristate "Qualcomm IPQ806x SATA SerDes/PHY driver" - depends on ARCH_QCOM - depends on HAS_IOMEM - depends on OF - select GENERIC_PHY - -config PHY_ROCKCHIP_USB - tristate "Rockchip USB2 PHY Driver" - depends on ARCH_ROCKCHIP && OF - select GENERIC_PHY - help - Enable this to support the Rockchip USB 2.0 PHY. - -config PHY_ROCKCHIP_INNO_USB2 - tristate "Rockchip INNO USB2PHY Driver" - depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF - depends on COMMON_CLK - depends on EXTCON - depends on USB_SUPPORT - select GENERIC_PHY - select USB_COMMON - help - Support for Rockchip USB2.0 PHY with Innosilicon IP block. - -config PHY_ROCKCHIP_EMMC - tristate "Rockchip EMMC PHY Driver" - depends on ARCH_ROCKCHIP && OF - select GENERIC_PHY - help - Enable this to support the Rockchip EMMC PHY. - -config PHY_ROCKCHIP_DP - tristate "Rockchip Display Port PHY Driver" - depends on ARCH_ROCKCHIP && OF - select GENERIC_PHY - help - Enable this to support the Rockchip Display Port PHY. - -config PHY_ROCKCHIP_PCIE - tristate "Rockchip PCIe PHY Driver" - depends on (ARCH_ROCKCHIP && OF) || COMPILE_TEST - select GENERIC_PHY - select MFD_SYSCON - help - Enable this to support the Rockchip PCIe PHY. - -config PHY_ROCKCHIP_TYPEC - tristate "Rockchip TYPEC PHY Driver" - depends on OF && (ARCH_ROCKCHIP || COMPILE_TEST) - select EXTCON - select GENERIC_PHY - select RESET_CONTROLLER - help - Enable this to support the Rockchip USB TYPEC PHY. - -config PHY_ST_SPEAR1310_MIPHY - tristate "ST SPEAR1310-MIPHY driver" - select GENERIC_PHY - depends on MACH_SPEAR1310 || COMPILE_TEST - help - Support for ST SPEAr1310 MIPHY which can be used for PCIe and SATA. - -config PHY_ST_SPEAR1340_MIPHY - tristate "ST SPEAR1340-MIPHY driver" - select GENERIC_PHY - depends on MACH_SPEAR1340 || COMPILE_TEST - help - Support for ST SPEAr1340 MIPHY which can be used for PCIe and SATA. - config PHY_XGENE tristate "APM X-Gene 15Gbps PHY support" depends on HAS_IOMEM && OF && (ARM64 || COMPILE_TEST) @@ -430,104 +48,18 @@ config PHY_XGENE help This option enables support for APM X-Gene SoC multi-purpose PHY. -config PHY_STIH407_USB - tristate "STMicroelectronics USB2 picoPHY driver for STiH407 family" - depends on RESET_CONTROLLER - depends on ARCH_STI || COMPILE_TEST - select GENERIC_PHY - help - Enable this support to enable the picoPHY device used by USB2 - and USB3 controllers on STMicroelectronics STiH407 SoC families. - -config PHY_QCOM_QMP - tristate "Qualcomm QMP PHY Driver" - depends on OF && COMMON_CLK && (ARCH_QCOM || COMPILE_TEST) - select GENERIC_PHY - help - Enable this to support the QMP PHY transceiver that is used - with controllers such as PCIe, UFS, and USB on Qualcomm chips. - -config PHY_QCOM_QUSB2 - tristate "Qualcomm QUSB2 PHY Driver" - depends on OF && (ARCH_QCOM || COMPILE_TEST) - depends on NVMEM || !NVMEM - select GENERIC_PHY - help - Enable this to support the HighSpeed QUSB2 PHY transceiver for USB - controllers on Qualcomm chips. This driver supports the high-speed - PHY which is usually paired with either the ChipIdea or Synopsys DWC3 - USB IPs on MSM SOCs. - -config PHY_QCOM_UFS - tristate "Qualcomm UFS PHY driver" - depends on OF && ARCH_QCOM - select GENERIC_PHY - help - Support for UFS PHY on QCOM chipsets. - -config PHY_QCOM_USB_HS - tristate "Qualcomm USB HS PHY module" - depends on USB_ULPI_BUS - depends on EXTCON || !EXTCON # if EXTCON=m, this cannot be built-in - select GENERIC_PHY - help - Support for the USB high-speed ULPI compliant phy on Qualcomm - chipsets. - -config PHY_QCOM_USB_HSIC - tristate "Qualcomm USB HSIC ULPI PHY module" - depends on USB_ULPI_BUS - select GENERIC_PHY - help - Support for the USB HSIC ULPI compliant PHY on QCOM chipsets. - -config PHY_TUSB1210 - tristate "TI TUSB1210 ULPI PHY module" - depends on USB_ULPI_BUS - select GENERIC_PHY - help - Support for TI TUSB1210 USB ULPI PHY. - -config PHY_BRCM_SATA - tristate "Broadcom SATA PHY driver" - depends on ARCH_BRCMSTB || ARCH_BCM_IPROC || BMIPS_GENERIC || COMPILE_TEST - depends on OF - select GENERIC_PHY - default ARCH_BCM_IPROC - help - Enable this to support the Broadcom SATA PHY. - If unsure, say N. - -config PHY_CYGNUS_PCIE - tristate "Broadcom Cygnus PCIe PHY driver" - depends on OF && (ARCH_BCM_CYGNUS || COMPILE_TEST) - select GENERIC_PHY - default ARCH_BCM_CYGNUS - help - Enable this to support the Broadcom Cygnus PCIe PHY. - If unsure, say N. - +source "drivers/phy/allwinner/Kconfig" +source "drivers/phy/amlogic/Kconfig" +source "drivers/phy/broadcom/Kconfig" +source "drivers/phy/hisilicon/Kconfig" +source "drivers/phy/marvell/Kconfig" +source "drivers/phy/motorola/Kconfig" +source "drivers/phy/qualcomm/Kconfig" +source "drivers/phy/renesas/Kconfig" +source "drivers/phy/rockchip/Kconfig" +source "drivers/phy/samsung/Kconfig" +source "drivers/phy/st/Kconfig" source "drivers/phy/tegra/Kconfig" - -config PHY_NS2_PCIE - tristate "Broadcom Northstar2 PCIe PHY driver" - depends on OF && MDIO_BUS_MUX_BCM_IPROC - select GENERIC_PHY - default ARCH_BCM_IPROC - help - Enable this to support the Broadcom Northstar2 PCIe PHY. - If unsure, say N. - -config PHY_MESON8B_USB2 - tristate "Meson8b and GXBB USB2 PHY driver" - default ARCH_MESON - depends on OF && (ARCH_MESON || COMPILE_TEST) - depends on USB_SUPPORT - select USB_COMMON - select GENERIC_PHY - help - Enable this to support the Meson USB2 PHYs found in Meson8b - and GXBB SoCs. - If unsure, say N. +source "drivers/phy/ti/Kconfig" endmenu diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index f8047b4639fa..f252201e0ec9 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -3,64 +3,21 @@ # obj-$(CONFIG_GENERIC_PHY) += phy-core.o -obj-$(CONFIG_PHY_BCM_NS_USB2) += phy-bcm-ns-usb2.o -obj-$(CONFIG_PHY_BCM_NS_USB3) += phy-bcm-ns-usb3.o -obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.o -obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.o -obj-$(CONFIG_PHY_DA8XX_USB) += phy-da8xx-usb.o -obj-$(CONFIG_PHY_DM816X_USB) += phy-dm816x-usb.o -obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY) += phy-armada375-usb2.o -obj-$(CONFIG_BCM_KONA_USB2_PHY) += phy-bcm-kona-usb2.o -obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o -obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o obj-$(CONFIG_PHY_LPC18XX_USB_OTG) += phy-lpc18xx-usb-otg.o -obj-$(CONFIG_PHY_PXA_28NM_USB2) += phy-pxa-28nm-usb2.o -obj-$(CONFIG_PHY_PXA_28NM_HSIC) += phy-pxa-28nm-hsic.o -obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o -obj-$(CONFIG_PHY_MIPHY28LP) += phy-miphy28lp.o -obj-$(CONFIG_PHY_RCAR_GEN2) += phy-rcar-gen2.o -obj-$(CONFIG_PHY_RCAR_GEN3_USB2) += phy-rcar-gen3-usb2.o -obj-$(CONFIG_OMAP_CONTROL_PHY) += phy-omap-control.o -obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o -obj-$(CONFIG_TI_PIPE3) += phy-ti-pipe3.o -obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o -obj-$(CONFIG_PHY_EXYNOS5250_SATA) += phy-exynos5250-sata.o -obj-$(CONFIG_PHY_HIX5HD2_SATA) += phy-hix5hd2-sata.o -obj-$(CONFIG_PHY_HI6220_USB) += phy-hi6220-usb.o obj-$(CONFIG_PHY_MT65XX_USB3) += phy-mt65xx-usb3.o -obj-$(CONFIG_PHY_SUN4I_USB) += phy-sun4i-usb.o -obj-$(CONFIG_PHY_SUN9I_USB) += phy-sun9i-usb.o -obj-$(CONFIG_PHY_SAMSUNG_USB2) += phy-exynos-usb2.o -phy-exynos-usb2-y += phy-samsung-usb2.o -phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4210_USB2) += phy-exynos4210-usb2.o -phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4X12_USB2) += phy-exynos4x12-usb2.o -phy-exynos-usb2-$(CONFIG_PHY_EXYNOS5250_USB2) += phy-exynos5250-usb2.o -phy-exynos-usb2-$(CONFIG_PHY_S5PV210_USB2) += phy-s5pv210-usb2.o -obj-$(CONFIG_PHY_EXYNOS5_USBDRD) += phy-exynos5-usbdrd.o -obj-$(CONFIG_PHY_EXYNOS_PCIE) += phy-exynos-pcie.o -obj-$(CONFIG_PHY_QCOM_APQ8064_SATA) += phy-qcom-apq8064-sata.o -obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o -obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2) += phy-rockchip-inno-usb2.o -obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o -obj-$(CONFIG_PHY_ROCKCHIP_PCIE) += phy-rockchip-pcie.o -obj-$(CONFIG_PHY_ROCKCHIP_DP) += phy-rockchip-dp.o -obj-$(CONFIG_PHY_ROCKCHIP_TYPEC) += phy-rockchip-typec.o -obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o -obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY) += phy-spear1310-miphy.o -obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY) += phy-spear1340-miphy.o obj-$(CONFIG_PHY_XGENE) += phy-xgene.o -obj-$(CONFIG_PHY_STIH407_USB) += phy-stih407-usb.o -obj-$(CONFIG_PHY_QCOM_QMP) += phy-qcom-qmp.o -obj-$(CONFIG_PHY_QCOM_QUSB2) += phy-qcom-qusb2.o -obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o -obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o -obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o -obj-$(CONFIG_PHY_QCOM_USB_HS) += phy-qcom-usb-hs.o -obj-$(CONFIG_PHY_QCOM_USB_HSIC) += phy-qcom-usb-hsic.o -obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o -obj-$(CONFIG_PHY_BRCM_SATA) += phy-brcm-sata.o obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o -obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o -obj-$(CONFIG_ARCH_TEGRA) += tegra/ -obj-$(CONFIG_PHY_NS2_PCIE) += phy-bcm-ns2-pcie.o -obj-$(CONFIG_PHY_MESON8B_USB2) += phy-meson8b-usb2.o + +obj-$(CONFIG_ARCH_SUNXI) += allwinner/ +obj-$(CONFIG_ARCH_MESON) += amlogic/ +obj-$(CONFIG_ARCH_RENESAS) += renesas/ +obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ +obj-$(CONFIG_ARCH_TEGRA) += tegra/ +obj-y += broadcom/ \ + hisilicon/ \ + marvell/ \ + motorola/ \ + qualcomm/ \ + samsung/ \ + st/ \ + ti/ diff --git a/drivers/phy/allwinner/Kconfig b/drivers/phy/allwinner/Kconfig new file mode 100644 index 000000000000..cdc1e745ba47 --- /dev/null +++ b/drivers/phy/allwinner/Kconfig @@ -0,0 +1,31 @@ +# +# Phy drivers for Allwinner platforms +# +config PHY_SUN4I_USB + tristate "Allwinner sunxi SoC USB PHY driver" + depends on ARCH_SUNXI && HAS_IOMEM && OF + depends on RESET_CONTROLLER + depends on EXTCON + depends on POWER_SUPPLY + depends on USB_SUPPORT + select GENERIC_PHY + select USB_COMMON + help + Enable this to support the transceiver that is part of Allwinner + sunxi SoCs. + + This driver controls the entire USB PHY block, both the USB OTG + parts, as well as the 2 regular USB 2 host PHYs. + +config PHY_SUN9I_USB + tristate "Allwinner sun9i SoC USB PHY driver" + depends on ARCH_SUNXI && HAS_IOMEM && OF + depends on RESET_CONTROLLER + depends on USB_SUPPORT + select USB_COMMON + select GENERIC_PHY + help + Enable this to support the transceiver that is part of Allwinner + sun9i SoCs. + + This driver controls each individual USB 2 host PHY. diff --git a/drivers/phy/allwinner/Makefile b/drivers/phy/allwinner/Makefile new file mode 100644 index 000000000000..8605529c01a1 --- /dev/null +++ b/drivers/phy/allwinner/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_PHY_SUN4I_USB) += phy-sun4i-usb.o +obj-$(CONFIG_PHY_SUN9I_USB) += phy-sun9i-usb.o diff --git a/drivers/phy/phy-sun4i-usb.c b/drivers/phy/allwinner/phy-sun4i-usb.c similarity index 100% rename from drivers/phy/phy-sun4i-usb.c rename to drivers/phy/allwinner/phy-sun4i-usb.c diff --git a/drivers/phy/phy-sun9i-usb.c b/drivers/phy/allwinner/phy-sun9i-usb.c similarity index 100% rename from drivers/phy/phy-sun9i-usb.c rename to drivers/phy/allwinner/phy-sun9i-usb.c diff --git a/drivers/phy/amlogic/Kconfig b/drivers/phy/amlogic/Kconfig new file mode 100644 index 000000000000..cb8f4501652b --- /dev/null +++ b/drivers/phy/amlogic/Kconfig @@ -0,0 +1,27 @@ +# +# Phy drivers for Amlogic platforms +# +config PHY_MESON8B_USB2 + tristate "Meson8, Meson8b and GXBB USB2 PHY driver" + default ARCH_MESON + depends on OF && (ARCH_MESON || COMPILE_TEST) + depends on USB_SUPPORT + select USB_COMMON + select GENERIC_PHY + help + Enable this to support the Meson USB2 PHYs found in Meson8, + Meson8b and GXBB SoCs. + If unsure, say N. + +config PHY_MESON_GXL_USB2 + tristate "Meson GXL and GXM USB2 PHY drivers" + default ARCH_MESON + depends on OF && (ARCH_MESON || COMPILE_TEST) + depends on USB_SUPPORT + select USB_COMMON + select GENERIC_PHY + select REGMAP_MMIO + help + Enable this to support the Meson USB2 PHYs found in Meson + GXL and GXM SoCs. + If unsure, say N. diff --git a/drivers/phy/amlogic/Makefile b/drivers/phy/amlogic/Makefile new file mode 100644 index 000000000000..cfdc98715c30 --- /dev/null +++ b/drivers/phy/amlogic/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_PHY_MESON8B_USB2) += phy-meson8b-usb2.o +obj-$(CONFIG_PHY_MESON_GXL_USB2) += phy-meson-gxl-usb2.o diff --git a/drivers/phy/amlogic/phy-meson-gxl-usb2.c b/drivers/phy/amlogic/phy-meson-gxl-usb2.c new file mode 100644 index 000000000000..e90c4ee25dfe --- /dev/null +++ b/drivers/phy/amlogic/phy-meson-gxl-usb2.c @@ -0,0 +1,273 @@ +/* + * Meson GXL and GXM USB2 PHY driver + * + * Copyright (C) 2017 Martin Blumenstingl + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* bits [31:27] are read-only */ +#define U2P_R0 0x0 + #define U2P_R0_BYPASS_SEL BIT(0) + #define U2P_R0_BYPASS_DM_EN BIT(1) + #define U2P_R0_BYPASS_DP_EN BIT(2) + #define U2P_R0_TXBITSTUFF_ENH BIT(3) + #define U2P_R0_TXBITSTUFF_EN BIT(4) + #define U2P_R0_DM_PULLDOWN BIT(5) + #define U2P_R0_DP_PULLDOWN BIT(6) + #define U2P_R0_DP_VBUS_VLD_EXT_SEL BIT(7) + #define U2P_R0_DP_VBUS_VLD_EXT BIT(8) + #define U2P_R0_ADP_PRB_EN BIT(9) + #define U2P_R0_ADP_DISCHARGE BIT(10) + #define U2P_R0_ADP_CHARGE BIT(11) + #define U2P_R0_DRV_VBUS BIT(12) + #define U2P_R0_ID_PULLUP BIT(13) + #define U2P_R0_LOOPBACK_EN_B BIT(14) + #define U2P_R0_OTG_DISABLE BIT(15) + #define U2P_R0_COMMON_ONN BIT(16) + #define U2P_R0_FSEL_MASK GENMASK(19, 17) + #define U2P_R0_REF_CLK_SEL_MASK GENMASK(21, 20) + #define U2P_R0_POWER_ON_RESET BIT(22) + #define U2P_R0_V_ATE_TEST_EN_B_MASK GENMASK(24, 23) + #define U2P_R0_ID_SET_ID_DQ BIT(25) + #define U2P_R0_ATE_RESET BIT(26) + #define U2P_R0_FSV_MINUS BIT(27) + #define U2P_R0_FSV_PLUS BIT(28) + #define U2P_R0_BYPASS_DM_DATA BIT(29) + #define U2P_R0_BYPASS_DP_DATA BIT(30) + +#define U2P_R1 0x4 + #define U2P_R1_BURN_IN_TEST BIT(0) + #define U2P_R1_ACA_ENABLE BIT(1) + #define U2P_R1_DCD_ENABLE BIT(2) + #define U2P_R1_VDAT_SRC_EN_B BIT(3) + #define U2P_R1_VDAT_DET_EN_B BIT(4) + #define U2P_R1_CHARGES_SEL BIT(5) + #define U2P_R1_TX_PREEMP_PULSE_TUNE BIT(6) + #define U2P_R1_TX_PREEMP_AMP_TUNE_MASK GENMASK(8, 7) + #define U2P_R1_TX_RES_TUNE_MASK GENMASK(10, 9) + #define U2P_R1_TX_RISE_TUNE_MASK GENMASK(12, 11) + #define U2P_R1_TX_VREF_TUNE_MASK GENMASK(16, 13) + #define U2P_R1_TX_FSLS_TUNE_MASK GENMASK(20, 17) + #define U2P_R1_TX_HSXV_TUNE_MASK GENMASK(22, 21) + #define U2P_R1_OTG_TUNE_MASK GENMASK(25, 23) + #define U2P_R1_SQRX_TUNE_MASK GENMASK(28, 26) + #define U2P_R1_COMP_DIS_TUNE_MASK GENMASK(31, 29) + +/* bits [31:14] are read-only */ +#define U2P_R2 0x8 + #define U2P_R2_DATA_IN_MASK GENMASK(3, 0) + #define U2P_R2_DATA_IN_EN_MASK GENMASK(7, 4) + #define U2P_R2_ADDR_MASK GENMASK(11, 8) + #define U2P_R2_DATA_OUT_SEL BIT(12) + #define U2P_R2_CLK BIT(13) + #define U2P_R2_DATA_OUT_MASK GENMASK(17, 14) + #define U2P_R2_ACA_PIN_RANGE_C BIT(18) + #define U2P_R2_ACA_PIN_RANGE_B BIT(19) + #define U2P_R2_ACA_PIN_RANGE_A BIT(20) + #define U2P_R2_ACA_PIN_GND BIT(21) + #define U2P_R2_ACA_PIN_FLOAT BIT(22) + #define U2P_R2_CHARGE_DETECT BIT(23) + #define U2P_R2_DEVICE_SESSION_VALID BIT(24) + #define U2P_R2_ADP_PROBE BIT(25) + #define U2P_R2_ADP_SENSE BIT(26) + #define U2P_R2_SESSION_END BIT(27) + #define U2P_R2_VBUS_VALID BIT(28) + #define U2P_R2_B_VALID BIT(29) + #define U2P_R2_A_VALID BIT(30) + #define U2P_R2_ID_DIG BIT(31) + +#define U2P_R3 0xc + +#define RESET_COMPLETE_TIME 500 + +struct phy_meson_gxl_usb2_priv { + struct regmap *regmap; + enum phy_mode mode; + int is_enabled; +}; + +static const struct regmap_config phy_meson_gxl_usb2_regmap_conf = { + .reg_bits = 8, + .val_bits = 32, + .reg_stride = 4, + .max_register = U2P_R3, +}; + +static int phy_meson_gxl_usb2_reset(struct phy *phy) +{ + struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy); + + if (priv->is_enabled) { + /* reset the PHY and wait until settings are stabilized */ + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_POWER_ON_RESET, + U2P_R0_POWER_ON_RESET); + udelay(RESET_COMPLETE_TIME); + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_POWER_ON_RESET, + 0); + udelay(RESET_COMPLETE_TIME); + } + + return 0; +} + +static int phy_meson_gxl_usb2_set_mode(struct phy *phy, enum phy_mode mode) +{ + struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy); + + switch (mode) { + case PHY_MODE_USB_HOST: + case PHY_MODE_USB_OTG: + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_DM_PULLDOWN, + U2P_R0_DM_PULLDOWN); + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_DP_PULLDOWN, + U2P_R0_DP_PULLDOWN); + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_ID_PULLUP, 0); + break; + + case PHY_MODE_USB_DEVICE: + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_DM_PULLDOWN, + 0); + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_DP_PULLDOWN, + 0); + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_ID_PULLUP, + U2P_R0_ID_PULLUP); + break; + + default: + return -EINVAL; + } + + phy_meson_gxl_usb2_reset(phy); + + priv->mode = mode; + + return 0; +} + +static int phy_meson_gxl_usb2_power_off(struct phy *phy) +{ + struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy); + + priv->is_enabled = 0; + + /* power off the PHY by putting it into reset mode */ + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_POWER_ON_RESET, + U2P_R0_POWER_ON_RESET); + + return 0; +} + +static int phy_meson_gxl_usb2_power_on(struct phy *phy) +{ + struct phy_meson_gxl_usb2_priv *priv = phy_get_drvdata(phy); + int ret; + + priv->is_enabled = 1; + + /* power on the PHY by taking it out of reset mode */ + regmap_update_bits(priv->regmap, U2P_R0, U2P_R0_POWER_ON_RESET, 0); + + ret = phy_meson_gxl_usb2_set_mode(phy, priv->mode); + if (ret) { + phy_meson_gxl_usb2_power_off(phy); + + dev_err(&phy->dev, "Failed to initialize PHY with mode %d\n", + priv->mode); + return ret; + } + + return 0; +} + +static const struct phy_ops phy_meson_gxl_usb2_ops = { + .power_on = phy_meson_gxl_usb2_power_on, + .power_off = phy_meson_gxl_usb2_power_off, + .set_mode = phy_meson_gxl_usb2_set_mode, + .reset = phy_meson_gxl_usb2_reset, + .owner = THIS_MODULE, +}; + +static int phy_meson_gxl_usb2_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct phy_provider *phy_provider; + struct resource *res; + struct phy_meson_gxl_usb2_priv *priv; + struct phy *phy; + void __iomem *base; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + platform_set_drvdata(pdev, priv); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + switch (of_usb_get_dr_mode_by_phy(dev->of_node, -1)) { + case USB_DR_MODE_PERIPHERAL: + 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, + &phy_meson_gxl_usb2_regmap_conf); + if (IS_ERR(priv->regmap)) + return PTR_ERR(priv->regmap); + + phy = devm_phy_create(dev, NULL, &phy_meson_gxl_usb2_ops); + if (IS_ERR(phy)) { + dev_err(dev, "failed to create PHY\n"); + return PTR_ERR(phy); + } + + 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_usb2_of_match[] = { + { .compatible = "amlogic,meson-gxl-usb2-phy", }, + { }, +}; +MODULE_DEVICE_TABLE(of, phy_meson_gxl_usb2_of_match); + +static struct platform_driver phy_meson_gxl_usb2_driver = { + .probe = phy_meson_gxl_usb2_probe, + .driver = { + .name = "phy-meson-gxl-usb2", + .of_match_table = phy_meson_gxl_usb2_of_match, + }, +}; +module_platform_driver(phy_meson_gxl_usb2_driver); + +MODULE_AUTHOR("Martin Blumenstingl "); +MODULE_DESCRIPTION("Meson GXL and GXM USB2 PHY driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/phy-meson8b-usb2.c b/drivers/phy/amlogic/phy-meson8b-usb2.c similarity index 98% rename from drivers/phy/phy-meson8b-usb2.c rename to drivers/phy/amlogic/phy-meson8b-usb2.c index 30f56a6a411f..9c01b7e19b06 100644 --- a/drivers/phy/phy-meson8b-usb2.c +++ b/drivers/phy/amlogic/phy-meson8b-usb2.c @@ -1,5 +1,5 @@ /* - * Meson8b and GXBB USB2 PHY driver + * Meson8, Meson8b and GXBB USB2 PHY driver * * Copyright (C) 2016 Martin Blumenstingl * @@ -266,6 +266,7 @@ static int phy_meson8b_usb2_probe(struct platform_device *pdev) } static const struct of_device_id phy_meson8b_usb2_of_match[] = { + { .compatible = "amlogic,meson8-usb2-phy", }, { .compatible = "amlogic,meson8b-usb2-phy", }, { .compatible = "amlogic,meson-gxbb-usb2-phy", }, { }, @@ -282,5 +283,5 @@ static struct platform_driver phy_meson8b_usb2_driver = { module_platform_driver(phy_meson8b_usb2_driver); MODULE_AUTHOR("Martin Blumenstingl "); -MODULE_DESCRIPTION("Meson8b and GXBB USB2 PHY driver"); +MODULE_DESCRIPTION("Meson8, Meson8b and GXBB USB2 PHY driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/phy/broadcom/Kconfig b/drivers/phy/broadcom/Kconfig new file mode 100644 index 000000000000..37371b89b14f --- /dev/null +++ b/drivers/phy/broadcom/Kconfig @@ -0,0 +1,69 @@ +# +# Phy drivers for Broadcom platforms +# +config PHY_CYGNUS_PCIE + tristate "Broadcom Cygnus PCIe PHY driver" + depends on OF && (ARCH_BCM_CYGNUS || COMPILE_TEST) + select GENERIC_PHY + default ARCH_BCM_CYGNUS + help + Enable this to support the Broadcom Cygnus PCIe PHY. + If unsure, say N. + +config BCM_KONA_USB2_PHY + tristate "Broadcom Kona USB2 PHY Driver" + depends on HAS_IOMEM + select GENERIC_PHY + help + Enable this to support the Broadcom Kona USB 2.0 PHY. + +config PHY_BCM_NS_USB2 + tristate "Broadcom Northstar USB 2.0 PHY Driver" + depends on ARCH_BCM_IPROC || COMPILE_TEST + depends on HAS_IOMEM && OF + select GENERIC_PHY + help + Enable this to support Broadcom USB 2.0 PHY connected to the USB + controller on Northstar family. + +config PHY_BCM_NS_USB3 + tristate "Broadcom Northstar USB 3.0 PHY Driver" + depends on ARCH_BCM_IPROC || COMPILE_TEST + depends on HAS_IOMEM && OF + select GENERIC_PHY + select MDIO_DEVICE + help + Enable this to support Broadcom USB 3.0 PHY connected to the USB + controller on Northstar family. + +config PHY_NS2_PCIE + tristate "Broadcom Northstar2 PCIe PHY driver" + depends on OF && MDIO_BUS_MUX_BCM_IPROC + select GENERIC_PHY + default ARCH_BCM_IPROC + help + Enable this to support the Broadcom Northstar2 PCIe PHY. + If unsure, say N. + +config PHY_NS2_USB_DRD + tristate "Broadcom Northstar2 USB DRD PHY support" + depends on OF && (ARCH_BCM_IPROC || COMPILE_TEST) + select GENERIC_PHY + select EXTCON + default ARCH_BCM_IPROC + help + Enable this to support the Broadcom Northstar2 USB DRD PHY. + This driver initializes the PHY in either HOST or DEVICE mode. + The host or device configuration is read from device tree. + + If unsure, say N. + +config PHY_BRCM_SATA + tristate "Broadcom SATA PHY driver" + depends on ARCH_BRCMSTB || ARCH_BCM_IPROC || BMIPS_GENERIC || COMPILE_TEST + depends on OF + select GENERIC_PHY + default ARCH_BCM_IPROC + help + Enable this to support the Broadcom SATA PHY. + If unsure, say N. diff --git a/drivers/phy/broadcom/Makefile b/drivers/phy/broadcom/Makefile new file mode 100644 index 000000000000..4eb82ec8d491 --- /dev/null +++ b/drivers/phy/broadcom/Makefile @@ -0,0 +1,7 @@ +obj-$(CONFIG_PHY_CYGNUS_PCIE) += phy-bcm-cygnus-pcie.o +obj-$(CONFIG_BCM_KONA_USB2_PHY) += phy-bcm-kona-usb2.o +obj-$(CONFIG_PHY_BCM_NS_USB2) += phy-bcm-ns-usb2.o +obj-$(CONFIG_PHY_BCM_NS_USB3) += phy-bcm-ns-usb3.o +obj-$(CONFIG_PHY_NS2_PCIE) += phy-bcm-ns2-pcie.o +obj-$(CONFIG_PHY_NS2_USB_DRD) += phy-bcm-ns2-usbdrd.o +obj-$(CONFIG_PHY_BRCM_SATA) += phy-brcm-sata.o diff --git a/drivers/phy/phy-bcm-cygnus-pcie.c b/drivers/phy/broadcom/phy-bcm-cygnus-pcie.c similarity index 100% rename from drivers/phy/phy-bcm-cygnus-pcie.c rename to drivers/phy/broadcom/phy-bcm-cygnus-pcie.c diff --git a/drivers/phy/phy-bcm-kona-usb2.c b/drivers/phy/broadcom/phy-bcm-kona-usb2.c similarity index 100% rename from drivers/phy/phy-bcm-kona-usb2.c rename to drivers/phy/broadcom/phy-bcm-kona-usb2.c diff --git a/drivers/phy/phy-bcm-ns-usb2.c b/drivers/phy/broadcom/phy-bcm-ns-usb2.c similarity index 100% rename from drivers/phy/phy-bcm-ns-usb2.c rename to drivers/phy/broadcom/phy-bcm-ns-usb2.c diff --git a/drivers/phy/phy-bcm-ns-usb3.c b/drivers/phy/broadcom/phy-bcm-ns-usb3.c similarity index 70% rename from drivers/phy/phy-bcm-ns-usb3.c rename to drivers/phy/broadcom/phy-bcm-ns-usb3.c index 22b5e7047fa6..a53ae128eadf 100644 --- a/drivers/phy/phy-bcm-ns-usb3.c +++ b/drivers/phy/broadcom/phy-bcm-ns-usb3.c @@ -16,7 +16,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -52,7 +54,10 @@ struct bcm_ns_usb3 { enum bcm_ns_family family; void __iomem *dmp; void __iomem *ccb_mii; + struct mdio_device *mdiodev; struct phy *phy; + + int (*phy_write)(struct bcm_ns_usb3 *usb3, u16 reg, u16 value); }; static const struct of_device_id bcm_ns_usb3_id_table[] = { @@ -68,63 +73,16 @@ static const struct of_device_id bcm_ns_usb3_id_table[] = { }; MODULE_DEVICE_TABLE(of, bcm_ns_usb3_id_table); -static int bcm_ns_usb3_wait_reg(struct bcm_ns_usb3 *usb3, void __iomem *addr, - u32 mask, u32 value, unsigned long timeout) -{ - unsigned long deadline = jiffies + timeout; - u32 val; - - do { - val = readl(addr); - if ((val & mask) == value) - return 0; - cpu_relax(); - udelay(10); - } while (!time_after_eq(jiffies, deadline)); - - dev_err(usb3->dev, "Timeout waiting for register %p\n", addr); - - return -EBUSY; -} - -static inline int bcm_ns_usb3_mii_mng_wait_idle(struct bcm_ns_usb3 *usb3) -{ - return bcm_ns_usb3_wait_reg(usb3, usb3->ccb_mii + BCMA_CCB_MII_MNG_CTL, - 0x0100, 0x0000, - usecs_to_jiffies(BCM_NS_USB3_MII_MNG_TIMEOUT_US)); -} - static int bcm_ns_usb3_mdio_phy_write(struct bcm_ns_usb3 *usb3, u16 reg, u16 value) { - u32 tmp = 0; - int err; - - err = bcm_ns_usb3_mii_mng_wait_idle(usb3); - if (err < 0) { - dev_err(usb3->dev, "Couldn't write 0x%08x value\n", value); - return err; - } - - /* TODO: Use a proper MDIO bus layer */ - tmp |= 0x58020000; /* Magic value for MDIO PHY write */ - tmp |= reg << 18; - tmp |= value; - writel(tmp, usb3->ccb_mii + BCMA_CCB_MII_MNG_CMD_DATA); - - return 0; + return usb3->phy_write(usb3, reg, value); } static int bcm_ns_usb3_phy_init_ns_bx(struct bcm_ns_usb3 *usb3) { int err; - /* Enable MDIO. Setting MDCDIV as 26 */ - writel(0x0000009a, usb3->ccb_mii + BCMA_CCB_MII_MNG_CTL); - - /* Wait for MDIO? */ - udelay(2); - /* USB3 PLL Block */ err = bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PHY_BASE_ADDR_REG, BCM_NS_USB3_PHY_PLL30_BLOCK); @@ -143,9 +101,6 @@ static int bcm_ns_usb3_phy_init_ns_bx(struct bcm_ns_usb3 *usb3) /* Deaaserting PLL Reset */ bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PLLA_CONTROL1, 0x8000); - /* Waiting MII Mgt interface idle */ - bcm_ns_usb3_mii_mng_wait_idle(usb3); - /* Deasserting USB3 system reset */ writel(0, usb3->dmp + BCMA_RESET_CTL); @@ -169,9 +124,6 @@ static int bcm_ns_usb3_phy_init_ns_bx(struct bcm_ns_usb3 *usb3) /* Enabling SSC */ bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_TX_PMD_CONTROL1, 0x1003); - /* Waiting MII Mgt interface idle */ - bcm_ns_usb3_mii_mng_wait_idle(usb3); - return 0; } @@ -179,12 +131,6 @@ static int bcm_ns_usb3_phy_init_ns_ax(struct bcm_ns_usb3 *usb3) { int err; - /* Enable MDIO. Setting MDCDIV as 26 */ - writel(0x0000009a, usb3->ccb_mii + BCMA_CCB_MII_MNG_CTL); - - /* Wait for MDIO? */ - udelay(2); - /* PLL30 block */ err = bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_PHY_BASE_ADDR_REG, BCM_NS_USB3_PHY_PLL30_BLOCK); @@ -205,9 +151,6 @@ static int bcm_ns_usb3_phy_init_ns_ax(struct bcm_ns_usb3 *usb3) bcm_ns_usb3_mdio_phy_write(usb3, BCM_NS_USB3_TX_PMD_CONTROL1, 0x1003); - /* Waiting MII Mgt interface idle */ - bcm_ns_usb3_mii_mng_wait_idle(usb3); - /* Deasserting USB3 system reset */ writel(0, usb3->dmp + BCMA_RESET_CTL); @@ -242,6 +185,128 @@ static const struct phy_ops ops = { .owner = THIS_MODULE, }; +/************************************************** + * MDIO driver code + **************************************************/ + +static int bcm_ns_usb3_mdiodev_phy_write(struct bcm_ns_usb3 *usb3, u16 reg, + u16 value) +{ + struct mdio_device *mdiodev = usb3->mdiodev; + + return mdiobus_write(mdiodev->bus, mdiodev->addr, reg, value); +} + +static int bcm_ns_usb3_mdio_probe(struct mdio_device *mdiodev) +{ + struct device *dev = &mdiodev->dev; + const struct of_device_id *of_id; + struct phy_provider *phy_provider; + struct device_node *syscon_np; + struct bcm_ns_usb3 *usb3; + struct resource res; + int err; + + usb3 = devm_kzalloc(dev, sizeof(*usb3), GFP_KERNEL); + if (!usb3) + return -ENOMEM; + + usb3->dev = dev; + usb3->mdiodev = mdiodev; + + of_id = of_match_device(bcm_ns_usb3_id_table, dev); + if (!of_id) + return -EINVAL; + usb3->family = (enum bcm_ns_family)of_id->data; + + syscon_np = of_parse_phandle(dev->of_node, "usb3-dmp-syscon", 0); + err = of_address_to_resource(syscon_np, 0, &res); + of_node_put(syscon_np); + if (err) + return err; + + usb3->dmp = devm_ioremap_resource(dev, &res); + if (IS_ERR(usb3->dmp)) { + dev_err(dev, "Failed to map DMP regs\n"); + return PTR_ERR(usb3->dmp); + } + + usb3->phy_write = bcm_ns_usb3_mdiodev_phy_write; + + usb3->phy = devm_phy_create(dev, NULL, &ops); + if (IS_ERR(usb3->phy)) { + dev_err(dev, "Failed to create PHY\n"); + return PTR_ERR(usb3->phy); + } + + phy_set_drvdata(usb3->phy, usb3); + + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static struct mdio_driver bcm_ns_usb3_mdio_driver = { + .mdiodrv = { + .driver = { + .name = "bcm_ns_mdio_usb3", + .of_match_table = bcm_ns_usb3_id_table, + }, + }, + .probe = bcm_ns_usb3_mdio_probe, +}; + +/************************************************** + * Platform driver code + **************************************************/ + +static int bcm_ns_usb3_wait_reg(struct bcm_ns_usb3 *usb3, void __iomem *addr, + u32 mask, u32 value, unsigned long timeout) +{ + unsigned long deadline = jiffies + timeout; + u32 val; + + do { + val = readl(addr); + if ((val & mask) == value) + return 0; + cpu_relax(); + udelay(10); + } while (!time_after_eq(jiffies, deadline)); + + dev_err(usb3->dev, "Timeout waiting for register %p\n", addr); + + return -EBUSY; +} + +static inline int bcm_ns_usb3_mii_mng_wait_idle(struct bcm_ns_usb3 *usb3) +{ + return bcm_ns_usb3_wait_reg(usb3, usb3->ccb_mii + BCMA_CCB_MII_MNG_CTL, + 0x0100, 0x0000, + usecs_to_jiffies(BCM_NS_USB3_MII_MNG_TIMEOUT_US)); +} + +static int bcm_ns_usb3_platform_phy_write(struct bcm_ns_usb3 *usb3, u16 reg, + u16 value) +{ + u32 tmp = 0; + int err; + + err = bcm_ns_usb3_mii_mng_wait_idle(usb3); + if (err < 0) { + dev_err(usb3->dev, "Couldn't write 0x%08x value\n", value); + return err; + } + + /* TODO: Use a proper MDIO bus layer */ + tmp |= 0x58020000; /* Magic value for MDIO PHY write */ + tmp |= reg << 18; + tmp |= value; + writel(tmp, usb3->ccb_mii + BCMA_CCB_MII_MNG_CMD_DATA); + + return bcm_ns_usb3_mii_mng_wait_idle(usb3); +} + static int bcm_ns_usb3_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -275,6 +340,14 @@ static int bcm_ns_usb3_probe(struct platform_device *pdev) return PTR_ERR(usb3->ccb_mii); } + /* Enable MDIO. Setting MDCDIV as 26 */ + writel(0x0000009a, usb3->ccb_mii + BCMA_CCB_MII_MNG_CTL); + + /* Wait for MDIO? */ + udelay(2); + + usb3->phy_write = bcm_ns_usb3_platform_phy_write; + usb3->phy = devm_phy_create(dev, NULL, &ops); if (IS_ERR(usb3->phy)) { dev_err(dev, "Failed to create PHY\n"); @@ -298,6 +371,35 @@ static struct platform_driver bcm_ns_usb3_driver = { .of_match_table = bcm_ns_usb3_id_table, }, }; -module_platform_driver(bcm_ns_usb3_driver); + +static int __init bcm_ns_usb3_module_init(void) +{ + int err; + + /* + * For backward compatibility we register as MDIO and platform driver. + * After getting MDIO binding commonly used (e.g. switching all DT files + * to use it) we should deprecate the old binding and eventually drop + * support for it. + */ + + err = mdio_driver_register(&bcm_ns_usb3_mdio_driver); + if (err) + return err; + + err = platform_driver_register(&bcm_ns_usb3_driver); + if (err) + mdio_driver_unregister(&bcm_ns_usb3_mdio_driver); + + return err; +} +module_init(bcm_ns_usb3_module_init); + +static void __exit bcm_ns_usb3_module_exit(void) +{ + platform_driver_unregister(&bcm_ns_usb3_driver); + mdio_driver_unregister(&bcm_ns_usb3_mdio_driver); +} +module_exit(bcm_ns_usb3_module_exit) MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/phy-bcm-ns2-pcie.c b/drivers/phy/broadcom/phy-bcm-ns2-pcie.c similarity index 100% rename from drivers/phy/phy-bcm-ns2-pcie.c rename to drivers/phy/broadcom/phy-bcm-ns2-pcie.c diff --git a/drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c b/drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c new file mode 100644 index 000000000000..9ae59e223131 --- /dev/null +++ b/drivers/phy/broadcom/phy-bcm-ns2-usbdrd.c @@ -0,0 +1,437 @@ +/* + * Copyright (C) 2017 Broadcom + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ICFG_DRD_AFE 0x0 +#define ICFG_MISC_STAT 0x18 +#define ICFG_DRD_P0CTL 0x1C +#define ICFG_STRAP_CTRL 0x20 +#define ICFG_FSM_CTRL 0x24 + +#define ICFG_DEV_BIT BIT(2) +#define IDM_RST_BIT BIT(0) +#define AFE_CORERDY_VDDC BIT(18) +#define PHY_PLL_RESETB BIT(15) +#define PHY_RESETB BIT(14) +#define PHY_PLL_LOCK BIT(0) + +#define DRD_DEV_MODE BIT(20) +#define OHCI_OVRCUR_POL BIT(11) +#define ICFG_OFF_MODE BIT(6) +#define PLL_LOCK_RETRY 1000 + +#define EVT_DEVICE 0 +#define EVT_HOST 1 + +#define DRD_HOST_MODE (BIT(2) | BIT(3)) +#define DRD_DEVICE_MODE (BIT(4) | BIT(5)) +#define DRD_HOST_VAL 0x803 +#define DRD_DEV_VAL 0x807 +#define GPIO_DELAY 20 + +struct ns2_phy_data; +struct ns2_phy_driver { + void __iomem *icfgdrd_regs; + void __iomem *idmdrd_rst_ctrl; + void __iomem *crmu_usb2_ctrl; + void __iomem *usb2h_strap_reg; + struct ns2_phy_data *data; + struct extcon_dev *edev; + struct gpio_desc *vbus_gpiod; + struct gpio_desc *id_gpiod; + int id_irq; + int vbus_irq; + unsigned long debounce_jiffies; + struct delayed_work wq_extcon; +}; + +struct ns2_phy_data { + struct ns2_phy_driver *driver; + struct phy *phy; + int new_state; +}; + +static const unsigned int usb_extcon_cable[] = { + EXTCON_USB, + EXTCON_USB_HOST, + EXTCON_NONE, +}; + +static inline int pll_lock_stat(u32 usb_reg, int reg_mask, + struct ns2_phy_driver *driver) +{ + int retry = PLL_LOCK_RETRY; + u32 val; + + do { + udelay(1); + val = readl(driver->icfgdrd_regs + usb_reg); + if (val & reg_mask) + return 0; + } while (--retry > 0); + + return -EBUSY; +} + +static int ns2_drd_phy_init(struct phy *phy) +{ + struct ns2_phy_data *data = phy_get_drvdata(phy); + struct ns2_phy_driver *driver = data->driver; + u32 val; + + val = readl(driver->icfgdrd_regs + ICFG_FSM_CTRL); + + if (data->new_state == EVT_HOST) { + val &= ~DRD_DEVICE_MODE; + val |= DRD_HOST_MODE; + } else { + val &= ~DRD_HOST_MODE; + val |= DRD_DEVICE_MODE; + } + writel(val, driver->icfgdrd_regs + ICFG_FSM_CTRL); + + return 0; +} + +static int ns2_drd_phy_poweroff(struct phy *phy) +{ + struct ns2_phy_data *data = phy_get_drvdata(phy); + struct ns2_phy_driver *driver = data->driver; + u32 val; + + val = readl(driver->crmu_usb2_ctrl); + val &= ~AFE_CORERDY_VDDC; + writel(val, driver->crmu_usb2_ctrl); + + val = readl(driver->crmu_usb2_ctrl); + val &= ~DRD_DEV_MODE; + writel(val, driver->crmu_usb2_ctrl); + + /* Disable Host and Device Mode */ + val = readl(driver->icfgdrd_regs + ICFG_FSM_CTRL); + val &= ~(DRD_HOST_MODE | DRD_DEVICE_MODE | ICFG_OFF_MODE); + writel(val, driver->icfgdrd_regs + ICFG_FSM_CTRL); + + return 0; +} + +static int ns2_drd_phy_poweron(struct phy *phy) +{ + struct ns2_phy_data *data = phy_get_drvdata(phy); + struct ns2_phy_driver *driver = data->driver; + u32 extcon_event = data->new_state; + int ret; + u32 val; + + if (extcon_event == EVT_DEVICE) { + writel(DRD_DEV_VAL, driver->icfgdrd_regs + ICFG_DRD_P0CTL); + + val = readl(driver->idmdrd_rst_ctrl); + val &= ~IDM_RST_BIT; + writel(val, driver->idmdrd_rst_ctrl); + + val = readl(driver->crmu_usb2_ctrl); + val |= (AFE_CORERDY_VDDC | DRD_DEV_MODE); + writel(val, driver->crmu_usb2_ctrl); + + /* Bring PHY and PHY_PLL out of Reset */ + val = readl(driver->crmu_usb2_ctrl); + val |= (PHY_PLL_RESETB | PHY_RESETB); + writel(val, driver->crmu_usb2_ctrl); + + ret = pll_lock_stat(ICFG_MISC_STAT, PHY_PLL_LOCK, driver); + if (ret < 0) { + dev_err(&phy->dev, "Phy PLL lock failed\n"); + return ret; + } + } else { + writel(DRD_HOST_VAL, driver->icfgdrd_regs + ICFG_DRD_P0CTL); + + val = readl(driver->crmu_usb2_ctrl); + val |= AFE_CORERDY_VDDC; + writel(val, driver->crmu_usb2_ctrl); + + ret = pll_lock_stat(ICFG_MISC_STAT, PHY_PLL_LOCK, driver); + if (ret < 0) { + dev_err(&phy->dev, "Phy PLL lock failed\n"); + return ret; + } + + val = readl(driver->idmdrd_rst_ctrl); + val &= ~IDM_RST_BIT; + writel(val, driver->idmdrd_rst_ctrl); + + /* port over current Polarity */ + val = readl(driver->usb2h_strap_reg); + val |= OHCI_OVRCUR_POL; + writel(val, driver->usb2h_strap_reg); + } + + return 0; +} + +static void connect_change(struct ns2_phy_driver *driver) +{ + u32 extcon_event; + u32 val; + + extcon_event = driver->data->new_state; + val = readl(driver->icfgdrd_regs + ICFG_FSM_CTRL); + + switch (extcon_event) { + case EVT_DEVICE: + val &= ~(DRD_HOST_MODE | DRD_DEVICE_MODE); + writel(val, driver->icfgdrd_regs + ICFG_FSM_CTRL); + + val = (val & ~DRD_HOST_MODE) | DRD_DEVICE_MODE; + writel(val, driver->icfgdrd_regs + ICFG_FSM_CTRL); + + val = readl(driver->icfgdrd_regs + ICFG_DRD_P0CTL); + val |= ICFG_DEV_BIT; + writel(val, driver->icfgdrd_regs + ICFG_DRD_P0CTL); + break; + + case EVT_HOST: + val &= ~(DRD_HOST_MODE | DRD_DEVICE_MODE); + writel(val, driver->icfgdrd_regs + ICFG_FSM_CTRL); + + val = (val & ~DRD_DEVICE_MODE) | DRD_HOST_MODE; + writel(val, driver->icfgdrd_regs + ICFG_FSM_CTRL); + + val = readl(driver->usb2h_strap_reg); + val |= OHCI_OVRCUR_POL; + writel(val, driver->usb2h_strap_reg); + + val = readl(driver->icfgdrd_regs + ICFG_DRD_P0CTL); + val &= ~ICFG_DEV_BIT; + writel(val, driver->icfgdrd_regs + ICFG_DRD_P0CTL); + break; + + default: + pr_err("Invalid extcon event\n"); + break; + } +} + +static void extcon_work(struct work_struct *work) +{ + struct ns2_phy_driver *driver; + int vbus; + int id; + + driver = container_of(to_delayed_work(work), + struct ns2_phy_driver, wq_extcon); + + id = gpiod_get_value_cansleep(driver->id_gpiod); + vbus = gpiod_get_value_cansleep(driver->vbus_gpiod); + + if (!id && vbus) { /* Host connected */ + extcon_set_cable_state_(driver->edev, EXTCON_USB_HOST, true); + pr_debug("Host cable connected\n"); + driver->data->new_state = EVT_HOST; + connect_change(driver); + } else if (id && !vbus) { /* Disconnected */ + extcon_set_cable_state_(driver->edev, EXTCON_USB_HOST, false); + extcon_set_cable_state_(driver->edev, EXTCON_USB, false); + pr_debug("Cable disconnected\n"); + } else if (id && vbus) { /* Device connected */ + extcon_set_cable_state_(driver->edev, EXTCON_USB, true); + pr_debug("Device cable connected\n"); + driver->data->new_state = EVT_DEVICE; + connect_change(driver); + } +} + +static irqreturn_t gpio_irq_handler(int irq, void *dev_id) +{ + struct ns2_phy_driver *driver = dev_id; + + queue_delayed_work(system_power_efficient_wq, &driver->wq_extcon, + driver->debounce_jiffies); + + return IRQ_HANDLED; +} + +static struct phy_ops ops = { + .init = ns2_drd_phy_init, + .power_on = ns2_drd_phy_poweron, + .power_off = ns2_drd_phy_poweroff, + .owner = THIS_MODULE, +}; + +static const struct of_device_id ns2_drd_phy_dt_ids[] = { + { .compatible = "brcm,ns2-drd-phy", }, + { } +}; +MODULE_DEVICE_TABLE(of, ns2_drd_phy_dt_ids); + +static int ns2_drd_phy_probe(struct platform_device *pdev) +{ + struct phy_provider *phy_provider; + struct device *dev = &pdev->dev; + struct ns2_phy_driver *driver; + struct ns2_phy_data *data; + struct resource *res; + int ret; + u32 val; + + driver = devm_kzalloc(dev, sizeof(struct ns2_phy_driver), + GFP_KERNEL); + if (!driver) + return -ENOMEM; + + driver->data = devm_kzalloc(dev, sizeof(struct ns2_phy_data), + GFP_KERNEL); + if (!driver->data) + return -ENOMEM; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "icfg"); + driver->icfgdrd_regs = devm_ioremap_resource(dev, res); + if (IS_ERR(driver->icfgdrd_regs)) + return PTR_ERR(driver->icfgdrd_regs); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rst-ctrl"); + driver->idmdrd_rst_ctrl = devm_ioremap_resource(dev, res); + if (IS_ERR(driver->idmdrd_rst_ctrl)) + return PTR_ERR(driver->idmdrd_rst_ctrl); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "crmu-ctrl"); + driver->crmu_usb2_ctrl = devm_ioremap_resource(dev, res); + if (IS_ERR(driver->crmu_usb2_ctrl)) + return PTR_ERR(driver->crmu_usb2_ctrl); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "usb2-strap"); + driver->usb2h_strap_reg = devm_ioremap_resource(dev, res); + if (IS_ERR(driver->usb2h_strap_reg)) + return PTR_ERR(driver->usb2h_strap_reg); + + /* create extcon */ + driver->id_gpiod = devm_gpiod_get(&pdev->dev, "id", GPIOD_IN); + if (IS_ERR(driver->id_gpiod)) { + dev_err(dev, "failed to get ID GPIO\n"); + return PTR_ERR(driver->id_gpiod); + } + driver->vbus_gpiod = devm_gpiod_get(&pdev->dev, "vbus", GPIOD_IN); + if (IS_ERR(driver->vbus_gpiod)) { + dev_err(dev, "failed to get VBUS GPIO\n"); + return PTR_ERR(driver->vbus_gpiod); + } + + driver->edev = devm_extcon_dev_allocate(dev, usb_extcon_cable); + if (IS_ERR(driver->edev)) { + dev_err(dev, "failed to allocate extcon device\n"); + return -ENOMEM; + } + + ret = devm_extcon_dev_register(dev, driver->edev); + if (ret < 0) { + dev_err(dev, "failed to register extcon device\n"); + return ret; + } + + ret = gpiod_set_debounce(driver->id_gpiod, GPIO_DELAY * 1000); + if (ret < 0) + driver->debounce_jiffies = msecs_to_jiffies(GPIO_DELAY); + + INIT_DELAYED_WORK(&driver->wq_extcon, extcon_work); + + driver->id_irq = gpiod_to_irq(driver->id_gpiod); + if (driver->id_irq < 0) { + dev_err(dev, "failed to get ID IRQ\n"); + return driver->id_irq; + } + + driver->vbus_irq = gpiod_to_irq(driver->vbus_gpiod); + if (driver->vbus_irq < 0) { + dev_err(dev, "failed to get ID IRQ\n"); + return driver->vbus_irq; + } + + ret = devm_request_irq(dev, driver->id_irq, gpio_irq_handler, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "usb_id", driver); + if (ret < 0) { + dev_err(dev, "failed to request handler for ID IRQ\n"); + return ret; + } + + ret = devm_request_irq(dev, driver->vbus_irq, gpio_irq_handler, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "usb_vbus", driver); + if (ret < 0) { + dev_err(dev, "failed to request handler for VBUS IRQ\n"); + return ret; + } + + dev_set_drvdata(dev, driver); + + /* Shutdown all ports. They can be powered up as required */ + val = readl(driver->crmu_usb2_ctrl); + val &= ~(AFE_CORERDY_VDDC | PHY_RESETB); + writel(val, driver->crmu_usb2_ctrl); + + data = driver->data; + data->phy = devm_phy_create(dev, dev->of_node, &ops); + if (IS_ERR(data->phy)) { + dev_err(dev, "Failed to create usb drd phy\n"); + return PTR_ERR(data->phy); + } + + data->driver = driver; + phy_set_drvdata(data->phy, data); + + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (IS_ERR(phy_provider)) { + dev_err(dev, "Failed to register as phy provider\n"); + return PTR_ERR(phy_provider); + } + + platform_set_drvdata(pdev, driver); + + dev_info(dev, "Registered NS2 DRD Phy device\n"); + queue_delayed_work(system_power_efficient_wq, &driver->wq_extcon, + driver->debounce_jiffies); + + return 0; +} + +static struct platform_driver ns2_drd_phy_driver = { + .probe = ns2_drd_phy_probe, + .driver = { + .name = "bcm-ns2-usbphy", + .of_match_table = of_match_ptr(ns2_drd_phy_dt_ids), + }, +}; +module_platform_driver(ns2_drd_phy_driver); + +MODULE_ALIAS("platform:bcm-ns2-drd-phy"); +MODULE_AUTHOR("Broadcom"); +MODULE_DESCRIPTION("Broadcom NS2 USB2 PHY driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/phy-brcm-sata.c b/drivers/phy/broadcom/phy-brcm-sata.c similarity index 85% rename from drivers/phy/phy-brcm-sata.c rename to drivers/phy/broadcom/phy-brcm-sata.c index ccbc3d994998..e6544c8b1ace 100644 --- a/drivers/phy/phy-brcm-sata.c +++ b/drivers/phy/broadcom/phy-brcm-sata.c @@ -46,6 +46,7 @@ enum brcm_sata_phy_version { BRCM_SATA_PHY_STB_40NM, BRCM_SATA_PHY_IPROC_NS2, BRCM_SATA_PHY_IPROC_NSP, + BRCM_SATA_PHY_IPROC_SR, }; struct brcm_sata_port { @@ -81,12 +82,17 @@ enum sata_phy_regs { PLL_ACTRL2 = 0x8b, PLL_ACTRL2_SELDIV_MASK = 0x1f, PLL_ACTRL2_SELDIV_SHIFT = 9, + PLL_ACTRL6 = 0x86, PLL1_REG_BANK = 0x060, PLL1_ACTRL2 = 0x82, PLL1_ACTRL3 = 0x83, PLL1_ACTRL4 = 0x84, + TX_REG_BANK = 0x070, + TX_ACTRL0 = 0x80, + TX_ACTRL0_TXPOL_FLIP = BIT(6), + OOB_REG_BANK = 0x150, OOB1_REG_BANK = 0x160, OOB_CTRL1 = 0x80, @@ -347,6 +353,68 @@ static int brcm_nsp_sata_init(struct brcm_sata_port *port) return 0; } +/* SR PHY PLL0 registers */ +#define SR_PLL0_ACTRL6_MAGIC 0xa + +/* SR PHY PLL1 registers */ +#define SR_PLL1_ACTRL2_MAGIC 0x32 +#define SR_PLL1_ACTRL3_MAGIC 0x2 +#define SR_PLL1_ACTRL4_MAGIC 0x3e8 + +static int brcm_sr_sata_init(struct brcm_sata_port *port) +{ + struct brcm_sata_phy *priv = port->phy_priv; + struct device *dev = port->phy_priv->dev; + void __iomem *base = priv->phy_base; + unsigned int val, try; + + /* Configure PHY PLL register bank 1 */ + val = SR_PLL1_ACTRL2_MAGIC; + brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL2, 0x0, val); + val = SR_PLL1_ACTRL3_MAGIC; + brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL3, 0x0, val); + val = SR_PLL1_ACTRL4_MAGIC; + brcm_sata_phy_wr(base, PLL1_REG_BANK, PLL1_ACTRL4, 0x0, val); + + /* Configure PHY PLL register bank 0 */ + val = SR_PLL0_ACTRL6_MAGIC; + brcm_sata_phy_wr(base, PLL_REG_BANK_0, PLL_ACTRL6, 0x0, val); + + /* Wait for PHY PLL lock by polling pll_lock bit */ + try = 50; + do { + val = brcm_sata_phy_rd(base, BLOCK0_REG_BANK, + BLOCK0_XGXSSTATUS); + if (val & BLOCK0_XGXSSTATUS_PLL_LOCK) + break; + msleep(20); + try--; + } while (try); + + if ((val & BLOCK0_XGXSSTATUS_PLL_LOCK) == 0) { + /* PLL did not lock; give up */ + dev_err(dev, "port%d PLL did not lock\n", port->portnum); + return -ETIMEDOUT; + } + + /* Invert Tx polarity */ + brcm_sata_phy_wr(base, TX_REG_BANK, TX_ACTRL0, + ~TX_ACTRL0_TXPOL_FLIP, TX_ACTRL0_TXPOL_FLIP); + + /* Configure OOB control to handle 100MHz reference clock */ + val = ((0xc << OOB_CTRL1_BURST_MAX_SHIFT) | + (0x4 << OOB_CTRL1_BURST_MIN_SHIFT) | + (0x8 << OOB_CTRL1_WAKE_IDLE_MAX_SHIFT) | + (0x3 << OOB_CTRL1_WAKE_IDLE_MIN_SHIFT)); + brcm_sata_phy_wr(base, OOB_REG_BANK, OOB_CTRL1, 0x0, val); + val = ((0x1b << OOB_CTRL2_RESET_IDLE_MAX_SHIFT) | + (0x2 << OOB_CTRL2_BURST_CNT_SHIFT) | + (0x9 << OOB_CTRL2_RESET_IDLE_MIN_SHIFT)); + brcm_sata_phy_wr(base, OOB_REG_BANK, OOB_CTRL2, 0x0, val); + + return 0; +} + static int brcm_sata_phy_init(struct phy *phy) { int rc; @@ -363,6 +431,9 @@ static int brcm_sata_phy_init(struct phy *phy) case BRCM_SATA_PHY_IPROC_NSP: rc = brcm_nsp_sata_init(port); break; + case BRCM_SATA_PHY_IPROC_SR: + rc = brcm_sr_sata_init(port); + break; default: rc = -ENODEV; } @@ -384,6 +455,8 @@ static const struct of_device_id brcm_sata_phy_of_match[] = { .data = (void *)BRCM_SATA_PHY_IPROC_NS2 }, { .compatible = "brcm,iproc-nsp-sata-phy", .data = (void *)BRCM_SATA_PHY_IPROC_NSP }, + { .compatible = "brcm,iproc-sr-sata-phy", + .data = (void *)BRCM_SATA_PHY_IPROC_SR }, {}, }; MODULE_DEVICE_TABLE(of, brcm_sata_phy_of_match); diff --git a/drivers/phy/hisilicon/Kconfig b/drivers/phy/hisilicon/Kconfig new file mode 100644 index 000000000000..6164c4cd0f65 --- /dev/null +++ b/drivers/phy/hisilicon/Kconfig @@ -0,0 +1,20 @@ +# +# Phy drivers for Hisilicon platforms +# +config PHY_HI6220_USB + tristate "hi6220 USB PHY support" + depends on (ARCH_HISI && ARM64) || COMPILE_TEST + select GENERIC_PHY + select MFD_SYSCON + help + Enable this to support the HISILICON HI6220 USB PHY. + + To compile this driver as a module, choose M here. + +config PHY_HIX5HD2_SATA + tristate "HIX5HD2 SATA PHY Driver" + depends on ARCH_HIX5HD2 && OF && HAS_IOMEM + select GENERIC_PHY + select MFD_SYSCON + help + Support for SATA PHY on Hisilicon hix5hd2 Soc. diff --git a/drivers/phy/hisilicon/Makefile b/drivers/phy/hisilicon/Makefile new file mode 100644 index 000000000000..541b348187a8 --- /dev/null +++ b/drivers/phy/hisilicon/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_PHY_HI6220_USB) += phy-hi6220-usb.o +obj-$(CONFIG_PHY_HIX5HD2_SATA) += phy-hix5hd2-sata.o diff --git a/drivers/phy/phy-hi6220-usb.c b/drivers/phy/hisilicon/phy-hi6220-usb.c similarity index 100% rename from drivers/phy/phy-hi6220-usb.c rename to drivers/phy/hisilicon/phy-hi6220-usb.c diff --git a/drivers/phy/phy-hix5hd2-sata.c b/drivers/phy/hisilicon/phy-hix5hd2-sata.c similarity index 100% rename from drivers/phy/phy-hix5hd2-sata.c rename to drivers/phy/hisilicon/phy-hix5hd2-sata.c diff --git a/drivers/phy/marvell/Kconfig b/drivers/phy/marvell/Kconfig new file mode 100644 index 000000000000..048d8893bc2e --- /dev/null +++ b/drivers/phy/marvell/Kconfig @@ -0,0 +1,50 @@ +# +# Phy drivers for Marvell platforms +# +config ARMADA375_USBCLUSTER_PHY + def_bool y + depends on MACH_ARMADA_375 || COMPILE_TEST + depends on OF && HAS_IOMEM + select GENERIC_PHY + +config PHY_BERLIN_SATA + tristate "Marvell Berlin SATA PHY driver" + depends on ARCH_BERLIN && HAS_IOMEM && OF + select GENERIC_PHY + help + Enable this to support the SATA PHY on Marvell Berlin SoCs. + +config PHY_BERLIN_USB + tristate "Marvell Berlin USB PHY Driver" + depends on ARCH_BERLIN && RESET_CONTROLLER && HAS_IOMEM && OF + select GENERIC_PHY + help + Enable this to support the USB PHY on Marvell Berlin SoCs. + +config PHY_MVEBU_SATA + def_bool y + depends on ARCH_DOVE || MACH_DOVE || MACH_KIRKWOOD + depends on OF + select GENERIC_PHY + +config PHY_PXA_28NM_HSIC + tristate "Marvell USB HSIC 28nm PHY Driver" + depends on HAS_IOMEM + select GENERIC_PHY + help + Enable this to support Marvell USB HSIC PHY driver for Marvell + SoC. This driver will do the PHY initialization and shutdown. + The PHY driver will be used by Marvell ehci driver. + + To compile this driver as a module, choose M here. + +config PHY_PXA_28NM_USB2 + tristate "Marvell USB 2.0 28nm PHY Driver" + depends on HAS_IOMEM + select GENERIC_PHY + help + Enable this to support Marvell USB 2.0 PHY driver for Marvell + SoC. This driver will do the PHY initialization and shutdown. + The PHY driver will be used by Marvell udc/ehci/otg driver. + + To compile this driver as a module, choose M here. diff --git a/drivers/phy/marvell/Makefile b/drivers/phy/marvell/Makefile new file mode 100644 index 000000000000..3fc188f59118 --- /dev/null +++ b/drivers/phy/marvell/Makefile @@ -0,0 +1,6 @@ +obj-$(CONFIG_ARMADA375_USBCLUSTER_PHY) += phy-armada375-usb2.o +obj-$(CONFIG_PHY_BERLIN_SATA) += phy-berlin-sata.o +obj-$(CONFIG_PHY_BERLIN_USB) += phy-berlin-usb.o +obj-$(CONFIG_PHY_MVEBU_SATA) += phy-mvebu-sata.o +obj-$(CONFIG_PHY_PXA_28NM_HSIC) += phy-pxa-28nm-hsic.o +obj-$(CONFIG_PHY_PXA_28NM_USB2) += phy-pxa-28nm-usb2.o diff --git a/drivers/phy/phy-armada375-usb2.c b/drivers/phy/marvell/phy-armada375-usb2.c similarity index 100% rename from drivers/phy/phy-armada375-usb2.c rename to drivers/phy/marvell/phy-armada375-usb2.c diff --git a/drivers/phy/phy-berlin-sata.c b/drivers/phy/marvell/phy-berlin-sata.c similarity index 100% rename from drivers/phy/phy-berlin-sata.c rename to drivers/phy/marvell/phy-berlin-sata.c diff --git a/drivers/phy/phy-berlin-usb.c b/drivers/phy/marvell/phy-berlin-usb.c similarity index 100% rename from drivers/phy/phy-berlin-usb.c rename to drivers/phy/marvell/phy-berlin-usb.c diff --git a/drivers/phy/phy-mvebu-sata.c b/drivers/phy/marvell/phy-mvebu-sata.c similarity index 100% rename from drivers/phy/phy-mvebu-sata.c rename to drivers/phy/marvell/phy-mvebu-sata.c diff --git a/drivers/phy/phy-pxa-28nm-hsic.c b/drivers/phy/marvell/phy-pxa-28nm-hsic.c similarity index 100% rename from drivers/phy/phy-pxa-28nm-hsic.c rename to drivers/phy/marvell/phy-pxa-28nm-hsic.c diff --git a/drivers/phy/phy-pxa-28nm-usb2.c b/drivers/phy/marvell/phy-pxa-28nm-usb2.c similarity index 100% rename from drivers/phy/phy-pxa-28nm-usb2.c rename to drivers/phy/marvell/phy-pxa-28nm-usb2.c diff --git a/drivers/phy/motorola/Kconfig b/drivers/phy/motorola/Kconfig new file mode 100644 index 000000000000..6bb7d6bdf1bf --- /dev/null +++ b/drivers/phy/motorola/Kconfig @@ -0,0 +1,12 @@ +# +# Phy drivers for Motorola devices +# +config PHY_CPCAP_USB + tristate "CPCAP PMIC USB PHY driver" + depends on USB_SUPPORT && IIO + depends on USB_MUSB_HDRC || USB_MUSB_HDRC=n + select GENERIC_PHY + select USB_PHY + help + Enable this for USB to work on Motorola phones and tablets + such as Droid 4. diff --git a/drivers/phy/motorola/Makefile b/drivers/phy/motorola/Makefile new file mode 100644 index 000000000000..b6cd618d671a --- /dev/null +++ b/drivers/phy/motorola/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the phy drivers. +# + +obj-$(CONFIG_PHY_CPCAP_USB) += phy-cpcap-usb.o diff --git a/drivers/phy/motorola/phy-cpcap-usb.c b/drivers/phy/motorola/phy-cpcap-usb.c new file mode 100644 index 000000000000..9b63efa5ae4d --- /dev/null +++ b/drivers/phy/motorola/phy-cpcap-usb.c @@ -0,0 +1,676 @@ +/* + * Motorola CPCAP PMIC USB PHY driver + * Copyright (C) 2017 Tony Lindgren + * + * Some parts based on earlier Motorola Linux kernel tree code in + * board-mapphone-usb.c and cpcap-usb-det.c: + * Copyright (C) 2007 - 2011 Motorola, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation version 2. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +/* CPCAP_REG_USBC1 register bits */ +#define CPCAP_BIT_IDPULSE BIT(15) +#define CPCAP_BIT_ID100KPU BIT(14) +#define CPCAP_BIT_IDPUCNTRL BIT(13) +#define CPCAP_BIT_IDPU BIT(12) +#define CPCAP_BIT_IDPD BIT(11) +#define CPCAP_BIT_VBUSCHRGTMR3 BIT(10) +#define CPCAP_BIT_VBUSCHRGTMR2 BIT(9) +#define CPCAP_BIT_VBUSCHRGTMR1 BIT(8) +#define CPCAP_BIT_VBUSCHRGTMR0 BIT(7) +#define CPCAP_BIT_VBUSPU BIT(6) +#define CPCAP_BIT_VBUSPD BIT(5) +#define CPCAP_BIT_DMPD BIT(4) +#define CPCAP_BIT_DPPD BIT(3) +#define CPCAP_BIT_DM1K5PU BIT(2) +#define CPCAP_BIT_DP1K5PU BIT(1) +#define CPCAP_BIT_DP150KPU BIT(0) + +/* CPCAP_REG_USBC2 register bits */ +#define CPCAP_BIT_ZHSDRV1 BIT(15) +#define CPCAP_BIT_ZHSDRV0 BIT(14) +#define CPCAP_BIT_DPLLCLKREQ BIT(13) +#define CPCAP_BIT_SE0CONN BIT(12) +#define CPCAP_BIT_UARTTXTRI BIT(11) +#define CPCAP_BIT_UARTSWAP BIT(10) +#define CPCAP_BIT_UARTMUX1 BIT(9) +#define CPCAP_BIT_UARTMUX0 BIT(8) +#define CPCAP_BIT_ULPISTPLOW BIT(7) +#define CPCAP_BIT_TXENPOL BIT(6) +#define CPCAP_BIT_USBXCVREN BIT(5) +#define CPCAP_BIT_USBCNTRL BIT(4) +#define CPCAP_BIT_USBSUSPEND BIT(3) +#define CPCAP_BIT_EMUMODE2 BIT(2) +#define CPCAP_BIT_EMUMODE1 BIT(1) +#define CPCAP_BIT_EMUMODE0 BIT(0) + +/* CPCAP_REG_USBC3 register bits */ +#define CPCAP_BIT_SPARE_898_15 BIT(15) +#define CPCAP_BIT_IHSTX03 BIT(14) +#define CPCAP_BIT_IHSTX02 BIT(13) +#define CPCAP_BIT_IHSTX01 BIT(12) +#define CPCAP_BIT_IHSTX0 BIT(11) +#define CPCAP_BIT_IDPU_SPI BIT(10) +#define CPCAP_BIT_UNUSED_898_9 BIT(9) +#define CPCAP_BIT_VBUSSTBY_EN BIT(8) +#define CPCAP_BIT_VBUSEN_SPI BIT(7) +#define CPCAP_BIT_VBUSPU_SPI BIT(6) +#define CPCAP_BIT_VBUSPD_SPI BIT(5) +#define CPCAP_BIT_DMPD_SPI BIT(4) +#define CPCAP_BIT_DPPD_SPI BIT(3) +#define CPCAP_BIT_SUSPEND_SPI BIT(2) +#define CPCAP_BIT_PU_SPI BIT(1) +#define CPCAP_BIT_ULPI_SPI_SEL BIT(0) + +struct cpcap_usb_ints_state { + bool id_ground; + bool id_float; + bool chrg_det; + bool rvrs_chrg; + bool vbusov; + + bool chrg_se1b; + bool se0conn; + bool rvrs_mode; + bool chrgcurr1; + bool vbusvld; + bool sessvld; + bool sessend; + bool se1; + + bool battdetb; + bool dm; + bool dp; +}; + +enum cpcap_gpio_mode { + CPCAP_DM_DP, + CPCAP_MDM_RX_TX, + CPCAP_UNKNOWN, + CPCAP_OTG_DM_DP, +}; + +struct cpcap_phy_ddata { + struct regmap *reg; + struct device *dev; + struct clk *refclk; + struct usb_phy phy; + struct delayed_work detect_work; + struct pinctrl *pins; + struct pinctrl_state *pins_ulpi; + struct pinctrl_state *pins_utmi; + struct pinctrl_state *pins_uart; + struct gpio_desc *gpio[2]; + struct iio_channel *vbus; + struct iio_channel *id; + struct regulator *vusb; + atomic_t active; +}; + +static bool cpcap_usb_vbus_valid(struct cpcap_phy_ddata *ddata) +{ + int error, value = 0; + + error = iio_read_channel_processed(ddata->vbus, &value); + if (error >= 0) + return value > 3900 ? true : false; + + dev_err(ddata->dev, "error reading VBUS: %i\n", error); + + return false; +} + +static int cpcap_usb_phy_set_host(struct usb_otg *otg, struct usb_bus *host) +{ + otg->host = host; + if (!host) + otg->state = OTG_STATE_UNDEFINED; + + return 0; +} + +static int cpcap_usb_phy_set_peripheral(struct usb_otg *otg, + struct usb_gadget *gadget) +{ + otg->gadget = gadget; + if (!gadget) + otg->state = OTG_STATE_UNDEFINED; + + return 0; +} + +static const struct phy_ops ops = { + .owner = THIS_MODULE, +}; + +static int cpcap_phy_get_ints_state(struct cpcap_phy_ddata *ddata, + struct cpcap_usb_ints_state *s) +{ + int val, error; + + error = regmap_read(ddata->reg, CPCAP_REG_INTS1, &val); + if (error) + return error; + + s->id_ground = val & BIT(15); + s->id_float = val & BIT(14); + s->vbusov = val & BIT(11); + + error = regmap_read(ddata->reg, CPCAP_REG_INTS2, &val); + if (error) + return error; + + s->vbusvld = val & BIT(3); + s->sessvld = val & BIT(2); + s->sessend = val & BIT(1); + s->se1 = val & BIT(0); + + error = regmap_read(ddata->reg, CPCAP_REG_INTS4, &val); + if (error) + return error; + + s->dm = val & BIT(1); + s->dp = val & BIT(0); + + return 0; +} + +static int cpcap_usb_set_uart_mode(struct cpcap_phy_ddata *ddata); +static int cpcap_usb_set_usb_mode(struct cpcap_phy_ddata *ddata); + +static void cpcap_usb_detect(struct work_struct *work) +{ + struct cpcap_phy_ddata *ddata; + struct cpcap_usb_ints_state s; + bool vbus = false; + int error; + + ddata = container_of(work, struct cpcap_phy_ddata, detect_work.work); + + error = cpcap_phy_get_ints_state(ddata, &s); + if (error) + return; + + if (s.id_ground) { + dev_dbg(ddata->dev, "id ground, USB host mode\n"); + error = cpcap_usb_set_usb_mode(ddata); + if (error) + goto out_err; + + error = musb_mailbox(MUSB_ID_GROUND); + if (error) + goto out_err; + + error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3, + CPCAP_BIT_VBUSSTBY_EN, + CPCAP_BIT_VBUSSTBY_EN); + if (error) + goto out_err; + + return; + } + + error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3, + CPCAP_BIT_VBUSSTBY_EN, 0); + if (error) + goto out_err; + + vbus = cpcap_usb_vbus_valid(ddata); + + if (vbus) { + /* Are we connected to a docking station with vbus? */ + if (s.id_ground) { + dev_dbg(ddata->dev, "connected to a dock\n"); + + /* No VBUS needed with docks */ + error = cpcap_usb_set_usb_mode(ddata); + if (error) + goto out_err; + error = musb_mailbox(MUSB_ID_GROUND); + if (error) + goto out_err; + + return; + } + + /* Otherwise assume we're connected to a USB host */ + dev_dbg(ddata->dev, "connected to USB host\n"); + error = cpcap_usb_set_usb_mode(ddata); + if (error) + goto out_err; + error = musb_mailbox(MUSB_VBUS_VALID); + if (error) + goto out_err; + + return; + } + + /* Default to debug UART mode */ + error = cpcap_usb_set_uart_mode(ddata); + if (error) + goto out_err; + + error = musb_mailbox(MUSB_VBUS_OFF); + if (error) + goto out_err; + + dev_dbg(ddata->dev, "set UART mode\n"); + + return; + +out_err: + dev_err(ddata->dev, "error setting cable state: %i\n", error); +} + +static irqreturn_t cpcap_phy_irq_thread(int irq, void *data) +{ + struct cpcap_phy_ddata *ddata = data; + + if (!atomic_read(&ddata->active)) + return IRQ_NONE; + + schedule_delayed_work(&ddata->detect_work, msecs_to_jiffies(1)); + + return IRQ_HANDLED; +} + +static int cpcap_usb_init_irq(struct platform_device *pdev, + struct cpcap_phy_ddata *ddata, + const char *name) +{ + int irq, error; + + irq = platform_get_irq_byname(pdev, name); + if (!irq) + return -ENODEV; + + error = devm_request_threaded_irq(ddata->dev, irq, NULL, + cpcap_phy_irq_thread, + IRQF_SHARED, + name, ddata); + if (error) { + dev_err(ddata->dev, "could not get irq %s: %i\n", + name, error); + + return error; + } + + return 0; +} + +static const char * const cpcap_phy_irqs[] = { + /* REG_INT_0 */ + "id_ground", "id_float", + + /* REG_INT1 */ + "se0conn", "vbusvld", "sessvld", "sessend", "se1", + + /* REG_INT_3 */ + "dm", "dp", +}; + +static int cpcap_usb_init_interrupts(struct platform_device *pdev, + struct cpcap_phy_ddata *ddata) +{ + int i, error; + + for (i = 0; i < ARRAY_SIZE(cpcap_phy_irqs); i++) { + error = cpcap_usb_init_irq(pdev, ddata, cpcap_phy_irqs[i]); + if (error) + return error; + } + + return 0; +} + +/* + * Optional pins and modes. At least Motorola mapphone devices + * are using two GPIOs and dynamic pinctrl to multiplex PHY pins + * to UART, ULPI or UTMI mode. + */ + +static int cpcap_usb_gpio_set_mode(struct cpcap_phy_ddata *ddata, + enum cpcap_gpio_mode mode) +{ + if (!ddata->gpio[0] || !ddata->gpio[1]) + return 0; + + gpiod_set_value(ddata->gpio[0], mode & 1); + gpiod_set_value(ddata->gpio[1], mode >> 1); + + return 0; +} + +static int cpcap_usb_set_uart_mode(struct cpcap_phy_ddata *ddata) +{ + int error; + + error = cpcap_usb_gpio_set_mode(ddata, CPCAP_DM_DP); + if (error) + goto out_err; + + if (ddata->pins_uart) { + error = pinctrl_select_state(ddata->pins, ddata->pins_uart); + if (error) + goto out_err; + } + + error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC1, + CPCAP_BIT_VBUSPD, + CPCAP_BIT_VBUSPD); + if (error) + goto out_err; + + error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC2, + 0xffff, CPCAP_BIT_UARTMUX0 | + CPCAP_BIT_EMUMODE0); + if (error) + goto out_err; + + error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3, 0x7fff, + CPCAP_BIT_IDPU_SPI); + if (error) + goto out_err; + + return 0; + +out_err: + dev_err(ddata->dev, "%s failed with %i\n", __func__, error); + + return error; +} + +static int cpcap_usb_set_usb_mode(struct cpcap_phy_ddata *ddata) +{ + int error; + + error = cpcap_usb_gpio_set_mode(ddata, CPCAP_OTG_DM_DP); + if (error) + return error; + + if (ddata->pins_utmi) { + error = pinctrl_select_state(ddata->pins, ddata->pins_utmi); + if (error) { + dev_err(ddata->dev, "could not set usb mode: %i\n", + error); + + return error; + } + } + + error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC1, + CPCAP_BIT_VBUSPD, 0); + if (error) + goto out_err; + + error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC2, + CPCAP_BIT_USBXCVREN, + CPCAP_BIT_USBXCVREN); + if (error) + goto out_err; + + error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3, + CPCAP_BIT_PU_SPI | + CPCAP_BIT_DMPD_SPI | + CPCAP_BIT_DPPD_SPI | + CPCAP_BIT_SUSPEND_SPI | + CPCAP_BIT_ULPI_SPI_SEL, 0); + if (error) + goto out_err; + + error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC2, + CPCAP_BIT_USBXCVREN, + CPCAP_BIT_USBXCVREN); + if (error) + goto out_err; + + return 0; + +out_err: + dev_err(ddata->dev, "%s failed with %i\n", __func__, error); + + return error; +} + +static int cpcap_usb_init_optional_pins(struct cpcap_phy_ddata *ddata) +{ + ddata->pins = devm_pinctrl_get(ddata->dev); + if (IS_ERR(ddata->pins)) { + dev_info(ddata->dev, "default pins not configured: %ld\n", + PTR_ERR(ddata->pins)); + ddata->pins = NULL; + + return 0; + } + + ddata->pins_ulpi = pinctrl_lookup_state(ddata->pins, "ulpi"); + if (IS_ERR(ddata->pins_ulpi)) { + dev_info(ddata->dev, "ulpi pins not configured\n"); + ddata->pins_ulpi = NULL; + } + + ddata->pins_utmi = pinctrl_lookup_state(ddata->pins, "utmi"); + if (IS_ERR(ddata->pins_utmi)) { + dev_info(ddata->dev, "utmi pins not configured\n"); + ddata->pins_utmi = NULL; + } + + ddata->pins_uart = pinctrl_lookup_state(ddata->pins, "uart"); + if (IS_ERR(ddata->pins_uart)) { + dev_info(ddata->dev, "uart pins not configured\n"); + ddata->pins_uart = NULL; + } + + if (ddata->pins_uart) + return pinctrl_select_state(ddata->pins, ddata->pins_uart); + + return 0; +} + +static void cpcap_usb_init_optional_gpios(struct cpcap_phy_ddata *ddata) +{ + int i; + + for (i = 0; i < 2; i++) { + ddata->gpio[i] = devm_gpiod_get_index(ddata->dev, "mode", + i, GPIOD_OUT_HIGH); + if (IS_ERR(ddata->gpio[i])) { + dev_info(ddata->dev, "no mode change GPIO%i: %li\n", + i, PTR_ERR(ddata->gpio[i])); + ddata->gpio[i] = NULL; + } + } +} + +static int cpcap_usb_init_iio(struct cpcap_phy_ddata *ddata) +{ + enum iio_chan_type type; + int error; + + ddata->vbus = devm_iio_channel_get(ddata->dev, "vbus"); + if (IS_ERR(ddata->vbus)) { + error = PTR_ERR(ddata->vbus); + goto out_err; + } + + if (!ddata->vbus->indio_dev) { + error = -ENXIO; + goto out_err; + } + + error = iio_get_channel_type(ddata->vbus, &type); + if (error < 0) + goto out_err; + + if (type != IIO_VOLTAGE) { + error = -EINVAL; + goto out_err; + } + + return 0; + +out_err: + dev_err(ddata->dev, "could not initialize VBUS or ID IIO: %i\n", + error); + + return error; +} + +#ifdef CONFIG_OF +static const struct of_device_id cpcap_usb_phy_id_table[] = { + { + .compatible = "motorola,cpcap-usb-phy", + }, + { + .compatible = "motorola,mapphone-cpcap-usb-phy", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, cpcap_usb_phy_id_table); +#endif + +static int cpcap_usb_phy_probe(struct platform_device *pdev) +{ + struct cpcap_phy_ddata *ddata; + struct phy *generic_phy; + struct phy_provider *phy_provider; + struct usb_otg *otg; + const struct of_device_id *of_id; + int error; + + of_id = of_match_device(of_match_ptr(cpcap_usb_phy_id_table), + &pdev->dev); + if (!of_id) + return -EINVAL; + + ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL); + if (!ddata) + return -ENOMEM; + + ddata->reg = dev_get_regmap(pdev->dev.parent, NULL); + if (!ddata->reg) + return -ENODEV; + + otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL); + if (!otg) + return -ENOMEM; + + ddata->dev = &pdev->dev; + ddata->phy.dev = ddata->dev; + ddata->phy.label = "cpcap_usb_phy"; + ddata->phy.otg = otg; + ddata->phy.type = USB_PHY_TYPE_USB2; + otg->set_host = cpcap_usb_phy_set_host; + otg->set_peripheral = cpcap_usb_phy_set_peripheral; + otg->usb_phy = &ddata->phy; + INIT_DELAYED_WORK(&ddata->detect_work, cpcap_usb_detect); + platform_set_drvdata(pdev, ddata); + + ddata->vusb = devm_regulator_get(&pdev->dev, "vusb"); + if (IS_ERR(ddata->vusb)) + return PTR_ERR(ddata->vusb); + + error = regulator_enable(ddata->vusb); + if (error) + return error; + + generic_phy = devm_phy_create(ddata->dev, NULL, &ops); + if (IS_ERR(generic_phy)) { + error = PTR_ERR(generic_phy); + return PTR_ERR(generic_phy); + } + + phy_set_drvdata(generic_phy, ddata); + + phy_provider = devm_of_phy_provider_register(ddata->dev, + of_phy_simple_xlate); + if (IS_ERR(phy_provider)) + return PTR_ERR(phy_provider); + + error = cpcap_usb_init_optional_pins(ddata); + if (error) + return error; + + cpcap_usb_init_optional_gpios(ddata); + + error = cpcap_usb_init_iio(ddata); + if (error) + return error; + + error = cpcap_usb_init_interrupts(pdev, ddata); + if (error) + return error; + + usb_add_phy_dev(&ddata->phy); + atomic_set(&ddata->active, 1); + schedule_delayed_work(&ddata->detect_work, msecs_to_jiffies(1)); + + return 0; +} + +static int cpcap_usb_phy_remove(struct platform_device *pdev) +{ + struct cpcap_phy_ddata *ddata = platform_get_drvdata(pdev); + int error; + + atomic_set(&ddata->active, 0); + error = cpcap_usb_set_uart_mode(ddata); + if (error) + dev_err(ddata->dev, "could not set UART mode\n"); + + error = musb_mailbox(MUSB_VBUS_OFF); + if (error) + dev_err(ddata->dev, "could not set mailbox\n"); + + usb_remove_phy(&ddata->phy); + cancel_delayed_work_sync(&ddata->detect_work); + clk_unprepare(ddata->refclk); + regulator_disable(ddata->vusb); + + return 0; +} + +static struct platform_driver cpcap_usb_phy_driver = { + .probe = cpcap_usb_phy_probe, + .remove = cpcap_usb_phy_remove, + .driver = { + .name = "cpcap-usb-phy", + .of_match_table = of_match_ptr(cpcap_usb_phy_id_table), + }, +}; + +module_platform_driver(cpcap_usb_phy_driver); + +MODULE_ALIAS("platform:cpcap_usb"); +MODULE_AUTHOR("Tony Lindgren "); +MODULE_DESCRIPTION("CPCAP usb phy driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/phy/qualcomm/Kconfig b/drivers/phy/qualcomm/Kconfig new file mode 100644 index 000000000000..7bfa64baf837 --- /dev/null +++ b/drivers/phy/qualcomm/Kconfig @@ -0,0 +1,58 @@ +# +# Phy drivers for Qualcomm platforms +# +config PHY_QCOM_APQ8064_SATA + tristate "Qualcomm APQ8064 SATA SerDes/PHY driver" + depends on ARCH_QCOM + depends on HAS_IOMEM + depends on OF + select GENERIC_PHY + +config PHY_QCOM_IPQ806X_SATA + tristate "Qualcomm IPQ806x SATA SerDes/PHY driver" + depends on ARCH_QCOM + depends on HAS_IOMEM + depends on OF + select GENERIC_PHY + +config PHY_QCOM_QMP + tristate "Qualcomm QMP PHY Driver" + depends on OF && COMMON_CLK && (ARCH_QCOM || COMPILE_TEST) + select GENERIC_PHY + help + Enable this to support the QMP PHY transceiver that is used + with controllers such as PCIe, UFS, and USB on Qualcomm chips. + +config PHY_QCOM_QUSB2 + tristate "Qualcomm QUSB2 PHY Driver" + depends on OF && (ARCH_QCOM || COMPILE_TEST) + depends on NVMEM || !NVMEM + select GENERIC_PHY + help + Enable this to support the HighSpeed QUSB2 PHY transceiver for USB + controllers on Qualcomm chips. This driver supports the high-speed + PHY which is usually paired with either the ChipIdea or Synopsys DWC3 + USB IPs on MSM SOCs. + +config PHY_QCOM_UFS + tristate "Qualcomm UFS PHY driver" + depends on OF && ARCH_QCOM + select GENERIC_PHY + help + Support for UFS PHY on QCOM chipsets. + +config PHY_QCOM_USB_HS + tristate "Qualcomm USB HS PHY module" + depends on USB_ULPI_BUS + depends on EXTCON || !EXTCON # if EXTCON=m, this cannot be built-in + select GENERIC_PHY + help + Support for the USB high-speed ULPI compliant phy on Qualcomm + chipsets. + +config PHY_QCOM_USB_HSIC + tristate "Qualcomm USB HSIC ULPI PHY module" + depends on USB_ULPI_BUS + select GENERIC_PHY + help + Support for the USB HSIC ULPI compliant PHY on QCOM chipsets. diff --git a/drivers/phy/qualcomm/Makefile b/drivers/phy/qualcomm/Makefile new file mode 100644 index 000000000000..2e183d7695fd --- /dev/null +++ b/drivers/phy/qualcomm/Makefile @@ -0,0 +1,9 @@ +obj-$(CONFIG_PHY_QCOM_APQ8064_SATA) += phy-qcom-apq8064-sata.o +obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o +obj-$(CONFIG_PHY_QCOM_QMP) += phy-qcom-qmp.o +obj-$(CONFIG_PHY_QCOM_QUSB2) += phy-qcom-qusb2.o +obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o +obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o +obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o +obj-$(CONFIG_PHY_QCOM_USB_HS) += phy-qcom-usb-hs.o +obj-$(CONFIG_PHY_QCOM_USB_HSIC) += phy-qcom-usb-hsic.o diff --git a/drivers/phy/phy-qcom-apq8064-sata.c b/drivers/phy/qualcomm/phy-qcom-apq8064-sata.c similarity index 100% rename from drivers/phy/phy-qcom-apq8064-sata.c rename to drivers/phy/qualcomm/phy-qcom-apq8064-sata.c diff --git a/drivers/phy/phy-qcom-ipq806x-sata.c b/drivers/phy/qualcomm/phy-qcom-ipq806x-sata.c similarity index 100% rename from drivers/phy/phy-qcom-ipq806x-sata.c rename to drivers/phy/qualcomm/phy-qcom-ipq806x-sata.c diff --git a/drivers/phy/phy-qcom-qmp.c b/drivers/phy/qualcomm/phy-qcom-qmp.c similarity index 100% rename from drivers/phy/phy-qcom-qmp.c rename to drivers/phy/qualcomm/phy-qcom-qmp.c diff --git a/drivers/phy/phy-qcom-qusb2.c b/drivers/phy/qualcomm/phy-qcom-qusb2.c similarity index 100% rename from drivers/phy/phy-qcom-qusb2.c rename to drivers/phy/qualcomm/phy-qcom-qusb2.c diff --git a/drivers/phy/phy-qcom-ufs-i.h b/drivers/phy/qualcomm/phy-qcom-ufs-i.h similarity index 100% rename from drivers/phy/phy-qcom-ufs-i.h rename to drivers/phy/qualcomm/phy-qcom-ufs-i.h diff --git a/drivers/phy/phy-qcom-ufs-qmp-14nm.c b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-14nm.c similarity index 100% rename from drivers/phy/phy-qcom-ufs-qmp-14nm.c rename to drivers/phy/qualcomm/phy-qcom-ufs-qmp-14nm.c diff --git a/drivers/phy/phy-qcom-ufs-qmp-14nm.h b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-14nm.h similarity index 100% rename from drivers/phy/phy-qcom-ufs-qmp-14nm.h rename to drivers/phy/qualcomm/phy-qcom-ufs-qmp-14nm.h diff --git a/drivers/phy/phy-qcom-ufs-qmp-20nm.c b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-20nm.c similarity index 100% rename from drivers/phy/phy-qcom-ufs-qmp-20nm.c rename to drivers/phy/qualcomm/phy-qcom-ufs-qmp-20nm.c diff --git a/drivers/phy/phy-qcom-ufs-qmp-20nm.h b/drivers/phy/qualcomm/phy-qcom-ufs-qmp-20nm.h similarity index 100% rename from drivers/phy/phy-qcom-ufs-qmp-20nm.h rename to drivers/phy/qualcomm/phy-qcom-ufs-qmp-20nm.h diff --git a/drivers/phy/phy-qcom-ufs.c b/drivers/phy/qualcomm/phy-qcom-ufs.c similarity index 100% rename from drivers/phy/phy-qcom-ufs.c rename to drivers/phy/qualcomm/phy-qcom-ufs.c diff --git a/drivers/phy/phy-qcom-usb-hs.c b/drivers/phy/qualcomm/phy-qcom-usb-hs.c similarity index 99% rename from drivers/phy/phy-qcom-usb-hs.c rename to drivers/phy/qualcomm/phy-qcom-usb-hs.c index 94dfbfd739c3..4b20abc3ae2f 100644 --- a/drivers/phy/phy-qcom-usb-hs.c +++ b/drivers/phy/qualcomm/phy-qcom-usb-hs.c @@ -11,12 +11,11 @@ #include #include #include +#include #include #include #include -#include "ulpi_phy.h" - #define ULPI_PWR_CLK_MNG_REG 0x88 # define ULPI_PWR_OTG_COMP_DISABLE BIT(0) diff --git a/drivers/phy/phy-qcom-usb-hsic.c b/drivers/phy/qualcomm/phy-qcom-usb-hsic.c similarity index 99% rename from drivers/phy/phy-qcom-usb-hsic.c rename to drivers/phy/qualcomm/phy-qcom-usb-hsic.c index 47690f9945b9..c110563a73cb 100644 --- a/drivers/phy/phy-qcom-usb-hsic.c +++ b/drivers/phy/qualcomm/phy-qcom-usb-hsic.c @@ -8,13 +8,12 @@ #include #include #include +#include #include #include #include #include -#include "ulpi_phy.h" - #define ULPI_HSIC_CFG 0x30 #define ULPI_HSIC_IO_CAL 0x33 diff --git a/drivers/phy/renesas/Kconfig b/drivers/phy/renesas/Kconfig new file mode 100644 index 000000000000..cb09245e9b4c --- /dev/null +++ b/drivers/phy/renesas/Kconfig @@ -0,0 +1,24 @@ +# +# Phy drivers for Renesas platforms +# +config PHY_RCAR_GEN2 + tristate "Renesas R-Car generation 2 USB PHY driver" + depends on ARCH_RENESAS + depends on GENERIC_PHY + help + Support for USB PHY found on Renesas R-Car generation 2 SoCs. + +config PHY_RCAR_GEN3_USB2 + tristate "Renesas R-Car generation 3 USB 2.0 PHY driver" + depends on ARCH_RENESAS + depends on EXTCON + select GENERIC_PHY + help + Support for USB 2.0 PHY found on Renesas R-Car generation 3 SoCs. + +config PHY_RCAR_GEN3_USB3 + tristate "Renesas R-Car generation 3 USB 3.0 PHY driver" + depends on ARCH_RENESAS || COMPILE_TEST + select GENERIC_PHY + help + Support for USB 3.0 PHY found on Renesas R-Car generation 3 SoCs. diff --git a/drivers/phy/renesas/Makefile b/drivers/phy/renesas/Makefile new file mode 100644 index 000000000000..8b6025916a93 --- /dev/null +++ b/drivers/phy/renesas/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_PHY_RCAR_GEN2) += phy-rcar-gen2.o +obj-$(CONFIG_PHY_RCAR_GEN3_USB2) += phy-rcar-gen3-usb2.o +obj-$(CONFIG_PHY_RCAR_GEN3_USB3) += phy-rcar-gen3-usb3.o diff --git a/drivers/phy/phy-rcar-gen2.c b/drivers/phy/renesas/phy-rcar-gen2.c similarity index 100% rename from drivers/phy/phy-rcar-gen2.c rename to drivers/phy/renesas/phy-rcar-gen2.c diff --git a/drivers/phy/phy-rcar-gen3-usb2.c b/drivers/phy/renesas/phy-rcar-gen3-usb2.c similarity index 100% rename from drivers/phy/phy-rcar-gen3-usb2.c rename to drivers/phy/renesas/phy-rcar-gen3-usb2.c diff --git a/drivers/phy/renesas/phy-rcar-gen3-usb3.c b/drivers/phy/renesas/phy-rcar-gen3-usb3.c new file mode 100644 index 000000000000..88c83c9b8ff9 --- /dev/null +++ b/drivers/phy/renesas/phy-rcar-gen3-usb3.c @@ -0,0 +1,226 @@ +/* + * Renesas R-Car Gen3 for USB3.0 PHY driver + * + * Copyright (C) 2017 Renesas Electronics Corporation + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#define USB30_CLKSET0 0x034 +#define USB30_CLKSET1 0x036 +#define USB30_SSC_SET 0x038 +#define USB30_PHY_ENABLE 0x060 +#define USB30_VBUS_EN 0x064 + +/* USB30_CLKSET0 */ +#define CLKSET0_PRIVATE 0x05c0 +#define CLKSET0_USB30_FSEL_USB_EXTAL 0x0002 + +/* USB30_CLKSET1 */ +#define CLKSET1_USB30_PLL_MULTI_SHIFT 6 +#define CLKSET1_USB30_PLL_MULTI_USB_EXTAL (0x64 << \ + CLKSET1_USB30_PLL_MULTI_SHIFT) +#define CLKSET1_PHYRESET BIT(4) /* 1: reset */ +#define CLKSET1_REF_CLKDIV BIT(3) /* 1: USB_EXTAL */ +#define CLKSET1_PRIVATE_2_1 BIT(1) /* Write B'01 */ +#define CLKSET1_REF_CLK_SEL BIT(0) /* 1: USB3S0_CLK_P */ + +/* USB30_SSC_SET */ +#define SSC_SET_SSC_EN BIT(12) +#define SSC_SET_RANGE_SHIFT 9 +#define SSC_SET_RANGE_4980 (0x0 << SSC_SET_RANGE_SHIFT) +#define SSC_SET_RANGE_4492 (0x1 << SSC_SET_RANGE_SHIFT) +#define SSC_SET_RANGE_4003 (0x2 << SSC_SET_RANGE_SHIFT) + +/* USB30_PHY_ENABLE */ +#define PHY_ENABLE_RESET_EN BIT(4) + +/* USB30_VBUS_EN */ +#define VBUS_EN_VBUS_EN BIT(1) + +struct rcar_gen3_usb3 { + void __iomem *base; + struct phy *phy; + u32 ssc_range; + bool usb3s_clk; + bool usb_extal; +}; + +static void write_clkset1_for_usb_extal(struct rcar_gen3_usb3 *r, bool reset) +{ + u16 val = CLKSET1_USB30_PLL_MULTI_USB_EXTAL | + CLKSET1_REF_CLKDIV | CLKSET1_PRIVATE_2_1; + + if (reset) + val |= CLKSET1_PHYRESET; + + writew(val, r->base + USB30_CLKSET1); +} + +static void rcar_gen3_phy_usb3_enable_ssc(struct rcar_gen3_usb3 *r) +{ + u16 val = SSC_SET_SSC_EN; + + switch (r->ssc_range) { + case 4980: + val |= SSC_SET_RANGE_4980; + break; + case 4492: + val |= SSC_SET_RANGE_4492; + break; + case 4003: + val |= SSC_SET_RANGE_4003; + break; + default: + dev_err(&r->phy->dev, "%s: unsupported range (%x)\n", __func__, + r->ssc_range); + return; + } + + writew(val, r->base + USB30_SSC_SET); +} + +static void rcar_gen3_phy_usb3_select_usb_extal(struct rcar_gen3_usb3 *r) +{ + write_clkset1_for_usb_extal(r, false); + if (r->ssc_range) + rcar_gen3_phy_usb3_enable_ssc(r); + writew(CLKSET0_PRIVATE | CLKSET0_USB30_FSEL_USB_EXTAL, + r->base + USB30_CLKSET0); + writew(PHY_ENABLE_RESET_EN, r->base + USB30_PHY_ENABLE); + write_clkset1_for_usb_extal(r, true); + usleep_range(10, 20); + write_clkset1_for_usb_extal(r, false); +} + +static int rcar_gen3_phy_usb3_init(struct phy *p) +{ + struct rcar_gen3_usb3 *r = phy_get_drvdata(p); + + dev_vdbg(&r->phy->dev, "%s: enter (%d, %d, %d)\n", __func__, + r->usb3s_clk, r->usb_extal, r->ssc_range); + + if (!r->usb3s_clk && r->usb_extal) + rcar_gen3_phy_usb3_select_usb_extal(r); + + /* Enables VBUS detection anyway */ + writew(VBUS_EN_VBUS_EN, r->base + USB30_VBUS_EN); + + return 0; +} + +static const struct phy_ops rcar_gen3_phy_usb3_ops = { + .init = rcar_gen3_phy_usb3_init, + .owner = THIS_MODULE, +}; + +static const struct of_device_id rcar_gen3_phy_usb3_match_table[] = { + { .compatible = "renesas,rcar-gen3-usb3-phy" }, + { } +}; +MODULE_DEVICE_TABLE(of, rcar_gen3_phy_usb3_match_table); + +static int rcar_gen3_phy_usb3_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rcar_gen3_usb3 *r; + struct phy_provider *provider; + struct resource *res; + int ret = 0; + struct clk *clk; + + if (!dev->of_node) { + dev_err(dev, "This driver needs device tree\n"); + return -EINVAL; + } + + r = devm_kzalloc(dev, sizeof(*r), GFP_KERNEL); + if (!r) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + r->base = devm_ioremap_resource(dev, res); + if (IS_ERR(r->base)) + return PTR_ERR(r->base); + + clk = devm_clk_get(dev, "usb3s_clk"); + if (!IS_ERR(clk) && !clk_prepare_enable(clk)) { + r->usb3s_clk = !!clk_get_rate(clk); + clk_disable_unprepare(clk); + } + clk = devm_clk_get(dev, "usb_extal"); + if (!IS_ERR(clk) && !clk_prepare_enable(clk)) { + r->usb_extal = !!clk_get_rate(clk); + clk_disable_unprepare(clk); + } + + if (!r->usb3s_clk && !r->usb_extal) { + dev_err(dev, "This driver needs usb3s_clk and/or usb_extal\n"); + ret = -EINVAL; + goto error; + } + + /* + * devm_phy_create() will call pm_runtime_enable(&phy->dev); + * And then, phy-core will manage runtime pm for this device. + */ + pm_runtime_enable(dev); + + r->phy = devm_phy_create(dev, NULL, &rcar_gen3_phy_usb3_ops); + if (IS_ERR(r->phy)) { + dev_err(dev, "Failed to create USB3 PHY\n"); + ret = PTR_ERR(r->phy); + goto error; + } + + of_property_read_u32(dev->of_node, "renesas,ssc-range", &r->ssc_range); + + platform_set_drvdata(pdev, r); + phy_set_drvdata(r->phy, r); + + provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (IS_ERR(provider)) { + dev_err(dev, "Failed to register PHY provider\n"); + ret = PTR_ERR(provider); + goto error; + } + + return 0; + +error: + pm_runtime_disable(dev); + + return ret; +} + +static int rcar_gen3_phy_usb3_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + + return 0; +}; + +static struct platform_driver rcar_gen3_phy_usb3_driver = { + .driver = { + .name = "phy_rcar_gen3_usb3", + .of_match_table = rcar_gen3_phy_usb3_match_table, + }, + .probe = rcar_gen3_phy_usb3_probe, + .remove = rcar_gen3_phy_usb3_remove, +}; +module_platform_driver(rcar_gen3_phy_usb3_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Renesas R-Car Gen3 USB 3.0 PHY"); +MODULE_AUTHOR("Yoshihiro Shimoda "); diff --git a/drivers/phy/rockchip/Kconfig b/drivers/phy/rockchip/Kconfig new file mode 100644 index 000000000000..f5325b2b679e --- /dev/null +++ b/drivers/phy/rockchip/Kconfig @@ -0,0 +1,51 @@ +# +# Phy drivers for Rockchip platforms +# +config PHY_ROCKCHIP_DP + tristate "Rockchip Display Port PHY Driver" + depends on ARCH_ROCKCHIP && OF + select GENERIC_PHY + help + Enable this to support the Rockchip Display Port PHY. + +config PHY_ROCKCHIP_EMMC + tristate "Rockchip EMMC PHY Driver" + depends on ARCH_ROCKCHIP && OF + select GENERIC_PHY + help + Enable this to support the Rockchip EMMC PHY. + +config PHY_ROCKCHIP_INNO_USB2 + tristate "Rockchip INNO USB2PHY Driver" + depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF + depends on COMMON_CLK + depends on EXTCON + depends on USB_SUPPORT + select GENERIC_PHY + select USB_COMMON + help + Support for Rockchip USB2.0 PHY with Innosilicon IP block. + +config PHY_ROCKCHIP_PCIE + tristate "Rockchip PCIe PHY Driver" + depends on (ARCH_ROCKCHIP && OF) || COMPILE_TEST + select GENERIC_PHY + select MFD_SYSCON + help + Enable this to support the Rockchip PCIe PHY. + +config PHY_ROCKCHIP_TYPEC + tristate "Rockchip TYPEC PHY Driver" + depends on OF && (ARCH_ROCKCHIP || COMPILE_TEST) + select EXTCON + select GENERIC_PHY + select RESET_CONTROLLER + help + Enable this to support the Rockchip USB TYPEC PHY. + +config PHY_ROCKCHIP_USB + tristate "Rockchip USB2 PHY Driver" + depends on ARCH_ROCKCHIP && OF + select GENERIC_PHY + help + Enable this to support the Rockchip USB 2.0 PHY. diff --git a/drivers/phy/rockchip/Makefile b/drivers/phy/rockchip/Makefile new file mode 100644 index 000000000000..bd0acdf38e0f --- /dev/null +++ b/drivers/phy/rockchip/Makefile @@ -0,0 +1,6 @@ +obj-$(CONFIG_PHY_ROCKCHIP_DP) += phy-rockchip-dp.o +obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o +obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2) += phy-rockchip-inno-usb2.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 diff --git a/drivers/phy/phy-rockchip-dp.c b/drivers/phy/rockchip/phy-rockchip-dp.c similarity index 100% rename from drivers/phy/phy-rockchip-dp.c rename to drivers/phy/rockchip/phy-rockchip-dp.c diff --git a/drivers/phy/phy-rockchip-emmc.c b/drivers/phy/rockchip/phy-rockchip-emmc.c similarity index 100% rename from drivers/phy/phy-rockchip-emmc.c rename to drivers/phy/rockchip/phy-rockchip-emmc.c diff --git a/drivers/phy/phy-rockchip-inno-usb2.c b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c similarity index 94% rename from drivers/phy/phy-rockchip-inno-usb2.c rename to drivers/phy/rockchip/phy-rockchip-inno-usb2.c index 8efe78a49916..626883d9d176 100644 --- a/drivers/phy/phy-rockchip-inno-usb2.c +++ b/drivers/phy/rockchip/phy-rockchip-inno-usb2.c @@ -406,7 +406,8 @@ static int rockchip_usb2phy_init(struct phy *phy) mutex_lock(&rport->mutex); if (rport->port_id == USB2PHY_PORT_OTG) { - if (rport->mode != USB_DR_MODE_HOST) { + if (rport->mode != USB_DR_MODE_HOST && + rport->mode != USB_DR_MODE_UNKNOWN) { /* clear bvalid status and enable bvalid detect irq */ ret = property_enable(rphy, &rport->port_cfg->bvalid_det_clr, @@ -421,7 +422,7 @@ static int rockchip_usb2phy_init(struct phy *phy) goto out; schedule_delayed_work(&rport->otg_sm_work, - OTG_SCHEDULE_DELAY); + OTG_SCHEDULE_DELAY * 3); } else { /* If OTG works in host only mode, do nothing. */ dev_dbg(&rport->phy->dev, "mode %d\n", rport->mode); @@ -463,6 +464,9 @@ static int rockchip_usb2phy_power_on(struct phy *phy) if (ret) return ret; + /* waiting for the utmi_clk to become stable */ + usleep_range(1500, 2000); + rport->suspended = false; return 0; } @@ -493,7 +497,8 @@ static int rockchip_usb2phy_exit(struct phy *phy) struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy); if (rport->port_id == USB2PHY_PORT_OTG && - rport->mode != USB_DR_MODE_HOST) { + rport->mode != USB_DR_MODE_HOST && + rport->mode != USB_DR_MODE_UNKNOWN) { cancel_delayed_work_sync(&rport->otg_sm_work); cancel_delayed_work_sync(&rport->chg_work); } else if (rport->port_id == USB2PHY_PORT_HOST) @@ -970,7 +975,8 @@ static int rockchip_usb2phy_otg_port_init(struct rockchip_usb2phy *rphy, mutex_init(&rport->mutex); rport->mode = of_usb_get_dr_mode_by_phy(child_np, -1); - if (rport->mode == USB_DR_MODE_HOST) { + if (rport->mode == USB_DR_MODE_HOST || + rport->mode == USB_DR_MODE_UNKNOWN) { ret = 0; goto out; } @@ -1138,6 +1144,65 @@ disable_clks: return ret; } +static const struct rockchip_usb2phy_cfg rk3228_phy_cfgs[] = { + { + .reg = 0x760, + .num_ports = 2, + .clkout_ctl = { 0x0768, 4, 4, 1, 0 }, + .port_cfgs = { + [USB2PHY_PORT_OTG] = { + .phy_sus = { 0x0760, 15, 0, 0, 0x1d1 }, + .bvalid_det_en = { 0x0680, 3, 3, 0, 1 }, + .bvalid_det_st = { 0x0690, 3, 3, 0, 1 }, + .bvalid_det_clr = { 0x06a0, 3, 3, 0, 1 }, + .ls_det_en = { 0x0680, 2, 2, 0, 1 }, + .ls_det_st = { 0x0690, 2, 2, 0, 1 }, + .ls_det_clr = { 0x06a0, 2, 2, 0, 1 }, + .utmi_bvalid = { 0x0480, 4, 4, 0, 1 }, + .utmi_ls = { 0x0480, 3, 2, 0, 1 }, + }, + [USB2PHY_PORT_HOST] = { + .phy_sus = { 0x0764, 15, 0, 0, 0x1d1 }, + .ls_det_en = { 0x0680, 4, 4, 0, 1 }, + .ls_det_st = { 0x0690, 4, 4, 0, 1 }, + .ls_det_clr = { 0x06a0, 4, 4, 0, 1 } + } + }, + .chg_det = { + .opmode = { 0x0760, 3, 0, 5, 1 }, + .cp_det = { 0x0884, 4, 4, 0, 1 }, + .dcp_det = { 0x0884, 3, 3, 0, 1 }, + .dp_det = { 0x0884, 5, 5, 0, 1 }, + .idm_sink_en = { 0x0768, 8, 8, 0, 1 }, + .idp_sink_en = { 0x0768, 7, 7, 0, 1 }, + .idp_src_en = { 0x0768, 9, 9, 0, 1 }, + .rdm_pdwn_en = { 0x0768, 10, 10, 0, 1 }, + .vdm_src_en = { 0x0768, 12, 12, 0, 1 }, + .vdp_src_en = { 0x0768, 11, 11, 0, 1 }, + }, + }, + { + .reg = 0x800, + .num_ports = 2, + .clkout_ctl = { 0x0808, 4, 4, 1, 0 }, + .port_cfgs = { + [USB2PHY_PORT_OTG] = { + .phy_sus = { 0x800, 15, 0, 0, 0x1d1 }, + .ls_det_en = { 0x0684, 0, 0, 0, 1 }, + .ls_det_st = { 0x0694, 0, 0, 0, 1 }, + .ls_det_clr = { 0x06a4, 0, 0, 0, 1 } + }, + [USB2PHY_PORT_HOST] = { + .phy_sus = { 0x804, 15, 0, 0, 0x1d1 }, + .ls_det_en = { 0x0684, 1, 1, 0, 1 }, + .ls_det_st = { 0x0694, 1, 1, 0, 1 }, + .ls_det_clr = { 0x06a4, 1, 1, 0, 1 } + } + }, + }, + { /* sentinel */ } +}; + static const struct rockchip_usb2phy_cfg rk3328_phy_cfgs[] = { { .reg = 0x100, @@ -1263,6 +1328,7 @@ static const struct rockchip_usb2phy_cfg rk3399_phy_cfgs[] = { }; static const struct of_device_id rockchip_usb2phy_dt_match[] = { + { .compatible = "rockchip,rk3228-usb2phy", .data = &rk3228_phy_cfgs }, { .compatible = "rockchip,rk3328-usb2phy", .data = &rk3328_phy_cfgs }, { .compatible = "rockchip,rk3366-usb2phy", .data = &rk3366_phy_cfgs }, { .compatible = "rockchip,rk3399-usb2phy", .data = &rk3399_phy_cfgs }, diff --git a/drivers/phy/phy-rockchip-pcie.c b/drivers/phy/rockchip/phy-rockchip-pcie.c similarity index 100% rename from drivers/phy/phy-rockchip-pcie.c rename to drivers/phy/rockchip/phy-rockchip-pcie.c diff --git a/drivers/phy/phy-rockchip-typec.c b/drivers/phy/rockchip/phy-rockchip-typec.c similarity index 100% rename from drivers/phy/phy-rockchip-typec.c rename to drivers/phy/rockchip/phy-rockchip-typec.c diff --git a/drivers/phy/phy-rockchip-usb.c b/drivers/phy/rockchip/phy-rockchip-usb.c similarity index 100% rename from drivers/phy/phy-rockchip-usb.c rename to drivers/phy/rockchip/phy-rockchip-usb.c diff --git a/drivers/phy/samsung/Kconfig b/drivers/phy/samsung/Kconfig new file mode 100644 index 000000000000..b7e0645a7bd9 --- /dev/null +++ b/drivers/phy/samsung/Kconfig @@ -0,0 +1,95 @@ +# +# Phy drivers for Samsung platforms +# +config PHY_EXYNOS_DP_VIDEO + tristate "EXYNOS SoC series Display Port PHY driver" + depends on OF + depends on ARCH_EXYNOS || COMPILE_TEST + default ARCH_EXYNOS + select GENERIC_PHY + help + Support for Display Port PHY found on Samsung EXYNOS SoCs. + +config PHY_EXYNOS_MIPI_VIDEO + tristate "S5P/EXYNOS SoC series MIPI CSI-2/DSI PHY driver" + depends on HAS_IOMEM + depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST + select GENERIC_PHY + default y if ARCH_S5PV210 || ARCH_EXYNOS + help + Support for MIPI CSI-2 and MIPI DSI DPHY found on Samsung S5P + and EXYNOS SoCs. + +config PHY_EXYNOS_PCIE + bool "Exynos PCIe PHY driver" + depends on OF && (ARCH_EXYNOS || COMPILE_TEST) + select GENERIC_PHY + help + Enable PCIe PHY support for Exynos SoC series. + This driver provides PHY interface for Exynos PCIe controller. + +config PHY_SAMSUNG_USB2 + tristate "Samsung USB 2.0 PHY driver" + depends on HAS_IOMEM + depends on USB_EHCI_EXYNOS || USB_OHCI_EXYNOS || USB_DWC2 + select GENERIC_PHY + select MFD_SYSCON + default ARCH_EXYNOS + help + Enable this to support the Samsung USB 2.0 PHY driver for Samsung + SoCs. This driver provides the interface for USB 2.0 PHY. Support + for particular PHYs will be enabled based on the SoC type in addition + to this driver. + +config PHY_EXYNOS4210_USB2 + bool + depends on PHY_SAMSUNG_USB2 + default CPU_EXYNOS4210 + +config PHY_EXYNOS4X12_USB2 + bool + depends on PHY_SAMSUNG_USB2 + default SOC_EXYNOS3250 || SOC_EXYNOS4212 || SOC_EXYNOS4412 + +config PHY_EXYNOS5250_USB2 + bool + depends on PHY_SAMSUNG_USB2 + default SOC_EXYNOS5250 || SOC_EXYNOS5420 + +config PHY_S5PV210_USB2 + bool "Support for S5PV210" + depends on PHY_SAMSUNG_USB2 + depends on ARCH_S5PV210 + help + Enable USB PHY support for S5PV210. This option requires that Samsung + USB 2.0 PHY driver is enabled and means that support for this + particular SoC is compiled in the driver. In case of S5PV210 two phys + are available - device and host. + +config PHY_EXYNOS5_USBDRD + tristate "Exynos5 SoC series USB DRD PHY driver" + depends on ARCH_EXYNOS && OF + depends on HAS_IOMEM + depends on USB_DWC3_EXYNOS + select GENERIC_PHY + select MFD_SYSCON + default y + help + Enable USB DRD PHY support for Exynos 5 SoC series. + This driver provides PHY interface for USB 3.0 DRD controller + present on Exynos5 SoC series. + +config PHY_EXYNOS5250_SATA + tristate "Exynos5250 Sata SerDes/PHY driver" + depends on SOC_EXYNOS5250 + depends on HAS_IOMEM + depends on OF + select GENERIC_PHY + select I2C + select I2C_S3C2410 + select MFD_SYSCON + help + Enable this to support SATA SerDes/Phy found on Samsung's + Exynos5250 based SoCs.This SerDes/Phy supports SATA 1.5 Gb/s, + SATA 3.0 Gb/s, SATA 6.0 Gb/s speeds. It supports one SATA host + port to accept one SATA device. diff --git a/drivers/phy/samsung/Makefile b/drivers/phy/samsung/Makefile new file mode 100644 index 000000000000..20d7f2424772 --- /dev/null +++ b/drivers/phy/samsung/Makefile @@ -0,0 +1,11 @@ +obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o +obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o +obj-$(CONFIG_PHY_EXYNOS_PCIE) += phy-exynos-pcie.o +obj-$(CONFIG_PHY_SAMSUNG_USB2) += phy-exynos-usb2.o +phy-exynos-usb2-y += phy-samsung-usb2.o +phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4210_USB2) += phy-exynos4210-usb2.o +phy-exynos-usb2-$(CONFIG_PHY_EXYNOS4X12_USB2) += phy-exynos4x12-usb2.o +phy-exynos-usb2-$(CONFIG_PHY_EXYNOS5250_USB2) += phy-exynos5250-usb2.o +phy-exynos-usb2-$(CONFIG_PHY_S5PV210_USB2) += phy-s5pv210-usb2.o +obj-$(CONFIG_PHY_EXYNOS5_USBDRD) += phy-exynos5-usbdrd.o +obj-$(CONFIG_PHY_EXYNOS5250_SATA) += phy-exynos5250-sata.o diff --git a/drivers/phy/phy-exynos-dp-video.c b/drivers/phy/samsung/phy-exynos-dp-video.c similarity index 100% rename from drivers/phy/phy-exynos-dp-video.c rename to drivers/phy/samsung/phy-exynos-dp-video.c diff --git a/drivers/phy/phy-exynos-mipi-video.c b/drivers/phy/samsung/phy-exynos-mipi-video.c similarity index 100% rename from drivers/phy/phy-exynos-mipi-video.c rename to drivers/phy/samsung/phy-exynos-mipi-video.c diff --git a/drivers/phy/phy-exynos-pcie.c b/drivers/phy/samsung/phy-exynos-pcie.c similarity index 100% rename from drivers/phy/phy-exynos-pcie.c rename to drivers/phy/samsung/phy-exynos-pcie.c diff --git a/drivers/phy/phy-exynos4210-usb2.c b/drivers/phy/samsung/phy-exynos4210-usb2.c similarity index 100% rename from drivers/phy/phy-exynos4210-usb2.c rename to drivers/phy/samsung/phy-exynos4210-usb2.c diff --git a/drivers/phy/phy-exynos4x12-usb2.c b/drivers/phy/samsung/phy-exynos4x12-usb2.c similarity index 100% rename from drivers/phy/phy-exynos4x12-usb2.c rename to drivers/phy/samsung/phy-exynos4x12-usb2.c diff --git a/drivers/phy/phy-exynos5-usbdrd.c b/drivers/phy/samsung/phy-exynos5-usbdrd.c similarity index 100% rename from drivers/phy/phy-exynos5-usbdrd.c rename to drivers/phy/samsung/phy-exynos5-usbdrd.c diff --git a/drivers/phy/phy-exynos5250-sata.c b/drivers/phy/samsung/phy-exynos5250-sata.c similarity index 100% rename from drivers/phy/phy-exynos5250-sata.c rename to drivers/phy/samsung/phy-exynos5250-sata.c diff --git a/drivers/phy/phy-exynos5250-usb2.c b/drivers/phy/samsung/phy-exynos5250-usb2.c similarity index 100% rename from drivers/phy/phy-exynos5250-usb2.c rename to drivers/phy/samsung/phy-exynos5250-usb2.c diff --git a/drivers/phy/phy-s5pv210-usb2.c b/drivers/phy/samsung/phy-s5pv210-usb2.c similarity index 100% rename from drivers/phy/phy-s5pv210-usb2.c rename to drivers/phy/samsung/phy-s5pv210-usb2.c diff --git a/drivers/phy/phy-samsung-usb2.c b/drivers/phy/samsung/phy-samsung-usb2.c similarity index 100% rename from drivers/phy/phy-samsung-usb2.c rename to drivers/phy/samsung/phy-samsung-usb2.c diff --git a/drivers/phy/phy-samsung-usb2.h b/drivers/phy/samsung/phy-samsung-usb2.h similarity index 100% rename from drivers/phy/phy-samsung-usb2.h rename to drivers/phy/samsung/phy-samsung-usb2.h diff --git a/drivers/phy/st/Kconfig b/drivers/phy/st/Kconfig new file mode 100644 index 000000000000..0814d3f87ec6 --- /dev/null +++ b/drivers/phy/st/Kconfig @@ -0,0 +1,33 @@ +# +# Phy drivers for STMicro platforms +# +config PHY_MIPHY28LP + tristate "STMicroelectronics MIPHY28LP PHY driver for STiH407" + depends on ARCH_STI + select GENERIC_PHY + help + Enable this to support the miphy transceiver (for SATA/PCIE/USB3) + that is part of STMicroelectronics STiH407 SoC. + +config PHY_ST_SPEAR1310_MIPHY + tristate "ST SPEAR1310-MIPHY driver" + select GENERIC_PHY + depends on MACH_SPEAR1310 || COMPILE_TEST + help + Support for ST SPEAr1310 MIPHY which can be used for PCIe and SATA. + +config PHY_ST_SPEAR1340_MIPHY + tristate "ST SPEAR1340-MIPHY driver" + select GENERIC_PHY + depends on MACH_SPEAR1340 || COMPILE_TEST + help + Support for ST SPEAr1340 MIPHY which can be used for PCIe and SATA. + +config PHY_STIH407_USB + tristate "STMicroelectronics USB2 picoPHY driver for STiH407 family" + depends on RESET_CONTROLLER + depends on ARCH_STI || COMPILE_TEST + select GENERIC_PHY + help + Enable this support to enable the picoPHY device used by USB2 + and USB3 controllers on STMicroelectronics STiH407 SoC families. diff --git a/drivers/phy/st/Makefile b/drivers/phy/st/Makefile new file mode 100644 index 000000000000..e2adfe2166d2 --- /dev/null +++ b/drivers/phy/st/Makefile @@ -0,0 +1,4 @@ +obj-$(CONFIG_PHY_MIPHY28LP) += phy-miphy28lp.o +obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY) += phy-spear1310-miphy.o +obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY) += phy-spear1340-miphy.o +obj-$(CONFIG_PHY_STIH407_USB) += phy-stih407-usb.o diff --git a/drivers/phy/phy-miphy28lp.c b/drivers/phy/st/phy-miphy28lp.c similarity index 100% rename from drivers/phy/phy-miphy28lp.c rename to drivers/phy/st/phy-miphy28lp.c diff --git a/drivers/phy/phy-spear1310-miphy.c b/drivers/phy/st/phy-spear1310-miphy.c similarity index 100% rename from drivers/phy/phy-spear1310-miphy.c rename to drivers/phy/st/phy-spear1310-miphy.c diff --git a/drivers/phy/phy-spear1340-miphy.c b/drivers/phy/st/phy-spear1340-miphy.c similarity index 100% rename from drivers/phy/phy-spear1340-miphy.c rename to drivers/phy/st/phy-spear1340-miphy.c diff --git a/drivers/phy/phy-stih407-usb.c b/drivers/phy/st/phy-stih407-usb.c similarity index 100% rename from drivers/phy/phy-stih407-usb.c rename to drivers/phy/st/phy-stih407-usb.c diff --git a/drivers/phy/ti/Kconfig b/drivers/phy/ti/Kconfig new file mode 100644 index 000000000000..20503562666c --- /dev/null +++ b/drivers/phy/ti/Kconfig @@ -0,0 +1,78 @@ +# +# Phy drivers for TI platforms +# +config PHY_DA8XX_USB + tristate "TI DA8xx USB PHY Driver" + depends on ARCH_DAVINCI_DA8XX + select GENERIC_PHY + select MFD_SYSCON + help + Enable this to support the USB PHY on DA8xx SoCs. + + This driver controls both the USB 1.1 PHY and the USB 2.0 PHY. + +config PHY_DM816X_USB + tristate "TI dm816x USB PHY driver" + depends on ARCH_OMAP2PLUS + depends on USB_SUPPORT + select GENERIC_PHY + select USB_PHY + help + Enable this for dm816x USB to work. + +config OMAP_CONTROL_PHY + tristate "OMAP CONTROL PHY Driver" + depends on ARCH_OMAP2PLUS || COMPILE_TEST + help + Enable this to add support for the PHY part present in the control + module. This driver has API to power on the USB2 PHY and to write to + the mailbox. The mailbox is present only in omap4 and the register to + power on the USB2 PHY is present in OMAP4 and OMAP5. OMAP5 has an + additional register to power on USB3 PHY/SATA PHY/PCIE PHY + (PIPE3 PHY). + +config OMAP_USB2 + tristate "OMAP USB2 PHY Driver" + depends on ARCH_OMAP2PLUS + depends on USB_SUPPORT + select GENERIC_PHY + select USB_PHY + select OMAP_CONTROL_PHY + depends on OMAP_OCP2SCP + help + Enable this to support the transceiver that is part of SOC. This + driver takes care of all the PHY functionality apart from comparator. + The USB OTG controller communicates with the comparator using this + driver. + +config TI_PIPE3 + tristate "TI PIPE3 PHY Driver" + depends on ARCH_OMAP2PLUS || COMPILE_TEST + select GENERIC_PHY + select OMAP_CONTROL_PHY + depends on OMAP_OCP2SCP + help + Enable this to support the PIPE3 PHY that is part of TI SOCs. This + driver takes care of all the PHY functionality apart from comparator. + This driver interacts with the "OMAP Control PHY Driver" to power + on/off the PHY. + +config PHY_TUSB1210 + tristate "TI TUSB1210 ULPI PHY module" + depends on USB_ULPI_BUS + select GENERIC_PHY + help + Support for TI TUSB1210 USB ULPI PHY. + +config TWL4030_USB + tristate "TWL4030 USB Transceiver Driver" + depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS + depends on USB_SUPPORT + depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't 'y' + select GENERIC_PHY + select USB_PHY + help + Enable this to support the USB OTG transceiver on TWL4030 + family chips (including the TWL5030 and TPS659x0 devices). + This transceiver supports high and full speed devices plus, + in host mode, low speed. diff --git a/drivers/phy/ti/Makefile b/drivers/phy/ti/Makefile new file mode 100644 index 000000000000..0cc3a1a557a3 --- /dev/null +++ b/drivers/phy/ti/Makefile @@ -0,0 +1,7 @@ +obj-$(CONFIG_PHY_DA8XX_USB) += phy-da8xx-usb.o +obj-$(CONFIG_PHY_DM816X_USB) += phy-dm816x-usb.o +obj-$(CONFIG_OMAP_CONTROL_PHY) += phy-omap-control.o +obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o +obj-$(CONFIG_TI_PIPE3) += phy-ti-pipe3.o +obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o +obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o diff --git a/drivers/phy/phy-da8xx-usb.c b/drivers/phy/ti/phy-da8xx-usb.c similarity index 100% rename from drivers/phy/phy-da8xx-usb.c rename to drivers/phy/ti/phy-da8xx-usb.c diff --git a/drivers/phy/phy-dm816x-usb.c b/drivers/phy/ti/phy-dm816x-usb.c similarity index 100% rename from drivers/phy/phy-dm816x-usb.c rename to drivers/phy/ti/phy-dm816x-usb.c diff --git a/drivers/phy/phy-omap-control.c b/drivers/phy/ti/phy-omap-control.c similarity index 100% rename from drivers/phy/phy-omap-control.c rename to drivers/phy/ti/phy-omap-control.c diff --git a/drivers/phy/phy-omap-usb2.c b/drivers/phy/ti/phy-omap-usb2.c similarity index 100% rename from drivers/phy/phy-omap-usb2.c rename to drivers/phy/ti/phy-omap-usb2.c diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/ti/phy-ti-pipe3.c similarity index 100% rename from drivers/phy/phy-ti-pipe3.c rename to drivers/phy/ti/phy-ti-pipe3.c diff --git a/drivers/phy/phy-tusb1210.c b/drivers/phy/ti/phy-tusb1210.c similarity index 78% rename from drivers/phy/phy-tusb1210.c rename to drivers/phy/ti/phy-tusb1210.c index 4f6d5e71507d..b8ec39ac4dfc 100644 --- a/drivers/phy/phy-tusb1210.c +++ b/drivers/phy/ti/phy-tusb1210.c @@ -11,9 +11,9 @@ */ #include #include +#include #include - -#include "ulpi_phy.h" +#include #define TUSB1210_VENDOR_SPECIFIC2 0x80 #define TUSB1210_VENDOR_SPECIFIC2_IHSTX_SHIFT 0 @@ -53,9 +53,43 @@ static int tusb1210_power_off(struct phy *phy) return 0; } +static int tusb1210_set_mode(struct phy *phy, enum phy_mode mode) +{ + struct tusb1210 *tusb = phy_get_drvdata(phy); + int ret; + + ret = ulpi_read(tusb->ulpi, ULPI_OTG_CTRL); + if (ret < 0) + return ret; + + switch (mode) { + case PHY_MODE_USB_HOST: + ret |= (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; + break; + case PHY_MODE_USB_DEVICE: + ret &= ~(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; + break; + default: + /* nothing */ + return 0; + } + + return ulpi_write(tusb->ulpi, ULPI_OTG_CTRL, ret); +} + static const struct phy_ops phy_ops = { .power_on = tusb1210_power_on, .power_off = tusb1210_power_off, + .set_mode = tusb1210_set_mode, .owner = THIS_MODULE, }; @@ -125,7 +159,8 @@ static void tusb1210_remove(struct ulpi *ulpi) #define TI_VENDOR_ID 0x0451 static const struct ulpi_device_id tusb1210_ulpi_id[] = { - { TI_VENDOR_ID, 0x1507, }, + { TI_VENDOR_ID, 0x1507, }, /* TUSB1210 */ + { TI_VENDOR_ID, 0x1508, }, /* TUSB1211 */ { }, }; MODULE_DEVICE_TABLE(ulpi, tusb1210_ulpi_id); diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/ti/phy-twl4030-usb.c similarity index 100% rename from drivers/phy/phy-twl4030-usb.c rename to drivers/phy/ti/phy-twl4030-usb.c diff --git a/drivers/phy/ulpi_phy.h b/include/linux/phy/ulpi_phy.h similarity index 100% rename from drivers/phy/ulpi_phy.h rename to include/linux/phy/ulpi_phy.h