Files
rt-thread/components/drivers/phye/phye-generic-usb.c
GuEe-GUI 09b6099701 [DM/PHYE] Support USB generic PHYE.
Signed-off-by: GuEe-GUI <2991707448@qq.com>
2025-12-08 17:00:08 +08:00

233 lines
4.7 KiB
C

/*
* 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);