📄 otg_fsm.c
字号:
} else { // Disable local connection otg_reg_read16(REG_OTG_CONTROL, &wTemp); otg_reg_write16(REG_OTG_CONTROL, (wTemp&(~OTG_A_RDIS_LCON_EN))); }}void otgfsm_rcon_lse0_en(__u8 ctrl_flag) { __u16 wTemp; if(ctrl_flag == TRUE) { otg_reg_read16(REG_OTG_CONTROL, &wTemp); otg_reg_write16(REG_OTG_CONTROL, (wTemp|OTG_B_RCON_LSE0_EN)); } else { otg_reg_read16(REG_OTG_CONTROL, &wTemp); otg_reg_write16(REG_OTG_CONTROL, (wTemp&(~OTG_B_RCON_LSE0_EN))); }}/*----------------------------------------------*//* control local V Bus line *//* For B device, VBus pulsing *//* For A device VBus driving *//* ---------------------------------------------*/void otgfsm_local_vbus(otg_fsm_t *fsm_data, __u8 ctrl_flag) { __u16 wTemp; if(fsm_data->tcb.id == 1) { // B device vbus pulsing if( ctrl_flag == TRUE ) { otg_reg_read16(REG_OTG_CONTROL, &wTemp); otg_reg_write16(REG_OTG_CONTROL, (wTemp|OTG_CHRG_VBUS)); } else { otg_reg_read16(REG_OTG_CONTROL, &wTemp); otg_reg_write16(REG_OTG_CONTROL, (wTemp&(~OTG_CHRG_VBUS))); } } else { // A device driving VBUS line if(ctrl_flag == TRUE ) { otg_reg_read16(REG_OTG_CONTROL, &wTemp); otg_reg_write16(REG_OTG_CONTROL, (wTemp|OTG_DRV_VBUS)); } else { otg_reg_read16(REG_OTG_CONTROL, &wTemp); otg_reg_write16(REG_OTG_CONTROL, (wTemp&(~OTG_DRV_VBUS))); } }}/*----------------------------------------------*//* Read and update OTG status information *//* ---------------------------------------------*/void otgfsm_status_probe(otg_fsm_t *fsm_data) { __u16 data = 0; otg_reg_read16(REG_OTG_STATUS,&data); // Read Status Register fsm_data->regs.status_port.data = data;#ifdef CONFIG_DETAIL_DEBUG otgfsm_print_status(fsm_data); // Print OTG status #endif /* CONFIG_DETAIL_DEBUG */ // Copy Status and Interrupt registers info to FSM data fsm_data->tcb.id = fsm_data->regs.status_port.bitmap.ID; fsm_data->tcb.a_vbus_vld = fsm_data->regs.status_port.bitmap.a_vbus_vld; fsm_data->tcb.a_sess_vld = fsm_data->regs.status_port.bitmap.a_sess_vld; fsm_data->tcb.b_conn = fsm_data->regs.status_port.bitmap.rmt_conn; fsm_data->tcb.b_bus_resume = fsm_data->regs.int_port.bitmap.bus_resume; fsm_data->tcb.a_srp_det = fsm_data->regs.int_port.bitmap.a_srp_det; fsm_data->tcb.b_sess_end = fsm_data->regs.status_port.bitmap.b_sess_end; fsm_data->tcb.b_sess_vld = fsm_data->regs.status_port.bitmap.b_sess_vld; fsm_data->tcb.a_conn = fsm_data->regs.status_port.bitmap.rmt_conn; fsm_data->tcb.b_se0_srp = fsm_data->regs.int_port.bitmap.b_se0_srp; if(fsm_data->tcb.TimerRunning) { // Update timeout info, if timer is running fsm_data->tcb.TimeOut = fsm_data->regs.int_port.bitmap.otg_tmr_tmout; if(fsm_data->tcb.TimeOut) { fsm_data->tcb.TimerRunning = 0; } }}/*----------------------------------------------*//* Start timer for OTG fsm throug HW timer reg *//* Timer resolution is 0.01 milliseconds *//* the variable time is in milli seconds *//* ---------------------------------------------*/void otgfsm_start_timer(otg_fsm_t *fsm_data, __u8 timer_id, __u16 time ) { __u32 data; fsm_data->tcb.TimerRunning = 0; fsm_data->tcb.TimeOut = 0; fsm_data->tcb.TimerTick = time; //Timer interrupt @time ms fsm_data->tcb.TimerRunning = 1; fsm_data->tcb.TimerId = timer_id; otg_reg_write32(REG_OTG_TMR, 0); // Stop the timer first data = OTG_START_TIMER; data |= (time*OTG_TMR_RESOLUTION); otg_reg_write32(REG_OTG_TMR, data); // Start the timer}/*----------------------------------------------*//* stop the timer for OTG fsm *//* ---------------------------------------------*/void otgfsm_stop_timer(otg_fsm_t *fsm_data) { fsm_data->tcb.TimerRunning = 0; fsm_data->tcb.TimerId = 0; otg_reg_write32(REG_OTG_TMR, 0); // Stop the timer first}/*----------------------------------------------*//* Run the B device FSM *//* ---------------------------------------------*/void otgfsm_run_Bdevice(otg_fsm_t *fsm_data) { __u32 port_data; switch (fsm_data->tcb.state) { // B StateMachine case B_IDLE: fsm_data->tcb.b_hnp_en = 0; otgfsm_local_vbus(fsm_data, FALSE); otgfsm_local_pullup(FALSE); otgfsm_local_pulldown(TRUE); otgfsm_hc_dc_sel(TRUE); //default is DC if( fsm_data->tcb.id == 0 ) { otgfsm_init_fsm_data(fsm_data); otg_fsm_state_change(fsm_data,A_IDLE); } else if ( fsm_data->tcb.bus_req == 1 && fsm_data->tcb.b_sess_end == 1 && fsm_data->tcb.b_srp_done == 0) { // start VBus Pulsing otgfsm_local_pullup(TRUE); otgfsm_start_timer(fsm_data,B_DATA_PLS_TIMER_ID, B_DATA_PLS_TIMER); otg_fsm_state_change(fsm_data,B_SRP_INIT); } else if ( fsm_data->tcb.b_sess_vld == 1 ) { pdc_otg_control(NULL, PDC_ENABLE); otg_fsm_state_change(fsm_data,B_PERIPHERAL); } else if ( fsm_data->tcb.TimeOut == 1) { fsm_data->tcb.err_code = OTG_STATUS_TIMEOUT; fsm_data->tcb.b_srp_done = 0; fsm_data->tcb.bus_req = 0;// fsm_data->tcb.err_code = OTG_ERR_SRP_FAIL; } break; case B_SRP_INIT: if( fsm_data->tcb.TimeOut == 1 && fsm_data->tcb.TimerId == B_DATA_PLS_TIMER_ID) { otgfsm_local_pullup(FALSE); // VBUS Pulsing otgfsm_local_vbus(fsm_data, TRUE); otgfsm_start_timer(fsm_data,B_VBUS_PLS_TIMER_ID, B_VBUS_PLS_TIMER); } else if(fsm_data->tcb.TimeOut == 1 && fsm_data->tcb.TimerId == B_VBUS_PLS_TIMER_ID) { otgfsm_local_vbus(fsm_data, FALSE); fsm_data->tcb.b_srp_done = 1; } #if 0 /* Not needed */ else if ( fsm_data->tcb.b_sess_vld == 1 ) { if(fsm_data->tcb.TimerId == B_DATA_PLS_TIMER_ID) { otgfsm_local_pullup(FALSE); } else { otgfsm_local_vbus(fsm_data, FALSE); } otgfsm_stop_timer(fsm_data); fsm_data->tcb.b_srp_done = 0; pdc_otg_control(NULL, PDC_ENABLE); otg_fsm_state_change(fsm_data,B_PERIPHERAL); break; }#endif if( fsm_data->tcb.id == 0 || fsm_data->tcb.b_srp_done == 1 ) { //Allow 5s for A-device responding SRP otgfsm_start_timer(fsm_data, B_BUS_REQ_TIMER_ID, B_BUS_REQ_TIMER); otg_fsm_state_change(fsm_data,B_IDLE); } break; case B_PERIPHERAL: otgfsm_local_pullup(TRUE); otgfsm_hc_dc_sel(TRUE); if( fsm_data->tcb.b_sess_vld == 0 || fsm_data->tcb.id == 0) { pdc_otg_control(NULL,PDC_DISABLE); otg_fsm_state_change(fsm_data,B_IDLE); } else if ( fsm_data->tcb.bus_req == 1 && fsm_data->tcb.b_hnp_en == 1 && ( fsm_data->tcb.a_bus_suspend == 1) ) { otgfsm_rcon_lse0_en(TRUE); fsm_data->tcb.a_bus_suspend = 0; fsm_data->tcb.b_hnp_en = 0; otgfsm_start_timer(fsm_data,B_ASE0_BRST_TIMER_ID, B_ASE0_BRST_TIMER); //5ms (3.125-10ms) pdc_otg_control(NULL,PDC_DISABLE); otg_fsm_state_change(fsm_data,B_WAIT_ACON); } break; case B_WAIT_ACON: otgfsm_local_pullup(FALSE); otgfsm_hc_dc_sel(FALSE); if( fsm_data->tcb.b_sess_vld == 0 || fsm_data->tcb.id == 0 ) { otgfsm_rcon_lse0_en(FALSE); otgfsm_stop_timer(fsm_data); otg_fsm_state_change(fsm_data,B_IDLE); } else if( fsm_data->tcb.a_conn == 1 ) { otgfsm_rcon_lse0_en(FALSE); otgfsm_stop_timer(fsm_data); port_data = USB_OTG_ENUMERATE_DEV; phci_otg_port_control( fsm_data->hcd_priv, OTG_PORT_OPEN_PORT_IMM, &port_data); otg_fsm_state_change(fsm_data,B_HOST); } else if( fsm_data->tcb.TimeOut == 1 || fsm_data->tcb.a_bus_resume == 1) { if( fsm_data->tcb.TimeOut == 1) { fsm_data->tcb.err_code = OTG_STATUS_TIMEOUT; fsm_data->tcb.TimeOut = 0; fsm_data->tcb.a_bus_reset = 1; //SE0 >5ms should be taken as bus reset// fsm_data->tcb.err_code = OTG_ERR_B_ASE0_BRST_TMOUT; } else { fsm_data->tcb.a_bus_resume = 0; } otgfsm_rcon_lse0_en(FALSE); otg_fsm_state_change(fsm_data,B_PERIPHERAL); } break; case B_HOST: otgfsm_local_pullup(FALSE); otgfsm_hc_dc_sel(FALSE); if( fsm_data->tcb.b_sess_vld == 0 || fsm_data->tcb.id == 0 ) { // This might be a case of cable removal, and connection again, // so clear bus request fsm_data->tcb.bus_req = 0; phci_otg_port_control(fsm_data->hcd_priv, OTG_PORT_DISCONNECT_PORT, NULL); otg_fsm_state_change(fsm_data,B_IDLE); } else if( (fsm_data->tcb.a_conn == 0 || fsm_data->tcb.bus_req == 0) && fsm_data->tcb.AllowStateChange == 1 ) { fsm_data->tcb.AllowStateChange = 0; phci_otg_port_control(fsm_data->hcd_priv, OTG_PORT_DISCONNECT_PORT, NULL); pdc_otg_control(NULL, PDC_ENABLE); otg_fsm_state_change(fsm_data,B_PERIPHERAL); } break; default: break; }}/*----------------------------------------------*//* Run the A device FSM *//* ---------------------------------------------*/void otgfsm_run_Adevice(otg_fsm_t *fsm_data) { __u16 data; __u32 port_data; switch (fsm_data->tcb.state) { // A_device statemachine case A_IDLE: fsm_data->tcb.a_set_b_hnp_en = 0; otgfsm_local_vbus(fsm_data, FALSE); otgfsm_local_pullup(FALSE); otgfsm_local_pulldown(TRUE); otgfsm_hc_dc_sel(FALSE); //default HC otgfsm_srp_det_en(TRUE); //enable SRP detection if( fsm_data->tcb.id == 1 ) { otgfsm_srp_det_en(FALSE); //Disable SRP detection fsm_data->tcb.a_srp_det = 0; otg_fsm_state_change(fsm_data,B_IDLE); } else if( (fsm_data->tcb.bus_req == 1 || fsm_data->tcb.a_sess_vld == 1) && fsm_data->tcb.bus_drop == 0) { otgfsm_srp_det_en(FALSE); fsm_data->tcb.a_srp_det = 0; otgfsm_start_timer(fsm_data, A_WAIT_VRISE_TIMER_ID, A_WAIT_VRISE_TIMER); otg_fsm_state_change(fsm_data,A_WAIT_VRISE); } break; case A_WAIT_VRISE: otgfsm_local_vbus(fsm_data, TRUE); otgfsm_local_pullup(FALSE); otgfsm_hc_dc_sel(FALSE); if (((fsm_data->tcb.a_sess_vld == 1) && (fsm_data->tcb.b_sess_vld == 1) && (fsm_data->tcb.a_vbus_vld == 1)) || (fsm_data->tcb.TimeOut == 1)) { otgfsm_start_timer(fsm_data, A_WAIT_BCON_TIMER_ID, A_WAIT_BCON_TIMER); otg_fsm_state_change(fsm_data,A_WAIT_BCON); } break; case A_WAIT_BCON: otgfsm_local_vbus(fsm_data, TRUE); otgfsm_local_pullup(FALSE); otgfsm_hc_dc_sel(FALSE); if( fsm_data->tcb.TimeOut == 1) { if((fsm_data->tcb.b_conn == 1) && (fsm_data->tcb.TimerId == A_BCON_DEBOUNCE_TIMER_ID)) { fsm_data->tcb.AllowStateChange = 0; port_data = USB_OTG_GET_OTG_DESC; if(fsm_data->tcb.bus_req == 1) port_data |= USB_OTG_ENUMERATE_DEV; phci_otg_port_control(fsm_data->hcd_priv, OTG_PORT_OPEN_PORT_IMM, &port_data);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -