usb: musb: am335x: add support for dual instance
AM335x and TI81xx platform has dual musb controller so updating the musb_dspc.c to support the same. Changes: - Moved otg_workaround timer to glue structure - Moved static local variable last_timer to glue structure - PHY on/off related cleanups Signed-off-by: Ravi Babu <ravibabu@ti.com> Signed-off-by: Ajay Kumar Gupta <ajay.gupta@ti.com> Signed-off-by: Santhapuri, Damodar <damodar.santhapuri@ti.com> [afzal@ti.com: remove control module related modifications] Signed-off-by: Afzal Mohammed <afzal@ti.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
Родитель
8d2421e68c
Коммит
db4a93202e
|
@ -105,6 +105,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;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -112,9 +114,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 */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -164,8 +167,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,7 +204,7 @@ static void otg_timer(unsigned long _musb)
|
||||||
case OTG_STATE_B_IDLE:
|
case OTG_STATE_B_IDLE:
|
||||||
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;
|
||||||
|
@ -215,9 +218,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 (timeout == 0)
|
if (timeout == 0)
|
||||||
timeout = jiffies + msecs_to_jiffies(3);
|
timeout = jiffies + msecs_to_jiffies(3);
|
||||||
|
@ -227,22 +229,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)
|
||||||
|
@ -250,8 +253,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;
|
||||||
|
@ -310,7 +313,7 @@ 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 (drvvbus) {
|
} else if (drvvbus) {
|
||||||
|
@ -318,7 +321,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
|
||||||
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);
|
||||||
|
@ -345,7 +348,8 @@ static irqreturn_t dsps_interrupt(int irq, void *hci)
|
||||||
|
|
||||||
/* Poll for ID change */
|
/* Poll for ID change */
|
||||||
if (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);
|
||||||
|
|
||||||
|
@ -356,8 +360,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;
|
||||||
|
@ -380,7 +384,7 @@ static int dsps_musb_init(struct musb *musb)
|
||||||
goto err0;
|
goto err0;
|
||||||
}
|
}
|
||||||
|
|
||||||
setup_timer(&glue->timer, otg_timer, (unsigned long) musb);
|
setup_timer(&glue->timer[pdev->id], 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));
|
||||||
|
@ -411,10 +415,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);
|
||||||
|
|
||||||
del_timer_sync(&glue->timer);
|
del_timer_sync(&glue->timer[pdev->id]);
|
||||||
|
|
||||||
/* 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)
|
||||||
|
@ -493,7 +497,7 @@ static int __devinit dsps_create_musb_pdev(struct dsps_glue *glue, u8 id)
|
||||||
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;
|
pdata->platform_ops = &dsps_ops;
|
||||||
|
|
||||||
|
@ -525,11 +529,11 @@ 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)
|
||||||
{
|
{
|
||||||
musb_put_id(glue->dev, glue->musb->id);
|
musb_put_id(glue->dev, glue->musb[id]->id);
|
||||||
platform_device_del(glue->musb);
|
platform_device_del(glue->musb[id]);
|
||||||
platform_device_put(glue->musb);
|
platform_device_put(glue->musb[id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __devinit dsps_probe(struct platform_device *pdev)
|
static int __devinit dsps_probe(struct platform_device *pdev)
|
||||||
|
@ -539,7 +543,7 @@ static int __devinit dsps_probe(struct platform_device *pdev)
|
||||||
(struct dsps_musb_wrapper *)id->driver_data;
|
(struct dsps_musb_wrapper *)id->driver_data;
|
||||||
struct dsps_glue *glue;
|
struct dsps_glue *glue;
|
||||||
struct resource *iomem;
|
struct resource *iomem;
|
||||||
int ret;
|
int ret, i;
|
||||||
|
|
||||||
/* allocate glue */
|
/* allocate glue */
|
||||||
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
|
glue = kzalloc(sizeof(*glue), GFP_KERNEL);
|
||||||
|
@ -580,7 +584,16 @@ static int __devinit dsps_probe(struct platform_device *pdev)
|
||||||
ret = pm_runtime_get_sync(&pdev->dev);
|
ret = pm_runtime_get_sync(&pdev->dev);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(&pdev->dev, "pm_runtime_get_sync FAILED");
|
dev_err(&pdev->dev, "pm_runtime_get_sync FAILED");
|
||||||
goto err3;
|
/* create the child platform device for all instances of musb */
|
||||||
|
for (i = 0; i < wrp->instances ; i++) {
|
||||||
|
ret = dsps_create_musb_pdev(glue, i);
|
||||||
|
if (ret != 0) {
|
||||||
|
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;
|
||||||
|
@ -597,9 +610,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);
|
||||||
|
@ -665,6 +681,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 = {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче