summaryrefslogtreecommitdiff
path: root/drivers/phy
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/phy')
-rw-r--r--drivers/phy/Kconfig5
-rw-r--r--drivers/phy/Makefile1
-rw-r--r--drivers/phy/phy-rcar-gen3.c79
-rw-r--r--drivers/phy/starfive/Kconfig21
-rw-r--r--drivers/phy/starfive/Makefile7
-rw-r--r--drivers/phy/starfive/phy-jh7110-pcie.c239
-rw-r--r--drivers/phy/starfive/phy-jh7110-usb-syscon.h9
-rw-r--r--drivers/phy/starfive/phy-jh7110-usb2.c162
8 files changed, 507 insertions, 16 deletions
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index e12347e8a03..d3fe90d939e 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -163,8 +163,8 @@ config PHY_RCAR_GEN2
config PHY_RCAR_GEN3
tristate "Renesas R-Car Gen3 USB PHY"
- depends on PHY && RCAR_GEN3 && CLK && DM_REGULATOR
- default y if RCAR_GEN3
+ depends on PHY && CLK && DM_REGULATOR && (RCAR_GEN3 || RZG2L)
+ default y if (RCAR_GEN3 || RZG2L)
help
Support for the Renesas R-Car Gen3 USB PHY. This driver operates the
PHY connected to EHCI USB module and controls USB OTG operation.
@@ -309,5 +309,6 @@ source "drivers/phy/cadence/Kconfig"
source "drivers/phy/ti/Kconfig"
source "drivers/phy/qcom/Kconfig"
source "drivers/phy/renesas/Kconfig"
+source "drivers/phy/starfive/Kconfig"
endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index c35f9294dd9..ce4ea28b299 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -44,3 +44,4 @@ obj-y += cadence/
obj-y += ti/
obj-y += qcom/
obj-y += renesas/
+obj-y += starfive/
diff --git a/drivers/phy/phy-rcar-gen3.c b/drivers/phy/phy-rcar-gen3.c
index 8c004eaf4c6..d06861c4f79 100644
--- a/drivers/phy/phy-rcar-gen3.c
+++ b/drivers/phy/phy-rcar-gen3.c
@@ -55,6 +55,7 @@
/* VBCTRL */
#define USB2_VBCTRL_DRVVBUSSEL BIT(8)
+#define USB2_VBCTRL_VBOUT BIT(0)
/* LINECTRL1 */
#define USB2_LINECTRL1_DPRPD_EN BIT(19)
@@ -68,6 +69,13 @@
#define USB2_ADPCTRL_IDPULLUP BIT(5) /* 1 = ID sampling is enabled */
#define USB2_ADPCTRL_DRVVBUS BIT(4)
+/* RZ/G2L specific */
+#define USB2_OBINT_IDCHG_EN BIT(0)
+#define USB2_LINECTRL1_USB2_IDMON BIT(0)
+
+/* Device flags */
+#define RCAR_GEN3_PHY_NO_ADPCTRL BIT(0)
+
struct rcar_gen3_phy {
fdt_addr_t regs;
struct clk clk;
@@ -122,15 +130,50 @@ static int rcar_gen3_phy_phy_power_off(struct phy *phy)
return regulator_set_enable(priv->vbus_supply, false);
}
+static bool rcar_gen3_phy_check_id(struct phy *phy)
+{
+ const u32 adpdevmask = USB2_ADPCTRL_IDDIG | USB2_ADPCTRL_OTGSESSVLD;
+ struct rcar_gen3_phy *priv = dev_get_priv(phy->dev);
+ ulong flags = dev_get_driver_data(phy->dev);
+ u32 val;
+
+ if (flags & RCAR_GEN3_PHY_NO_ADPCTRL) {
+ val = readl(priv->regs + USB2_LINECTRL1);
+ return !!(val & USB2_LINECTRL1_USB2_IDMON);
+ }
+
+ val = readl(priv->regs + USB2_ADPCTRL);
+ return (val & adpdevmask) == adpdevmask;
+}
+
+static void rcar_gen3_phy_set_vbus(struct phy *phy, bool enable)
+{
+ struct rcar_gen3_phy *priv = dev_get_priv(phy->dev);
+ ulong flags = dev_get_driver_data(phy->dev);
+ u32 bits = USB2_ADPCTRL_DRVVBUS;
+ u64 reg = USB2_ADPCTRL;
+
+ if (flags & RCAR_GEN3_PHY_NO_ADPCTRL) {
+ bits = USB2_VBCTRL_VBOUT;
+ reg = USB2_VBCTRL;
+ }
+
+ if (enable)
+ setbits_le32(priv->regs + reg, bits);
+ else
+ clrbits_le32(priv->regs + reg, bits);
+}
+
static int rcar_gen3_phy_phy_set_mode(struct phy *phy, enum phy_mode mode,
int submode)
{
- const u32 adpdevmask = USB2_ADPCTRL_IDDIG | USB2_ADPCTRL_OTGSESSVLD;
struct rcar_gen3_phy *priv = dev_get_priv(phy->dev);
- u32 adpctrl;
+ ulong flags = dev_get_driver_data(phy->dev);
if (mode == PHY_MODE_USB_OTG) {
if (submode) {
+ u32 obint_enable_bits;
+
/* OTG submode is used as initialization indicator */
writel(USB2_INT_ENABLE_UCOM_INTEN |
USB2_INT_ENABLE_USBH_INTB_EN |
@@ -138,13 +181,16 @@ static int rcar_gen3_phy_phy_set_mode(struct phy *phy, enum phy_mode mode,
priv->regs + USB2_INT_ENABLE);
setbits_le32(priv->regs + USB2_VBCTRL,
USB2_VBCTRL_DRVVBUSSEL);
- writel(USB2_OBINT_SESSVLDCHG | USB2_OBINT_IDDIGCHG,
- priv->regs + USB2_OBINTSTA);
- setbits_le32(priv->regs + USB2_OBINTEN,
- USB2_OBINT_SESSVLDCHG |
- USB2_OBINT_IDDIGCHG);
- setbits_le32(priv->regs + USB2_ADPCTRL,
- USB2_ADPCTRL_IDPULLUP);
+ if (flags & RCAR_GEN3_PHY_NO_ADPCTRL) {
+ obint_enable_bits = USB2_OBINT_IDCHG_EN;
+ } else {
+ obint_enable_bits = USB2_OBINT_SESSVLDCHG |
+ USB2_OBINT_IDDIGCHG;
+ setbits_le32(priv->regs + USB2_ADPCTRL,
+ USB2_ADPCTRL_IDPULLUP);
+ }
+ writel(obint_enable_bits, priv->regs + USB2_OBINTSTA);
+ setbits_le32(priv->regs + USB2_OBINTEN, obint_enable_bits);
clrsetbits_le32(priv->regs + USB2_LINECTRL1,
USB2_LINECTRL1_DP_RPD |
USB2_LINECTRL1_DM_RPD |
@@ -154,8 +200,7 @@ static int rcar_gen3_phy_phy_set_mode(struct phy *phy, enum phy_mode mode,
USB2_LINECTRL1_DMRPD_EN);
}
- adpctrl = readl(priv->regs + USB2_ADPCTRL);
- if ((adpctrl & adpdevmask) == adpdevmask)
+ if (rcar_gen3_phy_check_id(phy))
mode = PHY_MODE_USB_DEVICE;
else
mode = PHY_MODE_USB_HOST;
@@ -165,13 +210,13 @@ static int rcar_gen3_phy_phy_set_mode(struct phy *phy, enum phy_mode mode,
clrbits_le32(priv->regs + USB2_COMMCTRL, USB2_COMMCTRL_OTG_PERI);
setbits_le32(priv->regs + USB2_LINECTRL1,
USB2_LINECTRL1_DP_RPD | USB2_LINECTRL1_DM_RPD);
- setbits_le32(priv->regs + USB2_ADPCTRL, USB2_ADPCTRL_DRVVBUS);
+ rcar_gen3_phy_set_vbus(phy, true);
} else if (mode == PHY_MODE_USB_DEVICE) {
setbits_le32(priv->regs + USB2_COMMCTRL, USB2_COMMCTRL_OTG_PERI);
clrsetbits_le32(priv->regs + USB2_LINECTRL1,
USB2_LINECTRL1_DP_RPD | USB2_LINECTRL1_DM_RPD,
USB2_LINECTRL1_DM_RPD);
- clrbits_le32(priv->regs + USB2_ADPCTRL, USB2_ADPCTRL_DRVVBUS);
+ rcar_gen3_phy_set_vbus(phy, false);
} else {
dev_err(phy->dev, "Unknown mode %d\n", mode);
return -EINVAL;
@@ -226,7 +271,13 @@ static int rcar_gen3_phy_remove(struct udevice *dev)
}
static const struct udevice_id rcar_gen3_phy_of_match[] = {
- { .compatible = "renesas,rcar-gen3-usb2-phy", },
+ {
+ .compatible = "renesas,rcar-gen3-usb2-phy",
+ },
+ {
+ .compatible = "renesas,rzg2l-usb2-phy",
+ .data = RCAR_GEN3_PHY_NO_ADPCTRL,
+ },
{ },
};
diff --git a/drivers/phy/starfive/Kconfig b/drivers/phy/starfive/Kconfig
new file mode 100644
index 00000000000..d11338ed484
--- /dev/null
+++ b/drivers/phy/starfive/Kconfig
@@ -0,0 +1,21 @@
+#
+# PHY drivers for Starfive platforms
+#
+
+menu "Starfive PHY driver"
+
+config PHY_STARFIVE_JH7110_PCIE
+ bool "Starfive JH7110 PCIe 2.0 PHY driver"
+ depends on PHY
+ help
+ Enable this to support the Starfive JH7110 PCIE 2.0/USB 3.0 PHY.
+ Generic PHY driver JH7110 USB 3.0/ PCIe 2.0.
+
+config PHY_STARFIVE_JH7110_USB2
+ bool "Starfive JH7110 USB 2.0 PHY driver"
+ depends on PHY
+ help
+ Enable this to support the Starfive JH7110 USB 2.0 PHY.
+ Generic PHY driver JH7110 USB 2.0.
+
+endmenu
diff --git a/drivers/phy/starfive/Makefile b/drivers/phy/starfive/Makefile
new file mode 100644
index 00000000000..82f25aa21b7
--- /dev/null
+++ b/drivers/phy/starfive/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2023 Starfive
+#
+
+obj-$(CONFIG_PHY_STARFIVE_JH7110_PCIE) += phy-jh7110-pcie.o
+obj-$(CONFIG_PHY_STARFIVE_JH7110_USB2) += phy-jh7110-usb2.o
diff --git a/drivers/phy/starfive/phy-jh7110-pcie.c b/drivers/phy/starfive/phy-jh7110-pcie.c
new file mode 100644
index 00000000000..a30582821d9
--- /dev/null
+++ b/drivers/phy/starfive/phy-jh7110-pcie.c
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * StarFive JH7110 PCIe 2.0 PHY driver
+ *
+ * Copyright (C) 2024 StarFive Technology Co., Ltd.
+ * Author: Minda Chen <minda.chen@starfivetech.com>
+ */
+#include <asm/io.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <errno.h>
+#include <generic-phy.h>
+#include <regmap.h>
+#include <soc.h>
+#include <syscon.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+
+#include "phy-jh7110-usb-syscon.h"
+
+#define PCIE_KVCO_LEVEL_OFF 0x28
+#define PCIE_USB3_PHY_PLL_CTL_OFF 0x7c
+#define PCIE_USB3_PHY_SS_MODE BIT(4)
+#define PCIE_KVCO_TUNE_SIGNAL_OFF 0x80
+#define PHY_KVCO_FINE_TUNE_LEVEL 0x91
+#define PHY_KVCO_FINE_TUNE_SIGNALS 0xc
+
+#define PCIE_USB3_PHY_MODE 0x1
+#define PCIE_BUS_WIDTH 0x2
+#define PCIE_USB3_PHY_ENABLE 0x1
+#define PCIE_USB3_PHY_SPLIT 0x1
+
+struct jh7110_pcie_phy {
+ struct phy *phy;
+ struct regmap *stg_syscon;
+ struct regmap *sys_syscon;
+ void __iomem *regs;
+ struct regmap_field *phy_mode;
+ struct regmap_field *bus_width;
+ struct regmap_field *usb3_phy_en;
+ struct regmap_field *usb_split;
+ enum phy_mode mode;
+};
+
+static int phy_pcie_mode_set(struct jh7110_pcie_phy *data, bool usb_mode)
+{
+ unsigned int phy_mode, width, usb3_phy, ss_mode, split;
+
+ /* default is PCIe mode */
+ if (!data->stg_syscon || !data->sys_syscon) {
+ if (usb_mode) {
+ dev_err(data->phy->dev, "doesn't support USB3 mode\n");
+ return -EINVAL;
+ }
+ return 0;
+ }
+
+ if (usb_mode) {
+ phy_mode = PCIE_USB3_PHY_MODE;
+ width = 0;
+ usb3_phy = PCIE_USB3_PHY_ENABLE;
+ ss_mode = PCIE_USB3_PHY_SS_MODE;
+ split = 0;
+ } else {
+ phy_mode = 0;
+ width = PCIE_BUS_WIDTH;
+ usb3_phy = 0;
+ ss_mode = 0;
+ split = PCIE_USB3_PHY_SPLIT;
+ }
+
+ regmap_field_write(data->phy_mode, phy_mode);
+ regmap_field_write(data->bus_width, width);
+ regmap_field_write(data->usb3_phy_en, usb3_phy);
+ clrsetbits_le32(data->regs + PCIE_USB3_PHY_PLL_CTL_OFF,
+ PCIE_USB3_PHY_SS_MODE, ss_mode);
+ regmap_field_write(data->usb_split, split);
+
+ return 0;
+}
+
+static void phy_kvco_gain_set(struct jh7110_pcie_phy *phy)
+{
+ /* PCIe Multi-PHY PLL KVCO Gain fine tune settings: */
+ writel(PHY_KVCO_FINE_TUNE_LEVEL, phy->regs + PCIE_KVCO_LEVEL_OFF);
+ writel(PHY_KVCO_FINE_TUNE_SIGNALS, phy->regs + PCIE_KVCO_TUNE_SIGNAL_OFF);
+}
+
+static int jh7110_pcie_phy_set_mode(struct phy *phy,
+ enum phy_mode mode, int submode)
+{
+ struct udevice *dev = phy->dev;
+ struct jh7110_pcie_phy *pcie_phy = dev_get_priv(dev);
+ int ret;
+
+ if (mode == pcie_phy->mode)
+ return 0;
+
+ switch (mode) {
+ case PHY_MODE_USB_HOST:
+ case PHY_MODE_USB_DEVICE:
+ case PHY_MODE_USB_OTG:
+ ret = phy_pcie_mode_set(pcie_phy, 1);
+ if (ret)
+ return ret;
+ break;
+ case PHY_MODE_PCIE:
+ phy_pcie_mode_set(pcie_phy, 0);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ dev_dbg(phy->dev, "Changing PHY mode to %d\n", mode);
+ pcie_phy->mode = mode;
+
+ return 0;
+}
+
+static const struct phy_ops jh7110_pcie_phy_ops = {
+ .set_mode = jh7110_pcie_phy_set_mode,
+};
+
+static int phy_stg_regfield_init(struct udevice *dev, int mode, int usb3)
+{
+ struct jh7110_pcie_phy *phy = dev_get_priv(dev);
+ struct reg_field phy_mode = REG_FIELD(mode, 20, 21);
+ struct reg_field bus_width = REG_FIELD(usb3, 2, 3);
+ struct reg_field usb3_phy_en = REG_FIELD(usb3, 4, 4);
+
+ phy->phy_mode = devm_regmap_field_alloc(dev, phy->stg_syscon, phy_mode);
+ if (IS_ERR(phy->phy_mode)) {
+ dev_err(dev, "PHY mode reg field init failed\n");
+ return PTR_ERR(phy->phy_mode);
+ }
+
+ phy->bus_width = devm_regmap_field_alloc(dev, phy->stg_syscon, bus_width);
+ if (IS_ERR(phy->bus_width)) {
+ dev_err(dev, "PHY bus width reg field init failed\n");
+ return PTR_ERR(phy->bus_width);
+ }
+
+ phy->usb3_phy_en = devm_regmap_field_alloc(dev, phy->stg_syscon, usb3_phy_en);
+ if (IS_ERR(phy->usb3_phy_en)) {
+ dev_err(dev, "USB3 PHY enable field init failed\n");
+ return PTR_ERR(phy->bus_width);
+ }
+
+ return 0;
+}
+
+static int phy_sys_regfield_init(struct udevice *dev, int split)
+{
+ struct jh7110_pcie_phy *phy = dev_get_priv(dev);
+ struct reg_field usb_split = REG_FIELD(split, USB_PDRSTN_SPLIT_BIT, USB_PDRSTN_SPLIT_BIT);
+
+ phy->usb_split = devm_regmap_field_alloc(dev, phy->sys_syscon, usb_split);
+ if (IS_ERR(phy->usb_split)) {
+ dev_err(dev, "USB split field init failed\n");
+ return PTR_ERR(phy->usb_split);
+ }
+
+ return 0;
+}
+
+static int starfive_pcie_phy_get_syscon(struct udevice *dev)
+{
+ struct jh7110_pcie_phy *phy = dev_get_priv(dev);
+ struct ofnode_phandle_args sys_phandle, stg_phandle;
+ int ret;
+
+ /* get corresponding syscon phandle */
+ ret = dev_read_phandle_with_args(dev, "starfive,sys-syscon", NULL, 1, 0,
+ &sys_phandle);
+
+ if (ret < 0) {
+ dev_err(dev, "Can't get sys cfg phandle: %d\n", ret);
+ return ret;
+ }
+
+ ret = dev_read_phandle_with_args(dev, "starfive,stg-syscon", NULL, 2, 0,
+ &stg_phandle);
+
+ if (ret < 0) {
+ dev_err(dev, "Can't get stg cfg phandle: %d\n", ret);
+ return ret;
+ }
+
+ phy->sys_syscon = syscon_node_to_regmap(sys_phandle.node);
+ /* get syscon register offset */
+ if (!IS_ERR(phy->sys_syscon)) {
+ ret = phy_sys_regfield_init(dev, SYSCON_USB_PDRSTN_REG_OFFSET);
+ if (ret)
+ return ret;
+ } else {
+ phy->sys_syscon = NULL;
+ }
+
+ phy->stg_syscon = syscon_node_to_regmap(stg_phandle.node);
+ if (!IS_ERR(phy->stg_syscon))
+ return phy_stg_regfield_init(dev, stg_phandle.args[0],
+ stg_phandle.args[1]);
+ else
+ phy->stg_syscon = NULL;
+
+ return 0;
+}
+
+int jh7110_pcie_phy_probe(struct udevice *dev)
+{
+ struct jh7110_pcie_phy *phy = dev_get_priv(dev);
+ int rc;
+
+ phy->regs = dev_read_addr_ptr(dev);
+ if (!phy->regs)
+ return -EINVAL;
+
+ rc = starfive_pcie_phy_get_syscon(dev);
+ if (rc)
+ return rc;
+
+ phy_kvco_gain_set(phy);
+
+ return 0;
+}
+
+static const struct udevice_id jh7110_pcie_phy[] = {
+ { .compatible = "starfive,jh7110-pcie-phy"},
+ {},
+};
+
+U_BOOT_DRIVER(jh7110_pcie_phy) = {
+ .name = "jh7110_pcie_phy",
+ .id = UCLASS_PHY,
+ .of_match = jh7110_pcie_phy,
+ .probe = jh7110_pcie_phy_probe,
+ .ops = &jh7110_pcie_phy_ops,
+ .priv_auto = sizeof(struct jh7110_pcie_phy),
+};
diff --git a/drivers/phy/starfive/phy-jh7110-usb-syscon.h b/drivers/phy/starfive/phy-jh7110-usb-syscon.h
new file mode 100644
index 00000000000..0eb66f0d859
--- /dev/null
+++ b/drivers/phy/starfive/phy-jh7110-usb-syscon.h
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef PHY_JH7110_USB_SYSCON_H_
+#define PHY_JH7110_USB_SYSCON_H_
+
+#define SYSCON_USB_PDRSTN_REG_OFFSET 0x18
+#define USB_PDRSTN_SPLIT_BIT 17
+
+#endif
diff --git a/drivers/phy/starfive/phy-jh7110-usb2.c b/drivers/phy/starfive/phy-jh7110-usb2.c
new file mode 100644
index 00000000000..1a28381e0df
--- /dev/null
+++ b/drivers/phy/starfive/phy-jh7110-usb2.c
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * StarFive JH7110 USB 2.0 PHY driver
+ *
+ * Copyright (C) 2024 StarFive Technology Co., Ltd.
+ * Author: Minda Chen <minda.chen@starfivetech.com>
+ */
+
+#include <asm/io.h>
+#include <clk.h>
+#include <dm.h>
+#include <dm/device_compat.h>
+#include <errno.h>
+#include <generic-phy.h>
+#include <regmap.h>
+#include <soc.h>
+#include <syscon.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+
+#include "phy-jh7110-usb-syscon.h"
+
+#define USB_LS_KEEPALIVE_OFF 0x4
+#define USB_LS_KEEPALIVE_ENABLE BIT(4)
+#define USB_PHY_CLK_RATE 125000000
+
+struct jh7110_usb2_phy {
+ struct phy *phy;
+ struct regmap *sys_syscon;
+ void __iomem *regs;
+ struct clk *usb_125m_clk;
+ struct clk *app_125m;
+ struct regmap_field *usb_split;
+ enum phy_mode mode;
+};
+
+static void usb2_set_ls_keepalive(struct jh7110_usb2_phy *phy, bool set)
+{
+ /* Host mode enable the LS speed keep-alive signal */
+ clrsetbits_le32(phy->regs + USB_LS_KEEPALIVE_OFF,
+ USB_LS_KEEPALIVE_ENABLE,
+ set ? USB_LS_KEEPALIVE_ENABLE : 0);
+}
+
+static int usb2_phy_set_mode(struct phy *phy,
+ enum phy_mode mode, int submode)
+{
+ struct udevice *dev = phy->dev;
+ struct jh7110_usb2_phy *usb2_phy = dev_get_priv(dev);
+
+ if (mode == usb2_phy->mode)
+ return 0;
+
+ switch (mode) {
+ case PHY_MODE_USB_HOST:
+ case PHY_MODE_USB_DEVICE:
+ case PHY_MODE_USB_OTG:
+ dev_dbg(dev, "Changing PHY to %d\n", mode);
+ usb2_phy->mode = mode;
+ usb2_set_ls_keepalive(usb2_phy, (mode != PHY_MODE_USB_DEVICE));
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* set default split usb 2.0 only mode */
+ regmap_field_write(usb2_phy->usb_split, true);
+
+ return 0;
+}
+
+static int jh7110_usb2_phy_init(struct phy *phy)
+{
+ struct udevice *dev = phy->dev;
+ struct jh7110_usb2_phy *usb2_phy = dev_get_priv(dev);
+ int ret;
+
+ ret = clk_set_rate(usb2_phy->usb_125m_clk, USB_PHY_CLK_RATE);
+ if (ret < 0) {
+ dev_err(dev, "Failed to set 125m clock\n");
+ return ret;
+ }
+
+ return clk_prepare_enable(usb2_phy->app_125m);
+}
+
+static int jh7110_usb2_phy_exit(struct phy *phy)
+{
+ struct udevice *dev = phy->dev;
+ struct jh7110_usb2_phy *usb2_phy = dev_get_priv(dev);
+
+ clk_disable_unprepare(usb2_phy->app_125m);
+
+ return 0;
+}
+
+struct phy_ops jh7110_usb2_phy_ops = {
+ .init = jh7110_usb2_phy_init,
+ .exit = jh7110_usb2_phy_exit,
+ .set_mode = usb2_phy_set_mode,
+};
+
+int jh7110_usb2_phy_probe(struct udevice *dev)
+{
+ struct jh7110_usb2_phy *phy = dev_get_priv(dev);
+ ofnode node;
+ struct reg_field usb_split;
+ int ret;
+
+ phy->regs = dev_read_addr_ptr(dev);
+ if (!phy->regs)
+ return -EINVAL;
+
+ node = ofnode_by_compatible(ofnode_null(), "starfive,jh7110-sys-syscon");
+ if (!ofnode_valid(node)) {
+ dev_err(dev, "Can't get syscon dev node\n");
+ return -ENODEV;
+ }
+
+ phy->sys_syscon = syscon_node_to_regmap(node);
+ if (IS_ERR(phy->sys_syscon)) {
+ dev_err(dev, "Can't get syscon regmap: %d\n", ret);
+ return PTR_ERR(phy->sys_syscon);
+ }
+
+ usb_split.reg = SYSCON_USB_PDRSTN_REG_OFFSET;
+ usb_split.lsb = USB_PDRSTN_SPLIT_BIT;
+ usb_split.msb = USB_PDRSTN_SPLIT_BIT;
+ phy->usb_split = devm_regmap_field_alloc(dev, phy->sys_syscon, usb_split);
+ if (IS_ERR(phy->usb_split)) {
+ dev_err(dev, "USB split field init failed\n");
+ return PTR_ERR(phy->usb_split);
+ }
+
+ phy->usb_125m_clk = devm_clk_get(dev, "125m");
+ if (IS_ERR(phy->usb_125m_clk)) {
+ dev_err(dev, "Failed to get 125m clock\n");
+ return PTR_ERR(phy->usb_125m_clk);
+ }
+
+ phy->app_125m = devm_clk_get(dev, "app_125m");
+ if (IS_ERR(phy->app_125m)) {
+ dev_err(dev, "Failed to get app 125m clock\n");
+ return PTR_ERR(phy->app_125m);
+ }
+
+ return 0;
+}
+
+static const struct udevice_id jh7110_usb2_phy[] = {
+ { .compatible = "starfive,jh7110-usb-phy"},
+ {},
+};
+
+U_BOOT_DRIVER(jh7110_usb2_phy) = {
+ .name = "jh7110_usb2_phy",
+ .id = UCLASS_PHY,
+ .of_match = jh7110_usb2_phy,
+ .probe = jh7110_usb2_phy_probe,
+ .ops = &jh7110_usb2_phy_ops,
+ .priv_auto = sizeof(struct jh7110_usb2_phy),
+};