On 05/17/2017 03:34 PM, patrice.chot...@st.com wrote: > 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);
Same comment as on 5/7 > + 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); > } > > -- Best regards, Marek Vasut _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot