usb: musb: patches for v3.7 merge window

Here we have a bunch of miscellaneous cleanups and fixes
 to the musb driver. It fixes a bunch of mistakes errors
 which nobody has triggered before, so I'm not Ccing stable
 tree.
 
 We are finally improving OMAP's VBUS/ID Mailbox usage so
 that we can introduce our PHY drivers properly. Also, we're
 adding support for multiple instances of the MUSB IP in
 the same SoC, as seen on some platforms from TI which
 have 2 MUSB instances.
 
 Other than that, we have some small fixes like not kicking
 DMA for a zero byte transfer, or properly handling NAK timeout
 on MUSB's host side, and the enabling of DMA Mode1 for any
 transfers which are aligned to wMaxPacketSize.
 
 All patches have been pending on mailing list for a long time
 and I don't expect any big surprises with this pull request.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.12 (GNU/Linux)
 
 iQIcBAABAgAGBQJQT1XLAAoJEIaOsuA1yqREsfMP/jae2huECuECrWtm76TNm6Kl
 +1Movls2IkrYuVIM/QzSSqrmQ0BUVyOYjf1Uuke3tFA1KwkZsITZ12UONokiUGDd
 EuPP0RfXSiwdVNWF6cyJ8PiT5JWXD2fRJn3L22pXSiA4MvocLXM0yJiHrsM5q3Hd
 idg2npo7LEbLI3y1NDRdzR36Gk3y3K40U/ovXSQQQilhyk4yv7wpSbLqOR1UkkN/
 Xcf2FiRb1xFYRdu1HoSHRnIW0CmC2a8MbpAcOuUSoPqH5HIiouA0Cc4Wt5xki4y3
 +e0D0xpGK/Kt42nDkNoi51TaCw6aSY+GOqEFcI96o2/pq819nlcAzOGI77WGQIXX
 sLud3oYsESdc++ux1+jaEX9xju41NyzColxDHn4AnplYF2t4fbTd36Loxed9xco/
 LzHaaK3v1Ll30XiRiEnO5RBcgcwXDfFCMOUIDyVaVqNgCuYRrJIuhoXdlXvhEHAt
 GQjFn/+8izIncVZ2rPQ1H2thshlmVWgrZ4kEwnbKLYtv2sqAVHBN/iaN25iQlm/l
 Jva8ecXKl+9n92++X7vL8X/OmdVecBLey9eoqS+C+a0Kn9pSedOlUgkYpz8lGL38
 dBPZ5Zjukl7J+gQ45ol5IN3cuYA+QcAZjHR1VEkeR7otAY5xsEun7vmyBoY4qazz
 rUGhbofXB1gtGhUaaDBj
 =UHPu
 -----END PGP SIGNATURE-----

Merge tag 'musb-for-v3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb into usb-next

usb: musb: patches for v3.7 merge window

Here we have a bunch of miscellaneous cleanups and fixes
to the musb driver. It fixes a bunch of mistakes errors
which nobody has triggered before, so I'm not Ccing stable
tree.

We are finally improving OMAP's VBUS/ID Mailbox usage so
that we can introduce our PHY drivers properly. Also, we're
adding support for multiple instances of the MUSB IP in
the same SoC, as seen on some platforms from TI which
have 2 MUSB instances.

Other than that, we have some small fixes like not kicking
DMA for a zero byte transfer, or properly handling NAK timeout
on MUSB's host side, and the enabling of DMA Mode1 for any
transfers which are aligned to wMaxPacketSize.

All patches have been pending on mailing list for a long time
and I don't expect any big surprises with this pull request.
This commit is contained in:
Greg Kroah-Hartman 2012-09-11 13:56:29 -07:00
commit 1cd572fc0c
25 changed files with 923 additions and 658 deletions

View File

@ -0,0 +1,14 @@
AM33XX MUSB GLUE
- compatible : Should be "ti,musb-am33xx"
- ti,hwmods : must be "usb_otg_hs"
- multipoint : Should be "1" indicating the musb controller supports
multipoint. This is a MUSB configuration-specific setting.
- num_eps : Specifies the number of endpoints. This is also a
MUSB configuration-specific setting. Should be set to "16"
- ram_bits : Specifies the ram address size. Should be set to "12"
- port0_mode : Should be "3" to represent OTG. "1" signifies HOST and "2"
represents PERIPHERAL.
- port1_mode : Should be "1" to represent HOST. "3" signifies OTG and "2"
represents PERIPHERAL.
- power : Should be "250". This signifies the controller can supply upto
500mA when operating in host mode.

View File

@ -0,0 +1,33 @@
OMAP GLUE
OMAP MUSB GLUE
- compatible : Should be "ti,omap4-musb" or "ti,omap3-musb"
- ti,hwmods : must be "usb_otg_hs"
- multipoint : Should be "1" indicating the musb controller supports
multipoint. This is a MUSB configuration-specific setting.
- num_eps : Specifies the number of endpoints. This is also a
MUSB configuration-specific setting. Should be set to "16"
- ram_bits : Specifies the ram address size. Should be set to "12"
- interface_type : This is a board specific setting to describe the type of
interface between the controller and the phy. It should be "0" or "1"
specifying ULPI and UTMI respectively.
- mode : Should be "3" to represent OTG. "1" signifies HOST and "2"
represents PERIPHERAL.
- power : Should be "50". This signifies the controller can supply upto
100mA when operating in host mode.
SOC specific device node entry
usb_otg_hs: usb_otg_hs@4a0ab000 {
compatible = "ti,omap4-musb";
ti,hwmods = "usb_otg_hs";
multipoint = <1>;
num_eps = <16>;
ram_bits = <12>;
};
Board specific device node entry
&usb_otg_hs {
interface_type = <1>;
mode = <3>;
power = <50>;
};

View File

@ -5890,6 +5890,12 @@ static struct omap_hwmod_addr_space omap44xx_usb_otg_hs_addrs[] = {
.pa_end = 0x4a0ab003, .pa_end = 0x4a0ab003,
.flags = ADDR_TYPE_RT .flags = ADDR_TYPE_RT
}, },
{
/* XXX: Remove this once control module driver is in place */
.pa_start = 0x4a00233c,
.pa_end = 0x4a00233f,
.flags = ADDR_TYPE_RT
},
{ } { }
}; };

View File

@ -19,7 +19,7 @@ config USB_MUSB_HDRC
it's being used with, including the USB peripheral role, it's being used with, including the USB peripheral role,
or the USB host role, or both. 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. (35x, 644x ...), OMAP 243x, OMAP 3, and TUSB 6010.
Analog Devices parts using this IP include Blackfin BF54x, Analog Devices parts using this IP include Blackfin BF54x,

View File

@ -108,9 +108,8 @@ static void am35x_musb_enable(struct musb *musb)
musb_writel(reg_base, CORE_INTR_MASK_SET_REG, AM35X_INTR_USB_MASK); 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. */ /* 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,
musb_writel(reg_base, CORE_INTR_SRC_SET_REG, AM35X_INTR_DRVVBUS << AM35X_INTR_USB_SHIFT);
AM35X_INTR_DRVVBUS << AM35X_INTR_USB_SHIFT);
} }
/* /*
@ -174,9 +173,6 @@ static void otg_timer(unsigned long _musb)
MUSB_INTR_VBUSERROR << AM35X_INTR_USB_SHIFT); MUSB_INTR_VBUSERROR << AM35X_INTR_USB_SHIFT);
break; break;
case OTG_STATE_B_IDLE: case OTG_STATE_B_IDLE:
if (!is_peripheral_enabled(musb))
break;
devctl = musb_readb(mregs, MUSB_DEVCTL); devctl = musb_readb(mregs, MUSB_DEVCTL);
if (devctl & MUSB_DEVCTL_BDEVICE) if (devctl & MUSB_DEVCTL_BDEVICE)
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
@ -193,9 +189,6 @@ static void am35x_musb_try_idle(struct musb *musb, unsigned long timeout)
{ {
static unsigned long last_timer; static unsigned long last_timer;
if (!is_otg_enabled(musb))
return;
if (timeout == 0) if (timeout == 0)
timeout = jiffies + msecs_to_jiffies(3); timeout = jiffies + msecs_to_jiffies(3);
@ -272,8 +265,7 @@ static irqreturn_t am35x_musb_interrupt(int irq, void *hci)
u8 devctl = musb_readb(mregs, MUSB_DEVCTL); u8 devctl = musb_readb(mregs, MUSB_DEVCTL);
int err; int err;
err = is_host_enabled(musb) && (musb->int_usb & err = musb->int_usb & MUSB_INTR_VBUSERROR;
MUSB_INTR_VBUSERROR);
if (err) { if (err) {
/* /*
* The Mentor core doesn't debounce VBUS as needed * The Mentor core doesn't debounce VBUS as needed
@ -290,7 +282,7 @@ static irqreturn_t am35x_musb_interrupt(int irq, void *hci)
musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
WARNING("VBUS error workaround (delay coming)\n"); WARNING("VBUS error workaround (delay coming)\n");
} else if (is_host_enabled(musb) && drvvbus) { } else if (drvvbus) {
MUSB_HST_MODE(musb); MUSB_HST_MODE(musb);
otg->default_a = 1; otg->default_a = 1;
musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
@ -327,7 +319,7 @@ eoi:
} }
/* Poll for ID change */ /* 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); mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
spin_unlock_irqrestore(&musb->lock, flags); spin_unlock_irqrestore(&musb->lock, flags);
@ -370,8 +362,7 @@ static int am35x_musb_init(struct musb *musb)
if (IS_ERR_OR_NULL(musb->xceiv)) if (IS_ERR_OR_NULL(musb->xceiv))
return -ENODEV; return -ENODEV;
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 */ /* Reset the musb */
if (data->reset) if (data->reset)
@ -401,8 +392,7 @@ static int am35x_musb_exit(struct musb *musb)
struct musb_hdrc_platform_data *plat = dev->platform_data; struct musb_hdrc_platform_data *plat = dev->platform_data;
struct omap_musb_board_data *data = plat->board_data; 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. */ /* Shutdown the on-chip PHY and its PLL. */
if (data->set_phy_power) if (data->set_phy_power)
@ -469,6 +459,7 @@ static int __devinit am35x_probe(struct platform_device *pdev)
struct clk *clk; struct clk *clk;
int ret = -ENOMEM; int ret = -ENOMEM;
int musbid;
glue = kzalloc(sizeof(*glue), GFP_KERNEL); glue = kzalloc(sizeof(*glue), GFP_KERNEL);
if (!glue) { if (!glue) {
@ -476,38 +467,47 @@ static int __devinit am35x_probe(struct platform_device *pdev)
goto err0; goto err0;
} }
musb = platform_device_alloc("musb-hdrc", -1); /* get the musb id */
musbid = musb_get_id(&pdev->dev, GFP_KERNEL);
if (musbid < 0) {
dev_err(&pdev->dev, "failed to allocate musb id\n");
ret = -ENOMEM;
goto err1;
}
musb = platform_device_alloc("musb-hdrc", musbid);
if (!musb) { if (!musb) {
dev_err(&pdev->dev, "failed to allocate musb device\n"); dev_err(&pdev->dev, "failed to allocate musb device\n");
goto err1; goto err2;
} }
phy_clk = clk_get(&pdev->dev, "fck"); phy_clk = clk_get(&pdev->dev, "fck");
if (IS_ERR(phy_clk)) { if (IS_ERR(phy_clk)) {
dev_err(&pdev->dev, "failed to get PHY clock\n"); dev_err(&pdev->dev, "failed to get PHY clock\n");
ret = PTR_ERR(phy_clk); ret = PTR_ERR(phy_clk);
goto err2; goto err3;
} }
clk = clk_get(&pdev->dev, "ick"); clk = clk_get(&pdev->dev, "ick");
if (IS_ERR(clk)) { if (IS_ERR(clk)) {
dev_err(&pdev->dev, "failed to get clock\n"); dev_err(&pdev->dev, "failed to get clock\n");
ret = PTR_ERR(clk); ret = PTR_ERR(clk);
goto err3; goto err4;
} }
ret = clk_enable(phy_clk); ret = clk_enable(phy_clk);
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to enable PHY clock\n"); dev_err(&pdev->dev, "failed to enable PHY clock\n");
goto err4; goto err5;
} }
ret = clk_enable(clk); ret = clk_enable(clk);
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to enable clock\n"); dev_err(&pdev->dev, "failed to enable clock\n");
goto err5; goto err6;
} }
musb->id = musbid;
musb->dev.parent = &pdev->dev; musb->dev.parent = &pdev->dev;
musb->dev.dma_mask = &am35x_dmamask; musb->dev.dma_mask = &am35x_dmamask;
musb->dev.coherent_dma_mask = am35x_dmamask; musb->dev.coherent_dma_mask = am35x_dmamask;
@ -525,38 +525,41 @@ static int __devinit am35x_probe(struct platform_device *pdev)
pdev->num_resources); pdev->num_resources);
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to add resources\n"); dev_err(&pdev->dev, "failed to add resources\n");
goto err6; goto err7;
} }
ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to add platform_data\n"); dev_err(&pdev->dev, "failed to add platform_data\n");
goto err6; goto err7;
} }
ret = platform_device_add(musb); ret = platform_device_add(musb);
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to register musb device\n"); dev_err(&pdev->dev, "failed to register musb device\n");
goto err6; goto err7;
} }
return 0; return 0;
err6: err7:
clk_disable(clk); clk_disable(clk);
err5: err6:
clk_disable(phy_clk); clk_disable(phy_clk);
err4: err5:
clk_put(clk); clk_put(clk);
err3: err4:
clk_put(phy_clk); clk_put(phy_clk);
err2: err3:
platform_device_put(musb); platform_device_put(musb);
err2:
musb_put_id(&pdev->dev, musbid);
err1: err1:
kfree(glue); kfree(glue);
@ -568,6 +571,7 @@ static int __devexit am35x_remove(struct platform_device *pdev)
{ {
struct am35x_glue *glue = platform_get_drvdata(pdev); struct am35x_glue *glue = platform_get_drvdata(pdev);
musb_put_id(&pdev->dev, glue->musb->id);
platform_device_del(glue->musb); platform_device_del(glue->musb);
platform_device_put(glue->musb); platform_device_put(glue->musb);
clk_disable(glue->clk); clk_disable(glue->clk);

View File

@ -185,8 +185,8 @@ static irqreturn_t blackfin_interrupt(int irq, void *__hci)
} }
/* Start sampling ID pin, when plug is removed from MUSB */ /* Start sampling ID pin, when plug is removed from MUSB */
if ((is_otg_enabled(musb) && (musb->xceiv->state == OTG_STATE_B_IDLE if ((musb->xceiv->state == OTG_STATE_B_IDLE
|| musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) || || musb->xceiv->state == OTG_STATE_A_WAIT_BCON) ||
(musb->int_usb & MUSB_INTR_DISCONNECT && is_host_active(musb))) { (musb->int_usb & MUSB_INTR_DISCONNECT && is_host_active(musb))) {
mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
musb->a_wait_bcon = TIMER_DELAY; musb->a_wait_bcon = TIMER_DELAY;
@ -229,18 +229,13 @@ static void musb_conn_timer_handler(unsigned long _musb)
val = MUSB_INTR_SUSPEND | MUSB_INTR_VBUSERROR; val = MUSB_INTR_SUSPEND | MUSB_INTR_VBUSERROR;
musb_writeb(musb->mregs, MUSB_INTRUSB, val); musb_writeb(musb->mregs, MUSB_INTRUSB, val);
if (is_otg_enabled(musb)) musb->xceiv->state = OTG_STATE_B_IDLE;
musb->xceiv->state = OTG_STATE_B_IDLE;
else
musb_writeb(musb->mregs, MUSB_POWER, MUSB_POWER_HSENAB);
} }
mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY); mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
break; break;
case OTG_STATE_B_IDLE: case OTG_STATE_B_IDLE:
/*
if (!is_peripheral_enabled(musb)) * Start a new session. It seems that MUSB needs taking
break;
/* Start a new session. It seems that MUSB needs taking
* some time to recognize the type of the plug inserted? * some time to recognize the type of the plug inserted?
*/ */
val = musb_readw(musb->mregs, MUSB_DEVCTL); val = musb_readw(musb->mregs, MUSB_DEVCTL);
@ -296,10 +291,7 @@ static void musb_conn_timer_handler(unsigned long _musb)
static void bfin_musb_enable(struct musb *musb) static void bfin_musb_enable(struct musb *musb)
{ {
if (!is_otg_enabled(musb) && is_host_enabled(musb)) { /* REVISIT is this really correct ? */
mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
musb->a_wait_bcon = TIMER_DELAY;
}
} }
static void bfin_musb_disable(struct musb *musb) static void bfin_musb_disable(struct musb *musb)
@ -324,12 +316,6 @@ static int bfin_musb_set_power(struct usb_phy *x, unsigned mA)
return 0; 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) static int bfin_musb_vbus_status(struct musb *musb)
{ {
return 0; return 0;
@ -425,12 +411,10 @@ static int bfin_musb_init(struct musb *musb)
bfin_musb_reg_init(musb); bfin_musb_reg_init(musb);
if (is_host_enabled(musb)) { setup_timer(&musb_conn_timer, musb_conn_timer_handler,
setup_timer(&musb_conn_timer, (unsigned long) musb);
musb_conn_timer_handler, (unsigned long) musb);
} musb->xceiv->set_power = bfin_musb_set_power;
if (is_peripheral_enabled(musb))
musb->xceiv->set_power = bfin_musb_set_power;
musb->isr = blackfin_interrupt; musb->isr = blackfin_interrupt;
musb->double_buffer_not_ok = true; musb->double_buffer_not_ok = true;
@ -455,7 +439,6 @@ static const struct musb_platform_ops bfin_ops = {
.disable = bfin_musb_disable, .disable = bfin_musb_disable,
.set_mode = bfin_musb_set_mode, .set_mode = bfin_musb_set_mode,
.try_idle = bfin_musb_try_idle,
.vbus_status = bfin_musb_vbus_status, .vbus_status = bfin_musb_vbus_status,
.set_vbus = bfin_musb_set_vbus, .set_vbus = bfin_musb_set_vbus,
@ -472,6 +455,7 @@ static int __devinit bfin_probe(struct platform_device *pdev)
struct bfin_glue *glue; struct bfin_glue *glue;
int ret = -ENOMEM; int ret = -ENOMEM;
int musbid;
glue = kzalloc(sizeof(*glue), GFP_KERNEL); glue = kzalloc(sizeof(*glue), GFP_KERNEL);
if (!glue) { if (!glue) {
@ -479,12 +463,21 @@ static int __devinit bfin_probe(struct platform_device *pdev)
goto err0; goto err0;
} }
musb = platform_device_alloc("musb-hdrc", -1); /* get the musb id */
if (!musb) { musbid = musb_get_id(&pdev->dev, GFP_KERNEL);
dev_err(&pdev->dev, "failed to allocate musb device\n"); if (musbid < 0) {
dev_err(&pdev->dev, "failed to allocate musb id\n");
ret = -ENOMEM;
goto err1; goto err1;
} }
musb = platform_device_alloc("musb-hdrc", musbid);
if (!musb) {
dev_err(&pdev->dev, "failed to allocate musb device\n");
goto err2;
}
musb->id = musbid;
musb->dev.parent = &pdev->dev; musb->dev.parent = &pdev->dev;
musb->dev.dma_mask = &bfin_dmamask; musb->dev.dma_mask = &bfin_dmamask;
musb->dev.coherent_dma_mask = bfin_dmamask; musb->dev.coherent_dma_mask = bfin_dmamask;
@ -500,26 +493,29 @@ static int __devinit bfin_probe(struct platform_device *pdev)
pdev->num_resources); pdev->num_resources);
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to add resources\n"); dev_err(&pdev->dev, "failed to add resources\n");
goto err2; goto err3;
} }
ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to add platform_data\n"); dev_err(&pdev->dev, "failed to add platform_data\n");
goto err2; goto err3;
} }
ret = platform_device_add(musb); ret = platform_device_add(musb);
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to register musb device\n"); dev_err(&pdev->dev, "failed to register musb device\n");
goto err2; goto err3;
} }
return 0; return 0;
err2: err3:
platform_device_put(musb); platform_device_put(musb);
err2:
musb_put_id(&pdev->dev, musbid);
err1: err1:
kfree(glue); kfree(glue);
@ -531,6 +527,7 @@ static int __devexit bfin_remove(struct platform_device *pdev)
{ {
struct bfin_glue *glue = platform_get_drvdata(pdev); struct bfin_glue *glue = platform_get_drvdata(pdev);
musb_put_id(&pdev->dev, glue->musb->id);
platform_device_del(glue->musb); platform_device_del(glue->musb);
platform_device_put(glue->musb); platform_device_put(glue->musb);
kfree(glue); kfree(glue);

View File

@ -1316,7 +1316,7 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id)
} }
/* Instantiate a software object representing a DMA controller. */ /* Instantiate a software object representing a DMA controller. */
struct dma_controller *__init struct dma_controller *__devinit
dma_controller_create(struct musb *musb, void __iomem *mregs) dma_controller_create(struct musb *musb, void __iomem *mregs)
{ {
struct cppi *controller; struct cppi *controller;

View File

@ -156,9 +156,8 @@ static void da8xx_musb_enable(struct musb *musb)
musb_writel(reg_base, DA8XX_USB_INTR_MASK_SET_REG, mask); musb_writel(reg_base, DA8XX_USB_INTR_MASK_SET_REG, mask);
/* Force the DRVVBUS IRQ so we can start polling for ID change. */ /* 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,
musb_writel(reg_base, DA8XX_USB_INTR_SRC_SET_REG, DA8XX_INTR_DRVVBUS << DA8XX_INTR_USB_SHIFT);
DA8XX_INTR_DRVVBUS << DA8XX_INTR_USB_SHIFT);
} }
/** /**
@ -232,9 +231,6 @@ static void otg_timer(unsigned long _musb)
MUSB_INTR_VBUSERROR << DA8XX_INTR_USB_SHIFT); MUSB_INTR_VBUSERROR << DA8XX_INTR_USB_SHIFT);
break; break;
case OTG_STATE_B_IDLE: 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 * when to switch to the A-Default state machine (by setting
@ -264,9 +260,6 @@ static void da8xx_musb_try_idle(struct musb *musb, unsigned long timeout)
{ {
static unsigned long last_timer; static unsigned long last_timer;
if (!is_otg_enabled(musb))
return;
if (timeout == 0) if (timeout == 0)
timeout = jiffies + msecs_to_jiffies(3); timeout = jiffies + msecs_to_jiffies(3);
@ -334,8 +327,7 @@ static irqreturn_t da8xx_musb_interrupt(int irq, void *hci)
u8 devctl = musb_readb(mregs, MUSB_DEVCTL); u8 devctl = musb_readb(mregs, MUSB_DEVCTL);
int err; int err;
err = is_host_enabled(musb) && (musb->int_usb & err = musb->int_usb & USB_INTR_VBUSERROR;
MUSB_INTR_VBUSERROR);
if (err) { if (err) {
/* /*
* The Mentor core doesn't debounce VBUS as needed * The Mentor core doesn't debounce VBUS as needed
@ -352,7 +344,7 @@ static irqreturn_t da8xx_musb_interrupt(int irq, void *hci)
musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
WARNING("VBUS error workaround (delay coming)\n"); WARNING("VBUS error workaround (delay coming)\n");
} else if (is_host_enabled(musb) && drvvbus) { } else if (drvvbus) {
MUSB_HST_MODE(musb); MUSB_HST_MODE(musb);
otg->default_a = 1; otg->default_a = 1;
musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
@ -383,7 +375,7 @@ static irqreturn_t da8xx_musb_interrupt(int irq, void *hci)
musb_writel(reg_base, DA8XX_USB_END_OF_INTR_REG, 0); musb_writel(reg_base, DA8XX_USB_END_OF_INTR_REG, 0);
/* Poll for ID change */ /* 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); mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
spin_unlock_irqrestore(&musb->lock, flags); spin_unlock_irqrestore(&musb->lock, flags);
@ -431,8 +423,7 @@ static int da8xx_musb_init(struct musb *musb)
if (IS_ERR_OR_NULL(musb->xceiv)) if (IS_ERR_OR_NULL(musb->xceiv))
goto fail; 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 */ /* Reset the controller */
musb_writel(reg_base, DA8XX_USB_CTRL_REG, DA8XX_SOFT_RESET_MASK); musb_writel(reg_base, DA8XX_USB_CTRL_REG, DA8XX_SOFT_RESET_MASK);
@ -455,8 +446,7 @@ fail:
static int da8xx_musb_exit(struct musb *musb) 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(); phy_off();
@ -490,6 +480,7 @@ static int __devinit da8xx_probe(struct platform_device *pdev)
struct clk *clk; struct clk *clk;
int ret = -ENOMEM; int ret = -ENOMEM;
int musbid;
glue = kzalloc(sizeof(*glue), GFP_KERNEL); glue = kzalloc(sizeof(*glue), GFP_KERNEL);
if (!glue) { if (!glue) {
@ -497,25 +488,34 @@ static int __devinit da8xx_probe(struct platform_device *pdev)
goto err0; goto err0;
} }
musb = platform_device_alloc("musb-hdrc", -1); /* get the musb id */
musbid = musb_get_id(&pdev->dev, GFP_KERNEL);
if (musbid < 0) {
dev_err(&pdev->dev, "failed to allocate musb id\n");
ret = -ENOMEM;
goto err1;
}
musb = platform_device_alloc("musb-hdrc", musbid);
if (!musb) { if (!musb) {
dev_err(&pdev->dev, "failed to allocate musb device\n"); dev_err(&pdev->dev, "failed to allocate musb device\n");
goto err1; goto err2;
} }
clk = clk_get(&pdev->dev, "usb20"); clk = clk_get(&pdev->dev, "usb20");
if (IS_ERR(clk)) { if (IS_ERR(clk)) {
dev_err(&pdev->dev, "failed to get clock\n"); dev_err(&pdev->dev, "failed to get clock\n");
ret = PTR_ERR(clk); ret = PTR_ERR(clk);
goto err2; goto err3;
} }
ret = clk_enable(clk); ret = clk_enable(clk);
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to enable clock\n"); dev_err(&pdev->dev, "failed to enable clock\n");
goto err3; goto err4;
} }
musb->id = musbid;
musb->dev.parent = &pdev->dev; musb->dev.parent = &pdev->dev;
musb->dev.dma_mask = &da8xx_dmamask; musb->dev.dma_mask = &da8xx_dmamask;
musb->dev.coherent_dma_mask = da8xx_dmamask; musb->dev.coherent_dma_mask = da8xx_dmamask;
@ -532,32 +532,35 @@ static int __devinit da8xx_probe(struct platform_device *pdev)
pdev->num_resources); pdev->num_resources);
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to add resources\n"); dev_err(&pdev->dev, "failed to add resources\n");
goto err4; goto err5;
} }
ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to add platform_data\n"); dev_err(&pdev->dev, "failed to add platform_data\n");
goto err4; goto err5;
} }
ret = platform_device_add(musb); ret = platform_device_add(musb);
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to register musb device\n"); dev_err(&pdev->dev, "failed to register musb device\n");
goto err4; goto err5;
} }
return 0; return 0;
err4: err5:
clk_disable(clk); clk_disable(clk);
err3: err4:
clk_put(clk); clk_put(clk);
err2: err3:
platform_device_put(musb); platform_device_put(musb);
err2:
musb_put_id(&pdev->dev, musbid);
err1: err1:
kfree(glue); kfree(glue);
@ -569,6 +572,7 @@ static int __devexit da8xx_remove(struct platform_device *pdev)
{ {
struct da8xx_glue *glue = platform_get_drvdata(pdev); struct da8xx_glue *glue = platform_get_drvdata(pdev);
musb_put_id(&pdev->dev, glue->musb->id);
platform_device_del(glue->musb); platform_device_del(glue->musb);
platform_device_put(glue->musb); platform_device_put(glue->musb);
clk_disable(glue->clk); clk_disable(glue->clk);

View File

@ -116,8 +116,7 @@ static void davinci_musb_enable(struct musb *musb)
dma_off = 0; dma_off = 0;
/* force a DRVVBUS irq so we can start polling for ID change */ /* 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); DAVINCI_INTR_DRVVBUS << DAVINCI_USB_USBINT_SHIFT);
} }
@ -235,10 +234,8 @@ static void otg_timer(unsigned long _musb)
MUSB_INTR_VBUSERROR << DAVINCI_USB_USBINT_SHIFT); MUSB_INTR_VBUSERROR << DAVINCI_USB_USBINT_SHIFT);
break; break;
case OTG_STATE_B_IDLE: 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 * when to switch to the A-Default state machine (by setting
* the DEVCTL.SESSION flag). * the DEVCTL.SESSION flag).
* *
@ -316,8 +313,7 @@ static irqreturn_t davinci_musb_interrupt(int irq, void *__hci)
u8 devctl = musb_readb(mregs, MUSB_DEVCTL); u8 devctl = musb_readb(mregs, MUSB_DEVCTL);
int err = musb->int_usb & MUSB_INTR_VBUSERROR; int err = musb->int_usb & MUSB_INTR_VBUSERROR;
err = is_host_enabled(musb) err = musb->int_usb & MUSB_INTR_VBUSERROR;
&& (musb->int_usb & MUSB_INTR_VBUSERROR);
if (err) { if (err) {
/* The Mentor core doesn't debounce VBUS as needed /* The Mentor core doesn't debounce VBUS as needed
* to cope with device connect current spikes. This * to cope with device connect current spikes. This
@ -333,7 +329,7 @@ static irqreturn_t davinci_musb_interrupt(int irq, void *__hci)
musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
WARNING("VBUS error workaround (delay coming)\n"); WARNING("VBUS error workaround (delay coming)\n");
} else if (is_host_enabled(musb) && drvvbus) { } else if (drvvbus) {
MUSB_HST_MODE(musb); MUSB_HST_MODE(musb);
otg->default_a = 1; otg->default_a = 1;
musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
@ -366,8 +362,7 @@ static irqreturn_t davinci_musb_interrupt(int irq, void *__hci)
musb_writel(tibase, DAVINCI_USB_EOI_REG, 0); musb_writel(tibase, DAVINCI_USB_EOI_REG, 0);
/* poll for ID change */ /* poll for ID change */
if (is_otg_enabled(musb) if (musb->xceiv->state == OTG_STATE_B_IDLE)
&& musb->xceiv->state == OTG_STATE_B_IDLE)
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
spin_unlock_irqrestore(&musb->lock, flags); spin_unlock_irqrestore(&musb->lock, flags);
@ -398,8 +393,7 @@ static int davinci_musb_init(struct musb *musb)
if (revision == 0) if (revision == 0)
goto fail; 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); davinci_musb_source_power(musb, 0, 1);
@ -420,12 +414,7 @@ static int davinci_musb_init(struct musb *musb)
if (cpu_is_davinci_dm355()) { if (cpu_is_davinci_dm355()) {
u32 deepsleep = __raw_readl(DM355_DEEPSLEEP); u32 deepsleep = __raw_readl(DM355_DEEPSLEEP);
if (is_host_enabled(musb)) { deepsleep &= ~DRVVBUS_FORCE;
deepsleep &= ~DRVVBUS_OVERRIDE;
} else {
deepsleep &= ~DRVVBUS_FORCE;
deepsleep |= DRVVBUS_OVERRIDE;
}
__raw_writel(deepsleep, DM355_DEEPSLEEP); __raw_writel(deepsleep, DM355_DEEPSLEEP);
} }
@ -454,8 +443,7 @@ unregister:
static int davinci_musb_exit(struct musb *musb) 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 */ /* force VBUS off */
if (cpu_is_davinci_dm355()) { if (cpu_is_davinci_dm355()) {
@ -469,7 +457,7 @@ static int davinci_musb_exit(struct musb *musb)
davinci_musb_source_power(musb, 0 /*off*/, 1); davinci_musb_source_power(musb, 0 /*off*/, 1);
/* delay, to avoid problems with module reload */ /* delay, to avoid problems with module reload */
if (is_host_enabled(musb) && musb->xceiv->otg->default_a) { if (musb->xceiv->otg->default_a) {
int maxdelay = 30; int maxdelay = 30;
u8 devctl, warn = 0; u8 devctl, warn = 0;
@ -524,6 +512,7 @@ static int __devinit davinci_probe(struct platform_device *pdev)
struct clk *clk; struct clk *clk;
int ret = -ENOMEM; int ret = -ENOMEM;
int musbid;
glue = kzalloc(sizeof(*glue), GFP_KERNEL); glue = kzalloc(sizeof(*glue), GFP_KERNEL);
if (!glue) { if (!glue) {
@ -531,25 +520,34 @@ static int __devinit davinci_probe(struct platform_device *pdev)
goto err0; goto err0;
} }
musb = platform_device_alloc("musb-hdrc", -1); /* get the musb id */
musbid = musb_get_id(&pdev->dev, GFP_KERNEL);
if (musbid < 0) {
dev_err(&pdev->dev, "failed to allocate musb id\n");
ret = -ENOMEM;
goto err1;
}
musb = platform_device_alloc("musb-hdrc", musbid);
if (!musb) { if (!musb) {
dev_err(&pdev->dev, "failed to allocate musb device\n"); dev_err(&pdev->dev, "failed to allocate musb device\n");
goto err1; goto err2;
} }
clk = clk_get(&pdev->dev, "usb"); clk = clk_get(&pdev->dev, "usb");
if (IS_ERR(clk)) { if (IS_ERR(clk)) {
dev_err(&pdev->dev, "failed to get clock\n"); dev_err(&pdev->dev, "failed to get clock\n");
ret = PTR_ERR(clk); ret = PTR_ERR(clk);
goto err2; goto err3;
} }
ret = clk_enable(clk); ret = clk_enable(clk);
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to enable clock\n"); dev_err(&pdev->dev, "failed to enable clock\n");
goto err3; goto err4;
} }
musb->id = musbid;
musb->dev.parent = &pdev->dev; musb->dev.parent = &pdev->dev;
musb->dev.dma_mask = &davinci_dmamask; musb->dev.dma_mask = &davinci_dmamask;
musb->dev.coherent_dma_mask = davinci_dmamask; musb->dev.coherent_dma_mask = davinci_dmamask;
@ -566,32 +564,35 @@ static int __devinit davinci_probe(struct platform_device *pdev)
pdev->num_resources); pdev->num_resources);
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to add resources\n"); dev_err(&pdev->dev, "failed to add resources\n");
goto err4; goto err5;
} }
ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to add platform_data\n"); dev_err(&pdev->dev, "failed to add platform_data\n");
goto err4; goto err5;
} }
ret = platform_device_add(musb); ret = platform_device_add(musb);
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to register musb device\n"); dev_err(&pdev->dev, "failed to register musb device\n");
goto err4; goto err5;
} }
return 0; return 0;
err4: err5:
clk_disable(clk); clk_disable(clk);
err3: err4:
clk_put(clk); clk_put(clk);
err2: err3:
platform_device_put(musb); platform_device_put(musb);
err2:
musb_put_id(&pdev->dev, musbid);
err1: err1:
kfree(glue); kfree(glue);
@ -603,6 +604,7 @@ static int __devexit davinci_remove(struct platform_device *pdev)
{ {
struct davinci_glue *glue = platform_get_drvdata(pdev); struct davinci_glue *glue = platform_get_drvdata(pdev);
musb_put_id(&pdev->dev, glue->musb->id);
platform_device_del(glue->musb); platform_device_del(glue->musb);
platform_device_put(glue->musb); platform_device_put(glue->musb);
clk_disable(glue->clk); clk_disable(glue->clk);

View File

@ -99,6 +99,8 @@
#include <linux/prefetch.h> #include <linux/prefetch.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/idr.h>
#include <linux/dma-mapping.h>
#include "musb_core.h" #include "musb_core.h"
@ -114,6 +116,7 @@
#define MUSB_DRIVER_NAME "musb-hdrc" #define MUSB_DRIVER_NAME "musb-hdrc"
const char musb_driver_name[] = MUSB_DRIVER_NAME; const char musb_driver_name[] = MUSB_DRIVER_NAME;
static DEFINE_IDA(musb_ida);
MODULE_DESCRIPTION(DRIVER_INFO); MODULE_DESCRIPTION(DRIVER_INFO);
MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_AUTHOR(DRIVER_AUTHOR);
@ -130,6 +133,35 @@ static inline struct musb *dev_to_musb(struct device *dev)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
int musb_get_id(struct device *dev, gfp_t gfp_mask)
{
int ret;
int id;
ret = ida_pre_get(&musb_ida, gfp_mask);
if (!ret) {
dev_err(dev, "failed to reserve resource for id\n");
return -ENOMEM;
}
ret = ida_get_new(&musb_ida, &id);
if (ret < 0) {
dev_err(dev, "failed to allocate a new id\n");
return ret;
}
return id;
}
EXPORT_SYMBOL_GPL(musb_get_id);
void musb_put_id(struct device *dev, int id)
{
dev_dbg(dev, "removing id %d\n", id);
ida_remove(&musb_ida, id);
}
EXPORT_SYMBOL_GPL(musb_put_id);
#ifndef CONFIG_BLACKFIN #ifndef CONFIG_BLACKFIN
static int musb_ulpi_read(struct usb_phy *phy, u32 offset) static int musb_ulpi_read(struct usb_phy *phy, u32 offset)
{ {
@ -234,6 +266,9 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
struct musb *musb = hw_ep->musb; struct musb *musb = hw_ep->musb;
void __iomem *fifo = hw_ep->fifo; void __iomem *fifo = hw_ep->fifo;
if (unlikely(len == 0))
return;
prefetch((u8 *)src); prefetch((u8 *)src);
dev_dbg(musb->controller, "%cX ep%d fifo %p count %d buf %p\n", dev_dbg(musb->controller, "%cX ep%d fifo %p count %d buf %p\n",
@ -276,6 +311,9 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
struct musb *musb = hw_ep->musb; struct musb *musb = hw_ep->musb;
void __iomem *fifo = hw_ep->fifo; 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", dev_dbg(musb->controller, "%cX ep%d fifo %p count %d buf %p\n",
'R', hw_ep->epnum, fifo, len, dst); 'R', hw_ep->epnum, fifo, len, dst);
@ -348,7 +386,7 @@ void musb_load_testpacket(struct musb *musb)
/* /*
* Handles OTG hnp timeouts, such as b_ase0_brst * 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; struct musb *musb = (struct musb *)data;
unsigned long flags; unsigned long flags;
@ -643,8 +681,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
break; break;
case OTG_STATE_B_PERIPHERAL: case OTG_STATE_B_PERIPHERAL:
musb_g_suspend(musb); musb_g_suspend(musb);
musb->is_active = is_otg_enabled(musb) musb->is_active = otg->gadget->b_hnp_enable;
&& otg->gadget->b_hnp_enable;
if (musb->is_active) { if (musb->is_active) {
musb->xceiv->state = OTG_STATE_B_WAIT_ACON; musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
dev_dbg(musb->controller, "HNP: Setting timer for b_ase0_brst\n"); dev_dbg(musb->controller, "HNP: Setting timer for b_ase0_brst\n");
@ -660,8 +697,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
break; break;
case OTG_STATE_A_HOST: case OTG_STATE_A_HOST:
musb->xceiv->state = OTG_STATE_A_SUSPEND; musb->xceiv->state = OTG_STATE_A_SUSPEND;
musb->is_active = is_otg_enabled(musb) musb->is_active = otg->host->b_hnp_enable;
&& otg->host->b_hnp_enable;
break; break;
case OTG_STATE_B_HOST: case OTG_STATE_B_HOST:
/* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */ /* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */
@ -749,7 +785,7 @@ b_host:
case OTG_STATE_A_SUSPEND: case OTG_STATE_A_SUSPEND:
usb_hcd_resume_root_hub(musb_to_hcd(musb)); usb_hcd_resume_root_hub(musb_to_hcd(musb));
musb_root_disconnect(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 musb_platform_try_idle(musb, jiffies
+ msecs_to_jiffies(musb->a_wait_bcon)); + msecs_to_jiffies(musb->a_wait_bcon));
break; break;
@ -787,7 +823,7 @@ b_host:
*/ */
if (int_usb & MUSB_INTR_RESET) { if (int_usb & MUSB_INTR_RESET) {
handled = IRQ_HANDLED; 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 * Looks like non-HS BABBLE can be ignored, but
* HS BABBLE is an error condition. For HS the solution * HS BABBLE is an error condition. For HS the solution
@ -801,7 +837,7 @@ b_host:
ERR("Stopping host session -- babble\n"); ERR("Stopping host session -- babble\n");
musb_writeb(musb->mregs, MUSB_DEVCTL, 0); musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
} }
} else if (is_peripheral_capable()) { } else {
dev_dbg(musb->controller, "BUS RESET as %s\n", dev_dbg(musb->controller, "BUS RESET as %s\n",
otg_state_string(musb->xceiv->state)); otg_state_string(musb->xceiv->state));
switch (musb->xceiv->state) { switch (musb->xceiv->state) {
@ -925,25 +961,16 @@ void musb_start(struct musb *musb)
devctl = musb_readb(regs, MUSB_DEVCTL); devctl = musb_readb(regs, MUSB_DEVCTL);
devctl &= ~MUSB_DEVCTL_SESSION; devctl &= ~MUSB_DEVCTL_SESSION;
if (is_otg_enabled(musb)) { /* session started after:
/* session started after: * (a) ID-grounded irq, host mode;
* (a) ID-grounded irq, host mode; * (b) vbus present/connect IRQ, peripheral mode;
* (b) vbus present/connect IRQ, peripheral mode; * (c) peripheral initiates, using SRP
* (c) peripheral initiates, using SRP */
*/ if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS)
if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) musb->is_active = 1;
musb->is_active = 1; else
else
devctl |= MUSB_DEVCTL_SESSION;
} else if (is_host_enabled(musb)) {
/* assume ID pin is hard-wired to ground */
devctl |= MUSB_DEVCTL_SESSION; 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_platform_enable(musb);
musb_writeb(regs, MUSB_DEVCTL, devctl); musb_writeb(regs, MUSB_DEVCTL, devctl);
} }
@ -1007,8 +1034,6 @@ static void musb_shutdown(struct platform_device *pdev)
musb_generic_disable(musb); musb_generic_disable(musb);
spin_unlock_irqrestore(&musb->lock, flags); 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_writeb(musb->mregs, MUSB_DEVCTL, 0);
musb_platform_exit(musb); musb_platform_exit(musb);
@ -1302,7 +1327,7 @@ done:
if (offset < 0) { if (offset < 0) {
pr_debug("%s: mem overrun, ep %d\n", pr_debug("%s: mem overrun, ep %d\n",
musb_driver_name, epn); musb_driver_name, epn);
return -EINVAL; return offset;
} }
epn++; epn++;
musb->nr_endpoints = max(epn, musb->nr_endpoints); musb->nr_endpoints = max(epn, musb->nr_endpoints);
@ -1330,7 +1355,7 @@ static int __devinit ep_config_from_hw(struct musb *musb)
{ {
u8 epnum = 0; u8 epnum = 0;
struct musb_hw_ep *hw_ep; struct musb_hw_ep *hw_ep;
void *mbase = musb->mregs; void __iomem *mbase = musb->mregs;
int ret = 0; int ret = 0;
dev_dbg(musb->controller, "<== static silicon ep config\n"); dev_dbg(musb->controller, "<== static silicon ep config\n");
@ -1571,13 +1596,10 @@ irqreturn_t musb_interrupt(struct musb *musb)
/* musb_ep_select(musb->mregs, ep_num); */ /* musb_ep_select(musb->mregs, ep_num); */
/* REVISIT just retval = ep->rx_irq(...) */ /* REVISIT just retval = ep->rx_irq(...) */
retval = IRQ_HANDLED; retval = IRQ_HANDLED;
if (devctl & MUSB_DEVCTL_HM) { if (devctl & MUSB_DEVCTL_HM)
if (is_host_capable()) musb_host_rx(musb, ep_num);
musb_host_rx(musb, ep_num); else
} else { musb_g_rx(musb, ep_num);
if (is_peripheral_capable())
musb_g_rx(musb, ep_num);
}
} }
reg >>= 1; reg >>= 1;
@ -1592,13 +1614,10 @@ irqreturn_t musb_interrupt(struct musb *musb)
/* musb_ep_select(musb->mregs, ep_num); */ /* musb_ep_select(musb->mregs, ep_num); */
/* REVISIT just retval |= ep->tx_irq(...) */ /* REVISIT just retval |= ep->tx_irq(...) */
retval = IRQ_HANDLED; retval = IRQ_HANDLED;
if (devctl & MUSB_DEVCTL_HM) { if (devctl & MUSB_DEVCTL_HM)
if (is_host_capable()) musb_host_tx(musb, ep_num);
musb_host_tx(musb, ep_num); else
} else { musb_g_tx(musb, ep_num);
if (is_peripheral_capable())
musb_g_tx(musb, ep_num);
}
} }
reg >>= 1; reg >>= 1;
ep_num++; ep_num++;
@ -1634,22 +1653,16 @@ void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit)
} else { } else {
/* endpoints 1..15 */ /* endpoints 1..15 */
if (transmit) { if (transmit) {
if (devctl & MUSB_DEVCTL_HM) { if (devctl & MUSB_DEVCTL_HM)
if (is_host_capable()) musb_host_tx(musb, epnum);
musb_host_tx(musb, epnum); else
} else { musb_g_tx(musb, epnum);
if (is_peripheral_capable())
musb_g_tx(musb, epnum);
}
} else { } else {
/* receive */ /* receive */
if (devctl & MUSB_DEVCTL_HM) { if (devctl & MUSB_DEVCTL_HM)
if (is_host_capable()) musb_host_rx(musb, epnum);
musb_host_rx(musb, epnum); else
} else { musb_g_rx(musb, epnum);
if (is_peripheral_capable())
musb_g_rx(musb, epnum);
}
} }
} }
} }
@ -1785,10 +1798,9 @@ static const struct attribute_group musb_attr_group = {
static void musb_irq_work(struct work_struct *data) static void musb_irq_work(struct work_struct *data)
{ {
struct musb *musb = container_of(data, struct musb, irq_work); struct musb *musb = container_of(data, struct musb, irq_work);
static int old_state;
if (musb->xceiv->state != old_state) { if (musb->xceiv->state != musb->xceiv_old_state) {
old_state = musb->xceiv->state; musb->xceiv_old_state = musb->xceiv->state;
sysfs_notify(&musb->controller->kobj, NULL, "mode"); sysfs_notify(&musb->controller->kobj, NULL, "mode");
} }
} }
@ -1862,15 +1874,15 @@ static void musb_free(struct musb *musb)
dma_controller_destroy(c); dma_controller_destroy(c);
} }
kfree(musb); usb_put_hcd(musb_to_hcd(musb));
} }
/* /*
* Perform generic per-controller initialization. * Perform generic per-controller initialization.
* *
* @pDevice: the controller (already clocked, etc) * @dev: the controller (already clocked, etc)
* @nIrq: irq * @nIrq: IRQ number
* @mregs: virtual address of controller registers, * @ctrl: virtual address of controller registers,
* not yet corrected for platform-specific offsets * not yet corrected for platform-specific offsets
*/ */
static int __devinit static int __devinit
@ -1879,6 +1891,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
int status; int status;
struct musb *musb; struct musb *musb;
struct musb_hdrc_platform_data *plat = dev->platform_data; struct musb_hdrc_platform_data *plat = dev->platform_data;
struct usb_hcd *hcd;
/* The driver might handle more features than the board; OK. /* The driver might handle more features than the board; OK.
* Fail when the board needs a feature that's not enabled. * Fail when the board needs a feature that's not enabled.
@ -1901,7 +1914,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
pm_runtime_enable(musb->controller); pm_runtime_enable(musb->controller);
spin_lock_init(&musb->lock); spin_lock_init(&musb->lock);
musb->board_mode = plat->mode;
musb->board_set_power = plat->set_power; musb->board_set_power = plat->set_power;
musb->min_power = plat->min_power; musb->min_power = plat->min_power;
musb->ops = plat->platform_ops; musb->ops = plat->platform_ops;
@ -1972,7 +1984,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
goto fail3; goto fail3;
} }
musb->nIrq = nIrq; musb->nIrq = nIrq;
/* FIXME this handles wakeup irqs wrong */ /* FIXME this handles wakeup irqs wrong */
if (enable_irq_wake(nIrq) == 0) { if (enable_irq_wake(nIrq) == 0) {
musb->irq_wake = 1; musb->irq_wake = 1;
device_init_wakeup(dev, 1); device_init_wakeup(dev, 1);
@ -1981,58 +1993,25 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
} }
/* host side needs more setup */ /* host side needs more setup */
if (is_host_enabled(musb)) { hcd = musb_to_hcd(musb);
struct usb_hcd *hcd = musb_to_hcd(musb); otg_set_host(musb->xceiv->otg, &hcd->self);
hcd->self.otg_port = 1;
musb->xceiv->otg->host = &hcd->self;
hcd->power_budget = 2 * (plat->power ? : 250);
otg_set_host(musb->xceiv->otg, &hcd->self); /* program PHY to use external vBus if required */
if (plat->extvbus) {
if (is_otg_enabled(musb)) u8 busctl = musb_read_ulpi_buscontrol(musb->mregs);
hcd->self.otg_port = 1; busctl |= MUSB_ULPI_USE_EXTVBUS;
musb->xceiv->otg->host = &hcd->self; musb_write_ulpi_buscontrol(musb->mregs, busctl);
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);
}
} }
/* For the host-only role, we can activate right away. MUSB_DEV_MODE(musb);
* (We expect the ID pin to be forcibly grounded!!) musb->xceiv->otg->default_a = 0;
* Otherwise, wait till the gadget driver hooks up. musb->xceiv->state = OTG_STATE_B_IDLE;
*/
if (!is_otg_enabled(musb) && is_host_enabled(musb)) {
struct usb_hcd *hcd = musb_to_hcd(musb);
MUSB_HST_MODE(musb); status = musb_gadget_setup(musb);
musb->xceiv->otg->default_a = 1;
musb->xceiv->state = OTG_STATE_A_IDLE;
status = usb_add_hcd(musb_to_hcd(musb), 0, 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 */ {
MUSB_DEV_MODE(musb);
musb->xceiv->otg->default_a = 0;
musb->xceiv->state = OTG_STATE_B_IDLE;
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) if (status < 0)
goto fail3; goto fail3;
@ -2048,28 +2027,13 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
pm_runtime_put(musb->controller); pm_runtime_put(musb->controller);
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);
return 0; return 0;
fail5: fail5:
musb_exit_debugfs(musb); musb_exit_debugfs(musb);
fail4: fail4:
if (!is_otg_enabled(musb) && is_host_enabled(musb)) musb_gadget_cleanup(musb);
usb_remove_hcd(musb_to_hcd(musb));
else
musb_gadget_cleanup(musb);
fail3: fail3:
pm_runtime_put_sync(musb->controller); pm_runtime_put_sync(musb->controller);
@ -2096,11 +2060,6 @@ fail0:
/* all implementations (PCI bridge to FPGA, VLYNQ, etc) should just /* all implementations (PCI bridge to FPGA, VLYNQ, etc) should just
* bridge to a platform device; this driver then suffices. * bridge to a platform device; this driver then suffices.
*/ */
#ifndef CONFIG_MUSB_PIO_ONLY
static u64 *orig_dma_mask;
#endif
static int __devinit musb_probe(struct platform_device *pdev) static int __devinit musb_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
@ -2119,10 +2078,6 @@ static int __devinit musb_probe(struct platform_device *pdev)
return -ENOMEM; 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); status = musb_init_controller(dev, irq, base);
if (status < 0) if (status < 0)
iounmap(base); iounmap(base);
@ -2132,7 +2087,8 @@ static int __devinit musb_probe(struct platform_device *pdev)
static int __devexit musb_remove(struct platform_device *pdev) static int __devexit musb_remove(struct platform_device *pdev)
{ {
struct musb *musb = dev_to_musb(&pdev->dev); struct device *dev = &pdev->dev;
struct musb *musb = dev_to_musb(dev);
void __iomem *ctrl_base = musb->ctrl_base; void __iomem *ctrl_base = musb->ctrl_base;
/* this gets called on rmmod. /* this gets called on rmmod.
@ -2145,9 +2101,9 @@ static int __devexit musb_remove(struct platform_device *pdev)
musb_free(musb); musb_free(musb);
iounmap(ctrl_base); iounmap(ctrl_base);
device_init_wakeup(&pdev->dev, 0); device_init_wakeup(dev, 0);
#ifndef CONFIG_MUSB_PIO_ONLY #ifndef CONFIG_MUSB_PIO_ONLY
pdev->dev.dma_mask = orig_dma_mask; dma_set_mask(dev, *dev->parent->dma_mask);
#endif #endif
return 0; return 0;
} }
@ -2160,11 +2116,9 @@ static void musb_save_context(struct musb *musb)
void __iomem *musb_base = musb->mregs; void __iomem *musb_base = musb->mregs;
void __iomem *epio; void __iomem *epio;
if (is_host_enabled(musb)) { musb->context.frame = musb_readw(musb_base, MUSB_FRAME);
musb->context.frame = musb_readw(musb_base, MUSB_FRAME); musb->context.testmode = musb_readb(musb_base, MUSB_TESTMODE);
musb->context.testmode = musb_readb(musb_base, MUSB_TESTMODE); musb->context.busctl = musb_read_ulpi_buscontrol(musb->mregs);
musb->context.busctl = musb_read_ulpi_buscontrol(musb->mregs);
}
musb->context.power = musb_readb(musb_base, MUSB_POWER); musb->context.power = musb_readb(musb_base, MUSB_POWER);
musb->context.intrtxe = musb_readw(musb_base, MUSB_INTRTXE); musb->context.intrtxe = musb_readw(musb_base, MUSB_INTRTXE);
musb->context.intrrxe = musb_readw(musb_base, MUSB_INTRRXE); musb->context.intrrxe = musb_readw(musb_base, MUSB_INTRRXE);
@ -2203,30 +2157,29 @@ static void musb_save_context(struct musb *musb)
musb->context.index_regs[i].rxfifosz = musb->context.index_regs[i].rxfifosz =
musb_read_rxfifosz(musb_base); 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->context.index_regs[i].txtype =
musb_read_txfunaddr(musb_base, i); musb_readb(epio, MUSB_TXTYPE);
musb->context.index_regs[i].txhubaddr = musb->context.index_regs[i].txinterval =
musb_read_txhubaddr(musb_base, i); musb_readb(epio, MUSB_TXINTERVAL);
musb->context.index_regs[i].txhubport = musb->context.index_regs[i].rxtype =
musb_read_txhubport(musb_base, i); musb_readb(epio, MUSB_RXTYPE);
musb->context.index_regs[i].rxinterval =
musb_readb(epio, MUSB_RXINTERVAL);
musb->context.index_regs[i].rxfunaddr = musb->context.index_regs[i].txfunaddr =
musb_read_rxfunaddr(musb_base, i); musb_read_txfunaddr(musb_base, i);
musb->context.index_regs[i].rxhubaddr = musb->context.index_regs[i].txhubaddr =
musb_read_rxhubaddr(musb_base, i); musb_read_txhubaddr(musb_base, i);
musb->context.index_regs[i].rxhubport = musb->context.index_regs[i].txhubport =
musb_read_rxhubport(musb_base, i); 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);
} }
} }
@ -2237,11 +2190,9 @@ static void musb_restore_context(struct musb *musb)
void __iomem *ep_target_regs; void __iomem *ep_target_regs;
void __iomem *epio; void __iomem *epio;
if (is_host_enabled(musb)) { musb_writew(musb_base, MUSB_FRAME, musb->context.frame);
musb_writew(musb_base, MUSB_FRAME, musb->context.frame); musb_writeb(musb_base, MUSB_TESTMODE, musb->context.testmode);
musb_writeb(musb_base, MUSB_TESTMODE, musb->context.testmode); musb_write_ulpi_buscontrol(musb->mregs, musb->context.busctl);
musb_write_ulpi_buscontrol(musb->mregs, musb->context.busctl);
}
musb_writeb(musb_base, MUSB_POWER, musb->context.power); musb_writeb(musb_base, MUSB_POWER, musb->context.power);
musb_writew(musb_base, MUSB_INTRTXE, musb->context.intrtxe); musb_writew(musb_base, MUSB_INTRTXE, musb->context.intrtxe);
musb_writew(musb_base, MUSB_INTRRXE, musb->context.intrrxe); musb_writew(musb_base, MUSB_INTRRXE, musb->context.intrrxe);
@ -2280,33 +2231,31 @@ static void musb_restore_context(struct musb *musb)
musb->context.index_regs[i].rxfifoadd); 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->context.index_regs[i].txtype);
musb_writeb(epio, MUSB_TXINTERVAL, musb_writeb(epio, MUSB_TXINTERVAL,
musb->context.index_regs[i].txinterval); musb->context.index_regs[i].txinterval);
musb_writeb(epio, MUSB_RXTYPE, musb_writeb(epio, MUSB_RXTYPE,
musb->context.index_regs[i].rxtype); musb->context.index_regs[i].rxtype);
musb_writeb(epio, MUSB_RXINTERVAL, musb_writeb(epio, MUSB_RXINTERVAL,
musb->context.index_regs[i].rxinterval); musb->context.index_regs[i].rxinterval);
musb_write_txfunaddr(musb_base, i, musb_write_txfunaddr(musb_base, i,
musb->context.index_regs[i].txfunaddr); 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->context.index_regs[i].txhubaddr);
musb_write_txhubport(musb_base, i, musb_write_txhubport(musb_base, i,
musb->context.index_regs[i].txhubport); musb->context.index_regs[i].txhubport);
ep_target_regs = ep_target_regs =
musb_read_target_reg_base(i, musb_base); 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->context.index_regs[i].rxfunaddr);
musb_write_rxhubaddr(ep_target_regs, musb_write_rxhubaddr(ep_target_regs,
musb->context.index_regs[i].rxhubaddr); 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->context.index_regs[i].rxhubport);
}
} }
musb_writeb(musb_base, MUSB_INDEX, musb->context.index); musb_writeb(musb_base, MUSB_INDEX, musb->context.index);
} }

View File

@ -71,10 +71,6 @@ struct musb_ep;
#include <linux/usb/hcd.h> #include <linux/usb/hcd.h>
#include "musb_host.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. /* NOTE: otg and peripheral-only state machines start at B_IDLE.
* OTG or host-only go to A_IDLE when ID is sensed. * OTG or host-only go to A_IDLE when ID is sensed.
*/ */
@ -88,8 +84,6 @@ struct musb_ep;
/****************************** PERIPHERAL ROLE *****************************/ /****************************** PERIPHERAL ROLE *****************************/
#define is_peripheral_capable() (1)
extern irqreturn_t musb_g_ep0_irq(struct musb *); extern irqreturn_t musb_g_ep0_irq(struct musb *);
extern void musb_g_tx(struct musb *, u8); extern void musb_g_tx(struct musb *, u8);
extern void musb_g_rx(struct musb *, u8); extern void musb_g_rx(struct musb *, u8);
@ -101,8 +95,6 @@ extern void musb_g_disconnect(struct musb *);
/****************************** HOST ROLE ***********************************/ /****************************** HOST ROLE ***********************************/
#define is_host_capable() (1)
extern irqreturn_t musb_h_ep0_irq(struct musb *); extern irqreturn_t musb_h_ep0_irq(struct musb *);
extern void musb_host_tx(struct musb *, u8); extern void musb_host_tx(struct musb *, u8);
extern void musb_host_rx(struct musb *, u8); extern void musb_host_rx(struct musb *, u8);
@ -376,7 +368,6 @@ struct musb {
u16 epmask; u16 epmask;
u8 nr_endpoints; u8 nr_endpoints;
u8 board_mode; /* enum musb_mode */
int (*board_set_power)(int state); int (*board_set_power)(int state);
u8 min_power; /* vbus for periph, in mA/2 */ u8 min_power; /* vbus for periph, in mA/2 */
@ -445,6 +436,10 @@ struct musb {
#ifdef MUSB_CONFIG_PROC_FS #ifdef MUSB_CONFIG_PROC_FS
struct proc_dir_entry *proc_entry; struct proc_dir_entry *proc_entry;
#endif
int xceiv_old_state;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_root;
#endif #endif
}; };
@ -484,7 +479,7 @@ static inline void musb_configure_ep0(struct musb *musb)
static inline int musb_read_fifosize(struct musb *musb, static inline int musb_read_fifosize(struct musb *musb,
struct musb_hw_ep *hw_ep, u8 epnum) struct musb_hw_ep *hw_ep, u8 epnum)
{ {
void *mbase = musb->mregs; void __iomem *mbase = musb->mregs;
u8 reg = 0; u8 reg = 0;
/* read from core using indexed model */ /* read from core using indexed model */
@ -526,6 +521,8 @@ extern const char musb_driver_name[];
extern void musb_start(struct musb *musb); extern void musb_start(struct musb *musb);
extern void musb_stop(struct musb *musb); extern void musb_stop(struct musb *musb);
extern int musb_get_id(struct device *dev, gfp_t gfp_mask);
extern void musb_put_id(struct device *dev, int id);
extern void musb_write_fifo(struct musb_hw_ep *ep, u16 len, const u8 *src); 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); extern void musb_read_fifo(struct musb_hw_ep *ep, u16 len, u8 *dst);

View File

@ -103,8 +103,6 @@ static const struct musb_register_map musb_regmap[] = {
{ } /* Terminating Entry */ { } /* Terminating Entry */
}; };
static struct dentry *musb_debugfs_root;
static int musb_regdump_show(struct seq_file *s, void *unused) static int musb_regdump_show(struct seq_file *s, void *unused)
{ {
struct musb *musb = s->private; struct musb *musb = s->private;
@ -241,7 +239,7 @@ int __devinit musb_init_debugfs(struct musb *musb)
struct dentry *file; struct dentry *file;
int ret; int ret;
root = debugfs_create_dir("musb", NULL); root = debugfs_create_dir(dev_name(musb->controller), NULL);
if (!root) { if (!root) {
ret = -ENOMEM; ret = -ENOMEM;
goto err0; goto err0;
@ -261,7 +259,7 @@ int __devinit musb_init_debugfs(struct musb *musb)
goto err1; goto err1;
} }
musb_debugfs_root = root; musb->debugfs_root = root;
return 0; return 0;
@ -274,5 +272,5 @@ err0:
void /* __init_or_exit */ musb_exit_debugfs(struct musb *musb) void /* __init_or_exit */ musb_exit_debugfs(struct musb *musb)
{ {
debugfs_remove_recursive(musb_debugfs_root); debugfs_remove_recursive(musb->debugfs_root);
} }

View File

@ -178,7 +178,7 @@ struct dma_controller {
extern void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit); extern void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit);
extern struct dma_controller *__init extern struct dma_controller *__devinit
dma_controller_create(struct musb *, void __iomem *); dma_controller_create(struct musb *, void __iomem *);
extern void dma_controller_destroy(struct dma_controller *); extern void dma_controller_destroy(struct dma_controller *);

View File

@ -31,6 +31,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/of.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
@ -46,6 +47,10 @@
#include "musb_core.h" #include "musb_core.h"
#ifdef CONFIG_OF
static const struct of_device_id musb_dsps_of_match[];
#endif
/** /**
* avoid using musb_readx()/musb_writex() as glue layer should not be * avoid using musb_readx()/musb_writex() as glue layer should not be
* dependent on musb core layer symbols. * dependent on musb core layer symbols.
@ -106,6 +111,8 @@ struct dsps_musb_wrapper {
/* miscellaneous stuff */ /* miscellaneous stuff */
u32 musb_core_offset; u32 musb_core_offset;
u8 poll_seconds; u8 poll_seconds;
/* number of musb instances */
u8 instances;
}; };
/** /**
@ -113,9 +120,10 @@ struct dsps_musb_wrapper {
*/ */
struct dsps_glue { struct dsps_glue {
struct device *dev; struct device *dev;
struct platform_device *musb; /* child musb pdev */ struct platform_device *musb[2]; /* child musb pdev */
const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */ const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */
struct timer_list timer; /* otg_workaround timer */ struct timer_list timer[2]; /* otg_workaround timer */
unsigned long last_timer[2]; /* last timer data for each instance */
}; };
/** /**
@ -138,9 +146,8 @@ static void dsps_musb_enable(struct musb *musb)
dsps_writel(reg_base, wrp->epintr_set, epmask); dsps_writel(reg_base, wrp->epintr_set, epmask);
dsps_writel(reg_base, wrp->coreintr_set, coremask); dsps_writel(reg_base, wrp->coreintr_set, coremask);
/* Force the DRVVBUS IRQ so we can start polling for ID change. */ /* Force the DRVVBUS IRQ so we can start polling for ID change. */
if (is_otg_enabled(musb)) dsps_writel(reg_base, wrp->coreintr_set,
dsps_writel(reg_base, wrp->coreintr_set, (1 << wrp->drvvbus) << wrp->usb_shift);
(1 << wrp->drvvbus) << wrp->usb_shift);
} }
/** /**
@ -166,8 +173,8 @@ static void otg_timer(unsigned long _musb)
struct musb *musb = (void *)_musb; struct musb *musb = (void *)_musb;
void __iomem *mregs = musb->mregs; void __iomem *mregs = musb->mregs;
struct device *dev = musb->controller; struct device *dev = musb->controller;
struct platform_device *pdev = to_platform_device(dev->parent); struct platform_device *pdev = to_platform_device(dev);
struct dsps_glue *glue = platform_get_drvdata(pdev); struct dsps_glue *glue = dev_get_drvdata(dev->parent);
const struct dsps_musb_wrapper *wrp = glue->wrp; const struct dsps_musb_wrapper *wrp = glue->wrp;
u8 devctl; u8 devctl;
unsigned long flags; unsigned long flags;
@ -201,12 +208,9 @@ static void otg_timer(unsigned long _musb)
MUSB_INTR_VBUSERROR << wrp->usb_shift); MUSB_INTR_VBUSERROR << wrp->usb_shift);
break; break;
case OTG_STATE_B_IDLE: case OTG_STATE_B_IDLE:
if (!is_peripheral_enabled(musb))
break;
devctl = dsps_readb(mregs, MUSB_DEVCTL); devctl = dsps_readb(mregs, MUSB_DEVCTL);
if (devctl & MUSB_DEVCTL_BDEVICE) if (devctl & MUSB_DEVCTL_BDEVICE)
mod_timer(&glue->timer, mod_timer(&glue->timer[pdev->id],
jiffies + wrp->poll_seconds * HZ); jiffies + wrp->poll_seconds * HZ);
else else
musb->xceiv->state = OTG_STATE_A_IDLE; musb->xceiv->state = OTG_STATE_A_IDLE;
@ -220,12 +224,8 @@ static void otg_timer(unsigned long _musb)
static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
{ {
struct device *dev = musb->controller; struct device *dev = musb->controller;
struct platform_device *pdev = to_platform_device(dev->parent); struct platform_device *pdev = to_platform_device(dev);
struct dsps_glue *glue = platform_get_drvdata(pdev); struct dsps_glue *glue = dev_get_drvdata(dev->parent);
static unsigned long last_timer;
if (!is_otg_enabled(musb))
return;
if (timeout == 0) if (timeout == 0)
timeout = jiffies + msecs_to_jiffies(3); timeout = jiffies + msecs_to_jiffies(3);
@ -235,22 +235,23 @@ static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout)
musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) { musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
dev_dbg(musb->controller, "%s active, deleting timer\n", dev_dbg(musb->controller, "%s active, deleting timer\n",
otg_state_string(musb->xceiv->state)); otg_state_string(musb->xceiv->state));
del_timer(&glue->timer); del_timer(&glue->timer[pdev->id]);
last_timer = jiffies; glue->last_timer[pdev->id] = jiffies;
return; return;
} }
if (time_after(last_timer, timeout) && timer_pending(&glue->timer)) { if (time_after(glue->last_timer[pdev->id], timeout) &&
timer_pending(&glue->timer[pdev->id])) {
dev_dbg(musb->controller, dev_dbg(musb->controller,
"Longer idle timer already pending, ignoring...\n"); "Longer idle timer already pending, ignoring...\n");
return; return;
} }
last_timer = timeout; glue->last_timer[pdev->id] = timeout;
dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n",
otg_state_string(musb->xceiv->state), otg_state_string(musb->xceiv->state),
jiffies_to_msecs(timeout - jiffies)); jiffies_to_msecs(timeout - jiffies));
mod_timer(&glue->timer, timeout); mod_timer(&glue->timer[pdev->id], timeout);
} }
static irqreturn_t dsps_interrupt(int irq, void *hci) static irqreturn_t dsps_interrupt(int irq, void *hci)
@ -258,8 +259,8 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
struct musb *musb = hci; struct musb *musb = hci;
void __iomem *reg_base = musb->ctrl_base; void __iomem *reg_base = musb->ctrl_base;
struct device *dev = musb->controller; struct device *dev = musb->controller;
struct platform_device *pdev = to_platform_device(dev->parent); struct platform_device *pdev = to_platform_device(dev);
struct dsps_glue *glue = platform_get_drvdata(pdev); struct dsps_glue *glue = dev_get_drvdata(dev->parent);
const struct dsps_musb_wrapper *wrp = glue->wrp; const struct dsps_musb_wrapper *wrp = glue->wrp;
unsigned long flags; unsigned long flags;
irqreturn_t ret = IRQ_NONE; irqreturn_t ret = IRQ_NONE;
@ -294,7 +295,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
* value but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set. * value but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set.
* Also, DRVVBUS pulses for SRP (but not at 5V) ... * Also, DRVVBUS pulses for SRP (but not at 5V) ...
*/ */
if ((usbintr & MUSB_INTR_BABBLE) && is_host_enabled(musb)) if (usbintr & MUSB_INTR_BABBLE)
pr_info("CAUTION: musb: Babble Interrupt Occured\n"); pr_info("CAUTION: musb: Babble Interrupt Occured\n");
if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) { if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) {
@ -303,8 +304,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
u8 devctl = dsps_readb(mregs, MUSB_DEVCTL); u8 devctl = dsps_readb(mregs, MUSB_DEVCTL);
int err; int err;
err = is_host_enabled(musb) && (musb->int_usb & err = musb->int_usb & MUSB_INTR_VBUSERROR;
MUSB_INTR_VBUSERROR);
if (err) { if (err) {
/* /*
* The Mentor core doesn't debounce VBUS as needed * The Mentor core doesn't debounce VBUS as needed
@ -319,15 +319,15 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
*/ */
musb->int_usb &= ~MUSB_INTR_VBUSERROR; musb->int_usb &= ~MUSB_INTR_VBUSERROR;
musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
mod_timer(&glue->timer, mod_timer(&glue->timer[pdev->id],
jiffies + wrp->poll_seconds * HZ); jiffies + wrp->poll_seconds * HZ);
WARNING("VBUS error workaround (delay coming)\n"); WARNING("VBUS error workaround (delay coming)\n");
} else if (is_host_enabled(musb) && drvvbus) { } else if (drvvbus) {
musb->is_active = 1; musb->is_active = 1;
MUSB_HST_MODE(musb); MUSB_HST_MODE(musb);
musb->xceiv->otg->default_a = 1; musb->xceiv->otg->default_a = 1;
musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
del_timer(&glue->timer); del_timer(&glue->timer[pdev->id]);
} else { } else {
musb->is_active = 0; musb->is_active = 0;
MUSB_DEV_MODE(musb); MUSB_DEV_MODE(musb);
@ -353,8 +353,9 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
dsps_writel(reg_base, wrp->eoi, 1); dsps_writel(reg_base, wrp->eoi, 1);
/* Poll for ID change */ /* 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(&glue->timer, jiffies + wrp->poll_seconds * HZ); mod_timer(&glue->timer[pdev->id],
jiffies + wrp->poll_seconds * HZ);
spin_unlock_irqrestore(&musb->lock, flags); spin_unlock_irqrestore(&musb->lock, flags);
@ -365,8 +366,8 @@ static int dsps_musb_init(struct musb *musb)
{ {
struct device *dev = musb->controller; struct device *dev = musb->controller;
struct musb_hdrc_platform_data *plat = dev->platform_data; struct musb_hdrc_platform_data *plat = dev->platform_data;
struct platform_device *pdev = to_platform_device(dev->parent); struct platform_device *pdev = to_platform_device(dev);
struct dsps_glue *glue = platform_get_drvdata(pdev); struct dsps_glue *glue = dev_get_drvdata(dev->parent);
const struct dsps_musb_wrapper *wrp = glue->wrp; const struct dsps_musb_wrapper *wrp = glue->wrp;
struct omap_musb_board_data *data = plat->board_data; struct omap_musb_board_data *data = plat->board_data;
void __iomem *reg_base = musb->ctrl_base; void __iomem *reg_base = musb->ctrl_base;
@ -376,8 +377,7 @@ static int dsps_musb_init(struct musb *musb)
/* mentor core register starts at offset of 0x400 from musb base */ /* mentor core register starts at offset of 0x400 from musb base */
musb->mregs += wrp->musb_core_offset; musb->mregs += wrp->musb_core_offset;
/* NOP driver needs change if supporting dual instance */ /* Get the NOP PHY */
usb_nop_xceiv_register();
musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
if (IS_ERR_OR_NULL(musb->xceiv)) if (IS_ERR_OR_NULL(musb->xceiv))
return -ENODEV; return -ENODEV;
@ -389,8 +389,7 @@ static int dsps_musb_init(struct musb *musb)
goto err0; goto err0;
} }
if (is_host_enabled(musb)) setup_timer(&glue->timer[pdev->id], otg_timer, (unsigned long) musb);
setup_timer(&glue->timer, otg_timer, (unsigned long) musb);
/* Reset the musb */ /* Reset the musb */
dsps_writel(reg_base, wrp->control, (1 << wrp->reset)); dsps_writel(reg_base, wrp->control, (1 << wrp->reset));
@ -421,11 +420,10 @@ static int dsps_musb_exit(struct musb *musb)
struct device *dev = musb->controller; struct device *dev = musb->controller;
struct musb_hdrc_platform_data *plat = dev->platform_data; struct musb_hdrc_platform_data *plat = dev->platform_data;
struct omap_musb_board_data *data = plat->board_data; struct omap_musb_board_data *data = plat->board_data;
struct platform_device *pdev = to_platform_device(dev->parent); struct platform_device *pdev = to_platform_device(dev);
struct dsps_glue *glue = platform_get_drvdata(pdev); struct dsps_glue *glue = dev_get_drvdata(dev->parent);
if (is_host_enabled(musb)) del_timer_sync(&glue->timer[pdev->id]);
del_timer_sync(&glue->timer);
/* Shutdown the on-chip PHY and its PLL. */ /* Shutdown the on-chip PHY and its PLL. */
if (data->set_phy_power) if (data->set_phy_power)
@ -455,11 +453,13 @@ static int __devinit dsps_create_musb_pdev(struct dsps_glue *glue, u8 id)
struct device *dev = glue->dev; struct device *dev = glue->dev;
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
struct musb_hdrc_platform_data *pdata = dev->platform_data; struct musb_hdrc_platform_data *pdata = dev->platform_data;
struct device_node *np = pdev->dev.of_node;
struct musb_hdrc_config *config;
struct platform_device *musb; struct platform_device *musb;
struct resource *res; struct resource *res;
struct resource resources[2]; struct resource resources[2];
char res_name[10]; char res_name[10];
int ret; int ret, musbid;
/* get memory resource */ /* get memory resource */
sprintf(res_name, "musb%d", id); sprintf(res_name, "musb%d", id);
@ -484,62 +484,107 @@ static int __devinit dsps_create_musb_pdev(struct dsps_glue *glue, u8 id)
resources[1] = *res; resources[1] = *res;
resources[1].name = "mc"; resources[1].name = "mc";
/* allocate the child platform device */ /* get the musb id */
musb = platform_device_alloc("musb-hdrc", -1); musbid = musb_get_id(dev, GFP_KERNEL);
if (!musb) { if (musbid < 0) {
dev_err(dev, "failed to allocate musb device\n"); dev_err(dev, "failed to allocate musb id\n");
ret = -ENOMEM; ret = -ENOMEM;
goto err0; goto err0;
} }
/* allocate the child platform device */
musb = platform_device_alloc("musb-hdrc", musbid);
if (!musb) {
dev_err(dev, "failed to allocate musb device\n");
ret = -ENOMEM;
goto err1;
}
musb->id = musbid;
musb->dev.parent = dev; musb->dev.parent = dev;
musb->dev.dma_mask = &musb_dmamask; musb->dev.dma_mask = &musb_dmamask;
musb->dev.coherent_dma_mask = musb_dmamask; musb->dev.coherent_dma_mask = musb_dmamask;
glue->musb = musb; glue->musb[id] = musb;
pdata->platform_ops = &dsps_ops;
ret = platform_device_add_resources(musb, resources, 2); ret = platform_device_add_resources(musb, resources, 2);
if (ret) { if (ret) {
dev_err(dev, "failed to add resources\n"); dev_err(dev, "failed to add resources\n");
goto err1; goto err2;
} }
if (np) {
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
dev_err(&pdev->dev,
"failed to allocate musb platfrom data\n");
ret = -ENOMEM;
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, "num-eps", (u32 *)&config->num_eps);
of_property_read_u32(np, "ram-bits", (u32 *)&config->ram_bits);
sprintf(res_name, "port%d-mode", id);
of_property_read_u32(np, res_name, (u32 *)&pdata->mode);
of_property_read_u32(np, "power", (u32 *)&pdata->power);
config->multipoint = of_property_read_bool(np, "multipoint");
pdata->config = config;
}
pdata->platform_ops = &dsps_ops;
ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
if (ret) { if (ret) {
dev_err(dev, "failed to add platform_data\n"); dev_err(dev, "failed to add platform_data\n");
goto err1; goto err2;
} }
ret = platform_device_add(musb); ret = platform_device_add(musb);
if (ret) { if (ret) {
dev_err(dev, "failed to register musb device\n"); dev_err(dev, "failed to register musb device\n");
goto err1; goto err2;
} }
return 0; return 0;
err1: err2:
platform_device_put(musb); platform_device_put(musb);
err1:
musb_put_id(dev, musbid);
err0: err0:
return ret; return ret;
} }
static void __devexit dsps_delete_musb_pdev(struct dsps_glue *glue) static void dsps_delete_musb_pdev(struct dsps_glue *glue, u8 id)
{ {
platform_device_del(glue->musb); musb_put_id(glue->dev, glue->musb[id]->id);
platform_device_put(glue->musb); platform_device_del(glue->musb[id]);
platform_device_put(glue->musb[id]);
} }
static int __devinit dsps_probe(struct platform_device *pdev) static int __devinit dsps_probe(struct platform_device *pdev)
{ {
const struct platform_device_id *id = platform_get_device_id(pdev); struct device_node *np = pdev->dev.of_node;
const struct dsps_musb_wrapper *wrp = const struct of_device_id *match;
(struct dsps_musb_wrapper *)id->driver_data; const struct dsps_musb_wrapper *wrp;
struct dsps_glue *glue; struct dsps_glue *glue;
struct resource *iomem; struct resource *iomem;
int ret; int ret, i;
match = of_match_node(musb_dsps_of_match, np);
if (!match) {
dev_err(&pdev->dev, "fail to get matching of_match struct\n");
ret = -EINVAL;
goto err0;
}
wrp = match->data;
/* allocate glue */ /* allocate glue */
glue = kzalloc(sizeof(*glue), GFP_KERNEL); glue = kzalloc(sizeof(*glue), GFP_KERNEL);
@ -576,11 +621,16 @@ static int __devinit dsps_probe(struct platform_device *pdev)
goto err2; goto err2;
} }
/* create the child platform device for first instances of musb */ /* create the child platform device for all instances of musb */
ret = dsps_create_musb_pdev(glue, 0); for (i = 0; i < wrp->instances ; i++) {
if (ret != 0) { ret = dsps_create_musb_pdev(glue, i);
dev_err(&pdev->dev, "failed to create child pdev\n"); if (ret != 0) {
goto err3; dev_err(&pdev->dev, "failed to create child pdev\n");
/* release resources of previously created instances */
for (i--; i >= 0 ; i--)
dsps_delete_musb_pdev(glue, i);
goto err3;
}
} }
return 0; return 0;
@ -598,9 +648,12 @@ err0:
static int __devexit dsps_remove(struct platform_device *pdev) static int __devexit dsps_remove(struct platform_device *pdev)
{ {
struct dsps_glue *glue = platform_get_drvdata(pdev); struct dsps_glue *glue = platform_get_drvdata(pdev);
const struct dsps_musb_wrapper *wrp = glue->wrp;
int i;
/* delete the child platform device */ /* delete the child platform device */
dsps_delete_musb_pdev(glue); for (i = 0; i < wrp->instances ; i++)
dsps_delete_musb_pdev(glue, i);
/* disable usbss clocks */ /* disable usbss clocks */
pm_runtime_put(&pdev->dev); pm_runtime_put(&pdev->dev);
@ -666,6 +719,7 @@ static const struct dsps_musb_wrapper ti81xx_driver_data __devinitconst = {
.rxep_bitmap = (0xfffe << 16), .rxep_bitmap = (0xfffe << 16),
.musb_core_offset = 0x400, .musb_core_offset = 0x400,
.poll_seconds = 2, .poll_seconds = 2,
.instances = 2,
}; };
static const struct platform_device_id musb_dsps_id_table[] __devinitconst = { static const struct platform_device_id musb_dsps_id_table[] __devinitconst = {
@ -677,13 +731,14 @@ static const struct platform_device_id musb_dsps_id_table[] __devinitconst = {
}; };
MODULE_DEVICE_TABLE(platform, musb_dsps_id_table); MODULE_DEVICE_TABLE(platform, musb_dsps_id_table);
#ifdef CONFIG_OF
static const struct of_device_id musb_dsps_of_match[] __devinitconst = { static const struct of_device_id musb_dsps_of_match[] __devinitconst = {
{ .compatible = "musb-ti81xx", }, { .compatible = "ti,musb-am33xx",
{ .compatible = "ti,ti81xx-musb", }, .data = (void *) &ti81xx_driver_data, },
{ .compatible = "ti,am335x-musb", },
{ }, { },
}; };
MODULE_DEVICE_TABLE(of, musb_dsps_of_match); MODULE_DEVICE_TABLE(of, musb_dsps_of_match);
#endif
static struct platform_driver dsps_usbss_driver = { static struct platform_driver dsps_usbss_driver = {
.probe = dsps_probe, .probe = dsps_probe,
@ -691,7 +746,7 @@ static struct platform_driver dsps_usbss_driver = {
.driver = { .driver = {
.name = "musb-dsps", .name = "musb-dsps",
.pm = &dsps_pm_ops, .pm = &dsps_pm_ops,
.of_match_table = musb_dsps_of_match, .of_match_table = of_match_ptr(musb_dsps_of_match),
}, },
.id_table = musb_dsps_id_table, .id_table = musb_dsps_id_table,
}; };

View File

@ -373,7 +373,7 @@ static void txstate(struct musb *musb, struct musb_request *req)
request_size = min_t(size_t, request->length - request->actual, request_size = min_t(size_t, request->length - request->actual,
musb_ep->dma->max_len); 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 */ /* MUSB_TXCSR_P_ISO is still set correctly */
@ -644,8 +644,8 @@ static void rxstate(struct musb *musb, struct musb_request *req)
struct usb_request *request = &req->request; struct usb_request *request = &req->request;
struct musb_ep *musb_ep; struct musb_ep *musb_ep;
void __iomem *epio = musb->endpoints[epnum].regs; void __iomem *epio = musb->endpoints[epnum].regs;
unsigned fifo_count = 0; unsigned len = 0;
u16 len; u16 fifo_count;
u16 csr = musb_readw(epio, MUSB_RXCSR); u16 csr = musb_readw(epio, MUSB_RXCSR);
struct musb_hw_ep *hw_ep = &musb->endpoints[epnum]; struct musb_hw_ep *hw_ep = &musb->endpoints[epnum];
u8 use_mode_1; u8 use_mode_1;
@ -655,7 +655,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
else else
musb_ep = &hw_ep->ep_out; musb_ep = &hw_ep->ep_out;
len = musb_ep->packet_sz; fifo_count = musb_ep->packet_sz;
/* Check if EP is disabled */ /* Check if EP is disabled */
if (!musb_ep->desc) { if (!musb_ep->desc) {
@ -704,15 +704,14 @@ static void rxstate(struct musb *musb, struct musb_request *req)
} }
if (csr & MUSB_RXCSR_RXPKTRDY) { 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 * use mode 1 only if we expect data of at least ep packet_sz
* is set. Currently short_not_ok flag is set only from * and have not yet received a short packet
* file_storage and f_mass_storage drivers
*/ */
if ((request->length - request->actual >= musb_ep->packet_sz) &&
if (request->short_not_ok && len == musb_ep->packet_sz) (fifo_count >= musb_ep->packet_sz))
use_mode_1 = 1; use_mode_1 = 1;
else else
use_mode_1 = 0; use_mode_1 = 0;
@ -723,31 +722,11 @@ static void rxstate(struct musb *musb, struct musb_request *req)
struct dma_controller *c; struct dma_controller *c;
struct dma_channel *channel; struct dma_channel *channel;
int use_dma = 0; int use_dma = 0;
int transfer_size;
c = musb->dma_controller; c = musb->dma_controller;
channel = musb_ep->dma; channel = musb_ep->dma;
/* We use DMA Req mode 0 in rx_csr, and DMA controller operates in
* mode 0 only. So we do not get endpoint interrupts due to DMA
* completion. We only get interrupts from DMA controller.
*
* We could operate in DMA mode 1 if we knew the size of the tranfer
* in advance. For mass storage class, request->length = what the host
* sends, so that'd work. But for pretty much everything else,
* request->length is routinely more than what the host sends. For
* most these gadgets, end of is signified either by a short packet,
* or filling the last byte of the buffer. (Sending extra data in
* that last pckate should trigger an overflow fault.) But in mode 1,
* we don't get DMA completion interrupt for short packets.
*
* Theoretically, we could enable DMAReq irq (MUSB_RXCSR_DMAMODE = 1),
* to get endpoint interrupt on every DMA req, but that didn't seem
* to work reliably.
*
* REVISIT an updated g_file_storage can set req->short_not_ok, which
* then becomes usable as a runtime "use mode 1" hint...
*/
/* Experimental: Mode1 works with mass storage use cases */ /* Experimental: Mode1 works with mass storage use cases */
if (use_mode_1) { if (use_mode_1) {
csr |= MUSB_RXCSR_AUTOCLEAR; csr |= MUSB_RXCSR_AUTOCLEAR;
@ -764,34 +743,29 @@ static void rxstate(struct musb *musb, struct musb_request *req)
csr | MUSB_RXCSR_DMAMODE); csr | MUSB_RXCSR_DMAMODE);
musb_writew(epio, MUSB_RXCSR, csr); musb_writew(epio, MUSB_RXCSR, csr);
transfer_size = min(request->length - request->actual,
channel->max_len);
musb_ep->dma->desired_mode = 1;
} else { } else {
if (!musb_ep->hb_mult && if (!musb_ep->hb_mult &&
musb_ep->hw_ep->rx_double_buffered) musb_ep->hw_ep->rx_double_buffered)
csr |= MUSB_RXCSR_AUTOCLEAR; csr |= MUSB_RXCSR_AUTOCLEAR;
csr |= MUSB_RXCSR_DMAENAB; csr |= MUSB_RXCSR_DMAENAB;
musb_writew(epio, MUSB_RXCSR, csr); musb_writew(epio, MUSB_RXCSR, csr);
transfer_size = min(request->length - request->actual,
(unsigned)fifo_count);
musb_ep->dma->desired_mode = 0;
} }
if (request->actual < request->length) { use_dma = c->channel_program(
int transfer_size = 0; channel,
if (use_mode_1) { musb_ep->packet_sz,
transfer_size = min(request->length - request->actual, channel->desired_mode,
channel->max_len); request->dma
musb_ep->dma->desired_mode = 1; + request->actual,
} else { transfer_size);
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);
}
if (use_dma) if (use_dma)
return; return;
@ -808,8 +782,8 @@ static void rxstate(struct musb *musb, struct musb_request *req)
channel = musb_ep->dma; channel = musb_ep->dma;
/* In case first packet is short */ /* In case first packet is short */
if (len < musb_ep->packet_sz) if (fifo_count < musb_ep->packet_sz)
transfer_size = len; transfer_size = fifo_count;
else if (request->short_not_ok) else if (request->short_not_ok)
transfer_size = min(request->length - transfer_size = min(request->length -
request->actual, request->actual,
@ -817,7 +791,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
else else
transfer_size = min(request->length - transfer_size = min(request->length -
request->actual, request->actual,
(unsigned)len); (unsigned)fifo_count);
csr &= ~MUSB_RXCSR_DMAMODE; csr &= ~MUSB_RXCSR_DMAMODE;
csr |= (MUSB_RXCSR_DMAENAB | csr |= (MUSB_RXCSR_DMAENAB |
@ -845,10 +819,10 @@ static void rxstate(struct musb *musb, struct musb_request *req)
} }
#endif /* Mentor's DMA */ #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", dev_dbg(musb->controller, "%s OUT/RX pio fifo %d/%d, maxpacket %d\n",
musb_ep->end_point.name, musb_ep->end_point.name,
len, fifo_count, fifo_count, len,
musb_ep->packet_sz); musb_ep->packet_sz);
fifo_count = min_t(unsigned, len, fifo_count); fifo_count = min_t(unsigned, len, fifo_count);
@ -901,7 +875,8 @@ static void rxstate(struct musb *musb, struct musb_request *req)
} }
/* reach the end or short packet detected */ /* 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); musb_g_giveback(musb_ep, request, 0);
} }
@ -1885,8 +1860,7 @@ int __devinit musb_gadget_setup(struct musb *musb)
musb->g.dev.release = musb_gadget_release; musb->g.dev.release = musb_gadget_release;
musb->g.name = musb_driver_name; musb->g.name = musb_driver_name;
if (is_otg_enabled(musb)) musb->g.is_otg = 1;
musb->g.is_otg = 1;
musb_g_init_endpoints(musb); musb_g_init_endpoints(musb);
@ -1932,11 +1906,14 @@ static int musb_gadget_start(struct usb_gadget *g,
{ {
struct musb *musb = gadget_to_musb(g); struct musb *musb = gadget_to_musb(g);
struct usb_otg *otg = musb->xceiv->otg; struct usb_otg *otg = musb->xceiv->otg;
struct usb_hcd *hcd = musb_to_hcd(musb);
unsigned long flags; unsigned long flags;
int retval = -EINVAL; int retval = 0;
if (driver->max_speed < USB_SPEED_HIGH) if (driver->max_speed < USB_SPEED_HIGH) {
goto err0; retval = -EINVAL;
goto err;
}
pm_runtime_get_sync(musb->controller); pm_runtime_get_sync(musb->controller);
@ -1950,49 +1927,30 @@ static int musb_gadget_start(struct usb_gadget *g,
otg_set_peripheral(otg, &musb->g); otg_set_peripheral(otg, &musb->g);
musb->xceiv->state = OTG_STATE_B_IDLE; 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); spin_unlock_irqrestore(&musb->lock, flags);
if (is_otg_enabled(musb)) { /* REVISIT: funcall to other code, which also
struct usb_hcd *hcd = musb_to_hcd(musb); * handles power budgeting ... this way also
* ensures HdrcStart is indirectly called.
dev_dbg(musb->controller, "OTG startup...\n"); */
retval = usb_add_hcd(hcd, 0, 0);
/* REVISIT: funcall to other code, which also if (retval < 0) {
* handles power budgeting ... this way also dev_dbg(musb->controller, "add_hcd failed, %d\n", retval);
* ensures HdrcStart is indirectly called. goto err;
*/
retval = usb_add_hcd(musb_to_hcd(musb), 0, 0);
if (retval < 0) {
dev_dbg(musb->controller, "add_hcd failed, %d\n", retval);
goto err2;
}
if ((musb->xceiv->last_event == USB_EVENT_ID)
&& otg->set_vbus)
otg_set_vbus(otg, 1);
hcd->self.uses_pio_for_control = 1;
} }
if ((musb->xceiv->last_event == USB_EVENT_ID)
&& otg->set_vbus)
otg_set_vbus(otg, 1);
hcd->self.uses_pio_for_control = 1;
if (musb->xceiv->last_event == USB_EVENT_NONE) if (musb->xceiv->last_event == USB_EVENT_NONE)
pm_runtime_put(musb->controller); pm_runtime_put(musb->controller);
return 0; return 0;
err2: err:
if (!is_otg_enabled(musb))
musb_stop(musb);
err0:
return retval; return retval;
} }
@ -2070,16 +2028,12 @@ static int musb_gadget_stop(struct usb_gadget *g,
musb_platform_try_idle(musb, 0); musb_platform_try_idle(musb, 0);
spin_unlock_irqrestore(&musb->lock, flags); spin_unlock_irqrestore(&musb->lock, flags);
if (is_otg_enabled(musb)) { usb_remove_hcd(musb_to_hcd(musb));
usb_remove_hcd(musb_to_hcd(musb)); /*
/* FIXME we need to be able to register another * FIXME we need to be able to register another
* gadget driver here and have everything work; * gadget driver here and have everything work;
* that currently misbehaves. * that currently misbehaves.
*/ */
}
if (!is_otg_enabled(musb))
musb_stop(musb);
pm_runtime_put(musb->controller); pm_runtime_put(musb->controller);
@ -2241,13 +2195,11 @@ __acquires(musb->lock)
if (devctl & MUSB_DEVCTL_BDEVICE) { if (devctl & MUSB_DEVCTL_BDEVICE) {
musb->xceiv->state = OTG_STATE_B_PERIPHERAL; musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
musb->g.is_a_peripheral = 0; musb->g.is_a_peripheral = 0;
} else if (is_otg_enabled(musb)) { } else {
musb->xceiv->state = OTG_STATE_A_PERIPHERAL; musb->xceiv->state = OTG_STATE_A_PERIPHERAL;
musb->g.is_a_peripheral = 1; musb->g.is_a_peripheral = 1;
} else }
WARN_ON(1);
/* start with default limits on VBUS power draw */ /* start with default limits on VBUS power draw */
(void) musb_gadget_vbus_draw(&musb->g, (void) musb_gadget_vbus_draw(&musb->g, 8);
is_otg_enabled(musb) ? 8 : 100);
} }

