diff options
Diffstat (limited to 'drivers/usb/musb')
| -rw-r--r-- | drivers/usb/musb/Kconfig | 28 | ||||
| -rw-r--r-- | drivers/usb/musb/Makefile | 1 | ||||
| -rw-r--r-- | drivers/usb/musb/am35x.c | 78 | ||||
| -rw-r--r-- | drivers/usb/musb/blackfin.c | 32 | ||||
| -rw-r--r-- | drivers/usb/musb/da8xx.c | 66 | ||||
| -rw-r--r-- | drivers/usb/musb/davinci.c | 68 | ||||
| -rw-r--r-- | drivers/usb/musb/jz4740.c | 201 | ||||
| -rw-r--r-- | drivers/usb/musb/musb_am335x.c | 26 | ||||
| -rw-r--r-- | drivers/usb/musb/musb_core.c | 195 | ||||
| -rw-r--r-- | drivers/usb/musb/musb_core.h | 15 | ||||
| -rw-r--r-- | drivers/usb/musb/musb_cppi41.c | 239 | ||||
| -rw-r--r-- | drivers/usb/musb/musb_dsps.c | 302 | ||||
| -rw-r--r-- | drivers/usb/musb/musb_gadget.c | 28 | ||||
| -rw-r--r-- | drivers/usb/musb/musb_host.c | 48 | ||||
| -rw-r--r-- | drivers/usb/musb/musb_host.h | 6 | ||||
| -rw-r--r-- | drivers/usb/musb/musb_virthub.c | 139 | ||||
| -rw-r--r-- | drivers/usb/musb/omap2430.c | 62 | ||||
| -rw-r--r-- | drivers/usb/musb/tusb6010.c | 78 | ||||
| -rw-r--r-- | drivers/usb/musb/tusb6010.h | 8 | ||||
| -rw-r--r-- | drivers/usb/musb/tusb6010_omap.c | 3 | ||||
| -rw-r--r-- | drivers/usb/musb/ux500.c | 17 | ||||
| -rw-r--r-- | drivers/usb/musb/ux500_dma.c | 4 | 
22 files changed, 1181 insertions, 463 deletions
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index c258a97ef1b..06cc5d6ea68 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -6,7 +6,7 @@  # (M)HDRC = (Multipoint) Highspeed Dual-Role Controller  config USB_MUSB_HDRC  	tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)' -	depends on USB_GADGET +	depends on (USB || USB_GADGET)  	help  	  Say Y here if your system has a dual role high speed USB  	  controller based on the Mentor Graphics silicon IP.  Then @@ -35,21 +35,23 @@ choice  config USB_MUSB_HOST  	bool "Host only mode" -	depends on USB +	depends on USB=y || USB=USB_MUSB_HDRC  	help  	  Select this when you want to use MUSB in host mode only,  	  thereby the gadget feature will be regressed.  config USB_MUSB_GADGET  	bool "Gadget only mode" -	depends on USB_GADGET +	depends on USB_GADGET=y || USB_GADGET=USB_MUSB_HDRC +	depends on HAS_DMA  	help  	  Select this when you want to use MUSB in gadget mode only,  	  thereby the host feature will be regressed.  config USB_MUSB_DUAL_ROLE  	bool "Dual Role mode" -	depends on (USB && USB_GADGET) +	depends on ((USB=y || USB=USB_MUSB_HDRC) && (USB_GADGET=y || USB_GADGET=USB_MUSB_HDRC)) +	depends on HAS_DMA  	help  	  This is the default mode of working of MUSB controller where  	  both host and gadget features are enabled. @@ -74,7 +76,8 @@ config USB_MUSB_TUSB6010  config USB_MUSB_OMAP2PLUS  	tristate "OMAP2430 and onwards" -	depends on ARCH_OMAP2PLUS +	depends on ARCH_OMAP2PLUS && USB +	select GENERIC_PHY  config USB_MUSB_AM35X  	tristate "AM35x" @@ -90,7 +93,13 @@ config USB_MUSB_BLACKFIN  	depends on (BF54x && !BF544) || (BF52x && ! BF522 && !BF523)  config USB_MUSB_UX500 -	tristate "U8500 and U5500" +	tristate "Ux500 platforms" + +config USB_MUSB_JZ4740 +	tristate "JZ4740" +	depends on MACH_JZ4740 || COMPILE_TEST +	depends on USB_MUSB_GADGET +	depends on USB_OTG_BLACKLIST_HUB  endchoice @@ -99,7 +108,7 @@ config USB_MUSB_AM335X_CHILD  choice  	prompt 'MUSB DMA mode' -	default MUSB_PIO_ONLY if ARCH_MULTIPLATFORM +	default MUSB_PIO_ONLY if ARCH_MULTIPLATFORM || USB_MUSB_JZ4740  	default USB_UX500_DMA if USB_MUSB_UX500  	default USB_INVENTRA_DMA if USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN  	default USB_TI_CPPI_DMA if USB_MUSB_DAVINCI @@ -112,7 +121,7 @@ choice  	  allow using DMA on multiplatform kernels.  config USB_UX500_DMA -	bool 'ST Ericsson U8500 and U5500' +	bool 'ST Ericsson Ux500'  	depends on USB_MUSB_UX500  	help  	  Enable DMA transfers on UX500 platforms. @@ -132,10 +141,11 @@ config USB_TI_CPPI_DMA  config USB_TI_CPPI41_DMA  	bool 'TI CPPI 4.1 (AM335x)'  	depends on ARCH_OMAP +	select TI_CPPI41  config USB_TUSB_OMAP_DMA  	bool 'TUSB 6010' -	depends on USB_MUSB_TUSB6010 +	depends on USB_MUSB_TUSB6010 = USB_MUSB_HDRC # both built-in or both modules  	depends on ARCH_OMAP  	help  	  Enable DMA transfers on TUSB 6010 when OMAP DMA is available. diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile index c5ea5c6dc16..ba495018b41 100644 --- a/drivers/usb/musb/Makefile +++ b/drivers/usb/musb/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_USB_MUSB_DAVINCI)			+= davinci.o  obj-$(CONFIG_USB_MUSB_DA8XX)			+= da8xx.o  obj-$(CONFIG_USB_MUSB_BLACKFIN)			+= blackfin.o  obj-$(CONFIG_USB_MUSB_UX500)			+= ux500.o +obj-$(CONFIG_USB_MUSB_JZ4740)			+= jz4740.o  obj-$(CONFIG_USB_MUSB_AM335X_CHILD)		+= musb_am335x.o diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c index 5c310c66421..0a34dd85955 100644 --- a/drivers/usb/musb/am35x.c +++ b/drivers/usb/musb/am35x.c @@ -26,14 +26,13 @@   *   */ -#include <linux/init.h>  #include <linux/module.h>  #include <linux/clk.h>  #include <linux/err.h>  #include <linux/io.h>  #include <linux/platform_device.h>  #include <linux/dma-mapping.h> -#include <linux/usb/usb_phy_gen_xceiv.h> +#include <linux/usb/usb_phy_generic.h>  #include <linux/platform_data/usb-omap.h>  #include "musb_core.h" @@ -86,10 +85,10 @@  struct am35x_glue {  	struct device		*dev;  	struct platform_device	*musb; +	struct platform_device	*phy;  	struct clk		*phy_clk;  	struct clk		*clk;  }; -#define glue_to_musb(g)		platform_get_drvdata(g->musb)  /*   * am35x_musb_enable - enable interrupts @@ -362,7 +361,6 @@ static int am35x_musb_init(struct musb *musb)  	if (!rev)  		return -ENODEV; -	usb_nop_xceiv_register();  	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);  	if (IS_ERR_OR_NULL(musb->xceiv))  		return -EPROBE_DEFER; @@ -404,7 +402,6 @@ static int am35x_musb_exit(struct musb *musb)  		data->set_phy_power(0);  	usb_put_phy(musb->xceiv); -	usb_nop_xceiv_unregister();  	return 0;  } @@ -452,14 +449,18 @@ static const struct musb_platform_ops am35x_ops = {  	.set_vbus	= am35x_musb_set_vbus,  }; -static u64 am35x_dmamask = DMA_BIT_MASK(32); +static const struct platform_device_info am35x_dev_info = { +	.name		= "musb-hdrc", +	.id		= PLATFORM_DEVID_AUTO, +	.dma_mask	= DMA_BIT_MASK(32), +};  static int am35x_probe(struct platform_device *pdev)  {  	struct musb_hdrc_platform_data	*pdata = dev_get_platdata(&pdev->dev);  	struct platform_device		*musb;  	struct am35x_glue		*glue; - +	struct platform_device_info	pinfo;  	struct clk			*phy_clk;  	struct clk			*clk; @@ -471,12 +472,6 @@ static int am35x_probe(struct platform_device *pdev)  		goto err0;  	} -	musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); -	if (!musb) { -		dev_err(&pdev->dev, "failed to allocate musb device\n"); -		goto err1; -	} -  	phy_clk = clk_get(&pdev->dev, "fck");  	if (IS_ERR(phy_clk)) {  		dev_err(&pdev->dev, "failed to get PHY clock\n"); @@ -503,40 +498,36 @@ static int am35x_probe(struct platform_device *pdev)  		goto err6;  	} -	musb->dev.parent		= &pdev->dev; -	musb->dev.dma_mask		= &am35x_dmamask; -	musb->dev.coherent_dma_mask	= am35x_dmamask; -  	glue->dev			= &pdev->dev; -	glue->musb			= musb;  	glue->phy_clk			= phy_clk;  	glue->clk			= clk;  	pdata->platform_ops		= &am35x_ops; -	platform_set_drvdata(pdev, glue); - -	ret = platform_device_add_resources(musb, pdev->resource, -			pdev->num_resources); -	if (ret) { -		dev_err(&pdev->dev, "failed to add resources\n"); -		goto err7; -	} - -	ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); -	if (ret) { -		dev_err(&pdev->dev, "failed to add platform_data\n"); +	glue->phy = usb_phy_generic_register(); +	if (IS_ERR(glue->phy))  		goto err7; -	} +	platform_set_drvdata(pdev, glue); -	ret = platform_device_add(musb); -	if (ret) { -		dev_err(&pdev->dev, "failed to register musb device\n"); -		goto err7; +	pinfo = am35x_dev_info; +	pinfo.parent = &pdev->dev; +	pinfo.res = pdev->resource; +	pinfo.num_res = pdev->num_resources; +	pinfo.data = pdata; +	pinfo.size_data = sizeof(*pdata); + +	glue->musb = musb = platform_device_register_full(&pinfo); +	if (IS_ERR(musb)) { +		ret = PTR_ERR(musb); +		dev_err(&pdev->dev, "failed to register musb device: %d\n", ret); +		goto err8;  	}  	return 0; +err8: +	usb_phy_generic_unregister(glue->phy); +  err7:  	clk_disable(clk); @@ -550,9 +541,6 @@ err4:  	clk_put(phy_clk);  err3: -	platform_device_put(musb); - -err1:  	kfree(glue);  err0: @@ -564,6 +552,7 @@ static int am35x_remove(struct platform_device *pdev)  	struct am35x_glue	*glue = platform_get_drvdata(pdev);  	platform_device_unregister(glue->musb); +	usb_phy_generic_unregister(glue->phy);  	clk_disable(glue->clk);  	clk_disable(glue->phy_clk);  	clk_put(glue->clk); @@ -615,23 +604,16 @@ static int am35x_resume(struct device *dev)  	return 0;  } - -static struct dev_pm_ops am35x_pm_ops = { -	.suspend	= am35x_suspend, -	.resume		= am35x_resume, -}; - -#define DEV_PM_OPS	&am35x_pm_ops -#else -#define DEV_PM_OPS	NULL  #endif +static SIMPLE_DEV_PM_OPS(am35x_pm_ops, am35x_suspend, am35x_resume); +  static struct platform_driver am35x_driver = {  	.probe		= am35x_probe,  	.remove		= am35x_remove,  	.driver		= {  		.name	= "musb-am35x", -		.pm	= DEV_PM_OPS, +		.pm	= &am35x_pm_ops,  	},  }; diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c index 72e2056b608..d40d5f0b552 100644 --- a/drivers/usb/musb/blackfin.c +++ b/drivers/usb/musb/blackfin.c @@ -11,7 +11,6 @@  #include <linux/module.h>  #include <linux/kernel.h>  #include <linux/sched.h> -#include <linux/init.h>  #include <linux/list.h>  #include <linux/gpio.h>  #include <linux/io.h> @@ -19,7 +18,7 @@  #include <linux/platform_device.h>  #include <linux/dma-mapping.h>  #include <linux/prefetch.h> -#include <linux/usb/usb_phy_gen_xceiv.h> +#include <linux/usb/usb_phy_generic.h>  #include <asm/cacheflush.h> @@ -30,6 +29,7 @@  struct bfin_glue {  	struct device		*dev;  	struct platform_device	*musb; +	struct platform_device	*phy;  };  #define glue_to_musb(g)		platform_get_drvdata(g->musb) @@ -77,7 +77,7 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)  		bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), dma_reg);  		SSYNC(); -		/* Wait for compelete */ +		/* Wait for complete */  		while (!(bfin_read_USB_DMA_INTERRUPT() & (1 << epnum)))  			cpu_relax(); @@ -131,7 +131,7 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)  		bfin_write16(USB_DMA_REG(epnum, USB_DMAx_CTRL), dma_reg);  		SSYNC(); -		/* Wait for compelete */ +		/* Wait for complete */  		while (!(bfin_read_USB_DMA_INTERRUPT() & (1 << epnum)))  			cpu_relax(); @@ -402,7 +402,6 @@ static int bfin_musb_init(struct musb *musb)  	}  	gpio_direction_output(musb->config->gpio_vrsel, 0); -	usb_nop_xceiv_register();  	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);  	if (IS_ERR_OR_NULL(musb->xceiv)) {  		gpio_free(musb->config->gpio_vrsel); @@ -425,9 +424,8 @@ static int bfin_musb_init(struct musb *musb)  static int bfin_musb_exit(struct musb *musb)  {  	gpio_free(musb->config->gpio_vrsel); -  	usb_put_phy(musb->xceiv); -	usb_nop_xceiv_unregister(); +  	return 0;  } @@ -478,6 +476,9 @@ static int bfin_probe(struct platform_device *pdev)  	pdata->platform_ops		= &bfin_ops; +	glue->phy = usb_phy_generic_register(); +	if (IS_ERR(glue->phy)) +		goto err2;  	platform_set_drvdata(pdev, glue);  	memset(musb_resources, 0x00, sizeof(*musb_resources) * @@ -515,6 +516,9 @@ static int bfin_probe(struct platform_device *pdev)  	return 0;  err3: +	usb_phy_generic_unregister(glue->phy); + +err2:  	platform_device_put(musb);  err1: @@ -529,6 +533,7 @@ static int bfin_remove(struct platform_device *pdev)  	struct bfin_glue		*glue = platform_get_drvdata(pdev);  	platform_device_unregister(glue->musb); +	usb_phy_generic_unregister(glue->phy);  	kfree(glue);  	return 0; @@ -561,23 +566,16 @@ static int bfin_resume(struct device *dev)  	return 0;  } - -static struct dev_pm_ops bfin_pm_ops = { -	.suspend	= bfin_suspend, -	.resume		= bfin_resume, -}; - -#define DEV_PM_OPS	&bfin_pm_ops -#else -#define DEV_PM_OPS	NULL  #endif +static SIMPLE_DEV_PM_OPS(bfin_pm_ops, bfin_suspend, bfin_resume); +  static struct platform_driver bfin_driver = {  	.probe		= bfin_probe,  	.remove		= __exit_p(bfin_remove),  	.driver		= {  		.name	= "musb-blackfin", -		.pm	= DEV_PM_OPS, +		.pm	= &bfin_pm_ops,  	},  }; diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index d9ddf4122f3..058775e647a 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -26,14 +26,13 @@   *   */ -#include <linux/init.h>  #include <linux/module.h>  #include <linux/clk.h>  #include <linux/err.h>  #include <linux/io.h>  #include <linux/platform_device.h>  #include <linux/dma-mapping.h> -#include <linux/usb/usb_phy_gen_xceiv.h> +#include <linux/usb/usb_phy_generic.h>  #include <mach/da8xx.h>  #include <linux/platform_data/usb-davinci.h> @@ -86,6 +85,7 @@  struct da8xx_glue {  	struct device		*dev;  	struct platform_device	*musb; +	struct platform_device	*phy;  	struct clk		*clk;  }; @@ -419,7 +419,6 @@ static int da8xx_musb_init(struct musb *musb)  	if (!rev)  		goto fail; -	usb_nop_xceiv_register();  	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);  	if (IS_ERR_OR_NULL(musb->xceiv)) {  		ret = -EPROBE_DEFER; @@ -454,7 +453,6 @@ static int da8xx_musb_exit(struct musb *musb)  	phy_off();  	usb_put_phy(musb->xceiv); -	usb_nop_xceiv_unregister();  	return 0;  } @@ -472,7 +470,11 @@ static const struct musb_platform_ops da8xx_ops = {  	.set_vbus	= da8xx_musb_set_vbus,  }; -static u64 da8xx_dmamask = DMA_BIT_MASK(32); +static const struct platform_device_info da8xx_dev_info = { +	.name		= "musb-hdrc", +	.id		= PLATFORM_DEVID_AUTO, +	.dma_mask	= DMA_BIT_MASK(32), +};  static int da8xx_probe(struct platform_device *pdev)  { @@ -480,7 +482,7 @@ static int da8xx_probe(struct platform_device *pdev)  	struct musb_hdrc_platform_data	*pdata = dev_get_platdata(&pdev->dev);  	struct platform_device		*musb;  	struct da8xx_glue		*glue; - +	struct platform_device_info	pinfo;  	struct clk			*clk;  	int				ret = -ENOMEM; @@ -491,12 +493,6 @@ static int da8xx_probe(struct platform_device *pdev)  		goto err0;  	} -	musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); -	if (!musb) { -		dev_err(&pdev->dev, "failed to allocate musb device\n"); -		goto err1; -	} -  	clk = clk_get(&pdev->dev, "usb20");  	if (IS_ERR(clk)) {  		dev_err(&pdev->dev, "failed to get clock\n"); @@ -510,16 +506,16 @@ static int da8xx_probe(struct platform_device *pdev)  		goto err4;  	} -	musb->dev.parent		= &pdev->dev; -	musb->dev.dma_mask		= &da8xx_dmamask; -	musb->dev.coherent_dma_mask	= da8xx_dmamask; -  	glue->dev			= &pdev->dev; -	glue->musb			= musb;  	glue->clk			= clk;  	pdata->platform_ops		= &da8xx_ops; +	glue->phy = usb_phy_generic_register(); +	if (IS_ERR(glue->phy)) { +		ret = PTR_ERR(glue->phy); +		goto err5; +	}  	platform_set_drvdata(pdev, glue);  	memset(musb_resources, 0x00, sizeof(*musb_resources) * @@ -535,27 +531,25 @@ static int da8xx_probe(struct platform_device *pdev)  	musb_resources[1].end = pdev->resource[1].end;  	musb_resources[1].flags = pdev->resource[1].flags; -	ret = platform_device_add_resources(musb, musb_resources, -			ARRAY_SIZE(musb_resources)); -	if (ret) { -		dev_err(&pdev->dev, "failed to add resources\n"); -		goto err5; -	} - -	ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); -	if (ret) { -		dev_err(&pdev->dev, "failed to add platform_data\n"); -		goto err5; -	} - -	ret = platform_device_add(musb); -	if (ret) { -		dev_err(&pdev->dev, "failed to register musb device\n"); -		goto err5; +	pinfo = da8xx_dev_info; +	pinfo.parent = &pdev->dev; +	pinfo.res = musb_resources; +	pinfo.num_res = ARRAY_SIZE(musb_resources); +	pinfo.data = pdata; +	pinfo.size_data = sizeof(*pdata); + +	glue->musb = musb = platform_device_register_full(&pinfo); +	if (IS_ERR(musb)) { +		ret = PTR_ERR(musb); +		dev_err(&pdev->dev, "failed to register musb device: %d\n", ret); +		goto err6;  	}  	return 0; +err6: +	usb_phy_generic_unregister(glue->phy); +  err5:  	clk_disable(clk); @@ -563,9 +557,6 @@ err4:  	clk_put(clk);  err3: -	platform_device_put(musb); - -err1:  	kfree(glue);  err0: @@ -577,6 +568,7 @@ static int da8xx_remove(struct platform_device *pdev)  	struct da8xx_glue		*glue = platform_get_drvdata(pdev);  	platform_device_unregister(glue->musb); +	usb_phy_generic_unregister(glue->phy);  	clk_disable(glue->clk);  	clk_put(glue->clk);  	kfree(glue); diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c index ed0834e2b72..de8492b06e4 100644 --- a/drivers/usb/musb/davinci.c +++ b/drivers/usb/musb/davinci.c @@ -24,7 +24,6 @@  #include <linux/module.h>  #include <linux/kernel.h>  #include <linux/sched.h> -#include <linux/init.h>  #include <linux/list.h>  #include <linux/delay.h>  #include <linux/clk.h> @@ -33,7 +32,7 @@  #include <linux/gpio.h>  #include <linux/platform_device.h>  #include <linux/dma-mapping.h> -#include <linux/usb/usb_phy_gen_xceiv.h> +#include <linux/usb/usb_phy_generic.h>  #include <mach/cputype.h>  #include <mach/hardware.h> @@ -382,7 +381,6 @@ static int davinci_musb_init(struct musb *musb)  	u32		revision;  	int 		ret = -ENODEV; -	usb_nop_xceiv_register();  	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);  	if (IS_ERR_OR_NULL(musb->xceiv)) {  		ret = -EPROBE_DEFER; @@ -440,7 +438,7 @@ static int davinci_musb_init(struct musb *musb)  fail:  	usb_put_phy(musb->xceiv);  unregister: -	usb_nop_xceiv_unregister(); +	usb_phy_generic_unregister();  	return ret;  } @@ -488,7 +486,6 @@ static int davinci_musb_exit(struct musb *musb)  	phy_off();  	usb_put_phy(musb->xceiv); -	usb_nop_xceiv_unregister();  	return 0;  } @@ -505,14 +502,19 @@ static const struct musb_platform_ops davinci_ops = {  	.set_vbus	= davinci_musb_set_vbus,  }; -static u64 davinci_dmamask = DMA_BIT_MASK(32); +static const struct platform_device_info davinci_dev_info = { +	.name		= "musb-hdrc", +	.id		= PLATFORM_DEVID_AUTO, +	.dma_mask	= DMA_BIT_MASK(32), +};  static int davinci_probe(struct platform_device *pdev)  { -	struct resource musb_resources[2]; +	struct resource			musb_resources[3];  	struct musb_hdrc_platform_data	*pdata = dev_get_platdata(&pdev->dev);  	struct platform_device		*musb;  	struct davinci_glue		*glue; +	struct platform_device_info	pinfo;  	struct clk			*clk;  	int				ret = -ENOMEM; @@ -523,12 +525,6 @@ static int davinci_probe(struct platform_device *pdev)  		goto err0;  	} -	musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); -	if (!musb) { -		dev_err(&pdev->dev, "failed to allocate musb device\n"); -		goto err1; -	} -  	clk = clk_get(&pdev->dev, "usb");  	if (IS_ERR(clk)) {  		dev_err(&pdev->dev, "failed to get clock\n"); @@ -542,16 +538,12 @@ static int davinci_probe(struct platform_device *pdev)  		goto err4;  	} -	musb->dev.parent		= &pdev->dev; -	musb->dev.dma_mask		= &davinci_dmamask; -	musb->dev.coherent_dma_mask	= davinci_dmamask; -  	glue->dev			= &pdev->dev; -	glue->musb			= musb;  	glue->clk			= clk;  	pdata->platform_ops		= &davinci_ops; +	usb_phy_generic_register();  	platform_set_drvdata(pdev, glue);  	memset(musb_resources, 0x00, sizeof(*musb_resources) * @@ -567,22 +559,26 @@ static int davinci_probe(struct platform_device *pdev)  	musb_resources[1].end = pdev->resource[1].end;  	musb_resources[1].flags = pdev->resource[1].flags; -	ret = platform_device_add_resources(musb, musb_resources, -			ARRAY_SIZE(musb_resources)); -	if (ret) { -		dev_err(&pdev->dev, "failed to add resources\n"); -		goto err5; -	} - -	ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); -	if (ret) { -		dev_err(&pdev->dev, "failed to add platform_data\n"); -		goto err5; -	} - -	ret = platform_device_add(musb); -	if (ret) { -		dev_err(&pdev->dev, "failed to register musb device\n"); +	/* +	 * For DM6467 3 resources are passed. A placeholder for the 3rd +	 * resource is always there, so it's safe to always copy it... +	 */ +	musb_resources[2].name = pdev->resource[2].name; +	musb_resources[2].start = pdev->resource[2].start; +	musb_resources[2].end = pdev->resource[2].end; +	musb_resources[2].flags = pdev->resource[2].flags; + +	pinfo = davinci_dev_info; +	pinfo.parent = &pdev->dev; +	pinfo.res = musb_resources; +	pinfo.num_res = ARRAY_SIZE(musb_resources); +	pinfo.data = pdata; +	pinfo.size_data = sizeof(*pdata); + +	glue->musb = musb = platform_device_register_full(&pinfo); +	if (IS_ERR(musb)) { +		ret = PTR_ERR(musb); +		dev_err(&pdev->dev, "failed to register musb device: %d\n", ret);  		goto err5;  	} @@ -595,9 +591,6 @@ err4:  	clk_put(clk);  err3: -	platform_device_put(musb); - -err1:  	kfree(glue);  err0: @@ -609,6 +602,7 @@ static int davinci_remove(struct platform_device *pdev)  	struct davinci_glue		*glue = platform_get_drvdata(pdev);  	platform_device_unregister(glue->musb); +	usb_phy_generic_unregister();  	clk_disable(glue->clk);  	clk_put(glue->clk);  	kfree(glue); diff --git a/drivers/usb/musb/jz4740.c b/drivers/usb/musb/jz4740.c new file mode 100644 index 00000000000..5f30537f192 --- /dev/null +++ b/drivers/usb/musb/jz4740.c @@ -0,0 +1,201 @@ +/* + * Ingenic JZ4740 "glue layer" + * + * Copyright (C) 2013, Apelete Seketeli <apelete@seketeli.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/clk.h> +#include <linux/dma-mapping.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#include "musb_core.h" + +struct jz4740_glue { +	struct device           *dev; +	struct platform_device  *musb; +	struct clk		*clk; +}; + +static irqreturn_t jz4740_musb_interrupt(int irq, void *__hci) +{ +	unsigned long   flags; +	irqreturn_t     retval = IRQ_NONE; +	struct musb     *musb = __hci; + +	spin_lock_irqsave(&musb->lock, flags); + +	musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); +	musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); +	musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); + +	/* +	 * The controller is gadget only, the state of the host mode IRQ bits is +	 * undefined. Mask them to make sure that the musb driver core will +	 * never see them set +	 */ +	musb->int_usb &= MUSB_INTR_SUSPEND | MUSB_INTR_RESUME | +	    MUSB_INTR_RESET | MUSB_INTR_SOF; + +	if (musb->int_usb || musb->int_tx || musb->int_rx) +		retval = musb_interrupt(musb); + +	spin_unlock_irqrestore(&musb->lock, flags); + +	return retval; +} + +static struct musb_fifo_cfg jz4740_musb_fifo_cfg[] = { +{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, }, +{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, }, +{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 64, }, +}; + +static struct musb_hdrc_config jz4740_musb_config = { +	/* Silicon does not implement USB OTG. */ +	.multipoint = 0, +	/* Max EPs scanned, driver will decide which EP can be used. */ +	.num_eps    = 4, +	/* RAMbits needed to configure EPs from table */ +	.ram_bits   = 9, +	.fifo_cfg = jz4740_musb_fifo_cfg, +	.fifo_cfg_size = ARRAY_SIZE(jz4740_musb_fifo_cfg), +}; + +static struct musb_hdrc_platform_data jz4740_musb_platform_data = { +	.mode   = MUSB_PERIPHERAL, +	.config = &jz4740_musb_config, +}; + +static int jz4740_musb_init(struct musb *musb) +{ +	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); +	if (!musb->xceiv) { +		pr_err("HS UDC: no transceiver configured\n"); +		return -ENODEV; +	} + +	/* Silicon does not implement ConfigData register. +	 * Set dyn_fifo to avoid reading EP config from hardware. +	 */ +	musb->dyn_fifo = true; + +	musb->isr = jz4740_musb_interrupt; + +	return 0; +} + +static int jz4740_musb_exit(struct musb *musb) +{ +	usb_put_phy(musb->xceiv); + +	return 0; +} + +static const struct musb_platform_ops jz4740_musb_ops = { +	.init		= jz4740_musb_init, +	.exit		= jz4740_musb_exit, +}; + +static int jz4740_probe(struct platform_device *pdev) +{ +	struct musb_hdrc_platform_data	*pdata = &jz4740_musb_platform_data; +	struct platform_device		*musb; +	struct jz4740_glue		*glue; +	struct clk                      *clk; +	int				ret; + +	glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); +	if (!glue) +		return -ENOMEM; + +	musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); +	if (!musb) { +		dev_err(&pdev->dev, "failed to allocate musb device\n"); +		return -ENOMEM; +	} + +	clk = devm_clk_get(&pdev->dev, "udc"); +	if (IS_ERR(clk)) { +		dev_err(&pdev->dev, "failed to get clock\n"); +		ret = PTR_ERR(clk); +		goto err_platform_device_put; +	} + +	ret = clk_prepare_enable(clk); +	if (ret) { +		dev_err(&pdev->dev, "failed to enable clock\n"); +		goto err_platform_device_put; +	} + +	musb->dev.parent		= &pdev->dev; + +	glue->dev			= &pdev->dev; +	glue->musb			= musb; +	glue->clk			= clk; + +	pdata->platform_ops		= &jz4740_musb_ops; + +	platform_set_drvdata(pdev, glue); + +	ret = platform_device_add_resources(musb, pdev->resource, +					    pdev->num_resources); +	if (ret) { +		dev_err(&pdev->dev, "failed to add resources\n"); +		goto err_clk_disable; +	} + +	ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); +	if (ret) { +		dev_err(&pdev->dev, "failed to add platform_data\n"); +		goto err_clk_disable; +	} + +	ret = platform_device_add(musb); +	if (ret) { +		dev_err(&pdev->dev, "failed to register musb device\n"); +		goto err_clk_disable; +	} + +	return 0; + +err_clk_disable: +	clk_disable_unprepare(clk); +err_platform_device_put: +	platform_device_put(musb); +	return ret; +} + +static int jz4740_remove(struct platform_device *pdev) +{ +	struct jz4740_glue	*glue = platform_get_drvdata(pdev); + +	platform_device_unregister(glue->musb); +	clk_disable_unprepare(glue->clk); + +	return 0; +} + +static struct platform_driver jz4740_driver = { +	.probe		= jz4740_probe, +	.remove		= jz4740_remove, +	.driver		= { +		.name	= "musb-jz4740", +	}, +}; + +MODULE_DESCRIPTION("JZ4740 MUSB Glue Layer"); +MODULE_AUTHOR("Apelete Seketeli <apelete@seketeli.net>"); +MODULE_LICENSE("GPL v2"); +module_platform_driver(jz4740_driver); diff --git a/drivers/usb/musb/musb_am335x.c b/drivers/usb/musb/musb_am335x.c index 41ac5b5b57c..1e58ed2361c 100644 --- a/drivers/usb/musb/musb_am335x.c +++ b/drivers/usb/musb/musb_am335x.c @@ -1,4 +1,3 @@ -#include <linux/init.h>  #include <linux/platform_device.h>  #include <linux/pm_runtime.h>  #include <linux/module.h> @@ -20,21 +19,6 @@ err:  	return ret;  } -static int of_remove_populated_child(struct device *dev, void *d) -{ -	struct platform_device *pdev = to_platform_device(dev); - -	of_device_unregister(pdev); -	return 0; -} - -static int am335x_child_remove(struct platform_device *pdev) -{ -	device_for_each_child(&pdev->dev, NULL, of_remove_populated_child); -	pm_runtime_disable(&pdev->dev); -	return 0; -} -  static const struct of_device_id am335x_child_of_match[] = {  	{ .compatible = "ti,am33xx-usb" },  	{  }, @@ -43,13 +27,17 @@ MODULE_DEVICE_TABLE(of, am335x_child_of_match);  static struct platform_driver am335x_child_driver = {  	.probe		= am335x_child_probe, -	.remove         = am335x_child_remove,  	.driver         = {  		.name   = "am335x-usb-childs", -		.of_match_table	= of_match_ptr(am335x_child_of_match), +		.of_match_table	= am335x_child_of_match,  	},  }; -module_platform_driver(am335x_child_driver); +static int __init am335x_child_init(void) +{ +	return platform_driver_register(&am335x_child_driver); +} +module_init(am335x_child_init); +  MODULE_DESCRIPTION("AM33xx child devices");  MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 18e877ffe7b..eff3c5cf84f 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -83,7 +83,7 @@   * This gets many kinds of configuration information:   *	- Kconfig for everything user-configurable   *	- platform_device for addressing, irq, and platform_data - *	- platform_data is mostly for board-specific informarion + *	- platform_data is mostly for board-specific information   *	  (plus recentrly, SOC or family details)   *   * Most of the conditional compilation will (someday) vanish. @@ -93,7 +93,6 @@  #include <linux/kernel.h>  #include <linux/sched.h>  #include <linux/slab.h> -#include <linux/init.h>  #include <linux/list.h>  #include <linux/kobject.h>  #include <linux/prefetch.h> @@ -439,7 +438,6 @@ void musb_hnp_stop(struct musb *musb)  static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,  				u8 devctl)  { -	struct usb_otg *otg = musb->xceiv->otg;  	irqreturn_t handled = IRQ_NONE;  	dev_dbg(musb->controller, "<== DevCtl=%02x, int_usb=0x%x\n", devctl, @@ -479,7 +477,10 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,  						(USB_PORT_STAT_C_SUSPEND << 16)  						| MUSB_PORT_STAT_RESUME;  				musb->rh_timer = jiffies -						+ msecs_to_jiffies(20); +						 + msecs_to_jiffies(20); +				schedule_delayed_work( +					&musb->finish_resume_work, +					msecs_to_jiffies(20));  				musb->xceiv->state = OTG_STATE_A_HOST;  				musb->is_active = 1; @@ -617,7 +618,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,  				/* case 3 << MUSB_DEVCTL_VBUS_SHIFT: */  				default:  					s = "VALID"; break; -				}; s; }), +				} s; }),  				VBUSERR_RETRY_COUNT - musb->vbuserr_retry,  				musb->port1_status); @@ -654,7 +655,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,  				break;  		case OTG_STATE_B_PERIPHERAL:  			musb_g_suspend(musb); -			musb->is_active = otg->gadget->b_hnp_enable; +			musb->is_active = musb->g.b_hnp_enable;  			if (musb->is_active) {  				musb->xceiv->state = OTG_STATE_B_WAIT_ACON;  				dev_dbg(musb->controller, "HNP: Setting timer for b_ase0_brst\n"); @@ -670,7 +671,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,  			break;  		case OTG_STATE_A_HOST:  			musb->xceiv->state = OTG_STATE_A_SUSPEND; -			musb->is_active = otg->host->b_hnp_enable; +			musb->is_active = musb->hcd->self.b_hnp_enable;  			break;  		case OTG_STATE_B_HOST:  			/* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */ @@ -847,6 +848,10 @@ b_host:  		}  	} +	/* handle babble condition */ +	if (int_usb & MUSB_INTR_BABBLE && is_host_active(musb)) +		schedule_work(&musb->recover_work); +  #if 0  /* REVISIT ... this would be for multiplexing periodic endpoints, or   * supporting transfer phasing to prevent exceeding ISO bandwidth @@ -922,6 +927,52 @@ static void musb_generic_disable(struct musb *musb)  }  /* + * Program the HDRC to start (enable interrupts, dma, etc.). + */ +void musb_start(struct musb *musb) +{ +	void __iomem    *regs = musb->mregs; +	u8              devctl = musb_readb(regs, MUSB_DEVCTL); + +	dev_dbg(musb->controller, "<== devctl %02x\n", devctl); + +	/*  Set INT enable registers, enable interrupts */ +	musb->intrtxe = musb->epmask; +	musb_writew(regs, MUSB_INTRTXE, musb->intrtxe); +	musb->intrrxe = musb->epmask & 0xfffe; +	musb_writew(regs, MUSB_INTRRXE, musb->intrrxe); +	musb_writeb(regs, MUSB_INTRUSBE, 0xf7); + +	musb_writeb(regs, MUSB_TESTMODE, 0); + +	/* put into basic highspeed mode and start session */ +	musb_writeb(regs, MUSB_POWER, MUSB_POWER_ISOUPDATE +			| MUSB_POWER_HSENAB +			/* ENSUSPEND wedges tusb */ +			/* | MUSB_POWER_ENSUSPEND */ +		   ); + +	musb->is_active = 0; +	devctl = musb_readb(regs, MUSB_DEVCTL); +	devctl &= ~MUSB_DEVCTL_SESSION; + +	/* session started after: +	 * (a) ID-grounded irq, host mode; +	 * (b) vbus present/connect IRQ, peripheral mode; +	 * (c) peripheral initiates, using SRP +	 */ +	if (musb->port_mode != MUSB_PORT_MODE_HOST && +			(devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) { +		musb->is_active = 1; +	} else { +		devctl |= MUSB_DEVCTL_SESSION; +	} + +	musb_platform_enable(musb); +	musb_writeb(regs, MUSB_DEVCTL, devctl); +} + +/*   * Make the HDRC stop (disable interrupts, etc.);   * reversible by musb_start   * called on gadget driver unregister @@ -1141,7 +1192,7 @@ fifo_setup(struct musb *musb, struct musb_hw_ep  *hw_ep,  	musb_writeb(mbase, MUSB_INDEX, hw_ep->epnum);  	/* EP0 reserved endpoint for control, bidirectional; -	 * EP1 reserved for bulk, two unidirection halves. +	 * EP1 reserved for bulk, two unidirectional halves.  	 */  	if (hw_ep->epnum == 1)  		musb->bulk_ep = hw_ep; @@ -1699,6 +1750,34 @@ static void musb_irq_work(struct work_struct *data)  	}  } +/* Recover from babble interrupt conditions */ +static void musb_recover_work(struct work_struct *data) +{ +	struct musb *musb = container_of(data, struct musb, recover_work); +	int status; + +	musb_platform_reset(musb); + +	usb_phy_vbus_off(musb->xceiv); +	udelay(100); + +	usb_phy_vbus_on(musb->xceiv); +	udelay(100); + +	/* +	 * When a babble condition occurs, the musb controller removes the +	 * session bit and the endpoint config is lost. +	 */ +	if (musb->dyn_fifo) +		status = ep_config_from_table(musb); +	else +		status = ep_config_from_hw(musb); + +	/* start the session again */ +	if (status == 0) +		musb_start(musb); +} +  /* --------------------------------------------------------------------------   * Init support   */ @@ -1763,12 +1842,25 @@ static void musb_free(struct musb *musb)  			disable_irq_wake(musb->nIrq);  		free_irq(musb->nIrq, musb);  	} -	if (musb->dma_controller) -		dma_controller_destroy(musb->dma_controller);  	musb_host_free(musb);  } +static void musb_deassert_reset(struct work_struct *work) +{ +	struct musb *musb; +	unsigned long flags; + +	musb = container_of(work, struct musb, deassert_reset_work.work); + +	spin_lock_irqsave(&musb->lock, flags); + +	if (musb->port1_status & USB_PORT_STAT_RESET) +		musb_port_reset(musb, false); + +	spin_unlock_irqrestore(&musb->lock, flags); +} +  /*   * Perform generic per-controller initialization.   * @@ -1813,7 +1905,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)  	/* The musb_platform_init() call:  	 *   - adjusts musb->mregs  	 *   - sets the musb->isr -	 *   - may initialize an integrated tranceiver +	 *   - may initialize an integrated transceiver  	 *   - initializes musb->xceiv, usually by otg_get_phy()  	 *   - stops powering VBUS  	 * @@ -1839,13 +1931,24 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)  	pm_runtime_get_sync(musb->controller); -	if (use_dma && dev->dma_mask) +	if (use_dma && dev->dma_mask) {  		musb->dma_controller = dma_controller_create(musb, musb->mregs); +		if (IS_ERR(musb->dma_controller)) { +			status = PTR_ERR(musb->dma_controller); +			goto fail2_5; +		} +	}  	/* be sure interrupts are disabled before connecting ISR */  	musb_platform_disable(musb);  	musb_generic_disable(musb); +	/* Init IRQ workqueue before request_irq */ +	INIT_WORK(&musb->irq_work, musb_irq_work); +	INIT_WORK(&musb->recover_work, musb_recover_work); +	INIT_DELAYED_WORK(&musb->deassert_reset_work, musb_deassert_reset); +	INIT_DELAYED_WORK(&musb->finish_resume_work, musb_host_finish_resume); +  	/* setup musb parts of the core (especially endpoints) */  	status = musb_core_init(plat->config->multipoint  			? MUSB_CONTROLLER_MHDRC @@ -1855,9 +1958,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)  	setup_timer(&musb->otg_timer, musb_otg_timer_func, (unsigned long) musb); -	/* Init IRQ workqueue before request_irq */ -	INIT_WORK(&musb->irq_work, musb_irq_work); -  	/* attach to the IRQ */  	if (request_irq(nIrq, musb->isr, 0, dev_name(dev), musb)) {  		dev_err(dev, "request_irq %d failed!\n", nIrq); @@ -1891,15 +1991,26 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)  	switch (musb->port_mode) {  	case MUSB_PORT_MODE_HOST:  		status = musb_host_setup(musb, plat->power); +		if (status < 0) +			goto fail3; +		status = musb_platform_set_mode(musb, MUSB_HOST);  		break;  	case MUSB_PORT_MODE_GADGET:  		status = musb_gadget_setup(musb); +		if (status < 0) +			goto fail3; +		status = musb_platform_set_mode(musb, MUSB_PERIPHERAL);  		break;  	case MUSB_PORT_MODE_DUAL_ROLE:  		status = musb_host_setup(musb, plat->power);  		if (status < 0)  			goto fail3;  		status = musb_gadget_setup(musb); +		if (status) { +			musb_host_cleanup(musb); +			goto fail3; +		} +		status = musb_platform_set_mode(musb, MUSB_OTG);  		break;  	default:  		dev_err(dev, "unsupported port mode %d\n", musb->port_mode); @@ -1926,10 +2037,16 @@ fail5:  fail4:  	musb_gadget_cleanup(musb); +	musb_host_cleanup(musb);  fail3: +	cancel_work_sync(&musb->irq_work); +	cancel_work_sync(&musb->recover_work); +	cancel_delayed_work_sync(&musb->finish_resume_work); +	cancel_delayed_work_sync(&musb->deassert_reset_work);  	if (musb->dma_controller)  		dma_controller_destroy(musb->dma_controller); +fail2_5:  	pm_runtime_put_sync(musb->controller);  fail2: @@ -1986,6 +2103,13 @@ static int musb_remove(struct platform_device *pdev)  	musb_exit_debugfs(musb);  	musb_shutdown(pdev); +	if (musb->dma_controller) +		dma_controller_destroy(musb->dma_controller); + +	cancel_work_sync(&musb->irq_work); +	cancel_work_sync(&musb->recover_work); +	cancel_delayed_work_sync(&musb->finish_resume_work); +	cancel_delayed_work_sync(&musb->deassert_reset_work);  	musb_free(musb);  	device_init_wakeup(dev, 0);  	return 0; @@ -2070,11 +2194,19 @@ static void musb_restore_context(struct musb *musb)  	void __iomem *musb_base = musb->mregs;  	void __iomem *ep_target_regs;  	void __iomem *epio; +	u8 power;  	musb_writew(musb_base, MUSB_FRAME, musb->context.frame);  	musb_writeb(musb_base, MUSB_TESTMODE, musb->context.testmode);  	musb_write_ulpi_buscontrol(musb->mregs, musb->context.busctl); -	musb_writeb(musb_base, MUSB_POWER, musb->context.power); + +	/* Don't affect SUSPENDM/RESUME bits in POWER reg */ +	power = musb_readb(musb_base, MUSB_POWER); +	power &= MUSB_POWER_SUSPENDM | MUSB_POWER_RESUME; +	musb->context.power &= ~(MUSB_POWER_SUSPENDM | MUSB_POWER_RESUME); +	power |= musb->context.power; +	musb_writeb(musb_base, MUSB_POWER, power); +  	musb_writew(musb_base, MUSB_INTRTXE, musb->intrtxe);  	musb_writew(musb_base, MUSB_INTRRXE, musb->intrrxe);  	musb_writeb(musb_base, MUSB_INTRUSBE, musb->context.intrusbe); @@ -2158,16 +2290,28 @@ static int musb_suspend(struct device *dev)  		 */  	} +	musb_save_context(musb); +  	spin_unlock_irqrestore(&musb->lock, flags);  	return 0;  }  static int musb_resume_noirq(struct device *dev)  { -	/* for static cmos like DaVinci, register values were preserved +	struct musb	*musb = dev_to_musb(dev); + +	/* +	 * For static cmos like DaVinci, register values were preserved  	 * unless for some reason the whole soc powered down or the USB  	 * module got reset through the PSC (vs just being disabled). +	 * +	 * For the DSPS glue layer though, a full register restore has to +	 * be done. As it shouldn't harm other platforms, we do it +	 * unconditionally.  	 */ + +	musb_restore_context(musb); +  	return 0;  } @@ -2225,19 +2369,4 @@ static struct platform_driver musb_driver = {  	.shutdown	= musb_shutdown,  }; -/*-------------------------------------------------------------------------*/ - -static int __init musb_init(void) -{ -	if (usb_disabled()) -		return 0; - -	return platform_driver_register(&musb_driver); -} -module_init(musb_init); - -static void __exit musb_cleanup(void) -{ -	platform_driver_unregister(&musb_driver); -} -module_exit(musb_cleanup); +module_platform_driver(musb_driver); diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 65f3917b4fc..d155a156f24 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -46,6 +46,8 @@  #include <linux/usb.h>  #include <linux/usb/otg.h>  #include <linux/usb/musb.h> +#include <linux/phy/phy.h> +#include <linux/workqueue.h>  struct musb;  struct musb_hw_ep; @@ -190,6 +192,7 @@ struct musb_platform_ops {  	int	(*set_mode)(struct musb *musb, u8 mode);  	void	(*try_idle)(struct musb *musb, unsigned long timeout); +	void	(*reset)(struct musb *musb);  	int	(*vbus_status)(struct musb *musb);  	void	(*set_vbus)(struct musb *musb, int on); @@ -294,6 +297,9 @@ struct musb {  	irqreturn_t		(*isr)(int, void *);  	struct work_struct	irq_work; +	struct work_struct	recover_work; +	struct delayed_work	deassert_reset_work; +	struct delayed_work	finish_resume_work;  	u16			hwvers;  	u16			intrrxe; @@ -333,6 +339,7 @@ struct musb {  	dma_addr_t		async;  	dma_addr_t		sync;  	void __iomem		*sync_va; +	u8			tusb_revision;  #endif  	/* passed down from chip/board specific irq handlers */ @@ -341,6 +348,7 @@ struct musb {  	u16			int_tx;  	struct usb_phy		*xceiv; +	struct phy		*phy;  	int nIrq;  	unsigned		irq_wake:1; @@ -503,6 +511,7 @@ static inline void musb_configure_ep0(struct musb *musb)  extern const char musb_driver_name[];  extern void musb_stop(struct musb *musb); +extern void musb_start(struct musb *musb);  extern void musb_write_fifo(struct musb_hw_ep *ep, u16 len, const u8 *src);  extern void musb_read_fifo(struct musb_hw_ep *ep, u16 len, u8 *dst); @@ -546,6 +555,12 @@ static inline void musb_platform_try_idle(struct musb *musb,  		musb->ops->try_idle(musb, timeout);  } +static inline void musb_platform_reset(struct musb *musb) +{ +	if (musb->ops->reset) +		musb->ops->reset(musb); +} +  static inline int musb_platform_get_vbus_status(struct musb *musb)  {  	if (!musb->ops->vbus_status) diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c index ae959746f77..5341bb223b7 100644 --- a/drivers/usb/musb/musb_cppi41.c +++ b/drivers/usb/musb/musb_cppi41.c @@ -38,6 +38,8 @@ struct cppi41_dma_channel {  	u32 prog_len;  	u32 transferred;  	u32 packet_sz; +	struct list_head tx_check; +	struct work_struct dma_completion;  };  #define MUSB_DMA_NUM_CHANNELS 15 @@ -47,6 +49,8 @@ struct cppi41_dma_controller {  	struct cppi41_dma_channel rx_channel[MUSB_DMA_NUM_CHANNELS];  	struct cppi41_dma_channel tx_channel[MUSB_DMA_NUM_CHANNELS];  	struct musb *musb; +	struct hrtimer early_tx; +	struct list_head early_tx_list;  	u32 rx_mode;  	u32 tx_mode;  	u32 auto_req; @@ -96,31 +100,40 @@ static void update_rx_toggle(struct cppi41_dma_channel *cppi41_channel)  	cppi41_channel->usb_toggle = toggle;  } -static void cppi41_dma_callback(void *private_data) +static bool musb_is_tx_fifo_empty(struct musb_hw_ep *hw_ep)  { -	struct dma_channel *channel = private_data; -	struct cppi41_dma_channel *cppi41_channel = channel->private_data; -	struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep; -	struct musb *musb = hw_ep->musb; -	unsigned long flags; -	struct dma_tx_state txstate; -	u32 transferred; +	u8		epnum = hw_ep->epnum; +	struct musb	*musb = hw_ep->musb; +	void __iomem	*epio = musb->endpoints[epnum].regs; +	u16		csr; -	spin_lock_irqsave(&musb->lock, flags); +	csr = musb_readw(epio, MUSB_TXCSR); +	if (csr & MUSB_TXCSR_TXPKTRDY) +		return false; +	return true; +} -	dmaengine_tx_status(cppi41_channel->dc, cppi41_channel->cookie, -			&txstate); -	transferred = cppi41_channel->prog_len - txstate.residue; -	cppi41_channel->transferred += transferred; +static bool is_isoc(struct musb_hw_ep *hw_ep, bool in) +{ +	if (in && hw_ep->in_qh) { +		if (hw_ep->in_qh->type == USB_ENDPOINT_XFER_ISOC) +			return true; +	} else if (hw_ep->out_qh) { +		if (hw_ep->out_qh->type == USB_ENDPOINT_XFER_ISOC) +			return true; +	} +	return false; +} -	dev_dbg(musb->controller, "DMA transfer done on hw_ep=%d bytes=%d/%d\n", -		hw_ep->epnum, cppi41_channel->transferred, -		cppi41_channel->total_len); +static void cppi41_dma_callback(void *private_data); -	update_rx_toggle(cppi41_channel); +static void cppi41_trans_done(struct cppi41_dma_channel *cppi41_channel) +{ +	struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep; +	struct musb *musb = hw_ep->musb; -	if (cppi41_channel->transferred == cppi41_channel->total_len || -			transferred < cppi41_channel->packet_sz) { +	if (!cppi41_channel->prog_len || +	    (cppi41_channel->channel.status == MUSB_DMA_STATUS_FREE)) {  		/* done, complete */  		cppi41_channel->channel.actual_len = @@ -150,13 +163,11 @@ static void cppi41_dma_callback(void *private_data)  				remain_bytes,  				direction,  				DMA_PREP_INTERRUPT | DMA_CTRL_ACK); -		if (WARN_ON(!dma_desc)) { -			spin_unlock_irqrestore(&musb->lock, flags); +		if (WARN_ON(!dma_desc))  			return; -		}  		dma_desc->callback = cppi41_dma_callback; -		dma_desc->callback_param = channel; +		dma_desc->callback_param = &cppi41_channel->channel;  		cppi41_channel->cookie = dma_desc->tx_submit(dma_desc);  		dma_async_issue_pending(dc); @@ -166,6 +177,155 @@ static void cppi41_dma_callback(void *private_data)  			musb_writew(epio, MUSB_RXCSR, csr);  		}  	} +} + +static void cppi_trans_done_work(struct work_struct *work) +{ +	unsigned long flags; +	struct cppi41_dma_channel *cppi41_channel = +		container_of(work, struct cppi41_dma_channel, dma_completion); +	struct cppi41_dma_controller *controller = cppi41_channel->controller; +	struct musb *musb = controller->musb; +	struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep; +	bool empty; + +	if (!cppi41_channel->is_tx && is_isoc(hw_ep, 1)) { +		spin_lock_irqsave(&musb->lock, flags); +		cppi41_trans_done(cppi41_channel); +		spin_unlock_irqrestore(&musb->lock, flags); +	} else { +		empty = musb_is_tx_fifo_empty(hw_ep); +		if (empty) { +			spin_lock_irqsave(&musb->lock, flags); +			cppi41_trans_done(cppi41_channel); +			spin_unlock_irqrestore(&musb->lock, flags); +		} else { +			schedule_work(&cppi41_channel->dma_completion); +		} +	} +} + +static enum hrtimer_restart cppi41_recheck_tx_req(struct hrtimer *timer) +{ +	struct cppi41_dma_controller *controller; +	struct cppi41_dma_channel *cppi41_channel, *n; +	struct musb *musb; +	unsigned long flags; +	enum hrtimer_restart ret = HRTIMER_NORESTART; + +	controller = container_of(timer, struct cppi41_dma_controller, +			early_tx); +	musb = controller->musb; + +	spin_lock_irqsave(&musb->lock, flags); +	list_for_each_entry_safe(cppi41_channel, n, &controller->early_tx_list, +			tx_check) { +		bool empty; +		struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep; + +		empty = musb_is_tx_fifo_empty(hw_ep); +		if (empty) { +			list_del_init(&cppi41_channel->tx_check); +			cppi41_trans_done(cppi41_channel); +		} +	} + +	if (!list_empty(&controller->early_tx_list)) { +		ret = HRTIMER_RESTART; +		hrtimer_forward_now(&controller->early_tx, +				ktime_set(0, 150 * NSEC_PER_USEC)); +	} + +	spin_unlock_irqrestore(&musb->lock, flags); +	return ret; +} + +static void cppi41_dma_callback(void *private_data) +{ +	struct dma_channel *channel = private_data; +	struct cppi41_dma_channel *cppi41_channel = channel->private_data; +	struct musb_hw_ep *hw_ep = cppi41_channel->hw_ep; +	struct musb *musb = hw_ep->musb; +	unsigned long flags; +	struct dma_tx_state txstate; +	u32 transferred; +	bool empty; + +	spin_lock_irqsave(&musb->lock, flags); + +	dmaengine_tx_status(cppi41_channel->dc, cppi41_channel->cookie, +			&txstate); +	transferred = cppi41_channel->prog_len - txstate.residue; +	cppi41_channel->transferred += transferred; + +	dev_dbg(musb->controller, "DMA transfer done on hw_ep=%d bytes=%d/%d\n", +		hw_ep->epnum, cppi41_channel->transferred, +		cppi41_channel->total_len); + +	update_rx_toggle(cppi41_channel); + +	if (cppi41_channel->transferred == cppi41_channel->total_len || +			transferred < cppi41_channel->packet_sz) +		cppi41_channel->prog_len = 0; + +	if (!cppi41_channel->is_tx) { +		if (is_isoc(hw_ep, 1)) +			schedule_work(&cppi41_channel->dma_completion); +		else +			cppi41_trans_done(cppi41_channel); +		goto out; +	} + +	empty = musb_is_tx_fifo_empty(hw_ep); +	if (empty) { +		cppi41_trans_done(cppi41_channel); +	} else { +		struct cppi41_dma_controller *controller; +		/* +		 * On AM335x it has been observed that the TX interrupt fires +		 * too early that means the TXFIFO is not yet empty but the DMA +		 * engine says that it is done with the transfer. We don't +		 * receive a FIFO empty interrupt so the only thing we can do is +		 * to poll for the bit. On HS it usually takes 2us, on FS around +		 * 110us - 150us depending on the transfer size. +		 * We spin on HS (no longer than than 25us and setup a timer on +		 * FS to check for the bit and complete the transfer. +		 */ +		controller = cppi41_channel->controller; + +		if (musb->g.speed == USB_SPEED_HIGH) { +			unsigned wait = 25; + +			do { +				empty = musb_is_tx_fifo_empty(hw_ep); +				if (empty) +					break; +				wait--; +				if (!wait) +					break; +				udelay(1); +			} while (1); + +			empty = musb_is_tx_fifo_empty(hw_ep); +			if (empty) { +				cppi41_trans_done(cppi41_channel); +				goto out; +			} +		} +		if (is_isoc(hw_ep, 0)) { +			schedule_work(&cppi41_channel->dma_completion); +			goto out; +		} +		list_add_tail(&cppi41_channel->tx_check, +				&controller->early_tx_list); +		if (!hrtimer_is_queued(&controller->early_tx)) { +			hrtimer_start_range_ns(&controller->early_tx, +				ktime_set(0, 140 * NSEC_PER_USEC), +				40 * NSEC_PER_USEC, +				HRTIMER_MODE_REL); +		} +	} +out:  	spin_unlock_irqrestore(&musb->lock, flags);  } @@ -340,12 +500,25 @@ static int cppi41_dma_channel_program(struct dma_channel *channel,  				dma_addr_t dma_addr, u32 len)  {  	int ret; +	struct cppi41_dma_channel *cppi41_channel = channel->private_data; +	int hb_mult = 0;  	BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN ||  		channel->status == MUSB_DMA_STATUS_BUSY); +	if (is_host_active(cppi41_channel->controller->musb)) { +		if (cppi41_channel->is_tx) +			hb_mult = cppi41_channel->hw_ep->out_qh->hb_mult; +		else +			hb_mult = cppi41_channel->hw_ep->in_qh->hb_mult; +	} +  	channel->status = MUSB_DMA_STATUS_BUSY;  	channel->actual_len = 0; + +	if (hb_mult) +		packet_sz = hb_mult * (packet_sz & 0x7FF); +  	ret = cppi41_configure_channel(channel, packet_sz, mode, dma_addr, len);  	if (!ret)  		channel->status = MUSB_DMA_STATUS_FREE; @@ -364,6 +537,8 @@ static int cppi41_is_compatible(struct dma_channel *channel, u16 maxpacket,  		WARN_ON(1);  		return 1;  	} +	if (cppi41_channel->hw_ep->ep_in.type != USB_ENDPOINT_XFER_BULK) +		return 0;  	if (cppi41_channel->is_tx)  		return 1;  	/* AM335x Advisory 1.0.13. No workaround for device RX mode */ @@ -388,6 +563,7 @@ static int cppi41_dma_channel_abort(struct dma_channel *channel)  	if (cppi41_channel->channel.status == MUSB_DMA_STATUS_FREE)  		return 0; +	list_del_init(&cppi41_channel->tx_check);  	if (is_tx) {  		csr = musb_readw(epio, MUSB_TXCSR);  		csr &= ~MUSB_TXCSR_DMAENAB; @@ -484,6 +660,7 @@ static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller)  		if (ret)  			goto err; +		ret = -EINVAL;  		if (port > MUSB_DMA_NUM_CHANNELS || !port)  			goto err;  		if (is_tx) @@ -494,6 +671,9 @@ static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller)  		cppi41_channel->controller = controller;  		cppi41_channel->port_num = port;  		cppi41_channel->is_tx = is_tx; +		INIT_LIST_HEAD(&cppi41_channel->tx_check); +		INIT_WORK(&cppi41_channel->dma_completion, +			  cppi_trans_done_work);  		musb_dma = &cppi41_channel->channel;  		musb_dma->private_data = cppi41_channel; @@ -502,7 +682,8 @@ static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller)  		dc = dma_request_slave_channel(dev, str);  		if (!dc) { -			dev_err(dev, "Falied to request %s.\n", str); +			dev_err(dev, "Failed to request %s.\n", str); +			ret = -EPROBE_DEFER;  			goto err;  		}  		cppi41_channel->dc = dc; @@ -510,7 +691,7 @@ static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller)  	return 0;  err:  	cppi41_release_all_dma_chans(controller); -	return -EINVAL; +	return ret;  }  void dma_controller_destroy(struct dma_controller *c) @@ -518,6 +699,7 @@ void dma_controller_destroy(struct dma_controller *c)  	struct cppi41_dma_controller *controller = container_of(c,  			struct cppi41_dma_controller, controller); +	hrtimer_cancel(&controller->early_tx);  	cppi41_dma_controller_stop(controller);  	kfree(controller);  } @@ -526,7 +708,7 @@ struct dma_controller *dma_controller_create(struct musb *musb,  					void __iomem *base)  {  	struct cppi41_dma_controller *controller; -	int ret; +	int ret = 0;  	if (!musb->controller->of_node) {  		dev_err(musb->controller, "Need DT for the DMA engine.\n"); @@ -537,6 +719,9 @@ struct dma_controller *dma_controller_create(struct musb *musb,  	if (!controller)  		goto kzalloc_fail; +	hrtimer_init(&controller->early_tx, CLOCK_MONOTONIC, HRTIMER_MODE_REL); +	controller->early_tx.function = cppi41_recheck_tx_req; +	INIT_LIST_HEAD(&controller->early_tx_list);  	controller->musb = musb;  	controller->controller.channel_alloc = cppi41_dma_channel_allocate; @@ -553,5 +738,7 @@ struct dma_controller *dma_controller_create(struct musb *musb,  plat_get_fail:  	kfree(controller);  kzalloc_fail: +	if (ret == -EPROBE_DEFER) +		return ERR_PTR(ret);  	return NULL;  } diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 4047cbb91ba..09529f94e72 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -29,14 +29,13 @@   * da8xx.c would be merged to this file after testing.   */ -#include <linux/init.h>  #include <linux/io.h>  #include <linux/err.h>  #include <linux/platform_device.h>  #include <linux/dma-mapping.h>  #include <linux/pm_runtime.h>  #include <linux/module.h> -#include <linux/usb/usb_phy_gen_xceiv.h> +#include <linux/usb/usb_phy_generic.h>  #include <linux/platform_data/usb-omap.h>  #include <linux/sizes.h> @@ -46,6 +45,8 @@  #include <linux/of_irq.h>  #include <linux/usb/of.h> +#include <linux/debugfs.h> +  #include "musb_core.h"  static const struct of_device_id musb_dsps_of_match[]; @@ -83,6 +84,8 @@ struct dsps_musb_wrapper {  	u16	coreintr_status;  	u16	phy_utmi;  	u16	mode; +	u16	tx_mode; +	u16	rx_mode;  	/* bit positions for control */  	unsigned	reset:5; @@ -106,10 +109,24 @@ struct dsps_musb_wrapper {  	/* bit positions for mode */  	unsigned	iddig:5; +	unsigned	iddig_mux:5;  	/* miscellaneous stuff */  	u8		poll_seconds;  }; +/* + * register shadow for suspend + */ +struct dsps_context { +	u32 control; +	u32 epintr; +	u32 coreintr; +	u32 phy_utmi; +	u32 mode; +	u32 tx_mode; +	u32 rx_mode; +}; +  /**   * DSPS glue structure.   */ @@ -119,8 +136,67 @@ struct dsps_glue {  	const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */  	struct timer_list timer;	/* otg_workaround timer */  	unsigned long last_timer;    /* last timer data for each instance */ + +	struct dsps_context context; +	struct debugfs_regset32 regset; +	struct dentry *dbgfs_root; +}; + +static const struct debugfs_reg32 dsps_musb_regs[] = { +	{ "revision",		0x00 }, +	{ "control",		0x14 }, +	{ "status",		0x18 }, +	{ "eoi",		0x24 }, +	{ "intr0_stat",		0x30 }, +	{ "intr1_stat",		0x34 }, +	{ "intr0_set",		0x38 }, +	{ "intr1_set",		0x3c }, +	{ "txmode",		0x70 }, +	{ "rxmode",		0x74 }, +	{ "autoreq",		0xd0 }, +	{ "srpfixtime",		0xd4 }, +	{ "tdown",		0xd8 }, +	{ "phy_utmi",		0xe0 }, +	{ "mode",		0xe8 },  }; +static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) +{ +	struct device *dev = musb->controller; +	struct dsps_glue *glue = dev_get_drvdata(dev->parent); + +	if (timeout == 0) +		timeout = jiffies + msecs_to_jiffies(3); + +	/* Never idle if active, or when VBUS timeout is not set as host */ +	if (musb->is_active || (musb->a_wait_bcon == 0 && +				musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) { +		dev_dbg(musb->controller, "%s active, deleting timer\n", +				usb_otg_state_string(musb->xceiv->state)); +		del_timer(&glue->timer); +		glue->last_timer = jiffies; +		return; +	} +	if (musb->port_mode != MUSB_PORT_MODE_DUAL_ROLE) +		return; + +	if (!musb->g.dev.driver) +		return; + +	if (time_after(glue->last_timer, timeout) && +				timer_pending(&glue->timer)) { +		dev_dbg(musb->controller, +			"Longer idle timer already pending, ignoring...\n"); +		return; +	} +	glue->last_timer = timeout; + +	dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", +		usb_otg_state_string(musb->xceiv->state), +			jiffies_to_msecs(timeout - jiffies)); +	mod_timer(&glue->timer, timeout); +} +  /**   * dsps_musb_enable - enable interrupts   */ @@ -143,6 +219,7 @@ static void dsps_musb_enable(struct musb *musb)  	/* Force the DRVVBUS IRQ so we can start polling for ID change. */  	dsps_writel(reg_base, wrp->coreintr_set,  		    (1 << wrp->drvvbus) << wrp->usb_shift); +	dsps_musb_try_idle(musb, 0);  }  /** @@ -171,6 +248,7 @@ static void otg_timer(unsigned long _musb)  	const struct dsps_musb_wrapper *wrp = glue->wrp;  	u8 devctl;  	unsigned long flags; +	int skip_session = 0;  	/*  	 * We poll because DSPS IP's won't expose several OTG-critical @@ -183,10 +261,12 @@ static void otg_timer(unsigned long _musb)  	spin_lock_irqsave(&musb->lock, flags);  	switch (musb->xceiv->state) {  	case OTG_STATE_A_WAIT_BCON: -		devctl &= ~MUSB_DEVCTL_SESSION; -		dsps_writeb(musb->mregs, MUSB_DEVCTL, devctl); +		dsps_writeb(musb->mregs, MUSB_DEVCTL, 0); +		skip_session = 1; +		/* fall */ -		devctl = dsps_readb(musb->mregs, MUSB_DEVCTL); +	case OTG_STATE_A_IDLE: +	case OTG_STATE_B_IDLE:  		if (devctl & MUSB_DEVCTL_BDEVICE) {  			musb->xceiv->state = OTG_STATE_B_IDLE;  			MUSB_DEV_MODE(musb); @@ -194,60 +274,21 @@ static void otg_timer(unsigned long _musb)  			musb->xceiv->state = OTG_STATE_A_IDLE;  			MUSB_HST_MODE(musb);  		} +		if (!(devctl & MUSB_DEVCTL_SESSION) && !skip_session) +			dsps_writeb(mregs, MUSB_DEVCTL, MUSB_DEVCTL_SESSION); +		mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ);  		break;  	case OTG_STATE_A_WAIT_VFALL:  		musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;  		dsps_writel(musb->ctrl_base, wrp->coreintr_set,  			    MUSB_INTR_VBUSERROR << wrp->usb_shift);  		break; -	case OTG_STATE_B_IDLE: -		devctl = dsps_readb(mregs, MUSB_DEVCTL); -		if (devctl & MUSB_DEVCTL_BDEVICE) -			mod_timer(&glue->timer, -					jiffies + wrp->poll_seconds * HZ); -		else -			musb->xceiv->state = OTG_STATE_A_IDLE; -		break;  	default:  		break;  	}  	spin_unlock_irqrestore(&musb->lock, flags);  } -static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) -{ -	struct device *dev = musb->controller; -	struct dsps_glue *glue = dev_get_drvdata(dev->parent); - -	if (timeout == 0) -		timeout = jiffies + msecs_to_jiffies(3); - -	/* Never idle if active, or when VBUS timeout is not set as host */ -	if (musb->is_active || (musb->a_wait_bcon == 0 && -				musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) { -		dev_dbg(musb->controller, "%s active, deleting timer\n", -				usb_otg_state_string(musb->xceiv->state)); -		del_timer(&glue->timer); -		glue->last_timer = jiffies; -		return; -	} -	if (musb->port_mode == MUSB_PORT_MODE_HOST) -		return; - -	if (time_after(glue->last_timer, timeout) && -				timer_pending(&glue->timer)) { -		dev_dbg(musb->controller, -			"Longer idle timer already pending, ignoring...\n"); -		return; -	} -	glue->last_timer = timeout; - -	dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", -		usb_otg_state_string(musb->xceiv->state), -			jiffies_to_msecs(timeout - jiffies)); -	mod_timer(&glue->timer, timeout); -} -  static irqreturn_t dsps_interrupt(int irq, void *hci)  {  	struct musb  *musb = hci; @@ -288,9 +329,21 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)  	 * value but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set.  	 * Also, DRVVBUS pulses for SRP (but not at 5V) ...  	 */ -	if (is_host_active(musb) && usbintr & MUSB_INTR_BABBLE) +	if (is_host_active(musb) && usbintr & MUSB_INTR_BABBLE) {  		pr_info("CAUTION: musb: Babble Interrupt Occurred\n"); +		/* +		 * When a babble condition occurs, the musb controller removes +		 * the session and is no longer in host mode. Hence, all +		 * devices connected to its root hub get disconnected. +		 * +		 * Hand this error down to the musb core isr, so it can +		 * recover. +		 */ +		musb->int_usb = MUSB_INTR_BABBLE | MUSB_INTR_DISCONNECT; +		musb->int_tx = musb->int_rx = 0; +	} +  	if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) {  		int drvvbus = dsps_readl(reg_base, wrp->status);  		void __iomem *mregs = musb->mregs; @@ -339,8 +392,9 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)  	if (musb->int_tx || musb->int_rx || musb->int_usb)  		ret |= musb_interrupt(musb); -	/* Poll for ID change */ -	if (musb->xceiv->state == OTG_STATE_B_IDLE) +	/* Poll for ID change in OTG port mode */ +	if (musb->xceiv->state == OTG_STATE_B_IDLE && +			musb->port_mode == MUSB_PORT_MODE_DUAL_ROLE)  		mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ);  out:  	spin_unlock_irqrestore(&musb->lock, flags); @@ -348,6 +402,30 @@ out:  	return ret;  } +static int dsps_musb_dbg_init(struct musb *musb, struct dsps_glue *glue) +{ +	struct dentry *root; +	struct dentry *file; +	char buf[128]; + +	sprintf(buf, "%s.dsps", dev_name(musb->controller)); +	root = debugfs_create_dir(buf, NULL); +	if (!root) +		return -ENOMEM; +	glue->dbgfs_root = root; + +	glue->regset.regs = dsps_musb_regs; +	glue->regset.nregs = ARRAY_SIZE(dsps_musb_regs); +	glue->regset.base = musb->ctrl_base; + +	file = debugfs_create_regset32("regdump", S_IRUGO, root, &glue->regset); +	if (!file) { +		debugfs_remove_recursive(root); +		return -ENOMEM; +	} +	return 0; +} +  static int dsps_musb_init(struct musb *musb)  {  	struct device *dev = musb->controller; @@ -357,6 +435,7 @@ static int dsps_musb_init(struct musb *musb)  	void __iomem *reg_base;  	struct resource *r;  	u32 rev, val; +	int ret;  	r = platform_get_resource_byname(parent, IORESOURCE_MEM, "control");  	if (!r) @@ -390,6 +469,10 @@ static int dsps_musb_init(struct musb *musb)  	val &= ~(1 << wrp->otg_disable);  	dsps_writel(musb->ctrl_base, wrp->phy_utmi, val); +	ret = dsps_musb_dbg_init(musb, glue); +	if (ret) +		return ret; +  	return 0;  } @@ -399,11 +482,69 @@ static int dsps_musb_exit(struct musb *musb)  	struct dsps_glue *glue = dev_get_drvdata(dev->parent);  	del_timer_sync(&glue->timer); -  	usb_phy_shutdown(musb->xceiv); +	debugfs_remove_recursive(glue->dbgfs_root); + +	return 0; +} + +static int dsps_musb_set_mode(struct musb *musb, u8 mode) +{ +	struct device *dev = musb->controller; +	struct dsps_glue *glue = dev_get_drvdata(dev->parent); +	const struct dsps_musb_wrapper *wrp = glue->wrp; +	void __iomem *ctrl_base = musb->ctrl_base; +	u32 reg; + +	reg = dsps_readl(ctrl_base, wrp->mode); + +	switch (mode) { +	case MUSB_HOST: +		reg &= ~(1 << wrp->iddig); + +		/* +		 * if we're setting mode to host-only or device-only, we're +		 * going to ignore whatever the PHY sends us and just force +		 * ID pin status by SW +		 */ +		reg |= (1 << wrp->iddig_mux); + +		dsps_writel(ctrl_base, wrp->mode, reg); +		dsps_writel(ctrl_base, wrp->phy_utmi, 0x02); +		break; +	case MUSB_PERIPHERAL: +		reg |= (1 << wrp->iddig); + +		/* +		 * if we're setting mode to host-only or device-only, we're +		 * going to ignore whatever the PHY sends us and just force +		 * ID pin status by SW +		 */ +		reg |= (1 << wrp->iddig_mux); + +		dsps_writel(ctrl_base, wrp->mode, reg); +		break; +	case MUSB_OTG: +		dsps_writel(ctrl_base, wrp->phy_utmi, 0x02); +		break; +	default: +		dev_err(glue->dev, "unsupported mode %d\n", mode); +		return -EINVAL; +	} +  	return 0;  } +static void dsps_musb_reset(struct musb *musb) +{ +	struct device *dev = musb->controller; +	struct dsps_glue *glue = dev_get_drvdata(dev->parent); +	const struct dsps_musb_wrapper *wrp = glue->wrp; + +	dsps_writel(musb->ctrl_base, wrp->control, (1 << wrp->reset)); +	udelay(100); +} +  static struct musb_platform_ops dsps_ops = {  	.init		= dsps_musb_init,  	.exit		= dsps_musb_exit, @@ -412,6 +553,8 @@ static struct musb_platform_ops dsps_ops = {  	.disable	= dsps_musb_disable,  	.try_idle	= dsps_musb_try_idle, +	.set_mode	= dsps_musb_set_mode, +	.reset		= dsps_musb_reset,  };  static u64 musb_dmamask = DMA_BIT_MASK(32); @@ -443,7 +586,7 @@ static int get_musb_port_mode(struct device *dev)  	case USB_DR_MODE_OTG:  	default:  		return MUSB_PORT_MODE_DUAL_ROLE; -	}; +	}  }  static int dsps_create_musb_pdev(struct dsps_glue *glue, @@ -505,6 +648,7 @@ static int dsps_create_musb_pdev(struct dsps_glue *glue,  	config->num_eps = get_int_prop(dn, "mentor,num-eps");  	config->ram_bits = get_int_prop(dn, "mentor,ram-bits"); +	config->host_port_deassert_reset_at_resume = 1;  	pdata.mode = get_musb_port_mode(dev);  	/* DT keeps this entry in mA, musb expects it as per USB spec */  	pdata.power = get_int_prop(dn, "mentor,power") / 2; @@ -535,6 +679,9 @@ static int dsps_probe(struct platform_device *pdev)  	struct dsps_glue *glue;  	int ret; +	if (!strcmp(pdev->name, "musb-hdrc")) +		return -ENODEV; +  	match = of_match_node(musb_dsps_of_match, pdev->dev.of_node);  	if (!match) {  		dev_err(&pdev->dev, "fail to get matching of_match struct\n"); @@ -543,7 +690,7 @@ static int dsps_probe(struct platform_device *pdev)  	wrp = match->data;  	/* allocate glue */ -	glue = kzalloc(sizeof(*glue), GFP_KERNEL); +	glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);  	if (!glue) {  		dev_err(&pdev->dev, "unable to allocate glue memory\n");  		return -ENOMEM; @@ -571,7 +718,6 @@ err3:  	pm_runtime_put(&pdev->dev);  err2:  	pm_runtime_disable(&pdev->dev); -	kfree(glue);  	return ret;  } @@ -584,7 +730,7 @@ static int dsps_remove(struct platform_device *pdev)  	/* disable usbss clocks */  	pm_runtime_put(&pdev->dev);  	pm_runtime_disable(&pdev->dev); -	kfree(glue); +  	return 0;  } @@ -600,9 +746,12 @@ static const struct dsps_musb_wrapper am33xx_driver_data = {  	.coreintr_status	= 0x34,  	.phy_utmi		= 0xe0,  	.mode			= 0xe8, +	.tx_mode		= 0x70, +	.rx_mode		= 0x74,  	.reset			= 0,  	.otg_disable		= 21,  	.iddig			= 8, +	.iddig_mux		= 7,  	.usb_shift		= 0,  	.usb_mask		= 0x1ff,  	.usb_bitmap		= (0x1ff << 0), @@ -623,12 +772,53 @@ static const struct of_device_id musb_dsps_of_match[] = {  };  MODULE_DEVICE_TABLE(of, musb_dsps_of_match); +#ifdef CONFIG_PM_SLEEP +static int dsps_suspend(struct device *dev) +{ +	struct dsps_glue *glue = dev_get_drvdata(dev); +	const struct dsps_musb_wrapper *wrp = glue->wrp; +	struct musb *musb = platform_get_drvdata(glue->musb); +	void __iomem *mbase = musb->ctrl_base; + +	glue->context.control = dsps_readl(mbase, wrp->control); +	glue->context.epintr = dsps_readl(mbase, wrp->epintr_set); +	glue->context.coreintr = dsps_readl(mbase, wrp->coreintr_set); +	glue->context.phy_utmi = dsps_readl(mbase, wrp->phy_utmi); +	glue->context.mode = dsps_readl(mbase, wrp->mode); +	glue->context.tx_mode = dsps_readl(mbase, wrp->tx_mode); +	glue->context.rx_mode = dsps_readl(mbase, wrp->rx_mode); + +	return 0; +} + +static int dsps_resume(struct device *dev) +{ +	struct dsps_glue *glue = dev_get_drvdata(dev); +	const struct dsps_musb_wrapper *wrp = glue->wrp; +	struct musb *musb = platform_get_drvdata(glue->musb); +	void __iomem *mbase = musb->ctrl_base; + +	dsps_writel(mbase, wrp->control, glue->context.control); +	dsps_writel(mbase, wrp->epintr_set, glue->context.epintr); +	dsps_writel(mbase, wrp->coreintr_set, glue->context.coreintr); +	dsps_writel(mbase, wrp->phy_utmi, glue->context.phy_utmi); +	dsps_writel(mbase, wrp->mode, glue->context.mode); +	dsps_writel(mbase, wrp->tx_mode, glue->context.tx_mode); +	dsps_writel(mbase, wrp->rx_mode, glue->context.rx_mode); + +	return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume); +  static struct platform_driver dsps_usbss_driver = {  	.probe		= dsps_probe,  	.remove         = dsps_remove,  	.driver         = {  		.name   = "musb-dsps", -		.of_match_table	= of_match_ptr(musb_dsps_of_match), +		.pm	= &dsps_pm_ops, +		.of_match_table	= musb_dsps_of_match,  	},  }; diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index 9a08679d204..d4aa779339f 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1121,7 +1121,7 @@ static int musb_gadget_enable(struct usb_ep *ep,  			case USB_ENDPOINT_XFER_BULK:	s = "bulk"; break;  			case USB_ENDPOINT_XFER_INT:	s = "int"; break;  			default:			s = "iso"; break; -			}; s; }), +			} s; }),  			musb_ep->is_in ? "IN" : "OUT",  			musb_ep->dma ? "dma, " : "",  			musb_ep->packet_sz); @@ -1727,14 +1727,14 @@ init_peripheral_ep(struct musb *musb, struct musb_ep *ep, u8 epnum, int is_in)  	ep->end_point.name = ep->name;  	INIT_LIST_HEAD(&ep->end_point.ep_list);  	if (!epnum) { -		ep->end_point.maxpacket = 64; +		usb_ep_set_maxpacket_limit(&ep->end_point, 64);  		ep->end_point.ops = &musb_g_ep0_ops;  		musb->g.ep0 = &ep->end_point;  	} else {  		if (is_in) -			ep->end_point.maxpacket = hw_ep->max_packet_sz_tx; +			usb_ep_set_maxpacket_limit(&ep->end_point, hw_ep->max_packet_sz_tx);  		else -			ep->end_point.maxpacket = hw_ep->max_packet_sz_rx; +			usb_ep_set_maxpacket_limit(&ep->end_point, hw_ep->max_packet_sz_rx);  		ep->end_point.ops = &musb_ep_ops;  		list_add_tail(&ep->end_point.ep_list, &musb->g.ep_list);  	} @@ -1790,9 +1790,17 @@ int musb_gadget_setup(struct musb *musb)  	musb->g.max_speed = USB_SPEED_HIGH;  	musb->g.speed = USB_SPEED_UNKNOWN; +	MUSB_DEV_MODE(musb); +	musb->xceiv->otg->default_a = 0; +	musb->xceiv->state = OTG_STATE_B_IDLE; +  	/* this "gadget" abstracts/virtualizes the controller */  	musb->g.name = musb_driver_name; +#if IS_ENABLED(CONFIG_USB_MUSB_DUAL_ROLE)  	musb->g.is_otg = 1; +#elif IS_ENABLED(CONFIG_USB_MUSB_GADGET) +	musb->g.is_otg = 0; +#endif  	musb_g_init_endpoints(musb); @@ -1855,6 +1863,8 @@ static int musb_gadget_start(struct usb_gadget *g,  	musb->xceiv->state = OTG_STATE_B_IDLE;  	spin_unlock_irqrestore(&musb->lock, flags); +	musb_start(musb); +  	/* REVISIT:  funcall to other code, which also  	 * handles power budgeting ... this way also  	 * ensures HdrcStart is indirectly called. @@ -2109,7 +2119,15 @@ __acquires(musb->lock)  	/* Normal reset, as B-Device;  	 * or else after HNP, as A-Device  	 */ -	if (devctl & MUSB_DEVCTL_BDEVICE) { +	if (!musb->g.is_otg) { +		/* USB device controllers that are not OTG compatible +		 * may not have DEVCTL register in silicon. +		 * In that case, do not rely on devctl for setting +		 * peripheral mode. +		 */ +		musb->xceiv->state = OTG_STATE_B_PERIPHERAL; +		musb->g.is_a_peripheral = 0; +	} else if (devctl & MUSB_DEVCTL_BDEVICE) {  		musb->xceiv->state = OTG_STATE_B_PERIPHERAL;  		musb->g.is_a_peripheral = 0;  	} else { diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index 9a2b8c85f19..eb06291a40c 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -39,7 +39,6 @@  #include <linux/sched.h>  #include <linux/slab.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/list.h>  #include <linux/dma-mapping.h> @@ -253,7 +252,7 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)  			case USB_ENDPOINT_XFER_BULK:	s = "-bulk"; break;  			case USB_ENDPOINT_XFER_ISOC:	s = "-iso"; break;  			default:			s = "-intr"; break; -			}; s; }), +			} s; }),  			epnum, buf + offset, len);  	/* Configure endpoint */ @@ -1184,6 +1183,9 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb)  				csr = MUSB_CSR0_H_STATUSPKT  					| MUSB_CSR0_TXPKTRDY; +			/* disable ping token in status phase */ +			csr |= MUSB_CSR0_H_DIS_PING; +  			/* flag status stage */  			musb->ep0_stage = MUSB_EP0_STATUS; @@ -1692,7 +1694,8 @@ void musb_host_rx(struct musb *musb, u8 epnum)  			| MUSB_RXCSR_RXPKTRDY);  		musb_writew(hw_ep->regs, MUSB_RXCSR, val); -#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA) +#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA) || \ +	defined(CONFIG_USB_TI_CPPI41_DMA)  		if (usb_pipeisoc(pipe)) {  			struct usb_iso_packet_descriptor *d; @@ -1705,10 +1708,30 @@ void musb_host_rx(struct musb *musb, u8 epnum)  			if (d->status != -EILSEQ && d->status != -EOVERFLOW)  				d->status = 0; -			if (++qh->iso_idx >= urb->number_of_packets) +			if (++qh->iso_idx >= urb->number_of_packets) {  				done = true; -			else +			} else { +#if defined(CONFIG_USB_TI_CPPI41_DMA) +				struct dma_controller   *c; +				dma_addr_t *buf; +				u32 length, ret; + +				c = musb->dma_controller; +				buf = (void *) +					urb->iso_frame_desc[qh->iso_idx].offset +					+ (u32)urb->transfer_dma; + +				length = +					urb->iso_frame_desc[qh->iso_idx].length; + +				val |= MUSB_RXCSR_DMAENAB; +				musb_writew(hw_ep->regs, MUSB_RXCSR, val); + +				ret = c->channel_program(dma, qh->maxpacket, +						0, (u32) buf, length); +#endif  				done = false; +			}  		} else  {  		/* done if urb buffer is full or short packet is recd */ @@ -1748,7 +1771,8 @@ void musb_host_rx(struct musb *musb, u8 epnum)  		}  		/* we are expecting IN packets */ -#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA) +#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA) || \ +	defined(CONFIG_USB_TI_CPPI41_DMA)  		if (dma) {  			struct dma_controller	*c;  			u16			rx_count; @@ -2013,7 +2037,7 @@ static int musb_schedule(  			head = &musb->out_bulk;  		/* Enable bulk RX/TX NAK timeout scheme when bulk requests are -		 * multiplexed.  This scheme doen't work in high speed to full +		 * multiplexed. This scheme does not work in high speed to full  		 * speed scenario as NAK interrupts are not coming from a  		 * full speed device connected to a high speed device.  		 * NAK timeout interval is 8 (128 uframe or 16ms) for HS and @@ -2433,6 +2457,8 @@ static int musb_bus_suspend(struct usb_hcd *hcd)  	struct musb	*musb = hcd_to_musb(hcd);  	u8		devctl; +	musb_port_suspend(musb, true); +  	if (!is_host_active(musb))  		return 0; @@ -2462,7 +2488,12 @@ static int musb_bus_suspend(struct usb_hcd *hcd)  static int musb_bus_resume(struct usb_hcd *hcd)  { -	/* resuming child port does the work */ +	struct musb *musb = hcd_to_musb(hcd); + +	if (musb->config && +	    musb->config->host_port_deassert_reset_at_resume) +		musb_port_reset(musb, false); +  	return 0;  } @@ -2657,6 +2688,7 @@ int musb_host_setup(struct musb *musb, int power_budget)  	if (ret < 0)  		return ret; +	device_wakeup_enable(hcd->self.controller);  	return 0;  } diff --git a/drivers/usb/musb/musb_host.h b/drivers/usb/musb/musb_host.h index 960d73570b2..7bbf01bf4bb 100644 --- a/drivers/usb/musb/musb_host.h +++ b/drivers/usb/musb/musb_host.h @@ -92,6 +92,9 @@ extern void musb_host_rx(struct musb *, u8);  extern void musb_root_disconnect(struct musb *musb);  extern void musb_host_resume_root_hub(struct musb *musb);  extern void musb_host_poke_root_hub(struct musb *musb); +extern void musb_port_suspend(struct musb *musb, bool do_suspend); +extern void musb_port_reset(struct musb *musb, bool do_reset); +extern void musb_host_finish_resume(struct work_struct *work);  #else  static inline struct musb *hcd_to_musb(struct usb_hcd *hcd)  { @@ -121,6 +124,9 @@ static inline void musb_root_disconnect(struct musb *musb)	{}  static inline void musb_host_resume_root_hub(struct musb *musb)	{}  static inline void musb_host_poll_rh_status(struct musb *musb)	{}  static inline void musb_host_poke_root_hub(struct musb *musb)	{} +static inline void musb_port_suspend(struct musb *musb, bool do_suspend) {} +static inline void musb_port_reset(struct musb *musb, bool do_reset) {} +static inline void musb_host_finish_resume(struct work_struct *work) {}  #endif  struct usb_hcd; diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c index a523950c2b3..e2d2d8c9891 100644 --- a/drivers/usb/musb/musb_virthub.c +++ b/drivers/usb/musb/musb_virthub.c @@ -36,7 +36,6 @@  #include <linux/kernel.h>  #include <linux/sched.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/time.h>  #include <linux/timer.h> @@ -44,53 +43,38 @@  #include "musb_core.h" -/* -* Program the HDRC to start (enable interrupts, dma, etc.). -*/ -static void musb_start(struct musb *musb) +void musb_host_finish_resume(struct work_struct *work)  { -	void __iomem	*regs = musb->mregs; -	u8		devctl = musb_readb(regs, MUSB_DEVCTL); - -	dev_dbg(musb->controller, "<== devctl %02x\n", devctl); - -	/*  Set INT enable registers, enable interrupts */ -	musb->intrtxe = musb->epmask; -	musb_writew(regs, MUSB_INTRTXE, musb->intrtxe); -	musb->intrrxe = musb->epmask & 0xfffe; -	musb_writew(regs, MUSB_INTRRXE, musb->intrrxe); -	musb_writeb(regs, MUSB_INTRUSBE, 0xf7); +	struct musb *musb; +	unsigned long flags; +	u8 power; -	musb_writeb(regs, MUSB_TESTMODE, 0); +	musb = container_of(work, struct musb, finish_resume_work.work); -	/* put into basic highspeed mode and start session */ -	musb_writeb(regs, MUSB_POWER, MUSB_POWER_ISOUPDATE -						| MUSB_POWER_HSENAB -						/* ENSUSPEND wedges tusb */ -						/* | MUSB_POWER_ENSUSPEND */ -						); +	spin_lock_irqsave(&musb->lock, flags); -	musb->is_active = 0; -	devctl = musb_readb(regs, MUSB_DEVCTL); -	devctl &= ~MUSB_DEVCTL_SESSION; +	power = musb_readb(musb->mregs, MUSB_POWER); +	power &= ~MUSB_POWER_RESUME; +	dev_dbg(musb->controller, "root port resume stopped, power %02x\n", +		power); +	musb_writeb(musb->mregs, MUSB_POWER, power); -	/* session started after: -	 * (a) ID-grounded irq, host mode; -	 * (b) vbus present/connect IRQ, peripheral mode; -	 * (c) peripheral initiates, using SRP +	/* +	 * ISSUE:  DaVinci (RTL 1.300) disconnects after +	 * resume of high speed peripherals (but not full +	 * speed ones).  	 */ -	if (musb->port_mode != MUSB_PORT_MODE_HOST && -	    (devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) { -		musb->is_active = 1; -	} else { -		devctl |= MUSB_DEVCTL_SESSION; -	} +	musb->is_active = 1; +	musb->port1_status &= ~(USB_PORT_STAT_SUSPEND | MUSB_PORT_STAT_RESUME); +	musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16; +	usb_hcd_poll_rh_status(musb->hcd); +	/* NOTE: it might really be A_WAIT_BCON ... */ +	musb->xceiv->state = OTG_STATE_A_HOST; -	musb_platform_enable(musb); -	musb_writeb(regs, MUSB_DEVCTL, devctl); +	spin_unlock_irqrestore(&musb->lock, flags);  } -static void musb_port_suspend(struct musb *musb, bool do_suspend) +void musb_port_suspend(struct musb *musb, bool do_suspend)  {  	struct usb_otg	*otg = musb->xceiv->otg;  	u8		power; @@ -151,11 +135,12 @@ static void musb_port_suspend(struct musb *musb, bool do_suspend)  		/* later, GetPortStatus will stop RESUME signaling */  		musb->port1_status |= MUSB_PORT_STAT_RESUME; -		musb->rh_timer = jiffies + msecs_to_jiffies(20); +		schedule_delayed_work(&musb->finish_resume_work, +				      msecs_to_jiffies(20));  	}  } -static void musb_port_reset(struct musb *musb, bool do_reset) +void musb_port_reset(struct musb *musb, bool do_reset)  {  	u8		power;  	void __iomem	*mbase = musb->mregs; @@ -174,7 +159,6 @@ static void musb_port_reset(struct musb *musb, bool do_reset)  	 */  	power = musb_readb(mbase, MUSB_POWER);  	if (do_reset) { -  		/*  		 * If RESUME is set, we must make sure it stays minimum 20 ms.  		 * Then we must clear RESUME and wait a bit to let musb start @@ -183,11 +167,22 @@ static void musb_port_reset(struct musb *musb, bool do_reset)  		 * detected".  		 */  		if (power &  MUSB_POWER_RESUME) { -			while (time_before(jiffies, musb->rh_timer)) -				msleep(1); +			long remain = (unsigned long) musb->rh_timer - jiffies; + +			if (musb->rh_timer > 0 && remain > 0) { +				/* take into account the minimum delay after resume */ +				schedule_delayed_work( +					&musb->deassert_reset_work, remain); +				return; +			} +  			musb_writeb(mbase, MUSB_POWER, -				power & ~MUSB_POWER_RESUME); -			msleep(1); +				    power & ~MUSB_POWER_RESUME); + +			/* Give the core 1 ms to clear MUSB_POWER_RESUME */ +			schedule_delayed_work(&musb->deassert_reset_work, +					      msecs_to_jiffies(1)); +			return;  		}  		power &= 0xf0; @@ -196,7 +191,8 @@ static void musb_port_reset(struct musb *musb, bool do_reset)  		musb->port1_status |= USB_PORT_STAT_RESET;  		musb->port1_status &= ~USB_PORT_STAT_ENABLE; -		musb->rh_timer = jiffies + msecs_to_jiffies(50); +		schedule_delayed_work(&musb->deassert_reset_work, +				      msecs_to_jiffies(50));  	} else {  		dev_dbg(musb->controller, "root port reset stopped\n");  		musb_writeb(mbase, MUSB_POWER, @@ -266,6 +262,23 @@ int musb_hub_status_data(struct usb_hcd *hcd, char *buf)  	return retval;  } +static int musb_has_gadget(struct musb *musb) +{ +	/* +	 * In host-only mode we start a connection right away. In OTG mode +	 * we have to wait until we loaded a gadget. We don't really need a +	 * gadget if we operate as a host but we should not start a session +	 * as a device without a gadget or else we explode. +	 */ +#ifdef CONFIG_USB_MUSB_HOST +	return 1; +#else +	if (musb->port_mode == MUSB_PORT_MODE_HOST) +		return 1; +	return musb->g.dev.driver != NULL; +#endif +} +  int musb_hub_control(  	struct usb_hcd	*hcd,  	u16		typeReq, @@ -354,36 +367,6 @@ int musb_hub_control(  		if (wIndex != 1)  			goto error; -		/* finish RESET signaling? */ -		if ((musb->port1_status & USB_PORT_STAT_RESET) -				&& time_after_eq(jiffies, musb->rh_timer)) -			musb_port_reset(musb, false); - -		/* finish RESUME signaling? */ -		if ((musb->port1_status & MUSB_PORT_STAT_RESUME) -				&& time_after_eq(jiffies, musb->rh_timer)) { -			u8		power; - -			power = musb_readb(musb->mregs, MUSB_POWER); -			power &= ~MUSB_POWER_RESUME; -			dev_dbg(musb->controller, "root port resume stopped, power %02x\n", -					power); -			musb_writeb(musb->mregs, MUSB_POWER, power); - -			/* ISSUE:  DaVinci (RTL 1.300) disconnects after -			 * resume of high speed peripherals (but not full -			 * speed ones). -			 */ - -			musb->is_active = 1; -			musb->port1_status &= ~(USB_PORT_STAT_SUSPEND -					| MUSB_PORT_STAT_RESUME); -			musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16; -			usb_hcd_poll_rh_status(musb->hcd); -			/* NOTE: it might really be A_WAIT_BCON ... */ -			musb->xceiv->state = OTG_STATE_A_HOST; -		} -  		put_unaligned(cpu_to_le32(musb->port1_status  					& ~MUSB_PORT_STAT_RESUME),  				(__le32 *) buf); @@ -408,7 +391,7 @@ int musb_hub_control(  			 * initialization logic, e.g. for OTG, or change any  			 * logic relating to VBUS power-up.  			 */ -			if (!hcd->self.is_b_host) +			if (!hcd->self.is_b_host && musb_has_gadget(musb))  				musb_start(musb);  			break;  		case USB_PORT_FEAT_RESET: diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 59d2245db1c..d369bf1f393 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -37,7 +37,8 @@  #include <linux/err.h>  #include <linux/delay.h>  #include <linux/usb/musb-omap.h> -#include <linux/usb/omap_control_usb.h> +#include <linux/phy/omap_control_phy.h> +#include <linux/of_platform.h>  #include "musb_core.h"  #include "omap2430.h" @@ -305,6 +306,9 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)  	default:  		dev_dbg(dev, "ID float\n");  	} + +	atomic_notifier_call_chain(&musb->xceiv->notifier, +			musb->xceiv->last_event, NULL);  } @@ -312,7 +316,13 @@ static void omap_musb_mailbox_work(struct work_struct *mailbox_work)  {  	struct omap2430_glue *glue = container_of(mailbox_work,  				struct omap2430_glue, omap_musb_mailbox_work); +	struct musb *musb = glue_to_musb(glue); +	struct device *dev = musb->controller; + +	pm_runtime_get_sync(dev);  	omap_musb_set_mailbox(glue); +	pm_runtime_mark_last_busy(dev); +	pm_runtime_put_autosuspend(dev);  }  static irqreturn_t omap2430_musb_interrupt(int irq, void *__hci) @@ -348,11 +358,21 @@ static int omap2430_musb_init(struct musb *musb)  	 * up through ULPI.  TWL4030-family PMICs include one,  	 * which needs a driver, drivers aren't always needed.  	 */ -	if (dev->parent->of_node) +	if (dev->parent->of_node) { +		musb->phy = devm_phy_get(dev->parent, "usb2-phy"); + +		/* We can't totally remove musb->xceiv as of now because +		 * musb core uses xceiv.state and xceiv.otg. Once we have +		 * a separate state machine to handle otg, these can be moved +		 * out of xceiv and then we can start using the generic PHY +		 * framework +		 */  		musb->xceiv = devm_usb_get_phy_by_phandle(dev->parent,  		    "usb-phy", 0); -	else +	} else {  		musb->xceiv = devm_usb_get_phy_dev(dev, 0); +		musb->phy = devm_phy_get(dev, "usb"); +	}  	if (IS_ERR(musb->xceiv)) {  		status = PTR_ERR(musb->xceiv); @@ -364,6 +384,10 @@ static int omap2430_musb_init(struct musb *musb)  		return -EPROBE_DEFER;  	} +	if (IS_ERR(musb->phy)) { +		pr_err("HS USB OTG: no PHY configured\n"); +		return PTR_ERR(musb->phy); +	}  	musb->isr = omap2430_musb_interrupt;  	status = pm_runtime_get_sync(dev); @@ -397,7 +421,8 @@ static int omap2430_musb_init(struct musb *musb)  	if (glue->status != OMAP_MUSB_UNKNOWN)  		omap_musb_set_mailbox(glue); -	usb_phy_init(musb->xceiv); +	phy_init(musb->phy); +	phy_power_on(musb->phy);  	pm_runtime_put_noidle(musb->controller);  	return 0; @@ -460,6 +485,8 @@ static int omap2430_musb_exit(struct musb *musb)  	del_timer_sync(&musb_idle_timer);  	omap2430_low_level_exit(musb); +	phy_power_off(musb->phy); +	phy_exit(musb->phy);  	return 0;  } @@ -509,8 +536,12 @@ static int omap2430_probe(struct platform_device *pdev)  	glue->dev			= &pdev->dev;  	glue->musb			= musb;  	glue->status			= OMAP_MUSB_UNKNOWN; +	glue->control_otghs = ERR_PTR(-ENODEV);  	if (np) { +		struct device_node *control_node; +		struct platform_device *control_pdev; +  		pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);  		if (!pdata) {  			dev_err(&pdev->dev, @@ -539,22 +570,20 @@ static int omap2430_probe(struct platform_device *pdev)  		of_property_read_u32(np, "ram-bits", (u32 *)&config->ram_bits);  		of_property_read_u32(np, "power", (u32 *)&pdata->power);  		config->multipoint = of_property_read_bool(np, "multipoint"); -		pdata->has_mailbox = of_property_read_bool(np, -		    "ti,has-mailbox");  		pdata->board_data	= data;  		pdata->config		= config; -	} -	if (pdata->has_mailbox) { -		glue->control_otghs = omap_get_control_dev(); -		if (IS_ERR(glue->control_otghs)) { -			dev_vdbg(&pdev->dev, "Failed to get control device\n"); -			ret = PTR_ERR(glue->control_otghs); -			goto err2; +		control_node = of_parse_phandle(np, "ctrl-module", 0); +		if (control_node) { +			control_pdev = of_find_device_by_node(control_node); +			if (!control_pdev) { +				dev_err(&pdev->dev, "Failed to get control device\n"); +				ret = -EINVAL; +				goto err2; +			} +			glue->control_otghs = &control_pdev->dev;  		} -	} else { -		glue->control_otghs = ERR_PTR(-ENODEV);  	}  	pdata->platform_ops		= &omap2430_ops; @@ -638,7 +667,6 @@ static int omap2430_runtime_suspend(struct device *dev)  				OTG_INTERFSEL);  		omap2430_low_level_exit(musb); -		usb_phy_set_suspend(musb->xceiv, 1);  	}  	return 0; @@ -653,8 +681,6 @@ static int omap2430_runtime_resume(struct device *dev)  		omap2430_low_level_init(musb);  		musb_writel(musb->mregs, OTG_INTERFSEL,  				musb->context.otg_interfsel); - -		usb_phy_set_suspend(musb->xceiv, 0);  	}  	return 0; diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index b3b3ed72388..159ef4be1ef 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -18,20 +18,20 @@  #include <linux/kernel.h>  #include <linux/errno.h>  #include <linux/err.h> -#include <linux/init.h>  #include <linux/prefetch.h>  #include <linux/usb.h>  #include <linux/irq.h>  #include <linux/io.h>  #include <linux/platform_device.h>  #include <linux/dma-mapping.h> -#include <linux/usb/usb_phy_gen_xceiv.h> +#include <linux/usb/usb_phy_generic.h>  #include "musb_core.h"  struct tusb6010_glue {  	struct device		*dev;  	struct platform_device	*musb; +	struct platform_device	*phy;  };  static void tusb_musb_set_vbus(struct musb *musb, int is_on); @@ -43,7 +43,7 @@ static void tusb_musb_set_vbus(struct musb *musb, int is_on);   * Checks the revision. We need to use the DMA register as 3.0 does not   * have correct versions for TUSB_PRCM_REV or TUSB_INT_CTRL_REV.   */ -u8 tusb_get_revision(struct musb *musb) +static u8 tusb_get_revision(struct musb *musb)  {  	void __iomem	*tbase = musb->ctrl_base;  	u32		die_id; @@ -59,14 +59,13 @@ u8 tusb_get_revision(struct musb *musb)  	return rev;  } -EXPORT_SYMBOL_GPL(tusb_get_revision); -static int tusb_print_revision(struct musb *musb) +static void tusb_print_revision(struct musb *musb)  {  	void __iomem	*tbase = musb->ctrl_base;  	u8		rev; -	rev = tusb_get_revision(musb); +	rev = musb->tusb_revision;  	pr_info("tusb: %s%i.%i %s%i.%i %s%i.%i %s%i.%i %s%i %s%i.%i\n",  		"prcm", @@ -85,8 +84,6 @@ static int tusb_print_revision(struct musb *musb)  		TUSB_DIDR1_HI_CHIP_REV(musb_readl(tbase, TUSB_DIDR1_HI)),  		"rev",  		TUSB_REV_MAJOR(rev), TUSB_REV_MINOR(rev)); - -	return tusb_get_revision(musb);  }  #define WBUS_QUIRK_MASK	(TUSB_PHY_OTG_CTRL_TESTM2 | TUSB_PHY_OTG_CTRL_TESTM1 \ @@ -350,7 +347,7 @@ static void tusb_allow_idle(struct musb *musb, u32 wakeup_enables)  	u32		reg;  	if ((wakeup_enables & TUSB_PRCM_WBUS) -			&& (tusb_get_revision(musb) == TUSB_REV_30)) +			&& (musb->tusb_revision == TUSB_REV_30))  		tusb_wbus_quirk(musb, 1);  	tusb_set_clock_source(musb, 0); @@ -798,7 +795,7 @@ static irqreturn_t tusb_musb_interrupt(int irq, void *__hci)  		u32	reg;  		u32	i; -		if (tusb_get_revision(musb) == TUSB_REV_30) +		if (musb->tusb_revision == TUSB_REV_30)  			tusb_wbus_quirk(musb, 0);  		/* there are issues re-locking the PLL on wakeup ... */ @@ -1012,10 +1009,11 @@ static int tusb_musb_start(struct musb *musb)  		goto err;  	} -	ret = tusb_print_revision(musb); -	if (ret < 2) { +	musb->tusb_revision = tusb_get_revision(musb); +	tusb_print_revision(musb); +	if (musb->tusb_revision < 2) {  		printk(KERN_ERR "tusb: Unsupported TUSB6010 revision %i\n", -				ret); +				musb->tusb_revision);  		goto err;  	} @@ -1066,7 +1064,6 @@ static int tusb_musb_init(struct musb *musb)  	void __iomem		*sync = NULL;  	int			ret; -	usb_nop_xceiv_register();  	musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);  	if (IS_ERR_OR_NULL(musb->xceiv))  		return -EPROBE_DEFER; @@ -1118,7 +1115,6 @@ done:  			iounmap(sync);  		usb_put_phy(musb->xceiv); -		usb_nop_xceiv_unregister();  	}  	return ret;  } @@ -1134,7 +1130,6 @@ static int tusb_musb_exit(struct musb *musb)  	iounmap(musb->sync_va);  	usb_put_phy(musb->xceiv); -	usb_nop_xceiv_unregister();  	return 0;  } @@ -1152,7 +1147,11 @@ static const struct musb_platform_ops tusb_ops = {  	.set_vbus	= tusb_musb_set_vbus,  }; -static u64 tusb_dmamask = DMA_BIT_MASK(32); +static const struct platform_device_info tusb_dev_info = { +	.name		= "musb-hdrc", +	.id		= PLATFORM_DEVID_AUTO, +	.dma_mask	= DMA_BIT_MASK(32), +};  static int tusb_probe(struct platform_device *pdev)  { @@ -1160,7 +1159,7 @@ static int tusb_probe(struct platform_device *pdev)  	struct musb_hdrc_platform_data	*pdata = dev_get_platdata(&pdev->dev);  	struct platform_device		*musb;  	struct tusb6010_glue		*glue; - +	struct platform_device_info	pinfo;  	int				ret = -ENOMEM;  	glue = kzalloc(sizeof(*glue), GFP_KERNEL); @@ -1169,21 +1168,11 @@ static int tusb_probe(struct platform_device *pdev)  		goto err0;  	} -	musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO); -	if (!musb) { -		dev_err(&pdev->dev, "failed to allocate musb device\n"); -		goto err1; -	} - -	musb->dev.parent		= &pdev->dev; -	musb->dev.dma_mask		= &tusb_dmamask; -	musb->dev.coherent_dma_mask	= tusb_dmamask; -  	glue->dev			= &pdev->dev; -	glue->musb			= musb;  	pdata->platform_ops		= &tusb_ops; +	usb_phy_generic_register();  	platform_set_drvdata(pdev, glue);  	memset(musb_resources, 0x00, sizeof(*musb_resources) * @@ -1204,31 +1193,23 @@ static int tusb_probe(struct platform_device *pdev)  	musb_resources[2].end = pdev->resource[2].end;  	musb_resources[2].flags = pdev->resource[2].flags; -	ret = platform_device_add_resources(musb, musb_resources, -			ARRAY_SIZE(musb_resources)); -	if (ret) { -		dev_err(&pdev->dev, "failed to add resources\n"); -		goto err3; -	} - -	ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); -	if (ret) { -		dev_err(&pdev->dev, "failed to add platform_data\n"); -		goto err3; -	} - -	ret = platform_device_add(musb); -	if (ret) { -		dev_err(&pdev->dev, "failed to register musb device\n"); +	pinfo = tusb_dev_info; +	pinfo.parent = &pdev->dev; +	pinfo.res = musb_resources; +	pinfo.num_res = ARRAY_SIZE(musb_resources); +	pinfo.data = pdata; +	pinfo.size_data = sizeof(*pdata); + +	glue->musb = musb = platform_device_register_full(&pinfo); +	if (IS_ERR(musb)) { +		ret = PTR_ERR(musb); +		dev_err(&pdev->dev, "failed to register musb device: %d\n", ret);  		goto err3;  	}  	return 0;  err3: -	platform_device_put(musb); - -err1:  	kfree(glue);  err0: @@ -1240,6 +1221,7 @@ static int tusb_remove(struct platform_device *pdev)  	struct tusb6010_glue		*glue = platform_get_drvdata(pdev);  	platform_device_unregister(glue->musb); +	usb_phy_generic_unregister(glue->phy);  	kfree(glue);  	return 0; diff --git a/drivers/usb/musb/tusb6010.h b/drivers/usb/musb/tusb6010.h index 35c933a5d99..aec86c86ce3 100644 --- a/drivers/usb/musb/tusb6010.h +++ b/drivers/usb/musb/tusb6010.h @@ -12,14 +12,6 @@  #ifndef __TUSB6010_H__  #define __TUSB6010_H__ -extern u8 tusb_get_revision(struct musb *musb); - -#ifdef CONFIG_USB_TUSB6010 -#define musb_in_tusb()			1 -#else -#define musb_in_tusb()			0 -#endif -  #ifdef CONFIG_USB_TUSB_OMAP_DMA  #define tusb_dma_omap()			1  #else diff --git a/drivers/usb/musb/tusb6010_omap.c b/drivers/usb/musb/tusb6010_omap.c index b8794eb81e9..3ce152c0408 100644 --- a/drivers/usb/musb/tusb6010_omap.c +++ b/drivers/usb/musb/tusb6010_omap.c @@ -11,7 +11,6 @@  #include <linux/module.h>  #include <linux/kernel.h>  #include <linux/errno.h> -#include <linux/init.h>  #include <linux/usb.h>  #include <linux/platform_device.h>  #include <linux/dma-mapping.h> @@ -678,7 +677,7 @@ struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *ba  	tusb_dma->controller.channel_program = tusb_omap_dma_program;  	tusb_dma->controller.channel_abort = tusb_omap_dma_abort; -	if (tusb_get_revision(musb) >= TUSB_REV_30) +	if (musb->tusb_revision >= TUSB_REV_30)  		tusb_dma->multichannel = 1;  	for (i = 0; i < MAX_DMAREQ; i++) { diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index 59256b12f74..f202e508846 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -21,7 +21,6 @@  #include <linux/module.h>  #include <linux/kernel.h> -#include <linux/init.h>  #include <linux/clk.h>  #include <linux/err.h>  #include <linux/io.h> @@ -259,7 +258,7 @@ static int ux500_probe(struct platform_device *pdev)  		goto err1;  	} -	clk = clk_get(&pdev->dev, "usb"); +	clk = clk_get(&pdev->dev, NULL);  	if (IS_ERR(clk)) {  		dev_err(&pdev->dev, "failed to get clock\n");  		ret = PTR_ERR(clk); @@ -275,7 +274,6 @@ static int ux500_probe(struct platform_device *pdev)  	musb->dev.parent		= &pdev->dev;  	musb->dev.dma_mask		= &pdev->dev.coherent_dma_mask;  	musb->dev.coherent_dma_mask	= pdev->dev.coherent_dma_mask; -	musb->dev.of_node		= pdev->dev.of_node;  	glue->dev			= &pdev->dev;  	glue->musb			= musb; @@ -376,17 +374,10 @@ static int ux500_resume(struct device *dev)  	return 0;  } - -static const struct dev_pm_ops ux500_pm_ops = { -	.suspend	= ux500_suspend, -	.resume		= ux500_resume, -}; - -#define DEV_PM_OPS	(&ux500_pm_ops) -#else -#define DEV_PM_OPS	NULL  #endif +static SIMPLE_DEV_PM_OPS(ux500_pm_ops, ux500_suspend, ux500_resume); +  static const struct of_device_id ux500_match[] = {          { .compatible = "stericsson,db8500-musb", },          {} @@ -397,7 +388,7 @@ static struct platform_driver ux500_driver = {  	.remove		= ux500_remove,  	.driver		= {  		.name	= "musb-ux500", -		.pm	= DEV_PM_OPS, +		.pm	= &ux500_pm_ops,  		.of_match_table = ux500_match,  	},  }; diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c index 3700e971325..9aad00f11bd 100644 --- a/drivers/usb/musb/ux500_dma.c +++ b/drivers/usb/musb/ux500_dma.c @@ -336,7 +336,9 @@ static int ux500_dma_controller_start(struct ux500_dma_controller *controller)  							    data ?  							    data->dma_filter :  							    NULL, -							    param_array[ch_num]); +							    param_array ? +							    param_array[ch_num] : +							    NULL);  			if (!ux500_channel->dma_chan) {  				ERR("Dma pipe allocation error dir=%d ch=%d\n",  | 
