aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/chipidea/otg.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/chipidea/otg.c')
-rw-r--r--drivers/usb/chipidea/otg.c48
1 files changed, 37 insertions, 11 deletions
diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c
index 39bd7ec8bf75..a048b08b9d4d 100644
--- a/drivers/usb/chipidea/otg.c
+++ b/drivers/usb/chipidea/otg.c
@@ -11,8 +11,8 @@
11 */ 11 */
12 12
13/* 13/*
14 * This file mainly handles otgsc register, it may include OTG operation 14 * This file mainly handles otgsc register, OTG fsm operations for HNP and SRP
15 * in the future. 15 * are also included.
16 */ 16 */
17 17
18#include <linux/usb/otg.h> 18#include <linux/usb/otg.h>
@@ -22,6 +22,26 @@
22#include "ci.h" 22#include "ci.h"
23#include "bits.h" 23#include "bits.h"
24#include "otg.h" 24#include "otg.h"
25#include "otg_fsm.h"
26
27/**
28 * hw_read_otgsc returns otgsc register bits value.
29 * @mask: bitfield mask
30 */
31u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask)
32{
33 return hw_read(ci, OP_OTGSC, mask);
34}
35
36/**
37 * hw_write_otgsc updates target bits of OTGSC register.
38 * @mask: bitfield mask
39 * @data: to be written
40 */
41void hw_write_otgsc(struct ci_hdrc *ci, u32 mask, u32 data)
42{
43 hw_write(ci, OP_OTGSC, mask | OTGSC_INT_STATUS_BITS, data);
44}
25 45
26/** 46/**
27 * ci_otg_role - pick role based on ID pin state 47 * ci_otg_role - pick role based on ID pin state
@@ -29,8 +49,7 @@
29 */ 49 */
30enum ci_role ci_otg_role(struct ci_hdrc *ci) 50enum ci_role ci_otg_role(struct ci_hdrc *ci)
31{ 51{
32 u32 sts = hw_read(ci, OP_OTGSC, ~0); 52 enum ci_role role = hw_read_otgsc(ci, OTGSC_ID)
33 enum ci_role role = sts & OTGSC_ID
34 ? CI_ROLE_GADGET 53 ? CI_ROLE_GADGET
35 : CI_ROLE_HOST; 54 : CI_ROLE_HOST;
36 55
@@ -39,14 +58,10 @@ enum ci_role ci_otg_role(struct ci_hdrc *ci)
39 58
40void ci_handle_vbus_change(struct ci_hdrc *ci) 59void ci_handle_vbus_change(struct ci_hdrc *ci)
41{ 60{
42 u32 otgsc;
43
44 if (!ci->is_otg) 61 if (!ci->is_otg)
45 return; 62 return;
46 63
47 otgsc = hw_read(ci, OP_OTGSC, ~0); 64 if (hw_read_otgsc(ci, OTGSC_BSV))
48
49 if (otgsc & OTGSC_BSV)
50 usb_gadget_vbus_connect(&ci->gadget); 65 usb_gadget_vbus_connect(&ci->gadget);
51 else 66 else
52 usb_gadget_vbus_disconnect(&ci->gadget); 67 usb_gadget_vbus_disconnect(&ci->gadget);
@@ -76,6 +91,11 @@ static void ci_otg_work(struct work_struct *work)
76{ 91{
77 struct ci_hdrc *ci = container_of(work, struct ci_hdrc, work); 92 struct ci_hdrc *ci = container_of(work, struct ci_hdrc, work);
78 93
94 if (ci_otg_is_fsm_mode(ci) && !ci_otg_fsm_work(ci)) {
95 enable_irq(ci->irq);
96 return;
97 }
98
79 if (ci->id_event) { 99 if (ci->id_event) {
80 ci->id_event = false; 100 ci->id_event = false;
81 ci_handle_id_switch(ci); 101 ci_handle_id_switch(ci);
@@ -102,6 +122,9 @@ int ci_hdrc_otg_init(struct ci_hdrc *ci)
102 return -ENODEV; 122 return -ENODEV;
103 } 123 }
104 124
125 if (ci_otg_is_fsm_mode(ci))
126 return ci_hdrc_otg_fsm_init(ci);
127
105 return 0; 128 return 0;
106} 129}
107 130
@@ -115,6 +138,9 @@ void ci_hdrc_otg_destroy(struct ci_hdrc *ci)
115 flush_workqueue(ci->wq); 138 flush_workqueue(ci->wq);
116 destroy_workqueue(ci->wq); 139 destroy_workqueue(ci->wq);
117 } 140 }
118 ci_disable_otg_interrupt(ci, OTGSC_INT_EN_BITS); 141 /* Disable all OTG irq and clear status */
119 ci_clear_otg_interrupt(ci, OTGSC_INT_STATUS_BITS); 142 hw_write_otgsc(ci, OTGSC_INT_EN_BITS | OTGSC_INT_STATUS_BITS,
143 OTGSC_INT_STATUS_BITS);
144 if (ci_otg_is_fsm_mode(ci))
145 ci_hdrc_otg_fsm_remove(ci);
120} 146}