Re: [RFC PATH 2/3] usb: dwc3: add ULPI interface support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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




[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux