[PATCH v2 1/1] usb: chipidea: support runtime power management for otg fsm mode

2015-02-09 Thread Li Jun
From: Li Jun b47...@freescale.com

This patch adds runtime power management support for otg fsm mode, since
A-device in a_idle state cannot detect data pulse irq after suspended, here
enable wakeup by connection before suspend to make it can be resumed by DP;
and handle wakeup from that state like SRP.

Signed-off-by: Li Jun jun...@freescale.com
---
 drivers/usb/chipidea/bits.h|1 +
 drivers/usb/chipidea/core.c|   35 +++
 drivers/usb/chipidea/otg_fsm.c |   22 +++---
 3 files changed, 55 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h
index e69424d..3cb9bda 100644
--- a/drivers/usb/chipidea/bits.h
+++ b/drivers/usb/chipidea/bits.h
@@ -63,6 +63,7 @@
 #define PORTSC_HSPBIT(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)
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 4b22d7c..5a186e3 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -861,6 +861,33 @@ 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-fsm.otg-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 ((ci-fsm.otg-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;
+   } else {
+   ci-fsm.id = 1;
+   }
+   ci_otg_queue_work(ci);
+   }
+}
+
 static void ci_controller_suspend(struct ci_hdrc *ci)
 {
disable_irq(ci-irq);
@@ -894,6 +921,8 @@ static int ci_controller_resume(struct device *dev)
pm_runtime_mark_last_busy(ci-dev);
pm_runtime_put_autosuspend(ci-dev);
enable_irq(ci-irq);
+   if (ci_otg_is_fsm_mode(ci))
+   ci_otg_fsm_wakeup_by_srp(ci);
}
 
return 0;
@@ -921,6 +950,9 @@ static int ci_suspend(struct device *dev)
}
 
if (device_may_wakeup(dev)) {
+   if (ci_otg_is_fsm_mode(ci))
+   ci_otg_fsm_suspend_for_srp(ci);
+
usb_phy_set_wakeup(ci-usb_phy, true);
enable_irq_wake(ci-irq);
}
@@ -963,6 +995,9 @@ static int ci_runtime_suspend(struct device *dev)
return 0;
}
 
+   if (ci_otg_is_fsm_mode(ci))
+   ci_otg_fsm_suspend_for_srp(ci);
+
usb_phy_set_wakeup(ci-usb_phy, true);
ci_controller_suspend(ci);
 
diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c
index 562e581..e3cf5be 100644
--- a/drivers/usb/chipidea/otg_fsm.c
+++ b/drivers/usb/chipidea/otg_fsm.c
@@ -225,6 +225,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);
 
