diff options
author | Li Jun <b47624@freescale.com> | 2014-03-17 04:33:19 -0400 |
---|---|---|
committer | Nitin Garg <nitin.garg@freescale.com> | 2014-04-16 12:02:35 -0400 |
commit | 6a623a35c0e5b268f6f4725c2a39cba9e3346b95 (patch) | |
tree | 1bf01c5c50302c9cdd15f00601155c5d9eb55bab /drivers/usb/chipidea/otg_fsm.c | |
parent | c777a32b4bf03edb888bb5831f1af2a5a5d58472 (diff) |
ENGR00307558-6 usb: chipidea: OTG fsm timers initialization.
This patch adds OTG fsm timers initialization, which use controller's 1ms
interrupt as timeout counter, also adds some local timers which are not
in otg_fsm_timer list.
Signed-off-by: Li Jun <b47624@freescale.com>
Diffstat (limited to 'drivers/usb/chipidea/otg_fsm.c')
-rw-r--r-- | drivers/usb/chipidea/otg_fsm.c | 190 |
1 files changed, 190 insertions, 0 deletions
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 | ||