Message ID | 1494610077-21721-6-git-send-email-patrice.chotard@st.com |
---|---|
State | Superseded |
Delegated to: | Marek Vasut |
Headers | show |
On 12 May 2017 at 11:27, <patrice.chotard@st.com> wrote: > From: Patrice Chotard <patrice.chotard@st.com> > > Add CLOCK, RESET and generic PHY frameworks support > > Signed-off-by: Patrice Chotard <patrice.chotard@st.com> > --- > > v2: _ add error path management > _ add .remove callback > > drivers/usb/host/ohci-generic.c | 99 +++++++++++++++++++++++++++++++++++++++-- > 1 file changed, 96 insertions(+), 3 deletions(-) > > diff --git a/drivers/usb/host/ohci-generic.c b/drivers/usb/host/ohci-generic.c > index f3307f4..f86e223 100644 > --- a/drivers/usb/host/ohci-generic.c > +++ b/drivers/usb/host/ohci-generic.c > @@ -5,26 +5,119 @@ > */ > > #include <common.h> > +#include <clk.h> > #include <dm.h> > +#include <fdtdec.h> > +#include <generic-phy.h> > +#include <reset.h> > + > #include "ohci.h" > > #if !defined(CONFIG_USB_OHCI_NEW) > # error "Generic OHCI driver requires CONFIG_USB_OHCI_NEW" > #endif > > +#define OHCI_MAX_CLOCKS 3 > +#define OHCI_MAX_RESETS 3 > + > struct generic_ohci { > ohci_t ohci; > + struct clk clks[OHCI_MAX_CLOCKS]; > + struct reset_ctl resets[OHCI_MAX_RESETS]; > + struct phy phy; > }; > > +static void ohci_assert_resets(struct udevice *dev) { > + struct generic_ohci *priv = dev_get_priv(dev); > + struct reset_ctl reset; > + int i; > + > + for (i = OHCI_MAX_RESETS; i >= 0; --i) { > + reset = priv->resets[i]; > + > + if (reset.dev) { > + reset_request(&reset); > + reset_assert(&reset); > + reset_free(&reset); Don't you need error checking here? > + } > + } > +} > + > +static void ohci_disable_clocks(struct udevice *dev) { > + struct generic_ohci *priv = dev_get_priv(dev); > + struct clk clk; > + int i; > + > + for (i = OHCI_MAX_CLOCKS; i >= 0; --i) { > + clk = priv->clks[i]; > + > + if (clk.dev) { > + clk_request(clk.dev, &clk); > + clk_disable(&clk); > + clk_free(&clk); > + } > + } > +} > + > static int ohci_usb_probe(struct udevice *dev) > { > struct ohci_regs *regs = (struct ohci_regs *)dev_get_addr(dev); > + struct generic_ohci *priv = dev_get_priv(dev); > + int i, ret; > + > + for (i = 0; i < OHCI_MAX_CLOCKS; i++) { > + struct clk clk = priv->clks[i]; > > - return ohci_register(dev, regs); > + 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); > + goto clk_err; > + } > + clk_free(&clk); > + } > + > + for (i = 0; i < OHCI_MAX_RESETS ; i++) { > + struct reset_ctl reset = priv->resets[i]; > + > + 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); > + } > + > + if (!generic_phy_get_by_index(dev, 0, &priv->phy)) > + if (generic_phy_init(&priv->phy)) > + error("failed to init usb phy %d\n", i); > + > + ret = ohci_register(dev, regs); > + if (!ret) > + return ret; > + > + generic_phy_exit(&priv->phy); > + > +reset_err: > + ohci_assert_resets(dev); > +clk_err: > + ohci_disable_clocks(dev); > + > + return ret; > } > > -static int ohci_usb_remove(struct udevice *dev) > -{ > +static int ohci_usb_remove(struct udevice *dev) { > + struct generic_ohci *priv = dev_get_priv(dev); > + > + generic_phy_exit(&priv->phy); > + ohci_assert_resets(dev); > + ohci_disable_clocks(dev); > + > return ohci_deregister(dev); > } > > -- > 1.9.1 > Regards, Simon
diff --git a/drivers/usb/host/ohci-generic.c b/drivers/usb/host/ohci-generic.c index f3307f4..f86e223 100644 --- a/drivers/usb/host/ohci-generic.c +++ b/drivers/usb/host/ohci-generic.c @@ -5,26 +5,119 @@ */ #include <common.h> +#include <clk.h> #include <dm.h> +#include <fdtdec.h> +#include <generic-phy.h> +#include <reset.h> + #include "ohci.h" #if !defined(CONFIG_USB_OHCI_NEW) # error "Generic OHCI driver requires CONFIG_USB_OHCI_NEW" #endif +#define OHCI_MAX_CLOCKS 3 +#define OHCI_MAX_RESETS 3 + struct generic_ohci { ohci_t ohci; + struct clk clks[OHCI_MAX_CLOCKS]; + struct reset_ctl resets[OHCI_MAX_RESETS]; + struct phy phy; }; +static void ohci_assert_resets(struct udevice *dev) { + struct generic_ohci *priv = dev_get_priv(dev); + struct reset_ctl reset; + int i; + + for (i = OHCI_MAX_RESETS; i >= 0; --i) { + reset = priv->resets[i]; + + if (reset.dev) { + reset_request(&reset); + reset_assert(&reset); + reset_free(&reset); + } + } +} + +static void ohci_disable_clocks(struct udevice *dev) { + struct generic_ohci *priv = dev_get_priv(dev); + struct clk clk; + int i; + + for (i = OHCI_MAX_CLOCKS; i >= 0; --i) { + clk = priv->clks[i]; + + if (clk.dev) { + clk_request(clk.dev, &clk); + clk_disable(&clk); + clk_free(&clk); + } + } +} + static int ohci_usb_probe(struct udevice *dev) { struct ohci_regs *regs = (struct ohci_regs *)dev_get_addr(dev); + struct generic_ohci *priv = dev_get_priv(dev); + int i, ret; + + for (i = 0; i < OHCI_MAX_CLOCKS; i++) { + struct clk clk = priv->clks[i]; - return ohci_register(dev, regs); + 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); + goto clk_err; + } + clk_free(&clk); + } + + for (i = 0; i < OHCI_MAX_RESETS ; i++) { + struct reset_ctl reset = priv->resets[i]; + + 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); + } + + if (!generic_phy_get_by_index(dev, 0, &priv->phy)) + if (generic_phy_init(&priv->phy)) + error("failed to init usb phy %d\n", i); + + ret = ohci_register(dev, regs); + if (!ret) + return ret; + + generic_phy_exit(&priv->phy); + +reset_err: + ohci_assert_resets(dev); +clk_err: + ohci_disable_clocks(dev); + + return ret; } -static int ohci_usb_remove(struct udevice *dev) -{ +static int ohci_usb_remove(struct udevice *dev) { + struct generic_ohci *priv = dev_get_priv(dev); + + generic_phy_exit(&priv->phy); + ohci_assert_resets(dev); + ohci_disable_clocks(dev); + return ohci_deregister(dev); }