
On 05/17/2017 03:34 PM, patrice.chotard@st.com wrote:
From: Patrice Chotard patrice.chotard@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.chotard@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);
}