From 155d9f65d3bf78cc7113475110c129dc0dbbdae1 Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Tue, 18 Jul 2017 11:57:12 +0200 Subject: [PATCH] usb: host: ohci-generic: add CLOCK support use array to save enabled clocks reference in order to disabled them in case of error during probe() or during driver removal. Signed-off-by: Patrice Chotard Reviewed-by: Simon Glass --- drivers/usb/host/ohci-generic.c | 55 +++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/drivers/usb/host/ohci-generic.c b/drivers/usb/host/ohci-generic.c index f85738fb05..f5b27ccf31 100644 --- a/drivers/usb/host/ohci-generic.c +++ b/drivers/usb/host/ohci-generic.c @@ -5,7 +5,9 @@ */ #include +#include #include +#include #include "ohci.h" #if !defined(CONFIG_USB_OHCI_NEW) @@ -14,18 +16,67 @@ struct generic_ohci { ohci_t ohci; + struct clk *clocks; /* clock list */ + int clock_count; /* number of clock in clock list */ }; static int ohci_usb_probe(struct udevice *dev) { struct ohci_regs *regs = (struct ohci_regs *)devfdt_get_addr(dev); + struct generic_ohci *priv = dev_get_priv(dev); + int i, err, ret, clock_nb; - return ohci_register(dev, regs); + err = 0; + priv->clock_count = 0; + clock_nb = dev_count_phandle_with_args(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) { + error("failed to enable clock %d\n", i); + clk_free(&priv->clocks[i]); + goto clk_err; + } + priv->clock_count++; + } + } else if (clock_nb != -ENOENT) { + error("failed to get clock phandle(%d)\n", clock_nb); + return clock_nb; + } + + err = ohci_register(dev, regs); + if (err) + goto clk_err; + + return 0; + +clk_err: + ret = clk_release_all(priv->clocks, priv->clock_count); + if (ret) + error("failed to disable all clocks\n"); + + return err; } static int ohci_usb_remove(struct udevice *dev) { - return ohci_deregister(dev); + struct generic_ohci *priv = dev_get_priv(dev); + int ret; + + ret = ohci_deregister(dev); + if (ret) + return ret; + + return clk_release_all(priv->clocks, priv->clock_count); } static const struct udevice_id ohci_usb_ids[] = {