Hi, On Thursday 28 November 2013 09:29 PM, Heikki Krogerus wrote: > Registers ULPI interface with the ULPI abstraction layer if > the HSPHY type is ULPI, which will create phy instance for > usb2. > > Depends on Kishon's patch set adding support for generic PHY > framework. > > Signed-off-by: Heikki Krogerus <heikki.krogerus@xxxxxxxxxxxxxxx> > --- > drivers/usb/dwc3/Kconfig | 7 +++ > drivers/usb/dwc3/Makefile | 4 ++ > drivers/usb/dwc3/core.c | 8 ++++ > drivers/usb/dwc3/core.h | 21 +++++++++ > drivers/usb/dwc3/ulpi.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++ > 5 files changed, 150 insertions(+) > create mode 100644 drivers/usb/dwc3/ulpi.c > > diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig > index 64eed6f..a97b294 100644 > --- a/drivers/usb/dwc3/Kconfig > +++ b/drivers/usb/dwc3/Kconfig > @@ -13,6 +13,13 @@ config USB_DWC3 > > if USB_DWC3 > > +config USB_DWC3_ULPI > + bool "Provide ULPI PHY Interface" > + depends on ULPI_PHY=y || ULPI_PHY=USB_DWC3 > + help > + Select this if you have ULPI type PHY attached to your DWC3 > + controller. > + > choice > bool "DWC3 Mode Selection" > default USB_DWC3_DUAL_ROLE if (USB && USB_GADGET) > diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile > index dd17601..8bb82bc 100644 > --- a/drivers/usb/dwc3/Makefile > +++ b/drivers/usb/dwc3/Makefile > @@ -13,6 +13,10 @@ ifneq ($(filter y,$(CONFIG_USB_DWC3_GADGET) $(CONFIG_USB_DWC3_DUAL_ROLE)),) > dwc3-y += gadget.o ep0.o > endif > > +ifneq ($(CONFIG_USB_DWC3_ULPI),) > + dwc3-y += ulpi.o > +endif > + > ifneq ($(CONFIG_DEBUG_FS),) > dwc3-y += debugfs.o > endif > diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c > index 1c0a69a..94927b2 100644 > --- a/drivers/usb/dwc3/core.c > +++ b/drivers/usb/dwc3/core.c > @@ -505,6 +505,12 @@ static int dwc3_probe(struct platform_device *pdev) > dwc->regs_size = resource_size(res); > dwc->dev = dev; > > + if (!dwc->usb2_generic_phy) { > + ret = dwc3_ulpi_init(dwc); shouldn't this be called from dwc3-pci (or any other dwc3 glue)? > + if (ret) > + return ret; > + } > + > dev->dma_mask = dev->parent->dma_mask; > dev->dma_parms = dev->parent->dma_parms; > dma_set_coherent_mask(dev, dev->parent->coherent_dma_mask); > @@ -613,6 +619,7 @@ err1: > > err0: > dwc3_free_event_buffers(dwc); > + dwc3_ulpi_exit(dwc); > > return ret; > } > @@ -653,6 +660,7 @@ static int dwc3_remove(struct platform_device *pdev) > dwc3_event_buffers_cleanup(dwc); > dwc3_free_event_buffers(dwc); > dwc3_core_exit(dwc); > + dwc3_ulpi_exit(dwc); > > return 0; > } > diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h > index 01ec7d7..6df398a 100644 > --- a/drivers/usb/dwc3/core.h > +++ b/drivers/usb/dwc3/core.h > @@ -169,6 +169,14 @@ > #define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31) > #define DWC3_GUSB2PHYCFG_SUSPHY (1 << 6) > > +/* Global USB2 PHY Vendor Control Register */ > +#define DWC3_GUSB2PHYACC_NEWREGREQ (1 << 25) > +#define DWC3_GUSB2PHYACC_BUSY (1 << 23) > +#define DWC3_GUSB2PHYACC_WRITE (1 << 22) > +#define DWC3_GUSB2PHYACC_ADDR(n) (n << 16) > +#define DWC3_GUSB2PHYACC_EXTEND_ADDR(n) (n << 8) > +#define DWC3_GUSB2PHYACC_DATA(n) (n & 0xff) > + > /* Global USB3 PIPE Control Register */ > #define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31) > #define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17) > @@ -557,6 +565,7 @@ struct dwc3_hwparams { > #define DWC3_NUM_INT(n) (((n) & (0x3f << 15)) >> 15) > > /* HWPARAMS3 */ > +#define DWC3_ULPI_HSPHY (1 << 3) > #define DWC3_NUM_IN_EPS_MASK (0x1f << 18) > #define DWC3_NUM_EPS_MASK (0x3f << 12) > #define DWC3_NUM_EPS(p) (((p)->hwparams3 & \ > @@ -672,6 +681,8 @@ struct dwc3 { > struct phy *usb2_generic_phy; > struct phy *usb3_generic_phy; > > + struct ulpi_interface *ulpi; > + > void __iomem *regs; > size_t regs_size; > > @@ -922,4 +933,14 @@ static inline int dwc3_gadget_resume(struct dwc3 *dwc) > } > #endif /* !IS_ENABLED(CONFIG_USB_DWC3_HOST) */ > > +#if IS_ENABLED(CONFIG_USB_DWC3_ULPI) > +int dwc3_ulpi_init(struct dwc3 *dwc); > +void dwc3_ulpi_exit(struct dwc3 *dwc); > +#else > +static inline int dwc3_ulpi_init(struct dwc3 *dwc) > +{ return 0; } > +static inline void dwc3_ulpi_exit(struct dwc3 *dwc) > +{ } > +#endif > + > #endif /* __DRIVERS_USB_DWC3_CORE_H */ > diff --git a/drivers/usb/dwc3/ulpi.c b/drivers/usb/dwc3/ulpi.c > new file mode 100644 > index 0000000..e1f152b > --- /dev/null > +++ b/drivers/usb/dwc3/ulpi.c > @@ -0,0 +1,110 @@ > +/** > + * ulpi.c - DesignWare USB3 ULPI PHY interface > + * > + * Copyright (C) 2013 Intel Corporation > + * > + * Author: Heikki Krogerus <heikki.krogerus@xxxxxxxxxxxxxxx> > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License as published by the > + * Free Software Foundation; either version 2 of the License, or (at your > + * option) any later version. > + */ > + > +#include <linux/platform_device.h> > +#include <linux/phy/ulpi.h> > + > +#include "core.h" > +#include "io.h" > + > +#define DWC3_ULPI_ADDR(a) \ > + ((a >= ULPI_EXT_VENDOR_SPECIFIC) ? \ > + DWC3_GUSB2PHYACC_ADDR(ULPI_ACCESS_EXTENDED) | \ > + DWC3_GUSB2PHYACC_EXTEND_ADDR(a) : DWC3_GUSB2PHYACC_ADDR(a)) > + > +static int dwc3_ulpi_busyloop(struct dwc3 *dwc) > +{ > + unsigned count = 100; > + u32 reg; > + > + while (count) { > + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYACC(0)); > + if (!(reg & DWC3_GUSB2PHYACC_BUSY)) > + return 0; > + count--; > + } > + > + return -ETIMEDOUT; > +} > + > +static int dwc3_ulpi_read(struct ulpi_interface *ulpi, u8 addr) > +{ > + struct dwc3 *dwc = ulpi->priv; > + int ret; > + u32 reg; > + > + reg = DWC3_GUSB2PHYACC_NEWREGREQ | DWC3_ULPI_ADDR(addr); > + dwc3_writel(dwc->regs, DWC3_GUSB2PHYACC(0), reg); > + > + ret = dwc3_ulpi_busyloop(dwc); > + if (ret) > + return ret; > + > + reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYACC(0)); > + > + return DWC3_GUSB2PHYACC_DATA(reg); > +} > + > +static int dwc3_ulpi_write(struct ulpi_interface *ulpi, u8 addr, u8 val) > +{ > + struct dwc3 *dwc = ulpi->priv; > + int ret; > + u32 reg; > + > + reg = DWC3_GUSB2PHYACC_NEWREGREQ | DWC3_ULPI_ADDR(addr); > + reg |= DWC3_GUSB2PHYACC_WRITE | val; > + dwc3_writel(dwc->regs, DWC3_GUSB2PHYACC(0), reg); > + > + ret = dwc3_ulpi_busyloop(dwc); > + if (ret) > + return ret; > + > + return 0; > +} > + > +int dwc3_ulpi_init(struct dwc3 *dwc) call this from dwc3-pci? I mean we should have this function only to create a ulpi device. > +{ > + int ret; > + > + /* First check if there is ULPI PHY */ > + ret = dwc3_readl(dwc->regs, DWC3_GHWPARAMS3); > + if (!(ret & DWC3_ULPI_HSPHY)) > + return 0; > + > + /* Register the interface */ > + dwc->ulpi = ulpi_new_interface(dwc->dev, > + dwc3_ulpi_read, dwc3_ulpi_write, dwc); > + if (IS_ERR(dwc->ulpi)) { > + dev_err(dwc->dev, "failed to register ULPI interface"); > + return PTR_ERR(dwc->ulpi); > + } > + > + /* Get the ULPI phy instance > + * REVISIT: There should be no need to get it separately here. > + */ > + dwc->usb2_generic_phy = devm_phy_get(dwc->dev, ULPI_PORT_NAME); You shouldn't be needing this. It should get the phy from dwc3 core probe itself. Thanks Kishon -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html