From patchwork Fri Dec 10 12:40:51 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Kalliguddi, Hema" X-Patchwork-Id: 398282 X-Patchwork-Delegate: me@felipebalbi.com Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id oBACf2mG024134 for ; Fri, 10 Dec 2010 12:41:02 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756105Ab0LJMk6 (ORCPT ); Fri, 10 Dec 2010 07:40:58 -0500 Received: from devils.ext.ti.com ([198.47.26.153]:56955 "EHLO devils.ext.ti.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756100Ab0LJMk5 (ORCPT ); Fri, 10 Dec 2010 07:40:57 -0500 Received: from dbdp31.itg.ti.com ([172.24.170.98]) by devils.ext.ti.com (8.13.7/8.13.7) with ESMTP id oBACesXs024355 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Fri, 10 Dec 2010 06:40:56 -0600 Received: from localhost.localdomain (localhost [127.0.0.1]) by dbdp31.itg.ti.com (8.13.8/8.13.8) with ESMTP id oBACeriI027059; Fri, 10 Dec 2010 18:10:53 +0530 (IST) From: Hema HK To: linux-usb@vger.kernel.org, linux-omap@vger.kernel.org Cc: Hema HK , Felipe Balbi Subject: [PATCH 7/8 V2] usb: musb: Adding musb support for OMAP4430 Date: Fri, 10 Dec 2010 18:10:51 +0530 Message-Id: <1291984851-26040-1-git-send-email-hemahk@ti.com> X-Mailer: git-send-email 1.7.0.4 Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Fri, 10 Dec 2010 12:41:02 +0000 (UTC) Index: usb/drivers/usb/musb/musb_core.h =================================================================== --- usb.orig/drivers/usb/musb/musb_core.h +++ usb/drivers/usb/musb/musb_core.h @@ -411,6 +411,7 @@ struct musb { struct timer_list otg_timer; #endif + struct notifier_block nb; struct dma_controller *dma_controller; Index: usb/drivers/usb/musb/omap2430.c =================================================================== --- usb.orig/drivers/usb/musb/omap2430.c +++ usb/drivers/usb/musb/omap2430.c @@ -57,12 +57,8 @@ static void musb_do_idle(unsigned long _ spin_lock_irqsave(&musb->lock, flags); - devctl = musb_readb(musb->mregs, MUSB_DEVCTL); - switch (musb->xceiv->state) { case OTG_STATE_A_WAIT_BCON: - devctl &= ~MUSB_DEVCTL_SESSION; - musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); devctl = musb_readb(musb->mregs, MUSB_DEVCTL); if (devctl & MUSB_DEVCTL_BDEVICE) { @@ -142,6 +138,8 @@ static void omap2430_musb_try_idle(struc static void omap2430_musb_set_vbus(struct musb *musb, int is_on) { u8 devctl; + unsigned long timeout = jiffies + msecs_to_jiffies(1000); + int ret = 1; /* HDRC controls CPEN, but beware current surges during device * connect. They can trigger transient overcurrent conditions * that must be ignored. @@ -150,12 +148,35 @@ static void omap2430_musb_set_vbus(struc devctl = musb_readb(musb->mregs, MUSB_DEVCTL); if (is_on) { - musb->is_active = 1; - musb->xceiv->default_a = 1; - musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; - devctl |= MUSB_DEVCTL_SESSION; + if (musb->xceiv->state == OTG_STATE_A_IDLE) { + /* start the session */ + devctl |= MUSB_DEVCTL_SESSION; + musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); + /* + * Wait for the musb to set as A device to enable the + * VBUS + */ + while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) { + + cpu_relax(); + + if (time_after(jiffies, timeout)) { + dev_err(musb->controller, + "configured as A device timeout"); + ret = -EINVAL; + break; + } + } - MUSB_HST_MODE(musb); + if (ret && musb->xceiv->set_vbus) + otg_set_vbus(musb->xceiv, 1); + } else { + musb->is_active = 1; + musb->xceiv->default_a = 1; + musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; + devctl |= MUSB_DEVCTL_SESSION; + MUSB_HST_MODE(musb); + } } else { musb->is_active = 0; @@ -214,9 +235,62 @@ static inline void omap2430_low_level_in musb_writel(musb->mregs, OTG_FORCESTDBY, l); } +/* blocking notifier support */ +static int musb_otg_notifications(struct notifier_block *nb, + unsigned long event, void *unused) +{ + struct musb *musb = container_of(nb, struct musb, nb); + struct device *dev = musb->controller; + struct musb_hdrc_platform_data *pdata = dev->platform_data; + struct omap_musb_board_data *data = pdata->board_data; + + switch (event) { + case USB_EVENT_ID: + DBG(4, "ID GND\n"); + + if (is_otg_enabled(musb)) { + if (musb->gadget_driver) { + otg_init(musb->xceiv); + + if (data->interface_type == + MUSB_INTERFACE_UTMI) + omap2430_musb_set_vbus(musb, 1); + + } + } else { + otg_init(musb->xceiv); + if (data->interface_type == + MUSB_INTERFACE_UTMI) + omap2430_musb_set_vbus(musb, 1); + } + break; + + case USB_EVENT_VBUS: + DBG(4, "VBUS Connect\n"); + + otg_init(musb->xceiv); + break; + + case USB_EVENT_NONE: + DBG(4, "VBUS Disconnect\n"); + + if (data->interface_type == MUSB_INTERFACE_UTMI) { + if (musb->xceiv->set_vbus) + otg_set_vbus(musb->xceiv, 0); + } + otg_shutdown(musb->xceiv); + break; + default: + DBG(4, "ID float\n"); + return NOTIFY_DONE; + } + + return NOTIFY_OK; +} + static int omap2430_musb_init(struct musb *musb) { - u32 l; + u32 l, status = 0; struct device *dev = musb->controller; struct musb_hdrc_platform_data *plat = dev->platform_data; struct omap_musb_board_data *data = plat->board_data; @@ -268,6 +342,17 @@ static int omap2430_musb_init(struct mus musb_readl(musb->mregs, OTG_INTERFSEL), musb_readl(musb->mregs, OTG_SIMENABLE)); + musb->nb.notifier_call = musb_otg_notifications; + status = otg_register_notifier(musb->xceiv, &musb->nb); + + if (status) + DBG(1, "notification register failed\n"); + + /* check whether cable is already connected */ + if (musb->xceiv->state ==OTG_STATE_B_IDLE) + musb_otg_notifications(&musb->nb, 1, + musb->xceiv->gadget); + setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb); return 0;