📄 otg_fsm.c
字号:
/*************************************************************
* Philips OTG FSM module for USB OTG controller
*
* (c) 2002 Koninklijke Philips Electronics N.V., All rights reserved
*
* This source code and any compilation or derivative thereof is the
* proprietary information of Koninklijke Philips Electronics N.V.
* and is confidential in nature.
* Under no circumstances is this software to be exposed to or placed
* under an Open Source License of any type without the expressed
* written permission of Koninklijke Philips Electronics N.V.
*
* File Name: otg_fsm.c
*
* History:
*
* Version Date Author Comments
* -------------------------------------------------
* 1.0 09/23/02 SYARRA Initial Creation
* 1.10 04/01/03 SYARRA OTG1.0A fixes
* 1.21 08/04/03 SYARRA OPT1.2 compliance
*************************************************************/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/timer.h>
#include <linux/interrupt.h> /* for in_interrupt() */
#undef DEBUG
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/unaligned.h>
#include <linux/usb.h>
#include "pdc_intf.h"
#include "usb_phci.h"
#include "usb_otg.h"
#define HC_IO_BASE 0x290
#define HC_DATA HC_IO_BASE
#define HC_COM (HC_IO_BASE+2)
__u32 otg_fn;
char fsm_state_X_name[25][15] = {
"B_IDLE",
"B_HOST",
"B_PERIPHERAL",
"B_WAIT_ACON",
"B_SRP_INIT",
"INV_STATE",
"INV_STATE",
"INV_STATE",
"INV_STATE",
"INV_STATE",
"INV_STATE",
"INV_STATE",
"INV_STATE",
"INV_STATE",
"INV_STATE",
"INV_STATE",
"A_IDLE",
"A_HOST",
"A_PERIPHERAL",
"A_WAIT_BCON",
"A_WAIT_VRISE",
"A_SUSPEND",
"A_WAIT_VFALL",
"A_VBUS_ERR"
};
struct isp1362_dev *isp1362_otg_dev = NULL;
unsigned char fsm_state_X_app_state[25] = {
B_IDLE,
B_HOST,
B_PERIPHERAL,
B_PERIPHERAL,
B_IDLE,
INV_STATE,
INV_STATE,
INV_STATE,
INV_STATE,
INV_STATE,
INV_STATE,
INV_STATE,
INV_STATE,
INV_STATE,
INV_STATE,
INV_STATE,
A_IDLE,
A_HOST,
A_PERIPHERAL,
A_IDLE,
A_IDLE,
A_HOST,
A_IDLE,
A_VBUS_ERR
};
#ifdef CONFIG_DETAIL_DEBUG
/*----------------------------------------------*/
/* printing function declerations */
/* ---------------------------------------------*/
void otgfsm_print_otg_data(otg_fsm_t *fsm_data);
void otgfsm_print_status(otg_fsm_t *fsm_data);
#endif /* CONFIG_DETAIL_DEBUG */
/*----------------------------------------------*/
/* control register function declerations */
/* ---------------------------------------------*/
void otgfsm_local_pulldown(__u8 ctrl_flag);
void otgfsm_local_pullup(__u8 ctrl_flag) ;
void otgfsm_local_vbus(otg_fsm_t *fsm_data, __u8 ctrl_flag);
void otgfsm_hc_dc_sel(__u8 ctrl_flag);
void otgfsm_srp_det_en(__u8 ctrl_flag) ;
void otgfsm_rdis_lcon_en(__u8 ctrl_flag);
void otgfsm_rcon_lse0_en(__u8 ctrl_flag);
/*----------------------------------------------*/
/* timer related functions */
/* ---------------------------------------------*/
void otgfsm_start_timer(otg_fsm_t *fsm_data, __u8 timer_id, __u16 time );
void otgfsm_stop_timer(otg_fsm_t *fsm_data);
void otgfsm_status_probe(otg_fsm_t *fsm_data);
void otgfsm_run_Adevice(otg_fsm_t *fsm_data);
void otgfsm_run_Bdevice(otg_fsm_t *fsm_data);
void otgfsm_run(otg_fsm_t *fsm_data);
void otgfsm_init(otg_fsm_t *fsm_data );
void otgfsm_init_fsm_data(otg_fsm_t *fsm_data);
void otgfsm_set_state(otg_fsm_t *fsm_data, __u8 cmd);
/* ISP1362 Hardware register access functions */
static void otg_reg_read16(__u16 reg, __u16 *data)
{
isp1362_reg_read16(isp1362_otg_dev, reg, (*data));
}
static void otg_reg_write16(__u16 reg, __u32 data)
{
isp1362_reg_write16(isp1362_otg_dev, (reg|0x80), data);
}
static void otg_reg_read32(__u16 reg, __u32 *data)
{
isp1362_reg_read32(isp1362_otg_dev, reg, (*data));
return;
}
static void otg_reg_write32(__u16 reg, __u32 data)
{
isp1362_reg_write32(isp1362_otg_dev, (reg|0x80), data);
return;
}
#ifdef CONFIG_DETAIL_DEBUG
/*----------------------------------------------*/
/* Print OTG status registers */
/* ---------------------------------------------*/
void otgfsm_print_status(otg_fsm_t *fsm_data) {
__u16 status;
__u16 interrupt;
interrupt = fsm_data->regs.int_port.data;
status = fsm_data->regs.status_port.data;
detail_debug(("Printing Status Change: in [%s]\n", (fsm_data->tcb.state != INV_STATE ) ? fsm_state_X_name[fsm_data->tcb.state] : "INV_STATE"));
if(interrupt & OTG_IRQ_ID) {
detail_debug((" ID[%d]", status & OTG_IRQ_ID));
}
if(interrupt & OTG_IRQ_A_VBUS_VLD) {
detail_debug((" A_VbusVld[%d]", (status & OTG_IRQ_A_VBUS_VLD)?1:0));
}
if(interrupt & OTG_IRQ_B_SESS_END) {
detail_debug((" B_SessEnd[%d]", (status & OTG_IRQ_B_SESS_END)?1:0));
}
if(interrupt & OTG_IRQ_A_SESS_VLD) {
detail_debug((" A_SessVld[%d]", (status & OTG_IRQ_A_SESS_VLD)?1:0));
}
if(interrupt & OTG_IRQ_B_SESS_VLD) {
detail_debug((" B_SessVld[%d]", (status & OTG_IRQ_B_SESS_VLD)?1:0));
}
if(interrupt & OTG_IRQ_RMT_CONN) {
detail_debug((" Conn[%d]", (status & OTG_IRQ_RMT_CONN)?1:0));
}
if(interrupt & OTG_IRQ_SUSPEND) {
detail_debug((" Susp[1]"));
}
if(interrupt & OTG_IRQ_RESUME) {
detail_debug((" Res[1]"));
}
if(interrupt & OTG_IRQ_SRP_DET) {
detail_debug((" Srp[1]"));
}
if(interrupt & OTG_IRQ_SE0_SRP){
detail_debug((" Srp[1]"));
}
if(interrupt & OTG_IRQ_TMR) {
detail_debug((" Tmr[1]"));
}
detail_debug(("\n"))
}
/*----------------------------------------------*/
/* Print OTG fsm data */
/* ---------------------------------------------*/
void otgfsm_print_otg_data(otg_fsm_t *fsm_data){
__u16 wTemp;
otg_tcb_t *tcb = &(fsm_data->tcb);
detail_debug(("printing OTG FSM Data\n"))
detail_debug(("TCB::\n"))
detail_debug((" state = %d err_code = %d id = %d\n", tcb->state, tcb->err_code, tcb->id))
detail_debug((" for A-device::\n a_vbus_vld = %d a_sess_vld = %d a_srp_det = %d b_conn = %d b_bus_suspend = %d b_bus_resume = %d\n", tcb->a_vbus_vld, tcb->a_sess_vld, tcb->a_srp_det, tcb->b_conn, tcb->b_bus_suspend, tcb->b_bus_resume))
detail_debug((" b_hnp_support = %d b_srp_support = %d a_set_b_hnp_en = %d a_suspend_req = %d \n", tcb->b_hnp_support, tcb->b_srp_support, tcb->a_set_b_hnp_en, tcb->a_suspend_req))
detail_debug((" for B-device:: \n b_sess_end = %d b_sess_vld = %d b_se0_srp = %d a_conn = %d a_bus_suspend = %d a_bus_resume = %d \n", tcb->b_sess_end, tcb->b_sess_vld, tcb->b_se0_srp, tcb->a_conn, tcb->a_bus_suspend, tcb->a_bus_resume))
detail_debug((" a_bus_reset = %d b_srp_done = %d b_hnp_en = %d a_hnp_support = %d a_alt_hnp_support = %d \n", tcb->a_bus_reset, tcb->b_srp_done, tcb->b_hnp_en, tcb->a_hnp_support, tcb->a_alt_hnp_support))
detail_debug((" for both A-device and B-device::\n bus_req = %d bus_drop = %d Req4StateChange = %d TimeOut =%d TimerRunning = %d TimerID = %d TimerTick = %d\n", tcb->bus_req, tcb->bus_drop, tcb->Req4StateChange, tcb->TimeOut, tcb->TimerRunning, tcb->TimerId, tcb->TimerTick))
otg_reg_read16(OTG_CONTROL_REG, &wTemp);
detail_debug((" Control Reg = %x\n", wTemp))
otg_reg_read16(OTG_STATUS_REG, &wTemp);
detail_debug((" Status Reg = %x\n", wTemp&0x3F))
otg_reg_read16(OTG_INT_REG, &wTemp);
detail_debug((" Interrupt Reg = %x\n", wTemp & OTG_IRQ_MASK))
otg_reg_read16(OTG_INT_ENABLE_REG, &wTemp);
detail_debug((" Interrrupt Enable Reg = %x\n", wTemp&OTG_IRQ_MASK))
otg_reg_read16(OTG_TMR_REG, &wTemp);
detail_debug((" Timer Reg = %x\n\n", wTemp))
}
#endif /* CONFIG_DETAIL_DEBUG */
/*----------------------------------------------*/
/* control local pulldown register on D- line */
/* ---------------------------------------------*/
void otgfsm_local_pulldown(__u8 ctrl_flag) {
__u16 wTemp;
if(ctrl_flag == TRUE ) {
//pulldown on D- is always enabled
otg_reg_read16(OTG_CONTROL_REG, &wTemp);
otg_reg_write16(OTG_CONTROL_REG, (wTemp|OTG_LOC_PULLDN_DM));
} else {
//pulldown on D- is disabled
otg_reg_read16(OTG_CONTROL_REG, &wTemp);
otg_reg_write16(OTG_CONTROL_REG, wTemp&(~OTG_LOC_PULLDN_DM));
}
}
/*----------------------------------------------*/
/* control local pulldown resister on D+ line */
/* ---------------------------------------------*/
void otgfsm_local_pullup(__u8 ctrl_flag) {
__u16 wTemp;
//for FPGA testing, ISP1181 chip needs SoftConnect bit and Vbus sensing to check suspend/awake
if( ctrl_flag == TRUE ) {
//pulldown on D+ is disabled when pullup enabled
pdc_otg_control(NULL, PDC_CONNECT);
otg_reg_read16(OTG_CONTROL_REG, &wTemp);
wTemp &= (~OTG_LOC_PULLDN_DP);
wTemp &= (~OTG_A_RDIS_LCON_EN);
wTemp |= OTG_LOC_CONN;
//disable auto connect (a_rdis_lcon_en bit)
otg_reg_write16(OTG_CONTROL_REG, wTemp);
} else {
//pulldown on D+ is enabled when pullup disabled
pdc_otg_control(NULL, PDC_DISCONNECT);
otg_reg_read16(OTG_CONTROL_REG, &wTemp);
wTemp &= ~(OTG_LOC_CONN);
otg_reg_write16(OTG_CONTROL_REG, (wTemp|OTG_LOC_PULLDN_DP));
}
}
/*----------------------------------------------*/
/* Select HC or DC for the OTG port */
/* control SEL_HC_DC. 0: HC, 1: DC */
/* ---------------------------------------------*/
void otgfsm_hc_dc_sel(__u8 ctrl_flag) {
__u16 wTemp;
if( ctrl_flag == TRUE ) {
// Select DC
otg_reg_read16(OTG_CONTROL_REG, &wTemp);
otg_reg_write16(OTG_CONTROL_REG, (wTemp|OTG_SEL_HC_DC));
} else {
// selct HC
otg_reg_read16(OTG_CONTROL_REG, &wTemp);
otg_reg_write16(OTG_CONTROL_REG, (wTemp&(~OTG_SEL_HC_DC)));
}
}
/*----------------------------------------------*/
/* Enable/disable SRP detection for OTG port */
/* VBUS pulsing SRP detection is used if enbaled*/
/* ---------------------------------------------*/
void otgfsm_srp_det_en(__u8 ctrl_flag) {
__u16 wTemp;
if( ctrl_flag == TRUE ) {
// Enable SRP (VBUS Pulsing) detection
otg_reg_read16(OTG_CONTROL_REG, &wTemp);
//VBUS pulsing(use a_sess_vld)
//Dataline pulsing(use D+ or D- low to high)
wTemp |= OTG_A_SRP_DET_EN;
wTemp &= (~OTG_A_SEL_SRP);
otg_reg_write16(OTG_CONTROL_REG, wTemp);
} else {
otg_reg_read16(OTG_CONTROL_REG, &wTemp);
otg_reg_write16(OTG_CONTROL_REG, wTemp&(~OTG_A_SRP_DET_EN));
}
}
/*----------------------------------------------*/
/* Enable/disable Local connect */
/* ---------------------------------------------*/
void otgfsm_rdis_lcon_en(__u8 ctrl_flag) {
__u16 wTemp;
if(ctrl_flag == TRUE) {
// Enable local connection
otg_reg_read16(OTG_CONTROL_REG, &wTemp);
otg_reg_write16(OTG_CONTROL_REG, (wTemp|OTG_A_RDIS_LCON_EN));
} else {
// Disable local connection
otg_reg_read16(OTG_CONTROL_REG, &wTemp);
otg_reg_write16(OTG_CONTROL_REG, (wTemp&(~OTG_A_RDIS_LCON_EN)));
}
}
void otgfsm_rcon_lse0_en(__u8 ctrl_flag) {
__u16 wTemp;
if(ctrl_flag == TRUE) {
otg_reg_read16(OTG_CONTROL_REG, &wTemp);
otg_reg_write16(OTG_CONTROL_REG, (wTemp|OTG_B_RCON_LSE0_EN));
} else {
otg_reg_read16(OTG_CONTROL_REG, &wTemp);
otg_reg_write16(OTG_CONTROL_REG, (wTemp&(~OTG_B_RCON_LSE0_EN)));
}
}
void otgfsm_print_fn(otg_fsm_t *fsm_data, char *mesg)
{
__u32 fn, fn_rem;
otg_reg_read32(HC_FN_REG, &fn);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -