]> 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)
committerDhiren Parmar <dparmar@nvidia.com>
Sat, 27 Sep 2014 12:34:22 +0000 (05:34 -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
(cherry picked from commit 6ea5e7c896c547cf23d1e0e8d54ff87503db92f1)
Reviewed-on: http://git-master/r/539882
Reviewed-by: Dhiren Parmar <dparmar@nvidia.com>
Tested-by: Dhiren Parmar <dparmar@nvidia.com>
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 6901718d40226e8a311d60ac6de08aeea67f769a..48f66f1765d1e45e00b423b7fa9f937e4beabb9f 100644 (file)
@@ -612,6 +612,7 @@ static struct tegra_usb_platform_data tegra_ehci2_hsic_baseband_pdata = {
                .hot_plug = false,
                .remote_wakeup_supported = true,
                .power_off_on_suspend = true,
+               .skip_resume = true,
        },
 };
 
@@ -626,6 +627,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 3ccf4e279e413e19c412fdc42d5a2df1275a0de8..a15a9afcbb3964066854e28f57b87ecb44fbceca 100644 (file)
@@ -72,6 +72,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 {
@@ -230,6 +231,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;
        }
@@ -427,8 +429,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__);
 
@@ -655,6 +659,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);
@@ -698,6 +704,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)
@@ -705,11 +713,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)
@@ -722,12 +740,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 e16cd53991b7127906c84aac1e0151d40bc17677..7faeda2d27f30f66c6819d2ce66c892cc21b26c0 100644 (file)
@@ -955,3 +955,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 a309f759e70d131db1d09f52101f5b962ba0fa24..cf61f856ac5674560a3d7d1a05e6481dee8b169f 100644 (file)
@@ -1806,6 +1806,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;
@@ -2508,6 +2525,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,
@@ -2528,6 +2563,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 = {
@@ -2539,6 +2575,7 @@ static struct tegra_usb_phy_ops uhsic_phy_ops = {
        .power_on       = uhsic_phy_power_on,
        .power_off      = uhsic_phy_power_off,
        .port_power = uhsic_phy_bus_port_power,
+       .is_pmc_wakeup = uhsic_phy_is_pmc_wakeup,
 };
 
 static struct tegra_usb_phy_ops *phy_ops[] = {
index 2f74e48aab745caf5bb4c5d9aa106f5692d095f1..a57ff80754b474dd054b027f0da4708bf7bb0ffd 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 40720f6708067efd93245b33b5abfe183e0ec1bd..686fca9b9952ce333523303b906989ca86ef0c9a 100644 (file)
@@ -144,6 +144,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);