X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=drivers%2Fusb%2Fhost%2Fehci-generic.c;h=0926986d27372f653faa502beba9e8701668b798;hb=20f06a48332d8dec255e3e808c3c97bb3222c2fd;hp=4444988e36fcace0566c8d99529cabf6b4969f1c;hpb=05195b2cbe5e8bd6df164503a4da9c84a7fe066f;p=u-boot diff --git a/drivers/usb/host/ehci-generic.c b/drivers/usb/host/ehci-generic.c index 4444988e36..0926986d27 100644 --- a/drivers/usb/host/ehci-generic.c +++ b/drivers/usb/host/ehci-generic.c @@ -6,6 +6,9 @@ #include #include +#include +#include +#include #include #include #include "ehci.h" @@ -17,36 +20,179 @@ */ struct generic_ehci { struct ehci_ctrl ctrl; + struct clk *clocks; + struct reset_ctl *resets; + struct phy phy; + int clock_count; + int reset_count; }; +static int ehci_setup_phy(struct udevice *dev, int index) +{ + struct generic_ehci *priv = dev_get_priv(dev); + int ret; + + ret = generic_phy_get_by_index(dev, index, &priv->phy); + if (ret) { + if (ret != -ENOENT) { + dev_err(dev, "failed to get usb phy\n"); + return ret; + } + } else { + ret = generic_phy_init(&priv->phy); + if (ret) { + dev_err(dev, "failed to init usb phy\n"); + return ret; + } + + ret = generic_phy_power_on(&priv->phy); + if (ret) { + dev_err(dev, "failed to power on usb phy\n"); + return generic_phy_exit(&priv->phy); + } + } + + return 0; +} + +static int ehci_shutdown_phy(struct udevice *dev) +{ + struct generic_ehci *priv = dev_get_priv(dev); + int ret = 0; + + if (generic_phy_valid(&priv->phy)) { + ret = generic_phy_power_off(&priv->phy); + if (ret) { + dev_err(dev, "failed to power off usb phy\n"); + return ret; + } + + ret = generic_phy_exit(&priv->phy); + if (ret) { + dev_err(dev, "failed to power off usb phy\n"); + return ret; + } + } + + return 0; +} + static int ehci_usb_probe(struct udevice *dev) { + struct generic_ehci *priv = dev_get_priv(dev); struct ehci_hccr *hccr; struct ehci_hcor *hcor; - int i; - - for (i = 0; ; i++) { - struct udevice *clk_dev; - int clk_id; - - clk_id = clk_get_by_index(dev, i, &clk_dev); - if (clk_id < 0) - break; - if (clk_enable(clk_dev, clk_id)) - printf("failed to enable clock (dev=%s, id=%d)\n", - clk_dev->name, clk_id); + int i, err, ret, clock_nb, reset_nb; + + err = 0; + priv->clock_count = 0; + clock_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "clocks", + "#clock-cells"); + if (clock_nb > 0) { + priv->clocks = devm_kcalloc(dev, clock_nb, sizeof(struct clk), + GFP_KERNEL); + if (!priv->clocks) + return -ENOMEM; + + for (i = 0; i < clock_nb; i++) { + err = clk_get_by_index(dev, i, &priv->clocks[i]); + + if (err < 0) + break; + err = clk_enable(&priv->clocks[i]); + if (err) { + pr_err("failed to enable clock %d\n", i); + clk_free(&priv->clocks[i]); + goto clk_err; + } + priv->clock_count++; + } + } else { + if (clock_nb != -ENOENT) { + pr_err("failed to get clock phandle(%d)\n", clock_nb); + return clock_nb; + } + } + + priv->reset_count = 0; + reset_nb = ofnode_count_phandle_with_args(dev_ofnode(dev), "resets", + "#reset-cells"); + if (reset_nb > 0) { + priv->resets = devm_kcalloc(dev, reset_nb, + sizeof(struct reset_ctl), + GFP_KERNEL); + if (!priv->resets) + return -ENOMEM; + + for (i = 0; i < reset_nb; i++) { + err = reset_get_by_index(dev, i, &priv->resets[i]); + if (err < 0) + break; + + if (reset_deassert(&priv->resets[i])) { + pr_err("failed to deassert reset %d\n", i); + reset_free(&priv->resets[i]); + goto reset_err; + } + priv->reset_count++; + } + } else { + if (reset_nb != -ENOENT) { + pr_err("failed to get reset phandle(%d)\n", reset_nb); + goto clk_err; + } } - hccr = map_physmem(dev_get_addr(dev), 0x100, MAP_NOCACHE); + err = ehci_setup_phy(dev, 0); + if (err) + + goto reset_err; + + hccr = map_physmem(dev_read_addr(dev), 0x100, MAP_NOCACHE); hcor = (struct ehci_hcor *)((uintptr_t)hccr + HC_LENGTH(ehci_readl(&hccr->cr_capbase))); - return ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST); + err = ehci_register(dev, hccr, hcor, NULL, 0, USB_INIT_HOST); + if (err) + goto phy_err; + + return 0; + +phy_err: + ret = ehci_shutdown_phy(dev); + if (ret) + dev_err(dev, "failed to shutdown usb phy\n"); + +reset_err: + ret = reset_release_all(priv->resets, priv->reset_count); + if (ret) + pr_err("failed to assert all resets\n"); +clk_err: + ret = clk_release_all(priv->clocks, priv->clock_count); + if (ret) + pr_err("failed to disable all clocks\n"); + + return err; } static int ehci_usb_remove(struct udevice *dev) { - return ehci_deregister(dev); + struct generic_ehci *priv = dev_get_priv(dev); + int ret; + + ret = ehci_deregister(dev); + if (ret) + return ret; + + ret = ehci_shutdown_phy(dev); + if (ret) + return ret; + + ret = reset_release_all(priv->resets, priv->reset_count); + if (ret) + return ret; + + return clk_release_all(priv->clocks, priv->clock_count); } static const struct udevice_id ehci_usb_ids[] = {