From patchwork Thu Aug 2 12:12:46 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "B, Ravi" X-Patchwork-Id: 1267261 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 11A53DF215 for ; Thu, 2 Aug 2012 12:13:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754323Ab2HBMNl (ORCPT ); Thu, 2 Aug 2012 08:13:41 -0400 Received: from devils.ext.ti.com ([198.47.26.153]:45280 "EHLO devils.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753545Ab2HBMNG (ORCPT ); Thu, 2 Aug 2012 08:13:06 -0400 Received: from dbdp20.itg.ti.com ([172.24.170.38]) by devils.ext.ti.com (8.13.7/8.13.7) with ESMTP id q72CCx1g023532; Thu, 2 Aug 2012 07:12:59 -0500 Received: from DBDE70.ent.ti.com (localhost [127.0.0.1]) by dbdp20.itg.ti.com (8.13.8/8.13.8) with ESMTP id q72CCuL5029770; Thu, 2 Aug 2012 17:42:58 +0530 (IST) Received: from dbdp32.itg.ti.com (172.24.170.251) by dbde70.ent.ti.com (172.24.170.148) with Microsoft SMTP Server id 14.1.323.3; Thu, 2 Aug 2012 17:42:57 +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 q72CCs7r002948; Thu, 2 Aug 2012 17:42:56 +0530 From: Ravi Babu To: CC: , , , , , Subject: [PATCH v7 03/11] usb: musb: am335x: add support for dual instance Date: Thu, 2 Aug 2012 17:42:46 +0530 Message-ID: <1343909574-15633-4-git-send-email-ravibabu@ti.com> X-Mailer: git-send-email 1.7.0.4 In-Reply-To: <1343909574-15633-1-git-send-email-ravibabu@ti.com> References: <1343909574-15633-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 From: Ajay Kumar Gupta 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: Ravi Babu --- drivers/usb/musb/musb_dsps.c | 113 +++++++++++++++++++++++++----------------- 1 files changed, 67 insertions(+), 46 deletions(-) diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 2174699..7a09d55 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -105,6 +105,8 @@ struct dsps_musb_wrapper { /* miscellaneous stuff */ u32 musb_core_offset; u8 poll_seconds; + /* number of musb instances */ + u8 instances; }; /** @@ -112,16 +114,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 @@ -130,11 +134,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) { @@ -157,7 +161,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; @@ -247,7 +251,7 @@ static void otg_timer(unsigned long _musb) 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; @@ -261,9 +265,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 (!is_otg_enabled(musb)) return; @@ -276,22 +279,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) @@ -299,8 +303,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; @@ -360,7 +364,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 (is_host_enabled(musb) && drvvbus) { @@ -368,7 +372,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); @@ -395,7 +399,8 @@ static irqreturn_t dsps_interrupt(int irq, void *hci) /* Poll for ID change */ if (is_otg_enabled(musb) && 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); @@ -405,8 +410,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; @@ -429,13 +434,14 @@ static int dsps_musb_init(struct musb *musb) } if (is_host_enabled(musb)) - 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; @@ -457,14 +463,14 @@ 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); if (is_host_enabled(musb)) - 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); @@ -504,8 +510,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; @@ -554,7 +560,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; @@ -586,11 +592,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) @@ -601,7 +607,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); @@ -645,11 +651,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 */ @@ -670,9 +681,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); @@ -687,9 +701,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; } @@ -698,9 +715,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; } @@ -736,6 +756,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 = {