Răsfoiți Sursa

[DM/PHYE] Support USB generic PHYE.

Signed-off-by: GuEe-GUI <2991707448@qq.com>
GuEe-GUI 1 lună în urmă
părinte
comite
09b6099701

+ 9 - 0
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

+ 3 - 0
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')

+ 232 - 0
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);