From patchwork Thu Sep 2 15:58:18 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ming Lei X-Patchwork-Id: 149841 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 o82FxeOO013666 for ; Thu, 2 Sep 2010 15:59:40 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756132Ab0IBP6m (ORCPT ); Thu, 2 Sep 2010 11:58:42 -0400 Received: from mail-pz0-f46.google.com ([209.85.210.46]:64584 "EHLO mail-pz0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752529Ab0IBP6k (ORCPT ); Thu, 2 Sep 2010 11:58:40 -0400 Received: by pzk9 with SMTP id 9so158720pzk.19 for ; Thu, 02 Sep 2010 08:58:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:from:to:cc:subject:date :message-id:x-mailer; bh=zuSJQ+02izFQ3ivxMrJ/nUrQBk652WNHZltmh3rduXE=; b=E4A/KVgZVOdnbJZdQKDK9StSUAIq5APnZ0RaSiJVHORhAFDPiHVdhHCgkYhGp+R8pM blzPMpdp0HbgI6yVZDE1Ju5+WXUpdKFFjGvZXFTl6sMCQBriI4CADyuXpCnz7cgXWPMM Yzxw9GJF69+MCsNyx7WBObZjUWb0T/13K/SRY= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer; b=r/BzISjbQ35G9k1veDsxOLexa4naHMQh+TQnIL/6JVoP3dNnyJ9mBhrIn5s4LaOYq3 GrTOzO7Iba6aHHvAOkeLOS1+vE9rQ0IFZizZV6xBAzASYwIc/QDSHfZWZmi3Hgxukvx5 F0hsEfALnkC7XFW++x7eYt3Nu9WYuEQ75fIgQ= Received: by 10.114.88.18 with SMTP id l18mr90895wab.92.1283443115655; Thu, 02 Sep 2010 08:58:35 -0700 (PDT) Received: from localhost ([183.16.35.231]) by mx.google.com with ESMTPS id c24sm1185375wam.19.2010.09.02.08.58.29 (version=TLSv1/SSLv3 cipher=RC4-MD5); Thu, 02 Sep 2010 08:58:33 -0700 (PDT) From: tom.leiming@gmail.com To: greg@kroah.com Cc: linux-usb@vger.kernel.org, linux-omap@vger.kernel.org, linux-kernel@vger.kernel.org, Ming Lei , David Brownell , Felipe Balbi , Anand Gadiyar , Mike Frysinger , Sergei Shtylyov Subject: [PATCH] USB: otg: twl4030: fix phy initialization Date: Thu, 2 Sep 2010 23:58:18 +0800 Message-Id: <1283443098-15262-1-git-send-email-tom.leiming@gmail.com> X-Mailer: git-send-email 1.6.2.5 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]); Thu, 02 Sep 2010 15:59:40 +0000 (UTC) diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c index 05aaac1..df6381f 100644 --- a/drivers/usb/otg/twl4030-usb.c +++ b/drivers/usb/otg/twl4030-usb.c @@ -347,11 +347,22 @@ static void twl4030_i2c_access(struct twl4030_usb *twl, int on) } } -static void twl4030_phy_power(struct twl4030_usb *twl, int on) +static void __twl4030_phy_power(struct twl4030_usb *twl, int on) { + u8 old_pwr = twl4030_usb_read(twl, PHY_PWR_CTRL); u8 pwr; - pwr = twl4030_usb_read(twl, PHY_PWR_CTRL); + if (on) + pwr = old_pwr & ~PHY_PWR_PHYPWD; + else + pwr = old_pwr | PHY_PWR_PHYPWD; + + if (pwr != old_pwr) + WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0); +} + +static void twl4030_phy_power(struct twl4030_usb *twl, int on) +{ if (on) { regulator_enable(twl->usb3v1); regulator_enable(twl->usb1v8); @@ -365,15 +376,13 @@ static void twl4030_phy_power(struct twl4030_usb *twl, int on) twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2); regulator_enable(twl->usb1v5); - pwr &= ~PHY_PWR_PHYPWD; - WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0); + __twl4030_phy_power(twl, 1); twl4030_usb_write(twl, PHY_CLK_CTRL, twl4030_usb_read(twl, PHY_CLK_CTRL) | (PHY_CLK_CTRL_CLOCKGATING_EN | PHY_CLK_CTRL_CLK32K_EN)); } else { - pwr |= PHY_PWR_PHYPWD; - WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0); + __twl4030_phy_power(twl, 0); regulator_disable(twl->usb1v5); regulator_disable(twl->usb1v8); regulator_disable(twl->usb3v1); @@ -387,19 +396,25 @@ static void twl4030_phy_suspend(struct twl4030_usb *twl, int controller_off) twl4030_phy_power(twl, 0); twl->asleep = 1; + dev_dbg(twl->dev, "%s\n", __func__); } -static void twl4030_phy_resume(struct twl4030_usb *twl) +static void __twl4030_phy_resume(struct twl4030_usb *twl) { - if (!twl->asleep) - return; - twl4030_phy_power(twl, 1); twl4030_i2c_access(twl, 1); twl4030_usb_set_mode(twl, twl->usb_mode); if (twl->usb_mode == T2_USB_MODE_ULPI) twl4030_i2c_access(twl, 0); +} + +static void twl4030_phy_resume(struct twl4030_usb *twl) +{ + if (!twl->asleep) + return; + __twl4030_phy_resume(twl); twl->asleep = 0; + dev_dbg(twl->dev, "%s\n", __func__); } static int twl4030_usb_ldo_init(struct twl4030_usb *twl) @@ -502,6 +517,26 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl) return IRQ_HANDLED; } +static void twl4030_usb_phy_init(struct twl4030_usb *twl) +{ + int status; + + status = twl4030_usb_linkstat(twl); + if (status >= 0) { + if (status == USB_EVENT_NONE) { + __twl4030_phy_power(twl, 0); + twl->asleep = 1; + } else { + __twl4030_phy_resume(twl); + twl->asleep = 0; + } + + blocking_notifier_call_chain(&twl->otg.notifier, status, + twl->otg.gadget); + } + sysfs_notify(&twl->dev->kobj, NULL, "vbus"); +} + static int twl4030_set_suspend(struct otg_transceiver *x, int suspend) { struct twl4030_usb *twl = xceiv_to_twl(x); @@ -550,7 +585,6 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev) struct twl4030_usb_data *pdata = pdev->dev.platform_data; struct twl4030_usb *twl; int status, err; - u8 pwr; if (!pdata) { dev_dbg(&pdev->dev, "platform_data not available\n"); @@ -569,10 +603,7 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev) twl->otg.set_peripheral = twl4030_set_peripheral; twl->otg.set_suspend = twl4030_set_suspend; twl->usb_mode = pdata->usb_mode; - - pwr = twl4030_usb_read(twl, PHY_PWR_CTRL); - - twl->asleep = (pwr & PHY_PWR_PHYPWD); + twl->asleep = 1; /* init spinlock for workqueue */ spin_lock_init(&twl->lock); @@ -610,15 +641,10 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev) return status; } - /* The IRQ handler just handles changes from the previous states - * of the ID and VBUS pins ... in probe() we must initialize that - * previous state. The easy way: fake an IRQ. - * - * REVISIT: a real IRQ might have happened already, if PREEMPT is - * enabled. Else the IRQ may not yet be configured or enabled, - * because of scheduling delays. + /* Power down phy or make it work according to + * current link state. */ - twl4030_usb_irq(twl->irq, twl); + twl4030_usb_phy_init(twl); dev_info(&pdev->dev, "Initialized TWL4030 USB module\n"); return 0;