summaryrefslogtreecommitdiff
path: root/components/drivers
diff options
context:
space:
mode:
authorGuEe-GUI <[email protected]>2025-12-01 17:09:08 +0800
committerR b b666 <[email protected]>2025-12-08 17:00:08 +0800
commit09b60997010985419be7a3e97d25114e86a2e7a2 (patch)
treeb9914a774d304ece6d3a5aab450159527bafcc9c /components/drivers
parentf7b3a8fedd26eabda69ea55cb8577833d89a4f70 (diff)
[DM/PHYE] Support USB generic PHYE.
Signed-off-by: GuEe-GUI <[email protected]>
Diffstat (limited to 'components/drivers')
-rw-r--r--components/drivers/phye/Kconfig9
-rw-r--r--components/drivers/phye/SConscript3
-rw-r--r--components/drivers/phye/phye-generic-usb.c232
3 files changed, 244 insertions, 0 deletions
diff --git a/components/drivers/phye/Kconfig b/components/drivers/phye/Kconfig
index c6672eee43..89a5d8997e 100644
--- a/components/drivers/phye/Kconfig
+++ b/components/drivers/phye/Kconfig
@@ -6,6 +6,15 @@ menuconfig RT_USING_PHYE
This framework will be of use only to devices that use
external PHY (PHY functionality is not embedded within the controller).
+config RT_PHYE_GENERIC_USB
+ bool "Generic USB"
+ depends on RT_USING_PHYE
+ help
+ Enable support for generic USB PHY devices that follow the
+ "usb-nop-xceiv" device tree binding. This driver provides basic
+ PHY operations including reset, power management, and clock control
+ for USB PHY hardware.
+
if RT_USING_PHYE
osource "$(SOC_DM_PHYE_DIR)/Kconfig"
endif
diff --git a/components/drivers/phye/SConscript b/components/drivers/phye/SConscript
index 23deafed7c..5c5fbb08e6 100644
--- a/components/drivers/phye/SConscript
+++ b/components/drivers/phye/SConscript
@@ -10,6 +10,9 @@ CPPPATH = [cwd + '/../include']
src = ['phye.c']
+if GetDepend(['RT_PHYE_GENERIC_USB']):
+ src += ['phye-generic-usb.c']
+
group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
Return('group')
diff --git a/components/drivers/phye/phye-generic-usb.c b/components/drivers/phye/phye-generic-usb.c
new file mode 100644
index 0000000000..a2fe44f13d
--- /dev/null
+++ b/components/drivers/phye/phye-generic-usb.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-10-24 GuEe-GUI first version
+ */
+
+#include <rtdevice.h>
+#include <rtthread.h>
+
+#define DBG_TAG "phye.generic.usb"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+struct generic_usb_phy
+{
+ struct rt_phye parent;
+
+ rt_base_t rst_pin;
+ rt_uint8_t rst_active_val;
+
+ struct rt_clk *clk;
+ struct rt_regulator *vcc;
+ struct rt_regulator *vbus;
+};
+
+#define raw_to_generic_usb_phy(raw) rt_container_of(raw, struct generic_usb_phy, parent)
+
+static rt_err_t generic_usb_phy_reset(struct rt_phye *phye)
+{
+ struct generic_usb_phy *usb_phy = raw_to_generic_usb_phy(phye);
+
+ if (usb_phy->rst_pin == PIN_NONE)
+ {
+ return RT_EOK;
+ }
+
+ rt_pin_mode(usb_phy->rst_pin, PIN_MODE_OUTPUT);
+
+ rt_pin_write(usb_phy->rst_pin, usb_phy->rst_active_val);
+ rt_hw_us_delay(15000);
+
+ rt_pin_write(usb_phy->rst_pin, !usb_phy->rst_active_val);
+ rt_hw_us_delay(20000);
+
+ return RT_EOK;
+}
+
+static rt_err_t generic_usb_phy_power_on(struct rt_phye *phye)
+{
+ rt_err_t err;
+ struct generic_usb_phy *usb_phy = raw_to_generic_usb_phy(phye);
+
+ if (usb_phy->vcc && (err = rt_regulator_enable(usb_phy->vcc)))
+ {
+ return err;
+ }
+
+ if ((err = rt_clk_prepare_enable(usb_phy->clk)))
+ {
+ if (usb_phy->vcc)
+ {
+ rt_regulator_disable(usb_phy->vcc);
+ }
+
+ return err;
+ }
+
+ return generic_usb_phy_reset(phye);
+}
+
+static rt_err_t generic_usb_phy_power_off(struct rt_phye *phye)
+{
+ rt_err_t err;
+ struct generic_usb_phy *usb_phy = raw_to_generic_usb_phy(phye);
+
+ if (usb_phy->vcc && (err = rt_regulator_disable(usb_phy->vcc)))
+ {
+ return err;
+ }
+
+ rt_clk_disable_unprepare(usb_phy->clk);
+
+ return RT_EOK;
+}
+
+static const struct rt_phye_ops generic_usb_phy_ops =
+{
+ .reset = generic_usb_phy_reset,
+ .power_on = generic_usb_phy_power_on,
+ .power_off = generic_usb_phy_power_off,
+};
+
+static void generic_usb_phy_free(struct generic_usb_phy *usb_phy)
+{
+ if (!rt_is_err_or_null(usb_phy->clk))
+ {
+ rt_clk_put(usb_phy->clk);
+ }
+
+ if (!rt_is_err_or_null(usb_phy->vcc))
+ {
+ rt_regulator_put(usb_phy->vcc);
+ }
+
+ if (!rt_is_err_or_null(usb_phy->vbus))
+ {
+ rt_regulator_put(usb_phy->vbus);
+ }
+
+ rt_free(usb_phy);
+}
+
+static rt_err_t generic_usb_phy_probe(struct rt_platform_device *pdev)
+{
+ rt_err_t err;
+ rt_uint32_t rate;
+ struct rt_phye *phy;
+ struct rt_device *dev = &pdev->parent;
+ struct generic_usb_phy *usb_phy = rt_calloc(1, sizeof(*usb_phy));
+
+ if (!usb_phy)
+ {
+ return -RT_ENOMEM;
+ }
+
+ usb_phy->rst_pin = rt_pin_get_named_pin(dev, "reset", 0,
+ RT_NULL, &usb_phy->rst_active_val);
+
+ if (usb_phy->rst_pin < 0 && usb_phy->rst_pin != PIN_NONE)
+ {
+ err = usb_phy->rst_pin;
+ goto _fail;
+ }
+
+ usb_phy->clk = rt_clk_get_by_name(dev, "main_clk");
+
+ if (rt_is_err(usb_phy->clk))
+ {
+ err = rt_ptr_err(usb_phy->clk);
+ goto _fail;
+ }
+
+ if (!rt_dm_dev_prop_read_u32(dev, "clock-frequency", &rate))
+ {
+ if ((err = rt_clk_set_rate(usb_phy->clk, rate)))
+ {
+ goto _fail;
+ }
+ }
+
+ usb_phy->vcc = rt_regulator_get(dev, "vcc");
+
+ if (rt_is_err(usb_phy->vcc))
+ {
+ err = rt_ptr_err(usb_phy->vcc);
+ goto _fail;
+ }
+
+ usb_phy->vbus = rt_regulator_get(dev, "vbus");
+
+ if (rt_is_err(usb_phy->vbus))
+ {
+ err = rt_ptr_err(usb_phy->vbus);
+ goto _fail;
+ }
+
+ if (usb_phy->vbus && (err = rt_regulator_enable(usb_phy->vbus)))
+ {
+ goto _fail;
+ }
+
+ dev->user_data = usb_phy;
+
+ phy = &usb_phy->parent;
+ phy->dev = dev;
+ phy->ops = &generic_usb_phy_ops;
+
+ if ((err = rt_phye_register(phy)))
+ {
+ goto _fail;
+ }
+
+ return RT_EOK;
+
+_fail:
+ generic_usb_phy_free(usb_phy);
+
+ return err;
+}
+
+static rt_err_t generic_usb_phy_remove(struct rt_platform_device *pdev)
+{
+ struct generic_usb_phy *usb_phy = pdev->parent.user_data;
+
+ rt_phye_unregister(&usb_phy->parent);
+
+ if (usb_phy->vbus)
+ {
+ rt_regulator_disable(usb_phy->vbus);
+ }
+
+ generic_usb_phy_free(usb_phy);
+
+ return RT_EOK;
+}
+
+static const struct rt_ofw_node_id generic_usb_phy_ofw_ids[] =
+{
+ { .compatible = "usb-nop-xceiv" },
+ { /* sentinel */ }
+};
+
+static struct rt_platform_driver generic_usb_phy_driver =
+{
+ .name = "phy-generic-usb",
+ .ids = generic_usb_phy_ofw_ids,
+
+ .probe = generic_usb_phy_probe,
+ .remove = generic_usb_phy_remove,
+};
+
+static int generic_usb_phy_drv_register(void)
+{
+ rt_platform_driver_register(&generic_usb_phy_driver);
+
+ return 0;
+}
+INIT_PLATFORM_EXPORT(generic_usb_phy_drv_register);