View File

@ -693,6 +693,8 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
void __iomem *epio = hw_ep->regs; void __iomem *epio = hw_ep->regs;
struct musb_qh *qh = musb_ep_get_qh(hw_ep, !is_out); struct musb_qh *qh = musb_ep_get_qh(hw_ep, !is_out);
u16 packet_sz = qh->maxpacket; 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 " 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", "h_addr%02x h_port%02x bytes %d\n",
@ -704,9 +706,17 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
musb_ep_select(mbase, 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? */ /* candidate for DMA? */
dma_controller = musb->dma_controller; 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; dma_channel = is_out ? hw_ep->tx_channel : hw_ep->rx_channel;
if (!dma_channel) { if (!dma_channel) {
dma_channel = dma_controller->channel_alloc( dma_channel = dma_controller->channel_alloc(
@ -813,9 +823,28 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
if (load_count) { if (load_count) {
/* PIO to load FIFO */ /* PIO to load FIFO */
qh->segsize = load_count; 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 */ /* re-enable interrupt */
musb_writew(mbase, MUSB_INTRTXE, int_txe); musb_writew(mbase, MUSB_INTRTXE, int_txe);
@ -882,6 +911,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. * Service the default endpoint (ep0) as host.
@ -1116,6 +1212,7 @@ void musb_host_tx(struct musb *musb, u8 epnum)
void __iomem *mbase = musb->mregs; void __iomem *mbase = musb->mregs;
struct dma_channel *dma; struct dma_channel *dma;
bool transfer_pending = false; bool transfer_pending = false;
static bool use_sg;
musb_ep_select(mbase, epnum); musb_ep_select(mbase, epnum);
tx_csr = musb_readw(epio, MUSB_TXCSR); tx_csr = musb_readw(epio, MUSB_TXCSR);
@ -1146,23 +1243,31 @@ void musb_host_tx(struct musb *musb, u8 epnum)
status = -ETIMEDOUT; status = -ETIMEDOUT;
} else if (tx_csr & MUSB_TXCSR_H_NAKTIMEOUT) { } else if (tx_csr & MUSB_TXCSR_H_NAKTIMEOUT) {
dev_dbg(musb->controller, "TX end=%d device not responding\n", epnum); if (USB_ENDPOINT_XFER_BULK == qh->type && qh->mux == 1
&& !list_is_singular(&musb->out_bulk)) {
/* NOTE: this code path would be a good place to PAUSE a dev_dbg(musb->controller,
* transfer, if there's some other (nonperiodic) tx urb "NAK timeout on TX%d ep\n", epnum);
* that could use this fifo. (dma complicates it...) musb_bulk_nak_timeout(musb, hw_ep, 0);
* That's already done for bulk RX transfers. } else {
* dev_dbg(musb->controller,
* if (bulk && qh->ring.next != &musb->out_bulk), then "TX end=%d device not responding\n", epnum);
* we have a candidate... NAKing is *NOT* an error /* NOTE: this code path would be a good place to PAUSE a
*/ * transfer, if there's some other (nonperiodic) tx urb
musb_ep_select(mbase, epnum); * that could use this fifo. (dma complicates it...)
musb_writew(epio, MUSB_TXCSR, * That's already done for bulk RX transfers.
MUSB_TXCSR_H_WZC_BITS *
| MUSB_TXCSR_TXPKTRDY); * if (bulk && qh->ring.next != &musb->out_bulk), then
return; * 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 (status) {
if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) { if (dma_channel_status(dma) == MUSB_DMA_STATUS_BUSY) {
dma->status = MUSB_DMA_STATUS_CORE_ABORT; dma->status = MUSB_DMA_STATUS_CORE_ABORT;
@ -1332,9 +1437,38 @@ void musb_host_tx(struct musb *musb, u8 epnum)
length = qh->maxpacket; length = qh->maxpacket;
/* Unmap the buffer so that CPU can use it */ /* Unmap the buffer so that CPU can use it */
usb_hcd_unmap_urb_for_dma(musb_to_hcd(musb), urb); usb_hcd_unmap_urb_for_dma(musb_to_hcd(musb), urb);
musb_write_fifo(hw_ep, length, urb->transfer_buffer + offset);
/*
* We need to map sg if the transfer_buffer is
* NULL.
*/
if (!urb->transfer_buffer)
use_sg = true;
if (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; qh->segsize = length;
if (use_sg) {
if (offset + length >= urb->transfer_buffer_length)
use_sg = false;
}
musb_ep_select(mbase, epnum); musb_ep_select(mbase, epnum);
musb_writew(epio, MUSB_TXCSR, musb_writew(epio, MUSB_TXCSR,
MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY); MUSB_TXCSR_H_WZC_BITS | MUSB_TXCSR_TXPKTRDY);
@ -1380,50 +1514,6 @@ void musb_host_tx(struct musb *musb, u8 epnum)
#endif #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, * Service an RX interrupt for the given IN endpoint; docs cover bulk, iso,
* and high-bandwidth IN transfer cases. * and high-bandwidth IN transfer cases.
@ -1442,6 +1532,8 @@ void musb_host_rx(struct musb *musb, u8 epnum)
bool done = false; bool done = false;
u32 status; u32 status;
struct dma_channel *dma; struct dma_channel *dma;
static bool use_sg;
unsigned int sg_flags = SG_MITER_ATOMIC | SG_MITER_TO_SG;
musb_ep_select(mbase, epnum); musb_ep_select(mbase, epnum);
@ -1500,7 +1592,7 @@ void musb_host_rx(struct musb *musb, u8 epnum)
if (usb_pipebulk(urb->pipe) if (usb_pipebulk(urb->pipe)
&& qh->mux == 1 && qh->mux == 1
&& !list_is_singular(&musb->in_bulk)) { && !list_is_singular(&musb->in_bulk)) {
musb_bulk_rx_nak_timeout(musb, hw_ep); musb_bulk_nak_timeout(musb, hw_ep, 1);
return; return;
} }
musb_ep_select(mbase, epnum); musb_ep_select(mbase, epnum);
@ -1756,10 +1848,43 @@ void musb_host_rx(struct musb *musb, u8 epnum)
#endif /* Mentor DMA */ #endif /* Mentor DMA */
if (!dma) { if (!dma) {
unsigned int received_len;
/* Unmap the buffer so that CPU can use it */ /* Unmap the buffer so that CPU can use it */
usb_hcd_unmap_urb_for_dma(musb_to_hcd(musb), urb); usb_hcd_unmap_urb_for_dma(musb_to_hcd(musb), urb);
done = musb_host_packet_rx(musb, urb,
epnum, iso_err); /*
* We need to map sg if the transfer_buffer is
* NULL.
*/
if (!urb->transfer_buffer) {
use_sg = true;
sg_miter_start(&qh->sg_miter, urb->sg, 1,
sg_flags);
}
if (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 " : ""); dev_dbg(musb->controller, "read %spacket\n", done ? "last " : "");
} }
} }
@ -1768,6 +1893,9 @@ finish:
urb->actual_length += xfer_len; urb->actual_length += xfer_len;
qh->offset += xfer_len; qh->offset += xfer_len;
if (done) { if (done) {
if (use_sg)
use_sg = false;
if (urb->status == -EINPROGRESS) if (urb->status == -EINPROGRESS)
urb->status = status; urb->status = status;
musb_advance_schedule(musb, urb, hw_ep, USB_DIR_IN); musb_advance_schedule(musb, urb, hw_ep, USB_DIR_IN);
@ -1863,14 +1991,14 @@ static int musb_schedule(
else else
head = &musb->out_bulk; head = &musb->out_bulk;
/* Enable bulk RX NAK timeout scheme when bulk requests are /* Enable bulk RX/TX NAK timeout scheme when bulk requests are
* multiplexed. This scheme doen't work in high speed to full * multiplexed. This scheme doen't work in high speed to full
* speed scenario as NAK interrupts are not coming from a * speed scenario as NAK interrupts are not coming from a
* full speed device connected to a high speed device. * full speed device connected to a high speed device.
* NAK timeout interval is 8 (128 uframe or 16ms) for HS and * NAK timeout interval is 8 (128 uframe or 16ms) for HS and
* 4 (8 frame or 8ms) for FS device. * 4 (8 frame or 8ms) for FS device.
*/ */
if (is_in && qh->dev) if (qh->dev)
qh->intv_reg = qh->intv_reg =
(USB_SPEED_HIGH == qh->dev->speed) ? 8 : 4; (USB_SPEED_HIGH == qh->dev->speed) ? 8 : 4;
goto success; goto success;

View File

@ -35,6 +35,8 @@
#ifndef _MUSB_HOST_H #ifndef _MUSB_HOST_H
#define _MUSB_HOST_H #define _MUSB_HOST_H
#include <linux/scatterlist.h>
static inline struct usb_hcd *musb_to_hcd(struct musb *musb) static inline struct usb_hcd *musb_to_hcd(struct musb *musb)
{ {
return container_of((void *) musb, struct usb_hcd, hcd_priv); return container_of((void *) musb, struct usb_hcd, hcd_priv);
@ -71,6 +73,7 @@ struct musb_qh {
u16 maxpacket; u16 maxpacket;
u16 frame; /* for periodic schedule */ u16 frame; /* for periodic schedule */
unsigned iso_idx; /* in urb->iso_frame_desc[] */ unsigned iso_idx; /* in urb->iso_frame_desc[] */
struct sg_mapping_iter sg_miter; /* for highmem in PIO mode */
}; };
/* map from control or bulk queue head to the first qh on that ring */ /* map from control or bulk queue head to the first qh on that ring */

View File

@ -81,8 +81,7 @@ static void musb_port_suspend(struct musb *musb, bool do_suspend)
switch (musb->xceiv->state) { switch (musb->xceiv->state) {
case OTG_STATE_A_HOST: case OTG_STATE_A_HOST:
musb->xceiv->state = OTG_STATE_A_SUSPEND; musb->xceiv->state = OTG_STATE_A_SUSPEND;
musb->is_active = is_otg_enabled(musb) musb->is_active = otg->host->b_hnp_enable;
&& otg->host->b_hnp_enable;
if (musb->is_active) if (musb->is_active)
mod_timer(&musb->otg_timer, jiffies mod_timer(&musb->otg_timer, jiffies
+ msecs_to_jiffies( + msecs_to_jiffies(
@ -91,8 +90,7 @@ static void musb_port_suspend(struct musb *musb, bool do_suspend)
break; break;
case OTG_STATE_B_HOST: case OTG_STATE_B_HOST:
musb->xceiv->state = OTG_STATE_B_WAIT_ACON; musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
musb->is_active = is_otg_enabled(musb) musb->is_active = otg->host->b_hnp_enable;
&& otg->host->b_hnp_enable;
musb_platform_try_idle(musb, 0); musb_platform_try_idle(musb, 0);
break; break;
default: default:
@ -190,8 +188,7 @@ void musb_root_disconnect(struct musb *musb)
switch (musb->xceiv->state) { switch (musb->xceiv->state) {
case OTG_STATE_A_SUSPEND: case OTG_STATE_A_SUSPEND:
if (is_otg_enabled(musb) if (otg->host->b_hnp_enable) {
&& otg->host->b_hnp_enable) {
musb->xceiv->state = OTG_STATE_A_PERIPHERAL; musb->xceiv->state = OTG_STATE_A_PERIPHERAL;
musb->g.is_a_peripheral = 1; musb->g.is_a_peripheral = 1;
break; break;
@ -273,7 +270,7 @@ int musb_hub_control(
musb_port_suspend(musb, false); musb_port_suspend(musb, false);
break; break;
case USB_PORT_FEAT_POWER: 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); musb_platform_set_vbus(musb, 0);
break; break;
case USB_PORT_FEAT_C_CONNECTION: case USB_PORT_FEAT_C_CONNECTION:
@ -369,7 +366,7 @@ int musb_hub_control(
* initialization logic, e.g. for OTG, or change any * initialization logic, e.g. for OTG, or change any
* logic relating to VBUS power-up. * logic relating to VBUS power-up.
*/ */
if (!(is_otg_enabled(musb) && hcd->self.is_b_host)) if (!hcd->self.is_b_host)
musb_start(musb); musb_start(musb);
break; break;
case USB_PORT_FEAT_RESET: case USB_PORT_FEAT_RESET:

View File

@ -380,7 +380,7 @@ void dma_controller_destroy(struct dma_controller *c)
kfree(controller); kfree(controller);
} }
struct dma_controller *__init struct dma_controller *__devinit
dma_controller_create(struct musb *musb, void __iomem *base) dma_controller_create(struct musb *musb, void __iomem *base)
{ {
struct musb_dma_controller *controller; struct musb_dma_controller *controller;

View File

@ -30,10 +30,12 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/of.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/delay.h>
#include <linux/usb/musb-omap.h> #include <linux/usb/musb-omap.h>
#include "musb_core.h" #include "musb_core.h"
@ -44,6 +46,7 @@ struct omap2430_glue {
struct platform_device *musb; struct platform_device *musb;
enum omap_musb_vbus_id_status status; enum omap_musb_vbus_id_status status;
struct work_struct omap_musb_mailbox_work; struct work_struct omap_musb_mailbox_work;
u32 __iomem *control_otghs;
}; };
#define glue_to_musb(g) platform_get_drvdata(g->musb) #define glue_to_musb(g) platform_get_drvdata(g->musb)
@ -51,6 +54,26 @@ struct omap2430_glue *_glue;
static struct timer_list musb_idle_timer; static struct timer_list musb_idle_timer;
/**
* omap4_usb_phy_mailbox - write to usb otg mailbox
* @glue: struct omap2430_glue *
* @val: the value to be written to the mailbox
*
* On detection of a device (ID pin is grounded), this API should be called
* to set AVALID, VBUSVALID and ID pin is grounded.
*
* When OMAP is connected to a host (OMAP in device mode), this API
* is called to set AVALID, VBUSVALID and ID pin in high impedance.
*
* XXX: This function will be removed once we have a seperate driver for
* control module
*/
static void omap4_usb_phy_mailbox(struct omap2430_glue *glue, u32 val)
{
if (glue->control_otghs)
writel(val, glue->control_otghs);
}
static void musb_do_idle(unsigned long _musb) static void musb_do_idle(unsigned long _musb)
{ {
struct musb *musb = (void *)_musb; struct musb *musb = (void *)_musb;
@ -140,7 +163,6 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
struct usb_otg *otg = musb->xceiv->otg; struct usb_otg *otg = musb->xceiv->otg;
u8 devctl; u8 devctl;
unsigned long timeout = jiffies + msecs_to_jiffies(1000); unsigned long timeout = jiffies + msecs_to_jiffies(1000);
int ret = 1;
/* HDRC controls CPEN, but beware current surges during device /* HDRC controls CPEN, but beware current surges during device
* connect. They can trigger transient overcurrent conditions * connect. They can trigger transient overcurrent conditions
* that must be ignored. * that must be ignored.
@ -150,6 +172,7 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
if (is_on) { if (is_on) {
if (musb->xceiv->state == OTG_STATE_A_IDLE) { if (musb->xceiv->state == OTG_STATE_A_IDLE) {
int loops = 100;
/* start the session */ /* start the session */
devctl |= MUSB_DEVCTL_SESSION; devctl |= MUSB_DEVCTL_SESSION;
musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
@ -159,17 +182,18 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
*/ */
while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) { while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) {
mdelay(5);
cpu_relax(); cpu_relax();
if (time_after(jiffies, timeout)) { if (time_after(jiffies, timeout)
|| loops-- <= 0) {
dev_err(musb->controller, dev_err(musb->controller,
"configured as A device timeout"); "configured as A device timeout");
ret = -EINVAL;
break; break;
} }
} }
if (ret && otg->set_vbus) if (otg->set_vbus)
otg_set_vbus(otg, 1); otg_set_vbus(otg, 1);
} else { } else {
musb->is_active = 1; musb->is_active = 1;
@ -245,6 +269,7 @@ EXPORT_SYMBOL_GPL(omap_musb_mailbox);
static void omap_musb_set_mailbox(struct omap2430_glue *glue) static void omap_musb_set_mailbox(struct omap2430_glue *glue)
{ {
u32 val;
struct musb *musb = glue_to_musb(glue); struct musb *musb = glue_to_musb(glue);
struct device *dev = musb->controller; struct device *dev = musb->controller;
struct musb_hdrc_platform_data *pdata = dev->platform_data; struct musb_hdrc_platform_data *pdata = dev->platform_data;
@ -258,9 +283,10 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
otg->default_a = true; otg->default_a = true;
musb->xceiv->state = OTG_STATE_A_IDLE; musb->xceiv->state = OTG_STATE_A_IDLE;
musb->xceiv->last_event = USB_EVENT_ID; musb->xceiv->last_event = USB_EVENT_ID;
if (!is_otg_enabled(musb) || musb->gadget_driver) { if (musb->gadget_driver) {
pm_runtime_get_sync(dev); pm_runtime_get_sync(dev);
usb_phy_init(musb->xceiv); val = AVALID | VBUSVALID;
omap4_usb_phy_mailbox(glue, val);
omap2430_musb_set_vbus(musb, 1); omap2430_musb_set_vbus(musb, 1);
} }
break; break;
@ -273,7 +299,8 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
musb->xceiv->last_event = USB_EVENT_VBUS; musb->xceiv->last_event = USB_EVENT_VBUS;
if (musb->gadget_driver) if (musb->gadget_driver)
pm_runtime_get_sync(dev); pm_runtime_get_sync(dev);
usb_phy_init(musb->xceiv); val = IDDIG | AVALID | VBUSVALID;
omap4_usb_phy_mailbox(glue, val);
break; break;
case OMAP_MUSB_ID_FLOAT: case OMAP_MUSB_ID_FLOAT:
@ -281,17 +308,17 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
dev_dbg(dev, "VBUS Disconnect\n"); dev_dbg(dev, "VBUS Disconnect\n");
musb->xceiv->last_event = USB_EVENT_NONE; musb->xceiv->last_event = USB_EVENT_NONE;
if (is_otg_enabled(musb) || is_peripheral_enabled(musb)) if (musb->gadget_driver) {
if (musb->gadget_driver) { pm_runtime_mark_last_busy(dev);
pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev);
pm_runtime_put_autosuspend(dev); }
}
if (data->interface_type == MUSB_INTERFACE_UTMI) { if (data->interface_type == MUSB_INTERFACE_UTMI) {
if (musb->xceiv->otg->set_vbus) if (musb->xceiv->otg->set_vbus)
otg_set_vbus(musb->xceiv->otg, 0); otg_set_vbus(musb->xceiv->otg, 0);
} }
usb_phy_shutdown(musb->xceiv); val = SESSEND | IDDIG;
omap4_usb_phy_mailbox(glue, val);
break; break;
default: default:
dev_dbg(dev, "ID float\n"); dev_dbg(dev, "ID float\n");
@ -366,6 +393,7 @@ err1:
static void omap2430_musb_enable(struct musb *musb) static void omap2430_musb_enable(struct musb *musb)
{ {
u8 devctl; u8 devctl;
u32 val;
unsigned long timeout = jiffies + msecs_to_jiffies(1000); unsigned long timeout = jiffies + msecs_to_jiffies(1000);
struct device *dev = musb->controller; struct device *dev = musb->controller;
struct omap2430_glue *glue = dev_get_drvdata(dev->parent); struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
@ -375,7 +403,8 @@ static void omap2430_musb_enable(struct musb *musb)
switch (glue->status) { switch (glue->status) {
case OMAP_MUSB_ID_GROUND: case OMAP_MUSB_ID_GROUND:
usb_phy_init(musb->xceiv); val = AVALID | VBUSVALID;
omap4_usb_phy_mailbox(glue, val);
if (data->interface_type != MUSB_INTERFACE_UTMI) if (data->interface_type != MUSB_INTERFACE_UTMI)
break; break;
devctl = musb_readb(musb->mregs, MUSB_DEVCTL); devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
@ -394,7 +423,8 @@ static void omap2430_musb_enable(struct musb *musb)
break; break;
case OMAP_MUSB_VBUS_VALID: case OMAP_MUSB_VBUS_VALID:
usb_phy_init(musb->xceiv); val = IDDIG | AVALID | VBUSVALID;
omap4_usb_phy_mailbox(glue, val);
break; break;
default: default:
@ -404,11 +434,14 @@ static void omap2430_musb_enable(struct musb *musb)
static void omap2430_musb_disable(struct musb *musb) static void omap2430_musb_disable(struct musb *musb)
{ {
u32 val;
struct device *dev = musb->controller; struct device *dev = musb->controller;
struct omap2430_glue *glue = dev_get_drvdata(dev->parent); struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
if (glue->status != OMAP_MUSB_UNKNOWN) if (glue->status != OMAP_MUSB_UNKNOWN) {
usb_phy_shutdown(musb->xceiv); val = SESSEND | IDDIG;
omap4_usb_phy_mailbox(glue, val);
}
} }
static int omap2430_musb_exit(struct musb *musb) static int omap2430_musb_exit(struct musb *musb)
@ -438,9 +471,14 @@ static u64 omap2430_dmamask = DMA_BIT_MASK(32);
static int __devinit omap2430_probe(struct platform_device *pdev) static int __devinit omap2430_probe(struct platform_device *pdev)
{ {
struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data; struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
struct omap_musb_board_data *data;
struct platform_device *musb; struct platform_device *musb;
struct omap2430_glue *glue; struct omap2430_glue *glue;
struct device_node *np = pdev->dev.of_node;
struct musb_hdrc_config *config;
struct resource *res;
int ret = -ENOMEM; int ret = -ENOMEM;
int musbid;
glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
if (!glue) { if (!glue) {
@ -448,12 +486,21 @@ static int __devinit omap2430_probe(struct platform_device *pdev)
goto err0; goto err0;
} }
musb = platform_device_alloc("musb-hdrc", -1); /* get the musb id */
if (!musb) { musbid = musb_get_id(&pdev->dev, GFP_KERNEL);
dev_err(&pdev->dev, "failed to allocate musb device\n"); if (musbid < 0) {
dev_err(&pdev->dev, "failed to allocate musb id\n");
ret = -ENOMEM;
goto err0; goto err0;
} }
musb = platform_device_alloc("musb-hdrc", musbid);
if (!musb) {
dev_err(&pdev->dev, "failed to allocate musb device\n");
goto err1;
}
musb->id = musbid;
musb->dev.parent = &pdev->dev; musb->dev.parent = &pdev->dev;
musb->dev.dma_mask = &omap2430_dmamask; musb->dev.dma_mask = &omap2430_dmamask;
musb->dev.coherent_dma_mask = omap2430_dmamask; musb->dev.coherent_dma_mask = omap2430_dmamask;
@ -462,6 +509,48 @@ static int __devinit omap2430_probe(struct platform_device *pdev)
glue->musb = musb; glue->musb = musb;
glue->status = OMAP_MUSB_UNKNOWN; glue->status = OMAP_MUSB_UNKNOWN;
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
glue->control_otghs = devm_request_and_ioremap(&pdev->dev, res);
if (glue->control_otghs == NULL)
dev_dbg(&pdev->dev, "Failed to obtain control memory\n");
if (np) {
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
dev_err(&pdev->dev,
"failed to allocate musb platfrom data\n");
ret = -ENOMEM;
goto err1;
}
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
if (!data) {
dev_err(&pdev->dev,
"failed to allocate musb board data\n");
ret = -ENOMEM;
goto err1;
}
config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL);
if (!data) {
dev_err(&pdev->dev,
"failed to allocate musb hdrc config\n");
goto err1;
}
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;
}
pdata->platform_ops = &omap2430_ops; pdata->platform_ops = &omap2430_ops;
platform_set_drvdata(pdev, glue); platform_set_drvdata(pdev, glue);
@ -478,13 +567,13 @@ static int __devinit omap2430_probe(struct platform_device *pdev)
pdev->num_resources); pdev->num_resources);
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to add resources\n"); dev_err(&pdev->dev, "failed to add resources\n");
goto err1; goto err2;
} }
ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to add platform_data\n"); dev_err(&pdev->dev, "failed to add platform_data\n");
goto err1; goto err2;
} }
pm_runtime_enable(&pdev->dev); pm_runtime_enable(&pdev->dev);
@ -492,14 +581,17 @@ static int __devinit omap2430_probe(struct platform_device *pdev)
ret = platform_device_add(musb); ret = platform_device_add(musb);
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to register musb device\n"); dev_err(&pdev->dev, "failed to register musb device\n");
goto err1; goto err2;
} }
return 0; return 0;
err1: err2:
platform_device_put(musb); platform_device_put(musb);
err1:
musb_put_id(&pdev->dev, musbid);
err0: err0:
return ret; return ret;
} }
@ -509,8 +601,8 @@ static int __devexit omap2430_remove(struct platform_device *pdev)
struct omap2430_glue *glue = platform_get_drvdata(pdev); struct omap2430_glue *glue = platform_get_drvdata(pdev);
cancel_work_sync(&glue->omap_musb_mailbox_work); cancel_work_sync(&glue->omap_musb_mailbox_work);
platform_device_del(glue->musb); musb_put_id(&pdev->dev, glue->musb->id);
platform_device_put(glue->musb); platform_device_unregister(glue->musb);
return 0; return 0;
} }
@ -559,12 +651,26 @@ static struct dev_pm_ops omap2430_pm_ops = {
#define DEV_PM_OPS NULL #define DEV_PM_OPS NULL
#endif #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 = { static struct platform_driver omap2430_driver = {
.probe = omap2430_probe, .probe = omap2430_probe,
.remove = __devexit_p(omap2430_remove), .remove = __devexit_p(omap2430_remove),
.driver = { .driver = {
.name = "musb-omap2430", .name = "musb-omap2430",
.pm = DEV_PM_OPS, .pm = DEV_PM_OPS,
.of_match_table = of_match_ptr(omap2430_id_table),
}, },
}; };

View File

@ -49,4 +49,13 @@
#define OTG_FORCESTDBY 0x414 #define OTG_FORCESTDBY 0x414
# define ENABLEFORCE (1 << 0) # define ENABLEFORCE (1 << 0)
/*
* Control Module bit definitions
* XXX: Will be removed once we have a driver for control module.
*/
#define AVALID BIT(0)
#define BVALID BIT(1)
#define VBUSVALID BIT(2)
#define SESSEND BIT(3)
#define IDDIG BIT(4)
#endif /* __MUSB_OMAP243X_H__ */ #endif /* __MUSB_OMAP243X_H__ */

View File

@ -154,7 +154,7 @@ tusb_fifo_write_unaligned(void __iomem *fifo, const u8 *buf, u16 len)
} }
static inline void tusb_fifo_read_unaligned(void __iomem *fifo, static inline void tusb_fifo_read_unaligned(void __iomem *fifo,
void __iomem *buf, u16 len) void *buf, u16 len)
{ {
u32 val; u32 val;
int i; int i;
@ -438,14 +438,13 @@ static void musb_do_idle(unsigned long _musb)
if (is_host_active(musb) && (musb->port1_status >> 16)) if (is_host_active(musb) && (musb->port1_status >> 16))
goto done; goto done;
if (is_peripheral_enabled(musb) && !musb->gadget_driver) { if (!musb->gadget_driver) {
wakeups = 0; wakeups = 0;
} else { } else {
wakeups = TUSB_PRCM_WHOSTDISCON wakeups = TUSB_PRCM_WHOSTDISCON
| TUSB_PRCM_WBUS | TUSB_PRCM_WBUS
| TUSB_PRCM_WVBUS; | TUSB_PRCM_WVBUS;
if (is_otg_enabled(musb)) wakeups |= TUSB_PRCM_WID;
wakeups |= TUSB_PRCM_WID;
} }
tusb_allow_idle(musb, wakeups); tusb_allow_idle(musb, wakeups);
} }
@ -583,21 +582,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 * 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. * 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) static int tusb_musb_set_mode(struct musb *musb, u8 musb_mode)
{ {
void __iomem *tbase = musb->ctrl_base; void __iomem *tbase = musb->ctrl_base;
u32 otg_stat, phy_otg_ctrl, phy_otg_ena, dev_conf; 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); otg_stat = musb_readl(tbase, TUSB_DEV_OTG_STAT);
phy_otg_ctrl = musb_readl(tbase, TUSB_PHY_OTG_CTRL); phy_otg_ctrl = musb_readl(tbase, TUSB_PHY_OTG_CTRL);
phy_otg_ena = musb_readl(tbase, TUSB_PHY_OTG_CTRL_ENABLE); phy_otg_ena = musb_readl(tbase, TUSB_PHY_OTG_CTRL_ENABLE);
@ -653,10 +643,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
if ((int_src & TUSB_INT_SRC_ID_STATUS_CHNG)) { if ((int_src & TUSB_INT_SRC_ID_STATUS_CHNG)) {
int default_a; int default_a;
if (is_otg_enabled(musb)) default_a = !(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS);
default_a = !(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS);
else
default_a = is_host_enabled(musb);
dev_dbg(musb->controller, "Default-%c\n", default_a ? 'A' : 'B'); dev_dbg(musb->controller, "Default-%c\n", default_a ? 'A' : 'B');
otg->default_a = default_a; otg->default_a = default_a;
tusb_musb_set_vbus(musb, default_a); tusb_musb_set_vbus(musb, default_a);
@ -670,8 +657,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
if (int_src & TUSB_INT_SRC_VBUS_SENSE_CHNG) { if (int_src & TUSB_INT_SRC_VBUS_SENSE_CHNG) {
/* B-dev state machine: no vbus ~= disconnect */ /* B-dev state machine: no vbus ~= disconnect */
if ((is_otg_enabled(musb) && !otg->default_a) if (!otg->default_a) {
|| !is_host_enabled(musb)) {
/* ? musb_root_disconnect(musb); */ /* ? musb_root_disconnect(musb); */
musb->port1_status &= musb->port1_status &=
~(USB_PORT_STAT_CONNECTION ~(USB_PORT_STAT_CONNECTION
@ -1120,10 +1106,8 @@ static int tusb_musb_init(struct musb *musb)
} }
musb->isr = tusb_musb_interrupt; musb->isr = tusb_musb_interrupt;
if (is_peripheral_enabled(musb)) { musb->xceiv->set_power = tusb_draw_power;
musb->xceiv->set_power = tusb_draw_power; the_musb = musb;
the_musb = musb;
}
setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb); setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
@ -1176,6 +1160,7 @@ static int __devinit tusb_probe(struct platform_device *pdev)
struct tusb6010_glue *glue; struct tusb6010_glue *glue;
int ret = -ENOMEM; int ret = -ENOMEM;
int musbid;
glue = kzalloc(sizeof(*glue), GFP_KERNEL); glue = kzalloc(sizeof(*glue), GFP_KERNEL);
if (!glue) { if (!glue) {
@ -1183,12 +1168,21 @@ static int __devinit tusb_probe(struct platform_device *pdev)
goto err0; goto err0;
} }
musb = platform_device_alloc("musb-hdrc", -1); /* get the musb id */
if (!musb) { musbid = musb_get_id(&pdev->dev, GFP_KERNEL);
dev_err(&pdev->dev, "failed to allocate musb device\n"); if (musbid < 0) {
dev_err(&pdev->dev, "failed to allocate musb id\n");
ret = -ENOMEM;
goto err1; goto err1;
} }
musb = platform_device_alloc("musb-hdrc", musbid);
if (!musb) {
dev_err(&pdev->dev, "failed to allocate musb device\n");
goto err2;
}
musb->id = musbid;
musb->dev.parent = &pdev->dev; musb->dev.parent = &pdev->dev;
musb->dev.dma_mask = &tusb_dmamask; musb->dev.dma_mask = &tusb_dmamask;
musb->dev.coherent_dma_mask = tusb_dmamask; musb->dev.coherent_dma_mask = tusb_dmamask;
@ -1204,26 +1198,29 @@ static int __devinit tusb_probe(struct platform_device *pdev)
pdev->num_resources); pdev->num_resources);
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to add resources\n"); dev_err(&pdev->dev, "failed to add resources\n");
goto err2; goto err3;
} }
ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to add platform_data\n"); dev_err(&pdev->dev, "failed to add platform_data\n");
goto err2; goto err3;
} }
ret = platform_device_add(musb); ret = platform_device_add(musb);
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to register musb device\n"); dev_err(&pdev->dev, "failed to register musb device\n");
goto err1; goto err3;
} }
return 0; return 0;
err2: err3:
platform_device_put(musb); platform_device_put(musb);
err2:
musb_put_id(&pdev->dev, musbid);
err1: err1:
kfree(glue); kfree(glue);
@ -1235,6 +1232,7 @@ static int __devexit tusb_remove(struct platform_device *pdev)
{ {
struct tusb6010_glue *glue = platform_get_drvdata(pdev); struct tusb6010_glue *glue = platform_get_drvdata(pdev);
musb_put_id(&pdev->dev, glue->musb->id);
platform_device_del(glue->musb); platform_device_del(glue->musb);
platform_device_put(glue->musb); platform_device_put(glue->musb);
kfree(glue); kfree(glue);

View File

@ -662,7 +662,7 @@ void dma_controller_destroy(struct dma_controller *c)
kfree(tusb_dma); kfree(tusb_dma);
} }
struct dma_controller *__init struct dma_controller *__devinit
dma_controller_create(struct musb *musb, void __iomem *base) dma_controller_create(struct musb *musb, void __iomem *base)
{ {
void __iomem *tbase = musb->ctrl_base; void __iomem *tbase = musb->ctrl_base;

View File

@ -74,25 +74,34 @@ static int __devinit ux500_probe(struct platform_device *pdev)
goto err0; goto err0;
} }
musb = platform_device_alloc("musb-hdrc", -1); /* get the musb id */
musbid = musb_get_id(&pdev->dev, GFP_KERNEL);
if (musbid < 0) {
dev_err(&pdev->dev, "failed to allocate musb id\n");
ret = -ENOMEM;
goto err1;
}
musb = platform_device_alloc("musb-hdrc", musbid);
if (!musb) { if (!musb) {
dev_err(&pdev->dev, "failed to allocate musb device\n"); dev_err(&pdev->dev, "failed to allocate musb device\n");
goto err1; goto err2;
} }
clk = clk_get(&pdev->dev, "usb"); clk = clk_get(&pdev->dev, "usb");
if (IS_ERR(clk)) { if (IS_ERR(clk)) {
dev_err(&pdev->dev, "failed to get clock\n"); dev_err(&pdev->dev, "failed to get clock\n");
ret = PTR_ERR(clk); ret = PTR_ERR(clk);
goto err2; goto err3;
} }
ret = clk_enable(clk); ret = clk_enable(clk);
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to enable clock\n"); dev_err(&pdev->dev, "failed to enable clock\n");
goto err3; goto err4;
} }
musb->id = musbid;
musb->dev.parent = &pdev->dev; musb->dev.parent = &pdev->dev;
musb->dev.dma_mask = pdev->dev.dma_mask; musb->dev.dma_mask = pdev->dev.dma_mask;
musb->dev.coherent_dma_mask = pdev->dev.coherent_dma_mask; musb->dev.coherent_dma_mask = pdev->dev.coherent_dma_mask;
@ -109,32 +118,35 @@ static int __devinit ux500_probe(struct platform_device *pdev)
pdev->num_resources); pdev->num_resources);
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to add resources\n"); dev_err(&pdev->dev, "failed to add resources\n");
goto err4; goto err5;
} }
ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to add platform_data\n"); dev_err(&pdev->dev, "failed to add platform_data\n");
goto err4; goto err5;
} }
ret = platform_device_add(musb); ret = platform_device_add(musb);
if (ret) { if (ret) {
dev_err(&pdev->dev, "failed to register musb device\n"); dev_err(&pdev->dev, "failed to register musb device\n");
goto err4; goto err5;
} }
return 0; return 0;
err4: err5:
clk_disable(clk); clk_disable(clk);
err3: err4:
clk_put(clk); clk_put(clk);
err2: err3:
platform_device_put(musb); platform_device_put(musb);
err2:
musb_put_id(&pdev->dev, musbid);
err1: err1:
kfree(glue); kfree(glue);
@ -146,6 +158,7 @@ static int __devexit ux500_remove(struct platform_device *pdev)
{ {
struct ux500_glue *glue = platform_get_drvdata(pdev); struct ux500_glue *glue = platform_get_drvdata(pdev);
musb_put_id(&pdev->dev, glue->musb->id);
platform_device_del(glue->musb); platform_device_del(glue->musb);
platform_device_put(glue->musb); platform_device_put(glue->musb);
clk_disable(glue->clk); clk_disable(glue->clk);

View File

@ -364,7 +364,7 @@ void dma_controller_destroy(struct dma_controller *c)
kfree(controller); kfree(controller);
} }
struct dma_controller *__init struct dma_controller *__devinit
dma_controller_create(struct musb *musb, void __iomem *base) dma_controller_create(struct musb *musb, void __iomem *base)
{ {
struct ux500_dma_controller *controller; struct ux500_dma_controller *controller;