]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge tag 'phy-for-4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/kishon...
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 31 Jan 2017 09:51:45 +0000 (10:51 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 31 Jan 2017 09:51:45 +0000 (10:51 +0100)
Kishon writes:

phy: for 4.11

 *) Add USB HSIC and HS phy driver for Qualcomm's SoC
 *) Add USB3 PHY driver for Broadcom NSP SoC
 *) Make sun4i-usb-phy driver to be used for V3s USB PHY
 *) Misc fixes and cleanups

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
20 files changed:
Documentation/devicetree/bindings/phy/brcm,nsp-usb3-phy.txt [new file with mode: 0644]
Documentation/devicetree/bindings/phy/qcom,usb-hs-phy.txt [new file with mode: 0644]
Documentation/devicetree/bindings/phy/qcom,usb-hsic-phy.txt [new file with mode: 0644]
Documentation/devicetree/bindings/phy/sun4i-usb-phy.txt
Documentation/devicetree/bindings/ufs/ufs-qcom.txt
drivers/phy/Kconfig
drivers/phy/Makefile
drivers/phy/phy-bcm-cygnus-pcie.c
drivers/phy/phy-bcm-nsp-usb3.c [new file with mode: 0644]
drivers/phy/phy-hi6220-usb.c
drivers/phy/phy-mt65xx-usb3.c
drivers/phy/phy-qcom-ufs-i.h
drivers/phy/phy-qcom-ufs-qmp-14nm.c
drivers/phy/phy-qcom-ufs-qmp-20nm.c
drivers/phy/phy-qcom-ufs.c
drivers/phy/phy-qcom-usb-hs.c [new file with mode: 0644]
drivers/phy/phy-qcom-usb-hsic.c [new file with mode: 0644]
drivers/phy/phy-rcar-gen3-usb2.c
drivers/phy/phy-rockchip-inno-usb2.c
drivers/phy/phy-sun4i-usb.c

