diff options
Diffstat (limited to 'drivers/usb/musb')
-rw-r--r-- | drivers/usb/musb/musb_dsps.c | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index b159fc92f84..6053af1f57c 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -124,8 +124,44 @@ struct dsps_glue { const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */ struct timer_list timer[2]; /* otg_workaround timer */ unsigned long last_timer[2]; /* last timer data for each instance */ + u32 __iomem *usb_ctrl[2]; }; +#define DSPS_AM33XX_CONTROL_MODULE_PHYS_0 0x44e10620 +#define DSPS_AM33XX_CONTROL_MODULE_PHYS_1 0x44e10628 + +static const resource_size_t dsps_control_module_phys[] = { + DSPS_AM33XX_CONTROL_MODULE_PHYS_0, + DSPS_AM33XX_CONTROL_MODULE_PHYS_1, +}; + +/** + * musb_dsps_phy_control - phy on/off + * @glue: struct dsps_glue * + * @id: musb instance + * @on: flag for phy to be switched on or off + * + * This is to enable the PHY using usb_ctrl register in system control + * module space. + * + * XXX: This function will be removed once we have a seperate driver for + * control module + */ +static void musb_dsps_phy_control(struct dsps_glue *glue, u8 id, u8 on) +{ + u32 usbphycfg; + + usbphycfg = readl(glue->usb_ctrl[id]); + + if (on) { + usbphycfg &= ~(USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN); + usbphycfg |= USBPHY_OTGVDET_EN | USBPHY_OTGSESSEND_EN; + } else { + usbphycfg |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN; + } + + writel(usbphycfg, glue->usb_ctrl[id]); +} /** * dsps_musb_enable - enable interrupts */ @@ -392,6 +428,9 @@ static int dsps_musb_init(struct musb *musb) /* Reset the musb */ dsps_writel(reg_base, wrp->control, (1 << wrp->reset)); + /* Start the on-chip PHY and its PLL. */ + musb_dsps_phy_control(glue, pdev->id, 1); + musb->isr = dsps_interrupt; /* reset the otgdisable bit, needed for host mode to work */ @@ -417,6 +456,9 @@ static int dsps_musb_exit(struct musb *musb) del_timer_sync(&glue->timer[pdev->id]); + /* Shutdown the on-chip PHY and its PLL. */ + musb_dsps_phy_control(glue, pdev->id, 0); + /* NOP driver needs change if supporting dual instance */ usb_put_phy(musb->xceiv); usb_nop_xceiv_unregister(); @@ -449,6 +491,17 @@ static int __devinit dsps_create_musb_pdev(struct dsps_glue *glue, u8 id) char res_name[10]; int ret; + resources[0].start = dsps_control_module_phys[id]; + resources[0].end = resources[0].start + SZ_4 - 1; + resources[0].flags = IORESOURCE_MEM; + + glue->usb_ctrl[id] = devm_request_and_ioremap(&pdev->dev, resources); + if (glue->usb_ctrl[id] == NULL) { + dev_err(dev, "Failed to obtain usb_ctrl%d memory\n", id); + ret = -ENODEV; + goto err0; + } + /* first resource is for usbss, so start index from 1 */ res = platform_get_resource(pdev, IORESOURCE_MEM, id + 1); if (!res) { @@ -635,11 +688,27 @@ static int __devexit dsps_remove(struct platform_device *pdev) #ifdef CONFIG_PM_SLEEP static int dsps_suspend(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev->parent); + struct dsps_glue *glue = platform_get_drvdata(pdev); + const struct dsps_musb_wrapper *wrp = glue->wrp; + int i; + + for (i = 0; i < wrp->instances; i++) + musb_dsps_phy_control(glue, i, 0); + return 0; } static int dsps_resume(struct device *dev) { + struct platform_device *pdev = to_platform_device(dev->parent); + struct dsps_glue *glue = platform_get_drvdata(pdev); + const struct dsps_musb_wrapper *wrp = glue->wrp; + int i; + + for (i = 0; i < wrp->instances; i++) + musb_dsps_phy_control(glue, i, 1); + return 0; } #endif |