]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
ARM: tegra: skip USB resume from LP0
authorSuresh Mangipudi <smangipudi@nvidia.com>
Fri, 13 Jun 2014 05:39:13 +0000 (11:09 +0530)
committerSuresh Mangipudi <smangipudi@nvidia.com>
Mon, 22 Sep 2014 08:48:48 +0000 (01:48 -0700)
Change to skip USB resume from LP0 when wake source is other than USB

Bug 1410165

Change-Id: I8fd177a128aca837dee8f737a783b59a5925e3c2
Signed-off-by: Suresh Mangipudi <smangipudi@nvidia.com>
Reviewed-on: http://git-master/r/454002
Reviewed-by: Venkat Moganty <vmoganty@nvidia.com>
(cherry picked from commit 6ea5e7c896c547cf23d1e0e8d54ff87503db92f1)
Reviewed-on: http://git-master/r/498749

arch/arm/mach-tegra/board-ardbeg.c
drivers/usb/core/driver.c
drivers/usb/host/ehci-tegra.c
drivers/usb/phy/phy-tegra-usb.c
drivers/usb/phy/tegra11x_usb_phy.c
drivers/usb/phy/tegra_usb_phy.h
include/linux/platform_data/tegra_usb.h
include/linux/usb.h
include/linux/usb/tegra_usb_phy.h

index 33c8311a35d498b253cf577212e8fdb31770443b..e6017850b3f03eb2ffaca1a7b354b51fc0d64554 100644 (file)
@@ -510,6 +510,7 @@ static struct tegra_usb_platform_data tegra_ehci2_hsic_smsc_hub_pdata = {
                .hot_plug = false,
                .remote_wakeup_supported = true,
                .power_off_on_suspend = true,
+               .skip_resume = true,
        },
 };
 
