
On Fri, 29 Mar 2019 15:42:15 +0100 Patrick Delaunay patrick.delaunay@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@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 lukma@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@denx.de