On Fri, 29 Mar 2019 15:42:15 +0100 Patrick Delaunay <patrick.delau...@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.delau...@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@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(®->gintsts); > u32 gintmsk = readl(®->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 <lu...@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: lu...@denx.de
pgpAMxPNOxpZ4.pgp
Description: OpenPGP digital signature
_______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot