From: Patrice Chotard <patrice.chot...@st.com> use list to save reference to deasserted resets in order to assert them in case of error during probe() or during driver removal.
Signed-off-by: Patrice Chotard <patrice.chot...@st.com> --- v3: _ extract in this patch the RESET support add-on from previous patch 5 _ keep deassrted resets reference in list in order to assert resets in error path or in .remove callback v2: _ add error path management _ add .remove callback drivers/usb/host/ohci-generic.c | 78 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/drivers/usb/host/ohci-generic.c b/drivers/usb/host/ohci-generic.c index a6d89a8..bf14ab7 100644 --- a/drivers/usb/host/ohci-generic.c +++ b/drivers/usb/host/ohci-generic.c @@ -7,6 +7,7 @@ #include <common.h> #include <clk.h> #include <dm.h> +#include <reset.h> #include "ohci.h" #if !defined(CONFIG_USB_OHCI_NEW) @@ -18,11 +19,43 @@ struct ohci_clock { struct list_head list; }; +struct ohci_reset { + struct reset_ctl *reset; + struct list_head list; +}; + struct generic_ohci { ohci_t ohci; struct list_head clks; + struct list_head resets; }; +static int ohci_release_resets(struct generic_ohci *priv) +{ + struct ohci_reset *ohci_reset, *tmp; + struct reset_ctl *reset; + int ret; + + list_for_each_entry_safe(ohci_reset, tmp, &priv->resets, list) { + reset = ohci_reset->reset; + + ret = reset_request(reset); + if (ret) + return ret; + + ret = reset_assert(reset); + if (ret) + return ret; + + ret = reset_free(reset); + if (ret) + return ret; + + list_del(&(ohci_reset->list)); + } + return 0; +} + static int ohci_release_clocks(struct generic_ohci *priv) { struct ohci_clock *ohci_clock, *tmp; @@ -54,6 +87,7 @@ static int ohci_usb_probe(struct udevice *dev) int i, ret; INIT_LIST_HEAD(&priv->clks); + INIT_LIST_HEAD(&priv->resets); for (i = 0; ; i++) { struct ohci_clock *ohci_clock; @@ -89,8 +123,48 @@ static int ohci_usb_probe(struct udevice *dev) list_add(&ohci_clock->list, &priv->clks); } + for (i = 0; ; i++) { + struct ohci_reset *ohci_reset; + struct reset_ctl *reset; + + reset = devm_kmalloc(dev, sizeof(*reset), GFP_KERNEL); + if (!reset) { + error("Can't allocate resource\n"); + goto clk_err; + } + + 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); + goto reset_err; + } + reset_free(reset); + + /* + * add deasserted resets into resets list in order to be + * asserted later on ohci_usb_remove() call or in error + * path if needed + */ + ohci_reset = devm_kmalloc(dev, sizeof(*ohci_reset), GFP_KERNEL); + if (!ohci_reset) { + error("Can't allocate resource\n"); + goto reset_err; + } + ohci_reset->reset = reset; + list_add(&ohci_reset->list, &priv->resets); + } + + return ohci_register(dev, regs); +reset_err: + ret = ohci_release_resets(priv); + if (ret) + return ret; clk_err: return ohci_release_clocks(priv); } @@ -104,6 +178,10 @@ static int ohci_usb_remove(struct udevice *dev) if (ret) return ret; + ret = ohci_release_resets(priv); + if (ret) + return ret; + return ohci_release_clocks(priv); } -- 1.9.1 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot