📄 otg_fsm.c
字号:
}else {
isp1362_kernel_user_mesg("Connected device is not responding");
}
fsm_data->tcb.bus_req = 0;
otgfsm_stop_timer(fsm_data);
otg_reg_write32(OTG_ALT_TMR_REG, OTG_START_TIMER);
// otgfsm_fast_discharge(fsm_data, TRUE);
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(OTG_STATUS_REG, &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(OTG_STATUS_REG, &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(OTG_STATUS_REG, &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);
fsm_data->tcb.b_bus_suspend = 0;
pdc_otg_control(NULL, PDC_ENABLE);
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(OTG_STATUS_REG, &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_fast_discharge(fsm_data, TRUE);
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.b_conn == 0) ||
fsm_data->tcb.id == 1) {
// otgfsm_fast_discharge(fsm_data, FALSE);
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.b_host_pending = 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(OTG_INT_REG, 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(OTG_INT_ENABLE_REG, 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(OTG_INT_ENABLE_REG, OTG_IRQ_MASK);
otg_reg_write16(OTG_CONTROL_REG, 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 if(fsm_data->tcb.b_host_pending == 0) {
/* There is no host pending, So
* Clear the bus request completely
*/
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 + -