usb: dwc2: convert driver to DM_USB_GADGET
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> Reviewed-by: Lukasz Majewski <lukma@denx.de>
This commit is contained in:
		
							parent
							
								
									a812d77617
								
							
						
					
					
						commit
						c791c8431c
					
				|  | @ -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"; | ||||
|         }; | ||||
|  | @ -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) */ | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue