From 9406f9735c998a179d8ecc886ad7d5287473222f Mon Sep 17 00:00:00 2001 From: Patrick Delaunay Date: Tue, 26 Apr 2022 14:37:48 +0200 Subject: phy: stm32-usbphyc: usbphyc is a clock provider of ck_usbo_48m clock ck_usbo_48m is generated by usbphyc PLL and used by OTG controller for Full-Speed use cases with dedicated Full-Speed transceiver. ck_usbo_48m is available as soon as the PLL is enabled. Signed-off-by: Patrick Delaunay Reviewed-by: Patrice Chotard --- drivers/phy/phy-stm32-usbphyc.c | 79 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/drivers/phy/phy-stm32-usbphyc.c b/drivers/phy/phy-stm32-usbphyc.c index bb743fe16f..9f0b7d7118 100644 --- a/drivers/phy/phy-stm32-usbphyc.c +++ b/drivers/phy/phy-stm32-usbphyc.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -17,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -72,6 +74,9 @@ #define PLL_INFF_MIN_RATE 19200000 /* in Hz */ #define PLL_INFF_MAX_RATE 38400000 /* in Hz */ +/* USBPHYC_CLK48 */ +#define USBPHYC_CLK48_FREQ 48000000 /* in Hz */ + enum boosting_vals { BOOST_1000_UA = 1000, BOOST_2000_UA = 2000, @@ -518,6 +523,16 @@ static const struct phy_ops stm32_usbphyc_phy_ops = { .of_xlate = stm32_usbphyc_of_xlate, }; +static int stm32_usbphyc_bind(struct udevice *dev) +{ + int ret; + + ret = device_bind_driver_to_node(dev, "stm32-usbphyc-clk", "ck_usbo_48m", + dev_ofnode(dev), NULL); + + return log_ret(ret); +} + static int stm32_usbphyc_probe(struct udevice *dev) { struct stm32_usbphyc *usbphyc = dev_get_priv(dev); @@ -611,6 +626,70 @@ U_BOOT_DRIVER(stm32_usb_phyc) = { .id = UCLASS_PHY, .of_match = stm32_usbphyc_of_match, .ops = &stm32_usbphyc_phy_ops, + .bind = stm32_usbphyc_bind, .probe = stm32_usbphyc_probe, .priv_auto = sizeof(struct stm32_usbphyc), }; + +struct stm32_usbphyc_clk { + bool enable; +}; + +static ulong stm32_usbphyc_clk48_get_rate(struct clk *clk) +{ + return USBPHYC_CLK48_FREQ; +} + +static int stm32_usbphyc_clk48_enable(struct clk *clk) +{ + struct stm32_usbphyc_clk *usbphyc_clk = dev_get_priv(clk->dev); + struct stm32_usbphyc *usbphyc; + int ret; + + if (usbphyc_clk->enable) + return 0; + + usbphyc = dev_get_priv(clk->dev->parent); + + /* ck_usbo_48m is generated by usbphyc PLL */ + ret = stm32_usbphyc_pll_enable(usbphyc); + if (ret) + return ret; + + usbphyc_clk->enable = true; + + return 0; +} + +static int stm32_usbphyc_clk48_disable(struct clk *clk) +{ + struct stm32_usbphyc_clk *usbphyc_clk = dev_get_priv(clk->dev); + struct stm32_usbphyc *usbphyc; + int ret; + + if (!usbphyc_clk->enable) + return 0; + + usbphyc = dev_get_priv(clk->dev->parent); + + ret = stm32_usbphyc_pll_disable(usbphyc); + if (ret) + return ret; + + usbphyc_clk->enable = false; + + return 0; +} + +const struct clk_ops usbphyc_clk48_ops = { + .get_rate = stm32_usbphyc_clk48_get_rate, + .enable = stm32_usbphyc_clk48_enable, + .disable = stm32_usbphyc_clk48_disable, +}; + +U_BOOT_DRIVER(stm32_usb_phyc_clk) = { + .name = "stm32-usbphyc-clk", + .id = UCLASS_CLK, + .ops = &usbphyc_clk48_ops, + .priv_auto = sizeof(struct stm32_usbphyc_clk), +}; -- cgit v1.2.3