aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/chipidea/bits.h1
-rw-r--r--drivers/usb/chipidea/core.c43
-rw-r--r--drivers/usb/chipidea/otg_fsm.c22
3 files changed, 59 insertions, 7 deletions
diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h
index e69424d6e423..3cb9bda51ddf 100644
--- a/drivers/usb/chipidea/bits.h
+++ b/drivers/usb/chipidea/bits.h
@@ -63,6 +63,7 @@
63#define PORTSC_HSP BIT(9) 63#define PORTSC_HSP BIT(9)
64#define PORTSC_PP BIT(12) 64#define PORTSC_PP BIT(12)
65#define PORTSC_PTC (0x0FUL << 16) 65#define PORTSC_PTC (0x0FUL << 16)
66#define PORTSC_WKCN BIT(20)
66#define PORTSC_PHCD(d) ((d) ? BIT(22) : BIT(23)) 67#define PORTSC_PHCD(d) ((d) ? BIT(22) : BIT(23))
67/* PTS and PTW for non lpm version only */ 68/* PTS and PTW for non lpm version only */
68#define PORTSC_PFSC BIT(24) 69#define PORTSC_PFSC BIT(24)
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 4b22d7cb6557..74fea4fa41b1 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -798,11 +798,11 @@ static int ci_hdrc_probe(struct platform_device *pdev)
798 : CI_ROLE_GADGET; 798 : CI_ROLE_GADGET;
799 } 799 }
800 800
801 /* only update vbus status for peripheral */
802 if (ci->role == CI_ROLE_GADGET)
803 ci_handle_vbus_change(ci);
804
805 if (!ci_otg_is_fsm_mode(ci)) { 801 if (!ci_otg_is_fsm_mode(ci)) {
802 /* only update vbus status for peripheral */
803 if (ci->role == CI_ROLE_GADGET)
804 ci_handle_vbus_change(ci);
805
806 ret = ci_role_start(ci, ci->role); 806 ret = ci_role_start(ci, ci->role);
807 if (ret) { 807 if (ret) {
808 dev_err(dev, "can't start %s role\n", 808 dev_err(dev, "can't start %s role\n",
@@ -861,6 +861,33 @@ static int ci_hdrc_remove(struct platform_device *pdev)
861} 861}
862 862
863#ifdef CONFIG_PM 863#ifdef CONFIG_PM
864/* Prepare wakeup by SRP before suspend */
865static void ci_otg_fsm_suspend_for_srp(struct ci_hdrc *ci)
866{
867 if ((ci->fsm.otg->state == OTG_STATE_A_IDLE) &&
868 !hw_read_otgsc(ci, OTGSC_ID)) {
869 hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_PP,
870 PORTSC_PP);
871 hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_WKCN,
872 PORTSC_WKCN);
873 }
874}
875
876/* Handle SRP when wakeup by data pulse */
877static void ci_otg_fsm_wakeup_by_srp(struct ci_hdrc *ci)
878{
879 if ((ci->fsm.otg->state == OTG_STATE_A_IDLE) &&
880 (ci->fsm.a_bus_drop == 1) && (ci->fsm.a_bus_req == 0)) {
881 if (!hw_read_otgsc(ci, OTGSC_ID)) {
882 ci->fsm.a_srp_det = 1;
883 ci->fsm.a_bus_drop = 0;
884 } else {
885 ci->fsm.id = 1;
886 }
887 ci_otg_queue_work(ci);
888 }
889}
890
864static void ci_controller_suspend(struct ci_hdrc *ci) 891static void ci_controller_suspend(struct ci_hdrc *ci)
865{ 892{
866 disable_irq(ci->irq); 893 disable_irq(ci->irq);
@@ -894,6 +921,8 @@ static int ci_controller_resume(struct device *dev)
894 pm_runtime_mark_last_busy(ci->dev); 921 pm_runtime_mark_last_busy(ci->dev);
895 pm_runtime_put_autosuspend(ci->dev); 922 pm_runtime_put_autosuspend(ci->dev);
896 enable_irq(ci->irq); 923 enable_irq(ci->irq);
924 if (ci_otg_is_fsm_mode(ci))
925 ci_otg_fsm_wakeup_by_srp(ci);
897 } 926 }
898 927
899 return 0; 928 return 0;
@@ -921,6 +950,9 @@ static int ci_suspend(struct device *dev)
921 } 950 }
922 951
923 if (device_may_wakeup(dev)) { 952 if (device_may_wakeup(dev)) {
953 if (ci_otg_is_fsm_mode(ci))
954 ci_otg_fsm_suspend_for_srp(ci);
955
924 usb_phy_set_wakeup(ci->usb_phy, true); 956 usb_phy_set_wakeup(ci->usb_phy, true);
925 enable_irq_wake(ci->irq); 957 enable_irq_wake(ci->irq);
926 } 958 }
@@ -963,6 +995,9 @@ static int ci_runtime_suspend(struct device *dev)
963 return 0; 995 return 0;
964 } 996 }
965 997
998 if (ci_otg_is_fsm_mode(ci))
999 ci_otg_fsm_suspend_for_srp(ci);
1000
966 usb_phy_set_wakeup(ci->usb_phy, true); 1001 usb_phy_set_wakeup(ci->usb_phy, true);
967 ci_controller_suspend(ci); 1002 ci_controller_suspend(ci);
968 1003
diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c
index 562e581f6765..e3cf5be66d3d 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)
225 return; 225 return;
226 } 226 }
227 227
228 if (list_empty(active_timers))
229 pm_runtime_get(ci->dev);
230
228 timer->count = timer->expires; 231 timer->count = timer->expires;
229 list_add_tail(&timer->list, active_timers); 232 list_add_tail(&timer->list, active_timers);
230 233
@@ -241,17 +244,22 @@ static void ci_otg_del_timer(struct ci_hdrc *ci, enum ci_otg_fsm_timer_index t)
241 struct ci_otg_fsm_timer *tmp_timer, *del_tmp; 244 struct ci_otg_fsm_timer *tmp_timer, *del_tmp;
242 struct ci_otg_fsm_timer *timer = ci->fsm_timer->timer_list[t]; 245 struct ci_otg_fsm_timer *timer = ci->fsm_timer->timer_list[t];
243 struct list_head *active_timers = &ci->fsm_timer->active_timers; 246 struct list_head *active_timers = &ci->fsm_timer->active_timers;
247 int flag = 0;
244 248
245 if (t >= NUM_CI_OTG_FSM_TIMERS) 249 if (t >= NUM_CI_OTG_FSM_TIMERS)
246 return; 250 return;
247 251
248 list_for_each_entry_safe(tmp_timer, del_tmp, active_timers, list) 252 list_for_each_entry_safe(tmp_timer, del_tmp, active_timers, list)
249 if (tmp_timer == timer) 253 if (tmp_timer == timer) {
250 list_del(&timer->list); 254 list_del(&timer->list);
255 flag = 1;
256 }
251 257
252 /* Disable 1ms irq if there is no any active timer */ 258 /* Disable 1ms irq if there is no any active timer */
253 if (list_empty(active_timers)) 259 if (list_empty(active_timers) && (flag == 1)) {
254 hw_write_otgsc(ci, OTGSC_1MSIE, 0); 260 hw_write_otgsc(ci, OTGSC_1MSIE, 0);
261 pm_runtime_put(ci->dev);
262 }
255} 263}
256 264
257/* 265/*
@@ -275,8 +283,10 @@ static inline int ci_otg_tick_timer(struct ci_hdrc *ci)
275 } 283 }
276 284
277 /* disable 1ms irq if there is no any timer active */ 285 /* disable 1ms irq if there is no any timer active */
278 if ((expired == 1) && list_empty(active_timers)) 286 if ((expired == 1) && list_empty(active_timers)) {
279 hw_write_otgsc(ci, OTGSC_1MSIE, 0); 287 hw_write_otgsc(ci, OTGSC_1MSIE, 0);
288 pm_runtime_put(ci->dev);
289 }
280 290
281 return expired; 291 return expired;
282} 292}
@@ -585,6 +595,7 @@ int ci_otg_fsm_work(struct ci_hdrc *ci)
585 ci->fsm.otg->state < OTG_STATE_A_IDLE) 595 ci->fsm.otg->state < OTG_STATE_A_IDLE)
586 return 0; 596 return 0;
587 597
598 pm_runtime_get_sync(ci->dev);
588 if (otg_statemachine(&ci->fsm)) { 599 if (otg_statemachine(&ci->fsm)) {
589 if (ci->fsm.otg->state == OTG_STATE_A_IDLE) { 600 if (ci->fsm.otg->state == OTG_STATE_A_IDLE) {
590 /* 601 /*
@@ -609,8 +620,13 @@ int ci_otg_fsm_work(struct ci_hdrc *ci)
609 */ 620 */
610 ci_otg_queue_work(ci); 621 ci_otg_queue_work(ci);
611 } 622 }
623 } else if (ci->fsm.otg->state == OTG_STATE_A_HOST) {
624 pm_runtime_mark_last_busy(ci->dev);
625 pm_runtime_put_autosuspend(ci->dev);
626 return 0;
612 } 627 }
613 } 628 }
629 pm_runtime_put_sync(ci->dev);
614 return 0; 630 return 0;
615} 631}
616 632