usb: musb-new: Add glue driver for ST-Ericsson Ux500
The ST-Ericsson DB8500 SoC contains a MUSB OTG controller which supports both host and gadget mode. For some reason there is nothing special about it - add a simple glue driver for Ux500 that literally just sets up MUSB together with a generic PHY. There are no SoC-specific registers etc needed to make USB work. The new Ux500 glue driver is only tested to work with DM_USB and DM_USB_GADGET. Both host and gadget mode work fine on the u8500 "stemmy" board that is already present in U-Boot. Reviewed-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Stephan Gerhold <stephan@gerhold.net>
This commit is contained in:
		
							parent
							
								
									4559df9e81
								
							
						
					
					
						commit
						845d9cf61c
					
				| 
						 | 
					@ -72,6 +72,15 @@ config USB_MUSB_SUNXI
 | 
				
			||||||
	Say y here to enable support for the sunxi OTG / DRC USB controller
 | 
						Say y here to enable support for the sunxi OTG / DRC USB controller
 | 
				
			||||||
	used on almost all sunxi boards.
 | 
						used on almost all sunxi boards.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config USB_MUSB_UX500
 | 
				
			||||||
 | 
						bool "Enable ST-Ericsson Ux500 USB controller"
 | 
				
			||||||
 | 
						depends on DM_USB && DM_USB_GADGET && ARCH_U8500
 | 
				
			||||||
 | 
						default y
 | 
				
			||||||
 | 
						help
 | 
				
			||||||
 | 
						  Say y to enable support for the MUSB OTG USB controller used in
 | 
				
			||||||
 | 
						  ST-Ericsson Ux500. The driver supports either gadget or host mode
 | 
				
			||||||
 | 
						  based on the selection of CONFIG_USB_MUSB_HOST.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config USB_MUSB_DISABLE_BULK_COMBINE_SPLIT
 | 
					config USB_MUSB_DISABLE_BULK_COMBINE_SPLIT
 | 
				
			||||||
	bool "Disable MUSB bulk split/combine"
 | 
						bool "Disable MUSB bulk split/combine"
 | 
				
			||||||
	default y
 | 
						default y
 | 
				
			||||||
| 
						 | 
					@ -85,7 +94,7 @@ endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config USB_MUSB_PIO_ONLY
 | 
					config USB_MUSB_PIO_ONLY
 | 
				
			||||||
	bool "Disable DMA (always use PIO)"
 | 
						bool "Disable DMA (always use PIO)"
 | 
				
			||||||
	default y if USB_MUSB_AM35X || USB_MUSB_PIC32 || USB_MUSB_OMAP2PLUS || USB_MUSB_DSPS || USB_MUSB_SUNXI || USB_MUSB_MT85XX
 | 
						default y if USB_MUSB_AM35X || USB_MUSB_PIC32 || USB_MUSB_OMAP2PLUS || USB_MUSB_DSPS || USB_MUSB_SUNXI || USB_MUSB_MT85XX || USB_MUSB_UX500
 | 
				
			||||||
	help
 | 
						help
 | 
				
			||||||
	  All data is copied between memory and FIFO by the CPU.
 | 
						  All data is copied between memory and FIFO by the CPU.
 | 
				
			||||||
	  DMA controllers are ignored.
 | 
						  DMA controllers are ignored.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,6 +13,7 @@ obj-$(CONFIG_USB_MUSB_OMAP2PLUS) += omap2430.o
 | 
				
			||||||
obj-$(CONFIG_USB_MUSB_PIC32) += pic32.o
 | 
					obj-$(CONFIG_USB_MUSB_PIC32) += pic32.o
 | 
				
			||||||
obj-$(CONFIG_USB_MUSB_SUNXI) += sunxi.o
 | 
					obj-$(CONFIG_USB_MUSB_SUNXI) += sunxi.o
 | 
				
			||||||
