ENGR00307558-13 usb: chipidea: otg-fsm: enable low power mode for otg fsm mode.
authorLi Jun <B47624@freescale.com>
Tue, 8 Apr 2014 14:21:13 +0000 (22:21 +0800)
committerNitin Garg <nitin.garg@freescale.com>
Wed, 16 Apr 2014 16:02:38 +0000 (11:02 -0500)
This patch enables runtime pm support for otg fsm mode.

Signed-off-by: Li Jun <b47624@freescale.com>
drivers/usb/chipidea/bits.h
drivers/usb/chipidea/ci_hdrc_imx.c
drivers/usb/chipidea/core.c
drivers/usb/chipidea/debug.c
drivers/usb/chipidea/otg_fsm.c
drivers/usb/phy/phy-mxs-usb.c

index b21ce325fb29131795f58a78f59af61da8f10dc9..db9d58e552fa9a5b2352e473f12e895b59b1cd9d 100644 (file)
@@ -53,6 +53,7 @@
 #define PORTSC_HSP            BIT(9)
 #define PORTSC_PP             BIT(12)
 #define PORTSC_PTC            (0x0FUL << 16)
+#define PORTSC_WKCN           BIT(20)
 #define PORTSC_PHCD(d)       ((d) ? BIT(22) : BIT(23))
 /* PTS and PTW for non lpm version only */
 #define PORTSC_PFSC           BIT(24)
index 41d21bbb69d897e7116cc7af06edc2af4122fe98..be9d32fbe2352719ec4313487af4a9ddb8178362 100644 (file)
@@ -28,6 +28,8 @@
 
 #include "ci.h"
 #include "ci_hdrc_imx.h"
+#include "otg.h"
+#include "bits.h"
 
 #define CI_HDRC_IMX_IMX28_WRITE_FIX            BIT(0)
 #define CI_HDRC_IMX_SUPPORT_RUNTIME_PM         BIT(1)
index 8e525b6c023dd755426c49608792799651d40731..d2e98edc5b1787176c362954dab4958c8f71fdf0 100644 (file)
@@ -802,6 +802,38 @@ static int ci_hdrc_remove(struct platform_device *pdev)
 }
 
 #ifdef CONFIG_PM
+/* Prepare wakeup by SRP before suspend */
+static void ci_otg_fsm_suspend_for_srp(struct ci_hdrc *ci)
+{
+       if ((ci->transceiver->state == OTG_STATE_A_IDLE) &&
+                               !hw_read_otgsc(ci, OTGSC_ID)) {
+               hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_PP,
+                                                               PORTSC_PP);
+               hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_WKCN,
+                                                               PORTSC_WKCN);
+       }
+}
+
+/* Handle SRP when wakeup by data pulse */
+static void ci_otg_fsm_wakeup_by_srp(struct ci_hdrc *ci)
+{
+       /*
+        * if a_idle wakeup by data pulse,
+        * handle it like normal SRP
+        */
+       if ((ci->transceiver->state == OTG_STATE_A_IDLE) &&
+               (ci->fsm.a_bus_drop == 1) && (ci->fsm.a_bus_req == 0)) {
+               if (!hw_read_otgsc(ci, OTGSC_ID)) {
+                       ci->fsm.a_srp_det = 1;
+                       ci->fsm.a_bus_drop = 0;
+                       disable_irq_nosync(ci->irq);
+                       queue_work(ci->wq, &ci->work);
+               } else {
+                       ci->fsm.id = 1;
+               }
+       }
+}
+
 static int ci_controller_suspend(struct device *dev)
 {
        struct ci_hdrc *ci = dev_get_drvdata(dev);
@@ -811,6 +843,9 @@ static int ci_controller_suspend(struct device *dev)
        if (ci->in_lpm)
                return 0;
 
+       if (ci_otg_is_fsm_mode(ci))
+               ci_otg_fsm_suspend_for_srp(ci);
+
        disable_irq(ci->irq);
 
        if (ci->transceiver)
@@ -853,6 +888,9 @@ static int ci_controller_resume(struct device *dev)
                mod_timer(&ci->timer, jiffies + msecs_to_jiffies(2000));
        }
 
