📄 otg_fsm.c
字号:
otg_reg_read32(HC_FM_REM_REG, &fn_rem);
printk("%s fn = %x, fn_rem = %x\n",mesg, fn, fn_rem);
}
void otgfsm_fast_discharge(otg_fsm_t *fsm_data, __u8 ctrl_flag) {
__u16 wTemp;
if(ctrl_flag == TRUE ) {
// Discharge VBUS fastly
otg_reg_read16(OTG_CONTROL_REG, &wTemp);
otg_reg_write16(OTG_CONTROL_REG, (wTemp|OTG_DISCHRG_VBUS));
} else {
// Remove Discharfe fast path
otgfsm_print_fn(fsm_data, "fast discharge disable");
otg_reg_read16(OTG_CONTROL_REG, &wTemp);
otg_reg_write16(OTG_CONTROL_REG, (wTemp&(~OTG_DISCHRG_VBUS)));
}
}
/*----------------------------------------------*/
/* 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(OTG_CONTROL_REG, &wTemp);
otg_reg_write16(OTG_CONTROL_REG, (wTemp|OTG_CHRG_VBUS));
} else {
otg_reg_read16(OTG_CONTROL_REG, &wTemp);
otg_reg_write16(OTG_CONTROL_REG, (wTemp&(~OTG_CHRG_VBUS)));
}
} else {
// A device driving VBUS line
if(ctrl_flag == TRUE ) {
otg_reg_read16(OTG_CONTROL_REG, &wTemp);
otg_reg_write16(OTG_CONTROL_REG, (wTemp|OTG_DRV_VBUS));
} else {
otg_reg_read16(OTG_CONTROL_REG, &wTemp);
otg_reg_write16(OTG_CONTROL_REG, (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(OTG_STATUS_REG,&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.status_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(OTG_TMR_REG, 0); // Stop the timer first
data = OTG_START_TIMER;
data |= (time*OTG_TMR_RESOLUTION);
otg_reg_write32(OTG_TMR_REG, 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(OTG_TMR_REG, 0); // Stop the timer first
}
/*----------------------------------------------*/
/* Run the B device FSM */
/* ---------------------------------------------*/
void otgfsm_run_Bdevice(otg_fsm_t *fsm_data) {
__u32 port_data;
__u32 rem_time;
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_se0_srp == 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) {
isp1362_kernel_user_mesg("Unable to communicate with the device");
fsm_data->tcb.err_code = OTG_STATUS_TIMEOUT;
fsm_data->tcb.b_srp_done = 0;
fsm_data->tcb.bus_req = 0;
fsm_data->tcb.b_host_pending = 0;
/* Inform application about timeout */
otg_fsm_state_change(fsm_data,B_IDLE);
}
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( fsm_data->tcb.id == 0 || fsm_data->tcb.b_srp_done == 1 ) {
//Allow 5s for A-device responding SRP
fsm_data->tcb.b_host_pending = 1;
otg_reg_write32(OTG_ALT_TMR_REG, OTG_START_TIMER);
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.TimeOut == 1) {
if(fsm_data->tcb.TimerId == B_BUS_REQ_TIMER_ID) {
/* Bus is Still in hold by the A-HOST */
isp1362_kernel_user_mesg("Unable to communicate with the connecetd device");
fsm_data->tcb.err_code = OTG_STATUS_TIMEOUT;
fsm_data->tcb.b_srp_done = 0;
fsm_data->tcb.bus_req = 0;
fsm_data->tcb.TimeOut = 0;
/* Inform application about timeout */
otg_fsm_state_change(fsm_data,B_PERIPHERAL);
} else {
fsm_data->tcb.TimeOut = 0;
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);
pdc_otg_control(NULL,PDC_DISABLE);
otg_fsm_state_change(fsm_data,B_WAIT_ACON);
}
} else if ((fsm_data->tcb.bus_req == 1 || fsm_data->tcb.b_host_pending) &&
fsm_data->tcb.b_hnp_en == 1 &&
( fsm_data->tcb.a_bus_suspend == 1) ) { /* OTG1.0A fix */
fsm_data->tcb.b_host_pending = 0;
otgfsm_start_timer(fsm_data,B_AIDL_BDIS_TIMER_ID,
B_AIDL_BDIS_TIMER);
}
break;
case B_WAIT_ACON:
otgfsm_local_pullup(FALSE);
isp1362_udelay(150); /* RCON_LSE0 fix */
otgfsm_hc_dc_sel(FALSE);
if( fsm_data->tcb.b_sess_vld == 0 || fsm_data->tcb.id == 0 ) {
isp1362_kernel_user_mesg("Unable to communicate with the connected device");
fsm_data->tcb.b_host_pending = 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);
fsm_data->tcb.b_host_pending = 0;
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) {
isp1362_kernel_user_mesg("Unable to communicate with the connected device");
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);
pdc_otg_control(NULL, PDC_ENABLE);
otg_reg_read32(OTG_ALT_TMR_REG, &rem_time);
rem_time &= 0x00FFFFFF; /* Mask the start-stop and reserved bits */
otgfsm_start_timer(fsm_data, B_BUS_REQ_TIMER_ID, (B_BUS_REQ_TIMER - rem_time/OTG_TMR_RESOLUTION));
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
isp1362_kernel_user_mesg("Unable to communicate with the connected device");
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 ) {
if(fsm_data->tcb.a_conn == 0) isp1362_kernel_user_mesg("Unable to communicate with the connected device");
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;
phci_otg_port_control(fsm_data->hcd_priv, OTG_PORT_OPEN_PORT_IMM, &port_data);
otg_fsm_state_change(fsm_data,A_HOST);
} else {
if(fsm_data->tcb.bus_req == 1) {
fsm_data->tcb.err_code = OTG_STATUS_TIMEOUT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -