On 29/07/2024 08:15, hpchen0 wrote: > Nuvoton MA35 SoCs support DWC2 USB controller. > Add the driver to drive the USB 2.0 PHY transceivers. > > Signed-off-by: hpchen0 <hpchen0nvt@xxxxxxxxx> > + > + ret = clk_prepare_enable(p_phy->clk); > + if (ret < 0) { > + dev_err(p_phy->dev, "Failed to enable PHY clock: %d\n", ret); > + return ret; > + } > + > + regmap_read(p_phy->sysreg, MA35_SYS_REG_USBPMISCR, &val); > + if (val & PHY0SUSPEND) { > + /* > + * USB PHY0 is in operation mode already > + * make sure USB PHY 60 MHz UTMI Interface Clock ready > + */ > + timeout = jiffies + msecs_to_jiffies(200); > + while (time_before(jiffies, timeout)) { > + regmap_read(p_phy->sysreg, MA35_SYS_REG_USBPMISCR, &val); > + if (val & PHY0DEVCKSTB) > + return 0; > + usleep_range(1000, 1500); > + } You want some readl_poll_timeout version here. > + } > + > + /* > + * reset USB PHY0. > + * wait until USB PHY0 60 MHz UTMI Interface Clock ready > + */ > + regmap_update_bits(p_phy->sysreg, MA35_SYS_REG_USBPMISCR, 0x7, (PHY0POR | PHY0SUSPEND)); > + timeout = jiffies + msecs_to_jiffies(200); > + while (time_before(jiffies, timeout)) { > + regmap_read(p_phy->sysreg, MA35_SYS_REG_USBPMISCR, &val); > + if (val & PHY0DEVCKSTB) > + break; > + usleep_range(1000, 1500); > + } > + > + /* make USB PHY0 enter operation mode */ > + regmap_update_bits(p_phy->sysreg, MA35_SYS_REG_USBPMISCR, 0x7, PHY0SUSPEND); > + > + /* make sure USB PHY 60 MHz UTMI Interface Clock ready */ > + timeout = jiffies + msecs_to_jiffies(200); > + while (time_before(jiffies, timeout)) { > + regmap_read(p_phy->sysreg, MA35_SYS_REG_USBPMISCR, &val); > + if (val & PHY0DEVCKSTB) > + return 0; > + usleep_range(1000, 1500); > + } > + > + dev_err(p_phy->dev, "Timed out waiting for PHY to power on\n"); > + ret = -ETIMEDOUT; > + > + clk_disable_unprepare(p_phy->clk); > + return ret; > +} > + > +static int ma35_usb_phy_power_off(struct phy *phy) > +{ > + struct ma35_usb_phy *p_phy = phy_get_drvdata(phy); > + > + clk_disable_unprepare(p_phy->clk); > + return 0; > +} > + > +static const struct phy_ops ma35_usb_phy_ops = { > + .power_on = ma35_usb_phy_power_on, > + .power_off = ma35_usb_phy_power_off, > + .owner = THIS_MODULE, > +}; > + > +static int ma35_usb_phy_probe(struct platform_device *pdev) > +{ > + struct phy_provider *provider; > + struct ma35_usb_phy *p_phy; > + const char *clkgate; > + struct phy *phy; > + > + p_phy = devm_kzalloc(&pdev->dev, sizeof(*p_phy), GFP_KERNEL); > + if (!p_phy) > + return -ENOMEM; > + > + p_phy->dev = &pdev->dev; > + platform_set_drvdata(pdev, p_phy); > + > + p_phy->sysreg = syscon_regmap_lookup_by_phandle(p_phy->dev->of_node, "nuvoton,sys"); > + if (IS_ERR(p_phy->sysreg)) > + return dev_err_probe(&pdev->dev, PTR_ERR(p_phy->sysreg), > + "Failed to get SYS registers\n"); > + > + /* enable clock */ > + of_property_read_string(p_phy->dev->of_node, "clock-enable", &clkgate); There is no such property. > + p_phy->clk = devm_clk_get(p_phy->dev, clkgate); Don't mix styles of variables: you were using pdev->dev but now entirely different. Stick to pdev->dev. > + if (IS_ERR(p_phy->clk)) > + return dev_err_probe(&pdev->dev, PTR_ERR(p_phy->clk), And here again pdev->dev... Bring some consistency, not random coding style. > + "Failed to get usb_phy clock\n"); > + Best regards, Krzysztof