+       if (ci_otg_is_fsm_mode(ci))
+               ci_otg_fsm_wakeup_by_srp(ci);
+
        return 0;
 }
 
index 7cccab6ff3081e0f1e1947c13085d9c0ce21b909..55beffc38973f7273977b2eb867386f6efd4c1d7 100644 (file)
@@ -339,6 +339,10 @@ int ci_registers_show(struct seq_file *s, void *unused)
        if (!ci)
                return 0;
 
+       seq_printf(s, "Low Power Mode: %d\n", ci->in_lpm);
+       if (ci->in_lpm)
+               return 0;
+
        /* ------ Registers ----- */
        tmp_reg = hw_read_intr_enable(ci);
        seq_printf(s, "USBINTR reg: %08x\n", tmp_reg);
index 028f7687ad2999b7ffd4c8e875f0675195eee296..630ae7560b753db3ebf870a82c87b0bf40de4495 100644 (file)
@@ -229,6 +229,9 @@ static void ci_otg_add_timer(struct ci_hdrc *ci, enum ci_otg_fsm_timer_index t)
                        return;
                }
 
+       if (list_empty(active_timers))
+               pm_runtime_get(ci->dev);
+
        timer->count = timer->expires;
        list_add_tail(&timer->list, active_timers);
 
@@ -245,17 +248,22 @@ static void ci_otg_del_timer(struct ci_hdrc *ci, enum ci_otg_fsm_timer_index t)
        struct ci_otg_fsm_timer *tmp_timer, *del_tmp;
        struct ci_otg_fsm_timer *timer = ci->fsm_timer->timer_list[t];
        struct list_head *active_timers = &ci->fsm_timer->active_timers;
+       int flag = 0;
 
        if (t >= NUM_CI_OTG_FSM_TIMERS)
                return;
 
        list_for_each_entry_safe(tmp_timer, del_tmp, active_timers, list)
-               if (tmp_timer == timer)
+               if (tmp_timer == timer) {
                        list_del(&timer->list);
+                       flag = 1;
+               }
 
        /* Disable 1ms irq if there is no any active timer */
-       if (list_empty(active_timers))
+       if (list_empty(active_timers) && (flag == 1)) {
                hw_write_otgsc(ci, OTGSC_1MSIE, 0);
+               pm_runtime_put(ci->dev);
+       }
 }
 
 /*
@@ -279,8 +287,10 @@ static inline int ci_otg_tick_timer(struct ci_hdrc *ci)
        }
 
        /* disable 1ms irq if there is no any timer active */
-       if ((expired == 1) && list_empty(active_timers))
+       if ((expired == 1) && list_empty(active_timers)) {
                hw_write_otgsc(ci, OTGSC_1MSIE, 0);
+               pm_runtime_put(ci->dev);
+       }
 
        return expired;
 }
@@ -605,6 +615,7 @@ int ci_otg_fsm_work(struct ci_hdrc *ci)
                return 0;
        }
 
+       pm_runtime_get_sync(ci->dev);
        if (otg_statemachine(&ci->fsm)) {
                if (ci->transceiver->state == OTG_STATE_A_IDLE) {
                        /*
@@ -634,6 +645,7 @@ int ci_otg_fsm_work(struct ci_hdrc *ci)
                        }
                }
        }
+       pm_runtime_put_sync(ci->dev);
        return 0;
 }
 
index c8e55045455cb9e9b556dec68b78b08f997fa831..305a3134bfa9dd67296c7ae2d7aafaaf6ac15aa0 100644 (file)
@@ -221,6 +221,11 @@ static bool mxs_phy_get_vbus_status(struct mxs_phy *mxs_phy)
                return false;
 }
 
+#ifdef CONFIG_USB_OTG_FSM
+static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on)
+{
+}
+#else
 static void __mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool disconnect)
 {
        void __iomem *base = mxs_phy->phy.io_priv;
@@ -273,6 +278,7 @@ static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on)
                __mxs_phy_disconnect_line(mxs_phy, false);
 
 }
+#endif
 
 static void mxs_phy_enable_ldo_in_suspend(struct mxs_phy *mxs_phy, bool on)
 {