obj-$(CONFIG_USB_MUSB_TI) += ti-musb.o
 | 
					obj-$(CONFIG_USB_MUSB_TI) += ti-musb.o
 | 
				
			||||||
 | 
					obj-$(CONFIG_USB_MUSB_UX500) += ux500.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ccflags-y := $(call cc-option,-Wno-unused-variable) \
 | 
					ccflags-y := $(call cc-option,-Wno-unused-variable) \
 | 
				
			||||||
		$(call cc-option,-Wno-unused-but-set-variable) \
 | 
							$(call cc-option,-Wno-unused-but-set-variable) \
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1526,7 +1526,7 @@ static int __devinit musb_core_init(u16 musb_type, struct musb *musb)
 | 
				
			||||||
/*-------------------------------------------------------------------------*/
 | 
					/*-------------------------------------------------------------------------*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(CONFIG_SOC_OMAP2430) || defined(CONFIG_SOC_OMAP3430) || \
 | 
					#if defined(CONFIG_SOC_OMAP2430) || defined(CONFIG_SOC_OMAP3430) || \
 | 
				
			||||||
	defined(CONFIG_ARCH_OMAP4)
 | 
						defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_ARCH_U8500)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static irqreturn_t generic_interrupt(int irq, void *__hci)
 | 
					static irqreturn_t generic_interrupt(int irq, void *__hci)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,179 @@
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: GPL-2.0+
 | 
				
			||||||
 | 
					/* Copyright (C) 2019 Stephan Gerhold */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <common.h>
 | 
				
			||||||
 | 
					#include <dm.h>
 | 
				
			||||||
 | 
					#include <generic-phy.h>
 | 
				
			||||||
 | 
					#include <dm/device_compat.h>
 | 
				
			||||||
 | 
					#include "musb_uboot.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct musb_hdrc_config ux500_musb_hdrc_config = {
 | 
				
			||||||
 | 
						.multipoint	= true,
 | 
				
			||||||
 | 
						.dyn_fifo	= true,
 | 
				
			||||||
 | 
						.num_eps	= 16,
 | 
				
			||||||
 | 
						.ram_bits	= 16,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ux500_glue {
 | 
				
			||||||
 | 
						struct musb_host_data mdata;
 | 
				
			||||||
 | 
						struct device dev;
 | 
				
			||||||
 | 
						struct phy phy;
 | 
				
			||||||
 | 
						bool enabled;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					#define to_ux500_glue(d)	container_of(d, struct ux500_glue, dev)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ux500_musb_enable(struct musb *musb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ux500_glue *glue = to_ux500_glue(musb->controller);
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (glue->enabled)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = generic_phy_power_on(&glue->phy);
 | 
				
			||||||
 | 
						if (ret) {
 | 
				
			||||||
 | 
							printf("%s: failed to power on USB PHY\n", __func__);
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						glue->enabled = true;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ux500_musb_disable(struct musb *musb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ux500_glue *glue = to_ux500_glue(musb->controller);
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!glue->enabled)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = generic_phy_power_off(&glue->phy);
 | 
				
			||||||
 | 
						if (ret) {
 | 
				
			||||||
 | 
							printf("%s: failed to power off USB PHY\n", __func__);
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						glue->enabled = false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ux500_musb_init(struct musb *musb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ux500_glue *glue = to_ux500_glue(musb->controller);
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = generic_phy_init(&glue->phy);
 | 
				
			||||||
 | 
						if (ret) {
 | 
				
			||||||
 | 
							printf("%s: failed to init USB PHY\n", __func__);
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ux500_musb_exit(struct musb *musb)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ux500_glue *glue = to_ux500_glue(musb->controller);
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = generic_phy_exit(&glue->phy);
 | 
				
			||||||
 | 
						if (ret) {
 | 
				
			||||||
 | 
							printf("%s: failed to exit USB PHY\n", __func__);
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct musb_platform_ops ux500_musb_ops = {
 | 
				
			||||||
 | 
						.init		= ux500_musb_init,
 | 
				
			||||||
 | 
						.exit		= ux500_musb_exit,
 | 
				
			||||||
 | 
						.enable		= ux500_musb_enable,
 | 
				
			||||||
 | 
						.disable	= ux500_musb_disable,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int dm_usb_gadget_handle_interrupts(struct udevice *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ux500_glue *glue = dev_get_priv(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						glue->mdata.host->isr(0, glue->mdata.host);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ux500_musb_probe(struct udevice *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#ifdef CONFIG_USB_MUSB_HOST
 | 
				
			||||||
 | 
						struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						struct ux500_glue *glue = dev_get_priv(dev);
 | 
				
			||||||
 | 
						struct musb_host_data *host = &glue->mdata;
 | 
				
			||||||
 | 
						struct musb_hdrc_platform_data pdata;
 | 
				
			||||||
 | 
						void *base = dev_read_addr_ptr(dev);
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!base)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ret = generic_phy_get_by_name(dev, "usb", &glue->phy);
 | 
				
			||||||
 | 
						if (ret) {
 | 
				
			||||||
 | 
							dev_err(dev, "failed to get USB PHY: %d\n", ret);
 | 
				
			||||||
 | 
							return ret;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memset(&pdata, 0, sizeof(pdata));
 | 
				
			||||||
 | 
						pdata.platform_ops = &ux500_musb_ops;
 | 
				
			||||||
 | 
						pdata.config = &ux500_musb_hdrc_config;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_USB_MUSB_HOST
 | 
				
			||||||
 | 
						priv->desc_before_addr = true;
 | 
				
			||||||
 | 
						pdata.mode = MUSB_HOST;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						host->host = musb_init_controller(&pdata, &glue->dev, base);
 | 
				
			||||||
 | 
						if (!host->host)
 | 
				
			||||||
 | 
							return -EIO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return musb_lowlevel_init(host);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						pdata.mode = MUSB_PERIPHERAL;
 | 
				
			||||||
 | 
						host->host = musb_init_controller(&pdata, &glue->dev, base);
 | 
				
			||||||
 | 
						if (!host->host)
 | 
				
			||||||
 | 
							return -EIO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return usb_add_gadget_udc(&glue->dev, &host->host->g);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ux500_musb_remove(struct udevice *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ux500_glue *glue = dev_get_priv(dev);
 | 
				
			||||||
 | 
						struct musb_host_data *host = &glue->mdata;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						usb_del_gadget_udc(&host->host->g);
 | 
				
			||||||
 | 
						musb_stop(host->host);
 | 
				
			||||||
 | 
						free(host->host);
 | 
				
			||||||
 | 
						host->host = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct udevice_id ux500_musb_ids[] = {
 | 
				
			||||||
 | 
						{ .compatible = "stericsson,db8500-musb" },
 | 
				
			||||||
 | 
						{ }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					U_BOOT_DRIVER(ux500_musb) = {
 | 
				
			||||||
 | 
						.name		= "ux500-musb",
 | 
				
			||||||
 | 
					#ifdef CONFIG_USB_MUSB_HOST
 | 
				
			||||||
 | 
						.id		= UCLASS_USB,
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						.id		= UCLASS_USB_GADGET_GENERIC,
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						.of_match	= ux500_musb_ids,
 | 
				
			||||||
 | 
						.probe		= ux500_musb_probe,
 | 
				
			||||||
 | 
						.remove		= ux500_musb_remove,
 | 
				
			||||||
 | 
					#ifdef CONFIG_USB_MUSB_HOST
 | 
				
			||||||
 | 
						.ops		= &musb_usb_ops,
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						.plat_auto	= sizeof(struct usb_plat),
 | 
				
			||||||
 | 
						.priv_auto	= sizeof(struct ux500_glue),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
		Loading…
	
		Reference in New Issue