index 6eab440e1542e450f7733fb4cbbf35b1b1044313..b4f03341c21f556ceab07a6573269c7ff3f03b7e 100644 (file)
@@ -1360,6 +1360,10 @@ int usb_suspend(struct device *dev, pm_message_t msg)
 {
        struct usb_device       *udev = to_usb_device(dev);
 
+       if (udev->bus->skip_resume) {
+               if (udev->state == USB_STATE_SUSPENDED)
+                       return 0;
+       }
        unbind_no_pm_drivers_interfaces(udev);
 
        /* From now on we are sure all drivers support suspend/resume
@@ -1389,6 +1393,9 @@ int usb_resume(struct device *dev, pm_message_t msg)
        struct usb_device       *udev = to_usb_device(dev);
        int                     status;
 
+       if (udev->bus->skip_resume)
+               return 0;
+
        /* For all calls, take the device back to full power and
         * tell the PM core in case it was autosuspended previously.
         * Unbind the interfaces that will need rebinding later,
index 6b0c7ca09bca4a3656d62bae06320554272810ae..74f6a8abc7f2d512371e3ae5d221d672047c6db0 100644 (file)
@@ -80,6 +80,7 @@ struct tegra_ehci_hcd {
        struct delayed_work boost_cpu_freq_work;
        struct pm_qos_request boost_cpu_freq_req;
 #endif
+       bool is_skip_resume_enabled;
 };
 
 struct dma_align_buffer {
@@ -238,6 +239,7 @@ static irqreturn_t tegra_ehci_irq(struct usb_hcd *hcd)
                ehci_dbg(ehci, "pmc interrupt detected\n");
                wake_lock_timeout(&tegra->ehci_wake_lock, HZ);
                usb_hcd_resume_root_hub(hcd);
+               hcd_to_bus(hcd)->skip_resume = false;
                spin_unlock(&ehci->lock);
                return irq_status;
        }
@@ -435,8 +437,10 @@ static int tegra_ehci_bus_suspend(struct usb_hcd *hcd)
        err = ehci_bus_suspend(hcd);
        if (err)
                tegra->bus_suspended_fail = true;
-       else
+       else {
                usb_phy_set_suspend(get_usb_phy(tegra->phy), 1);
+               hcd_to_bus(hcd)->skip_resume = true;
+       }
        mutex_unlock(&tegra->sync_lock);
        EHCI_DBG("%s() END\n", __func__);
 
@@ -793,6 +797,8 @@ static int tegra_ehci_probe(struct platform_device *pdev)
 
        tegra->ehci = hcd_to_ehci(hcd);
 
+       hcd_to_bus(hcd)->skip_resume = pdata->u_data.host.skip_resume;
+       tegra->is_skip_resume_enabled = pdata->u_data.host.skip_resume;
        if (pdata->port_otg) {
                tegra->transceiver =
                        devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2);
@@ -836,6 +842,8 @@ static int tegra_ehci_resume(struct platform_device *pdev)
        int err = 0;
        struct tegra_ehci_hcd *tegra = platform_get_drvdata(pdev);
        struct tegra_usb_platform_data *pdata = dev_get_platdata(&pdev->dev);
+       struct usb_hcd *hcd = ehci_to_hcd(tegra->ehci);
+
        if (tegra->irq) {
                err = disable_irq_wake(tegra->irq);
                if (err < 0)
@@ -843,11 +851,21 @@ static int tegra_ehci_resume(struct platform_device *pdev)
                                "Couldn't disable USB host mode wakeup, irq=%d, "
                                "error=%d\n", tegra->irq, err);
        }
+
+       if (tegra->is_skip_resume_enabled) {
+               if (tegra_usb_phy_is_pmc_wake(tegra->phy))
+                       hcd_to_bus(hcd)->skip_resume = false;
+       }
+
        if (pdata->u_data.host.turn_off_vbus_on_lp0) {
                tegra_usb_enable_vbus(tegra->phy, true);
                tegra_ehci_notify_event(tegra, USB_EVENT_ID);
        }
-       return tegra_usb_phy_power_on(tegra->phy);
+       if (tegra->is_skip_resume_enabled)
+               return 0;
+       else
+               return tegra_usb_phy_power_on(tegra->phy);
+
 }
 
 static int tegra_ehci_suspend(struct platform_device *pdev, pm_message_t state)
@@ -860,12 +878,14 @@ static int tegra_ehci_suspend(struct platform_device *pdev, pm_message_t state)
        if (tegra->bus_suspended_fail)
                return -EBUSY;
        else {
-               err = tegra_usb_phy_power_off(tegra->phy);
-               if (err < 0)
-                       return err;
-               if (pdata->u_data.host.turn_off_vbus_on_lp0) {
-                       tegra_usb_enable_vbus(tegra->phy, false);
-                       tegra_usb_phy_pmc_disable(tegra->phy);
+               if (!tegra->is_skip_resume_enabled) {
+                       err = tegra_usb_phy_power_off(tegra->phy);
+                       if (err < 0)
+                               return err;
+                       if (pdata->u_data.host.turn_off_vbus_on_lp0) {
+                               tegra_usb_enable_vbus(tegra->phy, false);
+                               tegra_usb_phy_pmc_disable(tegra->phy);
+                       }
                }
                if (tegra->irq) {
                        err = enable_irq_wake(tegra->irq);
index e64e220b215bd033a75e96b2d14f4d497b4c023d..08c22ba6c8c9f763dbc84b86824c1c01eb3c1922 100644 (file)
@@ -938,3 +938,12 @@ void tegra_usb_phy_pmc_disable(struct tegra_usb_phy *phy)
                phy->ops->pmc_disable(phy);
 }
 EXPORT_SYMBOL_GPL(tegra_usb_phy_pmc_disable);
+
+bool tegra_usb_phy_is_pmc_wake(struct tegra_usb_phy *phy)
+{
+       bool status = 0;
+       if (phy->ops && phy->ops->is_pmc_wakeup)
+               status = phy->ops->is_pmc_wakeup(phy);
+       return status;
+}
+EXPORT_SYMBOL_GPL(tegra_usb_phy_is_pmc_wake);
index dd752bfa518521fbba9116ea6d0e1d385238a9b5..1d6de913436ee82bbefbef76597f4bcce3c19c54 100644 (file)
@@ -1879,6 +1879,23 @@ static void utmi_phy_pmc_disable(struct tegra_usb_phy *phy)
                pmc->pmc_ops->powerdown_pmc_wake_detect(pmc);
        }
 }
+
+static int utmi_phy_is_pmc_wakeup(struct tegra_usb_phy *phy)
+{
+       u32 val;
+       int inst = phy->inst;
+       void __iomem *base = phy->regs;
+       val = tegra_usb_pmc_reg_read(UTMIP_STATUS);
+       if (UTMIP_WALK_PTR_VAL(inst) & val)
+               return 1;
+       else {
+               val = readl(base + UTMIP_PMC_WAKEUP0);
+               val |= EVENT_INT_ENB;
+               writel(val, base + UTMIP_PMC_WAKEUP0);
+               return 0;
+       }
+}
+
 static bool utmi_phy_nv_charger_detect(struct tegra_usb_phy *phy)
 {
        int status1;
@@ -2597,6 +2614,24 @@ static int uhsic_phy_bus_port_power(struct tegra_usb_phy *phy)
        return 0;
 }
 
+static int uhsic_phy_is_pmc_wakeup(struct tegra_usb_phy *phy)
+{
+       u32 val;
+       int inst = phy->inst;
+       void __iomem *base = phy->regs;
+
+       val = tegra_usb_pmc_reg_read(UHSIC_STATUS(inst));
+       /* check whether we wake up from the remote resume */
+       if (UHSIC_WALK_PTR_VAL(inst) & val)
+               return 1;
+       else {
+               val = readl(base + UHSIC_PMC_WAKEUP0);
+               val |= EVENT_INT_ENB;
+               writel(val, base + UHSIC_PMC_WAKEUP0);
+               return 0;
+       }
+}
+
 static struct tegra_usb_phy_ops utmi_phy_ops = {
        .init           = _usb_phy_init,
        .reset          = usb_phy_reset,
@@ -2617,6 +2652,7 @@ static struct tegra_usb_phy_ops utmi_phy_ops = {
        .apple_charger_2000ma_detect = utmi_phy_apple_charger_2000ma_detect,
        .apple_charger_500ma_detect = utmi_phy_apple_charger_500ma_detect,
        .pmc_disable = utmi_phy_pmc_disable,
+       .is_pmc_wakeup = utmi_phy_is_pmc_wakeup,
 };
 
 static struct tegra_usb_phy_ops uhsic_phy_ops = {
@@ -2629,6 +2665,7 @@ static struct tegra_usb_phy_ops uhsic_phy_ops = {
        .power_off      = uhsic_phy_power_off,
        .pre_resume     = uhsic_phy_pre_resume,
        .port_power = uhsic_phy_bus_port_power,
+       .is_pmc_wakeup = uhsic_phy_is_pmc_wakeup,
 };
 
 static struct tegra_usb_phy_ops *phy_ops[] = {
index 8c04abbb1a2bf4a10738952db9653152628e79ca..f0488e80117e722d11752c92d1ceabe7ae2d1255 100644 (file)
@@ -75,6 +75,7 @@ struct tegra_usb_phy_ops {
        bool (*apple_charger_2000ma_detect)(struct tegra_usb_phy *phy);
        bool (*apple_charger_500ma_detect)(struct tegra_usb_phy *phy);
        void (*pmc_disable) (struct tegra_usb_phy *phy);
+       bool (*is_pmc_wakeup)(struct tegra_usb_phy *phy);
 };
 
 /**
index f248d0a5649984c736d210d7bcdd952b4b870512..10474043f6d891606e9ad55d9174f166820703a8 100644 (file)
@@ -142,6 +142,7 @@ struct tegra_usb_host_mode_data {
        bool power_off_on_suspend;
        bool turn_off_vbus_on_lp0;
        bool support_y_cable;
+       bool skip_resume;
 };
 
 /**
index a0bee5a28d1a578a27829edd231968e1ff11ce1d..f80095ba935cd885ddc3d7f71b9a9a65d82f8ae7 100644 (file)
@@ -363,6 +363,7 @@ struct usb_bus {
        struct mon_bus *mon_bus;        /* non-null when associated */
        int monitored;                  /* non-zero when monitored */
 #endif
+       bool skip_resume;
 };
 
 /* ----------------------------------------------------------------------- */
index 0e55728a83e2c5e18090e187ecbf223879450177..8a87e66f45d96cca2c6f44e0de99a792ad0bf974 100644 (file)
@@ -143,6 +143,8 @@ bool tegra_usb_phy_apple_500ma_charger_detected(struct tegra_usb_phy *phy);
  */
 bool tegra_usb_phy_pmc_wakeup(struct tegra_usb_phy *phy);
 
+bool tegra_usb_phy_is_pmc_wake(struct tegra_usb_phy *phy);
+
 void tegra_usb_phy_memory_prefetch_on(struct tegra_usb_phy *phy);
 
 void tegra_usb_phy_memory_prefetch_off(struct tegra_usb_phy *phy);