@@ -241,17 +244,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);
+   }
 }
 
 /*
@@ -275,8 +283,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)  

Re: [PATCH v2 1/1] usb: chipidea: support runtime power management for otg fsm mode

2015-02-09 Thread Peter Chen
On Mon, Feb 09, 2015 at 02:45:30PM +0800, Li Jun wrote:
 From: Li Jun b47...@freescale.com
 
 This patch adds runtime power management support for otg fsm mode, since
 A-device in a_idle state cannot detect data pulse irq after suspended, here
 enable wakeup by connection before suspend to make it can be resumed by DP;
 and handle wakeup from that state like SRP.
 
 Signed-off-by: Li Jun jun...@freescale.com
 ---
  drivers/usb/chipidea/bits.h|1 +
  drivers/usb/chipidea/core.c|   35 +++
  drivers/usb/chipidea/otg_fsm.c |   22 +++---
  3 files changed, 55 insertions(+), 3 deletions(-)
 
 diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h
 index e69424d..3cb9bda 100644
 --- a/drivers/usb/chipidea/bits.h
 +++ b/drivers/usb/chipidea/bits.h
 @@ -63,6 +63,7 @@
  #define PORTSC_HSPBIT(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)
 diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
 index 4b22d7c..5a186e3 100644
 --- a/drivers/usb/chipidea/core.c
 +++ b/drivers/usb/chipidea/core.c
 @@ -861,6 +861,33 @@ 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-fsm.otg-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 ((ci-fsm.otg-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;
 + } else {
 + ci-fsm.id = 1;
 + }
 + ci_otg_queue_work(ci);
 + }
 +}
 +
  static void ci_controller_suspend(struct ci_hdrc *ci)
  {
   disable_irq(ci-irq);
 @@ -894,6 +921,8 @@ static int ci_controller_resume(struct device *dev)
   pm_runtime_mark_last_busy(ci-dev);
   pm_runtime_put_autosuspend(ci-dev);
   enable_irq(ci-irq);
 + if (ci_otg_is_fsm_mode(ci))
 + ci_otg_fsm_wakeup_by_srp(ci);
   }
  
   return 0;
 @@ -921,6 +950,9 @@ static int ci_suspend(struct device *dev)
   }
  
   if (device_may_wakeup(dev)) {
 + if (ci_otg_is_fsm_mode(ci))
 + ci_otg_fsm_suspend_for_srp(ci);
 +
   usb_phy_set_wakeup(ci-usb_phy, true);
   enable_irq_wake(ci-irq);
   }
 @@ -963,6 +995,9 @@ static int ci_runtime_suspend(struct device *dev)
   return 0;
   }
  
 + if (ci_otg_is_fsm_mode(ci))
 + ci_otg_fsm_suspend_for_srp(ci);
 +
   usb_phy_set_wakeup(ci-usb_phy, true);
   ci_controller_suspend(ci);
  
 diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c
 index 562e581..e3cf5be 100644
 --- a/drivers/usb/chipidea/otg_fsm.c
 +++ b/drivers/usb/chipidea/otg_fsm.c
 @@ -225,6 +225,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);
  
 @@ -241,17 +244,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);
 + }
  }
  
  /*
 @@ -275,8 +283,10 @@ static inline int ci_otg_tick_timer(struct ci_hdrc *ci)
   }
  
   /* disable 1ms irq 

Re: [PATCH v2 1/1] usb: chipidea: support runtime power management for otg fsm mode

2015-02-09 Thread Li Jun
On Mon, Feb 09, 2015 at 03:22:17PM +0800, Peter Chen wrote:
 On Mon, Feb 09, 2015 at 02:45:30PM +0800, Li Jun wrote:
  From: Li Jun b47...@freescale.com
  
  This patch adds runtime power management support for otg fsm mode, since
  A-device in a_idle state cannot detect data pulse irq after suspended, here
  enable wakeup by connection before suspend to make it can be resumed by DP;
  and handle wakeup from that state like SRP.
  
  Signed-off-by: Li Jun jun...@freescale.com
  ---
   drivers/usb/chipidea/bits.h|1 +
   drivers/usb/chipidea/core.c|   35 +++
   drivers/usb/chipidea/otg_fsm.c |   22 +++---
   3 files changed, 55 insertions(+), 3 deletions(-)
  
 
 I meet system hang at my imx6sx board after running below commands
 at B device, at A device, it did not meet the system hang during the
 boots up with this patch.
 
 root@imx6sxsabresd:~# modprobe g_mass_storage file=/dev/mmcblk0p1
 removable=1
 [   43.202180] Number of LUNs=8
 [   43.205103] Mass Storage Function, version: 2009/09/11
 [   43.211669] LUN: removable file: (no medium)
 [   43.217236] Number of LUNs=1
 [   43.221121] LUN: removable file: /dev/mmcblk0p1
 [   43.225802] Number of LUNs=1
 [   43.231027] g_mass_storage gadget: Mass Storage Gadget,
 version: 2009/09/11
 [   43.238126] g_mass_storage gadget: userspace failed to
 provide iSerialNumber
 [   43.245249] g_mass_storage gadget: g_mass_storage ready
 

Reproduced on my i.MX6SX-SDB board, I checked and found it's due to there is
vbus glitch on otg port during another host-only port initialization, it should
not hang and there is the same problem if load gadget driver with vbus on(e.g.
connect to a PC host), I will submit another patch to fix it, but cannot cover
vbus glitch case.

Li Jun
 -- 
 
 Best Regards,
 Peter Chen
--
To unsubscribe from this list: send the line unsubscribe linux-usb in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html