diff --git a/Documentation/devicetree/bindings/phy/brcm,nsp-usb3-phy.txt b/Documentation/devicetree/bindings/phy/brcm,nsp-usb3-phy.txt
new file mode 100644 (file)
index 0000000..e68ae5d
--- /dev/null
@@ -0,0 +1,39 @@
+Broadcom USB3 phy binding for northstar plus SoC
+The USB3 phy is internal to the SoC and is accessed using mdio interface.
+
+Required mdio bus properties:
+- reg: Should be 0x0 for SoC internal USB3 phy
+- #address-cells: must be 1
+- #size-cells: must be 0
+
+Required USB3 PHY properties:
+- compatible: should be "brcm,nsp-usb3-phy"
+- reg: USB3 Phy address on SoC internal MDIO bus and it should be 0x10.
+- usb3-ctrl-syscon: handler of syscon node defining physical address
+  of usb3 control register.
+- #phy-cells: must be 0
+
+Required usb3 control properties:
+- compatible: should be "brcm,nsp-usb3-ctrl"
+- reg: offset and length of the control registers
+
+Example:
+
+       mdio@0 {
+               reg = <0x0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               usb3_phy: usb-phy@10 {
+                       compatible = "brcm,nsp-usb3-phy";
+                       reg = <0x10>;
+                       usb3-ctrl-syscon = <&usb3_ctrl>;
+                       #phy-cells = <0>;
+                       status = "disabled";
+               };
+       };
+
+       usb3_ctrl: syscon@104408 {
+               compatible = "brcm,nsp-usb3-ctrl", "syscon";
+               reg = <0x104408 0x3fc>;
+       };
diff --git a/Documentation/devicetree/bindings/phy/qcom,usb-hs-phy.txt b/Documentation/devicetree/bindings/phy/qcom,usb-hs-phy.txt
new file mode 100644 (file)
index 0000000..b3b75c1
--- /dev/null
@@ -0,0 +1,84 @@
+Qualcomm's USB HS PHY
+
+PROPERTIES
+
+- compatible:
+    Usage: required
+    Value type: <string>
+    Definition: Should contain "qcom,usb-hs-phy" and more specifically one of the
+                following:
+
+                        "qcom,usb-hs-phy-apq8064"
+                        "qcom,usb-hs-phy-msm8916"
+                        "qcom,usb-hs-phy-msm8974"
+
+- #phy-cells:
+    Usage: required
+    Value type: <u32>
+    Definition: Should contain 0
+
+- clocks:
+    Usage: required
+    Value type: <prop-encoded-array>
+    Definition: Should contain clock specifier for the reference and sleep
+                clocks
+
+- clock-names:
+    Usage: required
+    Value type: <stringlist>
+    Definition: Should contain "ref" and "sleep" for the reference and sleep
+                clocks respectively
+
+- resets:
+    Usage: required
+    Value type: <prop-encoded-array>
+    Definition: Should contain the phy and POR resets
+
+- reset-names:
+    Usage: required
+    Value type: <stringlist>
+    Definition: Should contain "phy" and "por" for the phy and POR resets
+                respectively
+
+- v3p3-supply:
+    Usage: required
+    Value type: <phandle>
+    Definition: Should contain a reference to the 3.3V supply
+
+- v1p8-supply:
+    Usage: required
+    Value type: <phandle>
+    Definition: Should contain a reference to the 1.8V supply
+
+- extcon:
+    Usage: optional
+    Value type: <prop-encoded-array>
+    Definition: Should contain the vbus extcon
+
+- qcom,init-seq:
+    Usage: optional
+    Value type: <u8 array>
+    Definition: Should contain a sequence of ULPI address and value pairs to
+                program into the ULPI_EXT_VENDOR_SPECIFIC area. This is related
+                to Device Mode Eye Diagram test. The addresses are offsets
+                from the ULPI_EXT_VENDOR_SPECIFIC address, for example,
+                <0x1 0x53> would mean "write the value 0x53 to address 0x81".
+
+EXAMPLE
+
+otg: usb-controller {
+       ulpi {
+               phy {
+                       compatible = "qcom,usb-hs-phy-msm8974", "qcom,usb-hs-phy";
+                       #phy-cells = <0>;
+                       clocks = <&xo_board>, <&gcc GCC_USB2A_PHY_SLEEP_CLK>;
+                       clock-names = "ref", "sleep";
+                       resets = <&gcc GCC_USB2A_PHY_BCR>, <&otg 0>;
+                       reset-names = "phy", "por";
+                       v3p3-supply = <&pm8941_l24>;
+                       v1p8-supply = <&pm8941_l6>;
+                       extcon = <&smbb>;
+                       qcom,init-seq = /bits/ 8 <0x1 0x63>;
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/phy/qcom,usb-hsic-phy.txt b/Documentation/devicetree/bindings/phy/qcom,usb-hsic-phy.txt
new file mode 100644 (file)
index 0000000..3c7cb2b
--- /dev/null
@@ -0,0 +1,65 @@
+Qualcomm's USB HSIC PHY
+
+PROPERTIES
+
+- compatible:
+    Usage: required
+    Value type: <string>
+    Definition: Should contain "qcom,usb-hsic-phy" and more specifically one of the
+               following:
+
+                       "qcom,usb-hsic-phy-mdm9615"
+                       "qcom,usb-hsic-phy-msm8974"
+
+- #phy-cells:
+    Usage: required
+    Value type: <u32>
+    Definition: Should contain 0
+
+- clocks:
+    Usage: required
+    Value type: <prop-encoded-array>
+    Definition: Should contain clock specifier for phy, calibration and
+                a calibration sleep clock
+
+- clock-names:
+    Usage: required
+    Value type: <stringlist>
+    Definition: Should contain "phy, "cal" and "cal_sleep"
+
+- pinctrl-names:
+    Usage: required
+    Value type: <stringlist>
+    Definition: Should contain "init" and "default" in that order
+
+- pinctrl-0:
+    Usage: required
+    Value type: <prop-encoded-array>
+    Definition: List of pinctrl settings to apply to keep HSIC pins in a glitch
+                free state
+
+- pinctrl-1:
+    Usage: required
+    Value type: <prop-encoded-array>
+    Definition: List of pinctrl settings to apply to mux out the HSIC pins
+
+EXAMPLE
+
+usb-controller {
+       ulpi {
+               phy {
+                       compatible = "qcom,usb-hsic-phy-msm8974",
+                                    "qcom,usb-hsic-phy";
+                       #phy-cells = <0>;
+                       pinctrl-names = "init", "default";
+                       pinctrl-0 = <&hsic_sleep>;
+                       pinctrl-1 = <&hsic_default>;
+                       clocks = <&gcc GCC_USB_HSIC_CLK>,
+                                <&gcc GCC_USB_HSIC_IO_CAL_CLK>,
+                                <&gcc GCC_USB_HSIC_IO_CAL_SLEEP_CLK>;
+                       clock-names = "phy", "cal", "cal_sleep";
+                       assigned-clocks = <&gcc GCC_USB_HSIC_IO_CAL_CLK>;
+                       assigned-clock-rates = <960000>;
+               };
+       };
+};
index 287150db6db4f958add361f0aeabe087b50b60a9..e423342581855deebdc2bb4c9effa3e502540061 100644 (file)
@@ -10,6 +10,7 @@ Required properties:
   * allwinner,sun8i-a23-usb-phy
   * allwinner,sun8i-a33-usb-phy
   * allwinner,sun8i-h3-usb-phy
+  * allwinner,sun8i-v3s-usb-phy
   * allwinner,sun50i-a64-usb-phy
 - reg : a list of offset + length pairs
 - reg-names :
index b6b5130e5f65a8e625a25bfde7ad3593872040d8..1f69ee1a61ea25b776671be1becb8e8f63a29eb1 100644 (file)
@@ -29,7 +29,6 @@ Optional properties:
 - vdda-pll-max-microamp : specifies max. load that can be drawn from pll supply
 - vddp-ref-clk-supply   : phandle to UFS device ref_clk pad power supply
 - vddp-ref-clk-max-microamp : specifies max. load that can be drawn from this supply
-- vddp-ref-clk-always-on : specifies if this supply needs to be kept always on
 
 Example:
 
index e8eb7f225a88eee4490180bd6a3bc2f2ca6872f8..bb5cf6f49b068761db557067cdeeea5013773d36 100644 (file)
@@ -363,6 +363,7 @@ 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
@@ -437,6 +438,21 @@ config PHY_QCOM_UFS
        help
          Support for UFS PHY on QCOM chipsets.
 
+config PHY_QCOM_USB_HS
+       tristate "Qualcomm USB HS PHY module"
+       depends on USB_ULPI_BUS
+       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
@@ -486,4 +502,12 @@ config PHY_MESON8B_USB2
          and GXBB SoCs.
          If unsure, say N.
 
+config PHY_NSP_USB3
+       tristate "Broadcom NorthStar plus USB3 PHY driver"
+       depends on OF && (ARCH_BCM_NSP || COMPILE_TEST)
+       select GENERIC_PHY
+       default ARCH_BCM_NSP
+       help
+         Enable this to support the Broadcom Northstar plus USB3 PHY.
+         If unsure, say N.
 endmenu
index 65eb2f436a41d9c2c302fe3ac02c27242c620c38..9f008004f75d002c87aa7b8a6cf43d3a8ac5ed81 100644 (file)
@@ -52,6 +52,8 @@ obj-$(CONFIG_PHY_STIH407_USB)         += phy-stih407-usb.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
@@ -59,3 +61,4 @@ 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_PHY_NSP_USB3)             += phy-bcm-nsp-usb3.o
index 082c03f6438f796af868cb83127f1ce9ca56f83b..0f4ac5d63cff93211b8e0864b1de3e0e24fecfb5 100644 (file)
@@ -114,7 +114,7 @@ static int cygnus_pcie_phy_power_off(struct phy *p)
        return cygnus_pcie_power_config(phy, false);
 }
 
-static struct phy_ops cygnus_pcie_phy_ops = {
+static const struct phy_ops cygnus_pcie_phy_ops = {
        .power_on = cygnus_pcie_phy_power_on,
        .power_off = cygnus_pcie_phy_power_off,
        .owner = THIS_MODULE,
diff --git a/drivers/phy/phy-bcm-nsp-usb3.c b/drivers/phy/phy-bcm-nsp-usb3.c
new file mode 100644 (file)
index 0000000..49024ea
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2016 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 <linux/delay.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mdio.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/regmap.h>
+
+#define NSP_USB3_RST_CTRL_OFFSET       0x3f8
+
+/* mdio reg access */
+#define NSP_USB3_PHY_BASE_ADDR_REG     0x1f
+
+#define NSP_USB3_PHY_PLL30_BLOCK       0x8000
+#define NSP_USB3_PLL_CONTROL           0x01
+#define NSP_USB3_PLLA_CONTROL0         0x0a
+#define NSP_USB3_PLLA_CONTROL1         0x0b
+
+#define NSP_USB3_PHY_TX_PMD_BLOCK      0x8040
+#define NSP_USB3_TX_PMD_CONTROL1       0x01
+
+#define NSP_USB3_PHY_PIPE_BLOCK                0x8060
+#define NSP_USB3_LFPS_CMP              0x02
+#define NSP_USB3_LFPS_DEGLITCH         0x03
+
+struct nsp_usb3_phy {
+       struct regmap *usb3_ctrl;
+       struct phy *phy;
+       struct mdio_device *mdiodev;
+};
+
+static int nsp_usb3_phy_init(struct phy *phy)
+{
+       struct nsp_usb3_phy *iphy = phy_get_drvdata(phy);
+       struct mii_bus *bus = iphy->mdiodev->bus;
+       int addr = iphy->mdiodev->addr;
+       u32 data;
+       int rc;
+
+       rc = regmap_read(iphy->usb3_ctrl, 0, &data);
+       if (rc)
+               return rc;
+       data |= 1;
+       rc = regmap_write(iphy->usb3_ctrl, 0, data);
+       if (rc)
+               return rc;
+
+       rc = regmap_write(iphy->usb3_ctrl, NSP_USB3_RST_CTRL_OFFSET, 1);
+       if (rc)
+               return rc;
+
+       rc = mdiobus_write(bus, addr, NSP_USB3_PHY_BASE_ADDR_REG,
+                          NSP_USB3_PHY_PLL30_BLOCK);
+       if (rc)
+               return rc;
+
+       rc = mdiobus_write(bus, addr, NSP_USB3_PLL_CONTROL, 0x1000);
+       if (rc)
+               return rc;
+
+       rc = mdiobus_write(bus, addr, NSP_USB3_PLLA_CONTROL0, 0x6400);
+       if (rc)
+               return rc;
+
+       rc = mdiobus_write(bus, addr, NSP_USB3_PLLA_CONTROL1, 0xc000);
+       if (rc)
+               return rc;
+
+       rc = mdiobus_write(bus, addr, NSP_USB3_PLLA_CONTROL1, 0x8000);
+       if (rc)
+               return rc;
+
+       rc = regmap_write(iphy->usb3_ctrl, NSP_USB3_RST_CTRL_OFFSET, 0);
+       if (rc)
+               return rc;
+
+       rc = mdiobus_write(bus, addr, NSP_USB3_PLL_CONTROL, 0x9000);
+       if (rc)
+               return rc;
+
+       rc = mdiobus_write(bus, addr, NSP_USB3_PHY_BASE_ADDR_REG,
+                          NSP_USB3_PHY_PIPE_BLOCK);
+       if (rc)
+               return rc;
+
+       rc = mdiobus_write(bus, addr, NSP_USB3_LFPS_CMP, 0xf30d);
+       if (rc)
+               return rc;
+
+       rc = mdiobus_write(bus, addr, NSP_USB3_LFPS_DEGLITCH, 0x6302);
+       if (rc)
+               return rc;
+
+       rc = mdiobus_write(bus, addr, NSP_USB3_PHY_BASE_ADDR_REG,
+                          NSP_USB3_PHY_TX_PMD_BLOCK);
+       if (rc)
+               return rc;
+
+       rc = mdiobus_write(bus, addr, NSP_USB3_TX_PMD_CONTROL1, 0x1003);
+
+       return rc;
+}
+
+static struct phy_ops nsp_usb3_phy_ops = {
+       .init   = nsp_usb3_phy_init,
+       .owner  = THIS_MODULE,
+};
+
+static int nsp_usb3_phy_probe(struct mdio_device *mdiodev)
+{
+       struct device *dev = &mdiodev->dev;
+       struct phy_provider *provider;
+       struct nsp_usb3_phy *iphy;
+
+       iphy = devm_kzalloc(dev, sizeof(*iphy), GFP_KERNEL);
+       if (!iphy)
+               return -ENOMEM;
+       iphy->mdiodev = mdiodev;
+
+       iphy->usb3_ctrl = syscon_regmap_lookup_by_phandle(dev->of_node,
+                                                "usb3-ctrl-syscon");
+       if (IS_ERR(iphy->usb3_ctrl))
+               return PTR_ERR(iphy->usb3_ctrl);
+
+       iphy->phy = devm_phy_create(dev, dev->of_node, &nsp_usb3_phy_ops);
+       if (IS_ERR(iphy->phy)) {
+               dev_err(dev, "failed to create PHY\n");
+               return PTR_ERR(iphy->phy);
+       }
+
+       phy_set_drvdata(iphy->phy, iphy);
+
+       provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+       if (IS_ERR(provider)) {
+               dev_err(dev, "could not register PHY provider\n");
+               return PTR_ERR(provider);
+       }
+
+       return 0;
+}
+
+static const struct of_device_id nsp_usb3_phy_of_match[] = {
+       {.compatible = "brcm,nsp-usb3-phy",},
+       { /* sentinel */ }
+};
+
+static struct mdio_driver nsp_usb3_phy_driver = {
+       .mdiodrv = {
+               .driver = {
+                       .name = "nsp-usb3-phy",
+                       .of_match_table = nsp_usb3_phy_of_match,
+               },
+       },
+       .probe = nsp_usb3_phy_probe,
+};
+
+mdio_module_driver(nsp_usb3_phy_driver);
+
+MODULE_DESCRIPTION("Broadcom NSP USB3 PHY driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Yendapally Reddy Dhananjaya Reddy <yendapally.reddy@broadcom.com");
index b2141cbd4cf6cd7e5eb0127c58f1141b11fb5e53..398c1021deec056e2324fc1f22fc5efd19058682 100644 (file)
@@ -112,7 +112,7 @@ static int hi6220_phy_exit(struct phy *phy)
        return hi6220_phy_setup(priv, false);
 }
 
-static struct phy_ops hi6220_phy_ops = {
+static const struct phy_ops hi6220_phy_ops = {
        .init           = hi6220_phy_start,
        .exit           = hi6220_phy_exit,
        .owner          = THIS_MODULE,
index 4d85e730ccab131dc0821423c5d73427b6f89097..d9720675b9db311e0d847ee3c1bbac0ae3318811 100644 (file)
@@ -506,7 +506,7 @@ static struct phy *mt65xx_phy_xlate(struct device *dev,
        return instance->phy;
 }
 
-static struct phy_ops mt65xx_u3phy_ops = {
+static const struct phy_ops mt65xx_u3phy_ops = {
        .init           = mt65xx_phy_init,
        .exit           = mt65xx_phy_exit,
        .power_on       = mt65xx_phy_power_on,
index d505d98cf5f8187c1be36c93ca05ac5c7e510804..13b02b7de30b3f0e82d47ffbaa5824bf212a6f15 100644 (file)
@@ -77,7 +77,6 @@ struct ufs_qcom_phy_vreg {
        int min_uV;
        int max_uV;
        bool enabled;
-       bool is_always_on;
 };
 
 struct ufs_qcom_phy {
index c71c84734916c80f1a9a6600e9ad8fc533e637fd..12a1b498dc4b07850120dc03c8eca3bd9c7dcf46 100644 (file)
@@ -132,27 +132,18 @@ static int ufs_qcom_phy_qmp_14nm_probe(struct platform_device *pdev)
                                &ufs_qcom_phy_qmp_14nm_phy_ops, &phy_14nm_ops);
 
        if (!generic_phy) {
-               dev_err(dev, "%s: ufs_qcom_phy_generic_probe() failed\n",
-                       __func__);
                err = -EIO;
                goto out;
        }
 
        err = ufs_qcom_phy_init_clks(phy_common);
-       if (err) {
-               dev_err(phy_common->dev,
-                       "%s: ufs_qcom_phy_init_clks() failed %d\n",
-                       __func__, err);
+       if (err)
                goto out;
-       }
 
        err = ufs_qcom_phy_init_vregulators(phy_common);
-       if (err) {
-               dev_err(phy_common->dev,
-                       "%s: ufs_qcom_phy_init_vregulators() failed %d\n",
-                       __func__, err);
+       if (err)
                goto out;
-       }
+
        phy_common->vdda_phy.max_uV = UFS_PHY_VDDA_PHY_UV;
        phy_common->vdda_phy.min_uV = UFS_PHY_VDDA_PHY_UV;
 
index 1a26a64e06d34ffc9cbc48fc3067376f4b3fadc1..4f68acb58b7361e2f158cbb463907452b31f1485 100644 (file)
@@ -190,25 +190,17 @@ static int ufs_qcom_phy_qmp_20nm_probe(struct platform_device *pdev)
                                &ufs_qcom_phy_qmp_20nm_phy_ops, &phy_20nm_ops);
 
        if (!generic_phy) {
-               dev_err(dev, "%s: ufs_qcom_phy_generic_probe() failed\n",
-                       __func__);
                err = -EIO;
                goto out;
        }
 
        err = ufs_qcom_phy_init_clks(phy_common);
-       if (err) {
-               dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_clks() failed %d\n",
-                       __func__, err);
+       if (err)
                goto out;
-       }
 
        err = ufs_qcom_phy_init_vregulators(phy_common);
-       if (err) {
-               dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_vregulators() failed %d\n",
-                       __func__, err);
+       if (err)
                goto out;
-       }
 
        ufs_qcom_phy_qmp_20nm_advertise_quirks(phy_common);
 
index c69568b8543dcfaf4958875288cf9b13432169e5..43865ef340e210aa568465295ff4cb372467485b 100644 (file)
@@ -189,12 +189,12 @@ int ufs_qcom_phy_init_clks(struct ufs_qcom_phy *phy_common)
        if (err)
                goto out;
 
+skip_txrx_clk:
        err = ufs_qcom_phy_clk_get(phy_common->dev, "ref_clk_src",
                                   &phy_common->ref_clk_src);
        if (err)
                goto out;
 
-skip_txrx_clk:
        /*
         * "ref_clk_parent" is optional hence don't abort init if it's not
         * found.
@@ -210,25 +210,19 @@ out:
 }
 EXPORT_SYMBOL_GPL(ufs_qcom_phy_init_clks);
 
-static int __ufs_qcom_phy_init_vreg(struct device *dev,
-               struct ufs_qcom_phy_vreg *vreg, const char *name, bool optional)
+static int ufs_qcom_phy_init_vreg(struct device *dev,
+                                 struct ufs_qcom_phy_vreg *vreg,
+                                 const char *name)
 {
        int err = 0;
 
        char prop_name[MAX_PROP_NAME];
 
-       vreg->name = devm_kstrdup(dev, name, GFP_KERNEL);
-       if (!vreg->name) {
-               err = -ENOMEM;
-               goto out;
-       }
-
+       vreg->name = name;
        vreg->reg = devm_regulator_get(dev, name);
        if (IS_ERR(vreg->reg)) {
                err = PTR_ERR(vreg->reg);
-               vreg->reg = NULL;
-               if (!optional)
-                       dev_err(dev, "failed to get %s, %d\n", name, err);
+               dev_err(dev, "failed to get %s, %d\n", name, err);
                goto out;
        }
 
@@ -248,9 +242,6 @@ static int __ufs_qcom_phy_init_vreg(struct device *dev,
                        }
                        err = 0;
                }
-               snprintf(prop_name, MAX_PROP_NAME, "%s-always-on", name);
-               vreg->is_always_on = of_property_read_bool(dev->of_node,
-                                                          prop_name);
        }
 
        if (!strcmp(name, "vdda-pll")) {
@@ -265,17 +256,9 @@ static int __ufs_qcom_phy_init_vreg(struct device *dev,
        }
 
 out:
-       if (err)
-               kfree(vreg->name);
        return err;
 }
 
-static int ufs_qcom_phy_init_vreg(struct device *dev,
-                       struct ufs_qcom_phy_vreg *vreg, const char *name)
-{
-       return __ufs_qcom_phy_init_vreg(dev, vreg, name, false);
-}
-
 int ufs_qcom_phy_init_vregulators(struct ufs_qcom_phy *phy_common)
 {
        int err;
@@ -291,9 +274,9 @@ int ufs_qcom_phy_init_vregulators(struct ufs_qcom_phy *phy_common)
        if (err)
                goto out;
 
-       /* vddp-ref-clk-* properties are optional */
-       __ufs_qcom_phy_init_vreg(phy_common->dev, &phy_common->vddp_ref_clk,
-                                "vddp-ref-clk", true);
+       err = ufs_qcom_phy_init_vreg(phy_common->dev, &phy_common->vddp_ref_clk,
+                                    "vddp-ref-clk");
+
 out:
        return err;
 }
@@ -416,7 +399,7 @@ static int ufs_qcom_phy_disable_vreg(struct device *dev,
 {
        int ret = 0;
 
-       if (!vreg || !vreg->enabled || vreg->is_always_on)
+       if (!vreg || !vreg->enabled)
                goto out;
 
        ret = regulator_disable(vreg->reg);
diff --git a/drivers/phy/phy-qcom-usb-hs.c b/drivers/phy/phy-qcom-usb-hs.c
new file mode 100644 (file)
index 0000000..94dfbfd
--- /dev/null
@@ -0,0 +1,296 @@
+/**
+ * Copyright (C) 2016 Linaro Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/ulpi/driver.h>
+#include <linux/ulpi/regs.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/of_device.h>
+#include <linux/reset.h>
+#include <linux/extcon.h>
+#include <linux/notifier.h>
+
+#include "ulpi_phy.h"
+
+#define ULPI_PWR_CLK_MNG_REG           0x88
+# define ULPI_PWR_OTG_COMP_DISABLE     BIT(0)
+
+#define ULPI_MISC_A                    0x96
+# define ULPI_MISC_A_VBUSVLDEXTSEL     BIT(1)
+# define ULPI_MISC_A_VBUSVLDEXT                BIT(0)
+
+
+struct ulpi_seq {
+       u8 addr;
+       u8 val;
+};
+
+struct qcom_usb_hs_phy {
+       struct ulpi *ulpi;
+       struct phy *phy;
+       struct clk *ref_clk;
+       struct clk *sleep_clk;
+       struct regulator *v1p8;
+       struct regulator *v3p3;
+       struct reset_control *reset;
+       struct ulpi_seq *init_seq;
+       struct extcon_dev *vbus_edev;
+       struct notifier_block vbus_notify;
+};
+
+static int qcom_usb_hs_phy_set_mode(struct phy *phy, enum phy_mode mode)
+{
+       struct qcom_usb_hs_phy *uphy = phy_get_drvdata(phy);
+       u8 addr;
+       int ret;
+
+       if (!uphy->vbus_edev) {
+               u8 val = 0;
+
+               switch (mode) {
+               case PHY_MODE_USB_OTG:
+               case PHY_MODE_USB_HOST:
+                       val |= ULPI_INT_IDGRD;
+               case PHY_MODE_USB_DEVICE:
+                       val |= ULPI_INT_SESS_VALID;
+               default:
+                       break;
+               }
+
+               ret = ulpi_write(uphy->ulpi, ULPI_USB_INT_EN_RISE, val);
+               if (ret)
+                       return ret;
+               ret = ulpi_write(uphy->ulpi, ULPI_USB_INT_EN_FALL, val);
+       } else {
+               switch (mode) {
+               case PHY_MODE_USB_OTG:
+               case PHY_MODE_USB_DEVICE:
+                       addr = ULPI_SET(ULPI_MISC_A);
+                       break;
+               case PHY_MODE_USB_HOST:
+                       addr = ULPI_CLR(ULPI_MISC_A);
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               ret = ulpi_write(uphy->ulpi, ULPI_SET(ULPI_PWR_CLK_MNG_REG),
+                                ULPI_PWR_OTG_COMP_DISABLE);
+               if (ret)
+                       return ret;
+               ret = ulpi_write(uphy->ulpi, addr, ULPI_MISC_A_VBUSVLDEXTSEL);
+       }
+
+       return ret;
+}
+
+static int
+qcom_usb_hs_phy_vbus_notifier(struct notifier_block *nb, unsigned long event,
+                             void *ptr)
+{
+       struct qcom_usb_hs_phy *uphy;
+       u8 addr;
+
+       uphy = container_of(nb, struct qcom_usb_hs_phy, vbus_notify);
+
+       if (event)
+               addr = ULPI_SET(ULPI_MISC_A);
+       else
+               addr = ULPI_CLR(ULPI_MISC_A);
+
+       return ulpi_write(uphy->ulpi, addr, ULPI_MISC_A_VBUSVLDEXT);
+}
+
+static int qcom_usb_hs_phy_power_on(struct phy *phy)
+{
+       struct qcom_usb_hs_phy *uphy = phy_get_drvdata(phy);
+       struct ulpi *ulpi = uphy->ulpi;
+       const struct ulpi_seq *seq;
+       int ret, state;
+
+       ret = clk_prepare_enable(uphy->ref_clk);
+       if (ret)
+               return ret;
+
+       ret = clk_prepare_enable(uphy->sleep_clk);
+       if (ret)
+               goto err_sleep;
+
+       ret = regulator_set_load(uphy->v1p8, 50000);
+       if (ret < 0)
+               goto err_1p8;
+
+       ret = regulator_enable(uphy->v1p8);
+       if (ret)
+               goto err_1p8;
+
+       ret = regulator_set_voltage_triplet(uphy->v3p3, 3050000, 3300000,
+                                           3300000);
+       if (ret)
+               goto err_3p3;
+
+       ret = regulator_set_load(uphy->v3p3, 50000);
+       if (ret < 0)
+               goto err_3p3;
+
+       ret = regulator_enable(uphy->v3p3);
+       if (ret)
+               goto err_3p3;
+
+       for (seq = uphy->init_seq; seq->addr; seq++) {
+               ret = ulpi_write(ulpi, ULPI_EXT_VENDOR_SPECIFIC + seq->addr,
+                                seq->val);
+               if (ret)
+                       goto err_ulpi;
+       }
+
+       if (uphy->reset) {
+               ret = reset_control_reset(uphy->reset);
+               if (ret)
+                       goto err_ulpi;
+       }
+
+       if (uphy->vbus_edev) {
+               state = extcon_get_cable_state_(uphy->vbus_edev, EXTCON_USB);
+               /* setup initial state */
+               qcom_usb_hs_phy_vbus_notifier(&uphy->vbus_notify, state,
+                                             uphy->vbus_edev);
+               ret = extcon_register_notifier(uphy->vbus_edev, EXTCON_USB,
+                               &uphy->vbus_notify);
+               if (ret)
+                       goto err_ulpi;
+       }
+
+       return 0;
+err_ulpi:
+       regulator_disable(uphy->v3p3);
+err_3p3:
+       regulator_disable(uphy->v1p8);
+err_1p8:
+       clk_disable_unprepare(uphy->sleep_clk);
+err_sleep:
+       clk_disable_unprepare(uphy->ref_clk);
+       return ret;
+}
+
+static int qcom_usb_hs_phy_power_off(struct phy *phy)
+{
+       int ret;
+       struct qcom_usb_hs_phy *uphy = phy_get_drvdata(phy);
+
+       if (uphy->vbus_edev) {
+               ret = extcon_unregister_notifier(uphy->vbus_edev, EXTCON_USB,
+                                                &uphy->vbus_notify);
+               if (ret)
+                       return ret;
+       }
+
+       regulator_disable(uphy->v3p3);
+       regulator_disable(uphy->v1p8);
+       clk_disable_unprepare(uphy->sleep_clk);
+       clk_disable_unprepare(uphy->ref_clk);
+
+       return 0;
+}
+
+static const struct phy_ops qcom_usb_hs_phy_ops = {
+       .power_on = qcom_usb_hs_phy_power_on,
+       .power_off = qcom_usb_hs_phy_power_off,
+       .set_mode = qcom_usb_hs_phy_set_mode,
+       .owner = THIS_MODULE,
+};
+
+static int qcom_usb_hs_phy_probe(struct ulpi *ulpi)
+{
+       struct qcom_usb_hs_phy *uphy;
+       struct phy_provider *p;
+       struct clk *clk;
+       struct regulator *reg;
+       struct reset_control *reset;
+       int size;
+       int ret;
+
+       uphy = devm_kzalloc(&ulpi->dev, sizeof(*uphy), GFP_KERNEL);
+       if (!uphy)
+               return -ENOMEM;
+       ulpi_set_drvdata(ulpi, uphy);
+       uphy->ulpi = ulpi;
+
+       size = of_property_count_u8_elems(ulpi->dev.of_node, "qcom,init-seq");
+       if (size < 0)
+               size = 0;
+       uphy->init_seq = devm_kmalloc_array(&ulpi->dev, (size / 2) + 1,
+                                          sizeof(*uphy->init_seq), GFP_KERNEL);
+       if (!uphy->init_seq)
+               return -ENOMEM;
+       ret = of_property_read_u8_array(ulpi->dev.of_node, "qcom,init-seq",
+                                       (u8 *)uphy->init_seq, size);
+       if (ret && size)
+               return ret;
+       /* NUL terminate */
+       uphy->init_seq[size / 2].addr = uphy->init_seq[size / 2].val = 0;
+
+       uphy->ref_clk = clk = devm_clk_get(&ulpi->dev, "ref");
+       if (IS_ERR(clk))
+               return PTR_ERR(clk);
+
+       uphy->sleep_clk = clk = devm_clk_get(&ulpi->dev, "sleep");
+       if (IS_ERR(clk))
+               return PTR_ERR(clk);
+
+       uphy->v1p8 = reg = devm_regulator_get(&ulpi->dev, "v1p8");
+       if (IS_ERR(reg))
+               return PTR_ERR(reg);
+
+       uphy->v3p3 = reg = devm_regulator_get(&ulpi->dev, "v3p3");
+       if (IS_ERR(reg))
+               return PTR_ERR(reg);
+
+       uphy->reset = reset = devm_reset_control_get(&ulpi->dev, "por");
+       if (IS_ERR(reset)) {
+               if (PTR_ERR(reset) == -EPROBE_DEFER)
+                       return PTR_ERR(reset);
+               uphy->reset = NULL;
+       }
+
+       uphy->phy = devm_phy_create(&ulpi->dev, ulpi->dev.of_node,
+                                   &qcom_usb_hs_phy_ops);
+       if (IS_ERR(uphy->phy))
+               return PTR_ERR(uphy->phy);
+
+       uphy->vbus_edev = extcon_get_edev_by_phandle(&ulpi->dev, 0);
+       if (IS_ERR(uphy->vbus_edev)) {
+               if (PTR_ERR(uphy->vbus_edev) != -ENODEV)
+                       return PTR_ERR(uphy->vbus_edev);
+               uphy->vbus_edev = NULL;
+       }
+
+       uphy->vbus_notify.notifier_call = qcom_usb_hs_phy_vbus_notifier;
+       phy_set_drvdata(uphy->phy, uphy);
+
+       p = devm_of_phy_provider_register(&ulpi->dev, of_phy_simple_xlate);
+       return PTR_ERR_OR_ZERO(p);
+}
+
+static const struct of_device_id qcom_usb_hs_phy_match[] = {
+       { .compatible = "qcom,usb-hs-phy", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, qcom_usb_hs_phy_match);
+
+static struct ulpi_driver qcom_usb_hs_phy_driver = {
+       .probe = qcom_usb_hs_phy_probe,
+       .driver = {
+               .name = "qcom_usb_hs_phy",
+               .of_match_table = qcom_usb_hs_phy_match,
+       },
+};
+module_ulpi_driver(qcom_usb_hs_phy_driver);
+
+MODULE_DESCRIPTION("Qualcomm USB HS phy");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/phy-qcom-usb-hsic.c b/drivers/phy/phy-qcom-usb-hsic.c
new file mode 100644 (file)
index 0000000..47690f9
--- /dev/null
@@ -0,0 +1,160 @@
+/**
+ * Copyright (C) 2016 Linaro Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/ulpi/driver.h>
+#include <linux/ulpi/regs.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/pinctrl-state.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+
+#include "ulpi_phy.h"
+
+#define ULPI_HSIC_CFG          0x30
+#define ULPI_HSIC_IO_CAL       0x33
+
+struct qcom_usb_hsic_phy {
+       struct ulpi *ulpi;
+       struct phy *phy;
+       struct pinctrl *pctl;
+       struct clk *phy_clk;
+       struct clk *cal_clk;
+       struct clk *cal_sleep_clk;
+};
+
+static int qcom_usb_hsic_phy_power_on(struct phy *phy)
+{
+       struct qcom_usb_hsic_phy *uphy = phy_get_drvdata(phy);
+       struct ulpi *ulpi = uphy->ulpi;
+       struct pinctrl_state *pins_default;
+       int ret;
+
+       ret = clk_prepare_enable(uphy->phy_clk);
+       if (ret)
+               return ret;
+
+       ret = clk_prepare_enable(uphy->cal_clk);
+       if (ret)
+               goto err_cal;
+
+       ret = clk_prepare_enable(uphy->cal_sleep_clk);
+       if (ret)
+               goto err_sleep;
+
+       /* Set periodic calibration interval to ~2.048sec in HSIC_IO_CAL_REG */
+       ret = ulpi_write(ulpi, ULPI_HSIC_IO_CAL, 0xff);
+       if (ret)
+               goto err_ulpi;
+
+       /* Enable periodic IO calibration in HSIC_CFG register */
+       ret = ulpi_write(ulpi, ULPI_HSIC_CFG, 0xa8);
+       if (ret)
+               goto err_ulpi;
+
+       /* Configure pins for HSIC functionality */
+       pins_default = pinctrl_lookup_state(uphy->pctl, PINCTRL_STATE_DEFAULT);
+       if (IS_ERR(pins_default))
+               return PTR_ERR(pins_default);
+
+       ret = pinctrl_select_state(uphy->pctl, pins_default);
+       if (ret)
+               goto err_ulpi;
+
+        /* Enable HSIC mode in HSIC_CFG register */
+       ret = ulpi_write(ulpi, ULPI_SET(ULPI_HSIC_CFG), 0x01);
+       if (ret)
+               goto err_ulpi;
+
+       /* Disable auto-resume */
+       ret = ulpi_write(ulpi, ULPI_CLR(ULPI_IFC_CTRL),
+                        ULPI_IFC_CTRL_AUTORESUME);
+       if (ret)
+               goto err_ulpi;
+
+       return ret;
+err_ulpi:
+       clk_disable_unprepare(uphy->cal_sleep_clk);
+err_sleep:
+       clk_disable_unprepare(uphy->cal_clk);
+err_cal:
+       clk_disable_unprepare(uphy->phy_clk);
+       return ret;
+}
+
+static int qcom_usb_hsic_phy_power_off(struct phy *phy)
+{
+       struct qcom_usb_hsic_phy *uphy = phy_get_drvdata(phy);
+
+       clk_disable_unprepare(uphy->cal_sleep_clk);
+       clk_disable_unprepare(uphy->cal_clk);
+       clk_disable_unprepare(uphy->phy_clk);
+
+       return 0;
+}
+
+static const struct phy_ops qcom_usb_hsic_phy_ops = {
+       .power_on = qcom_usb_hsic_phy_power_on,
+       .power_off = qcom_usb_hsic_phy_power_off,
+       .owner = THIS_MODULE,
+};
+
+static int qcom_usb_hsic_phy_probe(struct ulpi *ulpi)
+{
+       struct qcom_usb_hsic_phy *uphy;
+       struct phy_provider *p;
+       struct clk *clk;
+
+       uphy = devm_kzalloc(&ulpi->dev, sizeof(*uphy), GFP_KERNEL);
+       if (!uphy)
+               return -ENOMEM;
+       ulpi_set_drvdata(ulpi, uphy);
+
+       uphy->ulpi = ulpi;
+       uphy->pctl = devm_pinctrl_get(&ulpi->dev);
+       if (IS_ERR(uphy->pctl))
+               return PTR_ERR(uphy->pctl);
+
+       uphy->phy_clk = clk = devm_clk_get(&ulpi->dev, "phy");
+       if (IS_ERR(clk))
+               return PTR_ERR(clk);
+
+       uphy->cal_clk = clk = devm_clk_get(&ulpi->dev, "cal");
+       if (IS_ERR(clk))
+               return PTR_ERR(clk);
+
+       uphy->cal_sleep_clk = clk = devm_clk_get(&ulpi->dev, "cal_sleep");
+       if (IS_ERR(clk))
+               return PTR_ERR(clk);
+
+       uphy->phy = devm_phy_create(&ulpi->dev, ulpi->dev.of_node,
+                                   &qcom_usb_hsic_phy_ops);
+       if (IS_ERR(uphy->phy))
+               return PTR_ERR(uphy->phy);
+       phy_set_drvdata(uphy->phy, uphy);
+
+       p = devm_of_phy_provider_register(&ulpi->dev, of_phy_simple_xlate);
+       return PTR_ERR_OR_ZERO(p);
+}
+
+static const struct of_device_id qcom_usb_hsic_phy_match[] = {
+       { .compatible = "qcom,usb-hsic-phy", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, qcom_usb_hsic_phy_match);
+
+static struct ulpi_driver qcom_usb_hsic_phy_driver = {
+       .probe = qcom_usb_hsic_phy_probe,
+       .driver = {
+               .name = "qcom_usb_hsic_phy",
+               .of_match_table = qcom_usb_hsic_phy_match,
+       },
+};
+module_ulpi_driver(qcom_usb_hsic_phy_driver);
+
+MODULE_DESCRIPTION("Qualcomm USB HSIC phy");
+MODULE_LICENSE("GPL v2");
index c63da1b955c17325881018bd912e742eff0018d9..afb4d048d3e984c5cc02e83b12a2b10d55bb561d 100644 (file)
@@ -94,11 +94,11 @@ static void rcar_gen3_phy_usb2_work(struct work_struct *work)
                                                 work);
 
        if (ch->extcon_host) {
-               extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, true);
-               extcon_set_cable_state_(ch->extcon, EXTCON_USB, false);
+               extcon_set_state_sync(ch->extcon, EXTCON_USB_HOST, true);
+               extcon_set_state_sync(ch->extcon, EXTCON_USB, false);
        } else {
-               extcon_set_cable_state_(ch->extcon, EXTCON_USB_HOST, false);
-               extcon_set_cable_state_(ch->extcon, EXTCON_USB, true);
+               extcon_set_state_sync(ch->extcon, EXTCON_USB_HOST, false);
+               extcon_set_state_sync(ch->extcon, EXTCON_USB, true);
        }
 }
 
