[U-Boot] [PATCH v6 07/11] usb: host: ehci-generic: add error path and .remove callback
patrice.chotard at st.com
patrice.chotard at st.com
Mon Jun 5 09:42:07 UTC 2017
From: Patrice Chotard <patrice.chotard at st.com>
Use an array to save enabled clocks reference and deasserted resets
in order to respectively disabled and asserted them in case of error
during probe() or during driver removal.
Signed-off-by: Patrice Chotard <patrice.chotard at st.com>
Reviewed-by: Simon Glass <sjg at chromium.org>
---
v6: _ none
v5: _ none
v4: _ update the memory allocation for deasserted resets and enabled
clocks reference list. Replace lists by arrays.
_ usage of new RESET and CLOCK methods clk_count(), reset_count(),
reset_assert_all() and clk_disable_all().
v3: _ keep enabled clocks and deasserted resets reference in list in order to
disable clock or assert resets in error path or in .remove callback
_ use struct generic_ehci * instead of struct udevice * as parameter for
ehci_release_resets() and ehci_release_clocks()
drivers/usb/host/ehci-generic.c | 114 +++++++++++++++++++++++++++++++---------
1 file changed, 90 insertions(+), 24 deletions(-)
diff --git a/drivers/usb/host/ehci-generic.c b/drivers/usb/host/ehci-generic.c
index 2116ae1..1250d59 100644
--- a/drivers/usb/host/ehci-generic.c
+++ b/drivers/usb/host/ehci-generic.c
@@ -18,43 +18,109 @@
*/
struct generic_ehci {
struct ehci_ctrl ctrl;
+ struct clk *clocks;
+ struct reset_ctl *resets;
+ int clock_count;
+ int reset_count;
};
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 clk clk;
- int ret;
-
- ret = clk_get_by_index(dev, i, &clk);
- if (ret < 0)
- break;
- if (clk_enable(&clk))
- error("failed to enable clock %d\n", i);
- clk_free(&clk);
- }
+ int i, err, ret, clock_nb, reset_nb;
+
+ err = 0;
+ priv->clock_count = 0;
+ clock_nb = clk_count(dev);
+
+ if (clock_nb) {
+ priv->clocks = devm_kmalloc(dev, sizeof(struct clk) * clock_nb,
+ GFP_KERNEL);
+ if (!priv->clocks) {
+ error("Can't allocate resource\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < clock_nb; i++) {
+ err = clk_get_by_index(dev, i, &priv->clocks[i]);
+
+ if (err < 0)
+ break;
- for (i = 0; ; i++) {
- struct reset_ctl reset;
- int ret;
+ priv->clock_count++;
- ret = reset_get_by_index(dev, i, &reset);
- if (ret < 0)
- break;
- if (reset_deassert(&reset))
- error("failed to deassert reset %d\n", i);
- reset_free(&reset);
+ if (clk_enable(&priv->clocks[i])) {
+ error("failed to enable clock %d\n", i);
+ clk_free(&priv->clocks[i]);
+ goto clk_err;
+ }
+ clk_free(&priv->clocks[i]);
+ }
}
+ priv->reset_count = 0;
+ reset_nb = reset_count(dev);
+
+ if (reset_nb) {
+ priv->resets = devm_kmalloc(dev,
+ sizeof(struct reset_ctl) * reset_nb,
+ GFP_KERNEL);
+ if (!priv->resets) {
+ error("Can't allocate resource\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < reset_nb; i++) {
+ err = reset_get_by_index(dev, i, &priv->resets[i]);
+ if (err < 0)
+ break;
+
+ priv->reset_count++;
+
+ if (reset_deassert(&priv->resets[i])) {
+ error("failed to deassert reset %d\n", i);
+ reset_free(&priv->resets[i]);
+ goto reset_err;
+ }
+ reset_free(&priv->resets[i]);
+ }
+ }
hccr = map_physmem(devfdt_get_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)
+ return err;
+
+reset_err:
+ ret = reset_assert_all(priv->resets, priv->reset_count);
+ if (ret)
+ return ret;
+clk_err:
+ ret = clk_disable_all(priv->clocks, priv->clock_count);
+ if (ret)
+ return ret;
+
+ return err;
+}
+
+static int ehci_usb_remove(struct udevice *dev)
+{
+ struct generic_ehci *priv = dev_get_priv(dev);
+ int ret;
+
+ ret = ehci_deregister(dev);
+ if (ret)
+ return ret;
+
+ ret = reset_assert_all(priv->resets, priv->reset_count);
+ if (ret)
+ return ret;
+
+ return clk_disable_all(priv->clocks, priv->clock_count);
}
static const struct udevice_id ehci_usb_ids[] = {
@@ -67,7 +133,7 @@ U_BOOT_DRIVER(ehci_generic) = {
.id = UCLASS_USB,
.of_match = ehci_usb_ids,
.probe = ehci_usb_probe,
- .remove = ehci_deregister,
+ .remove = ehci_usb_remove,
.ops = &ehci_usb_ops,
.priv_auto_alloc_size = sizeof(struct generic_ehci),
.flags = DM_FLAG_ALLOC_PRIV_DMA,
--
1.9.1
More information about the U-Boot
mailing list