/* * 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 #include #define DBG_TAG "phye.generic.usb" #define DBG_LVL DBG_INFO #include 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);