@@ -350,7 +350,7 @@ static int rcar_gen3_phy_usb2_power_off(struct phy *p)
        return ret;
 }
 
-static struct phy_ops rcar_gen3_phy_usb2_ops = {
+static const struct phy_ops rcar_gen3_phy_usb2_ops = {
        .init           = rcar_gen3_phy_usb2_init,
        .exit           = rcar_gen3_phy_usb2_exit,
        .power_on       = rcar_gen3_phy_usb2_power_on,
index 2f99ec95079cd2bcd3419a2c38c38bf2a8dd25cd..4ea95c28a66f7eb7a36fabb973a65c566cf22812 100644 (file)
@@ -595,9 +595,14 @@ static void rockchip_usb2phy_otg_sm_work(struct work_struct *work)
                if (rport->vbus_attached != vbus_attach) {
                        rport->vbus_attached = vbus_attach;
 
-                       if (notify_charger && rphy->edev)
+                       if (notify_charger && rphy->edev) {
                                extcon_set_cable_state_(rphy->edev,
                                                        cable, vbus_attach);
+                               if (cable == EXTCON_CHG_USB_SDP)
+                                       extcon_set_state_sync(rphy->edev,
+                                                             EXTCON_USB,
+                                                             vbus_attach);
+                       }
                }
                break;
        case OTG_STATE_B_PERIPHERAL:
index bf28a0fdd569c56a6dc6f395925dfbf6e89903b2..a21b5f24a3406eef0438cdd6b3cb337784ebcbc0 100644 (file)
@@ -99,6 +99,7 @@ enum sun4i_usb_phy_type {
        sun6i_a31_phy,
        sun8i_a33_phy,
        sun8i_h3_phy,
+       sun8i_v3s_phy,
        sun50i_a64_phy,
 };
 
@@ -188,7 +189,8 @@ static void sun4i_usb_phy_write(struct sun4i_usb_phy *phy, u32 addr, u32 data,
        spin_lock_irqsave(&phy_data->reg_lock, flags);
 
        if (phy_data->cfg->type == sun8i_a33_phy ||
-           phy_data->cfg->type == sun50i_a64_phy) {
+           phy_data->cfg->type == sun50i_a64_phy ||
+           phy_data->cfg->type == sun8i_v3s_phy) {
                /* A33 or A64 needs us to set phyctl to 0 explicitly */
                writel(0, phyctl);
        }
@@ -534,7 +536,7 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work)
        mutex_unlock(&phy0->mutex);
 
        if (id_notify) {
-               extcon_set_cable_state_(data->extcon, EXTCON_USB_HOST,
+               extcon_set_state_sync(data->extcon, EXTCON_USB_HOST,
                                        !id_det);
                /* When leaving host mode force end the session here */
                if (force_session_end && id_det == 1) {
@@ -547,7 +549,7 @@ static void sun4i_usb_phy0_id_vbus_det_scan(struct work_struct *work)
        }
 
        if (vbus_notify)
-               extcon_set_cable_state_(data->extcon, EXTCON_USB, vbus_det);
+               extcon_set_state_sync(data->extcon, EXTCON_USB, vbus_det);
 
        if (sun4i_usb_phy0_poll(data))
                queue_delayed_work(system_wq, &data->detect, POLL_TIME);
@@ -825,6 +827,15 @@ static const struct sun4i_usb_phy_cfg sun8i_h3_cfg = {
        .enable_pmu_unk1 = true,
 };
 
+static const struct sun4i_usb_phy_cfg sun8i_v3s_cfg = {
+       .num_phys = 1,
+       .type = sun8i_v3s_phy,
+       .disc_thresh = 3,
+       .phyctl_offset = REG_PHYCTL_A33,
+       .dedicated_clocks = true,
+       .enable_pmu_unk1 = true,
+};
+
 static const struct sun4i_usb_phy_cfg sun50i_a64_cfg = {
        .num_phys = 2,
        .type = sun50i_a64_phy,
@@ -842,6 +853,7 @@ static const struct of_device_id sun4i_usb_phy_of_match[] = {
        { .compatible = "allwinner,sun8i-a23-usb-phy", .data = &sun8i_a23_cfg },
        { .compatible = "allwinner,sun8i-a33-usb-phy", .data = &sun8i_a33_cfg },
        { .compatible = "allwinner,sun8i-h3-usb-phy", .data = &sun8i_h3_cfg },
+       { .compatible = "allwinner,sun8i-v3s-usb-phy", .data = &sun8i_v3s_cfg },
        { .compatible = "allwinner,sun50i-a64-usb-phy",
          .data = &sun50i_a64_cfg},
        { },