aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/musb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/musb')
-rw-r--r--drivers/usb/musb/Kconfig75
-rw-r--r--drivers/usb/musb/Makefile10
-rw-r--r--drivers/usb/musb/am35x.c187
-rw-r--r--drivers/usb/musb/blackfin.c132
-rw-r--r--drivers/usb/musb/cppi_dma.c42
-rw-r--r--drivers/usb/musb/da8xx.c165
-rw-r--r--drivers/usb/musb/davinci.c171
-rw-r--r--drivers/usb/musb/davinci.h4
-rw-r--r--drivers/usb/musb/jz4740.c201
-rw-r--r--drivers/usb/musb/musb_am335x.c43
-rw-r--r--drivers/usb/musb/musb_core.c837
-rw-r--r--drivers/usb/musb/musb_core.h78
-rw-r--r--drivers/usb/musb/musb_cppi41.c744
-rw-r--r--drivers/usb/musb/musb_debugfs.c22
-rw-r--r--drivers/usb/musb/musb_dma.h24
-rw-r--r--drivers/usb/musb/musb_dsps.c830
-rw-r--r--drivers/usb/musb/musb_gadget.c519
-rw-r--r--drivers/usb/musb/musb_gadget.h38
-rw-r--r--drivers/usb/musb/musb_gadget_ep0.c12
-rw-r--r--drivers/usb/musb/musb_host.c594
-rw-r--r--drivers/usb/musb/musb_host.h65
-rw-r--r--drivers/usb/musb/musb_io.h20
-rw-r--r--drivers/usb/musb/musb_virthub.c135
-rw-r--r--drivers/usb/musb/musbhsdma.c22
-rw-r--r--drivers/usb/musb/musbhsdma.h4
-rw-r--r--drivers/usb/musb/omap2430.c378
-rw-r--r--drivers/usb/musb/omap2430.h2
-rw-r--r--drivers/usb/musb/tusb6010.c199
-rw-r--r--drivers/usb/musb/tusb6010.h8
-rw-r--r--drivers/usb/musb/tusb6010_omap.c40
-rw-r--r--drivers/usb/musb/ux500.c287
-rw-r--r--drivers/usb/musb/ux500_dma.c121
32 files changed, 4230 insertions, 1779 deletions
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index f70cab3beee..06cc5d6ea68 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -6,12 +6,7 @@
# (M)HDRC = (Multipoint) Highspeed Dual-Role Controller
config USB_MUSB_HDRC
tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
- depends on USB && USB_GADGET
- select NOP_USB_XCEIV if (ARCH_DAVINCI || MACH_OMAP3EVM || BLACKFIN)
- select TWL4030_USB if MACH_OMAP_3430SDP
- select TWL6030_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA
- select USB_OTG_UTILS
- select USB_GADGET_DUALSPEED
+ 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
@@ -19,7 +14,7 @@ config USB_MUSB_HDRC
it's being used with, including the USB peripheral role,
or the USB host role, or both.
- Texas Instruments familiies using this IP include DaVinci
+ Texas Instruments families using this IP include DaVinci
(35x, 644x ...), OMAP 243x, OMAP 3, and TUSB 6010.
Analog Devices parts using this IP include Blackfin BF54x,
@@ -33,51 +28,100 @@ config USB_MUSB_HDRC
if USB_MUSB_HDRC
choice
+ bool "MUSB Mode Selection"
+ default USB_MUSB_DUAL_ROLE if (USB && USB_GADGET)
+ default USB_MUSB_HOST if (USB && !USB_GADGET)
+ default USB_MUSB_GADGET if (!USB && USB_GADGET)
+
+config USB_MUSB_HOST
+ bool "Host only mode"
+ 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=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=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.
+
+endchoice
+
+choice
prompt "Platform Glue Layer"
config USB_MUSB_DAVINCI
tristate "DaVinci"
depends on ARCH_DAVINCI_DMx
+ depends on BROKEN
config USB_MUSB_DA8XX
tristate "DA8xx/OMAP-L1x"
depends on ARCH_DAVINCI_DA8XX
+ depends on BROKEN
config USB_MUSB_TUSB6010
tristate "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"
depends on ARCH_OMAP
+config USB_MUSB_DSPS
+ tristate "TI DSPS platforms"
+ select USB_MUSB_AM335X_CHILD
+ depends on OF_IRQ
+
config USB_MUSB_BLACKFIN
tristate "Blackfin"
depends on (BF54x && !BF544) || (BF52x && ! BF522 && !BF523)
config USB_MUSB_UX500
- tristate "U8500 and U5500"
- depends on (ARCH_U8500 && AB8500_USB)
+ 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
+config USB_MUSB_AM335X_CHILD
+ tristate
+
choice
prompt 'MUSB DMA mode'
+ 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
default USB_TUSB_OMAP_DMA if USB_MUSB_TUSB6010
- default MUSB_PIO_ONLY if USB_MUSB_TUSB6010 || USB_MUSB_DA8XX || USB_MUSB_AM35X
+ default MUSB_PIO_ONLY if USB_MUSB_TUSB6010 || USB_MUSB_DA8XX || USB_MUSB_AM35X \
+ || USB_MUSB_DSPS
help
Unfortunately, only one option can be enabled here. Ideally one
should be able to build all these drivers into one kernel to
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.
@@ -94,9 +138,14 @@ config USB_TI_CPPI_DMA
help
Enable DMA transfers when TI CPPI DMA is available.
+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 88bfb9dee4b..ba495018b41 100644
--- a/drivers/usb/musb/Makefile
+++ b/drivers/usb/musb/Makefile
@@ -6,18 +6,23 @@ obj-$(CONFIG_USB_MUSB_HDRC) += musb_hdrc.o
musb_hdrc-y := musb_core.o
-musb_hdrc-y += musb_gadget_ep0.o musb_gadget.o
-musb_hdrc-y += musb_virthub.o musb_host.o
+musb_hdrc-$(CONFIG_USB_MUSB_HOST)$(CONFIG_USB_MUSB_DUAL_ROLE) += musb_virthub.o musb_host.o
+musb_hdrc-$(CONFIG_USB_MUSB_GADGET)$(CONFIG_USB_MUSB_DUAL_ROLE) += musb_gadget_ep0.o musb_gadget.o
musb_hdrc-$(CONFIG_DEBUG_FS) += musb_debugfs.o
# Hardware Glue Layer
obj-$(CONFIG_USB_MUSB_OMAP2PLUS) += omap2430.o
obj-$(CONFIG_USB_MUSB_AM35X) += am35x.o
+obj-$(CONFIG_USB_MUSB_DSPS) += musb_dsps.o
obj-$(CONFIG_USB_MUSB_TUSB6010) += tusb6010.o
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
# the kconfig must guarantee that only one of the
# possible I/O schemes will be enabled at a time ...
@@ -28,3 +33,4 @@ musb_hdrc-$(CONFIG_USB_INVENTRA_DMA) += musbhsdma.o
musb_hdrc-$(CONFIG_USB_TI_CPPI_DMA) += cppi_dma.o
musb_hdrc-$(CONFIG_USB_TUSB_OMAP_DMA) += tusb6010_omap.o
musb_hdrc-$(CONFIG_USB_UX500_DMA) += ux500_dma.o
+musb_hdrc-$(CONFIG_USB_TI_CPPI41_DMA) += musb_cppi41.o
diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c
index e233d2b7d33..0a34dd85955 100644
--- a/drivers/usb/musb/am35x.c
+++ b/drivers/usb/musb/am35x.c
@@ -26,14 +26,14 @@
*
*/
-#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 <plat/usb.h>
+#include <linux/usb/usb_phy_generic.h>
+#include <linux/platform_data/usb-omap.h>
#include "musb_core.h"
@@ -85,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
@@ -106,9 +106,8 @@ static void am35x_musb_enable(struct musb *musb)
musb_writel(reg_base, CORE_INTR_MASK_SET_REG, AM35X_INTR_USB_MASK);
/* Force the DRVVBUS IRQ so we can start polling for ID change. */
- if (is_otg_enabled(musb))
- musb_writel(reg_base, CORE_INTR_SRC_SET_REG,
- AM35X_INTR_DRVVBUS << AM35X_INTR_USB_SHIFT);
+ musb_writel(reg_base, CORE_INTR_SRC_SET_REG,
+ AM35X_INTR_DRVVBUS << AM35X_INTR_USB_SHIFT);
}
/*
@@ -149,7 +148,7 @@ static void otg_timer(unsigned long _musb)
*/
devctl = musb_readb(mregs, MUSB_DEVCTL);
dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl,
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
spin_lock_irqsave(&musb->lock, flags);
switch (musb->xceiv->state) {
@@ -172,9 +171,6 @@ static void otg_timer(unsigned long _musb)
MUSB_INTR_VBUSERROR << AM35X_INTR_USB_SHIFT);
break;
case OTG_STATE_B_IDLE:
- if (!is_peripheral_enabled(musb))
- break;
-
devctl = musb_readb(mregs, MUSB_DEVCTL);
if (devctl & MUSB_DEVCTL_BDEVICE)
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
@@ -191,9 +187,6 @@ static void am35x_musb_try_idle(struct musb *musb, unsigned long timeout)
{
static unsigned long last_timer;
- if (!is_otg_enabled(musb))
- return;
-
if (timeout == 0)
timeout = jiffies + msecs_to_jiffies(3);
@@ -201,7 +194,7 @@ static void am35x_musb_try_idle(struct musb *musb, unsigned long timeout)
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",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
del_timer(&otg_workaround);
last_timer = jiffies;
return;
@@ -214,7 +207,7 @@ static void am35x_musb_try_idle(struct musb *musb, unsigned long timeout)
last_timer = timeout;
dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
jiffies_to_msecs(timeout - jiffies));
mod_timer(&otg_workaround, timeout);
}
@@ -224,8 +217,9 @@ static irqreturn_t am35x_musb_interrupt(int irq, void *hci)
struct musb *musb = hci;
void __iomem *reg_base = musb->ctrl_base;
struct device *dev = musb->controller;
- struct musb_hdrc_platform_data *plat = dev->platform_data;
+ struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
struct omap_musb_board_data *data = plat->board_data;
+ struct usb_otg *otg = musb->xceiv->otg;
unsigned long flags;
irqreturn_t ret = IRQ_NONE;
u32 epintr, usbintr;
@@ -269,8 +263,7 @@ static irqreturn_t am35x_musb_interrupt(int irq, void *hci)
u8 devctl = musb_readb(mregs, MUSB_DEVCTL);
int err;
- err = is_host_enabled(musb) && (musb->int_usb &
- MUSB_INTR_VBUSERROR);
+ err = musb->int_usb & MUSB_INTR_VBUSERROR;
if (err) {
/*
* The Mentor core doesn't debounce VBUS as needed
@@ -287,16 +280,16 @@ static irqreturn_t am35x_musb_interrupt(int irq, void *hci)
musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
WARNING("VBUS error workaround (delay coming)\n");
- } else if (is_host_enabled(musb) && drvvbus) {
+ } else if (drvvbus) {
MUSB_HST_MODE(musb);
- musb->xceiv->default_a = 1;
+ otg->default_a = 1;
musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
portstate(musb->port1_status |= USB_PORT_STAT_POWER);
del_timer(&otg_workaround);
} else {
musb->is_active = 0;
MUSB_DEV_MODE(musb);
- musb->xceiv->default_a = 0;
+ otg->default_a = 0;
musb->xceiv->state = OTG_STATE_B_IDLE;
portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
}
@@ -304,12 +297,18 @@ static irqreturn_t am35x_musb_interrupt(int irq, void *hci)
/* NOTE: this must complete power-on within 100 ms. */
dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
drvvbus ? "on" : "off",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
err ? " ERROR" : "",
devctl);
ret = IRQ_HANDLED;
}
+ /* Drop spurious RX and TX if device is disconnected */
+ if (musb->int_usb & MUSB_INTR_DISCONNECT) {
+ musb->int_tx = 0;
+ musb->int_rx = 0;
+ }
+
if (musb->int_tx || musb->int_rx || musb->int_usb)
ret |= musb_interrupt(musb);
@@ -324,7 +323,7 @@ eoi:
}
/* Poll for ID change */
- if (is_otg_enabled(musb) && musb->xceiv->state == OTG_STATE_B_IDLE)
+ if (musb->xceiv->state == OTG_STATE_B_IDLE)
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
spin_unlock_irqrestore(&musb->lock, flags);
@@ -335,7 +334,7 @@ eoi:
static int am35x_musb_set_mode(struct musb *musb, u8 musb_mode)
{
struct device *dev = musb->controller;
- struct musb_hdrc_platform_data *plat = dev->platform_data;
+ struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
struct omap_musb_board_data *data = plat->board_data;
int retval = 0;
@@ -350,7 +349,7 @@ static int am35x_musb_set_mode(struct musb *musb, u8 musb_mode)
static int am35x_musb_init(struct musb *musb)
{
struct device *dev = musb->controller;
- struct musb_hdrc_platform_data *plat = dev->platform_data;
+ struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
struct omap_musb_board_data *data = plat->board_data;
void __iomem *reg_base = musb->ctrl_base;
u32 rev;
@@ -362,13 +361,11 @@ static int am35x_musb_init(struct musb *musb)
if (!rev)
return -ENODEV;
- usb_nop_xceiv_register();
- musb->xceiv = otg_get_transceiver();
- if (!musb->xceiv)
- return -ENODEV;
+ musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
+ if (IS_ERR_OR_NULL(musb->xceiv))
+ return -EPROBE_DEFER;
- if (is_host_enabled(musb))
- setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);
+ setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);
/* Reset the musb */
if (data->reset)
@@ -395,18 +392,16 @@ static int am35x_musb_init(struct musb *musb)
static int am35x_musb_exit(struct musb *musb)
{
struct device *dev = musb->controller;
- struct musb_hdrc_platform_data *plat = dev->platform_data;
+ struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
struct omap_musb_board_data *data = plat->board_data;
- if (is_host_enabled(musb))
- del_timer_sync(&otg_workaround);
+ del_timer_sync(&otg_workaround);
/* Shutdown the on-chip PHY and its PLL. */
if (data->set_phy_power)
data->set_phy_power(0);
- otg_put_transceiver(musb->xceiv);
- usb_nop_xceiv_unregister();
+ usb_put_phy(musb->xceiv);
return 0;
}
@@ -454,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 __init am35x_probe(struct platform_device *pdev)
+static int am35x_probe(struct platform_device *pdev)
{
- struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
+ 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;
@@ -473,100 +472,87 @@ static int __init am35x_probe(struct platform_device *pdev)
goto err0;
}
- musb = platform_device_alloc("musb-hdrc", -1);
- 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");
ret = PTR_ERR(phy_clk);
- goto err2;
+ goto err3;
}
clk = clk_get(&pdev->dev, "ick");
if (IS_ERR(clk)) {
dev_err(&pdev->dev, "failed to get clock\n");
ret = PTR_ERR(clk);
- goto err3;
+ goto err4;
}
ret = clk_enable(phy_clk);
if (ret) {
dev_err(&pdev->dev, "failed to enable PHY clock\n");
- goto err4;
+ goto err5;
}
ret = clk_enable(clk);
if (ret) {
dev_err(&pdev->dev, "failed to enable clock\n");
- goto err5;
+ 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;
+ glue->phy = usb_phy_generic_register();
+ if (IS_ERR(glue->phy))
+ goto err7;
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 err6;
- }
-
- ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
- if (ret) {
- dev_err(&pdev->dev, "failed to add platform_data\n");
- goto err6;
- }
-
- ret = platform_device_add(musb);
- if (ret) {
- dev_err(&pdev->dev, "failed to register musb device\n");
- goto err6;
+ 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;
-err6:
+err8:
+ usb_phy_generic_unregister(glue->phy);
+
+err7:
clk_disable(clk);
-err5:
+err6:
clk_disable(phy_clk);
-err4:
+err5:
clk_put(clk);
-err3:
+err4:
clk_put(phy_clk);
-err2:
- platform_device_put(musb);
-
-err1:
+err3:
kfree(glue);
err0:
return ret;
}
-static int __exit am35x_remove(struct platform_device *pdev)
+static int am35x_remove(struct platform_device *pdev)
{
struct am35x_glue *glue = platform_get_drvdata(pdev);
- platform_device_del(glue->musb);
- platform_device_put(glue->musb);
+ platform_device_unregister(glue->musb);
+ usb_phy_generic_unregister(glue->phy);
clk_disable(glue->clk);
clk_disable(glue->phy_clk);
clk_put(glue->clk);
@@ -580,7 +566,7 @@ static int __exit am35x_remove(struct platform_device *pdev)
static int am35x_suspend(struct device *dev)
{
struct am35x_glue *glue = dev_get_drvdata(dev);
- struct musb_hdrc_platform_data *plat = dev->platform_data;
+ struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
struct omap_musb_board_data *data = plat->board_data;
/* Shutdown the on-chip PHY and its PLL. */
@@ -596,7 +582,7 @@ static int am35x_suspend(struct device *dev)
static int am35x_resume(struct device *dev)
{
struct am35x_glue *glue = dev_get_drvdata(dev);
- struct musb_hdrc_platform_data *plat = dev->platform_data;
+ struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
struct omap_musb_board_data *data = plat->board_data;
int ret;
@@ -618,37 +604,20 @@ 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 = {
- .remove = __exit_p(am35x_remove),
+ .probe = am35x_probe,
+ .remove = am35x_remove,
.driver = {
.name = "musb-am35x",
- .pm = DEV_PM_OPS,
+ .pm = &am35x_pm_ops,
},
};
MODULE_DESCRIPTION("AM35x MUSB Glue Layer");
MODULE_AUTHOR("Ajay Kumar Gupta <ajay.gupta@ti.com>");
MODULE_LICENSE("GPL v2");
-
-static int __init am35x_init(void)
-{
- return platform_driver_probe(&am35x_driver, am35x_probe);
-}
-subsys_initcall(am35x_init);
-
-static void __exit am35x_exit(void)
-{
- platform_driver_unregister(&am35x_driver);
-}
-module_exit(am35x_exit);
+module_platform_driver(am35x_driver);
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c
index 5e7cfba5b07..d40d5f0b552 100644
--- a/drivers/usb/musb/blackfin.c
+++ b/drivers/usb/musb/blackfin.c
@@ -11,13 +11,14 @@
#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>
+#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/prefetch.h>
+#include <linux/usb/usb_phy_generic.h>
#include <asm/cacheflush.h>
@@ -28,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)
@@ -75,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();
@@ -129,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();
@@ -183,8 +185,8 @@ static irqreturn_t blackfin_interrupt(int irq, void *__hci)
}
/* Start sampling ID pin, when plug is removed from MUSB */
- if ((is_otg_enabled(musb) && (musb->xceiv->state == OTG_STATE_B_IDLE
- || musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) ||
+ if ((musb->xceiv->state == OTG_STATE_B_IDLE
+ || musb->xceiv->state == OTG_STATE_A_WAIT_BCON) ||
(musb->int_usb & MUSB_INTR_DISCONNECT && is_host_active(musb))) {
mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
musb->a_wait_bcon = TIMER_DELAY;
@@ -227,18 +229,13 @@ static void musb_conn_timer_handler(unsigned long _musb)
val = MUSB_INTR_SUSPEND | MUSB_INTR_VBUSERROR;
musb_writeb(musb->mregs, MUSB_INTRUSB, val);
- if (is_otg_enabled(musb))
- musb->xceiv->state = OTG_STATE_B_IDLE;
- else
- musb_writeb(musb->mregs, MUSB_POWER, MUSB_POWER_HSENAB);
+ musb->xceiv->state = OTG_STATE_B_IDLE;
}
mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
break;
case OTG_STATE_B_IDLE:
-
- if (!is_peripheral_enabled(musb))
- break;
- /* Start a new session. It seems that MUSB needs taking
+ /*
+ * Start a new session. It seems that MUSB needs taking
* some time to recognize the type of the plug inserted?
*/
val = musb_readw(musb->mregs, MUSB_DEVCTL);
@@ -283,21 +280,18 @@ static void musb_conn_timer_handler(unsigned long _musb)
break;
default:
dev_dbg(musb->controller, "%s state not handled\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
break;
}
spin_unlock_irqrestore(&musb->lock, flags);
dev_dbg(musb->controller, "state is %s\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
static void bfin_musb_enable(struct musb *musb)
{
- if (!is_otg_enabled(musb) && is_host_enabled(musb)) {
- mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
- musb->a_wait_bcon = TIMER_DELAY;
- }
+ /* REVISIT is this really correct ? */
}
static void bfin_musb_disable(struct musb *musb)
@@ -313,21 +307,15 @@ static void bfin_musb_set_vbus(struct musb *musb, int is_on)
dev_dbg(musb->controller, "VBUS %s, devctl %02x "
/* otg %3x conf %08x prcm %08x */ "\n",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
musb_readb(musb->mregs, MUSB_DEVCTL));
}
-static int bfin_musb_set_power(struct otg_transceiver *x, unsigned mA)
+static int bfin_musb_set_power(struct usb_phy *x, unsigned mA)
{
return 0;
}
-static void bfin_musb_try_idle(struct musb *musb, unsigned long timeout)
-{
- if (!is_otg_enabled(musb) && is_host_enabled(musb))
- mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
-}
-
static int bfin_musb_vbus_status(struct musb *musb)
{
return 0;
@@ -414,21 +402,18 @@ static int bfin_musb_init(struct musb *musb)
}
gpio_direction_output(musb->config->gpio_vrsel, 0);
- usb_nop_xceiv_register();
- musb->xceiv = otg_get_transceiver();
- if (!musb->xceiv) {
+ musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
+ if (IS_ERR_OR_NULL(musb->xceiv)) {
gpio_free(musb->config->gpio_vrsel);
- return -ENODEV;
+ return -EPROBE_DEFER;
}
bfin_musb_reg_init(musb);
- if (is_host_enabled(musb)) {
- setup_timer(&musb_conn_timer,
- musb_conn_timer_handler, (unsigned long) musb);
- }
- if (is_peripheral_enabled(musb))
- musb->xceiv->set_power = bfin_musb_set_power;
+ setup_timer(&musb_conn_timer, musb_conn_timer_handler,
+ (unsigned long) musb);
+
+ musb->xceiv->set_power = bfin_musb_set_power;
musb->isr = blackfin_interrupt;
musb->double_buffer_not_ok = true;
@@ -439,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);
- otg_put_transceiver(musb->xceiv);
- usb_nop_xceiv_unregister();
return 0;
}
@@ -453,7 +437,6 @@ static const struct musb_platform_ops bfin_ops = {
.disable = bfin_musb_disable,
.set_mode = bfin_musb_set_mode,
- .try_idle = bfin_musb_try_idle,
.vbus_status = bfin_musb_vbus_status,
.set_vbus = bfin_musb_set_vbus,
@@ -463,9 +446,10 @@ static const struct musb_platform_ops bfin_ops = {
static u64 bfin_dmamask = DMA_BIT_MASK(32);
-static int __init bfin_probe(struct platform_device *pdev)
+static int bfin_probe(struct platform_device *pdev)
{
- struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
+ struct resource musb_resources[2];
+ struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev);
struct platform_device *musb;
struct bfin_glue *glue;
@@ -477,7 +461,7 @@ static int __init bfin_probe(struct platform_device *pdev)
goto err0;
}
- musb = platform_device_alloc("musb-hdrc", -1);
+ musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO);
if (!musb) {
dev_err(&pdev->dev, "failed to allocate musb device\n");
goto err1;
@@ -492,29 +476,48 @@ static int __init 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);
- ret = platform_device_add_resources(musb, pdev->resource,
- pdev->num_resources);
+ memset(musb_resources, 0x00, sizeof(*musb_resources) *
+ ARRAY_SIZE(musb_resources));
+
+ musb_resources[0].name = pdev->resource[0].name;
+ musb_resources[0].start = pdev->resource[0].start;
+ musb_resources[0].end = pdev->resource[0].end;
+ musb_resources[0].flags = pdev->resource[0].flags;
+
+ musb_resources[1].name = pdev->resource[1].name;
+ musb_resources[1].start = pdev->resource[1].start;
+ 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 err2;
+ goto err3;
}
ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
if (ret) {
dev_err(&pdev->dev, "failed to add platform_data\n");
- goto err2;
+ goto err3;
}
ret = platform_device_add(musb);
if (ret) {
dev_err(&pdev->dev, "failed to register musb device\n");
- goto err2;
+ goto err3;
}
return 0;
+err3:
+ usb_phy_generic_unregister(glue->phy);
+
err2:
platform_device_put(musb);
@@ -525,12 +528,12 @@ err0:
return ret;
}
-static int __exit bfin_remove(struct platform_device *pdev)
+static int bfin_remove(struct platform_device *pdev)
{
struct bfin_glue *glue = platform_get_drvdata(pdev);
- platform_device_del(glue->musb);
- platform_device_put(glue->musb);
+ platform_device_unregister(glue->musb);
+ usb_phy_generic_unregister(glue->phy);
kfree(glue);
return 0;
@@ -563,37 +566,20 @@ 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,
},
};
MODULE_DESCRIPTION("Blackfin MUSB Glue Layer");
MODULE_AUTHOR("Bryan Wy <cooloney@kernel.org>");
MODULE_LICENSE("GPL v2");
-
-static int __init bfin_init(void)
-{
- return platform_driver_probe(&bfin_driver, bfin_probe);
-}
-subsys_initcall(bfin_init);
-
-static void __exit bfin_exit(void)
-{
- platform_driver_unregister(&bfin_driver);
-}
-module_exit(bfin_exit);
+module_platform_driver(bfin_driver);
diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c
index 66bc376005d..904fb85d85a 100644
--- a/drivers/usb/musb/cppi_dma.c
+++ b/drivers/usb/musb/cppi_dma.c
@@ -6,6 +6,7 @@
* The TUSB6020, using VLYNQ, has CPPI that looks much like DaVinci.
*/
+#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/usb.h>
@@ -104,7 +105,7 @@ static void cppi_reset_tx(struct cppi_tx_stateram __iomem *tx, u32 ptr)
musb_writel(&tx->tx_complete, 0, ptr);
}
-static void __init cppi_pool_init(struct cppi *cppi, struct cppi_channel *c)
+static void cppi_pool_init(struct cppi *cppi, struct cppi_channel *c)
{
int j;
@@ -149,14 +150,11 @@ static void cppi_pool_free(struct cppi_channel *c)
c->last_processed = NULL;
}
-static int __init cppi_controller_start(struct dma_controller *c)
+static void cppi_controller_start(struct cppi *controller)
{
- struct cppi *controller;
void __iomem *tibase;
int i;
- controller = container_of(c, struct cppi, controller);
-
/* do whatever is necessary to start controller */
for (i = 0; i < ARRAY_SIZE(controller->tx); i++) {
controller->tx[i].transmit = true;
@@ -211,8 +209,6 @@ static int __init cppi_controller_start(struct dma_controller *c)
/* disable RNDIS mode, also host rx RNDIS autorequest */
musb_writel(tibase, DAVINCI_RNDIS_REG, 0);
musb_writel(tibase, DAVINCI_AUTOREQ_REG, 0);
-
- return 0;
}
/*
@@ -221,14 +217,12 @@ static int __init cppi_controller_start(struct dma_controller *c)
* De-Init the DMA controller as necessary.
*/
-static int cppi_controller_stop(struct dma_controller *c)
+static void cppi_controller_stop(struct cppi *controller)
{
- struct cppi *controller;
void __iomem *tibase;
int i;
struct musb *musb;
- controller = container_of(c, struct cppi, controller);
musb = controller->musb;
tibase = controller->tibase;
@@ -254,8 +248,6 @@ static int cppi_controller_stop(struct dma_controller *c)
/*disable tx/rx cppi */
musb_writel(tibase, DAVINCI_TXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_DISABLE);
musb_writel(tibase, DAVINCI_RXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_DISABLE);
-
- return 0;
}
/* While dma channel is allocated, we only want the core irqs active
@@ -434,7 +426,6 @@ cppi_rndis_update(struct cppi_channel *c, int is_rx,
}
}
-#ifdef CONFIG_USB_MUSB_DEBUG
static void cppi_dump_rxbd(const char *tag, struct cppi_descriptor *bd)
{
pr_debug("RXBD/%s %08x: "
@@ -443,21 +434,16 @@ static void cppi_dump_rxbd(const char *tag, struct cppi_descriptor *bd)
bd->hw_next, bd->hw_bufp, bd->hw_off_len,
bd->hw_options);
}
-#endif
static void cppi_dump_rxq(int level, const char *tag, struct cppi_channel *rx)
{
-#ifdef CONFIG_USB_MUSB_DEBUG
struct cppi_descriptor *bd;
- if (!_dbg_level(level))
- return;
cppi_dump_rx(level, rx, tag);
if (rx->last_processed)
cppi_dump_rxbd("last", rx->last_processed);
for (bd = rx->head; bd; bd = bd->next)
cppi_dump_rxbd("active", bd);
-#endif
}
@@ -783,6 +769,7 @@ cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket)
void __iomem *tibase = musb->ctrl_base;
int is_rndis = 0;
struct cppi_rx_stateram __iomem *rx_ram = rx->state_ram;
+ struct cppi_descriptor *d;
if (onepacket) {
/* almost every USB driver, host or peripheral side */
@@ -896,14 +883,8 @@ cppi_next_rx_segment(struct musb *musb, struct cppi_channel *rx, int onepacket)
bd->hw_options |= CPPI_SOP_SET;
tail->hw_options |= CPPI_EOP_SET;
-#ifdef CONFIG_USB_MUSB_DEBUG
- if (_dbg_level(5)) {
- struct cppi_descriptor *d;
-
- for (d = rx->head; d; d = d->next)
- cppi_dump_rxbd("S", d);
- }
-#endif
+ for (d = rx->head; d; d = d->next)
+ cppi_dump_rxbd("S", d);
/* in case the preceding transfer left some state... */
tail = rx->last_processed;
@@ -1313,10 +1294,10 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
+EXPORT_SYMBOL_GPL(cppi_interrupt);
/* Instantiate a software object representing a DMA controller. */
-struct dma_controller *__init
-dma_controller_create(struct musb *musb, void __iomem *mregs)
+struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *mregs)
{
struct cppi *controller;
struct device *dev = musb->controller;
@@ -1331,8 +1312,6 @@ dma_controller_create(struct musb *musb, void __iomem *mregs)
controller->tibase = mregs - DAVINCI_BASE_OFFSET;
controller->musb = musb;
- controller->controller.start = cppi_controller_start;
- controller->controller.stop = cppi_controller_stop;
controller->controller.channel_alloc = cppi_channel_allocate;
controller->controller.channel_release = cppi_channel_release;
controller->controller.channel_program = cppi_channel_program;
@@ -1361,6 +1340,7 @@ dma_controller_create(struct musb *musb, void __iomem *mregs)
controller->irq = irq;
}
+ cppi_controller_start(controller);
return &controller->controller;
}
@@ -1373,6 +1353,8 @@ void dma_controller_destroy(struct dma_controller *c)
cppi = container_of(c, struct cppi, controller);
+ cppi_controller_stop(cppi);
+
if (cppi->irq)
free_irq(cppi->irq, cppi->musb);
diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c
index 2613bfdb09b..058775e647a 100644
--- a/drivers/usb/musb/da8xx.c
+++ b/drivers/usb/musb/da8xx.c
@@ -26,15 +26,16 @@
*
*/
-#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_generic.h>
#include <mach/da8xx.h>
-#include <mach/usb.h>
+#include <linux/platform_data/usb-davinci.h>
#include "musb_core.h"
@@ -84,6 +85,7 @@
struct da8xx_glue {
struct device *dev;
struct platform_device *musb;
+ struct platform_device *phy;
struct clk *clk;
};
@@ -154,9 +156,8 @@ static void da8xx_musb_enable(struct musb *musb)
musb_writel(reg_base, DA8XX_USB_INTR_MASK_SET_REG, mask);
/* Force the DRVVBUS IRQ so we can start polling for ID change. */
- if (is_otg_enabled(musb))
- musb_writel(reg_base, DA8XX_USB_INTR_SRC_SET_REG,
- DA8XX_INTR_DRVVBUS << DA8XX_INTR_USB_SHIFT);
+ musb_writel(reg_base, DA8XX_USB_INTR_SRC_SET_REG,
+ DA8XX_INTR_DRVVBUS << DA8XX_INTR_USB_SHIFT);
}
/**
@@ -197,7 +198,7 @@ static void otg_timer(unsigned long _musb)
*/
devctl = musb_readb(mregs, MUSB_DEVCTL);
dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl,
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
spin_lock_irqsave(&musb->lock, flags);
switch (musb->xceiv->state) {
@@ -230,9 +231,6 @@ static void otg_timer(unsigned long _musb)
MUSB_INTR_VBUSERROR << DA8XX_INTR_USB_SHIFT);
break;
case OTG_STATE_B_IDLE:
- if (!is_peripheral_enabled(musb))
- break;
-
/*
* There's no ID-changed IRQ, so we have no good way to tell
* when to switch to the A-Default state machine (by setting
@@ -262,9 +260,6 @@ static void da8xx_musb_try_idle(struct musb *musb, unsigned long timeout)
{
static unsigned long last_timer;
- if (!is_otg_enabled(musb))
- return;
-
if (timeout == 0)
timeout = jiffies + msecs_to_jiffies(3);
@@ -272,7 +267,7 @@ static void da8xx_musb_try_idle(struct musb *musb, unsigned long timeout)
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",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
del_timer(&otg_workaround);
last_timer = jiffies;
return;
@@ -285,7 +280,7 @@ static void da8xx_musb_try_idle(struct musb *musb, unsigned long timeout)
last_timer = timeout;
dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
jiffies_to_msecs(timeout - jiffies));
mod_timer(&otg_workaround, timeout);
}
@@ -294,6 +289,7 @@ static irqreturn_t da8xx_musb_interrupt(int irq, void *hci)
{
struct musb *musb = hci;
void __iomem *reg_base = musb->ctrl_base;
+ struct usb_otg *otg = musb->xceiv->otg;
unsigned long flags;
irqreturn_t ret = IRQ_NONE;
u32 status;
@@ -331,8 +327,7 @@ static irqreturn_t da8xx_musb_interrupt(int irq, void *hci)
u8 devctl = musb_readb(mregs, MUSB_DEVCTL);
int err;
- err = is_host_enabled(musb) && (musb->int_usb &
- MUSB_INTR_VBUSERROR);
+ err = musb->int_usb & MUSB_INTR_VBUSERROR;
if (err) {
/*
* The Mentor core doesn't debounce VBUS as needed
@@ -349,23 +344,23 @@ static irqreturn_t da8xx_musb_interrupt(int irq, void *hci)
musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
WARNING("VBUS error workaround (delay coming)\n");
- } else if (is_host_enabled(musb) && drvvbus) {
+ } else if (drvvbus) {
MUSB_HST_MODE(musb);
- musb->xceiv->default_a = 1;
+ otg->default_a = 1;
musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
portstate(musb->port1_status |= USB_PORT_STAT_POWER);
del_timer(&otg_workaround);
} else {
musb->is_active = 0;
MUSB_DEV_MODE(musb);
- musb->xceiv->default_a = 0;
+ otg->default_a = 0;
musb->xceiv->state = OTG_STATE_B_IDLE;
portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
}
dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
drvvbus ? "on" : "off",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
err ? " ERROR" : "",
devctl);
ret = IRQ_HANDLED;
@@ -380,7 +375,7 @@ static irqreturn_t da8xx_musb_interrupt(int irq, void *hci)
musb_writel(reg_base, DA8XX_USB_END_OF_INTR_REG, 0);
/* Poll for ID change */
- if (is_otg_enabled(musb) && musb->xceiv->state == OTG_STATE_B_IDLE)
+ if (musb->xceiv->state == OTG_STATE_B_IDLE)
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
spin_unlock_irqrestore(&musb->lock, flags);
@@ -415,6 +410,7 @@ static int da8xx_musb_init(struct musb *musb)
{
void __iomem *reg_base = musb->ctrl_base;
u32 rev;
+ int ret = -ENODEV;
musb->mregs += DA8XX_MENTOR_CORE_OFFSET;
@@ -423,13 +419,13 @@ static int da8xx_musb_init(struct musb *musb)
if (!rev)
goto fail;
- usb_nop_xceiv_register();
- musb->xceiv = otg_get_transceiver();
- if (!musb->xceiv)
+ musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
+ if (IS_ERR_OR_NULL(musb->xceiv)) {
+ ret = -EPROBE_DEFER;
goto fail;
+ }
- if (is_host_enabled(musb))
- setup_timer(&otg_workaround, otg_timer, (unsigned long)musb);
+ setup_timer(&otg_workaround, otg_timer, (unsigned long)musb);
/* Reset the controller */
musb_writel(reg_base, DA8XX_USB_CTRL_REG, DA8XX_SOFT_RESET_MASK);
@@ -447,18 +443,16 @@ static int da8xx_musb_init(struct musb *musb)
musb->isr = da8xx_musb_interrupt;
return 0;
fail:
- return -ENODEV;
+ return ret;
}
static int da8xx_musb_exit(struct musb *musb)
{
- if (is_host_enabled(musb))
- del_timer_sync(&otg_workaround);
+ del_timer_sync(&otg_workaround);
phy_off();
- otg_put_transceiver(musb->xceiv);
- usb_nop_xceiv_unregister();
+ usb_put_phy(musb->xceiv);
return 0;
}
@@ -476,14 +470,19 @@ 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 __init da8xx_probe(struct platform_device *pdev)
+static int da8xx_probe(struct platform_device *pdev)
{
- struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
+ struct resource musb_resources[2];
+ 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;
@@ -494,80 +493,82 @@ static int __init da8xx_probe(struct platform_device *pdev)
goto err0;
}
- musb = platform_device_alloc("musb-hdrc", -1);
- 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");
ret = PTR_ERR(clk);
- goto err2;
+ goto err3;
}
ret = clk_enable(clk);
if (ret) {
dev_err(&pdev->dev, "failed to enable clock\n");
- goto err3;
+ 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;
- 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 err4;
- }
-
- ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
- if (ret) {
- dev_err(&pdev->dev, "failed to add platform_data\n");
- goto err4;
+ glue->phy = usb_phy_generic_register();
+ if (IS_ERR(glue->phy)) {
+ ret = PTR_ERR(glue->phy);
+ goto err5;
}
+ platform_set_drvdata(pdev, glue);
- ret = platform_device_add(musb);
- if (ret) {
- dev_err(&pdev->dev, "failed to register musb device\n");
- goto err4;
+ memset(musb_resources, 0x00, sizeof(*musb_resources) *
+ ARRAY_SIZE(musb_resources));
+
+ musb_resources[0].name = pdev->resource[0].name;
+ musb_resources[0].start = pdev->resource[0].start;
+ musb_resources[0].end = pdev->resource[0].end;
+ musb_resources[0].flags = pdev->resource[0].flags;
+
+ musb_resources[1].name = pdev->resource[1].name;
+ musb_resources[1].start = pdev->resource[1].start;
+ musb_resources[1].end = pdev->resource[1].end;
+ musb_resources[1].flags = pdev->resource[1].flags;
+
+ 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;
-err4:
+err6:
+ usb_phy_generic_unregister(glue->phy);
+
+err5:
clk_disable(clk);
-err3:
+err4:
clk_put(clk);
-err2:
- platform_device_put(musb);
-
-err1:
+err3:
kfree(glue);
err0:
return ret;
}
-static int __exit da8xx_remove(struct platform_device *pdev)
+static int da8xx_remove(struct platform_device *pdev)
{
struct da8xx_glue *glue = platform_get_drvdata(pdev);
- platform_device_del(glue->musb);
- platform_device_put(glue->musb);
+ platform_device_unregister(glue->musb);
+ usb_phy_generic_unregister(glue->phy);
clk_disable(glue->clk);
clk_put(glue->clk);
kfree(glue);
@@ -576,7 +577,8 @@ static int __exit da8xx_remove(struct platform_device *pdev)
}
static struct platform_driver da8xx_driver = {
- .remove = __exit_p(da8xx_remove),
+ .probe = da8xx_probe,
+ .remove = da8xx_remove,
.driver = {
.name = "musb-da8xx",
},
@@ -585,15 +587,4 @@ static struct platform_driver da8xx_driver = {
MODULE_DESCRIPTION("DA8xx/OMAP-L1x MUSB Glue Layer");
MODULE_AUTHOR("Sergei Shtylyov <sshtylyov@ru.mvista.com>");
MODULE_LICENSE("GPL v2");
-
-static int __init da8xx_init(void)
-{
- return platform_driver_probe(&da8xx_driver, da8xx_probe);
-}
-subsys_initcall(da8xx_init);
-
-static void __exit da8xx_exit(void)
-{
- platform_driver_unregister(&da8xx_driver);
-}
-module_exit(da8xx_exit);
+module_platform_driver(da8xx_driver);
diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
index 7c569f51212..de8492b06e4 100644
--- a/drivers/usb/musb/davinci.c
+++ b/drivers/usb/musb/davinci.c
@@ -24,16 +24,18 @@
#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>
+#include <linux/err.h>
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
+#include <linux/usb/usb_phy_generic.h>
#include <mach/cputype.h>
+#include <mach/hardware.h>
#include <asm/mach-types.h>
@@ -113,8 +115,7 @@ static void davinci_musb_enable(struct musb *musb)
dma_off = 0;
/* force a DRVVBUS irq so we can start polling for ID change */
- if (is_otg_enabled(musb))
- musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG,
+ musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG,
DAVINCI_INTR_DRVVBUS << DAVINCI_USB_USBINT_SHIFT);
}
@@ -213,7 +214,7 @@ static void otg_timer(unsigned long _musb)
*/
devctl = musb_readb(mregs, MUSB_DEVCTL);
dev_dbg(musb->controller, "poll devctl %02x (%s)\n", devctl,
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
spin_lock_irqsave(&musb->lock, flags);
switch (musb->xceiv->state) {
@@ -232,10 +233,8 @@ static void otg_timer(unsigned long _musb)
MUSB_INTR_VBUSERROR << DAVINCI_USB_USBINT_SHIFT);
break;
case OTG_STATE_B_IDLE:
- if (!is_peripheral_enabled(musb))
- break;
-
- /* There's no ID-changed IRQ, so we have no good way to tell
+ /*
+ * There's no ID-changed IRQ, so we have no good way to tell
* when to switch to the A-Default state machine (by setting
* the DEVCTL.SESSION flag).
*
@@ -265,6 +264,7 @@ static irqreturn_t davinci_musb_interrupt(int irq, void *__hci)
unsigned long flags;
irqreturn_t retval = IRQ_NONE;
struct musb *musb = __hci;
+ struct usb_otg *otg = musb->xceiv->otg;
void __iomem *tibase = musb->ctrl_base;
struct cppi *cppi;
u32 tmp;
@@ -312,8 +312,7 @@ static irqreturn_t davinci_musb_interrupt(int irq, void *__hci)
u8 devctl = musb_readb(mregs, MUSB_DEVCTL);
int err = musb->int_usb & MUSB_INTR_VBUSERROR;
- err = is_host_enabled(musb)
- && (musb->int_usb & MUSB_INTR_VBUSERROR);
+ err = musb->int_usb & MUSB_INTR_VBUSERROR;
if (err) {
/* The Mentor core doesn't debounce VBUS as needed
* to cope with device connect current spikes. This
@@ -329,16 +328,16 @@ static irqreturn_t davinci_musb_interrupt(int irq, void *__hci)
musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
WARNING("VBUS error workaround (delay coming)\n");
- } else if (is_host_enabled(musb) && drvvbus) {
+ } else if (drvvbus) {
MUSB_HST_MODE(musb);
- musb->xceiv->default_a = 1;
+ otg->default_a = 1;
musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
portstate(musb->port1_status |= USB_PORT_STAT_POWER);
del_timer(&otg_workaround);
} else {
musb->is_active = 0;
MUSB_DEV_MODE(musb);
- musb->xceiv->default_a = 0;
+ otg->default_a = 0;
musb->xceiv->state = OTG_STATE_B_IDLE;
portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
}
@@ -349,7 +348,7 @@ static irqreturn_t davinci_musb_interrupt(int irq, void *__hci)
davinci_musb_source_power(musb, drvvbus, 0);
dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
drvvbus ? "on" : "off",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
err ? " ERROR" : "",
devctl);
retval = IRQ_HANDLED;
@@ -362,8 +361,7 @@ static irqreturn_t davinci_musb_interrupt(int irq, void *__hci)
musb_writel(tibase, DAVINCI_USB_EOI_REG, 0);
/* poll for ID change */
- if (is_otg_enabled(musb)
- && musb->xceiv->state == OTG_STATE_B_IDLE)
+ if (musb->xceiv->state == OTG_STATE_B_IDLE)
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
spin_unlock_irqrestore(&musb->lock, flags);
@@ -381,11 +379,13 @@ static int davinci_musb_init(struct musb *musb)
{
void __iomem *tibase = musb->ctrl_base;
u32 revision;
+ int ret = -ENODEV;
- usb_nop_xceiv_register();
- musb->xceiv = otg_get_transceiver();
- if (!musb->xceiv)
- return -ENODEV;
+ musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
+ if (IS_ERR_OR_NULL(musb->xceiv)) {
+ ret = -EPROBE_DEFER;
+ goto unregister;
+ }
musb->mregs += DAVINCI_BASE_OFFSET;
@@ -394,8 +394,7 @@ static int davinci_musb_init(struct musb *musb)
if (revision == 0)
goto fail;
- if (is_host_enabled(musb))
- setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);
+ setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);
davinci_musb_source_power(musb, 0, 1);
@@ -416,12 +415,7 @@ static int davinci_musb_init(struct musb *musb)
if (cpu_is_davinci_dm355()) {
u32 deepsleep = __raw_readl(DM355_DEEPSLEEP);
- if (is_host_enabled(musb)) {
- deepsleep &= ~DRVVBUS_OVERRIDE;
- } else {
- deepsleep &= ~DRVVBUS_FORCE;
- deepsleep |= DRVVBUS_OVERRIDE;
- }
+ deepsleep &= ~DRVVBUS_FORCE;
__raw_writel(deepsleep, DM355_DEEPSLEEP);
}
@@ -442,15 +436,15 @@ static int davinci_musb_init(struct musb *musb)
return 0;
fail:
- otg_put_transceiver(musb->xceiv);
- usb_nop_xceiv_unregister();
- return -ENODEV;
+ usb_put_phy(musb->xceiv);
+unregister:
+ usb_phy_generic_unregister();
+ return ret;
}
static int davinci_musb_exit(struct musb *musb)
{
- if (is_host_enabled(musb))
- del_timer_sync(&otg_workaround);
+ del_timer_sync(&otg_workaround);
/* force VBUS off */
if (cpu_is_davinci_dm355()) {
@@ -464,7 +458,7 @@ static int davinci_musb_exit(struct musb *musb)
davinci_musb_source_power(musb, 0 /*off*/, 1);
/* delay, to avoid problems with module reload */
- if (is_host_enabled(musb) && musb->xceiv->default_a) {
+ if (musb->xceiv->otg->default_a) {
int maxdelay = 30;
u8 devctl, warn = 0;
@@ -491,8 +485,7 @@ static int davinci_musb_exit(struct musb *musb)
phy_off();
- otg_put_transceiver(musb->xceiv);
- usb_nop_xceiv_unregister();
+ usb_put_phy(musb->xceiv);
return 0;
}
@@ -509,13 +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 __init davinci_probe(struct platform_device *pdev)
+static int davinci_probe(struct platform_device *pdev)
{
- struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
+ 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;
@@ -526,80 +525,84 @@ static int __init davinci_probe(struct platform_device *pdev)
goto err0;
}
- musb = platform_device_alloc("musb-hdrc", -1);
- 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");
ret = PTR_ERR(clk);
- goto err2;
+ goto err3;
}
ret = clk_enable(clk);
if (ret) {
dev_err(&pdev->dev, "failed to enable clock\n");
- goto err3;
+ 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);
- ret = platform_device_add_resources(musb, pdev->resource,
- pdev->num_resources);
- if (ret) {
- dev_err(&pdev->dev, "failed to add resources\n");
- goto err4;
- }
+ memset(musb_resources, 0x00, sizeof(*musb_resources) *
+ ARRAY_SIZE(musb_resources));
- ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
- if (ret) {
- dev_err(&pdev->dev, "failed to add platform_data\n");
- goto err4;
- }
+ musb_resources[0].name = pdev->resource[0].name;
+ musb_resources[0].start = pdev->resource[0].start;
+ musb_resources[0].end = pdev->resource[0].end;
+ musb_resources[0].flags = pdev->resource[0].flags;
- ret = platform_device_add(musb);
- if (ret) {
- dev_err(&pdev->dev, "failed to register musb device\n");
- goto err4;
+ musb_resources[1].name = pdev->resource[1].name;
+ musb_resources[1].start = pdev->resource[1].start;
+ musb_resources[1].end = pdev->resource[1].end;
+ musb_resources[1].flags = pdev->resource[1].flags;
+
+ /*
+ * 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;
}
return 0;
-err4:
+err5:
clk_disable(clk);
-err3:
+err4:
clk_put(clk);
-err2:
- platform_device_put(musb);
-
-err1:
+err3:
kfree(glue);
err0:
return ret;
}
-static int __exit davinci_remove(struct platform_device *pdev)
+static int davinci_remove(struct platform_device *pdev)
{
struct davinci_glue *glue = platform_get_drvdata(pdev);
- platform_device_del(glue->musb);
- platform_device_put(glue->musb);
+ platform_device_unregister(glue->musb);
+ usb_phy_generic_unregister();
clk_disable(glue->clk);
clk_put(glue->clk);
kfree(glue);
@@ -608,7 +611,8 @@ static int __exit davinci_remove(struct platform_device *pdev)
}
static struct platform_driver davinci_driver = {
- .remove = __exit_p(davinci_remove),
+ .probe = davinci_probe,
+ .remove = davinci_remove,
.driver = {
.name = "musb-davinci",
},
@@ -617,15 +621,4 @@ static struct platform_driver davinci_driver = {
MODULE_DESCRIPTION("DaVinci MUSB Glue Layer");
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
MODULE_LICENSE("GPL v2");
-
-static int __init davinci_init(void)
-{
- return platform_driver_probe(&davinci_driver, davinci_probe);
-}
-subsys_initcall(davinci_init);
-
-static void __exit davinci_exit(void)
-{
- platform_driver_unregister(&davinci_driver);
-}
-module_exit(davinci_exit);
+module_platform_driver(davinci_driver);
diff --git a/drivers/usb/musb/davinci.h b/drivers/usb/musb/davinci.h
index 046c84433ca..371baa0ee50 100644
--- a/drivers/usb/musb/davinci.h
+++ b/drivers/usb/musb/davinci.h
@@ -15,7 +15,7 @@
*/
/* Integrated highspeed/otg PHY */
-#define USBPHY_CTL_PADDR (DAVINCI_SYSTEM_MODULE_BASE + 0x34)
+#define USBPHY_CTL_PADDR 0x01c40034
#define USBPHY_DATAPOL BIT(11) /* (dm355) switch D+/D- */
#define USBPHY_PHYCLKGD BIT(8)
#define USBPHY_SESNDEN BIT(7) /* v(sess_end) comparator */
@@ -27,7 +27,7 @@
#define USBPHY_OTGPDWN BIT(1)
#define USBPHY_PHYPDWN BIT(0)
-#define DM355_DEEPSLEEP_PADDR (DAVINCI_SYSTEM_MODULE_BASE + 0x48)
+#define DM355_DEEPSLEEP_PADDR 0x01c40048
#define DRVVBUS_FORCE BIT(2)
#define DRVVBUS_OVERRIDE BIT(1)
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
new file mode 100644
index 00000000000..1e58ed2361c
--- /dev/null
+++ b/drivers/usb/musb/musb_am335x.c
@@ -0,0 +1,43 @@
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+
+static int am335x_child_probe(struct platform_device *pdev)
+{
+ int ret;
+
+ pm_runtime_enable(&pdev->dev);
+
+ ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ pm_runtime_disable(&pdev->dev);
+ return ret;
+}
+
+static const struct of_device_id am335x_child_of_match[] = {
+ { .compatible = "ti,am33xx-usb" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, am335x_child_of_match);
+
+static struct platform_driver am335x_child_driver = {
+ .probe = am335x_child_probe,
+ .driver = {
+ .name = "am335x-usb-childs",
+ .of_match_table = am335x_child_of_match,
+ },
+};
+
+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 3d11cf64ebd..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,12 +93,12 @@
#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>
#include <linux/platform_device.h>
#include <linux/io.h>
+#include <linux/dma-mapping.h>
#include "musb_core.h"
@@ -131,12 +131,15 @@ static inline struct musb *dev_to_musb(struct device *dev)
/*-------------------------------------------------------------------------*/
#ifndef CONFIG_BLACKFIN
-static int musb_ulpi_read(struct otg_transceiver *otg, u32 offset)
+static int musb_ulpi_read(struct usb_phy *phy, u32 offset)
{
- void __iomem *addr = otg->io_priv;
+ void __iomem *addr = phy->io_priv;
int i = 0;
u8 r;
u8 power;
+ int ret;
+
+ pm_runtime_get_sync(phy->io_dev);
/* Make sure the transceiver is not in low power mode */
power = musb_readb(addr, MUSB_POWER);
@@ -154,24 +157,33 @@ static int musb_ulpi_read(struct otg_transceiver *otg, u32 offset)
while (!(musb_readb(addr, MUSB_ULPI_REG_CONTROL)
& MUSB_ULPI_REG_CMPLT)) {
i++;
- if (i == 10000)
- return -ETIMEDOUT;
+ if (i == 10000) {
+ ret = -ETIMEDOUT;
+ goto out;
+ }
}
r = musb_readb(addr, MUSB_ULPI_REG_CONTROL);
r &= ~MUSB_ULPI_REG_CMPLT;
musb_writeb(addr, MUSB_ULPI_REG_CONTROL, r);
- return musb_readb(addr, MUSB_ULPI_REG_DATA);
+ ret = musb_readb(addr, MUSB_ULPI_REG_DATA);
+
+out:
+ pm_runtime_put(phy->io_dev);
+
+ return ret;
}
-static int musb_ulpi_write(struct otg_transceiver *otg,
- u32 offset, u32 data)
+static int musb_ulpi_write(struct usb_phy *phy, u32 offset, u32 data)
{
- void __iomem *addr = otg->io_priv;
+ void __iomem *addr = phy->io_priv;
int i = 0;
u8 r = 0;
u8 power;
+ int ret = 0;
+
+ pm_runtime_get_sync(phy->io_dev);
/* Make sure the transceiver is not in low power mode */
power = musb_readb(addr, MUSB_POWER);
@@ -185,22 +197,27 @@ static int musb_ulpi_write(struct otg_transceiver *otg,
while (!(musb_readb(addr, MUSB_ULPI_REG_CONTROL)
& MUSB_ULPI_REG_CMPLT)) {
i++;
- if (i == 10000)
- return -ETIMEDOUT;
+ if (i == 10000) {
+ ret = -ETIMEDOUT;
+ goto out;
+ }
}
r = musb_readb(addr, MUSB_ULPI_REG_CONTROL);
r &= ~MUSB_ULPI_REG_CMPLT;
musb_writeb(addr, MUSB_ULPI_REG_CONTROL, r);
- return 0;
+out:
+ pm_runtime_put(phy->io_dev);
+
+ return ret;
}
#else
#define musb_ulpi_read NULL
#define musb_ulpi_write NULL
#endif
-static struct otg_io_access_ops musb_ulpi_access = {
+static struct usb_phy_io_ops musb_ulpi_access = {
.read = musb_ulpi_read,
.write = musb_ulpi_write,
};
@@ -217,6 +234,9 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
struct musb *musb = hw_ep->musb;
void __iomem *fifo = hw_ep->fifo;
+ if (unlikely(len == 0))
+ return;
+
prefetch((u8 *)src);
dev_dbg(musb->controller, "%cX ep%d fifo %p count %d buf %p\n",
@@ -229,7 +249,7 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
/* best case is 32bit-aligned source address */
if ((0x02 & (unsigned long) src) == 0) {
if (len >= 4) {
- writesl(fifo, src + index, len >> 2);
+ iowrite32_rep(fifo, src + index, len >> 2);
index += len & ~0x03;
}
if (len & 0x02) {
@@ -238,7 +258,7 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
}
} else {
if (len >= 2) {
- writesw(fifo, src + index, len >> 1);
+ iowrite16_rep(fifo, src + index, len >> 1);
index += len & ~0x01;
}
}
@@ -246,7 +266,7 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
musb_writeb(fifo, 0, src[index]);
} else {
/* byte aligned */
- writesb(fifo, src, len);
+ iowrite8_rep(fifo, src, len);
}
}
@@ -259,6 +279,9 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
struct musb *musb = hw_ep->musb;
void __iomem *fifo = hw_ep->fifo;
+ if (unlikely(len == 0))
+ return;
+
dev_dbg(musb->controller, "%cX ep%d fifo %p count %d buf %p\n",
'R', hw_ep->epnum, fifo, len, dst);
@@ -269,7 +292,7 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
/* best case is 32bit-aligned destination address */
if ((0x02 & (unsigned long) dst) == 0) {
if (len >= 4) {
- readsl(fifo, dst, len >> 2);
+ ioread32_rep(fifo, dst, len >> 2);
index = len & ~0x03;
}
if (len & 0x02) {
@@ -278,7 +301,7 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
}
} else {
if (len >= 2) {
- readsw(fifo, dst, len >> 1);
+ ioread16_rep(fifo, dst, len >> 1);
index = len & ~0x01;
}
}
@@ -286,7 +309,7 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
dst[index] = musb_readb(fifo, 0);
} else {
/* byte aligned */
- readsb(fifo, dst, len);
+ ioread8_rep(fifo, dst, len);
}
}
#endif
@@ -331,7 +354,7 @@ void musb_load_testpacket(struct musb *musb)
/*
* Handles OTG hnp timeouts, such as b_ase0_brst
*/
-void musb_otg_timer_func(unsigned long data)
+static void musb_otg_timer_func(unsigned long data)
{
struct musb *musb = (struct musb *)data;
unsigned long flags;
@@ -347,15 +370,14 @@ void musb_otg_timer_func(unsigned long data)
case OTG_STATE_A_SUSPEND:
case OTG_STATE_A_WAIT_BCON:
dev_dbg(musb->controller, "HNP: %s timeout\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
musb_platform_set_vbus(musb, 0);
musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
break;
default:
dev_dbg(musb->controller, "HNP: Unhandled mode %s\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
- musb->ignore_disconnect = 0;
spin_unlock_irqrestore(&musb->lock, flags);
}
@@ -364,21 +386,23 @@ void musb_otg_timer_func(unsigned long data)
*/
void musb_hnp_stop(struct musb *musb)
{
- struct usb_hcd *hcd = musb_to_hcd(musb);
+ struct usb_hcd *hcd = musb->hcd;
void __iomem *mbase = musb->mregs;
u8 reg;
- dev_dbg(musb->controller, "HNP: stop from %s\n", otg_state_string(musb->xceiv->state));
+ dev_dbg(musb->controller, "HNP: stop from %s\n",
+ usb_otg_state_string(musb->xceiv->state));
switch (musb->xceiv->state) {
case OTG_STATE_A_PERIPHERAL:
musb_g_disconnect(musb);
dev_dbg(musb->controller, "HNP: back to %s\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
break;
case OTG_STATE_B_HOST:
dev_dbg(musb->controller, "HNP: Disabling HR\n");
- hcd->self.is_b_host = 0;
+ if (hcd)
+ hcd->self.is_b_host = 0;
musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
MUSB_DEV_MODE(musb);
reg = musb_readb(mbase, MUSB_POWER);
@@ -388,7 +412,7 @@ void musb_hnp_stop(struct musb *musb)
break;
default:
dev_dbg(musb->controller, "HNP: Stopping in unknown state %s\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
/*
@@ -412,11 +436,11 @@ void musb_hnp_stop(struct musb *musb)
*/
static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
- u8 devctl, u8 power)
+ u8 devctl)
{
irqreturn_t handled = IRQ_NONE;
- dev_dbg(musb->controller, "<== Power=%02x, DevCtl=%02x, int_usb=0x%x\n", power, devctl,
+ dev_dbg(musb->controller, "<== DevCtl=%02x, int_usb=0x%x\n", devctl,
int_usb);
/* in host mode, the peripheral may issue remote wakeup.
@@ -425,10 +449,11 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
*/
if (int_usb & MUSB_INTR_RESUME) {
handled = IRQ_HANDLED;
- dev_dbg(musb->controller, "RESUME (%s)\n", otg_state_string(musb->xceiv->state));
+ dev_dbg(musb->controller, "RESUME (%s)\n", usb_otg_state_string(musb->xceiv->state));
if (devctl & MUSB_DEVCTL_HM) {
void __iomem *mbase = musb->mregs;
+ u8 power;
switch (musb->xceiv->state) {
case OTG_STATE_A_SUSPEND:
@@ -436,6 +461,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
* will stop RESUME signaling
*/
+ power = musb_readb(musb->mregs, MUSB_POWER);
if (power & MUSB_POWER_SUSPENDM) {
/* spurious */
musb->int_usb &= ~MUSB_INTR_SUSPEND;
@@ -451,11 +477,14 @@ 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;
- usb_hcd_resume_root_hub(musb_to_hcd(musb));
+ musb_host_resume_root_hub(musb);
break;
case OTG_STATE_B_WAIT_ACON:
musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
@@ -465,14 +494,14 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
default:
WARNING("bogus %s RESUME (%s)\n",
"host",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
} else {
switch (musb->xceiv->state) {
case OTG_STATE_A_SUSPEND:
/* possibly DISCONNECT is upcoming */
musb->xceiv->state = OTG_STATE_A_HOST;
- usb_hcd_resume_root_hub(musb_to_hcd(musb));
+ musb_host_resume_root_hub(musb);
break;
case OTG_STATE_B_WAIT_ACON:
case OTG_STATE_B_PERIPHERAL:
@@ -494,7 +523,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
default:
WARNING("bogus %s RESUME (%s)\n",
"peripheral",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
}
}
@@ -510,7 +539,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
}
dev_dbg(musb->controller, "SESSION_REQUEST (%s)\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
/* IRQ arrives from ID pin sense or (later, if VBUS power
* is removed) SRP. responses are time critical:
@@ -574,8 +603,9 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
break;
}
- dev_dbg(musb->controller, "VBUS_ERROR in %s (%02x, %s), retry #%d, port1 %08x\n",
- otg_state_string(musb->xceiv->state),
+ dev_printk(ignore ? KERN_DEBUG : KERN_ERR, musb->controller,
+ "VBUS_ERROR in %s (%02x, %s), retry #%d, port1 %08x\n",
+ usb_otg_state_string(musb->xceiv->state),
devctl,
({ char *s;
switch (devctl & MUSB_DEVCTL_VBUS) {
@@ -588,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);
@@ -599,8 +629,8 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
}
if (int_usb & MUSB_INTR_SUSPEND) {
- dev_dbg(musb->controller, "SUSPEND (%s) devctl %02x power %02x\n",
- otg_state_string(musb->xceiv->state), devctl, power);
+ dev_dbg(musb->controller, "SUSPEND (%s) devctl %02x\n",
+ usb_otg_state_string(musb->xceiv->state), devctl);
handled = IRQ_HANDLED;
switch (musb->xceiv->state) {
@@ -613,7 +643,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
* undesired detour through A_WAIT_BCON.
*/
musb_hnp_stop(musb);
- usb_hcd_resume_root_hub(musb_to_hcd(musb));
+ musb_host_resume_root_hub(musb);
musb_root_disconnect(musb);
musb_platform_try_idle(musb, jiffies
+ msecs_to_jiffies(musb->a_wait_bcon
@@ -625,8 +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 = is_otg_enabled(musb)
- && musb->xceiv->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");
@@ -642,8 +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 = is_otg_enabled(musb)
- && musb->xceiv->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 */
@@ -657,7 +685,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
}
if (int_usb & MUSB_INTR_CONNECT) {
- struct usb_hcd *hcd = musb_to_hcd(musb);
+ struct usb_hcd *hcd = musb->hcd;
handled = IRQ_HANDLED;
musb->is_active = 1;
@@ -668,8 +696,10 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
if (is_peripheral_active(musb)) {
/* REVISIT HNP; just force disconnect */
}
- musb_writew(musb->mregs, MUSB_INTRTXE, musb->epmask);
- musb_writew(musb->mregs, MUSB_INTRRXE, musb->epmask & 0xfffe);
+ musb->intrtxe = musb->epmask;
+ musb_writew(musb->mregs, MUSB_INTRTXE, musb->intrtxe);
+ musb->intrrxe = musb->epmask & 0xfffe;
+ musb_writew(musb->mregs, MUSB_INTRRXE, musb->intrrxe);
musb_writeb(musb->mregs, MUSB_INTRUSBE, 0xf7);
musb->port1_status &= ~(USB_PORT_STAT_LOW_SPEED
|USB_PORT_STAT_HIGH_SPEED
@@ -696,42 +726,38 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
dev_dbg(musb->controller, "HNP: CONNECT, now b_host\n");
b_host:
musb->xceiv->state = OTG_STATE_B_HOST;
- hcd->self.is_b_host = 1;
- musb->ignore_disconnect = 0;
+ if (musb->hcd)
+ musb->hcd->self.is_b_host = 1;
del_timer(&musb->otg_timer);
break;
default:
if ((devctl & MUSB_DEVCTL_VBUS)
== (3 << MUSB_DEVCTL_VBUS_SHIFT)) {
musb->xceiv->state = OTG_STATE_A_HOST;
- hcd->self.is_b_host = 0;
+ if (hcd)
+ hcd->self.is_b_host = 0;
}
break;
}
- /* poke the root hub */
- MUSB_HST_MODE(musb);
- if (hcd->status_urb)
- usb_hcd_poll_rh_status(hcd);
- else
- usb_hcd_resume_root_hub(hcd);
+ musb_host_poke_root_hub(musb);
dev_dbg(musb->controller, "CONNECT (%s) devctl %02x\n",
- otg_state_string(musb->xceiv->state), devctl);
+ usb_otg_state_string(musb->xceiv->state), devctl);
}
- if ((int_usb & MUSB_INTR_DISCONNECT) && !musb->ignore_disconnect) {
+ if (int_usb & MUSB_INTR_DISCONNECT) {
dev_dbg(musb->controller, "DISCONNECT (%s) as %s, devctl %02x\n",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
MUSB_MODE(musb), devctl);
handled = IRQ_HANDLED;
switch (musb->xceiv->state) {
case OTG_STATE_A_HOST:
case OTG_STATE_A_SUSPEND:
- usb_hcd_resume_root_hub(musb_to_hcd(musb));
+ musb_host_resume_root_hub(musb);
musb_root_disconnect(musb);
- if (musb->a_wait_bcon != 0 && is_otg_enabled(musb))
+ if (musb->a_wait_bcon != 0)
musb_platform_try_idle(musb, jiffies
+ msecs_to_jiffies(musb->a_wait_bcon));
break;
@@ -742,7 +768,8 @@ b_host:
* in hnp_stop() is currently not used...
*/
musb_root_disconnect(musb);
- musb_to_hcd(musb)->self.is_b_host = 0;
+ if (musb->hcd)
+ musb->hcd->self.is_b_host = 0;
musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
MUSB_DEV_MODE(musb);
musb_g_disconnect(musb);
@@ -759,7 +786,7 @@ b_host:
break;
default:
WARNING("unhandled DISCONNECT transition (%s)\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
break;
}
}
@@ -769,7 +796,7 @@ b_host:
*/
if (int_usb & MUSB_INTR_RESET) {
handled = IRQ_HANDLED;
- if (is_host_capable() && (devctl & MUSB_DEVCTL_HM) != 0) {
+ if ((devctl & MUSB_DEVCTL_HM) != 0) {
/*
* Looks like non-HS BABBLE can be ignored, but
* HS BABBLE is an error condition. For HS the solution
@@ -783,34 +810,28 @@ b_host:
ERR("Stopping host session -- babble\n");
musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
}
- } else if (is_peripheral_capable()) {
+ } else {
dev_dbg(musb->controller, "BUS RESET as %s\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
switch (musb->xceiv->state) {
case OTG_STATE_A_SUSPEND:
- /* We need to ignore disconnect on suspend
- * otherwise tusb 2.0 won't reconnect after a
- * power cycle, which breaks otg compliance.
- */
- musb->ignore_disconnect = 1;
musb_g_reset(musb);
/* FALLTHROUGH */
case OTG_STATE_A_WAIT_BCON: /* OPT TD.4.7-900ms */
/* never use invalid T(a_wait_bcon) */
dev_dbg(musb->controller, "HNP: in %s, %d msec timeout\n",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
TA_WAIT_BCON(musb));
mod_timer(&musb->otg_timer, jiffies
+ msecs_to_jiffies(TA_WAIT_BCON(musb)));
break;
case OTG_STATE_A_PERIPHERAL:
- musb->ignore_disconnect = 0;
del_timer(&musb->otg_timer);
musb_g_reset(musb);
break;
case OTG_STATE_B_WAIT_ACON:
dev_dbg(musb->controller, "HNP: RESET (%s), to b_peripheral\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
musb_g_reset(musb);
break;
@@ -822,11 +843,15 @@ b_host:
break;
default:
dev_dbg(musb->controller, "Unhandled BUS RESET as %s\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
}
}
+ /* 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
@@ -879,78 +904,74 @@ b_host:
/*-------------------------------------------------------------------------*/
+static void musb_generic_disable(struct musb *musb)
+{
+ void __iomem *mbase = musb->mregs;
+ u16 temp;
+
+ /* disable interrupts */
+ musb_writeb(mbase, MUSB_INTRUSBE, 0);
+ musb->intrtxe = 0;
+ musb_writew(mbase, MUSB_INTRTXE, 0);
+ musb->intrrxe = 0;
+ musb_writew(mbase, MUSB_INTRRXE, 0);
+
+ /* off */
+ musb_writeb(mbase, MUSB_DEVCTL, 0);
+
+ /* flush pending interrupts */
+ temp = musb_readb(mbase, MUSB_INTRUSB);
+ temp = musb_readw(mbase, MUSB_INTRTX);
+ temp = musb_readw(mbase, MUSB_INTRRX);
+
+}
+
/*
-* Program the HDRC to start (enable interrupts, dma, etc.).
-*/
+ * 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);
+ 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_writew(regs, MUSB_INTRTXE, musb->epmask);
- musb_writew(regs, MUSB_INTRRXE, musb->epmask & 0xfffe);
+ 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_POWER_HSENAB
+ /* ENSUSPEND wedges tusb */
+ /* | MUSB_POWER_ENSUSPEND */
+ );
musb->is_active = 0;
devctl = musb_readb(regs, MUSB_DEVCTL);
devctl &= ~MUSB_DEVCTL_SESSION;
- if (is_otg_enabled(musb)) {
- /* session started after:
- * (a) ID-grounded irq, host mode;
- * (b) vbus present/connect IRQ, peripheral mode;
- * (c) peripheral initiates, using SRP
- */
- if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS)
- musb->is_active = 1;
- else
- devctl |= MUSB_DEVCTL_SESSION;
-
- } else if (is_host_enabled(musb)) {
- /* assume ID pin is hard-wired to ground */
+ /* 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;
-
- } else /* peripheral is enabled */ {
- if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS)
- musb->is_active = 1;
}
+
musb_platform_enable(musb);
musb_writeb(regs, MUSB_DEVCTL, devctl);
}
-
-static void musb_generic_disable(struct musb *musb)
-{
- void __iomem *mbase = musb->mregs;
- u16 temp;
-
- /* disable interrupts */
- musb_writeb(mbase, MUSB_INTRUSBE, 0);
- musb_writew(mbase, MUSB_INTRTXE, 0);
- musb_writew(mbase, MUSB_INTRRXE, 0);
-
- /* off */
- musb_writeb(mbase, MUSB_DEVCTL, 0);
-
- /* flush pending interrupts */
- temp = musb_readb(mbase, MUSB_INTRUSB);
- temp = musb_readw(mbase, MUSB_INTRTX);
- temp = musb_readw(mbase, MUSB_INTRRX);
-
-}
-
/*
* Make the HDRC stop (disable interrupts, etc.);
* reversible by musb_start
@@ -982,6 +1003,7 @@ static void musb_shutdown(struct platform_device *pdev)
pm_runtime_get_sync(musb->controller);
+ musb_host_cleanup(musb);
musb_gadget_cleanup(musb);
spin_lock_irqsave(&musb->lock, flags);
@@ -989,8 +1011,6 @@ static void musb_shutdown(struct platform_device *pdev)
musb_generic_disable(musb);
spin_unlock_irqrestore(&musb->lock, flags);
- if (!is_otg_enabled(musb) && is_host_enabled(musb))
- usb_remove_hcd(musb_to_hcd(musb));
musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
musb_platform_exit(musb);
@@ -1016,13 +1036,15 @@ static void musb_shutdown(struct platform_device *pdev)
|| defined(CONFIG_USB_MUSB_OMAP2PLUS) \
|| defined(CONFIG_USB_MUSB_OMAP2PLUS_MODULE) \
|| defined(CONFIG_USB_MUSB_AM35X) \
- || defined(CONFIG_USB_MUSB_AM35X_MODULE)
-static ushort __initdata fifo_mode = 4;
+ || defined(CONFIG_USB_MUSB_AM35X_MODULE) \
+ || defined(CONFIG_USB_MUSB_DSPS) \
+ || defined(CONFIG_USB_MUSB_DSPS_MODULE)
+static ushort fifo_mode = 4;
#elif defined(CONFIG_USB_MUSB_UX500) \
|| defined(CONFIG_USB_MUSB_UX500_MODULE)
-static ushort __initdata fifo_mode = 5;
+static ushort fifo_mode = 5;
#else
-static ushort __initdata fifo_mode = 2;
+static ushort fifo_mode = 2;
#endif
/* "modprobe ... fifo_mode=1" etc */
@@ -1035,7 +1057,7 @@ MODULE_PARM_DESC(fifo_mode, "initial endpoint configuration");
*/
/* mode 0 - fits in 2KB */
-static struct musb_fifo_cfg __initdata mode_0_cfg[] = {
+static struct musb_fifo_cfg mode_0_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_RXTX, .maxpacket = 512, },
@@ -1044,7 +1066,7 @@ static struct musb_fifo_cfg __initdata mode_0_cfg[] = {
};
/* mode 1 - fits in 4KB */
-static struct musb_fifo_cfg __initdata mode_1_cfg[] = {
+static struct musb_fifo_cfg mode_1_cfg[] = {
{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, .mode = BUF_DOUBLE, },
{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_DOUBLE, },
{ .hw_ep_num = 2, .style = FIFO_RXTX, .maxpacket = 512, .mode = BUF_DOUBLE, },
@@ -1053,7 +1075,7 @@ static struct musb_fifo_cfg __initdata mode_1_cfg[] = {
};
/* mode 2 - fits in 4KB */
-static struct musb_fifo_cfg __initdata mode_2_cfg[] = {
+static struct musb_fifo_cfg mode_2_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 = 512, },
@@ -1063,7 +1085,7 @@ static struct musb_fifo_cfg __initdata mode_2_cfg[] = {
};
/* mode 3 - fits in 4KB */
-static struct musb_fifo_cfg __initdata mode_3_cfg[] = {
+static struct musb_fifo_cfg mode_3_cfg[] = {
{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, .mode = BUF_DOUBLE, },
{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_DOUBLE, },
{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, },
@@ -1073,7 +1095,7 @@ static struct musb_fifo_cfg __initdata mode_3_cfg[] = {
};
/* mode 4 - fits in 16KB */
-static struct musb_fifo_cfg __initdata mode_4_cfg[] = {
+static struct musb_fifo_cfg mode_4_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 = 512, },
@@ -1104,7 +1126,7 @@ static struct musb_fifo_cfg __initdata mode_4_cfg[] = {
};
/* mode 5 - fits in 8KB */
-static struct musb_fifo_cfg __initdata mode_5_cfg[] = {
+static struct musb_fifo_cfg mode_5_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 = 512, },
@@ -1140,7 +1162,7 @@ static struct musb_fifo_cfg __initdata mode_5_cfg[] = {
*
* returns negative errno or offset for next fifo.
*/
-static int __init
+static int
fifo_setup(struct musb *musb, struct musb_hw_ep *hw_ep,
const struct musb_fifo_cfg *cfg, u16 offset)
{
@@ -1170,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;
@@ -1211,11 +1233,11 @@ fifo_setup(struct musb *musb, struct musb_hw_ep *hw_ep,
return offset + (maxpacket << ((c_size & MUSB_FIFOSZ_DPB) ? 1 : 0));
}
-static struct musb_fifo_cfg __initdata ep0_cfg = {
+static struct musb_fifo_cfg ep0_cfg = {
.style = FIFO_RXTX, .maxpacket = 64,
};
-static int __init ep_config_from_table(struct musb *musb)
+static int ep_config_from_table(struct musb *musb)
{
const struct musb_fifo_cfg *cfg;
unsigned i, n;
@@ -1282,7 +1304,7 @@ done:
if (offset < 0) {
pr_debug("%s: mem overrun, ep %d\n",
musb_driver_name, epn);
- return -EINVAL;
+ return offset;
}
epn++;
musb->nr_endpoints = max(epn, musb->nr_endpoints);
@@ -1306,11 +1328,11 @@ done:
* ep_config_from_hw - when MUSB_C_DYNFIFO_DEF is false
* @param musb the controller
*/
-static int __init ep_config_from_hw(struct musb *musb)
+static int ep_config_from_hw(struct musb *musb)
{
u8 epnum = 0;
struct musb_hw_ep *hw_ep;
- void *mbase = musb->mregs;
+ void __iomem *mbase = musb->mregs;
int ret = 0;
dev_dbg(musb->controller, "<== static silicon ep config\n");
@@ -1353,7 +1375,7 @@ enum { MUSB_CONTROLLER_MHDRC, MUSB_CONTROLLER_HDRC, };
/* Initialize MUSB (M)HDRC part of the USB hardware subsystem;
* configure endpoints, or take their config from silicon
*/
-static int __init musb_core_init(u16 musb_type, struct musb *musb)
+static int musb_core_init(u16 musb_type, struct musb *musb)
{
u8 reg;
char *type;
@@ -1478,33 +1500,6 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
/*-------------------------------------------------------------------------*/
-#if defined(CONFIG_SOC_OMAP2430) || defined(CONFIG_SOC_OMAP3430) || \
- defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_ARCH_U8500)
-
-static irqreturn_t generic_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);
-
- if (musb->int_usb || musb->int_tx || musb->int_rx)
- retval = musb_interrupt(musb);
-
- spin_unlock_irqrestore(&musb->lock, flags);
-
- return retval;
-}
-
-#else
-#define generic_interrupt NULL
-#endif
-
/*
* handle all the irqs defined by the HDRC core. for now we expect: other
* irq sources (phy, dma, etc) will be handled first, musb->int_* values
@@ -1515,12 +1510,11 @@ static irqreturn_t generic_interrupt(int irq, void *__hci)
irqreturn_t musb_interrupt(struct musb *musb)
{
irqreturn_t retval = IRQ_NONE;
- u8 devctl, power;
+ u8 devctl;
int ep_num;
u32 reg;
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
- power = musb_readb(musb->mregs, MUSB_POWER);
dev_dbg(musb->controller, "** IRQ %s usb%04x tx%04x rx%04x\n",
(devctl & MUSB_DEVCTL_HM) ? "host" : "peripheral",
@@ -1531,7 +1525,7 @@ irqreturn_t musb_interrupt(struct musb *musb)
*/
if (musb->int_usb)
retval |= musb_stage0_irq(musb, musb->int_usb,
- devctl, power);
+ devctl);
/* "stage 1" is handling endpoint irqs */
@@ -1551,13 +1545,10 @@ irqreturn_t musb_interrupt(struct musb *musb)
/* musb_ep_select(musb->mregs, ep_num); */
/* REVISIT just retval = ep->rx_irq(...) */
retval = IRQ_HANDLED;
- if (devctl & MUSB_DEVCTL_HM) {
- if (is_host_capable())
- musb_host_rx(musb, ep_num);
- } else {
- if (is_peripheral_capable())
- musb_g_rx(musb, ep_num);
- }
+ if (devctl & MUSB_DEVCTL_HM)
+ musb_host_rx(musb, ep_num);
+ else
+ musb_g_rx(musb, ep_num);
}
reg >>= 1;
@@ -1572,13 +1563,10 @@ irqreturn_t musb_interrupt(struct musb *musb)
/* musb_ep_select(musb->mregs, ep_num); */
/* REVISIT just retval |= ep->tx_irq(...) */
retval = IRQ_HANDLED;
- if (devctl & MUSB_DEVCTL_HM) {
- if (is_host_capable())
- musb_host_tx(musb, ep_num);
- } else {
- if (is_peripheral_capable())
- musb_g_tx(musb, ep_num);
- }
+ if (devctl & MUSB_DEVCTL_HM)
+ musb_host_tx(musb, ep_num);
+ else
+ musb_g_tx(musb, ep_num);
}
reg >>= 1;
ep_num++;
@@ -1589,7 +1577,7 @@ irqreturn_t musb_interrupt(struct musb *musb)
EXPORT_SYMBOL_GPL(musb_interrupt);
#ifndef CONFIG_MUSB_PIO_ONLY
-static bool __initdata use_dma = 1;
+static bool use_dma = 1;
/* "modprobe ... use_dma=0" etc */
module_param(use_dma, bool, 0);
@@ -1614,22 +1602,16 @@ void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit)
} else {
/* endpoints 1..15 */
if (transmit) {
- if (devctl & MUSB_DEVCTL_HM) {
- if (is_host_capable())
- musb_host_tx(musb, epnum);
- } else {
- if (is_peripheral_capable())
- musb_g_tx(musb, epnum);
- }
+ if (devctl & MUSB_DEVCTL_HM)
+ musb_host_tx(musb, epnum);
+ else
+ musb_g_tx(musb, epnum);
} else {
/* receive */
- if (devctl & MUSB_DEVCTL_HM) {
- if (is_host_capable())
- musb_host_rx(musb, epnum);
- } else {
- if (is_peripheral_capable())
- musb_g_rx(musb, epnum);
- }
+ if (devctl & MUSB_DEVCTL_HM)
+ musb_host_rx(musb, epnum);
+ else
+ musb_g_rx(musb, epnum);
}
}
}
@@ -1641,8 +1623,6 @@ EXPORT_SYMBOL_GPL(musb_dma_completion);
/*-------------------------------------------------------------------------*/
-#ifdef CONFIG_SYSFS
-
static ssize_t
musb_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -1651,7 +1631,7 @@ musb_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
int ret = -EINVAL;
spin_lock_irqsave(&musb->lock, flags);
- ret = sprintf(buf, "%s\n", otg_state_string(musb->xceiv->state));
+ ret = sprintf(buf, "%s\n", usb_otg_state_string(musb->xceiv->state));
spin_unlock_irqrestore(&musb->lock, flags);
return ret;
@@ -1759,49 +1739,67 @@ static const struct attribute_group musb_attr_group = {
.attrs = musb_attributes,
};
-#endif /* sysfs */
-
/* Only used to provide driver mode change events */
static void musb_irq_work(struct work_struct *data)
{
struct musb *musb = container_of(data, struct musb, irq_work);
- static int old_state;
- if (musb->xceiv->state != old_state) {
- old_state = musb->xceiv->state;
+ if (musb->xceiv->state != musb->xceiv_old_state) {
+ musb->xceiv_old_state = musb->xceiv->state;
sysfs_notify(&musb->controller->kobj, NULL, "mode");
}
}
+/* 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
*/
-static struct musb *__init
-allocate_instance(struct device *dev,
+static struct musb *allocate_instance(struct device *dev,
struct musb_hdrc_config *config, void __iomem *mbase)
{
struct musb *musb;
struct musb_hw_ep *ep;
int epnum;
- struct usb_hcd *hcd;
+ int ret;
- hcd = usb_create_hcd(&musb_hc_driver, dev, dev_name(dev));
- if (!hcd)
+ musb = devm_kzalloc(dev, sizeof(*musb), GFP_KERNEL);
+ if (!musb)
return NULL;
- /* usbcore sets dev->driver_data to hcd, and sometimes uses that... */
- musb = hcd_to_musb(hcd);
INIT_LIST_HEAD(&musb->control);
INIT_LIST_HEAD(&musb->in_bulk);
INIT_LIST_HEAD(&musb->out_bulk);
- hcd->uses_new_polling = 1;
- hcd->has_tt = 1;
-
musb->vbuserr_retry = VBUSERR_RETRY_COUNT;
musb->a_wait_bcon = OTG_TIME_A_WAIT_BCON;
- dev_set_drvdata(dev, musb);
musb->mregs = mbase;
musb->ctrl_base = mbase;
musb->nIrq = -ENODEV;
@@ -1816,7 +1814,16 @@ allocate_instance(struct device *dev,
musb->controller = dev;
+ ret = musb_host_alloc(musb);
+ if (ret < 0)
+ goto err_free;
+
+ dev_set_drvdata(dev, musb);
+
return musb;
+
+err_free:
+ return NULL;
}
static void musb_free(struct musb *musb)
@@ -1835,30 +1842,39 @@ static void musb_free(struct musb *musb)
disable_irq_wake(musb->nIrq);
free_irq(musb->nIrq, musb);
}
- if (is_dma_capable() && musb->dma_controller) {
- struct dma_controller *c = musb->dma_controller;
- (void) c->stop(c);
- dma_controller_destroy(c);
- }
+ 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);
- kfree(musb);
+ 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.
*
- * @pDevice: the controller (already clocked, etc)
- * @nIrq: irq
- * @mregs: virtual address of controller registers,
+ * @dev: the controller (already clocked, etc)
+ * @nIrq: IRQ number
+ * @ctrl: virtual address of controller registers,
* not yet corrected for platform-specific offsets
*/
-static int __init
+static int
musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
{
int status;
struct musb *musb;
- struct musb_hdrc_platform_data *plat = dev->platform_data;
+ struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
/* The driver might handle more features than the board; OK.
* Fail when the board needs a feature that's not enabled.
@@ -1881,15 +1897,16 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
pm_runtime_enable(musb->controller);
spin_lock_init(&musb->lock);
- musb->board_mode = plat->mode;
musb->board_set_power = plat->set_power;
musb->min_power = plat->min_power;
musb->ops = plat->platform_ops;
+ musb->port_mode = plat->mode;
/* The musb_platform_init() call:
- * - adjusts musb->mregs and musb->isr if needed,
- * - may initialize an integrated tranceiver
- * - initializes musb->xceiv, usually by otg_get_transceiver()
+ * - adjusts musb->mregs
+ * - sets the musb->isr
+ * - may initialize an integrated transceiver
+ * - initializes musb->xceiv, usually by otg_get_phy()
* - stops powering VBUS
*
* There are various transceiver configurations. Blackfin,
@@ -1897,39 +1914,41 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
* external/discrete ones in various flavors (twl4030 family,
* isp1504, non-OTG, etc) mostly hooking up through ULPI.
*/
- musb->isr = generic_interrupt;
status = musb_platform_init(musb);
if (status < 0)
goto fail1;
if (!musb->isr) {
status = -ENODEV;
- goto fail3;
+ goto fail2;
}
if (!musb->xceiv->io_ops) {
+ musb->xceiv->io_dev = musb->controller;
musb->xceiv->io_priv = musb->mregs;
musb->xceiv->io_ops = &musb_ulpi_access;
}
-#ifndef CONFIG_MUSB_PIO_ONLY
- if (use_dma && dev->dma_mask) {
- struct dma_controller *c;
+ pm_runtime_get_sync(musb->controller);
- c = dma_controller_create(musb, musb->mregs);
- musb->dma_controller = c;
- if (c)
- (void) c->start(c);
+ 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;
+ }
}
-#endif
- /* ideally this would be abstracted in platform setup */
- if (!is_dma_capable() || !musb->dma_controller)
- dev->dma_mask = NULL;
/* 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
@@ -1939,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);
@@ -1949,7 +1965,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
goto fail3;
}
musb->nIrq = nIrq;
-/* FIXME this handles wakeup irqs wrong */
+ /* FIXME this handles wakeup irqs wrong */
if (enable_irq_wake(nIrq) == 0) {
musb->irq_wake = 1;
device_init_wakeup(dev, 1);
@@ -1957,59 +1973,50 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
musb->irq_wake = 0;
}
- /* host side needs more setup */
- if (is_host_enabled(musb)) {
- struct usb_hcd *hcd = musb_to_hcd(musb);
-
- otg_set_host(musb->xceiv, &hcd->self);
-
- if (is_otg_enabled(musb))
- hcd->self.otg_port = 1;
- musb->xceiv->host = &hcd->self;
- hcd->power_budget = 2 * (plat->power ? : 250);
-
- /* program PHY to use external vBus if required */
- if (plat->extvbus) {
- u8 busctl = musb_read_ulpi_buscontrol(musb->mregs);
- busctl |= MUSB_ULPI_USE_EXTVBUS;
- musb_write_ulpi_buscontrol(musb->mregs, busctl);
- }
+ /* program PHY to use external vBus if required */
+ if (plat->extvbus) {
+ u8 busctl = musb_read_ulpi_buscontrol(musb->mregs);
+ busctl |= MUSB_ULPI_USE_EXTVBUS;
+ musb_write_ulpi_buscontrol(musb->mregs, busctl);
}
- /* For the host-only role, we can activate right away.
- * (We expect the ID pin to be forcibly grounded!!)
- * Otherwise, wait till the gadget driver hooks up.
- */
- if (!is_otg_enabled(musb) && is_host_enabled(musb)) {
- struct usb_hcd *hcd = musb_to_hcd(musb);
-
+ if (musb->xceiv->otg->default_a) {
MUSB_HST_MODE(musb);
- musb->xceiv->default_a = 1;
musb->xceiv->state = OTG_STATE_A_IDLE;
-
- status = usb_add_hcd(musb_to_hcd(musb), -1, 0);
-
- hcd->self.uses_pio_for_control = 1;
- dev_dbg(musb->controller, "%s mode, status %d, devctl %02x %c\n",
- "HOST", status,
- musb_readb(musb->mregs, MUSB_DEVCTL),
- (musb_readb(musb->mregs, MUSB_DEVCTL)
- & MUSB_DEVCTL_BDEVICE
- ? 'B' : 'A'));
-
- } else /* peripheral is enabled */ {
+ } else {
MUSB_DEV_MODE(musb);
- musb->xceiv->default_a = 0;
musb->xceiv->state = OTG_STATE_B_IDLE;
+ }
+ 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);
-
- dev_dbg(musb->controller, "%s mode, status %d, dev%02x\n",
- is_otg_enabled(musb) ? "OTG" : "PERIPHERAL",
- status,
- musb_readb(musb->mregs, MUSB_DEVCTL));
-
+ 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);
+ break;
}
+
if (status < 0)
goto fail3;
@@ -2017,23 +2024,11 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
if (status < 0)
goto fail4;
-#ifdef CONFIG_SYSFS
status = sysfs_create_group(&musb->controller->kobj, &musb_attr_group);
if (status)
goto fail5;
-#endif
- dev_info(dev, "USB %s mode controller at %p using %s, IRQ %d\n",
- ({char *s;
- switch (musb->board_mode) {
- case MUSB_HOST: s = "Host"; break;
- case MUSB_PERIPHERAL: s = "Peripheral"; break;
- default: s = "OTG"; break;
- }; s; }),
- ctrl,
- (is_dma_capable() && musb->dma_controller)
- ? "DMA" : "PIO",
- musb->nIrq);
+ pm_runtime_put(musb->controller);
return 0;
@@ -2041,17 +2036,26 @@ fail5:
musb_exit_debugfs(musb);
fail4:
- if (!is_otg_enabled(musb) && is_host_enabled(musb))
- usb_remove_hcd(musb_to_hcd(musb));
- else
- musb_gadget_cleanup(musb);
+ 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:
if (musb->irq_wake)
device_init_wakeup(dev, 0);
musb_platform_exit(musb);
fail1:
+ pm_runtime_disable(musb->controller);
dev_err(musb->controller,
"musb_init_controller failed with status %d\n", status);
@@ -2068,16 +2072,10 @@ fail0:
/* all implementations (PCI bridge to FPGA, VLYNQ, etc) should just
* bridge to a platform device; this driver then suffices.
*/
-
-#ifndef CONFIG_MUSB_PIO_ONLY
-static u64 *orig_dma_mask;
-#endif
-
-static int __init musb_probe(struct platform_device *pdev)
+static int musb_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
int irq = platform_get_irq_byname(pdev, "mc");
- int status;
struct resource *iomem;
void __iomem *base;
@@ -2085,44 +2083,35 @@ static int __init musb_probe(struct platform_device *pdev)
if (!iomem || irq <= 0)
return -ENODEV;
- base = ioremap(iomem->start, resource_size(iomem));
- if (!base) {
- dev_err(dev, "ioremap failed\n");
- return -ENOMEM;
- }
-
-#ifndef CONFIG_MUSB_PIO_ONLY
- /* clobbered by use_dma=n */
- orig_dma_mask = dev->dma_mask;
-#endif
- status = musb_init_controller(dev, irq, base);
- if (status < 0)
- iounmap(base);
+ base = devm_ioremap_resource(dev, iomem);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
- return status;
+ return musb_init_controller(dev, irq, base);
}
-static int __exit musb_remove(struct platform_device *pdev)
+static int musb_remove(struct platform_device *pdev)
{
- struct musb *musb = dev_to_musb(&pdev->dev);
- void __iomem *ctrl_base = musb->ctrl_base;
+ struct device *dev = &pdev->dev;
+ struct musb *musb = dev_to_musb(dev);
/* this gets called on rmmod.
* - Host mode: host may still be active
* - Peripheral mode: peripheral is deactivated (or never-activated)
* - OTG mode: both roles are deactivated (or never-activated)
*/
- pm_runtime_get_sync(musb->controller);
musb_exit_debugfs(musb);
musb_shutdown(pdev);
- pm_runtime_put(musb->controller);
+ 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);
- iounmap(ctrl_base);
- device_init_wakeup(&pdev->dev, 0);
-#ifndef CONFIG_MUSB_PIO_ONLY
- pdev->dev.dma_mask = orig_dma_mask;
-#endif
+ device_init_wakeup(dev, 0);
return 0;
}
@@ -2134,14 +2123,10 @@ static void musb_save_context(struct musb *musb)
void __iomem *musb_base = musb->mregs;
void __iomem *epio;
- if (is_host_enabled(musb)) {
- musb->context.frame = musb_readw(musb_base, MUSB_FRAME);
- musb->context.testmode = musb_readb(musb_base, MUSB_TESTMODE);
- musb->context.busctl = musb_read_ulpi_buscontrol(musb->mregs);
- }
+ musb->context.frame = musb_readw(musb_base, MUSB_FRAME);
+ musb->context.testmode = musb_readb(musb_base, MUSB_TESTMODE);
+ musb->context.busctl = musb_read_ulpi_buscontrol(musb->mregs);
musb->context.power = musb_readb(musb_base, MUSB_POWER);
- musb->context.intrtxe = musb_readw(musb_base, MUSB_INTRTXE);
- musb->context.intrrxe = musb_readw(musb_base, MUSB_INTRRXE);
musb->context.intrusbe = musb_readb(musb_base, MUSB_INTRUSBE);
musb->context.index = musb_readb(musb_base, MUSB_INDEX);
musb->context.devctl = musb_readb(musb_base, MUSB_DEVCTL);
@@ -2177,30 +2162,29 @@ static void musb_save_context(struct musb *musb)
musb->context.index_regs[i].rxfifosz =
musb_read_rxfifosz(musb_base);
}
- if (is_host_enabled(musb)) {
- musb->context.index_regs[i].txtype =
- musb_readb(epio, MUSB_TXTYPE);
- musb->context.index_regs[i].txinterval =
- musb_readb(epio, MUSB_TXINTERVAL);
- musb->context.index_regs[i].rxtype =
- musb_readb(epio, MUSB_RXTYPE);
- musb->context.index_regs[i].rxinterval =
- musb_readb(epio, MUSB_RXINTERVAL);
-
- musb->context.index_regs[i].txfunaddr =
- musb_read_txfunaddr(musb_base, i);
- musb->context.index_regs[i].txhubaddr =
- musb_read_txhubaddr(musb_base, i);
- musb->context.index_regs[i].txhubport =
- musb_read_txhubport(musb_base, i);
-
- musb->context.index_regs[i].rxfunaddr =
- musb_read_rxfunaddr(musb_base, i);
- musb->context.index_regs[i].rxhubaddr =
- musb_read_rxhubaddr(musb_base, i);
- musb->context.index_regs[i].rxhubport =
- musb_read_rxhubport(musb_base, i);
- }
+
+ musb->context.index_regs[i].txtype =
+ musb_readb(epio, MUSB_TXTYPE);
+ musb->context.index_regs[i].txinterval =
+ musb_readb(epio, MUSB_TXINTERVAL);
+ musb->context.index_regs[i].rxtype =
+ musb_readb(epio, MUSB_RXTYPE);
+ musb->context.index_regs[i].rxinterval =
+ musb_readb(epio, MUSB_RXINTERVAL);
+
+ musb->context.index_regs[i].txfunaddr =
+ musb_read_txfunaddr(musb_base, i);
+ musb->context.index_regs[i].txhubaddr =
+ musb_read_txhubaddr(musb_base, i);
+ musb->context.index_regs[i].txhubport =
+ musb_read_txhubport(musb_base, i);
+
+ musb->context.index_regs[i].rxfunaddr =
+ musb_read_rxfunaddr(musb_base, i);
+ musb->context.index_regs[i].rxhubaddr =
+ musb_read_rxhubaddr(musb_base, i);
+ musb->context.index_regs[i].rxhubport =
+ musb_read_rxhubport(musb_base, i);
}
}
@@ -2210,15 +2194,21 @@ static void musb_restore_context(struct musb *musb)
void __iomem *musb_base = musb->mregs;
void __iomem *ep_target_regs;
void __iomem *epio;
+ u8 power;
- if (is_host_enabled(musb)) {
- 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);
- musb_writew(musb_base, MUSB_INTRTXE, musb->context.intrtxe);
- musb_writew(musb_base, MUSB_INTRRXE, musb->context.intrrxe);
+ 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);
+
+ /* 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);
musb_writeb(musb_base, MUSB_DEVCTL, musb->context.devctl);
@@ -2254,33 +2244,31 @@ static void musb_restore_context(struct musb *musb)
musb->context.index_regs[i].rxfifoadd);
}
- if (is_host_enabled(musb)) {
- musb_writeb(epio, MUSB_TXTYPE,
+ musb_writeb(epio, MUSB_TXTYPE,
musb->context.index_regs[i].txtype);
- musb_writeb(epio, MUSB_TXINTERVAL,
+ musb_writeb(epio, MUSB_TXINTERVAL,
musb->context.index_regs[i].txinterval);
- musb_writeb(epio, MUSB_RXTYPE,
+ musb_writeb(epio, MUSB_RXTYPE,
musb->context.index_regs[i].rxtype);
- musb_writeb(epio, MUSB_RXINTERVAL,
+ musb_writeb(epio, MUSB_RXINTERVAL,
- musb->context.index_regs[i].rxinterval);
- musb_write_txfunaddr(musb_base, i,
+ musb->context.index_regs[i].rxinterval);
+ musb_write_txfunaddr(musb_base, i,
musb->context.index_regs[i].txfunaddr);
- musb_write_txhubaddr(musb_base, i,
+ musb_write_txhubaddr(musb_base, i,
musb->context.index_regs[i].txhubaddr);
- musb_write_txhubport(musb_base, i,
+ musb_write_txhubport(musb_base, i,
musb->context.index_regs[i].txhubport);
- ep_target_regs =
- musb_read_target_reg_base(i, musb_base);
+ ep_target_regs =
+ musb_read_target_reg_base(i, musb_base);
- musb_write_rxfunaddr(ep_target_regs,
+ musb_write_rxfunaddr(ep_target_regs,
musb->context.index_regs[i].rxfunaddr);
- musb_write_rxhubaddr(ep_target_regs,
+ musb_write_rxhubaddr(ep_target_regs,
musb->context.index_regs[i].rxhubaddr);
- musb_write_rxhubport(ep_target_regs,
+ musb_write_rxhubport(ep_target_regs,
musb->context.index_regs[i].rxhubport);
- }
}
musb_writeb(musb_base, MUSB_INDEX, musb->context.index);
}
@@ -2302,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;
}
@@ -2364,32 +2364,9 @@ static struct platform_driver musb_driver = {
.owner = THIS_MODULE,
.pm = MUSB_DEV_PM_OPS,
},
- .remove = __exit_p(musb_remove),
+ .probe = musb_probe,
+ .remove = musb_remove,
.shutdown = musb_shutdown,
};
-/*-------------------------------------------------------------------------*/
-
-static int __init musb_init(void)
-{
- if (usb_disabled())
- return 0;
-
- pr_info("%s: version " MUSB_VERSION ", "
- "?dma?"
- ", "
- "otg (peripheral+host)",
- musb_driver_name);
- return platform_driver_probe(&musb_driver, musb_probe);
-}
-
-/* make us init after usbcore and i2c (transceivers, regulators, etc)
- * and before usb gadget and host-side drivers start to register
- */
-fs_initcall(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 3d28fb8a2dc..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;
@@ -71,49 +73,17 @@ struct musb_ep;
#include <linux/usb/hcd.h>
#include "musb_host.h"
-#define is_peripheral_enabled(musb) ((musb)->board_mode != MUSB_HOST)
-#define is_host_enabled(musb) ((musb)->board_mode != MUSB_PERIPHERAL)
-#define is_otg_enabled(musb) ((musb)->board_mode == MUSB_OTG)
-
/* NOTE: otg and peripheral-only state machines start at B_IDLE.
* OTG or host-only go to A_IDLE when ID is sensed.
*/
#define is_peripheral_active(m) (!(m)->is_host)
#define is_host_active(m) ((m)->is_host)
-#ifndef CONFIG_HAVE_CLK
-/* Dummy stub for clk framework */
-#define clk_get(dev, id) NULL
-#define clk_put(clock) do {} while (0)
-#define clk_enable(clock) do {} while (0)
-#define clk_disable(clock) do {} while (0)
-#endif
-
-#ifdef CONFIG_PROC_FS
-#include <linux/fs.h>
-#define MUSB_CONFIG_PROC_FS
-#endif
-
-/****************************** PERIPHERAL ROLE *****************************/
-
-#define is_peripheral_capable() (1)
-
-extern irqreturn_t musb_g_ep0_irq(struct musb *);
-extern void musb_g_tx(struct musb *, u8);
-extern void musb_g_rx(struct musb *, u8);
-extern void musb_g_reset(struct musb *);
-extern void musb_g_suspend(struct musb *);
-extern void musb_g_resume(struct musb *);
-extern void musb_g_wakeup(struct musb *);
-extern void musb_g_disconnect(struct musb *);
-
-/****************************** HOST ROLE ***********************************/
-
-#define is_host_capable() (1)
-
-extern irqreturn_t musb_h_ep0_irq(struct musb *);
-extern void musb_host_tx(struct musb *, u8);
-extern void musb_host_rx(struct musb *, u8);
+enum {
+ MUSB_PORT_MODE_HOST = 1,
+ MUSB_PORT_MODE_GADGET,
+ MUSB_PORT_MODE_DUAL_ROLE,
+};
/****************************** CONSTANTS ********************************/
@@ -222,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);
@@ -304,7 +275,6 @@ struct musb_csr_regs {
struct musb_context_registers {
u8 power;
- u16 intrtxe, intrrxe;
u8 intrusbe;
u16 frame;
u8 index, testmode;
@@ -327,9 +297,13 @@ struct musb {
irqreturn_t (*isr)(int, void *);
struct work_struct irq_work;
- struct work_struct otg_notifier_work;
+ struct work_struct recover_work;
+ struct delayed_work deassert_reset_work;
+ struct delayed_work finish_resume_work;
u16 hwvers;
+ u16 intrrxe;
+ u16 intrtxe;
/* this hub status bit is reserved by USB 2.0 and not seen by usbcore */
#define MUSB_PORT_STAT_RESUME (1 << 31)
@@ -365,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 */
@@ -372,8 +347,8 @@ struct musb {
u16 int_rx;
u16 int_tx;
- struct otg_transceiver *xceiv;
- u8 xceiv_event;
+ struct usb_phy *xceiv;
+ struct phy *phy;
int nIrq;
unsigned irq_wake:1;
@@ -386,11 +361,11 @@ struct musb {
u16 epmask;
u8 nr_endpoints;
- u8 board_mode; /* enum musb_mode */
int (*board_set_power)(int state);
u8 min_power; /* vbus for periph, in mA/2 */
+ int port_mode; /* MUSB_PORT_MODE_* */
bool is_host;
int a_wait_bcon; /* VBUS timeout in msecs */
@@ -400,7 +375,6 @@ struct musb {
unsigned is_active:1;
unsigned is_multipoint:1;
- unsigned ignore_disconnect:1; /* during bus resets */
unsigned hb_iso_rx:1; /* high bandwidth iso rx? */
unsigned hb_iso_tx:1; /* high bandwidth iso tx? */
@@ -437,6 +411,7 @@ struct musb {
enum musb_g_ep0_state ep0_state;
struct usb_gadget g; /* the gadget */
struct usb_gadget_driver *gadget_driver; /* its driver */
+ struct usb_hcd *hcd; /* the usb hcd */
/*
* FIXME: Remove this flag.
@@ -449,12 +424,13 @@ struct musb {
* We added this flag to forcefully disable double
* buffering until we get it working.
*/
- unsigned double_buffer_not_ok:1 __deprecated;
+ unsigned double_buffer_not_ok:1;
struct musb_hdrc_config *config;
-#ifdef MUSB_CONFIG_PROC_FS
- struct proc_dir_entry *proc_entry;
+ int xceiv_old_state;
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *debugfs_root;
#endif
};
@@ -494,7 +470,7 @@ static inline void musb_configure_ep0(struct musb *musb)
static inline int musb_read_fifosize(struct musb *musb,
struct musb_hw_ep *hw_ep, u8 epnum)
{
- void *mbase = musb->mregs;
+ void __iomem *mbase = musb->mregs;
u8 reg = 0;
/* read from core using indexed model */
@@ -534,8 +510,8 @@ static inline void musb_configure_ep0(struct musb *musb)
extern const char musb_driver_name[];
-extern void musb_start(struct musb *musb);
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);
@@ -579,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
new file mode 100644
index 00000000000..5341bb223b7
--- /dev/null
+++ b/drivers/usb/musb/musb_cppi41.c
@@ -0,0 +1,744 @@
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/sizes.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+
+#include "musb_core.h"
+
+#define RNDIS_REG(x) (0x80 + ((x - 1) * 4))
+
+#define EP_MODE_AUTOREG_NONE 0
+#define EP_MODE_AUTOREG_ALL_NEOP 1
+#define EP_MODE_AUTOREG_ALWAYS 3
+
+#define EP_MODE_DMA_TRANSPARENT 0
+#define EP_MODE_DMA_RNDIS 1
+#define EP_MODE_DMA_GEN_RNDIS 3
+
+#define USB_CTRL_TX_MODE 0x70
+#define USB_CTRL_RX_MODE 0x74
+#define USB_CTRL_AUTOREQ 0xd0
+#define USB_TDOWN 0xd8
+
+struct cppi41_dma_channel {
+ struct dma_channel channel;
+ struct cppi41_dma_controller *controller;
+ struct musb_hw_ep *hw_ep;
+ struct dma_chan *dc;
+ dma_cookie_t cookie;
+ u8 port_num;
+ u8 is_tx;
+ u8 is_allocated;
+ u8 usb_toggle;
+
+ dma_addr_t buf_addr;
+ u32 total_len;
+ u32 prog_len;
+ u32 transferred;
+ u32 packet_sz;
+ struct list_head tx_check;
+ struct work_struct dma_completion;
+};
+
+#define MUSB_DMA_NUM_CHANNELS 15
+
+struct cppi41_dma_controller {
+ struct dma_controller 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;
+};
+
+static void save_rx_toggle(struct cppi41_dma_channel *cppi41_channel)
+{
+ u16 csr;
+ u8 toggle;
+
+ if (cppi41_channel->is_tx)
+ return;
+ if (!is_host_active(cppi41_channel->controller->musb))
+ return;
+
+ csr = musb_readw(cppi41_channel->hw_ep->regs, MUSB_RXCSR);
+ toggle = csr & MUSB_RXCSR_H_DATATOGGLE ? 1 : 0;
+
+ cppi41_channel->usb_toggle = toggle;
+}
+
+static void update_rx_toggle(struct cppi41_dma_channel *cppi41_channel)
+{
+ u16 csr;
+ u8 toggle;
+
+ if (cppi41_channel->is_tx)
+ return;
+ if (!is_host_active(cppi41_channel->controller->musb))
+ return;
+
+ csr = musb_readw(cppi41_channel->hw_ep->regs, MUSB_RXCSR);
+ toggle = csr & MUSB_RXCSR_H_DATATOGGLE ? 1 : 0;
+
+ /*
+ * AM335x Advisory 1.0.13: Due to internal synchronisation error the
+ * data toggle may reset from DATA1 to DATA0 during receiving data from
+ * more than one endpoint.
+ */
+ if (!toggle && toggle == cppi41_channel->usb_toggle) {
+ csr |= MUSB_RXCSR_H_DATATOGGLE | MUSB_RXCSR_H_WR_DATATOGGLE;
+ musb_writew(cppi41_channel->hw_ep->regs, MUSB_RXCSR, csr);
+ dev_dbg(cppi41_channel->controller->musb->controller,
+ "Restoring DATA1 toggle.\n");
+ }
+
+ cppi41_channel->usb_toggle = toggle;
+}
+
+static bool musb_is_tx_fifo_empty(struct musb_hw_ep *hw_ep)
+{
+ u8 epnum = hw_ep->epnum;
+ struct musb *musb = hw_ep->musb;
+ void __iomem *epio = musb->endpoints[epnum].regs;
+ u16 csr;
+
+ csr = musb_readw(epio, MUSB_TXCSR);
+ if (csr & MUSB_TXCSR_TXPKTRDY)
+ return false;
+ return true;
+}
+
+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;
+}
+
+static void cppi41_dma_callback(void *private_data);
+
+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->prog_len ||
+ (cppi41_channel->channel.status == MUSB_DMA_STATUS_FREE)) {
+
+ /* done, complete */
+ cppi41_channel->channel.actual_len =
+ cppi41_channel->transferred;
+ cppi41_channel->channel.status = MUSB_DMA_STATUS_FREE;
+ musb_dma_completion(musb, hw_ep->epnum, cppi41_channel->is_tx);
+ } else {
+ /* next iteration, reload */
+ struct dma_chan *dc = cppi41_channel->dc;
+ struct dma_async_tx_descriptor *dma_desc;
+ enum dma_transfer_direction direction;
+ u16 csr;
+ u32 remain_bytes;
+ void __iomem *epio = cppi41_channel->hw_ep->regs;
+
+ cppi41_channel->buf_addr += cppi41_channel->packet_sz;
+
+ remain_bytes = cppi41_channel->total_len;
+ remain_bytes -= cppi41_channel->transferred;
+ remain_bytes = min(remain_bytes, cppi41_channel->packet_sz);
+ cppi41_channel->prog_len = remain_bytes;
+
+ direction = cppi41_channel->is_tx ? DMA_MEM_TO_DEV
+ : DMA_DEV_TO_MEM;
+ dma_desc = dmaengine_prep_slave_single(dc,
+ cppi41_channel->buf_addr,
+ remain_bytes,
+ direction,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (WARN_ON(!dma_desc))
+ return;
+
+ dma_desc->callback = cppi41_dma_callback;
+ dma_desc->callback_param = &cppi41_channel->channel;
+ cppi41_channel->cookie = dma_desc->tx_submit(dma_desc);
+ dma_async_issue_pending(dc);
+
+ if (!cppi41_channel->is_tx) {
+ csr = musb_readw(epio, MUSB_RXCSR);
+ csr |= MUSB_RXCSR_H_REQPKT;
+ 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);
+}
+
+static u32 update_ep_mode(unsigned ep, unsigned mode, u32 old)
+{
+ unsigned shift;
+
+ shift = (ep - 1) * 2;
+ old &= ~(3 << shift);
+ old |= mode << shift;
+ return old;
+}
+
+static void cppi41_set_dma_mode(struct cppi41_dma_channel *cppi41_channel,
+ unsigned mode)
+{
+ struct cppi41_dma_controller *controller = cppi41_channel->controller;
+ u32 port;
+ u32 new_mode;
+ u32 old_mode;
+
+ if (cppi41_channel->is_tx)
+ old_mode = controller->tx_mode;
+ else
+ old_mode = controller->rx_mode;
+ port = cppi41_channel->port_num;
+ new_mode = update_ep_mode(port, mode, old_mode);
+
+ if (new_mode == old_mode)
+ return;
+ if (cppi41_channel->is_tx) {
+ controller->tx_mode = new_mode;
+ musb_writel(controller->musb->ctrl_base, USB_CTRL_TX_MODE,
+ new_mode);
+ } else {
+ controller->rx_mode = new_mode;
+ musb_writel(controller->musb->ctrl_base, USB_CTRL_RX_MODE,
+ new_mode);
+ }
+}
+
+static void cppi41_set_autoreq_mode(struct cppi41_dma_channel *cppi41_channel,
+ unsigned mode)
+{
+ struct cppi41_dma_controller *controller = cppi41_channel->controller;
+ u32 port;
+ u32 new_mode;
+ u32 old_mode;
+
+ old_mode = controller->auto_req;
+ port = cppi41_channel->port_num;
+ new_mode = update_ep_mode(port, mode, old_mode);
+
+ if (new_mode == old_mode)
+ return;
+ controller->auto_req = new_mode;
+ musb_writel(controller->musb->ctrl_base, USB_CTRL_AUTOREQ, new_mode);
+}
+
+static bool cppi41_configure_channel(struct dma_channel *channel,
+ u16 packet_sz, u8 mode,
+ dma_addr_t dma_addr, u32 len)
+{
+ struct cppi41_dma_channel *cppi41_channel = channel->private_data;
+ struct dma_chan *dc = cppi41_channel->dc;
+ struct dma_async_tx_descriptor *dma_desc;
+ enum dma_transfer_direction direction;
+ struct musb *musb = cppi41_channel->controller->musb;
+ unsigned use_gen_rndis = 0;
+
+ dev_dbg(musb->controller,
+ "configure ep%d/%x packet_sz=%d, mode=%d, dma_addr=0x%llx, len=%d is_tx=%d\n",
+ cppi41_channel->port_num, RNDIS_REG(cppi41_channel->port_num),
+ packet_sz, mode, (unsigned long long) dma_addr,
+ len, cppi41_channel->is_tx);
+
+ cppi41_channel->buf_addr = dma_addr;
+ cppi41_channel->total_len = len;
+ cppi41_channel->transferred = 0;
+ cppi41_channel->packet_sz = packet_sz;
+
+ /*
+ * Due to AM335x' Advisory 1.0.13 we are not allowed to transfer more
+ * than max packet size at a time.
+ */
+ if (cppi41_channel->is_tx)
+ use_gen_rndis = 1;
+
+ if (use_gen_rndis) {
+ /* RNDIS mode */
+ if (len > packet_sz) {
+ musb_writel(musb->ctrl_base,
+ RNDIS_REG(cppi41_channel->port_num), len);
+ /* gen rndis */
+ cppi41_set_dma_mode(cppi41_channel,
+ EP_MODE_DMA_GEN_RNDIS);
+
+ /* auto req */
+ cppi41_set_autoreq_mode(cppi41_channel,
+ EP_MODE_AUTOREG_ALL_NEOP);
+ } else {
+ musb_writel(musb->ctrl_base,
+ RNDIS_REG(cppi41_channel->port_num), 0);
+ cppi41_set_dma_mode(cppi41_channel,
+ EP_MODE_DMA_TRANSPARENT);
+ cppi41_set_autoreq_mode(cppi41_channel,
+ EP_MODE_AUTOREG_NONE);
+ }
+ } else {
+ /* fallback mode */
+ cppi41_set_dma_mode(cppi41_channel, EP_MODE_DMA_TRANSPARENT);
+ cppi41_set_autoreq_mode(cppi41_channel, EP_MODE_AUTOREG_NONE);
+ len = min_t(u32, packet_sz, len);
+ }
+ cppi41_channel->prog_len = len;
+ direction = cppi41_channel->is_tx ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
+ dma_desc = dmaengine_prep_slave_single(dc, dma_addr, len, direction,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+ if (!dma_desc)
+ return false;
+
+ dma_desc->callback = cppi41_dma_callback;
+ dma_desc->callback_param = channel;
+ cppi41_channel->cookie = dma_desc->tx_submit(dma_desc);
+
+ save_rx_toggle(cppi41_channel);
+ dma_async_issue_pending(dc);
+ return true;
+}
+
+static struct dma_channel *cppi41_dma_channel_allocate(struct dma_controller *c,
+ struct musb_hw_ep *hw_ep, u8 is_tx)
+{
+ struct cppi41_dma_controller *controller = container_of(c,
+ struct cppi41_dma_controller, controller);
+ struct cppi41_dma_channel *cppi41_channel = NULL;
+ u8 ch_num = hw_ep->epnum - 1;
+
+ if (ch_num >= MUSB_DMA_NUM_CHANNELS)
+ return NULL;
+
+ if (is_tx)
+ cppi41_channel = &controller->tx_channel[ch_num];
+ else
+ cppi41_channel = &controller->rx_channel[ch_num];
+
+ if (!cppi41_channel->dc)
+ return NULL;
+
+ if (cppi41_channel->is_allocated)
+ return NULL;
+
+ cppi41_channel->hw_ep = hw_ep;
+ cppi41_channel->is_allocated = 1;
+
+ return &cppi41_channel->channel;
+}
+
+static void cppi41_dma_channel_release(struct dma_channel *channel)
+{
+ struct cppi41_dma_channel *cppi41_channel = channel->private_data;
+
+ if (cppi41_channel->is_allocated) {
+ cppi41_channel->is_allocated = 0;
+ channel->status = MUSB_DMA_STATUS_FREE;
+ channel->actual_len = 0;
+ }
+}
+
+static int cppi41_dma_channel_program(struct dma_channel *channel,
+ u16 packet_sz, u8 mode,
+ 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;
+
+ return ret;
+}
+
+static int cppi41_is_compatible(struct dma_channel *channel, u16 maxpacket,
+ void *buf, u32 length)
+{
+ struct cppi41_dma_channel *cppi41_channel = channel->private_data;
+ struct cppi41_dma_controller *controller = cppi41_channel->controller;
+ struct musb *musb = controller->musb;
+
+ if (is_host_active(musb)) {
+ 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 */
+ return 0;
+}
+
+static int cppi41_dma_channel_abort(struct dma_channel *channel)
+{
+ struct cppi41_dma_channel *cppi41_channel = channel->private_data;
+ struct cppi41_dma_controller *controller = cppi41_channel->controller;
+ struct musb *musb = controller->musb;
+ void __iomem *epio = cppi41_channel->hw_ep->regs;
+ int tdbit;
+ int ret;
+ unsigned is_tx;
+ u16 csr;
+
+ is_tx = cppi41_channel->is_tx;
+ dev_dbg(musb->controller, "abort channel=%d, is_tx=%d\n",
+ cppi41_channel->port_num, is_tx);
+
+ 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;
+ musb_writew(epio, MUSB_TXCSR, csr);
+ } else {
+ csr = musb_readw(epio, MUSB_RXCSR);
+ csr &= ~(MUSB_RXCSR_H_REQPKT | MUSB_RXCSR_DMAENAB);
+ musb_writew(epio, MUSB_RXCSR, csr);
+
+ csr = musb_readw(epio, MUSB_RXCSR);
+ if (csr & MUSB_RXCSR_RXPKTRDY) {
+ csr |= MUSB_RXCSR_FLUSHFIFO;
+ musb_writew(epio, MUSB_RXCSR, csr);
+ musb_writew(epio, MUSB_RXCSR, csr);
+ }
+ }
+
+ tdbit = 1 << cppi41_channel->port_num;
+ if (is_tx)
+ tdbit <<= 16;
+
+ do {
+ musb_writel(musb->ctrl_base, USB_TDOWN, tdbit);
+ ret = dmaengine_terminate_all(cppi41_channel->dc);
+ } while (ret == -EAGAIN);
+
+ musb_writel(musb->ctrl_base, USB_TDOWN, tdbit);
+
+ if (is_tx) {
+ csr = musb_readw(epio, MUSB_TXCSR);
+ if (csr & MUSB_TXCSR_TXPKTRDY) {
+ csr |= MUSB_TXCSR_FLUSHFIFO;
+ musb_writew(epio, MUSB_TXCSR, csr);
+ }
+ }
+
+ cppi41_channel->channel.status = MUSB_DMA_STATUS_FREE;
+ return 0;
+}
+
+static void cppi41_release_all_dma_chans(struct cppi41_dma_controller *ctrl)
+{
+ struct dma_chan *dc;
+ int i;
+
+ for (i = 0; i < MUSB_DMA_NUM_CHANNELS; i++) {
+ dc = ctrl->tx_channel[i].dc;
+ if (dc)
+ dma_release_channel(dc);
+ dc = ctrl->rx_channel[i].dc;
+ if (dc)
+ dma_release_channel(dc);
+ }
+}
+
+static void cppi41_dma_controller_stop(struct cppi41_dma_controller *controller)
+{
+ cppi41_release_all_dma_chans(controller);
+}
+
+static int cppi41_dma_controller_start(struct cppi41_dma_controller *controller)
+{
+ struct musb *musb = controller->musb;
+ struct device *dev = musb->controller;
+ struct device_node *np = dev->of_node;
+ struct cppi41_dma_channel *cppi41_channel;
+ int count;
+ int i;
+ int ret;
+
+ count = of_property_count_strings(np, "dma-names");
+ if (count < 0)
+ return count;
+
+ for (i = 0; i < count; i++) {
+ struct dma_chan *dc;
+ struct dma_channel *musb_dma;
+ const char *str;
+ unsigned is_tx;
+ unsigned int port;
+
+ ret = of_property_read_string_index(np, "dma-names", i, &str);
+ if (ret)
+ goto err;
+ if (!strncmp(str, "tx", 2))
+ is_tx = 1;
+ else if (!strncmp(str, "rx", 2))
+ is_tx = 0;
+ else {
+ dev_err(dev, "Wrong dmatype %s\n", str);
+ goto err;
+ }
+ ret = kstrtouint(str + 2, 0, &port);
+ if (ret)
+ goto err;
+
+ ret = -EINVAL;
+ if (port > MUSB_DMA_NUM_CHANNELS || !port)
+ goto err;
+ if (is_tx)
+ cppi41_channel = &controller->tx_channel[port - 1];
+ else
+ cppi41_channel = &controller->rx_channel[port - 1];
+
+ 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;
+ musb_dma->status = MUSB_DMA_STATUS_FREE;
+ musb_dma->max_len = SZ_4M;
+
+ dc = dma_request_slave_channel(dev, str);
+ if (!dc) {
+ dev_err(dev, "Failed to request %s.\n", str);
+ ret = -EPROBE_DEFER;
+ goto err;
+ }
+ cppi41_channel->dc = dc;
+ }
+ return 0;
+err:
+ cppi41_release_all_dma_chans(controller);
+ return ret;
+}
+
+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);
+}
+
+struct dma_controller *dma_controller_create(struct musb *musb,
+ void __iomem *base)
+{
+ struct cppi41_dma_controller *controller;
+ int ret = 0;
+
+ if (!musb->controller->of_node) {
+ dev_err(musb->controller, "Need DT for the DMA engine.\n");
+ return NULL;
+ }
+
+ controller = kzalloc(sizeof(*controller), GFP_KERNEL);
+ 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;
+ controller->controller.channel_release = cppi41_dma_channel_release;
+ controller->controller.channel_program = cppi41_dma_channel_program;
+ controller->controller.channel_abort = cppi41_dma_channel_abort;
+ controller->controller.is_compatible = cppi41_is_compatible;
+
+ ret = cppi41_dma_controller_start(controller);
+ if (ret)
+ goto plat_get_fail;
+ return &controller->controller;
+
+plat_get_fail:
+ kfree(controller);
+kzalloc_fail:
+ if (ret == -EPROBE_DEFER)
+ return ERR_PTR(ret);
+ return NULL;
+}
diff --git a/drivers/usb/musb/musb_debugfs.c b/drivers/usb/musb/musb_debugfs.c
index 13d9af9bf92..4c216790e86 100644
--- a/drivers/usb/musb/musb_debugfs.c
+++ b/drivers/usb/musb/musb_debugfs.c
@@ -103,8 +103,6 @@ static const struct musb_register_map musb_regmap[] = {
{ } /* Terminating Entry */
};
-static struct dentry *musb_debugfs_root;
-
static int musb_regdump_show(struct seq_file *s, void *unused)
{
struct musb *musb = s->private;
@@ -235,33 +233,33 @@ static const struct file_operations musb_test_mode_fops = {
.release = single_release,
};
-int __init musb_init_debugfs(struct musb *musb)
+int musb_init_debugfs(struct musb *musb)
{
struct dentry *root;
struct dentry *file;
int ret;
- root = debugfs_create_dir("musb", NULL);
- if (IS_ERR(root)) {
- ret = PTR_ERR(root);
+ root = debugfs_create_dir(dev_name(musb->controller), NULL);
+ if (!root) {
+ ret = -ENOMEM;
goto err0;
}
file = debugfs_create_file("regdump", S_IRUGO, root, musb,
&musb_regdump_fops);
- if (IS_ERR(file)) {
- ret = PTR_ERR(file);
+ if (!file) {
+ ret = -ENOMEM;
goto err1;
}
file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR,
root, musb, &musb_test_mode_fops);
- if (IS_ERR(file)) {
- ret = PTR_ERR(file);
+ if (!file) {
+ ret = -ENOMEM;
goto err1;
}
- musb_debugfs_root = root;
+ musb->debugfs_root = root;
return 0;
@@ -274,5 +272,5 @@ err0:
void /* __init_or_exit */ musb_exit_debugfs(struct musb *musb)
{
- debugfs_remove_recursive(musb_debugfs_root);
+ debugfs_remove_recursive(musb->debugfs_root);
}
diff --git a/drivers/usb/musb/musb_dma.h b/drivers/usb/musb/musb_dma.h
index 3a97c4e2d4f..1345a4ff041 100644
--- a/drivers/usb/musb/musb_dma.h
+++ b/drivers/usb/musb/musb_dma.h
@@ -62,13 +62,13 @@ struct musb_hw_ep;
#define DMA_ADDR_INVALID (~(dma_addr_t)0)
-#ifndef CONFIG_MUSB_PIO_ONLY
-#define is_dma_capable() (1)
-#else
+#ifdef CONFIG_MUSB_PIO_ONLY
#define is_dma_capable() (0)
+#else
+#define is_dma_capable() (1)
#endif
-#ifdef CONFIG_USB_TI_CPPI_DMA
+#if defined(CONFIG_USB_TI_CPPI_DMA) || defined(CONFIG_USB_TI_CPPI41_DMA)
#define is_cppi_enabled() 1
#else
#define is_cppi_enabled() 0
@@ -159,8 +159,6 @@ dma_channel_status(struct dma_channel *c)
* Controllers manage dma channels.
*/
struct dma_controller {
- int (*start)(struct dma_controller *);
- int (*stop)(struct dma_controller *);
struct dma_channel *(*channel_alloc)(struct dma_controller *,
struct musb_hw_ep *, u8 is_tx);
void (*channel_release)(struct dma_channel *);
@@ -177,10 +175,20 @@ struct dma_controller {
/* called after channel_program(), may indicate a fault */
extern void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit);
+#ifdef CONFIG_MUSB_PIO_ONLY
+static inline struct dma_controller *dma_controller_create(struct musb *m,
+ void __iomem *io)
+{
+ return NULL;
+}
+
+static inline void dma_controller_destroy(struct dma_controller *d) { }
-extern struct dma_controller *__init
-dma_controller_create(struct musb *, void __iomem *);
+#else
+
+extern struct dma_controller *dma_controller_create(struct musb *, void __iomem *);
extern void dma_controller_destroy(struct dma_controller *);
+#endif
#endif /* __MUSB_DMA_H__ */
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c
new file mode 100644
index 00000000000..09529f94e72
--- /dev/null
+++ b/drivers/usb/musb/musb_dsps.c
@@ -0,0 +1,830 @@
+/*
+ * Texas Instruments DSPS platforms "glue layer"
+ *
+ * Copyright (C) 2012, by Texas Instruments
+ *
+ * Based on the am35x "glue layer" code.
+ *
+ * This file is part of the Inventra Controller Driver for Linux.
+ *
+ * The Inventra Controller Driver for Linux is free software; you
+ * can redistribute it and/or modify it under the terms of the GNU
+ * General Public License version 2 as published by the Free Software
+ * Foundation.
+ *
+ * The Inventra Controller Driver for Linux is distributed in
+ * the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with The Inventra Controller Driver for Linux ; if not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place,
+ * Suite 330, Boston, MA 02111-1307 USA
+ *
+ * musb_dsps.c will be a common file for all the TI DSPS platforms
+ * such as dm64x, dm36x, dm35x, da8x, am35x and ti81x.
+ * For now only ti81x is using this and in future davinci.c, am35x.c
+ * da8xx.c would be merged to this file after testing.
+ */
+
+#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_generic.h>
+#include <linux/platform_data/usb-omap.h>
+#include <linux/sizes.h>
+
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#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[];
+
+/**
+ * avoid using musb_readx()/musb_writex() as glue layer should not be
+ * dependent on musb core layer symbols.
+ */
+static inline u8 dsps_readb(const void __iomem *addr, unsigned offset)
+ { return __raw_readb(addr + offset); }
+
+static inline u32 dsps_readl(const void __iomem *addr, unsigned offset)
+ { return __raw_readl(addr + offset); }
+
+static inline void dsps_writeb(void __iomem *addr, unsigned offset, u8 data)
+ { __raw_writeb(data, addr + offset); }
+
+static inline void dsps_writel(void __iomem *addr, unsigned offset, u32 data)
+ { __raw_writel(data, addr + offset); }
+
+/**
+ * DSPS musb wrapper register offset.
+ * FIXME: This should be expanded to have all the wrapper registers from TI DSPS
+ * musb ips.
+ */
+struct dsps_musb_wrapper {
+ u16 revision;
+ u16 control;
+ u16 status;
+ u16 epintr_set;
+ u16 epintr_clear;
+ u16 epintr_status;
+ u16 coreintr_set;
+ u16 coreintr_clear;
+ u16 coreintr_status;
+ u16 phy_utmi;
+ u16 mode;
+ u16 tx_mode;
+ u16 rx_mode;
+
+ /* bit positions for control */
+ unsigned reset:5;
+
+ /* bit positions for interrupt */
+ unsigned usb_shift:5;
+ u32 usb_mask;
+ u32 usb_bitmap;
+ unsigned drvvbus:5;
+
+ unsigned txep_shift:5;
+ u32 txep_mask;
+ u32 txep_bitmap;
+
+ unsigned rxep_shift:5;
+ u32 rxep_mask;
+ u32 rxep_bitmap;
+
+ /* bit positions for phy_utmi */
+ unsigned otg_disable:5;
+
+ /* 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.
+ */
+struct dsps_glue {
+ struct device *dev;
+ struct platform_device *musb; /* child musb pdev */
+ 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
+ */
+static void dsps_musb_enable(struct musb *musb)
+{
+ struct device *dev = musb->controller;
+ struct platform_device *pdev = to_platform_device(dev->parent);
+ struct dsps_glue *glue = platform_get_drvdata(pdev);
+ const struct dsps_musb_wrapper *wrp = glue->wrp;
+ void __iomem *reg_base = musb->ctrl_base;
+ u32 epmask, coremask;
+
+ /* Workaround: setup IRQs through both register sets. */
+ epmask = ((musb->epmask & wrp->txep_mask) << wrp->txep_shift) |
+ ((musb->epmask & wrp->rxep_mask) << wrp->rxep_shift);
+ coremask = (wrp->usb_bitmap & ~MUSB_INTR_SOF);
+
+ dsps_writel(reg_base, wrp->epintr_set, epmask);
+ dsps_writel(reg_base, wrp->coreintr_set, coremask);
+ /* 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);
+}
+
+/**
+ * dsps_musb_disable - disable HDRC and flush interrupts
+ */
+static void dsps_musb_disable(struct musb *musb)
+{
+ struct device *dev = musb->controller;
+ struct platform_device *pdev = to_platform_device(dev->parent);
+ struct dsps_glue *glue = platform_get_drvdata(pdev);
+ const struct dsps_musb_wrapper *wrp = glue->wrp;
+ void __iomem *reg_base = musb->ctrl_base;
+
+ dsps_writel(reg_base, wrp->coreintr_clear, wrp->usb_bitmap);
+ dsps_writel(reg_base, wrp->epintr_clear,
+ wrp->txep_bitmap | wrp->rxep_bitmap);
+ dsps_writeb(musb->mregs, MUSB_DEVCTL, 0);
+}
+
+static void otg_timer(unsigned long _musb)
+{
+ struct musb *musb = (void *)_musb;
+ void __iomem *mregs = musb->mregs;
+ struct device *dev = musb->controller;
+ struct dsps_glue *glue = dev_get_drvdata(dev->parent);
+ 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
+ * status change events (from the transceiver) otherwise.
+ */
+ devctl = dsps_readb(mregs, MUSB_DEVCTL);
+ dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl,
+ usb_otg_state_string(musb->xceiv->state));
+
+ spin_lock_irqsave(&musb->lock, flags);
+ switch (musb->xceiv->state) {
+ case OTG_STATE_A_WAIT_BCON:
+ dsps_writeb(musb->mregs, MUSB_DEVCTL, 0);
+ skip_session = 1;
+ /* fall */
+
+ 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);
+ } else {
+ 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;
+ default:
+ break;
+ }
+ spin_unlock_irqrestore(&musb->lock, flags);
+}
+
+static irqreturn_t dsps_interrupt(int irq, void *hci)
+{
+ struct musb *musb = hci;
+ void __iomem *reg_base = musb->ctrl_base;
+ struct device *dev = musb->controller;
+ struct dsps_glue *glue = dev_get_drvdata(dev->parent);
+ const struct dsps_musb_wrapper *wrp = glue->wrp;
+ unsigned long flags;
+ irqreturn_t ret = IRQ_NONE;
+ u32 epintr, usbintr;
+
+ spin_lock_irqsave(&musb->lock, flags);
+
+ /* Get endpoint interrupts */
+ epintr = dsps_readl(reg_base, wrp->epintr_status);
+ musb->int_rx = (epintr & wrp->rxep_bitmap) >> wrp->rxep_shift;
+ musb->int_tx = (epintr & wrp->txep_bitmap) >> wrp->txep_shift;
+
+ if (epintr)
+ dsps_writel(reg_base, wrp->epintr_status, epintr);
+
+ /* Get usb core interrupts */
+ usbintr = dsps_readl(reg_base, wrp->coreintr_status);
+ if (!usbintr && !epintr)
+ goto out;
+
+ musb->int_usb = (usbintr & wrp->usb_bitmap) >> wrp->usb_shift;
+ if (usbintr)
+ dsps_writel(reg_base, wrp->coreintr_status, usbintr);
+
+ dev_dbg(musb->controller, "usbintr (%x) epintr(%x)\n",
+ usbintr, epintr);
+ /*
+ * DRVVBUS IRQs are the only proxy we have (a very poor one!) for
+ * DSPS IP's missing ID change IRQ. We need an ID change IRQ to
+ * switch appropriately between halves of the OTG state machine.
+ * Managing DEVCTL.SESSION per Mentor docs requires that we know its
+ * 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) {
+ 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;
+ u8 devctl = dsps_readb(mregs, MUSB_DEVCTL);
+ int err;
+
+ err = musb->int_usb & MUSB_INTR_VBUSERROR;
+ if (err) {
+ /*
+ * The Mentor core doesn't debounce VBUS as needed
+ * to cope with device connect current spikes. This
+ * means it's not uncommon for bus-powered devices
+ * to get VBUS errors during enumeration.
+ *
+ * This is a workaround, but newer RTL from Mentor
+ * seems to allow a better one: "re"-starting sessions
+ * without waiting for VBUS to stop registering in
+ * devctl.
+ */
+ musb->int_usb &= ~MUSB_INTR_VBUSERROR;
+ musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
+ mod_timer(&glue->timer,
+ jiffies + wrp->poll_seconds * HZ);
+ WARNING("VBUS error workaround (delay coming)\n");
+ } else if (drvvbus) {
+ MUSB_HST_MODE(musb);
+ musb->xceiv->otg->default_a = 1;
+ musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+ del_timer(&glue->timer);
+ } else {
+ musb->is_active = 0;
+ MUSB_DEV_MODE(musb);
+ musb->xceiv->otg->default_a = 0;
+ musb->xceiv->state = OTG_STATE_B_IDLE;
+ }
+
+ /* NOTE: this must complete power-on within 100 ms. */
+ dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n",
+ drvvbus ? "on" : "off",
+ usb_otg_state_string(musb->xceiv->state),
+ err ? " ERROR" : "",
+ devctl);
+ ret = IRQ_HANDLED;
+ }
+
+ if (musb->int_tx || musb->int_rx || musb->int_usb)
+ ret |= musb_interrupt(musb);
+
+ /* 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);
+
+ 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;
+ struct dsps_glue *glue = dev_get_drvdata(dev->parent);
+ struct platform_device *parent = to_platform_device(dev->parent);
+ const struct dsps_musb_wrapper *wrp = glue->wrp;
+ void __iomem *reg_base;
+ struct resource *r;
+ u32 rev, val;
+ int ret;
+
+ r = platform_get_resource_byname(parent, IORESOURCE_MEM, "control");
+ if (!r)
+ return -EINVAL;
+
+ reg_base = devm_ioremap_resource(dev, r);
+ if (IS_ERR(reg_base))
+ return PTR_ERR(reg_base);
+ musb->ctrl_base = reg_base;
+
+ /* NOP driver needs change if supporting dual instance */
+ musb->xceiv = devm_usb_get_phy_by_phandle(dev, "phys", 0);
+ if (IS_ERR(musb->xceiv))
+ return PTR_ERR(musb->xceiv);
+
+ /* Returns zero if e.g. not clocked */
+ rev = dsps_readl(reg_base, wrp->revision);
+ if (!rev)
+ return -ENODEV;
+
+ usb_phy_init(musb->xceiv);
+ setup_timer(&glue->timer, otg_timer, (unsigned long) musb);
+
+ /* Reset the musb */
+ dsps_writel(reg_base, wrp->control, (1 << wrp->reset));
+
+ musb->isr = dsps_interrupt;
+
+ /* reset the otgdisable bit, needed for host mode to work */
+ val = dsps_readl(reg_base, wrp->phy_utmi);
+ 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;
+}
+
+static int dsps_musb_exit(struct musb *musb)
+{
+ struct device *dev = musb->controller;
+ 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,
+
+ .enable = dsps_musb_enable,
+ .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);
+
+static int get_int_prop(struct device_node *dn, const char *s)
+{
+ int ret;
+ u32 val;
+
+ ret = of_property_read_u32(dn, s, &val);
+ if (ret)
+ return 0;
+ return val;
+}
+
+static int get_musb_port_mode(struct device *dev)
+{
+ enum usb_dr_mode mode;
+
+ mode = of_usb_get_dr_mode(dev->of_node);
+ switch (mode) {
+ case USB_DR_MODE_HOST:
+ return MUSB_PORT_MODE_HOST;
+
+ case USB_DR_MODE_PERIPHERAL:
+ return MUSB_PORT_MODE_GADGET;
+
+ case USB_DR_MODE_UNKNOWN:
+ case USB_DR_MODE_OTG:
+ default:
+ return MUSB_PORT_MODE_DUAL_ROLE;
+ }
+}
+
+static int dsps_create_musb_pdev(struct dsps_glue *glue,
+ struct platform_device *parent)
+{
+ struct musb_hdrc_platform_data pdata;
+ struct resource resources[2];
+ struct resource *res;
+ struct device *dev = &parent->dev;
+ struct musb_hdrc_config *config;
+ struct platform_device *musb;
+ struct device_node *dn = parent->dev.of_node;
+ int ret;
+
+ memset(resources, 0, sizeof(resources));
+ res = platform_get_resource_byname(parent, IORESOURCE_MEM, "mc");
+ if (!res) {
+ dev_err(dev, "failed to get memory.\n");
+ return -EINVAL;
+ }
+ resources[0] = *res;
+
+ res = platform_get_resource_byname(parent, IORESOURCE_IRQ, "mc");
+ if (!res) {
+ dev_err(dev, "failed to get irq.\n");
+ return -EINVAL;
+ }
+ resources[1] = *res;
+
+ /* allocate the child platform device */
+ musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO);
+ if (!musb) {
+ dev_err(dev, "failed to allocate musb device\n");
+ return -ENOMEM;
+ }
+
+ musb->dev.parent = dev;
+ musb->dev.dma_mask = &musb_dmamask;
+ musb->dev.coherent_dma_mask = musb_dmamask;
+ musb->dev.of_node = of_node_get(dn);
+
+ glue->musb = musb;
+
+ ret = platform_device_add_resources(musb, resources,
+ ARRAY_SIZE(resources));
+ if (ret) {
+ dev_err(dev, "failed to add resources\n");
+ goto err;
+ }
+
+ config = devm_kzalloc(&parent->dev, sizeof(*config), GFP_KERNEL);
+ if (!config) {
+ dev_err(dev, "failed to allocate musb hdrc config\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+ pdata.config = config;
+ pdata.platform_ops = &dsps_ops;
+
+ 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;
+ config->multipoint = of_property_read_bool(dn, "mentor,multipoint");
+
+ ret = platform_device_add_data(musb, &pdata, sizeof(pdata));
+ if (ret) {
+ dev_err(dev, "failed to add platform_data\n");
+ goto err;
+ }
+
+ ret = platform_device_add(musb);
+ if (ret) {
+ dev_err(dev, "failed to register musb device\n");
+ goto err;
+ }
+ return 0;
+
+err:
+ platform_device_put(musb);
+ return ret;
+}
+
+static int dsps_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+ const struct dsps_musb_wrapper *wrp;
+ 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");
+ return -EINVAL;
+ }
+ wrp = match->data;
+
+ /* allocate glue */
+ glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
+ if (!glue) {
+ dev_err(&pdev->dev, "unable to allocate glue memory\n");
+ return -ENOMEM;
+ }
+
+ glue->dev = &pdev->dev;
+ glue->wrp = wrp;
+
+ platform_set_drvdata(pdev, glue);
+ pm_runtime_enable(&pdev->dev);
+
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "pm_runtime_get_sync FAILED");
+ goto err2;
+ }
+
+ ret = dsps_create_musb_pdev(glue, pdev);
+ if (ret)
+ goto err3;
+
+ return 0;
+
+err3:
+ pm_runtime_put(&pdev->dev);
+err2:
+ pm_runtime_disable(&pdev->dev);
+ return ret;
+}
+
+static int dsps_remove(struct platform_device *pdev)
+{
+ struct dsps_glue *glue = platform_get_drvdata(pdev);
+
+ platform_device_unregister(glue->musb);
+
+ /* disable usbss clocks */
+ pm_runtime_put(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static const struct dsps_musb_wrapper am33xx_driver_data = {
+ .revision = 0x00,
+ .control = 0x14,
+ .status = 0x18,
+ .epintr_set = 0x38,
+ .epintr_clear = 0x40,
+ .epintr_status = 0x30,
+ .coreintr_set = 0x3c,
+ .coreintr_clear = 0x44,
+ .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),
+ .drvvbus = 8,
+ .txep_shift = 0,
+ .txep_mask = 0xffff,
+ .txep_bitmap = (0xffff << 0),
+ .rxep_shift = 16,
+ .rxep_mask = 0xfffe,
+ .rxep_bitmap = (0xfffe << 16),
+ .poll_seconds = 2,
+};
+
+static const struct of_device_id musb_dsps_of_match[] = {
+ { .compatible = "ti,musb-am33xx",
+ .data = (void *) &am33xx_driver_data, },
+ { },
+};
+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",
+ .pm = &dsps_pm_ops,
+ .of_match_table = musb_dsps_of_match,
+ },
+};
+
+MODULE_DESCRIPTION("TI DSPS MUSB Glue Layer");
+MODULE_AUTHOR("Ravi B <ravibabu@ti.com>");
+MODULE_AUTHOR("Ajay Kumar Gupta <ajay.gupta@ti.com>");
+MODULE_LICENSE("GPL v2");
+
+module_platform_driver(dsps_usbss_driver);
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index ac3d2eec20f..d4aa779339f 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -46,48 +46,6 @@
#include "musb_core.h"
-/* MUSB PERIPHERAL status 3-mar-2006:
- *
- * - EP0 seems solid. It passes both USBCV and usbtest control cases.
- * Minor glitches:
- *
- * + remote wakeup to Linux hosts work, but saw USBCV failures;
- * in one test run (operator error?)
- * + endpoint halt tests -- in both usbtest and usbcv -- seem
- * to break when dma is enabled ... is something wrongly
- * clearing SENDSTALL?
- *
- * - Mass storage behaved ok when last tested. Network traffic patterns
- * (with lots of short transfers etc) need retesting; they turn up the
- * worst cases of the DMA, since short packets are typical but are not
- * required.
- *
- * - TX/IN
- * + both pio and dma behave in with network and g_zero tests
- * + no cppi throughput issues other than no-hw-queueing
- * + failed with FLAT_REG (DaVinci)
- * + seems to behave with double buffering, PIO -and- CPPI
- * + with gadgetfs + AIO, requests got lost?
- *
- * - RX/OUT
- * + both pio and dma behave in with network and g_zero tests
- * + dma is slow in typical case (short_not_ok is clear)
- * + double buffering ok with PIO
- * + double buffering *FAILS* with CPPI, wrong data bytes sometimes
- * + request lossage observed with gadgetfs
- *
- * - ISO not tested ... might work, but only weakly isochronous
- *
- * - Gadget driver disabling of softconnect during bind() is ignored; so
- * drivers can't hold off host requests until userspace is ready.
- * (Workaround: they can turn it off later.)
- *
- * - PORTABILITY (assumes PIO works):
- * + DaVinci, basically works with cppi dma
- * + OMAP 2430, ditto with mentor dma
- * + TUSB 6010, platform-specific dma in the works
- */
-
/* ----------------------------------------------------------------------- */
#define is_buffer_mapped(req) (is_dma_capable() && \
@@ -118,13 +76,21 @@ static inline void map_dma_buffer(struct musb_request *request,
return;
if (request->request.dma == DMA_ADDR_INVALID) {
- request->request.dma = dma_map_single(
+ dma_addr_t dma_addr;
+ int ret;
+
+ dma_addr = dma_map_single(
musb->controller,
request->request.buf,
request->request.length,
request->tx
? DMA_TO_DEVICE
: DMA_FROM_DEVICE);
+ ret = dma_mapping_error(musb->controller, dma_addr);
+ if (ret)
+ return;
+
+ request->request.dma = dma_addr;
request->map_state = MUSB_MAPPED;
} else {
dma_sync_single_for_device(musb->controller,
@@ -141,7 +107,9 @@ static inline void map_dma_buffer(struct musb_request *request,
static inline void unmap_dma_buffer(struct musb_request *request,
struct musb *musb)
{
- if (!is_buffer_mapped(request))
+ struct musb_ep *musb_ep = request->ep;
+
+ if (!is_buffer_mapped(request) || !musb_ep->dma)
return;
if (request->request.dma == DMA_ADDR_INVALID) {
@@ -195,7 +163,10 @@ __acquires(ep->musb->lock)
ep->busy = 1;
spin_unlock(&musb->lock);
- unmap_dma_buffer(req, musb);
+
+ if (!dma_mapping_error(&musb->g.dev, request->dma))
+ unmap_dma_buffer(req, musb);
+
if (request->status == 0)
dev_dbg(musb->controller, "%s done request %p, %d/%d\n",
ep->end_point.name, request,
@@ -275,41 +246,6 @@ static inline int max_ep_writesize(struct musb *musb, struct musb_ep *ep)
return ep->packet_sz;
}
-
-#ifdef CONFIG_USB_INVENTRA_DMA
-
-/* Peripheral tx (IN) using Mentor DMA works as follows:
- Only mode 0 is used for transfers <= wPktSize,
- mode 1 is used for larger transfers,
-
- One of the following happens:
- - Host sends IN token which causes an endpoint interrupt
- -> TxAvail
- -> if DMA is currently busy, exit.
- -> if queue is non-empty, txstate().
-
- - Request is queued by the gadget driver.
- -> if queue was previously empty, txstate()
-
- txstate()
- -> start
- /\ -> setup DMA
- | (data is transferred to the FIFO, then sent out when
- | IN token(s) are recd from Host.
- | -> DMA interrupt on completion
- | calls TxAvail.
- | -> stop DMA, ~DMAENAB,
- | -> set TxPktRdy for last short pkt or zlp
- | -> Complete Request
- | -> Continue next request (call txstate)
- |___________________________________|
-
- * Non-Mentor DMA engines can of course work differently, such as by
- * upleveling from irq-per-packet to irq-per-buffer.
- */
-
-#endif
-
/*
* An endpoint is transmitting data. This can be called either from
* the IRQ routine or from ep.queue() to kickstart a request on an
@@ -328,6 +264,13 @@ static void txstate(struct musb *musb, struct musb_request *req)
musb_ep = req->ep;
+ /* Check if EP is disabled */
+ if (!musb_ep->desc) {
+ dev_dbg(musb->controller, "ep:%s disabled - ignore request\n",
+ musb_ep->end_point.name);
+ return;
+ }
+
/* we shouldn't get here while DMA is active ... but we do ... */
if (dma_channel_status(musb_ep->dma) == MUSB_DMA_STATUS_BUSY) {
dev_dbg(musb->controller, "dma pending...\n");
@@ -366,7 +309,7 @@ static void txstate(struct musb *musb, struct musb_request *req)
request_size = min_t(size_t, request->length - request->actual,
musb_ep->dma->max_len);
- use_dma = (request->dma != DMA_ADDR_INVALID);
+ use_dma = (request->dma != DMA_ADDR_INVALID && request_size);
/* MUSB_TXCSR_P_ISO is still set correctly */
@@ -401,7 +344,19 @@ static void txstate(struct musb *musb, struct musb_request *req)
csr |= (MUSB_TXCSR_DMAENAB
| MUSB_TXCSR_DMAMODE
| MUSB_TXCSR_MODE);
- if (!musb_ep->hb_mult)
+ /*
+ * Enable Autoset according to table
+ * below
+ * bulk_split hb_mult Autoset_Enable
+ * 0 0 Yes(Normal)
+ * 0 >0 No(High BW ISO)
+ * 1 0 Yes(HS bulk)
+ * 1 >0 Yes(FS bulk)
+ */
+ if (!musb_ep->hb_mult ||
+ (musb_ep->hb_mult &&
+ can_bulk_split(musb,
+ musb_ep->type)))
csr |= MUSB_TXCSR_AUTOSET;
}
csr &= ~MUSB_TXCSR_P_UNDERRUN;
@@ -410,47 +365,49 @@ static void txstate(struct musb *musb, struct musb_request *req)
}
}
-#elif defined(CONFIG_USB_TI_CPPI_DMA)
- /* program endpoint CSR first, then setup DMA */
- csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY);
- csr |= MUSB_TXCSR_DMAENAB | MUSB_TXCSR_DMAMODE |
- MUSB_TXCSR_MODE;
- musb_writew(epio, MUSB_TXCSR,
- (MUSB_TXCSR_P_WZC_BITS & ~MUSB_TXCSR_P_UNDERRUN)
- | csr);
-
- /* ensure writebuffer is empty */
- csr = musb_readw(epio, MUSB_TXCSR);
-
- /* NOTE host side sets DMAENAB later than this; both are
- * OK since the transfer dma glue (between CPPI and Mentor
- * fifos) just tells CPPI it could start. Data only moves
- * to the USB TX fifo when both fifos are ready.
- */
-
- /* "mode" is irrelevant here; handle terminating ZLPs like
- * PIO does, since the hardware RNDIS mode seems unreliable
- * except for the last-packet-is-already-short case.
- */
- use_dma = use_dma && c->channel_program(
- musb_ep->dma, musb_ep->packet_sz,
- 0,
- request->dma + request->actual,
- request_size);
- if (!use_dma) {
- c->channel_release(musb_ep->dma);
- musb_ep->dma = NULL;
- csr &= ~MUSB_TXCSR_DMAENAB;
- musb_writew(epio, MUSB_TXCSR, csr);
- /* invariant: prequest->buf is non-null */
- }
-#elif defined(CONFIG_USB_TUSB_OMAP_DMA)
- use_dma = use_dma && c->channel_program(
- musb_ep->dma, musb_ep->packet_sz,
- request->zero,
- request->dma + request->actual,
- request_size);
#endif
+ if (is_cppi_enabled()) {
+ /* program endpoint CSR first, then setup DMA */
+ csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY);
+ csr |= MUSB_TXCSR_DMAENAB | MUSB_TXCSR_DMAMODE |
+ MUSB_TXCSR_MODE;
+ musb_writew(epio, MUSB_TXCSR, (MUSB_TXCSR_P_WZC_BITS &
+ ~MUSB_TXCSR_P_UNDERRUN) | csr);
+
+ /* ensure writebuffer is empty */
+ csr = musb_readw(epio, MUSB_TXCSR);
+
+ /*
+ * NOTE host side sets DMAENAB later than this; both are
+ * OK since the transfer dma glue (between CPPI and
+ * Mentor fifos) just tells CPPI it could start. Data
+ * only moves to the USB TX fifo when both fifos are
+ * ready.
+ */
+ /*
+ * "mode" is irrelevant here; handle terminating ZLPs
+ * like PIO does, since the hardware RNDIS mode seems
+ * unreliable except for the
+ * last-packet-is-already-short case.
+ */
+ use_dma = use_dma && c->channel_program(
+ musb_ep->dma, musb_ep->packet_sz,
+ 0,
+ request->dma + request->actual,
+ request_size);
+ if (!use_dma) {
+ c->channel_release(musb_ep->dma);
+ musb_ep->dma = NULL;
+ csr &= ~MUSB_TXCSR_DMAENAB;
+ musb_writew(epio, MUSB_TXCSR, csr);
+ /* invariant: prequest->buf is non-null */
+ }
+ } else if (tusb_dma_omap())
+ use_dma = use_dma && c->channel_program(
+ musb_ep->dma, musb_ep->packet_sz,
+ request->zero,
+ request->dma + request->actual,
+ request_size);
}
#endif
@@ -574,6 +531,15 @@ void musb_g_tx(struct musb *musb, u8 epnum)
if (request->actual == request->length) {
musb_g_giveback(musb_ep, request, 0);
+ /*
+ * In the giveback function the MUSB lock is
+ * released and acquired after sometime. During
+ * this time period the INDEX register could get
+ * changed by the gadget_queue function especially
+ * on SMP systems. Reselect the INDEX to be sure
+ * we are reading/modifying the right registers
+ */
+ musb_ep_select(mbase, epnum);
req = musb_ep->desc ? next_request(musb_ep) : NULL;
if (!req) {
dev_dbg(musb->controller, "%s idle now\n",
@@ -588,37 +554,6 @@ void musb_g_tx(struct musb *musb, u8 epnum)
/* ------------------------------------------------------------ */
-#ifdef CONFIG_USB_INVENTRA_DMA
-
-/* Peripheral rx (OUT) using Mentor DMA works as follows:
- - Only mode 0 is used.
-
- - Request is queued by the gadget class driver.
- -> if queue was previously empty, rxstate()
-
- - Host sends OUT token which causes an endpoint interrupt
- /\ -> RxReady
- | -> if request queued, call rxstate
- | /\ -> setup DMA
- | | -> DMA interrupt on completion
- | | -> RxReady
- | | -> stop DMA
- | | -> ack the read
- | | -> if data recd = max expected
- | | by the request, or host
- | | sent a short packet,
- | | complete the request,
- | | and start the next one.
- | |_____________________________________|
- | else just wait for the host
- | to send the next OUT token.
- |__________________________________________________|
-
- * Non-Mentor DMA engines can of course work differently.
- */
-
-#endif
-
/*
* Context: controller locked, IRQs blocked, endpoint selected
*/
@@ -628,8 +563,8 @@ static void rxstate(struct musb *musb, struct musb_request *req)
struct usb_request *request = &req->request;
struct musb_ep *musb_ep;
void __iomem *epio = musb->endpoints[epnum].regs;
- unsigned fifo_count = 0;
- u16 len;
+ unsigned len = 0;
+ u16 fifo_count;
u16 csr = musb_readw(epio, MUSB_RXCSR);
struct musb_hw_ep *hw_ep = &musb->endpoints[epnum];
u8 use_mode_1;
@@ -639,7 +574,14 @@ static void rxstate(struct musb *musb, struct musb_request *req)
else
musb_ep = &hw_ep->ep_out;
- len = musb_ep->packet_sz;
+ fifo_count = musb_ep->packet_sz;
+
+ /* Check if EP is disabled */
+ if (!musb_ep->desc) {
+ dev_dbg(musb->controller, "ep:%s disabled - ignore request\n",
+ musb_ep->end_point.name);
+ return;
+ }
/* We shouldn't get here while DMA is active, but we do... */
if (dma_channel_status(musb_ep->dma) == MUSB_DMA_STATUS_BUSY) {
@@ -681,7 +623,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
}
if (csr & MUSB_RXCSR_RXPKTRDY) {
- len = musb_readw(epio, MUSB_RXCOUNT);
+ fifo_count = musb_readw(epio, MUSB_RXCOUNT);
/*
* Enable Mode 1 on RX transfers only when short_not_ok flag
@@ -689,7 +631,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
* file_storage and f_mass_storage drivers
*/
- if (request->short_not_ok && len == musb_ep->packet_sz)
+ if (request->short_not_ok && fifo_count == musb_ep->packet_sz)
use_mode_1 = 1;
else
use_mode_1 = 0;
@@ -700,6 +642,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
struct dma_controller *c;
struct dma_channel *channel;
int use_dma = 0;
+ unsigned int transfer_size;
c = musb->dma_controller;
channel = musb_ep->dma;
@@ -741,35 +684,31 @@ static void rxstate(struct musb *musb, struct musb_request *req)
csr | MUSB_RXCSR_DMAMODE);
musb_writew(epio, MUSB_RXCSR, csr);
+ transfer_size = min_t(unsigned int,
+ request->length -
+ request->actual,
+ channel->max_len);
+ musb_ep->dma->desired_mode = 1;
} else {
if (!musb_ep->hb_mult &&
musb_ep->hw_ep->rx_double_buffered)
csr |= MUSB_RXCSR_AUTOCLEAR;
csr |= MUSB_RXCSR_DMAENAB;
musb_writew(epio, MUSB_RXCSR, csr);
- }
- if (request->actual < request->length) {
- int transfer_size = 0;
- if (use_mode_1) {
- transfer_size = min(request->length - request->actual,
- channel->max_len);
- musb_ep->dma->desired_mode = 1;
- } else {
- transfer_size = min(request->length - request->actual,
- (unsigned)len);
- musb_ep->dma->desired_mode = 0;
- }
-
- use_dma = c->channel_program(
- channel,
- musb_ep->packet_sz,
- channel->desired_mode,
- request->dma
- + request->actual,
- transfer_size);
+ transfer_size = min(request->length - request->actual,
+ (unsigned)fifo_count);
+ musb_ep->dma->desired_mode = 0;
}
+ use_dma = c->channel_program(
+ channel,
+ musb_ep->packet_sz,
+ channel->desired_mode,
+ request->dma
+ + request->actual,
+ transfer_size);
+
if (use_dma)
return;
}
@@ -779,22 +718,24 @@ static void rxstate(struct musb *musb, struct musb_request *req)
struct dma_controller *c;
struct dma_channel *channel;
- int transfer_size = 0;
+ unsigned int transfer_size = 0;
c = musb->dma_controller;
channel = musb_ep->dma;
/* In case first packet is short */
- if (len < musb_ep->packet_sz)
- transfer_size = len;
+ if (fifo_count < musb_ep->packet_sz)
+ transfer_size = fifo_count;
else if (request->short_not_ok)
- transfer_size = min(request->length -
+ transfer_size = min_t(unsigned int,
+ request->length -
request->actual,
channel->max_len);
else
- transfer_size = min(request->length -
+ transfer_size = min_t(unsigned int,
+ request->length -
request->actual,
- (unsigned)len);
+ (unsigned)fifo_count);
csr &= ~MUSB_RXCSR_DMAMODE;
csr |= (MUSB_RXCSR_DMAENAB |
@@ -822,10 +763,10 @@ static void rxstate(struct musb *musb, struct musb_request *req)
}
#endif /* Mentor's DMA */
- fifo_count = request->length - request->actual;
+ len = request->length - request->actual;
dev_dbg(musb->controller, "%s OUT/RX pio fifo %d/%d, maxpacket %d\n",
musb_ep->end_point.name,
- len, fifo_count,
+ fifo_count, len,
musb_ep->packet_sz);
fifo_count = min_t(unsigned, len, fifo_count);
@@ -878,7 +819,8 @@ static void rxstate(struct musb *musb, struct musb_request *req)
}
/* reach the end or short packet detected */
- if (request->actual == request->length || len < musb_ep->packet_sz)
+ if (request->actual == request->length ||
+ fifo_count < musb_ep->packet_sz)
musb_g_giveback(musb_ep, request, 0);
}
@@ -983,6 +925,15 @@ void musb_g_rx(struct musb *musb, u8 epnum)
}
#endif
musb_g_giveback(musb_ep, request, 0);
+ /*
+ * In the giveback function the MUSB lock is
+ * released and acquired after sometime. During
+ * this time period the INDEX register could get
+ * changed by the gadget_queue function especially
+ * on SMP systems. Reselect the INDEX to be sure
+ * we are reading/modifying the right registers
+ */
+ musb_ep_select(mbase, epnum);
req = next_request(musb_ep);
if (!req)
@@ -1061,7 +1012,6 @@ static int musb_gadget_enable(struct usb_ep *ep,
*/
musb_ep_select(mbase, epnum);
if (usb_endpoint_dir_in(desc)) {
- u16 int_txe = musb_readw(mbase, MUSB_INTRTXE);
if (hw_ep->is_shared_fifo)
musb_ep->is_in = 1;
@@ -1073,8 +1023,8 @@ static int musb_gadget_enable(struct usb_ep *ep,
goto fail;
}
- int_txe |= (1 << epnum);
- musb_writew(mbase, MUSB_INTRTXE, int_txe);
+ musb->intrtxe |= (1 << epnum);
+ musb_writew(mbase, MUSB_INTRTXE, musb->intrtxe);
/* REVISIT if can_bulk_split(), use by updating "tmp";
* likewise high bandwidth periodic tx
@@ -1082,11 +1032,15 @@ static int musb_gadget_enable(struct usb_ep *ep,
/* Set TXMAXP with the FIFO size of the endpoint
* to disable double buffering mode.
*/
- if (musb->double_buffer_not_ok)
+ if (musb->double_buffer_not_ok) {
musb_writew(regs, MUSB_TXMAXP, hw_ep->max_packet_sz_tx);
- else
+ } else {
+ if (can_bulk_split(musb, musb_ep->type))
+ musb_ep->hb_mult = (hw_ep->max_packet_sz_tx /
+ musb_ep->packet_sz) - 1;
musb_writew(regs, MUSB_TXMAXP, musb_ep->packet_sz
| (musb_ep->hb_mult << 11));
+ }
csr = MUSB_TXCSR_MODE | MUSB_TXCSR_CLRDATATOG;
if (musb_readw(regs, MUSB_TXCSR)
@@ -1101,7 +1055,6 @@ static int musb_gadget_enable(struct usb_ep *ep,
musb_writew(regs, MUSB_TXCSR, csr);
} else {
- u16 int_rxe = musb_readw(mbase, MUSB_INTRRXE);
if (hw_ep->is_shared_fifo)
musb_ep->is_in = 0;
@@ -1113,8 +1066,8 @@ static int musb_gadget_enable(struct usb_ep *ep,
goto fail;
}
- int_rxe |= (1 << epnum);
- musb_writew(mbase, MUSB_INTRRXE, int_rxe);
+ musb->intrrxe |= (1 << epnum);
+ musb_writew(mbase, MUSB_INTRRXE, musb->intrrxe);
/* REVISIT if can_bulk_combine() use by updating "tmp"
* likewise high bandwidth periodic rx
@@ -1168,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);
@@ -1202,18 +1155,17 @@ static int musb_gadget_disable(struct usb_ep *ep)
/* zero the endpoint sizes */
if (musb_ep->is_in) {
- u16 int_txe = musb_readw(musb->mregs, MUSB_INTRTXE);
- int_txe &= ~(1 << epnum);
- musb_writew(musb->mregs, MUSB_INTRTXE, int_txe);
+ musb->intrtxe &= ~(1 << epnum);
+ musb_writew(musb->mregs, MUSB_INTRTXE, musb->intrtxe);
musb_writew(epio, MUSB_TXMAXP, 0);
} else {
- u16 int_rxe = musb_readw(musb->mregs, MUSB_INTRRXE);
- int_rxe &= ~(1 << epnum);
- musb_writew(musb->mregs, MUSB_INTRRXE, int_rxe);
+ musb->intrrxe &= ~(1 << epnum);
+ musb_writew(musb->mregs, MUSB_INTRRXE, musb->intrrxe);
musb_writew(epio, MUSB_RXMAXP, 0);
}
musb_ep->desc = NULL;
+ musb_ep->end_point.desc = NULL;
/* abort all pending DMA and requests */
nuke(musb_ep, -ESHUTDOWN);
@@ -1324,7 +1276,8 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,
dev_dbg(musb->controller, "req %p queued to %s while ep %s\n",
req, ep->name, "disabled");
status = -ESHUTDOWN;
- goto cleanup;
+ unmap_dma_buffer(request, musb);
+ goto unlock;
}
/* add request to the list */
@@ -1334,7 +1287,7 @@ static int musb_gadget_queue(struct usb_ep *ep, struct usb_request *req,
if (!musb_ep->busy && &request->list == musb_ep->req_list.next)
musb_ep_restart(musb, request);
-cleanup:
+unlock:
spin_unlock_irqrestore(&musb->lock, lockflags);
return status;
}
@@ -1524,7 +1477,7 @@ static void musb_gadget_fifo_flush(struct usb_ep *ep)
void __iomem *epio = musb->endpoints[epnum].regs;
void __iomem *mbase;
unsigned long flags;
- u16 csr, int_txe;
+ u16 csr;
mbase = musb->mregs;
@@ -1532,8 +1485,7 @@ static void musb_gadget_fifo_flush(struct usb_ep *ep)
musb_ep_select(mbase, (u8) epnum);
/* disable interrupts */
- int_txe = musb_readw(mbase, MUSB_INTRTXE);
- musb_writew(mbase, MUSB_INTRTXE, int_txe & ~(1 << epnum));
+ musb_writew(mbase, MUSB_INTRTXE, musb->intrtxe & ~(1 << epnum));
if (musb_ep->is_in) {
csr = musb_readw(epio, MUSB_TXCSR);
@@ -1557,7 +1509,7 @@ static void musb_gadget_fifo_flush(struct usb_ep *ep)
}
/* re-enable interrupt */
- musb_writew(mbase, MUSB_INTRTXE, int_txe);
+ musb_writew(mbase, MUSB_INTRTXE, musb->intrtxe);
spin_unlock_irqrestore(&musb->lock, flags);
}
@@ -1624,7 +1576,7 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget)
}
spin_unlock_irqrestore(&musb->lock, flags);
- otg_start_srp(musb->xceiv);
+ otg_start_srp(musb->xceiv->otg);
spin_lock_irqsave(&musb->lock, flags);
/* Block idling for at least 1s */
@@ -1635,7 +1587,7 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget)
goto done;
default:
dev_dbg(musb->controller, "Unhandled wake: %s\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
goto done;
}
@@ -1703,7 +1655,7 @@ static int musb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
if (!musb->xceiv->set_power)
return -EOPNOTSUPP;
- return otg_set_power(musb->xceiv, mA);
+ return usb_phy_set_power(musb->xceiv, mA);
}
static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on)
@@ -1755,14 +1707,7 @@ static const struct usb_gadget_ops musb_gadget_operations = {
* all peripheral ports are external...
*/
-static void musb_gadget_release(struct device *dev)
-{
- /* kref_put(WHAT) */
- dev_dbg(dev, "%s\n", __func__);
-}
-
-
-static void __init
+static void
init_peripheral_ep(struct musb *musb, struct musb_ep *ep, u8 epnum, int is_in)
{
struct musb_hw_ep *hw_ep = musb->endpoints + epnum;
@@ -1782,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);
}
@@ -1799,7 +1744,7 @@ init_peripheral_ep(struct musb *musb, struct musb_ep *ep, u8 epnum, int is_in)
* Initialize the endpoints exposed to peripheral drivers, with backlinks
* to the rest of the driver state.
*/
-static inline void __init musb_g_init_endpoints(struct musb *musb)
+static inline void musb_g_init_endpoints(struct musb *musb)
{
u8 epnum;
struct musb_hw_ep *hw_ep;
@@ -1832,7 +1777,7 @@ static inline void __init musb_g_init_endpoints(struct musb *musb)
/* called once during driver setup to initialize and link into
* the driver model; memory is zeroed.
*/
-int __init musb_gadget_setup(struct musb *musb)
+int musb_gadget_setup(struct musb *musb)
{
int status;
@@ -1845,26 +1790,23 @@ int __init 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 */
- dev_set_name(&musb->g.dev, "gadget");
- musb->g.dev.parent = musb->controller;
- musb->g.dev.dma_mask = musb->controller->dma_mask;
- musb->g.dev.release = musb_gadget_release;
musb->g.name = musb_driver_name;
-
- if (is_otg_enabled(musb))
- musb->g.is_otg = 1;
+#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);
musb->is_active = 0;
musb_platform_try_idle(musb, 0);
- status = device_register(&musb->g.dev);
- if (status != 0) {
- put_device(&musb->g.dev);
- return status;
- }
status = usb_add_gadget_udc(musb->controller, &musb->g);
if (status)
goto err;
@@ -1878,9 +1820,9 @@ err:
void musb_gadget_cleanup(struct musb *musb)
{
+ if (musb->port_mode == MUSB_PORT_MODE_HOST)
+ return;
usb_del_gadget_udc(&musb->g);
- if (musb->g.dev.parent)
- device_unregister(&musb->g.dev);
}
/*
@@ -1898,11 +1840,14 @@ static int musb_gadget_start(struct usb_gadget *g,
struct usb_gadget_driver *driver)
{
struct musb *musb = gadget_to_musb(g);
+ struct usb_otg *otg = musb->xceiv->otg;
unsigned long flags;
- int retval = -EINVAL;
+ int retval = 0;
- if (driver->max_speed < USB_SPEED_HIGH)
- goto err0;
+ if (driver->max_speed < USB_SPEED_HIGH) {
+ retval = -EINVAL;
+ goto err;
+ }
pm_runtime_get_sync(musb->controller);
@@ -1914,51 +1859,25 @@ static int musb_gadget_start(struct usb_gadget *g,
spin_lock_irqsave(&musb->lock, flags);
musb->is_active = 1;
- otg_set_peripheral(musb->xceiv, &musb->g);
+ otg_set_peripheral(otg, &musb->g);
musb->xceiv->state = OTG_STATE_B_IDLE;
-
- /*
- * FIXME this ignores the softconnect flag. Drivers are
- * allowed hold the peripheral inactive until for example
- * userspace hooks up printer hardware or DSP codecs, so
- * hosts only see fully functional devices.
- */
-
- if (!is_otg_enabled(musb))
- musb_start(musb);
-
spin_unlock_irqrestore(&musb->lock, flags);
- if (is_otg_enabled(musb)) {
- struct usb_hcd *hcd = musb_to_hcd(musb);
-
- dev_dbg(musb->controller, "OTG startup...\n");
-
- /* REVISIT: funcall to other code, which also
- * handles power budgeting ... this way also
- * ensures HdrcStart is indirectly called.
- */
- retval = usb_add_hcd(musb_to_hcd(musb), -1, 0);
- if (retval < 0) {
- dev_dbg(musb->controller, "add_hcd failed, %d\n", retval);
- goto err2;
- }
+ musb_start(musb);
- if ((musb->xceiv->last_event == USB_EVENT_ID)
- && musb->xceiv->set_vbus)
- otg_set_vbus(musb->xceiv, 1);
+ /* REVISIT: funcall to other code, which also
+ * handles power budgeting ... this way also
+ * ensures HdrcStart is indirectly called.
+ */
+ if (musb->xceiv->last_event == USB_EVENT_ID)
+ musb_platform_set_vbus(musb, 1);
- hcd->self.uses_pio_for_control = 1;
- }
if (musb->xceiv->last_event == USB_EVENT_NONE)
pm_runtime_put(musb->controller);
return 0;
-err2:
- if (!is_otg_enabled(musb))
- musb_stop(musb);
-err0:
+err:
return retval;
}
@@ -2028,24 +1947,21 @@ static int musb_gadget_stop(struct usb_gadget *g,
musb->xceiv->state = OTG_STATE_UNDEFINED;
stop_activity(musb, driver);
- otg_set_peripheral(musb->xceiv, NULL);
+ otg_set_peripheral(musb->xceiv->otg, NULL);
- dev_dbg(musb->controller, "unregistering driver %s\n", driver->function);
+ dev_dbg(musb->controller, "unregistering driver %s\n",
+ driver ? driver->function : "(removed)");
musb->is_active = 0;
+ musb->gadget_driver = NULL;
musb_platform_try_idle(musb, 0);
spin_unlock_irqrestore(&musb->lock, flags);
- if (is_otg_enabled(musb)) {
- usb_remove_hcd(musb_to_hcd(musb));
- /* FIXME we need to be able to register another
- * gadget driver here and have everything work;
- * that currently misbehaves.
- */
- }
-
- if (!is_otg_enabled(musb))
- musb_stop(musb);
+ /*
+ * FIXME we need to be able to register another
+ * gadget driver here and have everything work;
+ * that currently misbehaves.
+ */
pm_runtime_put(musb->controller);
@@ -2073,7 +1989,7 @@ void musb_g_resume(struct musb *musb)
break;
default:
WARNING("unhandled RESUME transition (%s)\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
}
@@ -2103,7 +2019,7 @@ void musb_g_suspend(struct musb *musb)
* A_PERIPHERAL may need care too
*/
WARNING("unhandled SUSPEND transition (%s)\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
}
@@ -2137,7 +2053,7 @@ void musb_g_disconnect(struct musb *musb)
switch (musb->xceiv->state) {
default:
dev_dbg(musb->controller, "Unhandled disconnect %s, setting a_idle\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
musb->xceiv->state = OTG_STATE_A_IDLE;
MUSB_HST_MODE(musb);
break;
@@ -2166,10 +2082,9 @@ __acquires(musb->lock)
u8 devctl = musb_readb(mbase, MUSB_DEVCTL);
u8 power;
- dev_dbg(musb->controller, "<== %s addr=%x driver '%s'\n",
+ dev_dbg(musb->controller, "<== %s driver '%s'\n",
(devctl & MUSB_DEVCTL_BDEVICE)
? "B-Device" : "A-Device",
- musb_readb(mbase, MUSB_FADDR),
musb->gadget_driver
? musb->gadget_driver->driver.name
: NULL
@@ -2204,16 +2119,22 @@ __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 if (is_otg_enabled(musb)) {
+ } else {
musb->xceiv->state = OTG_STATE_A_PERIPHERAL;
musb->g.is_a_peripheral = 1;
- } else
- WARN_ON(1);
+ }
/* start with default limits on VBUS power draw */
- (void) musb_gadget_vbus_draw(&musb->g,
- is_otg_enabled(musb) ? 8 : 100);
+ (void) musb_gadget_vbus_draw(&musb->g, 8);
}
diff --git a/drivers/usb/musb/musb_gadget.h b/drivers/usb/musb/musb_gadget.h
index 66b7c5e0fb4..0314dfc770c 100644
--- a/drivers/usb/musb/musb_gadget.h
+++ b/drivers/usb/musb/musb_gadget.h
@@ -37,6 +37,38 @@
#include <linux/list.h>
+#if IS_ENABLED(CONFIG_USB_MUSB_GADGET) || IS_ENABLED(CONFIG_USB_MUSB_DUAL_ROLE)
+extern irqreturn_t musb_g_ep0_irq(struct musb *);
+extern void musb_g_tx(struct musb *, u8);
+extern void musb_g_rx(struct musb *, u8);
+extern void musb_g_reset(struct musb *);
+extern void musb_g_suspend(struct musb *);
+extern void musb_g_resume(struct musb *);
+extern void musb_g_wakeup(struct musb *);
+extern void musb_g_disconnect(struct musb *);
+extern void musb_gadget_cleanup(struct musb *);
+extern int musb_gadget_setup(struct musb *);
+
+#else
+static inline irqreturn_t musb_g_ep0_irq(struct musb *musb)
+{
+ return 0;
+}
+
+static inline void musb_g_tx(struct musb *musb, u8 epnum) {}
+static inline void musb_g_rx(struct musb *musb, u8 epnum) {}
+static inline void musb_g_reset(struct musb *musb) {}
+static inline void musb_g_suspend(struct musb *musb) {}
+static inline void musb_g_resume(struct musb *musb) {}
+static inline void musb_g_wakeup(struct musb *musb) {}
+static inline void musb_g_disconnect(struct musb *musb) {}
+static inline void musb_gadget_cleanup(struct musb *musb) {}
+static inline int musb_gadget_setup(struct musb *musb)
+{
+ return 0;
+}
+#endif
+
enum buffer_map_state {
UN_MAPPED = 0,
PRE_MAPPED,
@@ -106,14 +138,8 @@ static inline struct musb_request *next_request(struct musb_ep *ep)
return container_of(queue->next, struct musb_request, list);
}
-extern void musb_g_tx(struct musb *musb, u8 epnum);
-extern void musb_g_rx(struct musb *musb, u8 epnum);
-
extern const struct usb_ep_ops musb_g_ep0_ops;
-extern int musb_gadget_setup(struct musb *);
-extern void musb_gadget_cleanup(struct musb *);
-
extern void musb_g_giveback(struct musb_ep *, struct usb_request *, int);
extern void musb_ep_restart(struct musb *, struct musb_request *);
diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c
index e40d7647caf..2af45a0c893 100644
--- a/drivers/usb/musb/musb_gadget_ep0.c
+++ b/drivers/usb/musb/musb_gadget_ep0.c
@@ -505,8 +505,10 @@ static void ep0_rxstate(struct musb *musb)
req->status = -EOVERFLOW;
count = len;
}
- musb_read_fifo(&musb->endpoints[0], count, buf);
- req->actual += count;
+ if (count > 0) {
+ musb_read_fifo(&musb->endpoints[0], count, buf);
+ req->actual += count;
+ }
csr = MUSB_CSR0_P_SVDRXPKTRDY;
if (count < 64 || req->actual == req->length) {
musb->ep0_state = MUSB_EP0_STAGE_STATUSIN;
@@ -673,10 +675,8 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)
csr = musb_readw(regs, MUSB_CSR0);
len = musb_readb(regs, MUSB_COUNT0);
- dev_dbg(musb->controller, "csr %04x, count %d, myaddr %d, ep0stage %s\n",
- csr, len,
- musb_readb(mbase, MUSB_FADDR),
- decode_ep0stage(musb->ep0_state));
+ dev_dbg(musb->controller, "csr %04x, count %d, ep0stage %s\n",
+ csr, len, decode_ep0stage(musb->ep0_state));
if (csr & MUSB_CSR0_P_DATAEND) {
/*
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index 79cb0af779f..eb06291a40c 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -39,14 +39,12 @@
#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>
#include "musb_core.h"
#include "musb_host.h"
-
/* MUSB HOST status 22-mar-2006
*
* - There's still lots of partial code duplication for fault paths, so
@@ -96,6 +94,11 @@
* of transfers between endpoints, or anything clever.
*/
+struct musb *hcd_to_musb(struct usb_hcd *hcd)
+{
+ return *(struct musb **) hcd->hcd_priv;
+}
+
static void musb_ep_program(struct musb *musb, u8 epnum,
struct urb *urb, int is_out,
@@ -249,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 */
@@ -269,8 +272,7 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
/* FIXME this doesn't implement that scheduling policy ...
* or handle framecounter wrapping
*/
- if ((urb->transfer_flags & URB_ISO_ASAP)
- || (frame >= urb->start_frame)) {
+ if (1) { /* Always assume URB_ISO_ASAP */
/* REVISIT the SOF irq handler shouldn't duplicate
* this code; and we don't init urb->start_frame...
*/
@@ -311,9 +313,9 @@ __acquires(musb->lock)
urb->actual_length, urb->transfer_buffer_length
);
- usb_hcd_unlink_urb_from_ep(musb_to_hcd(musb), urb);
+ usb_hcd_unlink_urb_from_ep(musb->hcd, urb);
spin_unlock(&musb->lock);
- usb_hcd_giveback_urb(musb_to_hcd(musb), urb, status);
+ usb_hcd_giveback_urb(musb->hcd, urb, status);
spin_lock(&musb->lock);
}
@@ -375,11 +377,21 @@ static void musb_advance_schedule(struct musb *musb, struct urb *urb,
*/
if (list_empty(&qh->hep->urb_list)) {
struct list_head *head;
+ struct dma_controller *dma = musb->dma_controller;
- if (is_in)
+ if (is_in) {
ep->rx_reinit = 1;
- else
+ if (ep->rx_channel) {
+ dma->channel_release(ep->rx_channel);
+ ep->rx_channel = NULL;
+ }
+ } else {
ep->tx_reinit = 1;
+ if (ep->tx_channel) {
+ dma->channel_release(ep->tx_channel);
+ ep->tx_channel = NULL;
+ }
+ }
/* Clobber old pointers to this qh */
musb_ep_set_qh(ep, is_in, NULL);
@@ -615,7 +627,7 @@ static bool musb_tx_dma_program(struct dma_controller *dma,
u16 csr;
u8 mode;
-#ifdef CONFIG_USB_INVENTRA_DMA
+#if defined(CONFIG_USB_INVENTRA_DMA) || defined(CONFIG_USB_UX500_DMA)
if (length > channel->max_len)
length = channel->max_len;
@@ -624,7 +636,17 @@ static bool musb_tx_dma_program(struct dma_controller *dma,
mode = 1;
csr |= MUSB_TXCSR_DMAMODE | MUSB_TXCSR_DMAENAB;
/* autoset shouldn't be set in high bandwidth */
- if (qh->hb_mult == 1)
+ /*
+ * Enable Autoset according to table
+ * below
+ * bulk_split hb_mult Autoset_Enable
+ * 0 1 Yes(Normal)
+ * 0 >1 No(High BW ISO)
+ * 1 1 Yes(HS bulk)
+ * 1 >1 Yes(FS bulk)
+ */
+ if (qh->hb_mult == 1 || (qh->hb_mult > 1 &&
+ can_bulk_split(hw_ep->musb, qh->type)))
csr |= MUSB_TXCSR_AUTOSET;
} else {
mode = 0;
@@ -683,6 +705,8 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
void __iomem *epio = hw_ep->regs;
struct musb_qh *qh = musb_ep_get_qh(hw_ep, !is_out);
u16 packet_sz = qh->maxpacket;
+ u8 use_dma = 1;
+ u16 csr;
dev_dbg(musb->controller, "%s hw%d urb %p spd%d dev%d ep%d%s "
"h_addr%02x h_port%02x bytes %d\n",
@@ -694,9 +718,17 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
musb_ep_select(mbase, epnum);
+ if (is_out && !len) {
+ use_dma = 0;
+ csr = musb_readw(epio, MUSB_TXCSR);
+ csr &= ~MUSB_TXCSR_DMAENAB;
+ musb_writew(epio, MUSB_TXCSR, csr);
+ hw_ep->tx_channel = NULL;
+ }
+
/* candidate for DMA? */
dma_controller = musb->dma_controller;
- if (is_dma_capable() && epnum && dma_controller) {
+ if (use_dma && is_dma_capable() && epnum && dma_controller) {
dma_channel = is_out ? hw_ep->tx_channel : hw_ep->rx_channel;
if (!dma_channel) {
dma_channel = dma_controller->channel_alloc(
@@ -720,13 +752,19 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
csr = musb_readw(epio, MUSB_TXCSR);
/* disable interrupt in case we flush */
- int_txe = musb_readw(mbase, MUSB_INTRTXE);
+ int_txe = musb->intrtxe;
musb_writew(mbase, MUSB_INTRTXE, int_txe & ~(1 << epnum));
/* general endpoint setup */
if (epnum) {
/* flush all old state, set default */
- musb_h_tx_flush_fifo(hw_ep);
+ /*
+ * We could be flushing valid
+ * packets in double buffering
+ * case
+ */
+ if (!hw_ep->tx_double_buffered)
+ musb_h_tx_flush_fifo(hw_ep);
/*
* We must not clear the DMAMODE bit before or in
@@ -743,11 +781,13 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
);
csr |= MUSB_TXCSR_MODE;
- if (usb_gettoggle(urb->dev, qh->epnum, 1))
- csr |= MUSB_TXCSR_H_WR_DATATOGGLE
- | MUSB_TXCSR_H_DATATOGGLE;
- else
- csr |= MUSB_TXCSR_CLRDATATOG;
+ if (!hw_ep->tx_double_buffered) {
+ if (usb_gettoggle(urb->dev, qh->epnum, 1))
+ csr |= MUSB_TXCSR_H_WR_DATATOGGLE
+ | MUSB_TXCSR_H_DATATOGGLE;
+ else
+ csr |= MUSB_TXCSR_CLRDATATOG;
+ }
musb_writew(epio, MUSB_TXCSR, csr);
/* REVISIT may need to clear FLUSHFIFO ... */
@@ -771,17 +811,19 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
/* protocol/endpoint/interval/NAKlimit */
if (epnum) {
musb_writeb(epio, MUSB_TXTYPE, qh->type_reg);
- if (musb->double_buffer_not_ok)
+ if (musb->double_buffer_not_ok) {
musb_writew(epio, MUSB_TXMAXP,
hw_ep->max_packet_sz_tx);
- else if (can_bulk_split(musb, qh->type))
+ } else if (can_bulk_split(musb, qh->type)) {
+ qh->hb_mult = hw_ep->max_packet_sz_tx
+ / packet_sz;
musb_writew(epio, MUSB_TXMAXP, packet_sz
- | ((hw_ep->max_packet_sz_tx /
- packet_sz) - 1) << 11);
- else
+ | ((qh->hb_mult) - 1) << 11);
+ } else {
musb_writew(epio, MUSB_TXMAXP,
qh->maxpacket |
((qh->hb_mult - 1) << 11));
+ }
musb_writeb(epio, MUSB_TXINTERVAL, qh->intv_reg);
} else {
musb_writeb(epio, MUSB_NAKLIMIT0, qh->intv_reg);
@@ -803,9 +845,28 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
if (load_count) {
/* PIO to load FIFO */
qh->segsize = load_count;
- musb_write_fifo(hw_ep, load_count, buf);
+ if (!buf) {
+ sg_miter_start(&qh->sg_miter, urb->sg, 1,
+ SG_MITER_ATOMIC
+ | SG_MITER_FROM_SG);
+ if (!sg_miter_next(&qh->sg_miter)) {
+ dev_err(musb->controller,
+ "error: sg"
+ "list empty\n");
+ sg_miter_stop(&qh->sg_miter);
+ goto finish;
+ }
+ buf = qh->sg_miter.addr + urb->sg->offset +
+ urb->actual_length;
+ load_count = min_t(u32, load_count,
+ qh->sg_miter.length);
+ musb_write_fifo(hw_ep, load_count, buf);
+ qh->sg_miter.consumed = load_count;
+ sg_miter_stop(&qh->sg_miter);
+ } else
+ musb_write_fifo(hw_ep, load_count, buf);
}
-
+finish:
/* re-enable interrupt */
musb_writew(mbase, MUSB_INTRTXE, int_txe);
@@ -872,6 +933,73 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
}
}
+/* Schedule next QH from musb->in_bulk/out_bulk and move the current qh to
+ * the end; avoids starvation for other endpoints.
+ */
+static void musb_bulk_nak_timeout(struct musb *musb, struct musb_hw_ep *ep,
+ int is_in)
+{
+ struct dma_channel *dma;
+ struct urb *urb;
+ void __iomem *mbase = musb->mregs;
+ void __iomem *epio = ep->regs;
+ struct musb_qh *cur_qh, *next_qh;
+ u16 rx_csr, tx_csr;
+
+ musb_ep_select(mbase, ep->epnum);
+ if (is_in) {
+ dma = is_dma_capable() ? ep->rx_channel : NULL;
+
+ /* clear nak timeout bit */
+ rx_csr = musb_readw(epio, MUSB_RXCSR);
+ rx_csr |= MUSB_RXCSR_H_WZC_BITS;
+ rx_csr &= ~MUSB_RXCSR_DATAERROR;
+ musb_writew(epio, MUSB_RXCSR, rx_csr);
+
+ cur_qh = first_qh(&musb->in_bulk);
+ } else {
+ dma = is_dma_capable() ? ep->tx_channel : NULL;
+
+ /* clear nak timeout bit */
+ tx_csr = musb_readw(epio, MUSB_TXCSR);
+ tx_csr |= MUSB_TXCSR_H_WZC_BITS;
+ tx_csr &= ~MUSB_TXCSR_H_NAKTIMEOUT;
+ musb_writew(epio, MUSB_TXCSR, tx_csr);
+
+ cur_qh = first_qh(&musb->out_bulk);
+ }
+ if (cur_qh) {
+ urb = next_urb(cur_qh);
+ if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
+ dma->status = MUSB_DMA_STATUS_CORE_ABORT;
+ musb->dma_controller->channel_abort(dma);
+ urb->actual_length += dma->actual_len;
+ dma->actual_len = 0L;
+ }
+ musb_save_toggle(cur_qh, is_in, urb);
+
+ if (is_in) {
+ /* move cur_qh to end of queue */
+ list_move_tail(&cur_qh->ring, &musb->in_bulk);
+
+ /* get the next qh from musb->in_bulk */
+ next_qh = first_qh(&musb->in_bulk);
+
+ /* set rx_reinit and schedule the next qh */
+ ep->rx_reinit = 1;
+ } else {
+ /* move cur_qh to end of queue */
+ list_move_tail(&cur_qh->ring, &musb->out_bulk);
+
+ /* get the next qh from musb->out_bulk */
+ next_qh = first_qh(&musb->out_bulk);
+
+ /* set tx_reinit and schedule the next qh */
+ ep->tx_reinit = 1;
+ }
+ musb_start_urb(musb, is_in, next_qh);
+ }
+}
/*
* Service the default endpoint (ep0) as host.
@@ -1055,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;
@@ -1136,23 +1267,31 @@ void musb_host_tx(struct musb *musb, u8 epnum)
status = -ETIMEDOUT;
} else if (tx_csr & MUSB_TXCSR_H_NAKTIMEOUT) {
- dev_dbg(musb->controller, "TX end=%d device not responding\n", epnum);
-
- /* NOTE: this code path would be a good place to PAUSE a
- * transfer, if there's some other (nonperiodic) tx urb
- * that could use this fifo. (dma complicates it...)
- * That's already done for bulk RX transfers.
- *
- * if (bulk && qh->ring.next != &musb->out_bulk), then
- * we have a candidate... NAKing is *NOT* an error
- */
- musb_ep_select(mbase, epnum);
- musb_writew(epio, MUSB_TXCSR,
- MUSB_TXCSR_H_WZC_BITS
- | MUSB_TXCSR_TXPKTRDY);
- return;
+ if (USB_ENDPOINT_XFER_BULK == qh->type && qh->mux == 1
+ && !list_is_singular(&musb->out_bulk)) {
+ dev_dbg(musb->controller,
+ "NAK timeout on TX%d ep\n", epnum);
+ musb_bulk_nak_timeout(musb, hw_ep, 0);
+ } else {
+ dev_dbg(musb->controller,
+ "TX end=%d device not responding\n", epnum);
+ /* NOTE: this code path would be a good place to PAUSE a
+ * transfer, if there's some other (nonperiodic) tx urb
+ * that could use this fifo. (dma complicates it...)
+ * That's already done for bulk RX transfers.
+ *
+ * if (bulk && qh->ring.next != &musb->out_bulk), then
+ * we have a candidate... NAKing is *NOT* an error
+ */
+ musb_ep_select(mbase, epnum);
+ musb_writew(epio, MUSB_TXCSR,
+ MUSB_TXCSR_H_WZC_BITS
+ | MUSB_TXCSR_TXPKTRDY);
+ }
+ return;
}
+done:
if (status) {
if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
dma->status = MUSB_DMA_STATUS_CORE_ABORT;
@@ -1321,10 +1460,39 @@ void musb_host_tx(struct musb *musb, u8 epnum)
if (length > qh->maxpacket)
length = qh->maxpacket;
/* Unmap the buffer so that CPU can use it */
- usb_hcd_unmap_urb_for_dma(musb_to_hcd(musb), urb);
- musb_write_fifo(hw_ep, length, urb->transfer_buffer + offset);
+ usb_hcd_unmap_urb_for_dma(musb->hcd, urb);
+
+ /*
+ * We need to map sg if the transfer_buffer is
+ * NULL.
+ */
+ if (!urb->transfer_buffer)
+ qh->use_sg = true;
+
+ if (qh->use_sg) {
+ /* sg_miter_start is already done in musb_ep_program */
+ if (!sg_miter_next(&qh->sg_miter)) {
+ dev_err(musb->controller, "error: sg list empty\n");
+ sg_miter_stop(&qh->sg_miter);
+ status = -EINVAL;
+ goto done;
+ }
+ urb->transfer_buffer = qh->sg_miter.addr;
+ length = min_t(u32, length, qh->sg_miter.length);
+ musb_write_fifo(hw_ep, length, urb->transfer_buffer);
+ qh->sg_miter.consumed = length;
+ sg_miter_stop(&qh->sg_miter);
+ } else {
+ musb_write_fifo(hw_ep, length, urb->transfer_buffer + offset);
+ }
+
qh->segsize = length;
+ if (qh->use_sg) {
+ if (offset + length >= urb->transfer_buffer_length)
+ qh->use_sg = false;
+ }
+
musb_ep_select(mbase, epnum);
musb_writew(epio, MUSB_TXCSR,
MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY);
@@ -1370,50 +1538,6 @@ void musb_host_tx(struct musb *musb, u8 epnum)
#endif
-/* Schedule next QH from musb->in_bulk and move the current qh to
- * the end; avoids starvation for other endpoints.
- */
-static void musb_bulk_rx_nak_timeout(struct musb *musb, struct musb_hw_ep *ep)
-{
- struct dma_channel *dma;
- struct urb *urb;
- void __iomem *mbase = musb->mregs;
- void __iomem *epio = ep->regs;
- struct musb_qh *cur_qh, *next_qh;
- u16 rx_csr;
-
- musb_ep_select(mbase, ep->epnum);
- dma = is_dma_capable() ? ep->rx_channel : NULL;
-
- /* clear nak timeout bit */
- rx_csr = musb_readw(epio, MUSB_RXCSR);
- rx_csr |= MUSB_RXCSR_H_WZC_BITS;
- rx_csr &= ~MUSB_RXCSR_DATAERROR;
- musb_writew(epio, MUSB_RXCSR, rx_csr);
-
- cur_qh = first_qh(&musb->in_bulk);
- if (cur_qh) {
- urb = next_urb(cur_qh);
- if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
- dma->status = MUSB_DMA_STATUS_CORE_ABORT;
- musb->dma_controller->channel_abort(dma);
- urb->actual_length += dma->actual_len;
- dma->actual_len = 0L;
- }
- musb_save_toggle(cur_qh, 1, urb);
-
- /* move cur_qh to end of queue */
- list_move_tail(&cur_qh->ring, &musb->in_bulk);
-
- /* get the next qh from musb->in_bulk */
- next_qh = first_qh(&musb->in_bulk);
-
- /* set rx_reinit and schedule the next qh */
- ep->rx_reinit = 1;
- musb_start_urb(musb, 1, next_qh);
- }
-}
-
/*
* Service an RX interrupt for the given IN endpoint; docs cover bulk, iso,
* and high-bandwidth IN transfer cases.
@@ -1432,6 +1556,7 @@ void musb_host_rx(struct musb *musb, u8 epnum)
bool done = false;
u32 status;
struct dma_channel *dma;
+ unsigned int sg_flags = SG_MITER_ATOMIC | SG_MITER_TO_SG;
musb_ep_select(mbase, epnum);
@@ -1490,7 +1615,7 @@ void musb_host_rx(struct musb *musb, u8 epnum)
if (usb_pipebulk(urb->pipe)
&& qh->mux == 1
&& !list_is_singular(&musb->in_bulk)) {
- musb_bulk_rx_nak_timeout(musb, hw_ep);
+ musb_bulk_nak_timeout(musb, hw_ep, 1);
return;
}
musb_ep_select(mbase, epnum);
@@ -1537,7 +1662,7 @@ void musb_host_rx(struct musb *musb, u8 epnum)
/* FIXME this is _way_ too much in-line logic for Mentor DMA */
-#ifndef CONFIG_USB_INVENTRA_DMA
+#if !defined(CONFIG_USB_INVENTRA_DMA) && !defined(CONFIG_USB_UX500_DMA)
if (rx_csr & MUSB_RXCSR_H_REQPKT) {
/* REVISIT this happened for a while on some short reads...
* the cleanup still needs investigation... looks bad...
@@ -1569,7 +1694,8 @@ void musb_host_rx(struct musb *musb, u8 epnum)
| MUSB_RXCSR_RXPKTRDY);
musb_writew(hw_ep->regs, MUSB_RXCSR, val);
-#ifdef CONFIG_USB_INVENTRA_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;
@@ -1582,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 */
@@ -1625,7 +1771,8 @@ void musb_host_rx(struct musb *musb, u8 epnum)
}
/* we are expecting IN packets */
-#ifdef CONFIG_USB_INVENTRA_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;
@@ -1634,10 +1781,10 @@ void musb_host_rx(struct musb *musb, u8 epnum)
rx_count = musb_readw(epio, MUSB_RXCOUNT);
- dev_dbg(musb->controller, "RX%d count %d, buffer 0x%x len %d/%d\n",
+ dev_dbg(musb->controller, "RX%d count %d, buffer 0x%llx len %d/%d\n",
epnum, rx_count,
- urb->transfer_dma
- + urb->actual_length,
+ (unsigned long long) urb->transfer_dma
+ + urb->actual_length,
qh->offset,
urb->transfer_buffer_length);
@@ -1736,16 +1883,53 @@ void musb_host_rx(struct musb *musb, u8 epnum)
c->channel_release(dma);
hw_ep->rx_channel = NULL;
dma = NULL;
- /* REVISIT reset CSR */
+ val = musb_readw(epio, MUSB_RXCSR);
+ val &= ~(MUSB_RXCSR_DMAENAB
+ | MUSB_RXCSR_H_AUTOREQ
+ | MUSB_RXCSR_AUTOCLEAR);
+ musb_writew(epio, MUSB_RXCSR, val);
}
}
#endif /* Mentor DMA */
if (!dma) {
+ unsigned int received_len;
+
/* Unmap the buffer so that CPU can use it */
- usb_hcd_unmap_urb_for_dma(musb_to_hcd(musb), urb);
- done = musb_host_packet_rx(musb, urb,
- epnum, iso_err);
+ usb_hcd_unmap_urb_for_dma(musb->hcd, urb);
+
+ /*
+ * We need to map sg if the transfer_buffer is
+ * NULL.
+ */
+ if (!urb->transfer_buffer) {
+ qh->use_sg = true;
+ sg_miter_start(&qh->sg_miter, urb->sg, 1,
+ sg_flags);
+ }
+
+ if (qh->use_sg) {
+ if (!sg_miter_next(&qh->sg_miter)) {
+ dev_err(musb->controller, "error: sg list empty\n");
+ sg_miter_stop(&qh->sg_miter);
+ status = -EINVAL;
+ done = true;
+ goto finish;
+ }
+ urb->transfer_buffer = qh->sg_miter.addr;
+ received_len = urb->actual_length;
+ qh->offset = 0x0;
+ done = musb_host_packet_rx(musb, urb, epnum,
+ iso_err);
+ /* Calculate the number of bytes received */
+ received_len = urb->actual_length -
+ received_len;
+ qh->sg_miter.consumed = received_len;
+ sg_miter_stop(&qh->sg_miter);
+ } else {
+ done = musb_host_packet_rx(musb, urb,
+ epnum, iso_err);
+ }
dev_dbg(musb->controller, "read %spacket\n", done ? "last " : "");
}
}
@@ -1754,6 +1938,9 @@ finish:
urb->actual_length += xfer_len;
qh->offset += xfer_len;
if (done) {
+ if (qh->use_sg)
+ qh->use_sg = false;
+
if (urb->status == -EINPROGRESS)
urb->status = status;
musb_advance_schedule(musb, urb, hw_ep, USB_DIR_IN);
@@ -1849,14 +2036,14 @@ static int musb_schedule(
else
head = &musb->out_bulk;
- /* Enable bulk RX NAK timeout scheme when bulk requests are
- * multiplexed. This scheme doen't work in high speed to full
+ /* Enable bulk RX/TX NAK timeout scheme when bulk requests are
+ * 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
* 4 (8 frame or 8ms) for FS device.
*/
- if (is_in && qh->dev)
+ if (qh->dev)
qh->intv_reg =
(USB_SPEED_HIGH == qh->dev->speed) ? 8 : 4;
goto success;
@@ -2035,7 +2222,7 @@ static int musb_urb_enqueue(
* we only have work to do in the former case.
*/
spin_lock_irqsave(&musb->lock, flags);
- if (hep->hcpriv) {
+ if (hep->hcpriv || !next_urb(qh)) {
/* some concurrent activity submitted another urb to hep...
* odd, rare, error prone, but legal.
*/
@@ -2098,7 +2285,7 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh)
}
/* turn off DMA requests, discard state, stop polling ... */
- if (is_in) {
+ if (ep->epnum && is_in) {
/* giveback saves bulk toggle */
csr = musb_h_flush_rxfifo(ep, 0);
@@ -2270,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;
@@ -2291,7 +2480,7 @@ static int musb_bus_suspend(struct usb_hcd *hcd)
if (musb->is_active) {
WARNING("trying to suspend as %s while active\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
return -EBUSY;
} else
return 0;
@@ -2299,14 +2488,130 @@ 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;
+}
+
+#ifndef CONFIG_MUSB_PIO_ONLY
+
+#define MUSB_USB_DMA_ALIGN 4
+
+struct musb_temp_buffer {
+ void *kmalloc_ptr;
+ void *old_xfer_buffer;
+ u8 data[0];
+};
+
+static void musb_free_temp_buffer(struct urb *urb)
+{
+ enum dma_data_direction dir;
+ struct musb_temp_buffer *temp;
+
+ if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER))
+ return;
+
+ dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+
+ temp = container_of(urb->transfer_buffer, struct musb_temp_buffer,
+ data);
+
+ if (dir == DMA_FROM_DEVICE) {
+ memcpy(temp->old_xfer_buffer, temp->data,
+ urb->transfer_buffer_length);
+ }
+ urb->transfer_buffer = temp->old_xfer_buffer;
+ kfree(temp->kmalloc_ptr);
+
+ urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER;
+}
+
+static int musb_alloc_temp_buffer(struct urb *urb, gfp_t mem_flags)
+{
+ enum dma_data_direction dir;
+ struct musb_temp_buffer *temp;
+ void *kmalloc_ptr;
+ size_t kmalloc_size;
+
+ if (urb->num_sgs || urb->sg ||
+ urb->transfer_buffer_length == 0 ||
+ !((uintptr_t)urb->transfer_buffer & (MUSB_USB_DMA_ALIGN - 1)))
+ return 0;
+
+ dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+
+ /* Allocate a buffer with enough padding for alignment */
+ kmalloc_size = urb->transfer_buffer_length +
+ sizeof(struct musb_temp_buffer) + MUSB_USB_DMA_ALIGN - 1;
+
+ kmalloc_ptr = kmalloc(kmalloc_size, mem_flags);
+ if (!kmalloc_ptr)
+ return -ENOMEM;
+
+ /* Position our struct temp_buffer such that data is aligned */
+ temp = PTR_ALIGN(kmalloc_ptr, MUSB_USB_DMA_ALIGN);
+
+
+ temp->kmalloc_ptr = kmalloc_ptr;
+ temp->old_xfer_buffer = urb->transfer_buffer;
+ if (dir == DMA_TO_DEVICE)
+ memcpy(temp->data, urb->transfer_buffer,
+ urb->transfer_buffer_length);
+ urb->transfer_buffer = temp->data;
+
+ urb->transfer_flags |= URB_ALIGNED_TEMP_BUFFER;
+
return 0;
}
-const struct hc_driver musb_hc_driver = {
+static int musb_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
+ gfp_t mem_flags)
+{
+ struct musb *musb = hcd_to_musb(hcd);
+ int ret;
+
+ /*
+ * The DMA engine in RTL1.8 and above cannot handle
+ * DMA addresses that are not aligned to a 4 byte boundary.
+ * For such engine implemented (un)map_urb_for_dma hooks.
+ * Do not use these hooks for RTL<1.8
+ */
+ if (musb->hwvers < MUSB_HWVERS_1800)
+ return usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
+
+ ret = musb_alloc_temp_buffer(urb, mem_flags);
+ if (ret)
+ return ret;
+
+ ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags);
+ if (ret)
+ musb_free_temp_buffer(urb);
+
+ return ret;
+}
+
+static void musb_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+{
+ struct musb *musb = hcd_to_musb(hcd);
+
+ usb_hcd_unmap_urb_for_dma(hcd, urb);
+
+ /* Do not use this hook for RTL<1.8 (see description above) */
+ if (musb->hwvers < MUSB_HWVERS_1800)
+ return;
+
+ musb_free_temp_buffer(urb);
+}
+#endif /* !CONFIG_MUSB_PIO_ONLY */
+
+static const struct hc_driver musb_hc_driver = {
.description = "musb-hcd",
.product_desc = "MUSB HDRC host driver",
- .hcd_priv_size = sizeof(struct musb),
+ .hcd_priv_size = sizeof(struct musb *),
.flags = HCD_USB2 | HCD_MEMORY,
/* not using irq handler or reset hooks from usbcore, since
@@ -2322,6 +2627,11 @@ const struct hc_driver musb_hc_driver = {
.urb_dequeue = musb_urb_dequeue,
.endpoint_disable = musb_h_disable,
+#ifndef CONFIG_MUSB_PIO_ONLY
+ .map_urb_for_dma = musb_map_urb_for_dma,
+ .unmap_urb_for_dma = musb_unmap_urb_for_dma,
+#endif
+
.hub_status_data = musb_hub_status_data,
.hub_control = musb_hub_control,
.bus_suspend = musb_bus_suspend,
@@ -2329,3 +2639,69 @@ const struct hc_driver musb_hc_driver = {
/* .start_port_reset = NULL, */
/* .hub_irq_enable = NULL, */
};
+
+int musb_host_alloc(struct musb *musb)
+{
+ struct device *dev = musb->controller;
+
+ /* usbcore sets dev->driver_data to hcd, and sometimes uses that... */
+ musb->hcd = usb_create_hcd(&musb_hc_driver, dev, dev_name(dev));
+ if (!musb->hcd)
+ return -EINVAL;
+
+ *musb->hcd->hcd_priv = (unsigned long) musb;
+ musb->hcd->self.uses_pio_for_control = 1;
+ musb->hcd->uses_new_polling = 1;
+ musb->hcd->has_tt = 1;
+
+ return 0;
+}
+
+void musb_host_cleanup(struct musb *musb)
+{
+ if (musb->port_mode == MUSB_PORT_MODE_GADGET)
+ return;
+ usb_remove_hcd(musb->hcd);
+ musb->hcd = NULL;
+}
+
+void musb_host_free(struct musb *musb)
+{
+ usb_put_hcd(musb->hcd);
+}
+
+int musb_host_setup(struct musb *musb, int power_budget)
+{
+ int ret;
+ struct usb_hcd *hcd = musb->hcd;
+
+ MUSB_HST_MODE(musb);
+ musb->xceiv->otg->default_a = 1;
+ musb->xceiv->state = OTG_STATE_A_IDLE;
+
+ otg_set_host(musb->xceiv->otg, &hcd->self);
+ hcd->self.otg_port = 1;
+ musb->xceiv->otg->host = &hcd->self;
+ hcd->power_budget = 2 * (power_budget ? : 250);
+
+ ret = usb_add_hcd(hcd, 0, 0);
+ if (ret < 0)
+ return ret;
+
+ device_wakeup_enable(hcd->self.controller);
+ return 0;
+}
+
+void musb_host_resume_root_hub(struct musb *musb)
+{
+ usb_hcd_resume_root_hub(musb->hcd);
+}
+
+void musb_host_poke_root_hub(struct musb *musb)
+{
+ MUSB_HST_MODE(musb);
+ if (musb->hcd->status_urb)
+ usb_hcd_poll_rh_status(musb->hcd);
+ else
+ usb_hcd_resume_root_hub(musb->hcd);
+}
diff --git a/drivers/usb/musb/musb_host.h b/drivers/usb/musb/musb_host.h
index 622d09fb9ab..7bbf01bf4bb 100644
--- a/drivers/usb/musb/musb_host.h
+++ b/drivers/usb/musb/musb_host.h
@@ -35,15 +35,7 @@
#ifndef _MUSB_HOST_H
#define _MUSB_HOST_H
-static inline struct usb_hcd *musb_to_hcd(struct musb *musb)
-{
- return container_of((void *) musb, struct usb_hcd, hcd_priv);
-}
-
-static inline struct musb *hcd_to_musb(struct usb_hcd *hcd)
-{
- return (struct musb *) (hcd->hcd_priv);
-}
+#include <linux/scatterlist.h>
/* stored in "usb_host_endpoint.hcpriv" for scheduled endpoints */
struct musb_qh {
@@ -71,6 +63,8 @@ struct musb_qh {
u16 maxpacket;
u16 frame; /* for periodic schedule */
unsigned iso_idx; /* in urb->iso_frame_desc[] */
+ struct sg_mapping_iter sg_miter; /* for highmem in PIO mode */
+ bool use_sg; /* to track urb using sglist */
};
/* map from control or bulk queue head to the first qh on that ring */
@@ -82,7 +76,58 @@ static inline struct musb_qh *first_qh(struct list_head *q)
}
+#if IS_ENABLED(CONFIG_USB_MUSB_HOST) || IS_ENABLED(CONFIG_USB_MUSB_DUAL_ROLE)
+extern struct musb *hcd_to_musb(struct usb_hcd *);
+extern irqreturn_t musb_h_ep0_irq(struct musb *);
+extern int musb_host_alloc(struct musb *);
+extern int musb_host_setup(struct musb *, int);
+extern void musb_host_cleanup(struct musb *);
+extern void musb_host_tx(struct musb *, u8);
+extern void musb_host_rx(struct musb *, u8);
extern void musb_root_disconnect(struct musb *musb);
+extern void musb_host_free(struct musb *);
+extern void musb_host_cleanup(struct musb *);
+extern void musb_host_tx(struct musb *, u8);
+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)
+{
+ return NULL;
+}
+
+static inline irqreturn_t musb_h_ep0_irq(struct musb *musb)
+{
+ return 0;
+}
+
+static inline int musb_host_alloc(struct musb *musb)
+{
+ return 0;
+}
+
+static inline int musb_host_setup(struct musb *musb, int power_budget)
+{
+ return 0;
+}
+
+static inline void musb_host_cleanup(struct musb *musb) {}
+static inline void musb_host_free(struct musb *musb) {}
+static inline void musb_host_tx(struct musb *musb, u8 epnum) {}
+static inline void musb_host_rx(struct musb *musb, u8 epnum) {}
+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;
@@ -91,8 +136,6 @@ extern int musb_hub_control(struct usb_hcd *hcd,
u16 typeReq, u16 wValue, u16 wIndex,
char *buf, u16 wLength);
-extern const struct hc_driver musb_hc_driver;
-
static inline struct urb *next_urb(struct musb_qh *qh)
{
struct list_head *queue;
diff --git a/drivers/usb/musb/musb_io.h b/drivers/usb/musb/musb_io.h
index 1d5eda26fbd..eebeed78edd 100644
--- a/drivers/usb/musb/musb_io.h
+++ b/drivers/usb/musb/musb_io.h
@@ -37,26 +37,6 @@
#include <linux/io.h>
-#if !defined(CONFIG_ARM) && !defined(CONFIG_SUPERH) \
- && !defined(CONFIG_AVR32) && !defined(CONFIG_PPC32) \
- && !defined(CONFIG_PPC64) && !defined(CONFIG_BLACKFIN) \
- && !defined(CONFIG_MIPS)
-static inline void readsl(const void __iomem *addr, void *buf, int len)
- { insl((unsigned long)addr, buf, len); }
-static inline void readsw(const void __iomem *addr, void *buf, int len)
- { insw((unsigned long)addr, buf, len); }
-static inline void readsb(const void __iomem *addr, void *buf, int len)
- { insb((unsigned long)addr, buf, len); }
-
-static inline void writesl(const void __iomem *addr, const void *buf, int len)
- { outsl((unsigned long)addr, buf, len); }
-static inline void writesw(const void __iomem *addr, const void *buf, int len)
- { outsw((unsigned long)addr, buf, len); }
-static inline void writesb(const void __iomem *addr, const void *buf, int len)
- { outsb((unsigned long)addr, buf, len); }
-
-#endif
-
#ifndef CONFIG_BLACKFIN
/* NOTE: these offsets are all in bytes */
diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c
index e9f80adc45a..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,9 +43,40 @@
#include "musb_core.h"
+void musb_host_finish_resume(struct work_struct *work)
+{
+ struct musb *musb;
+ unsigned long flags;
+ u8 power;
+
+ musb = container_of(work, struct musb, finish_resume_work.work);
+
+ spin_lock_irqsave(&musb->lock, flags);
+
+ 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;
-static void musb_port_suspend(struct musb *musb, bool do_suspend)
+ spin_unlock_irqrestore(&musb->lock, flags);
+}
+
+void musb_port_suspend(struct musb *musb, bool do_suspend)
{
+ struct usb_otg *otg = musb->xceiv->otg;
u8 power;
void __iomem *mbase = musb->mregs;
@@ -80,8 +110,7 @@ static void musb_port_suspend(struct musb *musb, bool do_suspend)
switch (musb->xceiv->state) {
case OTG_STATE_A_HOST:
musb->xceiv->state = OTG_STATE_A_SUSPEND;
- musb->is_active = is_otg_enabled(musb)
- && musb->xceiv->host->b_hnp_enable;
+ musb->is_active = otg->host->b_hnp_enable;
if (musb->is_active)
mod_timer(&musb->otg_timer, jiffies
+ msecs_to_jiffies(
@@ -90,13 +119,12 @@ static void musb_port_suspend(struct musb *musb, bool do_suspend)
break;
case OTG_STATE_B_HOST:
musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
- musb->is_active = is_otg_enabled(musb)
- && musb->xceiv->host->b_hnp_enable;
+ musb->is_active = otg->host->b_hnp_enable;
musb_platform_try_idle(musb, 0);
break;
default:
dev_dbg(musb->controller, "bogus rh suspend? %s\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
} else if (power & MUSB_POWER_SUSPENDM) {
power &= ~MUSB_POWER_SUSPENDM;
@@ -107,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;
@@ -130,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
@@ -139,28 +167,37 @@ 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;
}
- musb->ignore_disconnect = true;
power &= 0xf0;
musb_writeb(mbase, MUSB_POWER,
power | MUSB_POWER_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,
power & ~MUSB_POWER_RESET);
- musb->ignore_disconnect = false;
-
power = musb_readb(mbase, MUSB_POWER);
if (power & MUSB_POWER_HSMODE) {
dev_dbg(musb->controller, "high-speed device connected\n");
@@ -171,7 +208,7 @@ static void musb_port_reset(struct musb *musb, bool do_reset)
musb->port1_status |= USB_PORT_STAT_ENABLE
| (USB_PORT_STAT_C_RESET << 16)
| (USB_PORT_STAT_C_ENABLE << 16);
- usb_hcd_poll_rh_status(musb_to_hcd(musb));
+ usb_hcd_poll_rh_status(musb->hcd);
musb->vbuserr_retry = VBUSERR_RETRY_COUNT;
}
@@ -179,16 +216,17 @@ static void musb_port_reset(struct musb *musb, bool do_reset)
void musb_root_disconnect(struct musb *musb)
{
+ struct usb_otg *otg = musb->xceiv->otg;
+
musb->port1_status = USB_PORT_STAT_POWER
| (USB_PORT_STAT_C_CONNECTION << 16);
- usb_hcd_poll_rh_status(musb_to_hcd(musb));
+ usb_hcd_poll_rh_status(musb->hcd);
musb->is_active = 0;
switch (musb->xceiv->state) {
case OTG_STATE_A_SUSPEND:
- if (is_otg_enabled(musb)
- && musb->xceiv->host->b_hnp_enable) {
+ if (otg->host->b_hnp_enable) {
musb->xceiv->state = OTG_STATE_A_PERIPHERAL;
musb->g.is_a_peripheral = 1;
break;
@@ -203,7 +241,7 @@ void musb_root_disconnect(struct musb *musb)
break;
default:
dev_dbg(musb->controller, "host disconnect (%s)\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
}
@@ -224,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,
@@ -270,7 +325,7 @@ int musb_hub_control(
musb_port_suspend(musb, false);
break;
case USB_PORT_FEAT_POWER:
- if (!(is_otg_enabled(musb) && hcd->self.is_b_host))
+ if (!hcd->self.is_b_host)
musb_platform_set_vbus(musb, 0);
break;
case USB_PORT_FEAT_C_CONNECTION:
@@ -312,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_to_hcd(musb));
- /* 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);
@@ -366,7 +391,7 @@ int musb_hub_control(
* initialization logic, e.g. for OTG, or change any
* logic relating to VBUS power-up.
*/
- if (!(is_otg_enabled(musb) && 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/musbhsdma.c b/drivers/usb/musb/musbhsdma.c
index 57a608584e1..e8e9f9aab20 100644
--- a/drivers/usb/musb/musbhsdma.c
+++ b/drivers/usb/musb/musbhsdma.c
@@ -37,18 +37,10 @@
#include "musb_core.h"
#include "musbhsdma.h"
-static int dma_controller_start(struct dma_controller *c)
-{
- /* nothing to do */
- return 0;
-}
-
static void dma_channel_release(struct dma_channel *channel);
-static int dma_controller_stop(struct dma_controller *c)
+static void dma_controller_stop(struct musb_dma_controller *controller)
{
- struct musb_dma_controller *controller = container_of(c,
- struct musb_dma_controller, controller);
struct musb *musb = controller->private_data;
struct dma_channel *channel;
u8 bit;
@@ -67,8 +59,6 @@ static int dma_controller_stop(struct dma_controller *c)
}
}
}
-
- return 0;
}
static struct dma_channel *dma_channel_allocate(struct dma_controller *c,
@@ -371,8 +361,7 @@ void dma_controller_destroy(struct dma_controller *c)
struct musb_dma_controller *controller = container_of(c,
struct musb_dma_controller, controller);
- if (!controller)
- return;
+ dma_controller_stop(controller);
if (controller->irq)
free_irq(controller->irq, c);
@@ -380,15 +369,14 @@ void dma_controller_destroy(struct dma_controller *c)
kfree(controller);
}
-struct dma_controller *__init
-dma_controller_create(struct musb *musb, void __iomem *base)
+struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *base)
{
struct musb_dma_controller *controller;
struct device *dev = musb->controller;
struct platform_device *pdev = to_platform_device(dev);
int irq = platform_get_irq_byname(pdev, "dma");
- if (irq == 0) {
+ if (irq <= 0) {
dev_err(dev, "No DMA interrupt line!\n");
return NULL;
}
@@ -401,8 +389,6 @@ dma_controller_create(struct musb *musb, void __iomem *base)
controller->private_data = musb;
controller->base = base;
- controller->controller.start = dma_controller_start;
- controller->controller.stop = dma_controller_stop;
controller->controller.channel_alloc = dma_channel_allocate;
controller->controller.channel_release = dma_channel_release;
controller->controller.channel_program = dma_channel_program;
diff --git a/drivers/usb/musb/musbhsdma.h b/drivers/usb/musb/musbhsdma.h
index 320fd4afb93..f7b13fd2525 100644
--- a/drivers/usb/musb/musbhsdma.h
+++ b/drivers/usb/musb/musbhsdma.h
@@ -31,10 +31,6 @@
*
*/
-#if defined(CONFIG_SOC_OMAP2430) || defined(CONFIG_SOC_OMAP3430)
-#include "omap2430.h"
-#endif
-
#ifndef CONFIG_BLACKFIN
#define MUSB_HSDMA_BASE 0x200
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index df719eae3b0..d369bf1f393 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -30,10 +30,15 @@
#include <linux/init.h>
#include <linux/list.h>
#include <linux/io.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/pm_runtime.h>
#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/usb/musb-omap.h>
+#include <linux/phy/omap_control_phy.h>
+#include <linux/of_platform.h>
#include "musb_core.h"
#include "omap2430.h"
@@ -41,9 +46,14 @@
struct omap2430_glue {
struct device *dev;
struct platform_device *musb;
+ enum omap_musb_vbus_id_status status;
+ struct work_struct omap_musb_mailbox_work;
+ struct device *control_otghs;
};
#define glue_to_musb(g) platform_get_drvdata(g->musb)
+static struct omap2430_glue *_glue;
+
static struct timer_list musb_idle_timer;
static void musb_do_idle(unsigned long _musb)
@@ -78,7 +88,7 @@ static void musb_do_idle(unsigned long _musb)
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_to_hcd(musb));
+ usb_hcd_poll_rh_status(musb->hcd);
/* NOTE: it might really be A_WAIT_BCON ... */
musb->xceiv->state = OTG_STATE_A_HOST;
}
@@ -108,7 +118,7 @@ static void omap2430_musb_try_idle(struct musb *musb, unsigned long timeout)
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",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
del_timer(&musb_idle_timer);
last_timer = jiffies;
return;
@@ -125,16 +135,16 @@ static void omap2430_musb_try_idle(struct musb *musb, unsigned long timeout)
last_timer = timeout;
dev_dbg(musb->controller, "%s inactive, for idle timer for %lu ms\n",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
(unsigned long)jiffies_to_msecs(timeout - jiffies));
mod_timer(&musb_idle_timer, timeout);
}
static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
{
+ struct usb_otg *otg = musb->xceiv->otg;
u8 devctl;
unsigned long timeout = jiffies + msecs_to_jiffies(1000);
- int ret = 1;
/* HDRC controls CPEN, but beware current surges during device
* connect. They can trigger transient overcurrent conditions
* that must be ignored.
@@ -144,6 +154,7 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
if (is_on) {
if (musb->xceiv->state == OTG_STATE_A_IDLE) {
+ int loops = 100;
/* start the session */
devctl |= MUSB_DEVCTL_SESSION;
musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
@@ -153,21 +164,21 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
*/
while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) {
+ mdelay(5);
cpu_relax();
- if (time_after(jiffies, timeout)) {
+ if (time_after(jiffies, timeout)
+ || loops-- <= 0) {
dev_err(musb->controller,
"configured as A device timeout");
- ret = -EINVAL;
break;
}
}
- if (ret && musb->xceiv->set_vbus)
- otg_set_vbus(musb->xceiv, 1);
+ otg_set_vbus(otg, 1);
} else {
musb->is_active = 1;
- musb->xceiv->default_a = 1;
+ otg->default_a = 1;
musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
devctl |= MUSB_DEVCTL_SESSION;
MUSB_HST_MODE(musb);
@@ -179,7 +190,7 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
* jumping right to B_IDLE...
*/
- musb->xceiv->default_a = 0;
+ otg->default_a = 0;
musb->xceiv->state = OTG_STATE_B_IDLE;
devctl &= ~MUSB_DEVCTL_SESSION;
@@ -189,7 +200,7 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
dev_dbg(musb->controller, "VBUS %s, devctl %02x "
/* otg %3x conf %08x prcm %08x */ "\n",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
musb_readb(musb->mregs, MUSB_DEVCTL));
}
@@ -222,85 +233,166 @@ static inline void omap2430_low_level_init(struct musb *musb)
musb_writel(musb->mregs, OTG_FORCESTDBY, l);
}
-static int musb_otg_notifications(struct notifier_block *nb,
- unsigned long event, void *unused)
+void omap_musb_mailbox(enum omap_musb_vbus_id_status status)
{
- struct musb *musb = container_of(nb, struct musb, nb);
+ struct omap2430_glue *glue = _glue;
+
+ if (!glue) {
+ pr_err("%s: musb core is not yet initialized\n", __func__);
+ return;
+ }
+ glue->status = status;
- musb->xceiv_event = event;
- schedule_work(&musb->otg_notifier_work);
+ if (!glue_to_musb(glue)) {
+ pr_err("%s: musb core is not yet ready\n", __func__);
+ return;
+ }
- return NOTIFY_OK;
+ schedule_work(&glue->omap_musb_mailbox_work);
}
+EXPORT_SYMBOL_GPL(omap_musb_mailbox);
-static void musb_otg_notifier_work(struct work_struct *data_notifier_work)
+static void omap_musb_set_mailbox(struct omap2430_glue *glue)
{
- struct musb *musb = container_of(data_notifier_work, struct musb, otg_notifier_work);
+ struct musb *musb = glue_to_musb(glue);
struct device *dev = musb->controller;
- struct musb_hdrc_platform_data *pdata = dev->platform_data;
+ struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev);
struct omap_musb_board_data *data = pdata->board_data;
-
- switch (musb->xceiv_event) {
- case USB_EVENT_ID:
- dev_dbg(musb->controller, "ID GND\n");
-
- if (!is_otg_enabled(musb) || musb->gadget_driver) {
- pm_runtime_get_sync(musb->controller);
- otg_init(musb->xceiv);
+ struct usb_otg *otg = musb->xceiv->otg;
+
+ switch (glue->status) {
+ case OMAP_MUSB_ID_GROUND:
+ dev_dbg(dev, "ID GND\n");
+
+ otg->default_a = true;
+ musb->xceiv->state = OTG_STATE_A_IDLE;
+ musb->xceiv->last_event = USB_EVENT_ID;
+ if (musb->gadget_driver) {
+ pm_runtime_get_sync(dev);
+ omap_control_usb_set_mode(glue->control_otghs,
+ USB_MODE_HOST);
omap2430_musb_set_vbus(musb, 1);
}
break;
- case USB_EVENT_VBUS:
- dev_dbg(musb->controller, "VBUS Connect\n");
+ case OMAP_MUSB_VBUS_VALID:
+ dev_dbg(dev, "VBUS Connect\n");
+ otg->default_a = false;
+ musb->xceiv->state = OTG_STATE_B_IDLE;
+ musb->xceiv->last_event = USB_EVENT_VBUS;
if (musb->gadget_driver)
- pm_runtime_get_sync(musb->controller);
- otg_init(musb->xceiv);
+ pm_runtime_get_sync(dev);
+ omap_control_usb_set_mode(glue->control_otghs, USB_MODE_DEVICE);
break;
- case USB_EVENT_NONE:
- dev_dbg(musb->controller, "VBUS Disconnect\n");
+ case OMAP_MUSB_ID_FLOAT:
+ case OMAP_MUSB_VBUS_OFF:
+ dev_dbg(dev, "VBUS Disconnect\n");
- if (is_otg_enabled(musb) || is_peripheral_enabled(musb))
- if (musb->gadget_driver) {
- pm_runtime_mark_last_busy(musb->controller);
- pm_runtime_put_autosuspend(musb->controller);
- }
-
- if (data->interface_type == MUSB_INTERFACE_UTMI) {
- if (musb->xceiv->set_vbus)
- otg_set_vbus(musb->xceiv, 0);
+ musb->xceiv->last_event = USB_EVENT_NONE;
+ if (musb->gadget_driver) {
+ omap2430_musb_set_vbus(musb, 0);
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_autosuspend(dev);
}
- otg_shutdown(musb->xceiv);
+
+ if (data->interface_type == MUSB_INTERFACE_UTMI)
+ otg_set_vbus(musb->xceiv->otg, 0);
+
+ omap_control_usb_set_mode(glue->control_otghs,
+ USB_MODE_DISCONNECT);
break;
default:
- dev_dbg(musb->controller, "ID float\n");
+ dev_dbg(dev, "ID float\n");
}
+
+ atomic_notifier_call_chain(&musb->xceiv->notifier,
+ musb->xceiv->last_event, NULL);
+}
+
+
+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)
+{
+ 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);
+
+ if (musb->int_usb || musb->int_tx || musb->int_rx)
+ retval = musb_interrupt(musb);
+
+ spin_unlock_irqrestore(&musb->lock, flags);
+
+ return retval;
}
static int omap2430_musb_init(struct musb *musb)
{
- u32 l, status = 0;
+ u32 l;
+ int status = 0;
struct device *dev = musb->controller;
- struct musb_hdrc_platform_data *plat = dev->platform_data;
+ struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
+ struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
struct omap_musb_board_data *data = plat->board_data;
/* We require some kind of external transceiver, hooked
* up through ULPI. TWL4030-family PMICs include one,
* which needs a driver, drivers aren't always needed.
*/
- musb->xceiv = otg_get_transceiver();
- if (!musb->xceiv) {
+ 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 {
+ 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);
+
+ if (status == -ENXIO)
+ return status;
+
pr_err("HS USB OTG: no transceiver configured\n");
- return -ENODEV;
+ return -EPROBE_DEFER;
}
- INIT_WORK(&musb->otg_notifier_work, musb_otg_notifier_work);
+ 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);
if (status < 0) {
- dev_err(dev, "pm_runtime_get_sync FAILED");
+ dev_err(dev, "pm_runtime_get_sync FAILED %d\n", status);
goto err1;
}
@@ -324,14 +416,15 @@ static int omap2430_musb_init(struct musb *musb)
musb_readl(musb->mregs, OTG_INTERFSEL),
musb_readl(musb->mregs, OTG_SIMENABLE));
- musb->nb.notifier_call = musb_otg_notifications;
- status = otg_register_notifier(musb->xceiv, &musb->nb);
+ setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
- if (status)
- dev_dbg(musb->controller, "notification register failed\n");
+ if (glue->status != OMAP_MUSB_UNKNOWN)
+ omap_musb_set_mailbox(glue);
- setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
+ phy_init(musb->phy);
+ phy_power_on(musb->phy);
+ pm_runtime_put_noidle(musb->controller);
return 0;
err1:
@@ -343,13 +436,14 @@ static void omap2430_musb_enable(struct musb *musb)
u8 devctl;
unsigned long timeout = jiffies + msecs_to_jiffies(1000);
struct device *dev = musb->controller;
- struct musb_hdrc_platform_data *pdata = dev->platform_data;
+ struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
+ struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev);
struct omap_musb_board_data *data = pdata->board_data;
- switch (musb->xceiv->last_event) {
+ switch (glue->status) {
- case USB_EVENT_ID:
- otg_init(musb->xceiv);
+ case OMAP_MUSB_ID_GROUND:
+ omap_control_usb_set_mode(glue->control_otghs, USB_MODE_HOST);
if (data->interface_type != MUSB_INTERFACE_UTMI)
break;
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
@@ -367,8 +461,8 @@ static void omap2430_musb_enable(struct musb *musb)
}
break;
- case USB_EVENT_VBUS:
- otg_init(musb->xceiv);
+ case OMAP_MUSB_VBUS_VALID:
+ omap_control_usb_set_mode(glue->control_otghs, USB_MODE_DEVICE);
break;
default:
@@ -378,17 +472,21 @@ static void omap2430_musb_enable(struct musb *musb)
static void omap2430_musb_disable(struct musb *musb)
{
- if (musb->xceiv->last_event)
- otg_shutdown(musb->xceiv);
+ struct device *dev = musb->controller;
+ struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
+
+ if (glue->status != OMAP_MUSB_UNKNOWN)
+ omap_control_usb_set_mode(glue->control_otghs,
+ USB_MODE_DISCONNECT);
}
static int omap2430_musb_exit(struct musb *musb)
{
del_timer_sync(&musb_idle_timer);
- cancel_work_sync(&musb->otg_notifier_work);
omap2430_low_level_exit(musb);
- otg_put_transceiver(musb->xceiv);
+ phy_power_off(musb->phy);
+ phy_exit(musb->phy);
return 0;
}
@@ -408,23 +506,27 @@ static const struct musb_platform_ops omap2430_ops = {
static u64 omap2430_dmamask = DMA_BIT_MASK(32);
-static int __init omap2430_probe(struct platform_device *pdev)
+static int omap2430_probe(struct platform_device *pdev)
{
- struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
+ struct resource musb_resources[3];
+ struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev);
+ struct omap_musb_board_data *data;
struct platform_device *musb;
struct omap2430_glue *glue;
+ struct device_node *np = pdev->dev.of_node;
+ struct musb_hdrc_config *config;
int ret = -ENOMEM;
- glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+ glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
if (!glue) {
dev_err(&pdev->dev, "failed to allocate glue context\n");
goto err0;
}
- musb = platform_device_alloc("musb-hdrc", -1);
+ musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO);
if (!musb) {
dev_err(&pdev->dev, "failed to allocate musb device\n");
- goto err1;
+ goto err0;
}
musb->dev.parent = &pdev->dev;
@@ -433,13 +535,88 @@ static int __init 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,
+ "failed to allocate musb platform data\n");
+ goto err2;
+ }
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ dev_err(&pdev->dev,
+ "failed to allocate musb board data\n");
+ goto err2;
+ }
+ config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL);
+ if (!config) {
+ dev_err(&pdev->dev,
+ "failed to allocate musb hdrc config\n");
+ goto err2;
+ }
+
+ of_property_read_u32(np, "mode", (u32 *)&pdata->mode);
+ of_property_read_u32(np, "interface-type",
+ (u32 *)&data->interface_type);
+ of_property_read_u32(np, "num-eps", (u32 *)&config->num_eps);
+ 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->board_data = data;
+ pdata->config = config;
+
+ 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;
+ }
+ }
pdata->platform_ops = &omap2430_ops;
platform_set_drvdata(pdev, glue);
- ret = platform_device_add_resources(musb, pdev->resource,
- pdev->num_resources);
+ /*
+ * REVISIT if we ever have two instances of the wrapper, we will be
+ * in big trouble
+ */
+ _glue = glue;
+
+ INIT_WORK(&glue->omap_musb_mailbox_work, omap_musb_mailbox_work);
+
+ memset(musb_resources, 0x00, sizeof(*musb_resources) *
+ ARRAY_SIZE(musb_resources));
+
+ musb_resources[0].name = pdev->resource[0].name;
+ musb_resources[0].start = pdev->resource[0].start;
+ musb_resources[0].end = pdev->resource[0].end;
+ musb_resources[0].flags = pdev->resource[0].flags;
+
+ musb_resources[1].name = pdev->resource[1].name;
+ musb_resources[1].start = pdev->resource[1].start;
+ musb_resources[1].end = pdev->resource[1].end;
+ musb_resources[1].flags = pdev->resource[1].flags;
+
+ 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;
+
+ ret = platform_device_add_resources(musb, musb_resources,
+ ARRAY_SIZE(musb_resources));
if (ret) {
dev_err(&pdev->dev, "failed to add resources\n");
goto err2;
@@ -451,34 +628,29 @@ static int __init omap2430_probe(struct platform_device *pdev)
goto err2;
}
+ pm_runtime_enable(&pdev->dev);
+
ret = platform_device_add(musb);
if (ret) {
dev_err(&pdev->dev, "failed to register musb device\n");
goto err2;
}
- pm_runtime_enable(&pdev->dev);
-
return 0;
err2:
platform_device_put(musb);
-err1:
- kfree(glue);
-
err0:
return ret;
}
-static int __exit omap2430_remove(struct platform_device *pdev)
+static int omap2430_remove(struct platform_device *pdev)
{
struct omap2430_glue *glue = platform_get_drvdata(pdev);
- platform_device_del(glue->musb);
- platform_device_put(glue->musb);
- pm_runtime_put(&pdev->dev);
- kfree(glue);
+ cancel_work_sync(&glue->omap_musb_mailbox_work);
+ platform_device_unregister(glue->musb);
return 0;
}
@@ -490,11 +662,12 @@ static int omap2430_runtime_suspend(struct device *dev)
struct omap2430_glue *glue = dev_get_drvdata(dev);
struct musb *musb = glue_to_musb(glue);
- musb->context.otg_interfsel = musb_readl(musb->mregs,
- OTG_INTERFSEL);
+ if (musb) {
+ musb->context.otg_interfsel = musb_readl(musb->mregs,
+ OTG_INTERFSEL);
- omap2430_low_level_exit(musb);
- otg_set_suspend(musb->xceiv, 1);
+ omap2430_low_level_exit(musb);
+ }
return 0;
}
@@ -504,11 +677,11 @@ static int omap2430_runtime_resume(struct device *dev)
struct omap2430_glue *glue = dev_get_drvdata(dev);
struct musb *musb = glue_to_musb(glue);
- omap2430_low_level_init(musb);
- musb_writel(musb->mregs, OTG_INTERFSEL,
- musb->context.otg_interfsel);
-
- otg_set_suspend(musb->xceiv, 0);
+ if (musb) {
+ omap2430_low_level_init(musb);
+ musb_writel(musb->mregs, OTG_INTERFSEL,
+ musb->context.otg_interfsel);
+ }
return 0;
}
@@ -523,11 +696,26 @@ static struct dev_pm_ops omap2430_pm_ops = {
#define DEV_PM_OPS NULL
#endif
+#ifdef CONFIG_OF
+static const struct of_device_id omap2430_id_table[] = {
+ {
+ .compatible = "ti,omap4-musb"
+ },
+ {
+ .compatible = "ti,omap3-musb"
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, omap2430_id_table);
+#endif
+
static struct platform_driver omap2430_driver = {
- .remove = __exit_p(omap2430_remove),
+ .probe = omap2430_probe,
+ .remove = omap2430_remove,
.driver = {
.name = "musb-omap2430",
.pm = DEV_PM_OPS,
+ .of_match_table = of_match_ptr(omap2430_id_table),
},
};
@@ -537,7 +725,7 @@ MODULE_LICENSE("GPL v2");
static int __init omap2430_init(void)
{
- return platform_driver_probe(&omap2430_driver, omap2430_probe);
+ return platform_driver_register(&omap2430_driver);
}
subsys_initcall(omap2430_init);
diff --git a/drivers/usb/musb/omap2430.h b/drivers/usb/musb/omap2430.h
index 40b3c02ae9f..1b5e83a9840 100644
--- a/drivers/usb/musb/omap2430.h
+++ b/drivers/usb/musb/omap2430.h
@@ -10,7 +10,7 @@
#ifndef __MUSB_OMAP243X_H__
#define __MUSB_OMAP243X_H__
-#include <plat/usb.h>
+#include <linux/platform_data/usb-omap.h>
/*
* OMAP2430-specific definitions
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
index 1f405616e6c..159ef4be1ef 100644
--- a/drivers/usb/musb/tusb6010.c
+++ b/drivers/usb/musb/tusb6010.c
@@ -17,18 +17,21 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/init.h>
+#include <linux/err.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_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);
@@ -40,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;
@@ -56,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",
@@ -82,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 \
@@ -152,7 +152,7 @@ tusb_fifo_write_unaligned(void __iomem *fifo, const u8 *buf, u16 len)
}
static inline void tusb_fifo_read_unaligned(void __iomem *fifo,
- void __iomem *buf, u16 len)
+ void *buf, u16 len)
{
u32 val;
int i;
@@ -196,7 +196,7 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *buf)
/* Best case is 32bit-aligned destination address */
if ((0x02 & (unsigned long) buf) == 0) {
if (len >= 4) {
- writesl(fifo, buf, len >> 2);
+ iowrite32_rep(fifo, buf, len >> 2);
buf += (len & ~0x03);
len &= 0x03;
}
@@ -243,7 +243,7 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *buf)
/* Best case is 32bit-aligned destination address */
if ((0x02 & (unsigned long) buf) == 0) {
if (len >= 4) {
- readsl(fifo, buf, len >> 2);
+ ioread32_rep(fifo, buf, len >> 2);
buf += (len & ~0x03);
len &= 0x03;
}
@@ -277,7 +277,7 @@ static struct musb *the_musb;
* mode), or low power Default-B sessions, something else supplies power.
* Caller must take care of locking.
*/
-static int tusb_draw_power(struct otg_transceiver *x, unsigned mA)
+static int tusb_draw_power(struct usb_phy *x, unsigned mA)
{
struct musb *musb = the_musb;
void __iomem *tbase = musb->ctrl_base;
@@ -293,7 +293,7 @@ static int tusb_draw_power(struct otg_transceiver *x, unsigned mA)
* The actual current usage would be very board-specific. For now,
* it's simpler to just use an aggregate (also board-specific).
*/
- if (x->default_a || mA < (musb->min_power << 1))
+ if (x->otg->default_a || mA < (musb->min_power << 1))
mA = 0;
reg = musb_readl(tbase, TUSB_PRCM_MNGMT);
@@ -347,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);
@@ -420,7 +420,7 @@ static void musb_do_idle(unsigned long _musb)
&& (musb->idle_timeout == 0
|| time_after(jiffies, musb->idle_timeout))) {
dev_dbg(musb->controller, "Nothing connected %s, turning off VBUS\n",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
}
/* FALLTHROUGH */
case OTG_STATE_A_IDLE:
@@ -436,14 +436,13 @@ static void musb_do_idle(unsigned long _musb)
if (is_host_active(musb) && (musb->port1_status >> 16))
goto done;
- if (is_peripheral_enabled(musb) && !musb->gadget_driver) {
+ if (!musb->gadget_driver) {
wakeups = 0;
} else {
wakeups = TUSB_PRCM_WHOSTDISCON
| TUSB_PRCM_WBUS
| TUSB_PRCM_WVBUS;
- if (is_otg_enabled(musb))
- wakeups |= TUSB_PRCM_WID;
+ wakeups |= TUSB_PRCM_WID;
}
tusb_allow_idle(musb, wakeups);
}
@@ -476,7 +475,7 @@ static void tusb_musb_try_idle(struct musb *musb, unsigned long timeout)
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",
- otg_state_string(musb->xceiv->state));
+ usb_otg_state_string(musb->xceiv->state));
del_timer(&musb_idle_timer);
last_timer = jiffies;
return;
@@ -493,7 +492,7 @@ static void tusb_musb_try_idle(struct musb *musb, unsigned long timeout)
last_timer = timeout;
dev_dbg(musb->controller, "%s inactive, for idle timer for %lu ms\n",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
(unsigned long)jiffies_to_msecs(timeout - jiffies));
mod_timer(&musb_idle_timer, timeout);
}
@@ -510,6 +509,7 @@ static void tusb_musb_set_vbus(struct musb *musb, int is_on)
void __iomem *tbase = musb->ctrl_base;
u32 conf, prcm, timer;
u8 devctl;
+ struct usb_otg *otg = musb->xceiv->otg;
/* HDRC controls CPEN, but beware current surges during device
* connect. They can trigger transient overcurrent conditions
@@ -522,7 +522,7 @@ static void tusb_musb_set_vbus(struct musb *musb, int is_on)
if (is_on) {
timer = OTG_TIMER_MS(OTG_TIME_A_WAIT_VRISE);
- musb->xceiv->default_a = 1;
+ otg->default_a = 1;
musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
devctl |= MUSB_DEVCTL_SESSION;
@@ -548,11 +548,11 @@ static void tusb_musb_set_vbus(struct musb *musb, int is_on)
musb->xceiv->state = OTG_STATE_A_IDLE;
}
musb->is_active = 0;
- musb->xceiv->default_a = 1;
+ otg->default_a = 1;
MUSB_HST_MODE(musb);
} else {
musb->is_active = 0;
- musb->xceiv->default_a = 0;
+ otg->default_a = 0;
musb->xceiv->state = OTG_STATE_B_IDLE;
MUSB_DEV_MODE(musb);
}
@@ -568,7 +568,7 @@ static void tusb_musb_set_vbus(struct musb *musb, int is_on)
musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
dev_dbg(musb->controller, "VBUS %s, devctl %02x otg %3x conf %08x prcm %08x\n",
- otg_state_string(musb->xceiv->state),
+ usb_otg_state_string(musb->xceiv->state),
musb_readb(musb->mregs, MUSB_DEVCTL),
musb_readl(tbase, TUSB_DEV_OTG_STAT),
conf, prcm);
@@ -580,21 +580,12 @@ static void tusb_musb_set_vbus(struct musb *musb, int is_on)
*
* Note that if a mini-A cable is plugged in the ID line will stay down as
* the weak ID pull-up is not able to pull the ID up.
- *
- * REVISIT: It would be possible to add support for changing between host
- * and peripheral modes in non-OTG configurations by reconfiguring hardware
- * and then setting musb->board_mode. For now, only support OTG mode.
*/
static int tusb_musb_set_mode(struct musb *musb, u8 musb_mode)
{
void __iomem *tbase = musb->ctrl_base;
u32 otg_stat, phy_otg_ctrl, phy_otg_ena, dev_conf;
- if (musb->board_mode != MUSB_OTG) {
- ERR("Changing mode currently only supported in OTG mode\n");
- return -EINVAL;
- }
-
otg_stat = musb_readl(tbase, TUSB_DEV_OTG_STAT);
phy_otg_ctrl = musb_readl(tbase, TUSB_PHY_OTG_CTRL);
phy_otg_ena = musb_readl(tbase, TUSB_PHY_OTG_CTRL_ENABLE);
@@ -644,17 +635,15 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
{
u32 otg_stat = musb_readl(tbase, TUSB_DEV_OTG_STAT);
unsigned long idle_timeout = 0;
+ struct usb_otg *otg = musb->xceiv->otg;
/* ID pin */
if ((int_src & TUSB_INT_SRC_ID_STATUS_CHNG)) {
int default_a;
- if (is_otg_enabled(musb))
- default_a = !(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS);
- else
- default_a = is_host_enabled(musb);
+ default_a = !(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS);
dev_dbg(musb->controller, "Default-%c\n", default_a ? 'A' : 'B');
- musb->xceiv->default_a = default_a;
+ otg->default_a = default_a;
tusb_musb_set_vbus(musb, default_a);
/* Don't allow idling immediately */
@@ -666,8 +655,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
if (int_src & TUSB_INT_SRC_VBUS_SENSE_CHNG) {
/* B-dev state machine: no vbus ~= disconnect */
- if ((is_otg_enabled(musb) && !musb->xceiv->default_a)
- || !is_host_enabled(musb)) {
+ if (!otg->default_a) {
/* ? musb_root_disconnect(musb); */
musb->port1_status &=
~(USB_PORT_STAT_CONNECTION
@@ -687,13 +675,13 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
musb->is_active = 0;
}
dev_dbg(musb->controller, "vbus change, %s, otg %03x\n",
- otg_state_string(musb->xceiv->state), otg_stat);
+ usb_otg_state_string(musb->xceiv->state), otg_stat);
idle_timeout = jiffies + (1 * HZ);
schedule_work(&musb->irq_work);
} else /* A-dev state machine */ {
dev_dbg(musb->controller, "vbus change, %s, otg %03x\n",
- otg_state_string(musb->xceiv->state), otg_stat);
+ usb_otg_state_string(musb->xceiv->state), otg_stat);
switch (musb->xceiv->state) {
case OTG_STATE_A_IDLE:
@@ -742,7 +730,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
u8 devctl;
dev_dbg(musb->controller, "%s timer, %03x\n",
- otg_state_string(musb->xceiv->state), otg_stat);
+ usb_otg_state_string(musb->xceiv->state), otg_stat);
switch (musb->xceiv->state) {
case OTG_STATE_A_WAIT_VRISE:
@@ -807,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 ... */
@@ -1021,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;
}
@@ -1075,10 +1064,9 @@ static int tusb_musb_init(struct musb *musb)
void __iomem *sync = NULL;
int ret;
- usb_nop_xceiv_register();
- musb->xceiv = otg_get_transceiver();
- if (!musb->xceiv)
- return -ENODEV;
+ musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
+ if (IS_ERR_OR_NULL(musb->xceiv))
+ return -EPROBE_DEFER;
pdev = to_platform_device(musb->controller);
@@ -1116,10 +1104,8 @@ static int tusb_musb_init(struct musb *musb)
}
musb->isr = tusb_musb_interrupt;
- if (is_peripheral_enabled(musb)) {
- musb->xceiv->set_power = tusb_draw_power;
- the_musb = musb;
- }
+ musb->xceiv->set_power = tusb_draw_power;
+ the_musb = musb;
setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
@@ -1128,8 +1114,7 @@ done:
if (sync)
iounmap(sync);
- otg_put_transceiver(musb->xceiv);
- usb_nop_xceiv_unregister();
+ usb_put_phy(musb->xceiv);
}
return ret;
}
@@ -1144,8 +1129,7 @@ static int tusb_musb_exit(struct musb *musb)
iounmap(musb->sync_va);
- otg_put_transceiver(musb->xceiv);
- usb_nop_xceiv_unregister();
+ usb_put_phy(musb->xceiv);
return 0;
}
@@ -1163,14 +1147,19 @@ 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 __init tusb_probe(struct platform_device *pdev)
+static int tusb_probe(struct platform_device *pdev)
{
- struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
+ struct resource musb_resources[3];
+ 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);
@@ -1179,67 +1168,68 @@ static int __init tusb_probe(struct platform_device *pdev)
goto err0;
}
- musb = platform_device_alloc("musb-hdrc", -1);
- 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);
- ret = platform_device_add_resources(musb, pdev->resource,
- pdev->num_resources);
- if (ret) {
- dev_err(&pdev->dev, "failed to add resources\n");
- goto err2;
- }
-
- ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
- if (ret) {
- dev_err(&pdev->dev, "failed to add platform_data\n");
- goto err2;
- }
-
- ret = platform_device_add(musb);
- if (ret) {
- dev_err(&pdev->dev, "failed to register musb device\n");
- goto err1;
+ memset(musb_resources, 0x00, sizeof(*musb_resources) *
+ ARRAY_SIZE(musb_resources));
+
+ musb_resources[0].name = pdev->resource[0].name;
+ musb_resources[0].start = pdev->resource[0].start;
+ musb_resources[0].end = pdev->resource[0].end;
+ musb_resources[0].flags = pdev->resource[0].flags;
+
+ musb_resources[1].name = pdev->resource[1].name;
+ musb_resources[1].start = pdev->resource[1].start;
+ musb_resources[1].end = pdev->resource[1].end;
+ musb_resources[1].flags = pdev->resource[1].flags;
+
+ 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 = 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;
-err2:
- platform_device_put(musb);
-
-err1:
+err3:
kfree(glue);
err0:
return ret;
}
-static int __exit tusb_remove(struct platform_device *pdev)
+static int tusb_remove(struct platform_device *pdev)
{
struct tusb6010_glue *glue = platform_get_drvdata(pdev);
- platform_device_del(glue->musb);
- platform_device_put(glue->musb);
+ platform_device_unregister(glue->musb);
+ usb_phy_generic_unregister(glue->phy);
kfree(glue);
return 0;
}
static struct platform_driver tusb_driver = {
- .remove = __exit_p(tusb_remove),
+ .probe = tusb_probe,
+ .remove = tusb_remove,
.driver = {
.name = "musb-tusb",
},
@@ -1248,15 +1238,4 @@ static struct platform_driver tusb_driver = {
MODULE_DESCRIPTION("TUSB6010 MUSB Glue Layer");
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
MODULE_LICENSE("GPL v2");
-
-static int __init tusb_init(void)
-{
- return platform_driver_probe(&tusb_driver, tusb_probe);
-}
-subsys_initcall(tusb_init);
-
-static void __exit tusb_exit(void)
-{
- platform_driver_unregister(&tusb_driver);
-}
-module_exit(tusb_exit);
+module_platform_driver(tusb_driver);
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 b67b4bc596c..3ce152c0408 100644
--- a/drivers/usb/musb/tusb6010_omap.c
+++ b/drivers/usb/musb/tusb6010_omap.c
@@ -11,13 +11,11 @@
#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>
#include <linux/slab.h>
-#include <plat/dma.h>
-#include <plat/mux.h>
+#include <linux/omap-dma.h>
#include "musb_core.h"
#include "tusb6010.h"
@@ -26,6 +24,13 @@
#define MAX_DMAREQ 5 /* REVISIT: Really 6, but req5 not OK */
+#define OMAP24XX_DMA_EXT_DMAREQ0 2
+#define OMAP24XX_DMA_EXT_DMAREQ1 3
+#define OMAP242X_DMA_EXT_DMAREQ2 14
+#define OMAP242X_DMA_EXT_DMAREQ3 15
+#define OMAP242X_DMA_EXT_DMAREQ4 16
+#define OMAP242X_DMA_EXT_DMAREQ5 64
+
struct tusb_omap_dma_ch {
struct musb *musb;
void __iomem *tbase;
@@ -60,28 +65,6 @@ struct tusb_omap_dma {
unsigned multichannel:1;
};
-static int tusb_omap_dma_start(struct dma_controller *c)
-{
- struct tusb_omap_dma *tusb_dma;
-
- tusb_dma = container_of(c, struct tusb_omap_dma, controller);
-
- /* dev_dbg(musb->controller, "ep%i ch: %i\n", chdat->epnum, chdat->ch); */
-
- return 0;
-}
-
-static int tusb_omap_dma_stop(struct dma_controller *c)
-{
- struct tusb_omap_dma *tusb_dma;
-
- tusb_dma = container_of(c, struct tusb_omap_dma, controller);
-
- /* dev_dbg(musb->controller, "ep%i ch: %i\n", chdat->epnum, chdat->ch); */
-
- return 0;
-}
-
/*
* Allocate dmareq0 to the current channel unless it's already taken
*/
@@ -662,8 +645,7 @@ void dma_controller_destroy(struct dma_controller *c)
kfree(tusb_dma);
}
-struct dma_controller *__init
-dma_controller_create(struct musb *musb, void __iomem *base)
+struct dma_controller *dma_controller_create(struct musb *musb, void __iomem *base)
{
void __iomem *tbase = musb->ctrl_base;
struct tusb_omap_dma *tusb_dma;
@@ -690,14 +672,12 @@ dma_controller_create(struct musb *musb, void __iomem *base)
tusb_dma->dmareq = -1;
tusb_dma->sync_dev = -1;
- tusb_dma->controller.start = tusb_omap_dma_start;
- tusb_dma->controller.stop = tusb_omap_dma_stop;
tusb_dma->controller.channel_alloc = tusb_omap_dma_allocate;
tusb_dma->controller.channel_release = tusb_omap_dma_release;
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 f7e04bf34a1..f202e508846 100644
--- a/drivers/usb/musb/ux500.c
+++ b/drivers/usb/musb/ux500.c
@@ -21,13 +21,22 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/init.h>
#include <linux/clk.h>
+#include <linux/err.h>
#include <linux/io.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
+#include <linux/usb/musb-ux500.h>
#include "musb_core.h"
+static struct musb_hdrc_config ux500_musb_hdrc_config = {
+ .multipoint = true,
+ .dyn_fifo = true,
+ .num_eps = 16,
+ .ram_bits = 16,
+};
+
struct ux500_glue {
struct device *dev;
struct platform_device *musb;
@@ -35,20 +44,145 @@ struct ux500_glue {
};
#define glue_to_musb(g) platform_get_drvdata(g->musb)
+static void ux500_musb_set_vbus(struct musb *musb, int is_on)
+{
+ u8 devctl;
+ unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+ /* HDRC controls CPEN, but beware current surges during device
+ * connect. They can trigger transient overcurrent conditions
+ * that must be ignored.
+ */
+
+ devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+
+ if (is_on) {
+ if (musb->xceiv->state == OTG_STATE_A_IDLE) {
+ /* start the session */
+ devctl |= MUSB_DEVCTL_SESSION;
+ musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+ /*
+ * Wait for the musb to set as A device to enable the
+ * VBUS
+ */
+ while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) {
+
+ if (time_after(jiffies, timeout)) {
+ dev_err(musb->controller,
+ "configured as A device timeout");
+ break;
+ }
+ }
+
+ } else {
+ musb->is_active = 1;
+ musb->xceiv->otg->default_a = 1;
+ musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
+ devctl |= MUSB_DEVCTL_SESSION;
+ MUSB_HST_MODE(musb);
+ }
+ } else {
+ musb->is_active = 0;
+
+ /* NOTE: we're skipping A_WAIT_VFALL -> A_IDLE and jumping
+ * right to B_IDLE...
+ */
+ musb->xceiv->otg->default_a = 0;
+ devctl &= ~MUSB_DEVCTL_SESSION;
+ MUSB_DEV_MODE(musb);
+ }
+ musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+
+ /*
+ * Devctl values will be updated after vbus goes below
+ * session_valid. The time taken depends on the capacitance
+ * on VBUS line. The max discharge time can be upto 1 sec
+ * as per the spec. Typically on our platform, it is 200ms
+ */
+ if (!is_on)
+ mdelay(200);
+
+ dev_dbg(musb->controller, "VBUS %s, devctl %02x\n",
+ usb_otg_state_string(musb->xceiv->state),
+ musb_readb(musb->mregs, MUSB_DEVCTL));
+}
+
+static int musb_otg_notifications(struct notifier_block *nb,
+ unsigned long event, void *unused)
+{
+ struct musb *musb = container_of(nb, struct musb, nb);
+
+ dev_dbg(musb->controller, "musb_otg_notifications %ld %s\n",
+ event, usb_otg_state_string(musb->xceiv->state));
+
+ switch (event) {
+ case UX500_MUSB_ID:
+ dev_dbg(musb->controller, "ID GND\n");
+ ux500_musb_set_vbus(musb, 1);
+ break;
+ case UX500_MUSB_VBUS:
+ dev_dbg(musb->controller, "VBUS Connect\n");
+ break;
+ case UX500_MUSB_NONE:
+ dev_dbg(musb->controller, "VBUS Disconnect\n");
+ if (is_host_active(musb))
+ ux500_musb_set_vbus(musb, 0);
+ else
+ musb->xceiv->state = OTG_STATE_B_IDLE;
+ break;
+ default:
+ dev_dbg(musb->controller, "ID float\n");
+ return NOTIFY_DONE;
+ }
+ return NOTIFY_OK;
+}
+
+static irqreturn_t ux500_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);
+
+ if (musb->int_usb || musb->int_tx || musb->int_rx)
+ retval = musb_interrupt(musb);
+
+ spin_unlock_irqrestore(&musb->lock, flags);
+
+ return retval;
+}
+
static int ux500_musb_init(struct musb *musb)
{
- musb->xceiv = otg_get_transceiver();
- if (!musb->xceiv) {
+ int status;
+
+ musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
+ if (IS_ERR_OR_NULL(musb->xceiv)) {
pr_err("HS USB OTG: no transceiver configured\n");
- return -ENODEV;
+ return -EPROBE_DEFER;
}
+ musb->nb.notifier_call = musb_otg_notifications;
+ status = usb_register_notifier(musb->xceiv, &musb->nb);
+ if (status < 0) {
+ dev_dbg(musb->controller, "notification register failed\n");
+ return status;
+ }
+
+ musb->isr = ux500_musb_interrupt;
+
return 0;
}
static int ux500_musb_exit(struct musb *musb)
{
- otg_put_transceiver(musb->xceiv);
+ usb_unregister_notifier(musb->xceiv, &musb->nb);
+
+ usb_put_phy(musb->xceiv);
return 0;
}
@@ -56,44 +190,89 @@ static int ux500_musb_exit(struct musb *musb)
static const struct musb_platform_ops ux500_ops = {
.init = ux500_musb_init,
.exit = ux500_musb_exit,
+
+ .set_vbus = ux500_musb_set_vbus,
};
-static int __init ux500_probe(struct platform_device *pdev)
+static struct musb_hdrc_platform_data *
+ux500_of_probe(struct platform_device *pdev, struct device_node *np)
{
- struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
+ struct musb_hdrc_platform_data *pdata;
+ const char *mode;
+ int strlen;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return NULL;
+
+ mode = of_get_property(np, "dr_mode", &strlen);
+ if (!mode) {
+ dev_err(&pdev->dev, "No 'dr_mode' property found\n");
+ return NULL;
+ }
+
+ if (strlen > 0) {
+ if (!strcmp(mode, "host"))
+ pdata->mode = MUSB_HOST;
+ if (!strcmp(mode, "otg"))
+ pdata->mode = MUSB_OTG;
+ if (!strcmp(mode, "peripheral"))
+ pdata->mode = MUSB_PERIPHERAL;
+ }
+
+ return pdata;
+}
+
+static int ux500_probe(struct platform_device *pdev)
+{
+ struct resource musb_resources[2];
+ struct musb_hdrc_platform_data *pdata = dev_get_platdata(&pdev->dev);
+ struct device_node *np = pdev->dev.of_node;
struct platform_device *musb;
struct ux500_glue *glue;
struct clk *clk;
-
int ret = -ENOMEM;
+ if (!pdata) {
+ if (np) {
+ pdata = ux500_of_probe(pdev, np);
+ if (!pdata)
+ goto err0;
+
+ pdev->dev.platform_data = pdata;
+ } else {
+ dev_err(&pdev->dev, "no pdata or device tree found\n");
+ goto err0;
+ }
+ }
+
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
if (!glue) {
dev_err(&pdev->dev, "failed to allocate glue context\n");
goto err0;
}
- musb = platform_device_alloc("musb-hdrc", -1);
+ 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");
+ clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(clk)) {
dev_err(&pdev->dev, "failed to get clock\n");
ret = PTR_ERR(clk);
- goto err2;
+ goto err3;
}
- ret = clk_enable(clk);
+ ret = clk_prepare_enable(clk);
if (ret) {
dev_err(&pdev->dev, "failed to enable clock\n");
- goto err3;
+ goto err4;
}
musb->dev.parent = &pdev->dev;
- musb->dev.dma_mask = pdev->dev.dma_mask;
+ musb->dev.dma_mask = &pdev->dev.coherent_dma_mask;
musb->dev.coherent_dma_mask = pdev->dev.coherent_dma_mask;
glue->dev = &pdev->dev;
@@ -101,37 +280,51 @@ static int __init ux500_probe(struct platform_device *pdev)
glue->clk = clk;
pdata->platform_ops = &ux500_ops;
+ pdata->config = &ux500_musb_hdrc_config;
platform_set_drvdata(pdev, glue);
- ret = platform_device_add_resources(musb, pdev->resource,
- pdev->num_resources);
+ memset(musb_resources, 0x00, sizeof(*musb_resources) *
+ ARRAY_SIZE(musb_resources));
+
+ musb_resources[0].name = pdev->resource[0].name;
+ musb_resources[0].start = pdev->resource[0].start;
+ musb_resources[0].end = pdev->resource[0].end;
+ musb_resources[0].flags = pdev->resource[0].flags;
+
+ musb_resources[1].name = pdev->resource[1].name;
+ musb_resources[1].start = pdev->resource[1].start;
+ 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 err4;
+ goto err5;
}
ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
if (ret) {
dev_err(&pdev->dev, "failed to add platform_data\n");
- goto err4;
+ goto err5;
}
ret = platform_device_add(musb);
if (ret) {
dev_err(&pdev->dev, "failed to register musb device\n");
- goto err4;
+ goto err5;
}
return 0;
-err4:
- clk_disable(clk);
+err5:
+ clk_disable_unprepare(clk);
-err3:
+err4:
clk_put(clk);
-err2:
+err3:
platform_device_put(musb);
err1:
@@ -141,13 +334,12 @@ err0:
return ret;
}
-static int __exit ux500_remove(struct platform_device *pdev)
+static int ux500_remove(struct platform_device *pdev)
{
struct ux500_glue *glue = platform_get_drvdata(pdev);
- platform_device_del(glue->musb);
- platform_device_put(glue->musb);
- clk_disable(glue->clk);
+ platform_device_unregister(glue->musb);
+ clk_disable_unprepare(glue->clk);
clk_put(glue->clk);
kfree(glue);
@@ -160,8 +352,8 @@ static int ux500_suspend(struct device *dev)
struct ux500_glue *glue = dev_get_drvdata(dev);
struct musb *musb = glue_to_musb(glue);
- otg_set_suspend(musb->xceiv, 1);
- clk_disable(glue->clk);
+ usb_phy_set_suspend(musb->xceiv, 1);
+ clk_disable_unprepare(glue->clk);
return 0;
}
@@ -172,47 +364,36 @@ static int ux500_resume(struct device *dev)
struct musb *musb = glue_to_musb(glue);
int ret;
- ret = clk_enable(glue->clk);
+ ret = clk_prepare_enable(glue->clk);
if (ret) {
dev_err(dev, "failed to enable clock\n");
return ret;
}
- otg_set_suspend(musb->xceiv, 0);
+ usb_phy_set_suspend(musb->xceiv, 0);
return 0;
}
+#endif
-static const struct dev_pm_ops ux500_pm_ops = {
- .suspend = ux500_suspend,
- .resume = ux500_resume,
-};
+static SIMPLE_DEV_PM_OPS(ux500_pm_ops, ux500_suspend, ux500_resume);
-#define DEV_PM_OPS (&ux500_pm_ops)
-#else
-#define DEV_PM_OPS NULL
-#endif
+static const struct of_device_id ux500_match[] = {
+ { .compatible = "stericsson,db8500-musb", },
+ {}
+};
static struct platform_driver ux500_driver = {
- .remove = __exit_p(ux500_remove),
+ .probe = ux500_probe,
+ .remove = ux500_remove,
.driver = {
.name = "musb-ux500",
- .pm = DEV_PM_OPS,
+ .pm = &ux500_pm_ops,
+ .of_match_table = ux500_match,
},
};
MODULE_DESCRIPTION("UX500 MUSB Glue Layer");
MODULE_AUTHOR("Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>");
MODULE_LICENSE("GPL v2");
-
-static int __init ux500_init(void)
-{
- return platform_driver_probe(&ux500_driver, ux500_probe);
-}
-subsys_initcall(ux500_init);
-
-static void __exit ux500_exit(void)
-{
- platform_driver_unregister(&ux500_driver);
-}
-module_exit(ux500_exit);
+module_platform_driver(ux500_driver);
diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c
index 97cb45916c4..9aad00f11bd 100644
--- a/drivers/usb/musb/ux500_dma.c
+++ b/drivers/usb/musb/ux500_dma.c
@@ -1,7 +1,7 @@
/*
* drivers/usb/musb/ux500_dma.c
*
- * U8500 and U5500 DMA support code
+ * U8500 DMA support code
*
* Copyright (C) 2009 STMicroelectronics
* Copyright (C) 2011 ST-Ericsson SA
@@ -30,9 +30,15 @@
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/pfn.h>
-#include <mach/usb.h>
+#include <linux/sizes.h>
+#include <linux/platform_data/usb-musb-ux500.h>
#include "musb_core.h"
+static const char *iep_chan_names[] = { "iep_1_9", "iep_2_10", "iep_3_11", "iep_4_12",
+ "iep_5_13", "iep_6_14", "iep_7_15", "iep_8" };
+static const char *oep_chan_names[] = { "oep_1_9", "oep_2_10", "oep_3_11", "oep_4_12",
+ "oep_5_13", "oep_6_14", "oep_7_15", "oep_8" };
+
struct ux500_dma_channel {
struct dma_channel channel;
struct ux500_dma_controller *controller;
@@ -47,16 +53,14 @@ struct ux500_dma_channel {
struct ux500_dma_controller {
struct dma_controller controller;
- struct ux500_dma_channel rx_channel[UX500_MUSB_DMA_NUM_RX_CHANNELS];
- struct ux500_dma_channel tx_channel[UX500_MUSB_DMA_NUM_TX_CHANNELS];
- u32 num_rx_channels;
- u32 num_tx_channels;
+ struct ux500_dma_channel rx_channel[UX500_MUSB_DMA_NUM_RX_TX_CHANNELS];
+ struct ux500_dma_channel tx_channel[UX500_MUSB_DMA_NUM_RX_TX_CHANNELS];
void *private_data;
dma_addr_t phy_base;
};
/* Work function invoked from DMA callback to handle rx transfers. */
-void ux500_dma_callback(void *private_data)
+static void ux500_dma_callback(void *private_data)
{
struct dma_channel *channel = private_data;
struct ux500_dma_channel *ux500_channel = channel->private_data;
@@ -70,8 +74,7 @@ void ux500_dma_callback(void *private_data)
spin_lock_irqsave(&musb->lock, flags);
ux500_channel->channel.actual_len = ux500_channel->cur_len;
ux500_channel->channel.status = MUSB_DMA_STATUS_FREE;
- musb_dma_completion(musb, hw_ep->epnum,
- ux500_channel->is_tx);
+ musb_dma_completion(musb, hw_ep->epnum, ux500_channel->is_tx);
spin_unlock_irqrestore(&musb->lock, flags);
}
@@ -93,8 +96,9 @@ static bool ux500_configure_channel(struct dma_channel *channel,
struct musb *musb = ux500_channel->controller->private_data;
dev_dbg(musb->controller,
- "packet_sz=%d, mode=%d, dma_addr=0x%x, len=%d is_tx=%d\n",
- packet_sz, mode, dma_addr, len, ux500_channel->is_tx);
+ "packet_sz=%d, mode=%d, dma_addr=0x%llu, len=%d is_tx=%d\n",
+ packet_sz, mode, (unsigned long long) dma_addr,
+ len, ux500_channel->is_tx);
ux500_channel->cur_len = len;
@@ -115,12 +119,12 @@ static bool ux500_configure_channel(struct dma_channel *channel,
slave_conf.dst_addr = usb_fifo_addr;
slave_conf.dst_addr_width = addr_width;
slave_conf.dst_maxburst = 16;
+ slave_conf.device_fc = false;
dma_chan->device->device_control(dma_chan, DMA_SLAVE_CONFIG,
(unsigned long) &slave_conf);
- dma_desc = dma_chan->device->
- device_prep_slave_sg(dma_chan, &sg, 1, direction,
+ dma_desc = dmaengine_prep_slave_sg(dma_chan, &sg, 1, direction,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!dma_desc)
return false;
@@ -142,19 +146,15 @@ static struct dma_channel *ux500_dma_channel_allocate(struct dma_controller *c,
struct ux500_dma_channel *ux500_channel = NULL;
struct musb *musb = controller->private_data;
u8 ch_num = hw_ep->epnum - 1;
- u32 max_ch;
- /* Max 8 DMA channels (0 - 7). Each DMA channel can only be allocated
+ /* 8 DMA channels (0 - 7). Each DMA channel can only be allocated
* to specified hw_ep. For example DMA channel 0 can only be allocated
* to hw_ep 1 and 9.
*/
if (ch_num > 7)
ch_num -= 8;
- max_ch = is_tx ? controller->num_tx_channels :
- controller->num_rx_channels;
-
- if (ch_num >= max_ch)
+ if (ch_num >= UX500_MUSB_DMA_NUM_RX_TX_CHANNELS)
return NULL;
ux500_channel = is_tx ? &(controller->tx_channel[ch_num]) :
@@ -191,7 +191,7 @@ static int ux500_dma_is_compatible(struct dma_channel *channel,
u16 maxpacket, void *buf, u32 length)
{
if ((maxpacket & 0x3) ||
- ((int)buf & 0x3) ||
+ ((unsigned long int) buf & 0x3) ||
(length < 512) ||
(length & 0x3))
return false;
@@ -254,15 +254,13 @@ static int ux500_dma_channel_abort(struct dma_channel *channel)
return 0;
}
-static int ux500_dma_controller_stop(struct dma_controller *c)
+static void ux500_dma_controller_stop(struct ux500_dma_controller *controller)
{
- struct ux500_dma_controller *controller = container_of(c,
- struct ux500_dma_controller, controller);
struct ux500_dma_channel *ux500_channel;
struct dma_channel *channel;
u8 ch_num;
- for (ch_num = 0; ch_num < controller->num_rx_channels; ch_num++) {
+ for (ch_num = 0; ch_num < UX500_MUSB_DMA_NUM_RX_TX_CHANNELS; ch_num++) {
channel = &controller->rx_channel[ch_num].channel;
ux500_channel = channel->private_data;
@@ -272,7 +270,7 @@ static int ux500_dma_controller_stop(struct dma_controller *c)
dma_release_channel(ux500_channel->dma_chan);
}
- for (ch_num = 0; ch_num < controller->num_tx_channels; ch_num++) {
+ for (ch_num = 0; ch_num < UX500_MUSB_DMA_NUM_RX_TX_CHANNELS; ch_num++) {
channel = &controller->tx_channel[ch_num].channel;
ux500_channel = channel->private_data;
@@ -281,46 +279,44 @@ static int ux500_dma_controller_stop(struct dma_controller *c)
if (ux500_channel->dma_chan)
dma_release_channel(ux500_channel->dma_chan);
}
-
- return 0;
}
-static int ux500_dma_controller_start(struct dma_controller *c)
+static int ux500_dma_controller_start(struct ux500_dma_controller *controller)
{
- struct ux500_dma_controller *controller = container_of(c,
- struct ux500_dma_controller, controller);
struct ux500_dma_channel *ux500_channel = NULL;
struct musb *musb = controller->private_data;
struct device *dev = musb->controller;
- struct musb_hdrc_platform_data *plat = dev->platform_data;
- struct ux500_musb_board_data *data = plat->board_data;
+ struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
+ struct ux500_musb_board_data *data;
struct dma_channel *dma_channel = NULL;
+ char **chan_names;
u32 ch_num;
u8 dir;
u8 is_tx = 0;
void **param_array;
struct ux500_dma_channel *channel_array;
- u32 ch_count;
dma_cap_mask_t mask;
- if ((data->num_rx_channels > UX500_MUSB_DMA_NUM_RX_CHANNELS) ||
- (data->num_tx_channels > UX500_MUSB_DMA_NUM_TX_CHANNELS))
+ if (!plat) {
+ dev_err(musb->controller, "No platform data\n");
return -EINVAL;
+ }
- controller->num_rx_channels = data->num_rx_channels;
- controller->num_tx_channels = data->num_tx_channels;
+ data = plat->board_data;
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
/* Prepare the loop for RX channels */
channel_array = controller->rx_channel;
- ch_count = data->num_rx_channels;
- param_array = data->dma_rx_param_array;
+ param_array = data ? data->dma_rx_param_array : NULL;
+ chan_names = (char **)iep_chan_names;
for (dir = 0; dir < 2; dir++) {
- for (ch_num = 0; ch_num < ch_count; ch_num++) {
+ for (ch_num = 0;
+ ch_num < UX500_MUSB_DMA_NUM_RX_TX_CHANNELS;
+ ch_num++) {
ux500_channel = &channel_array[ch_num];
ux500_channel->controller = controller;
ux500_channel->ch_num = ch_num;
@@ -331,15 +327,25 @@ static int ux500_dma_controller_start(struct dma_controller *c)
dma_channel->status = MUSB_DMA_STATUS_FREE;
dma_channel->max_len = SZ_16M;
- ux500_channel->dma_chan = dma_request_channel(mask,
- data->dma_filter,
- param_array[ch_num]);
+ ux500_channel->dma_chan =
+ dma_request_slave_channel(dev, chan_names[ch_num]);
+
+ if (!ux500_channel->dma_chan)
+ ux500_channel->dma_chan =
+ dma_request_channel(mask,
+ data ?
+ data->dma_filter :
+ NULL,
+ param_array ?
+ param_array[ch_num] :
+ NULL);
+
if (!ux500_channel->dma_chan) {
ERR("Dma pipe allocation error dir=%d ch=%d\n",
dir, ch_num);
/* Release already allocated channels */
- ux500_dma_controller_stop(c);
+ ux500_dma_controller_stop(controller);
return -EBUSY;
}
@@ -348,8 +354,8 @@ static int ux500_dma_controller_start(struct dma_controller *c)
/* Prepare the loop for TX channels */
channel_array = controller->tx_channel;
- ch_count = data->num_tx_channels;
- param_array = data->dma_tx_param_array;
+ param_array = data ? data->dma_tx_param_array : NULL;
+ chan_names = (char **)oep_chan_names;
is_tx = 1;
}
@@ -361,33 +367,46 @@ void dma_controller_destroy(struct dma_controller *c)
struct ux500_dma_controller *controller = container_of(c,
struct ux500_dma_controller, controller);
+ ux500_dma_controller_stop(controller);
kfree(controller);
}
-struct dma_controller *__init
-dma_controller_create(struct musb *musb, void __iomem *base)
+struct dma_controller *dma_controller_create(struct musb *musb,
+ void __iomem *base)
{
struct ux500_dma_controller *controller;
struct platform_device *pdev = to_platform_device(musb->controller);
struct resource *iomem;
+ int ret;
controller = kzalloc(sizeof(*controller), GFP_KERNEL);
if (!controller)
- return NULL;
+ goto kzalloc_fail;
controller->private_data = musb;
/* Save physical address for DMA controller. */
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!iomem) {
+ dev_err(musb->controller, "no memory resource defined\n");
+ goto plat_get_fail;
+ }
+
controller->phy_base = (dma_addr_t) iomem->start;
- controller->controller.start = ux500_dma_controller_start;
- controller->controller.stop = ux500_dma_controller_stop;
controller->controller.channel_alloc = ux500_dma_channel_allocate;
controller->controller.channel_release = ux500_dma_channel_release;
controller->controller.channel_program = ux500_dma_channel_program;
controller->controller.channel_abort = ux500_dma_channel_abort;
controller->controller.is_compatible = ux500_dma_is_compatible;
+ ret = ux500_dma_controller_start(controller);
+ if (ret)
+ goto plat_get_fail;
return &controller->controller;
+
+plat_get_fail:
+ kfree(controller);
+kzalloc_fail:
+ return NULL;
}