Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions components/drivers/phye/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Comment thread
GuEe-GUI marked this conversation as resolved.
if RT_USING_PHYE
osource "$(SOC_DM_PHYE_DIR)/Kconfig"
endif
3 changes: 3 additions & 0 deletions components/drivers/phye/SConscript
Original file line number Diff line number Diff line change
Expand Up @@ -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')
232 changes: 232 additions & 0 deletions components/drivers/phye/phye-generic-usb.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
/*

Copilot AI Dec 2, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 [PR Title/PR 标题]: Title format does not follow RT-Thread standards / 标题格式不符合 RT-Thread 标准

English: The PR title should follow the format: [module][subsystem] Description in lowercase. The current title uses uppercase "DM/PHYE" instead of lowercase, and the description is not specific enough.

Current title: [DM/PHYE] Support USB generic PHYE.
Suggested title: [drivers][phye] Add generic USB PHY driver

中文: PR 标题应遵循格式:小写的 [模块][子系统] 描述。当前标题使用了大写的 "DM/PHYE" 而非小写,且描述不够具体。

当前标题:[DM/PHYE] Support USB generic PHYE.
建议标题:[drivers][phye] Add generic USB PHY driver

Copilot generated this review using guidance from repository custom instructions.
Comment thread
GuEe-GUI marked this conversation as resolved.
* 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"
Comment thread
GuEe-GUI marked this conversation as resolved.
#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);

Comment thread
GuEe-GUI marked this conversation as resolved.
rt_pin_write(usb_phy->rst_pin, !usb_phy->rst_active_val);
rt_hw_us_delay(20000);
Comment on lines +44 to +47

Copilot AI Dec 2, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟠 [Performance/性能]: Using busy-wait delays in reset function / 复位函数中使用忙等待延迟

English: The generic_usb_phy_reset function uses rt_hw_us_delay() for delays of 15ms and 20ms (15000μs and 20000μs). These are busy-wait delays that block the CPU. For an RTOS like RT-Thread, this is inefficient and can impact system real-time performance. Consider using rt_thread_mdelay() instead, which allows other threads to run during the delay.

中文: generic_usb_phy_reset 函数使用 rt_hw_us_delay() 进行 15ms 和 20ms(15000μs 和 20000μs)的延迟。这些是阻塞 CPU 的忙等待延迟。对于像 RT-Thread 这样的 RTOS,这是低效的,会影响系统实时性能。考虑使用 rt_thread_mdelay(),它允许其他线程在延迟期间运行。

Suggested fix / 建议修复:

rt_pin_write(nop->rst_pin, nop->rst_active_val);
rt_thread_mdelay(15);  /* Use thread delay instead of busy-wait */

rt_pin_write(nop->rst_pin, !nop->rst_active_val);
rt_thread_mdelay(20);
Suggested change
rt_hw_us_delay(15000);
rt_pin_write(nop->rst_pin, !nop->rst_active_val);
rt_hw_us_delay(20000);
rt_thread_mdelay(15); /* Use thread delay instead of busy-wait */
rt_pin_write(nop->rst_pin, !nop->rst_active_val);
rt_thread_mdelay(20);

Copilot uses AI. Check for mistakes.

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)))
{
Comment thread
GuEe-GUI marked this conversation as resolved.
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);