📄 otg_fsm.c
字号:
otg_fsm_state_change(fsm_data,A_HOST); } else { fsm_data->tcb.err_code = OTG_STATUS_TIMEOUT; fsm_data->tcb.bus_req = 0; otgfsm_stop_timer(fsm_data); otg_fsm_state_change(fsm_data,A_WAIT_VFALL); } } else if( fsm_data->tcb.id == 1 || fsm_data->tcb.bus_drop == 1) { fsm_data->tcb.bus_req = 0; otgfsm_stop_timer(fsm_data); otg_fsm_state_change(fsm_data,A_WAIT_VFALL); } else if ( fsm_data->tcb.a_vbus_vld == 0 ) { /* SW patch for VA_VBUS_VLD Bit going to low suddenly */ isp1362_mdelay(10); otg_reg_read16(REG_OTG_STATUS, &data); fsm_data->tcb.a_vbus_vld = (data & 0x02) ? 1: 0; if ( fsm_data->tcb.a_vbus_vld == 0 ) { otg_fsm_state_change(fsm_data,A_VBUS_ERR); } } else if (fsm_data->tcb.b_conn == 1) { if(fsm_data->tcb.TimerId != A_BCON_DEBOUNCE_TIMER_ID) { otgfsm_stop_timer(fsm_data); otgfsm_start_timer(fsm_data, A_BCON_DEBOUNCE_TIMER_ID, A_BCON_DEBOUNCE_TIMER); } } break; case A_HOST: otgfsm_local_vbus(fsm_data, TRUE); otgfsm_local_pullup(FALSE); otgfsm_hc_dc_sel(FALSE); if( fsm_data->tcb.id == 1 || fsm_data->tcb.bus_drop == 1 || fsm_data->tcb.b_conn == 0) { otgfsm_start_timer(fsm_data,A_WAIT_BCON_TIMER_ID, A_WAIT_BCON_TIMER); phci_otg_port_control(fsm_data->hcd_priv, OTG_PORT_DISCONNECT_PORT, NULL); otg_fsm_state_change(fsm_data,A_WAIT_BCON); } else if( fsm_data->tcb.a_vbus_vld == 0) { /* SW patch for VA_VBUS_VLD Bit going to low suddenly */ isp1362_mdelay(10); otg_reg_read16(REG_OTG_STATUS, &data); fsm_data->tcb.a_vbus_vld = (data & 0x02) ? 1: 0; if ( fsm_data->tcb.a_vbus_vld == 0 ) { phci_otg_port_control(fsm_data->hcd_priv, OTG_PORT_DISCONNECT_PORT, NULL); otg_fsm_state_change(fsm_data,A_VBUS_ERR); } } else if((fsm_data->tcb.bus_req == 0 && fsm_data->tcb.AllowStateChange == 1) || fsm_data->tcb.a_suspend_req == 1) { otgfsm_rdis_lcon_en(TRUE); // if B-device disconnected, then A-device assert pull-up immediately otgfsm_start_timer(fsm_data, A_AIDL_BDIS_TIMER_ID, A_AIDL_BDIS_TIMER); phci_otg_port_control(fsm_data->hcd_priv, OTG_PORT_SUSPEND, NULL); phci_otg_port_control( fsm_data->hcd_priv, OTG_PORT_DISCONNECT_PORT, NULL); otg_fsm_state_change(fsm_data,A_SUSPEND); } break; case A_SUSPEND: otgfsm_local_vbus(fsm_data, TRUE); otgfsm_local_pullup(FALSE); otgfsm_hc_dc_sel(FALSE); fsm_data->tcb.a_suspend_req = 0; if( fsm_data->tcb.id == 1 || fsm_data->tcb.bus_drop == 1 || fsm_data->tcb.TimeOut == 1) { fsm_data->tcb.TimeOut = 0; otgfsm_rdis_lcon_en(FALSE); otg_fsm_state_change(fsm_data,A_WAIT_VFALL); } else if (fsm_data->tcb.a_vbus_vld == 0 ) { /* SW patch for VA_VBUS_VLD Bit going to low suddenly */ isp1362_mdelay(10); otg_reg_read16(REG_OTG_STATUS, &data); fsm_data->tcb.a_vbus_vld = (data & 0x02) ? 1: 0; if ( fsm_data->tcb.a_vbus_vld == 0 ) { otg_fsm_state_change(fsm_data,A_VBUS_ERR); } } else if ( fsm_data->tcb.b_conn == 0 && fsm_data->tcb.a_set_b_hnp_en == 1) { //A-device starts to detect suspend condition after 5ms delay otgfsm_start_timer(fsm_data, A_SUSPEND_DET_TIMER_ID, A_SUSPEND_DET_TIMER); pdc_otg_control(NULL, PDC_ENABLE); fsm_data->tcb.b_bus_suspend = 0; otg_fsm_state_change(fsm_data,A_PERIPHERAL); } else if ( fsm_data->tcb.b_conn == 0 && fsm_data->tcb.a_set_b_hnp_en == 0) { otgfsm_rdis_lcon_en(FALSE); otgfsm_start_timer(fsm_data,A_WAIT_BCON_TIMER_ID,A_WAIT_BCON_TIMER); otg_fsm_state_change(fsm_data,A_WAIT_BCON); } else if(fsm_data->tcb.bus_req == 1 || fsm_data->tcb.b_bus_resume == 1) { otgfsm_rdis_lcon_en(FALSE); fsm_data->tcb.AllowStateChange = 0; otg_fsm_state_change(fsm_data,A_HOST); } break; case A_PERIPHERAL: otgfsm_local_vbus(fsm_data, TRUE); otgfsm_local_pullup(TRUE); otgfsm_hc_dc_sel(TRUE); if( fsm_data->tcb.id == 1|| fsm_data->tcb.bus_drop == 1 ) // 0 == RmtSOF is IDLE for at least 3 ms { pdc_otg_control(NULL,PDC_DISABLE); otg_fsm_state_change(fsm_data,A_WAIT_VFALL); } else if (fsm_data->tcb.a_vbus_vld == 0 ) { /* SW patch for VA_VBUS_VLD Bit going to low suddenly */ isp1362_mdelay(10); otg_reg_read16(REG_OTG_STATUS, &data); fsm_data->tcb.a_vbus_vld = (data & 0x02) ? 1: 0; if ( fsm_data->tcb.a_vbus_vld == 0 ) { pdc_otg_control(NULL,PDC_DISABLE); otg_fsm_state_change(fsm_data,A_VBUS_ERR); } } else if (fsm_data->tcb.b_bus_suspend == 1 && fsm_data->tcb.TimeOut == 1 ) // suspend { fsm_data->tcb.err_code = OTG_STATUS_NONE; otgfsm_start_timer(fsm_data,A_WAIT_BCON_TIMER_ID,A_WAIT_BCON_TIMER); fsm_data->tcb.b_bus_suspend = 0; pdc_otg_control(NULL,PDC_DISABLE); otg_fsm_state_change(fsm_data,A_WAIT_BCON); } break; case A_WAIT_VFALL: otgfsm_local_vbus(fsm_data, FALSE); otgfsm_local_pullup(FALSE); otgfsm_hc_dc_sel(FALSE); if(fsm_data->tcb.bus_req == 1 || fsm_data->tcb.a_sess_vld == 0 || fsm_data->tcb.id == 1) { otgfsm_init_fsm_data(fsm_data); otg_fsm_state_change(fsm_data,A_IDLE); } break; case A_VBUS_ERR: otgfsm_local_vbus(fsm_data, FALSE); otgfsm_local_pullup(FALSE); fsm_data->tcb.err_code = OTG_STATUS_VBUS_ERR; /* Set the VBUS error status */ otgfsm_hc_dc_sel(FALSE); if(fsm_data->tcb.id == 1 || fsm_data->tcb.bus_drop == 1) { fsm_data->tcb.bus_drop = 0; otg_fsm_state_change(fsm_data,A_WAIT_VFALL); } break; default: break; }}/*----------------------------------------------*//* Run the OTG FSM *//* ---------------------------------------------*/void otgfsm_run(otg_fsm_t *fsm_data) { __u8 prev_state = INV_STATE; // Get inputs for the FSM otgfsm_status_probe(fsm_data); // Run the A device FSM until its stebilized while(prev_state != fsm_data->tcb.state) { prev_state = fsm_data->tcb.state; otgfsm_run_Adevice(fsm_data); } prev_state = INV_STATE; // Run the B device FSM until its stebilized while(prev_state != fsm_data->tcb.state) { prev_state = fsm_data->tcb.state; otgfsm_run_Bdevice(fsm_data); }}/*----------------------------------------------*//* Init fsm data variables *//* ---------------------------------------------*/void otgfsm_init_fsm_data(otg_fsm_t *fsm_data) { /* Reset all the fields of fsm_data */ fsm_data->tcb.bus_req = 0; fsm_data->tcb.a_suspend_req = 0; fsm_data->tcb.a_bus_resume = 0; fsm_data->tcb.a_bus_suspend = 0; fsm_data->tcb.a_bus_reset = 0; fsm_data->tcb.b_bus_resume = 0; fsm_data->tcb.b_bus_suspend = 0; fsm_data->tcb.b_hnp_en = 0; fsm_data->tcb.a_set_b_hnp_en = 0; fsm_data->tcb.b_hnp_support = 1; fsm_data->tcb.a_hnp_support = 0; fsm_data->tcb.a_alt_hnp_support = 0; /* Stop if any timer is running */ if(fsm_data->tcb.TimerRunning == 1) otgfsm_stop_timer(fsm_data); fsm_data->tcb.TimerRunning = 0; fsm_data->tcb.TimeOut = 0; fsm_data->tcb.TimerTick = 0; fsm_data->tcb.Req4StateChange = 0; fsm_data->tcb.AllowStateChange = 0; fsm_data->tcb.bus_drop = 0; fsm_data->tcb.TimerId = 0; isp1362_otg_dev = fsm_data->dev; /* Clear all the interrupts in the OTG interrupt register */ otg_reg_write16(REG_OTG_INT, 0xFFFF);}/*----------------------------------------------*//* Init fsm *//* ---------------------------------------------*/void otgfsm_init(otg_fsm_t *fsm_data ) { otgfsm_init_fsm_data(fsm_data); otgfsm_status_probe(fsm_data); /* Enable all possible OTG interrupt sources */ otg_reg_write16(REG_OTG_INT_ENABLE, OTG_IRQ_MASK); switch(fsm_data->tcb.id) { case 0: fsm_data->tcb.state = A_IDLE; fsm_data->tcb.app_state = A_IDLE; otgfsm_hc_dc_sel(FALSE); //default HC break; case 1: fsm_data->tcb.state = B_IDLE; fsm_data->tcb.app_state = B_IDLE; otgfsm_hc_dc_sel(TRUE); //default DC break; default: break; } otgfsm_run(fsm_data);}void otgfsm_deinit(otg_fsm_t *fsm_data ) { /* Disable all OTG interrupts */ otg_reg_write16(REG_OTG_INT_ENABLE, OTG_IRQ_MASK); otg_reg_write16(REG_OTG_CONTROL, 0x00C0); switch (fsm_data->tcb.state) { case A_HOST: case B_HOST: phci_otg_port_control(fsm_data->hcd_priv, OTG_PORT_DISCONNECT_PORT, NULL); break; case A_PERIPHERAL: case B_PERIPHERAL: pdc_otg_control(NULL, PDC_DISCONNECT); break; } return; }/*----------------------------------------------*//* Change the FSM state (request from application *//* ---------------------------------------------*/void otgfsm_set_state(otg_fsm_t *fsm_data, __u8 cmd) { // Change the FSM variables fsm_data->tcb.err_code = OTG_STATUS_NONE; /* Set the FSM variables based on the command received */ switch(cmd) { case HOST: /* Change the state of the FSM to HOST (open OTG session) */ fsm_data->tcb.bus_req = 1; fsm_data->tcb.bus_drop = 0; fsm_data->tcb.b_srp_done = 0; fsm_data->tcb.a_suspend_req = 0; break; case BUS_DROP: /* Drop the VBUS */ fsm_data->tcb.bus_req = 0; fsm_data->tcb.bus_drop = 1; break; case BUS_OPEN: /* Allow VBUS to go when required */ fsm_data->tcb.bus_drop = 0; break; case IDLE: /* Change the state to IDLE (close OTG session) */ fsm_data->tcb.bus_req = 0; if(fsm_data->tcb.id == 0) { fsm_data->tcb.a_suspend_req = 1; } else { fsm_data->tcb.AllowStateChange = 1; } break; case PERIPHERAL: /* This releases the mastership to other remote OTG device * if applicable otherwise closes the session */ fsm_data->tcb.bus_req = 0; if(fsm_data->tcb.id == 1) { fsm_data->tcb.AllowStateChange = 1; } break; } // Run the fsm otgfsm_run(fsm_data);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -