📄 ftc_fotg2xx.c
字号:
/* * Copyright (c) 2005 by Faraday * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, */#include <linux/config.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/pci.h>#include <linux/delay.h>#include <linux/ioport.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/smp_lock.h>#include <linux/errno.h>#include <linux/init.h>#include <linux/timer.h>#include <linux/list.h>#include <linux/interrupt.h>#include <linux/proc_fs.h>#include <linux/devfs_fs_kernel.h>//--For USB include#include <linux/usb_ch9.h>#include <linux/usb_gadget.h>#include <linux/usb_otg.h>//--For asm include#include <asm/byteorder.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/pci.h>#include <asm/system.h>#include <asm/unaligned.h>#include <asm/arch/cpe_int.h>//--For OTG include#include "FTC_FOTG2XX.h"#include "../gadget/FTC_FOTG200_udc.h"//--For usb include change between Linux2.4.18-USB and Linux2.6.10-USB#define FOTG2XX_AVOID_REDEFINE // will used in following usb.h#include <linux/usb.h>//#define FOTG2XX_HOST_ONLY 1 //john20060214 for HOST only usage#define OTG_MAJOR 42 //major device for OTG//--Driver & Module Info#define DRIVER_DESC "FOTG2XX USB Controller"#define DRIVER_VERSION "14-February 2006"static const char driver_name [] = "FTC_FOTG2XX";static const char driver_desc [] = DRIVER_DESC;MODULE_AUTHOR("bruce-john@faraday-tech.com");MODULE_DESCRIPTION(DRIVER_DESC);MODULE_LICENSE("GPL");//#define EINDBG(p,args...) do{if(msglevel>0)printk(p,##args);}while(0)//static int msglevel=1;static struct file_operations otg_fops = { owner: THIS_MODULE, ioctl: OTGC_AP_ioctl,};//--Global Variable Definitionstatic struct FTC_OTGC_STS *pFTC_OTG=0;static struct otg_transceiver *xceiv;//-----------------------------------------------------------------------------//-----------------------------------------------------------------------------//---------------------- Group-1:Basic Function -------------------------------//-----------------------------------------------------------------------------//-----------------------------------------------------------------------------static const char *OTGC_state_string(enum usb_otg_state state){ switch (state) { case OTG_STATE_A_IDLE: return "a_idle"; case OTG_STATE_A_WAIT_VRISE: return "a_wait_vrise"; case OTG_STATE_A_WAIT_BCON: return "a_wait_bcon"; case OTG_STATE_A_HOST: return "a_host"; case OTG_STATE_A_SUSPEND: return "a_suspend"; case OTG_STATE_A_PERIPHERAL: return "a_peripheral"; case OTG_STATE_A_WAIT_VFALL: return "a_wait_vfall"; case OTG_STATE_A_VBUS_ERR: return "a_vbus_err"; case OTG_STATE_B_IDLE: return "b_idle"; case OTG_STATE_B_SRP_INIT: return "b_srp_init"; case OTG_STATE_B_PERIPHERAL: return "b_peripheral"; case OTG_STATE_B_WAIT_ACON: return "b_wait_acon"; case OTG_STATE_B_HOST: return "b_host"; default: return "UNDEFINED"; }}//*********************************************************// Name: OTGH_host_quick_Reset// Description://For HNP critical timing// OTG need the quickly-bus-reset// Input:void// Output:0:OK//*********************************************************static int OTGH_host_quick_Reset(void){ //<1>.Issue Bus reset sequence mwHost20_PORTSC_PortReset_Set(); //<2>.Delay 55 ms mdelay(55); //<3>.terminate Bus reset sequence mwHost20_PORTSC_PortReset_Clr(); ////John0215 : this is useless code, because bit 0 always 0 ////<4>.Waiting for Reset complete //while(mwHost20_PORTSC_PortReset_Rd()==1); //<5>.Issue SOF mbHost20_USBCMD_RunStop_Set(); DBG_OTG_TRACEC("-OTGH_host_quick_Reset()(0x30=0x%x)\n",mdwFOTGPort(0x30)); return (0);}//*********************************************************// Name: OTGP_Close// Description:// Disable Interrupt for Peripheral// Input:void// Output:void//*********************************************************void OTGP_Close(void){ u32 wTemp; DBG_OTG_FUNCC("+OTGP_Close()\n"); //<1>.Clear All the Interrupt mUsbGlobIntDis(); //disable device interrupt mdwOTGC_GINT_MASK_PERIPHERAL_Set(); // mask device interrupt //john0215: offset 0x140 is read only ////<2>.Clear all the Interrupt Status //wTemp=mUsbIntGroupRegRd(); //mUsbIntGroupRegSet(0); //Interrupt source group 0(0x144) wTemp=mUsbIntSrc0Rd(); mUsbIntSrc0Set(0); //john0215: offset 0x148 is read only ////Interrupt source group 1(0x148) //wTemp=mUsbIntSrc1Rd(); //mUsbIntSrc1Set(0); //Interrupt source group 2(0x14C) wTemp=mUsbIntSrc2Rd(); mUsbIntSrc2Set(0); //<3>.Turn off D+ if (mdwOTGC_Control_CROLE_Rd()>0) //For Current Role = Peripheral mUsbUnPLGSet(); //emulate detached#ifdef CONFIG_USB_GADGET_FOTG2XX //<4>.Clear the variable //john0216 if pFTC_OTG->otg.gadget==NULL, and code runto here // only happen when OTG syill not boot OK, and device has plugged // in such condition, FTC_usb_probe() will clear these variable if (pFTC_OTG->otg.gadget) { pFTC_OTG->otg.gadget->b_hnp_enable = 0; pFTC_OTG->otg.gadget->a_hnp_support = 0; pFTC_OTG->otg.gadget->a_alt_hnp_support = 0; }#else printk("OTG2XX act as HOST only (remove gadget function)\n");#endif}//*********************************************************// Name: OTGH_Close// Description:// Disable Interrupt for Host// Input:void// Output:void//*********************************************************void OTGH_Close(void){ u32 wTemp; DBG_OTG_FUNCC("+OTGH_Close()(0x30=0x%x)\n",mdwFOTGPort(0x30)); //<1>.Enable Interrupt Mask mdwOTGC_GINT_MASK_HOST_Set(); //mask host interrupt //<2>.Clear the Interrupt status wTemp=mdwHost20_USBINTR_Rd(); wTemp=wTemp&0x0000003F; mdwHost20_USBSTS_Set(wTemp);}//*********************************************************// Name: OTGP_Open// Description:// open Peripheral Interrupt// Input:void// Output:void//*********************************************************void OTGP_Open(void){ DBG_OTG_FUNCC("+OTGP_Open()\n"); //<1>.Turn On the Interrupt for Peripheral if (pFTC_OTG->otg.gadget) //john0217 don't enable interrupt if gadget still not finish initialization mUsbGlobIntEnSet(); //enable device interrupt mdwOTGC_GINT_MASK_PERIPHERAL_Clr(); //unmask device interrupt mUsbUnPLGClr(); //clear detach setting}//*********************************************************// Name: OTGH_Open// Description:// open Host Interrupt// Input:void// Output:void//*********************************************************void OTGH_Open(void){ DBG_OTG_FUNCC("+OTGH_Open()(0x30=0x%x)\n",mdwFOTGPort(0x30)); //<1>.Turn On the Interrupt mdwOTGC_Control_A_SRP_DET_EN_Clr(); mdwOTGC_GINT_MASK_HOST_Clr();}#define OPEN_PHY_RESET#ifdef OPEN_PHY_RESET//*********************************************************// Name: OTGC_A_PHY_Reset// Description:// Phy Reset// Input:void// Output:void//*********************************************************void OTGC_A_PHY_Reset(void){ //DBG_OTG_FUNCC("+OTGC_A_PHY_Reset()\n"); printk("+OTGC_A_PHY_Reset()\n"); do { //wait until B-device VBUS voltage dropped mdelay(10); }while(mdwOTGC_Control_B_SESS_END_Rd()==0); mdwOTG20_Control_Phy_Reset_Set(); mdelay(5); mdwOTG20_Control_Phy_Reset_Clr(); printk("OTG Controller Reset...()\n"); mdwOTG20_Control_OTG_Reset_Set(); mdelay(5); mdwOTG20_Control_OTG_Reset_Clr();}#endif//*********************************************************// Name: OTGC_Waiting_VBUS_On// Description:// Waiting for A-device VBUS On// Input:bmsec => wait bmsec time// Output: 0 => ok//*********************************************************int OTGC_Waiting_VBUS_On(u32 bmsec){ u8 bExitFlag=0; u32 wTimer_ms=0; DBG_OTG_FUNCC("+OTGC_Waiting_VBUS_On()\n"); do { if (mdwOTGC_Control_A_VBUS_VLD_Rd()>0) bExitFlag=1; mdelay(1);//delay 1ms wTimer_ms++; if (wTimer_ms>bmsec) { bExitFlag=2; ERROR(pFTC_OTG,"??? Time out for waiting for VBUS On...\n"); return(1);//Time out } } while(bExitFlag==0); return(0);}//*********************************************************// Name: OTGC_Waiting_VBUS_Off// Description:// Waiting for A-device VBUS OFF// Input:bmsec => wait bmsec time// Output: 0 => ok//*********************************************************int OTGC_Waiting_VBUS_Off(u32 bmsec){ u8 bExitFlag=0; u32 wTimer_ms=0; DBG_OTG_FUNCC("+OTGC_Waiting_VBUS_Off()\n"); do { if (mdwOTGC_Control_A_VBUS_VLD_Rd()==0) bExitFlag=1; mdelay(1);//delay 1ms wTimer_ms++; if (wTimer_ms>bmsec) { bExitFlag=2; ERROR(pFTC_OTG,"??? Time out for waiting for VBUS Off...\n"); return(1);//Time out } } while(bExitFlag==0); return(0);}//*********************************************************// Name: OTGC_enable_vbus_draw// Description:// Drive/Drop VBUS// Input:0=>Drop VBUS// 1=>Drive VBUS// Output: 0 => ok//*********************************************************static void OTGC_enable_vbus_draw(u8 btype){ DBG_OTG_FUNCC("+(OTGC_enable_vbus_draw(btype=%d))\n",btype); if (btype>0) {//Drive VBUS if (mdwOTGC_Control_A_BUS_REQ_Rd()>0) //A-device VBUS has turned on return; //Exit when Current Role = Host mdwOTGC_Control_A_BUS_DROP_Clr(); //clear A-device drop VBUS mdwOTGC_Control_A_BUS_REQ_Set(); //A-device drive VBUS, generate traffic OTGC_Waiting_VBUS_On(5000); INFO(pFTC_OTG,">>> Drive VBUS ok...\n"); } else {//Drop VBUS if (mdwOTGC_Control_A_BUS_REQ_Rd()==0) //A-device VBUS has turned off return; //Exit when Current Role = Host mdwOTGC_Control_A_BUS_REQ_Clr(); // A-device drop driving VBUS and bus traffic mdwOTGC_Control_A_BUS_DROP_Set(); // Set A-device drop VBUS OTGC_Waiting_VBUS_Off(5000); INFO(pFTC_OTG,">>> Drop VBUS ok...\n"); }}//-----------------------------------------------------------------------------//-----------------------------------------------------------------------------//---------------------- Group-2:AP Function ----------------------------------//-----------------------------------------------------------------------------//-----------------------------------------------------------------------------//*********************************************************// Name: OTGC_AP_Get_State// Description: AP will get the OTG State from OTG Driver// Input:void// Output:otg.state//*********************************************************static int OTGC_AP_Get_State(void){ DBG_OTG_FUNCC("+OTGC_AP_Get_State() (pFTC_OTG->otg.state=%d)\n",pFTC_OTG->otg.state); return((int)(pFTC_OTG->otg.state));}//*********************************************************// Name: OTGC_AP_Set_to_Idle// Description: AP will call this function call to set device to idle// Input:void// Output:0:OK// others:Fail//*********************************************************static u8 OTGC_AP_Set_to_Idle(void){ DBG_OTG_FUNCC("+OTGC_AP_Set_to_Idle()\n"); pFTC_OTG->otg.host->A_Disable_Set_Feature_HNP=1; if (mdwOTGC_Control_ID_Rd()==0) { //For A Device if (pFTC_OTG->otg.state==OTG_STATE_A_HOST) { if (pFTC_OTG->otg.host->b_hnp_enable) { //For => A-Host & HNP Enable ==>Then Role change to Peripheral Mode INFO(pFTC_OTG,">>> call otg_start_hnp\n"); FOTG2XX_start_hnp(xceiv); return(0); } else {//For Normale A-Host-Idle Host_Disconnect_for_OTG(pFTC_OTG->otg.host,0); mdwOTGC_Control_A_BUS_REQ_Clr(); //A-device stop driving VBUS and traffic mdwOTGC_Control_A_BUS_DROP_Set(); // A-device want to pwer down VBUS mdwOTGC_Control_A_SRP_DET_EN_Set(); // enable SRP detection while(mdwOTGC_Control_A_VBUS_VLD_Rd()>0); //wait until VBUS dropped pFTC_OTG->otg.state=OTG_STATE_A_IDLE; return(0); } } if (pFTC_OTG->otg.state==OTG_STATE_A_IDLE) { INFO(pFTC_OTG,">>> Device-A is already in Idle mode\n"); return(0); } else { INFO(pFTC_OTG,">>> Set to Idle Fail...(Current State = %s)\n",OTGC_state_string(pFTC_OTG->otg.state)); return(-1); } } else { //For B Device if (pFTC_OTG->otg.state==OTG_STATE_B_HOST) { //Change to peripheral==>Host disconnect //printk("TEMP==> B exit the host mode...\n"); Host_Disconnect_for_OTG(pFTC_OTG->otg.host,0); // pFTC_OTG->otg.state=OTG_STATE_B_IDLE; return(0); } if (mdwOTGC_Control_A_VBUS_VLD_Rd()>0) { ERROR(pFTC_OTG,"??? Can not set Device-B to idle state(When VBUS>0 )...\n"); return(-1); } if (pFTC_OTG->otg.state==OTG_STATE_B_IDLE) { INFO(pFTC_OTG,">>> Device-B is already in Idle State... \n"); return(0); } if (pFTC_OTG->otg.state==OTG_STATE_B_PERIPHERAL) { OTGP_Close(); mdwOTGC_Control_B_BUS_REQ_Clr(); //B-device stop driving VBUS mdwOTGC_Control_B_HNP_EN_Clr(); //B-device disable HNP mdwOTGC_Control_B_DSCHG_VBUS_Clr(); //B-device discharge VBUS pFTC_OTG->otg.state=OTG_STATE_B_IDLE; return(0); } else { INFO(pFTC_OTG,">>> Set to Idle Fail...(Current State = %s)\n",OTGC_state_string(pFTC_OTG->otg.state)); return(-1); } } return(0);}//*********************************************************// Name: OTGC_AP_Set_to_Host// Description: AP will call this function call to set device to Host// Input:void
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -