From patchwork Fri Aug 31 11:09:51 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "B, Ravi" X-Patchwork-Id: 1392741 Return-Path: X-Original-To: patchwork-linux-omap@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork2.kernel.org (Postfix) with ESMTP id 41DECE00A6 for ; Fri, 31 Aug 2012 11:10:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752782Ab2HaLKc (ORCPT ); Fri, 31 Aug 2012 07:10:32 -0400 Received: from arroyo.ext.ti.com ([192.94.94.40]:48269 "EHLO arroyo.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752161Ab2HaLKM (ORCPT ); Fri, 31 Aug 2012 07:10:12 -0400 Received: from dbdp20.itg.ti.com ([172.24.170.38]) by arroyo.ext.ti.com (8.13.7/8.13.7) with ESMTP id q7VBA4hi028377; Fri, 31 Aug 2012 06:10:05 -0500 Received: from DBDE71.ent.ti.com (localhost [127.0.0.1]) by dbdp20.itg.ti.com (8.13.8/8.13.8) with ESMTP id q7VBA2Ut015233; Fri, 31 Aug 2012 16:40:04 +0530 (IST) Received: from dbdp32.itg.ti.com (172.24.170.251) by DBDE71.ent.ti.com (172.24.170.149) with Microsoft SMTP Server id 14.1.323.3; Fri, 31 Aug 2012 16:40:03 +0530 Received: from localhost.localdomain (dbdp20.itg.ti.com [172.24.170.38]) by dbdp32.itg.ti.com (8.13.8/8.13.8) with ESMTP id q7VB9xiQ021790; Fri, 31 Aug 2012 16:40:03 +0530 From: Ravi Babu To: CC: , , , , Subject: [PATCH v9 05/13] usb: musb: am335x: add support for dual instance Date: Fri, 31 Aug 2012 16:39:51 +0530 Message-ID: <1346411399-23964-6-git-send-email-ravibabu@ti.com> X-Mailer: git-send-email 1.7.0.4 In-Reply-To: <1346411399-23964-1-git-send-email-ravibabu@ti.com> References: <1346411399-23964-1-git-send-email-ravibabu@ti.com> MIME-Version: 1.0 Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org 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: Ajay Kumar Gupta Signed-off-by: Santhapuri, Damodar Signed-off-by: Ravi Babu --- drivers/usb/musb/musb_dsps.c | 112 +++++++++++++++++++++++++----------------- 1 files changed, 66 insertions(+), 46 deletions(-) diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 36130ba..f883c25 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -106,6 +106,8 @@ struct dsps_musb_wrapper { /* miscellaneous stuff */ u32 musb_core_offset; u8 poll_seconds; + /* number of musb instances */ + u8 instances; }; /** @@ -113,16 +115,18 @@ struct dsps_musb_wrapper { */ struct dsps_glue { 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 */ - struct timer_list timer; /* otg_workaround timer */ - u32 __iomem *usb_ctrl; + struct timer_list timer[2]; /* otg_workaround timer */ + unsigned long last_timer[2]; /* last timer data for each instance */ + u32 __iomem *usb_ctrl[2]; u8 usbss_rev; }; /** * 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 @@ -131,11 +135,11 @@ struct dsps_glue { * 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 on) +static void musb_dsps_phy_control(struct dsps_glue *glue, u8 id, u8 on) { u32 usbphycfg; - usbphycfg = __raw_readl(glue->usb_ctrl); + usbphycfg = __raw_readl(glue->usb_ctrl[id]); if (on) { if (glue->usbss_rev == MUSB_USBSS_REV_816X) { @@ -158,7 +162,7 @@ static void musb_dsps_phy_control(struct dsps_glue *glue, u8 on) glue->usbss_rev == MUSB_USBSS_REV_33XX) usbphycfg |= USBPHY_CM_PWRDN | USBPHY_OTG_PWRDN; } - __raw_writel(usbphycfg, glue->usb_ctrl); + __raw_writel(usbphycfg, glue->usb_ctrl[id]); } /** * dsps_musb_enable - enable interrupts @@ -207,8 +211,8 @@ static void otg_timer(unsigned long _musb) struct musb *musb = (void *)_musb; void __iomem *mregs = musb->mregs; struct device *dev = musb->controller; - struct platform_device *pdev = to_platform_device(dev->parent); - struct dsps_glue *glue = platform_get_drvdata(pdev); + struct platform_device *pdev = to_platform_device(dev); + struct dsps_glue *glue = dev_get_drvdata(dev->parent); const struct dsps_musb_wrapper *wrp = glue->wrp; u8 devctl; unsigned long flags; @@ -244,7 +248,7 @@ static void otg_timer(unsigned long _musb) case OTG_STATE_B_IDLE: devctl = dsps_readb(mregs, MUSB_DEVCTL); if (devctl & MUSB_DEVCTL_BDEVICE) - mod_timer(&glue->timer, + mod_timer(&glue->timer[pdev->id], jiffies + wrp->poll_seconds * HZ); else musb->xceiv->state = OTG_STATE_A_IDLE; @@ -258,9 +262,8 @@ static void otg_timer(unsigned long _musb) static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) { struct device *dev = musb->controller; - struct platform_device *pdev = to_platform_device(dev->parent); - struct dsps_glue *glue = platform_get_drvdata(pdev); - static unsigned long last_timer; + struct platform_device *pdev = to_platform_device(dev); + struct dsps_glue *glue = dev_get_drvdata(dev->parent); if (timeout == 0) timeout = jiffies + msecs_to_jiffies(3); @@ -270,22 +273,23 @@ static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) { dev_dbg(musb->controller, "%s active, deleting timer\n", otg_state_string(musb->xceiv->state)); - del_timer(&glue->timer); - last_timer = jiffies; + del_timer(&glue->timer[pdev->id]); + glue->last_timer[pdev->id] = jiffies; 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, "Longer idle timer already pending, ignoring...\n"); return; } - last_timer = timeout; + glue->last_timer[pdev->id] = timeout; dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", otg_state_string(musb->xceiv->state), 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) @@ -293,8 +297,8 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) struct musb *musb = hci; void __iomem *reg_base = musb->ctrl_base; struct device *dev = musb->controller; - struct platform_device *pdev = to_platform_device(dev->parent); - struct dsps_glue *glue = platform_get_drvdata(pdev); + struct platform_device *pdev = to_platform_device(dev); + struct dsps_glue *glue = dev_get_drvdata(dev->parent); const struct dsps_musb_wrapper *wrp = glue->wrp; unsigned long flags; irqreturn_t ret = IRQ_NONE; @@ -353,7 +357,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) */ musb->int_usb &= ~MUSB_INTR_VBUSERROR; musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; - mod_timer(&glue->timer, + mod_timer(&glue->timer[pdev->id], jiffies + wrp->poll_seconds * HZ); WARNING("VBUS error workaround (delay coming)\n"); } else if (drvvbus) { @@ -361,7 +365,7 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) MUSB_HST_MODE(musb); musb->xceiv->otg->default_a = 1; musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; - del_timer(&glue->timer); + del_timer(&glue->timer[pdev->id]); } else { musb->is_active = 0; MUSB_DEV_MODE(musb); @@ -388,7 +392,8 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) /* Poll for ID change */ 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); @@ -398,8 +403,8 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) static int dsps_musb_init(struct musb *musb) { struct device *dev = musb->controller; - struct platform_device *pdev = to_platform_device(dev->parent); - struct dsps_glue *glue = platform_get_drvdata(pdev); + struct platform_device *pdev = to_platform_device(dev); + struct dsps_glue *glue = dev_get_drvdata(dev->parent); const struct dsps_musb_wrapper *wrp = glue->wrp; void __iomem *reg_base = musb->ctrl_base; u32 rev, val; @@ -421,13 +426,13 @@ static int dsps_musb_init(struct musb *musb) 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 */ dsps_writel(reg_base, wrp->control, (1 << wrp->reset)); /* Start the on-chip PHY and its PLL. */ - musb_dsps_phy_control(glue, 1); + musb_dsps_phy_control(glue, pdev->id, 1); musb->isr = dsps_interrupt; @@ -449,13 +454,13 @@ err0: static int dsps_musb_exit(struct musb *musb) { struct device *dev = musb->controller; - struct platform_device *pdev = to_platform_device(dev->parent); - struct dsps_glue *glue = platform_get_drvdata(pdev); + struct platform_device *pdev = to_platform_device(dev); + 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. */ - musb_dsps_phy_control(glue, 0); + musb_dsps_phy_control(glue, pdev->id, 0); /* NOP driver needs change if supporting dual instance */ usb_put_phy(musb->xceiv); @@ -495,8 +500,8 @@ static int __devinit dsps_create_musb_pdev(struct dsps_glue *glue, u8 id) goto err0; } - glue->usb_ctrl = devm_request_and_ioremap(&pdev->dev, res); - if (glue->usb_ctrl == NULL) { + glue->usb_ctrl[id] = devm_request_and_ioremap(&pdev->dev, res); + if (glue->usb_ctrl[id] == NULL) { dev_err(dev, "Failed to obtain usb_ctrl%d memory\n", id); ret = -ENODEV; goto err0; @@ -545,7 +550,7 @@ static int __devinit dsps_create_musb_pdev(struct dsps_glue *glue, u8 id) musb->dev.dma_mask = &musb_dmamask; musb->dev.coherent_dma_mask = musb_dmamask; - glue->musb = musb; + glue->musb[id] = musb; pdata->platform_ops = &dsps_ops; @@ -577,11 +582,11 @@ err0: return ret; } -static void __devexit dsps_delete_musb_pdev(struct dsps_glue *glue) +static void __devexit dsps_delete_musb_pdev(struct dsps_glue *glue, u8 id) { - musb_put_id(glue->dev, glue->musb->id); - platform_device_del(glue->musb); - platform_device_put(glue->musb); + musb_put_id(glue->dev, glue->musb[id]->id); + platform_device_del(glue->musb[id]); + platform_device_put(glue->musb[id]); } static int __devinit dsps_probe(struct platform_device *pdev) @@ -592,7 +597,7 @@ static int __devinit dsps_probe(struct platform_device *pdev) struct dsps_glue *glue; struct resource *iomem; u32 __iomem *usbss; - int ret; + int ret, i; /* allocate glue */ glue = kzalloc(sizeof(*glue), GFP_KERNEL); @@ -636,11 +641,16 @@ static int __devinit dsps_probe(struct platform_device *pdev) goto err2; } - /* create the child platform device for first instances of musb */ - ret = dsps_create_musb_pdev(glue, 0); - if (ret != 0) { - dev_err(&pdev->dev, "failed to create child pdev\n"); - 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; + } } /* read the usbss revision register */ @@ -661,9 +671,12 @@ err0: static int __devexit dsps_remove(struct platform_device *pdev) { struct dsps_glue *glue = platform_get_drvdata(pdev); + const struct dsps_musb_wrapper *wrp = glue->wrp; + int i; /* 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 */ pm_runtime_put(&pdev->dev); @@ -678,9 +691,12 @@ 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; /* Shutdown the on-chip PHY and its PLL. */ - musb_dsps_phy_control(glue, 0); + for (i = 0 ; i < wrp->instances ; i++) + musb_dsps_phy_control(glue, i, 0); return 0; } @@ -689,9 +705,12 @@ 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; /* Start the on-chip PHY and its PLL. */ - musb_dsps_phy_control(glue, 1); + for (i = 0 ; i < wrp->instances ; i++) + musb_dsps_phy_control(glue, i, 1); return 0; } @@ -727,6 +746,7 @@ static const struct dsps_musb_wrapper ti81xx_driver_data __devinitconst = { .rxep_bitmap = (0xfffe << 16), .musb_core_offset = 0x400, .poll_seconds = 2, + .instances = 2, }; static const struct platform_device_id musb_dsps_id_table[] __devinitconst = {