diff options
-rw-r--r-- | drivers/usb/chipidea/bits.h | 1 | ||||
-rw-r--r-- | drivers/usb/chipidea/otg_fsm.c | 190 | ||||
-rw-r--r-- | drivers/usb/chipidea/otg_fsm.h | 51 |
3 files changed, 242 insertions, 0 deletions
diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h index 49d2dc1ab476..b21ce325fb29 100644 --- a/drivers/usb/chipidea/bits.h +++ b/drivers/usb/chipidea/bits.h | |||
@@ -81,6 +81,7 @@ | |||
81 | /* OTGSC */ | 81 | /* OTGSC */ |
82 | #define OTGSC_IDPU BIT(5) | 82 | #define OTGSC_IDPU BIT(5) |
83 | #define OTGSC_HADP BIT(6) | 83 | #define OTGSC_HADP BIT(6) |
84 | #define OTGSC_HABA BIT(7) | ||
84 | #define OTGSC_ID BIT(8) | 85 | #define OTGSC_ID BIT(8) |
85 | #define OTGSC_AVV BIT(9) | 86 | #define OTGSC_AVV BIT(9) |
86 | #define OTGSC_ASV BIT(10) | 87 | #define OTGSC_ASV BIT(10) |
diff --git a/drivers/usb/chipidea/otg_fsm.c b/drivers/usb/chipidea/otg_fsm.c index 4a40399df9e9..51b8a0fff3e5 100644 --- a/drivers/usb/chipidea/otg_fsm.c +++ b/drivers/usb/chipidea/otg_fsm.c | |||
@@ -26,6 +26,22 @@ | |||
26 | #include "otg.h" | 26 | #include "otg.h" |
27 | #include "otg_fsm.h" | 27 | #include "otg_fsm.h" |
28 | 28 | ||
29 | static struct ci_otg_fsm_timer *otg_timer_initializer | ||
30 | (struct ci_hdrc *ci, void (*function)(void *, unsigned long), | ||
31 | unsigned long expires, unsigned long data) | ||
32 | { | ||
33 | struct ci_otg_fsm_timer *timer; | ||
34 | |||
35 | timer = devm_kzalloc(ci->dev, sizeof(struct ci_otg_fsm_timer), | ||
36 | GFP_KERNEL); | ||
37 | if (!timer) | ||
38 | return NULL; | ||
39 | timer->function = function; | ||
40 | timer->expires = expires; | ||
41 | timer->data = data; | ||
42 | return timer; | ||
43 | } | ||
44 | |||
29 | /* | 45 | /* |
30 | * Add timer to active timer list | 46 | * Add timer to active timer list |
31 | */ | 47 | */ |
@@ -77,6 +93,164 @@ static void ci_otg_del_timer(struct ci_hdrc *ci, enum ci_otg_fsm_timer_index t) | |||
77 | hw_write_otgsc(ci, OTGSC_1MSIE, 0); | 93 | hw_write_otgsc(ci, OTGSC_1MSIE, 0); |
78 | } | 94 | } |
79 | 95 | ||
96 | /* The timeout callback function to set time out bit */ | ||
97 | static void set_tmout(void *ptr, unsigned long indicator) | ||
98 | { | ||
99 | *(int *)indicator = 1; | ||
100 | } | ||
101 | |||
102 | static void set_tmout_and_fsm(void *ptr, unsigned long indicator) | ||
103 | { | ||
104 | struct ci_hdrc *ci = (struct ci_hdrc *)ptr; | ||
105 | |||
106 | set_tmout(ci, indicator); | ||
107 | |||
108 | disable_irq_nosync(ci->irq); | ||
109 | queue_work(ci->wq, &ci->work); | ||
110 | } | ||
111 | |||
112 | static void a_wait_vfall_tmout_func(void *ptr, unsigned long indicator) | ||
113 | { | ||
114 | struct ci_hdrc *ci = (struct ci_hdrc *)ptr; | ||
115 | |||
116 | set_tmout(ci, indicator); | ||
117 | |||
118 | /* Disable port power for detect SRP */ | ||
119 | hw_write(ci, OP_PORTSC, PORTSC_W1C_BITS | PORTSC_PP, 0); | ||
120 | /* Clear exsiting DP irq */ | ||
121 | hw_write_otgsc(ci, OTGSC_DPIS, OTGSC_DPIS); | ||
122 | /* Enable data pulse irq */ | ||
123 | hw_write_otgsc(ci, OTGSC_DPIE, OTGSC_DPIE); | ||
124 | disable_irq_nosync(ci->irq); | ||
125 | queue_work(ci->wq, &ci->work); | ||
126 | } | ||
127 | |||
128 | static void b_ase0_brst_tmout_func(void *ptr, unsigned long indicator) | ||
129 | { | ||
130 | struct ci_hdrc *ci = (struct ci_hdrc *)ptr; | ||
131 | |||
132 | set_tmout(ci, indicator); | ||
133 | if (!hw_read_otgsc(ci, OTGSC_BSV)) | ||
134 | ci->fsm.b_sess_vld = 0; | ||
135 | |||
136 | disable_irq_nosync(ci->irq); | ||
137 | queue_work(ci->wq, &ci->work); | ||
138 | } | ||
139 | |||
140 | static void b_ssend_srp_tmout_func(void *ptr, unsigned long indicator) | ||
141 | { | ||
142 | struct ci_hdrc *ci = (struct ci_hdrc *)ptr; | ||
143 | |||
144 | set_tmout(ci, indicator); | ||
145 | |||
146 | /* only vbus fall below B_sess_vld in b_idle state */ | ||
147 | if (ci->transceiver->state == OTG_STATE_B_IDLE) { | ||
148 | disable_irq_nosync(ci->irq); | ||
149 | queue_work(ci->wq, &ci->work); | ||
150 | } | ||
151 | } | ||
152 | |||
153 | static void b_sess_vld_tmout_func(void *ptr, unsigned long indicator) | ||
154 | { | ||
155 | struct ci_hdrc *ci = (struct ci_hdrc *)ptr; | ||
156 | |||
157 | /* Check if A detached */ | ||
158 | if (!(hw_read_otgsc(ci, OTGSC_BSV))) { | ||
159 | ci->fsm.b_sess_vld = 0; | ||
160 | ci_otg_add_timer(ci, B_SSEND_SRP); | ||
161 | disable_irq_nosync(ci->irq); | ||
162 | queue_work(ci->wq, &ci->work); | ||
163 | } | ||
164 | } | ||
165 | |||
166 | static void b_data_pulse_end(void *ptr, unsigned long indicator) | ||
167 | { | ||
168 | struct ci_hdrc *ci = (struct ci_hdrc *)ptr; | ||
169 | |||
170 | ci->fsm.b_srp_done = 1; | ||
171 | ci->fsm.b_bus_req = 0; | ||
172 | if (ci->fsm.power_up) | ||
173 | ci->fsm.power_up = 0; | ||
174 | |||
175 | hw_write_otgsc(ci, OTGSC_HABA, 0); | ||
176 | |||
177 | disable_irq_nosync(ci->irq); | ||
178 | queue_work(ci->wq, &ci->work); | ||
179 | } | ||
180 | |||
181 | /* Initialize timers */ | ||
182 | static int ci_otg_init_timers(struct ci_hdrc *ci) | ||
183 | { | ||
184 | struct otg_fsm *fsm = &ci->fsm; | ||
185 | |||
186 | /* FSM used timers */ | ||
187 | ci->fsm_timer->timer_list[A_WAIT_VRISE] = | ||
188 | otg_timer_initializer(ci, &set_tmout_and_fsm, TA_WAIT_VRISE, | ||
189 | (unsigned long)&fsm->a_wait_vrise_tmout); | ||
190 | if (ci->fsm_timer->timer_list[A_WAIT_VRISE] == NULL) | ||
191 | return -ENOMEM; | ||
192 | |||
193 | ci->fsm_timer->timer_list[A_WAIT_VFALL] = | ||
194 | otg_timer_initializer(ci, &a_wait_vfall_tmout_func, | ||
195 | TA_WAIT_VFALL, (unsigned long)&fsm->a_wait_vfall_tmout); | ||
196 | if (ci->fsm_timer->timer_list[A_WAIT_VFALL] == NULL) | ||
197 | return -ENOMEM; | ||
198 | |||
199 | ci->fsm_timer->timer_list[A_WAIT_BCON] = | ||
200 | otg_timer_initializer(ci, &set_tmout_and_fsm, TA_WAIT_BCON, | ||
201 | (unsigned long)&fsm->a_wait_bcon_tmout); | ||
202 | if (ci->fsm_timer->timer_list[A_WAIT_BCON] == NULL) | ||
203 | return -ENOMEM; | ||
204 | |||
205 | ci->fsm_timer->timer_list[A_AIDL_BDIS] = | ||
206 | otg_timer_initializer(ci, &set_tmout_and_fsm, TA_AIDL_BDIS, | ||
207 | (unsigned long)&fsm->a_aidl_bdis_tmout); | ||
208 | if (ci->fsm_timer->timer_list[A_AIDL_BDIS] == NULL) | ||
209 | return -ENOMEM; | ||
210 | |||
211 | ci->fsm_timer->timer_list[A_BIDL_ADIS] = | ||
212 | otg_timer_initializer(ci, &set_tmout_and_fsm, TA_BIDL_ADIS, | ||
213 | (unsigned long)&fsm->a_bidl_adis_tmout); | ||
214 | if (ci->fsm_timer->timer_list[A_BIDL_ADIS] == NULL) | ||
215 | return -ENOMEM; | ||
216 | |||
217 | ci->fsm_timer->timer_list[B_ASE0_BRST] = | ||
218 | otg_timer_initializer(ci, &b_ase0_brst_tmout_func, TB_ASE0_BRST, | ||
219 | (unsigned long)&fsm->b_ase0_brst_tmout); | ||
220 | if (ci->fsm_timer->timer_list[B_ASE0_BRST] == NULL) | ||
221 | return -ENOMEM; | ||
222 | |||
223 | ci->fsm_timer->timer_list[B_SE0_SRP] = | ||
224 | otg_timer_initializer(ci, &set_tmout_and_fsm, TB_SE0_SRP, | ||
225 | (unsigned long)&fsm->b_se0_srp); | ||
226 | if (ci->fsm_timer->timer_list[B_SE0_SRP] == NULL) | ||
227 | return -ENOMEM; | ||
228 | |||
229 | ci->fsm_timer->timer_list[B_SSEND_SRP] = | ||
230 | otg_timer_initializer(ci, &b_ssend_srp_tmout_func, TB_SSEND_SRP, | ||
231 | (unsigned long)&fsm->b_ssend_srp); | ||
232 | if (ci->fsm_timer->timer_list[B_SSEND_SRP] == NULL) | ||
233 | return -ENOMEM; | ||
234 | |||
235 | ci->fsm_timer->timer_list[B_SRP_FAIL] = | ||
236 | otg_timer_initializer(ci, &set_tmout, TB_SRP_FAIL, | ||
237 | (unsigned long)&fsm->b_srp_done); | ||
238 | if (ci->fsm_timer->timer_list[B_SRP_FAIL] == NULL) | ||
239 | return -ENOMEM; | ||
240 | |||
241 | ci->fsm_timer->timer_list[B_DATA_PLS] = | ||
242 | otg_timer_initializer(ci, &b_data_pulse_end, TB_DATA_PLS, 0); | ||
243 | if (ci->fsm_timer->timer_list[B_DATA_PLS] == NULL) | ||
244 | return -ENOMEM; | ||
245 | |||
246 | ci->fsm_timer->timer_list[B_SESS_VLD] = otg_timer_initializer(ci, | ||
247 | &b_sess_vld_tmout_func, TB_SESS_VLD, 0); | ||
248 | if (ci->fsm_timer->timer_list[B_SESS_VLD] == NULL) | ||
249 | return -ENOMEM; | ||
250 | |||
251 | return 0; | ||
252 | } | ||
253 | |||
80 | /* -------------------------------------------------------------*/ | 254 | /* -------------------------------------------------------------*/ |
81 | /* Operations that will be called from OTG Finite State Machine */ | 255 | /* Operations that will be called from OTG Finite State Machine */ |
82 | /* -------------------------------------------------------------*/ | 256 | /* -------------------------------------------------------------*/ |
@@ -223,6 +397,7 @@ static struct otg_fsm_ops ci_otg_ops = { | |||
223 | 397 | ||
224 | int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci) | 398 | int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci) |
225 | { | 399 | { |
400 | int retval = 0; | ||
226 | struct usb_otg *otg; | 401 | struct usb_otg *otg; |
227 | 402 | ||
228 | otg = devm_kzalloc(ci->dev, | 403 | otg = devm_kzalloc(ci->dev, |
@@ -246,6 +421,21 @@ int ci_hdrc_otg_fsm_init(struct ci_hdrc *ci) | |||
246 | 421 | ||
247 | mutex_init(&ci->fsm.lock); | 422 | mutex_init(&ci->fsm.lock); |
248 | 423 | ||
424 | ci->fsm_timer = devm_kzalloc(ci->dev, | ||
425 | sizeof(struct ci_otg_fsm_timer_list), GFP_KERNEL); | ||
426 | if (!ci->fsm_timer) { | ||
427 | dev_err(ci->dev, | ||
428 | "Failed to allocate timer structure for ci hdrc otg!\n"); | ||
429 | return -ENOMEM; | ||
430 | } | ||
431 | |||
432 | INIT_LIST_HEAD(&ci->fsm_timer->active_timers); | ||
433 | retval = ci_otg_init_timers(ci); | ||
434 | if (retval) { | ||
435 | dev_err(ci->dev, "Couldn't init OTG timers\n"); | ||
436 | return retval; | ||
437 | } | ||
438 | |||
249 | /* Enable A vbus valid irq */ | 439 | /* Enable A vbus valid irq */ |
250 | hw_write_otgsc(ci, OTGSC_AVVIE, OTGSC_AVVIE); | 440 | hw_write_otgsc(ci, OTGSC_AVVIE, OTGSC_AVVIE); |
251 | 441 | ||
diff --git a/drivers/usb/chipidea/otg_fsm.h b/drivers/usb/chipidea/otg_fsm.h index 4d0dfe6900d6..420f081e7e6a 100644 --- a/drivers/usb/chipidea/otg_fsm.h +++ b/drivers/usb/chipidea/otg_fsm.h | |||
@@ -13,6 +13,57 @@ | |||
13 | 13 | ||
14 | #include <linux/usb/otg-fsm.h> | 14 | #include <linux/usb/otg-fsm.h> |
15 | 15 | ||
16 | /* | ||
17 | * A-DEVICE timing constants | ||
18 | */ | ||
19 | |||
20 | /* Wait for VBUS Rise */ | ||
21 | #define TA_WAIT_VRISE (100) /* a_wait_vrise: section 7.1.2 | ||
22 | * a_wait_vrise_tmr: section 7.4.5.1 | ||
23 | * TA_VBUS_RISE <= 100ms, section 4.4 | ||
24 | * Table 4-1: Electrical Characteristics | ||
25 | * ->DC Electrical Timing | ||
26 | */ | ||
27 | /* Wait for VBUS Fall */ | ||
28 | #define TA_WAIT_VFALL (1000) /* a_wait_vfall: section 7.1.7 | ||
29 | * a_wait_vfall_tmr: section: 7.4.5.2 | ||
30 | */ | ||
31 | /* Wait for B-Connect */ | ||
32 | #define TA_WAIT_BCON (10000) /* a_wait_bcon: section 7.1.3 | ||
33 | * TA_WAIT_BCON: should be between 1100 | ||
34 | * and 30000 ms, section 5.5, Table 5-1 | ||
35 | */ | ||
36 | /* A-Idle to B-Disconnect */ | ||
37 | #define TA_AIDL_BDIS (5000) /* a_suspend min 200 ms, section 5.2.1 | ||
38 | * TA_AIDL_BDIS: section 5.5, Table 5-1 | ||
39 | */ | ||
40 | /* B-Idle to A-Disconnect */ | ||
41 | #define TA_BIDL_ADIS (500) /* TA_BIDL_ADIS: section 5.2.1 | ||
42 | * 500ms is used for B switch to host | ||
43 | * for safe | ||
44 | */ | ||
45 | |||
46 | /* | ||
47 | * B-device timing constants | ||
48 | */ | ||
49 | |||
50 | /* Data-Line Pulse Time*/ | ||
51 | #define TB_DATA_PLS (10) /* b_srp_init,continue 5~10ms | ||
52 | * section:5.1.3 | ||
53 | */ | ||
54 | /* SRP Fail Time */ | ||
55 | #define TB_SRP_FAIL (6000) /* b_srp_init,fail time 5~6s | ||
56 | * section:5.1.6 | ||
57 | */ | ||
58 | /* A-SE0 to B-Reset */ | ||
59 | #define TB_ASE0_BRST (155) /* minimum 155 ms, section:5.3.1 */ | ||
60 | /* SE0 Time Before SRP */ | ||
61 | #define TB_SE0_SRP (1000) /* b_idle,minimum 1s, section:5.1.2 */ | ||
62 | /* SSEND time before SRP */ | ||
63 | #define TB_SSEND_SRP (1500) /* minimum 1.5 sec, section:5.1.2 */ | ||
64 | |||
65 | #define TB_SESS_VLD (1000) | ||
66 | |||
16 | enum ci_otg_fsm_timer_index { | 67 | enum ci_otg_fsm_timer_index { |
17 | /* | 68 | /* |
18 | * CI specific timers, start from the end | 69 | * CI specific timers, start from the end |