[U-Boot] [PATCH 07/16] usb: dwc2: convert driver to DM_USB_GADGET

Lukasz Majewski lukma at denx.de
Mon Apr 8 21:55:15 UTC 2019


On Fri, 29 Mar 2019 15:42:15 +0100
Patrick Delaunay <patrick.delaunay at st.com> wrote:

> Minimal conversion to driver model by using the uclass
> UCLASS_USB_GADGET_GENERIC based on:
> - reset uclass
> - clock uclass
> - generic uclass.
> 
> Signed-off-by: Patrick Delaunay <patrick.delaunay at st.com>
> ---
> 
>  doc/device-tree-bindings/usb/dwc2.txt |  54 +++++++
>  drivers/usb/gadget/dwc2_udc_otg.c     | 292
> +++++++++++++++++++++++++++++++++- 2 files changed, 344
> insertions(+), 2 deletions(-) create mode 100644
> doc/device-tree-bindings/usb/dwc2.txt
> 
> diff --git a/doc/device-tree-bindings/usb/dwc2.txt
> b/doc/device-tree-bindings/usb/dwc2.txt new file mode 100644
> index 0000000..6dc3c4a
> --- /dev/null
> +++ b/doc/device-tree-bindings/usb/dwc2.txt
> @@ -0,0 +1,54 @@
> +Platform DesignWare HS OTG USB 2.0 controller
> +-----------------------------------------------------
> +
> +Required properties:
> +- compatible : One of:
> +  - brcm,bcm2835-usb: The DWC2 USB controller instance in the
> BCM2835 SoC.
> +  - hisilicon,hi6220-usb: The DWC2 USB controller instance in the
> hi6220 SoC.
> +  - rockchip,rk3066-usb: The DWC2 USB controller instance in the
> rk3066 Soc;
> +  - "rockchip,px30-usb", "rockchip,rk3066-usb", "snps,dwc2": for
> px30 Soc;
> +  - "rockchip,rk3188-usb", "rockchip,rk3066-usb", "snps,dwc2": for
> rk3188 Soc;
> +  - "rockchip,rk3288-usb", "rockchip,rk3066-usb", "snps,dwc2": for
> rk3288 Soc;
> +  - "lantiq,arx100-usb": The DWC2 USB controller instance in Lantiq
> ARX SoCs;
> +  - "lantiq,xrx200-usb": The DWC2 USB controller instance in Lantiq
> XRX SoCs;
> +  - "amlogic,meson8-usb": The DWC2 USB controller instance in
> Amlogic Meson8 SoCs;
> +  - "amlogic,meson8b-usb": The DWC2 USB controller instance in
> Amlogic Meson8b SoCs;
> +  - "amlogic,meson-gxbb-usb": The DWC2 USB controller instance in
> Amlogic S905 SoCs;
> +  - "amcc,dwc-otg": The DWC2 USB controller instance in AMCC
> Canyonlands 460EX SoCs;
> +  - snps,dwc2: A generic DWC2 USB controller with default parameters.
> +  - "st,stm32f4x9-fsotg": The DWC2 USB FS/HS controller instance in
> STM32F4x9 SoCs
> +  configured in FS mode;
> +  - "st,stm32f4x9-hsotg": The DWC2 USB HS controller instance in
> STM32F4x9 SoCs
> +  configured in HS mode;
> +  - "st,stm32f7-hsotg": The DWC2 USB HS controller instance in
> STM32F7 SoCs
> +    configured in HS mode;
> +- reg : Should contain 1 register range (address and length)
> +- interrupts : Should contain 1 interrupt
> +- clocks: clock provider specifier
> +- clock-names: shall be "otg"
> +Refer to clk/clock-bindings.txt for generic clock consumer properties
> +
> +Optional properties:
> +- phys: phy provider specifier
> +- phy-names: shall be "usb2-phy"
> +Refer to phy/phy-bindings.txt for generic phy consumer properties
> +- dr_mode: shall be one of "host", "peripheral" and "otg"
> +  Refer to usb/generic.txt
> +- g-rx-fifo-size: size of rx fifo size in gadget mode.
> +- g-np-tx-fifo-size: size of non-periodic tx fifo size in gadget
> mode. +- g-tx-fifo-size: size of periodic tx fifo per endpoint
> (except ep0) in gadget mode. +
> +Deprecated properties:
> +- g-use-dma: gadget DMA mode is automatically detected
> +
> +Example:
> +
> +        usb at 101c0000 {
> +                compatible = "ralink,rt3050-usb, snps,dwc2";
> +                reg = <0x101c0000 40000>;
> +                interrupts = <18>;
> +		clocks = <&usb_otg_ahb_clk>;
> +		clock-names = "otg";
> +		phys = <&usbphy>;
> +		phy-names = "usb2-phy";
> +        };
> diff --git a/drivers/usb/gadget/dwc2_udc_otg.c
> b/drivers/usb/gadget/dwc2_udc_otg.c index edca05d..af16fc1 100644
> --- a/drivers/usb/gadget/dwc2_udc_otg.c
> +++ b/drivers/usb/gadget/dwc2_udc_otg.c
> @@ -18,11 +18,17 @@
>   */
>  #undef DEBUG
>  #include <common.h>
> +#include <clk.h>
> +#include <dm.h>
> +#include <generic-phy.h>
> +#include <malloc.h>
> +#include <reset.h>
> +
>  #include <linux/errno.h>
>  #include <linux/list.h>
> -#include <malloc.h>
>  
>  #include <linux/usb/ch9.h>
> +#include <linux/usb/otg.h>
>  #include <linux/usb/gadget.h>
>  
>  #include <asm/byteorder.h>
> @@ -31,6 +37,8 @@
>  
>  #include <asm/mach-types.h>
>  
> +#include <power/regulator.h>
> +
>  #include "dwc2_udc_otg_regs.h"
>  #include "dwc2_udc_otg_priv.h"
>  
> @@ -222,6 +230,7 @@ static int udc_enable(struct dwc2_udc *dev)
>  	return 0;
>  }
>  
> +#if !CONFIG_IS_ENABLED(DM_USB_GADGET)
>  /*
>    Register entry point for the peripheral controller driver.
>  */
> @@ -296,6 +305,54 @@ int usb_gadget_unregister_driver(struct
> usb_gadget_driver *driver) udc_disable(dev);
>  	return 0;
>  }
> +#else /* !CONFIG_IS_ENABLED(DM_USB_GADGET) */
> +
> +static int dwc2_gadget_start(struct usb_gadget *g,
> +			     struct usb_gadget_driver *driver)
> +{
> +	struct dwc2_udc *dev = the_controller;
> +
> +	debug_cond(DEBUG_SETUP != 0, "%s: %s\n", __func__, "no
> name"); +
> +	if (!driver ||
> +	    (driver->speed != USB_SPEED_FULL &&
> +	     driver->speed != USB_SPEED_HIGH) ||
> +	    !driver->bind || !driver->disconnect || !driver->setup)
> +		return -EINVAL;
> +
> +	if (!dev)
> +		return -ENODEV;
> +
> +	if (dev->driver)
> +		return -EBUSY;
> +
> +	/* first hook up the driver ... */
> +	dev->driver = driver;
> +
> +	debug_cond(DEBUG_SETUP != 0,
> +		   "Registered gadget driver %s\n",
> dev->gadget.name);
> +	return udc_enable(dev);
> +}
> +
> +static int dwc2_gadget_stop(struct usb_gadget *g)
> +{
> +	struct dwc2_udc *dev = the_controller;
> +
> +	if (!dev)
> +		return -ENODEV;
> +
> +	if (!dev->driver)
> +		return -EINVAL;
> +
> +	dev->driver = 0;
> +	stop_activity(dev, dev->driver);
> +
> +	udc_disable(dev);
> +
> +	return 0;
> +}
> +
> +#endif /* !CONFIG_IS_ENABLED(DM_USB_GADGET) */
>  
>  /*
>   *	done - retire a request; caller blocked irqs
> @@ -730,6 +787,10 @@ static void dwc2_fifo_flush(struct usb_ep *_ep)
>  
>  static const struct usb_gadget_ops dwc2_udc_ops = {
>  	/* current versions must always be self-powered */
> +#if CONFIG_IS_ENABLED(DM_USB_GADGET)
> +	.udc_start		= dwc2_gadget_start,
> +	.udc_stop		= dwc2_gadget_stop,
> +#endif
>  };
>  
>  static struct dwc2_udc memory = {
> @@ -841,12 +902,239 @@ int dwc2_udc_probe(struct dwc2_plat_otg_data
> *pdata) return retval;
>  }
>  
> -int usb_gadget_handle_interrupts(int index)
> +int dwc2_udc_handle_interrupt(void)
>  {
>  	u32 intr_status = readl(&reg->gintsts);
>  	u32 gintmsk = readl(&reg->gintmsk);
>  
>  	if (intr_status & gintmsk)
>  		return dwc2_udc_irq(1, (void *)the_controller);
> +
> +	return 0;
> +}
> +
> +#if !CONFIG_IS_ENABLED(DM_USB_GADGET)
> +
> +int usb_gadget_handle_interrupts(int index)
> +{
> +	return dwc2_udc_handle_interrupt();
> +}
> +
> +#else /* CONFIG_IS_ENABLED(DM_USB_GADGET) */
> +
> +struct dwc2_priv_data {
> +	struct clk_bulk		clks;
> +	struct reset_ctl_bulk	resets;
> +	struct phy *phys;
> +	int num_phys;
> +};
> +
> +int dm_usb_gadget_handle_interrupts(struct udevice *dev)
> +{
> +	return dwc2_udc_handle_interrupt();
> +}
> +
> +int dwc2_phy_setup(struct udevice *dev, struct phy **array, int
> *num_phys) +{
> +	int i, ret, count;
> +	struct phy *usb_phys;
> +
> +	/* Return if no phy declared */
> +	if (!dev_read_prop(dev, "phys", NULL))
> +		return 0;
> +
> +	count = dev_count_phandle_with_args(dev, "phys",
> "#phy-cells");
> +	if (count <= 0)
> +		return count;
> +
> +	usb_phys = devm_kcalloc(dev, count, sizeof(struct phy),
> +				GFP_KERNEL);
> +	if (!usb_phys)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < count; i++) {
> +		ret = generic_phy_get_by_index(dev, i, &usb_phys[i]);
> +		if (ret && ret != -ENOENT) {
> +			dev_err(dev, "Failed to get USB PHY%d for
> %s\n",
> +				i, dev->name);
> +			return ret;
> +		}
> +	}
> +
> +	for (i = 0; i < count; i++) {
> +		ret = generic_phy_init(&usb_phys[i]);
> +		if (ret) {
> +			dev_err(dev, "Can't init USB PHY%d for %s\n",
> +				i, dev->name);
> +			goto phys_init_err;
> +		}
> +	}
> +
> +	for (i = 0; i < count; i++) {
> +		ret = generic_phy_power_on(&usb_phys[i]);
> +		if (ret) {
> +			dev_err(dev, "Can't power USB PHY%d for
> %s\n",
> +				i, dev->name);
> +			goto phys_poweron_err;
> +		}
> +	}
> +
> +	*array = usb_phys;
> +	*num_phys =  count;
> +
>  	return 0;
> +
> +phys_poweron_err:
> +	for (i = count - 1; i >= 0; i--)
> +		generic_phy_power_off(&usb_phys[i]);
> +
> +	for (i = 0; i < count; i++)
> +		generic_phy_exit(&usb_phys[i]);
> +
> +	return ret;
> +
> +phys_init_err:
> +	for (; i >= 0; i--)
> +		generic_phy_exit(&usb_phys[i]);
> +
> +	return ret;
>  }
> +
> +void dwc2_phy_shutdown(struct udevice *dev, struct phy *usb_phys,
> int num_phys) +{
> +	int i, ret;
> +
> +	for (i = 0; i < num_phys; i++) {
> +		if (!generic_phy_valid(&usb_phys[i]))
> +			continue;
> +
> +		ret = generic_phy_power_off(&usb_phys[i]);
> +		ret |= generic_phy_exit(&usb_phys[i]);
> +		if (ret) {
> +			dev_err(dev, "Can't shutdown USB PHY%d for
> %s\n",
> +				i, dev->name);
> +		}
> +	}
> +}
> +
> +static int dwc2_udc_otg_ofdata_to_platdata(struct udevice *dev)
> +{
> +	struct dwc2_plat_otg_data *platdata = dev_get_platdata(dev);
> +	int node = dev_of_offset(dev);
> +
> +	if (usb_get_dr_mode(node) != USB_DR_MODE_PERIPHERAL) {
> +		dev_dbg(dev, "Invalid mode\n");
> +		return -ENODEV;
> +	}
> +
> +	platdata->regs_otg = dev_read_addr(dev);
> +
> +	platdata->rx_fifo_sz = dev_read_u32_default(dev,
> "g-rx-fifo-size", 0);
> +	platdata->np_tx_fifo_sz = dev_read_u32_default(dev,
> +
> "g-np-tx-fifo-size", 0);
> +	platdata->tx_fifo_sz = dev_read_u32_default(dev,
> "g-tx-fifo-size", 0); +
> +	return 0;
> +}
> +
> +static int dwc2_udc_otg_reset_init(struct udevice *dev,
> +				   struct reset_ctl_bulk *resets)
> +{
> +	int ret;
> +
> +	ret = reset_get_bulk(dev, resets);
> +	if (ret == -ENOTSUPP)
> +		return 0;
> +
> +	if (ret)
> +		return ret;
> +
> +	ret = reset_deassert_bulk(resets);
> +	if (ret) {
> +		reset_release_bulk(resets);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int dwc2_udc_otg_clk_init(struct udevice *dev,
> +				 struct clk_bulk *clks)
> +{
> +	int ret;
> +
> +	ret = clk_get_bulk(dev, clks);
> +	if (ret == -ENOSYS)
> +		return 0;
> +
> +	if (ret)
> +		return ret;
> +
> +	ret = clk_enable_bulk(clks);
> +	if (ret) {
> +		clk_release_bulk(clks);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int dwc2_udc_otg_probe(struct udevice *dev)
> +{
> +	struct dwc2_plat_otg_data *platdata = dev_get_platdata(dev);
> +	struct dwc2_priv_data *priv = dev_get_priv(dev);
> +	int ret;
> +
> +	ret = dwc2_udc_otg_clk_init(dev, &priv->clks);
> +	if (ret)
> +		return ret;
> +
> +	ret = dwc2_udc_otg_reset_init(dev, &priv->resets);
> +	if (ret)
> +		return ret;
> +
> +	ret = dwc2_phy_setup(dev, &priv->phys, &priv->num_phys);
> +	if (ret)
> +		return ret;
> +
> +	ret = dwc2_udc_probe(platdata);
> +	if (ret)
> +		return ret;
> +
> +	the_controller->driver = 0;
> +
> +	ret = usb_add_gadget_udc((struct device *)dev,
> &the_controller->gadget); +
> +	return ret;
> +}
> +
> +static int dwc2_udc_otg_remove(struct udevice *dev)
> +{
> +	struct dwc2_priv_data *priv = dev_get_priv(dev);
> +
> +	usb_del_gadget_udc(&the_controller->gadget);
> +
> +	reset_release_bulk(&priv->resets);
> +
> +	clk_release_bulk(&priv->clks);
> +
> +	dwc2_phy_shutdown(dev, priv->phys, priv->num_phys);
> +
> +	return dm_scan_fdt_dev(dev);
> +}
> +
> +static const struct udevice_id dwc2_udc_otg_ids[] = {
> +	{ .compatible = "snps,dwc2" },
> +};
> +
> +U_BOOT_DRIVER(dwc2_udc_otg) = {
> +	.name	= "dwc2-udc-otg",
> +	.id	= UCLASS_USB_GADGET_GENERIC,
> +	.of_match = dwc2_udc_otg_ids,
> +	.ofdata_to_platdata = dwc2_udc_otg_ofdata_to_platdata,
> +	.probe = dwc2_udc_otg_probe,
> +	.remove = dwc2_udc_otg_remove,
> +	.platdata_auto_alloc_size = sizeof(struct
> dwc2_plat_otg_data),
> +	.priv_auto_alloc_size = sizeof(struct dwc2_priv_data),
> +};
> +#endif /* CONFIG_IS_ENABLED(DM_USB_GADGET) */

Reviewed-by: Lukasz Majewski <lukma at denx.de>


Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma at denx.de
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 488 bytes
Desc: OpenPGP digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20190408/a391d385/attachment.sig>


More information about the U-Boot mailing list