📄 cy7c67200_300_otg.c
字号:
/* File: otg.c *//* This file implements the OTG state diagram. *//* Included files. */#include <linux/kernel.h>#include <linux/slab.h>#include <linux/delay.h>#include <linux/timer.h>#include "cy7c67200_300_otg.h"#include "cy7c67200_300_lcd.h"#include "usbd/bi/cy7c67200_300_pcd.h"#include "cy7c67200_300_debug.h"#include "67300.h" /* Data definitions */#define START_SOF 10#define STOP_SOF 11#define RAISE_VBUS 20#define DROP_VBUS 21/* global */char *state_names[] ={ "a_idle", "a_wait_vrise", "a_wait_bcon", "a_host", "a_suspend", "a_peripheral", "a_wait_vfall", "a_vbus_err", "b_idle", "b_srp_init", "b_peripheral", "b_wait_acon", "b_host"};extern void detected_hnp_accepted(void);extern void hcd_switch_role(int new_role, cy_priv_t * cy_priv);extern void handle_device_insertion (cy_priv_t * cy_priv, int port_num);extern void handle_device_removal (cy_priv_t * cy_priv, int port_num);extern void handle_remote_wakeup (cy_priv_t * cy_priv, int port_num);static cy_priv_t * otg_cy_priv = NULL;/* forware declaration */static void a_host_state(otg_t * otg);static void a_idle_state(otg_t * otg);static void a_peripheral_state(otg_t * otg);static void a_suspend_state(otg_t * otg);static void a_vbus_err_state(otg_t * otg);static void a_wait_bcon_state(otg_t * otg);static void a_wait_vfall_state(otg_t * otg);static void a_wait_vrise_state(otg_t * otg);static void b_host_state(otg_t * otg);static void b_idle_state(otg_t * otg);static void b_peripheral_state(otg_t * otg);static void b_srp_init_state(otg_t * otg);static void b_wait_acon_state(otg_t * otg);/* Functionality. *//* * FUNCTION: Timer utilities * * DESCRIPTION: * These functions are used to support timeout functionality for * the otg state diagram. */struct timer_list to_timer;// FIXME check these times/* The following enumerations are in jiffies. */typedef enum timeout_times{ Ta_wait_vrise = 10, // 100ms Ta_wait_bcon = -1, // infinite Ta_aidl_bdis = 35, // 350ms Tb_ase0_brst = 31, // We need 3.125 ms} OTG_Timeouts;void otg_timeout(unsigned long data){ cy_err("timeout"); *((boolean*)data) = TRUE; update_otg_state( (otg_t*)otg_cy_priv->otg );}static void otg_start_timer(boolean *state, OTG_Timeouts time){ if( time < 0 ) { return; } if( timer_pending(&to_timer) ) { cy_err("ERROR: timer in use - restarting"); } *state = FALSE; to_timer.data = (unsigned long)state; mod_timer( &to_timer, jiffies + time );}static void otg_cancel_timer(boolean *state){ *state = FALSE; del_timer(&to_timer);}/* * */void switch_role(int new_role){ const char * const name[] = { "HOST_ROLE", "PERIPHERAL_ROLE", "HOST_INACTIVE_ROLE" }; HWTrace (0x3100); //cy_err("Switch role to %s", name[new_role]); switch (new_role) { case PERIPHERAL_ROLE: HWTrace (0x3101); hcd_switch_role(new_role, otg_cy_priv); pcd_switch_role(new_role, otg_cy_priv); break; case HOST_ROLE: HWTrace (0x3102); case HOST_INACTIVE_ROLE: HWTrace (0x3103); pcd_switch_role(new_role, otg_cy_priv); hcd_switch_role(new_role, otg_cy_priv); break;#if 0 case HOST_INACTIVE_ROLE: { unsigned short intStat; HWTrace (0x3103); lcd_write_reg(0xc08a, 0x380, otg_cy_priv); // Setup interrupt steering intStat = 0; intStat |= SOFEOP1_TO_CPU_EN; intStat |= SOFEOP2_TO_CPU_EN; intStat |= VBUS_TO_HPI_EN; intStat |= ID_TO_HPI_EN; lcd_write_reg(HPI_SIE_IE, intStat, otg_cy_priv); // Turn on VBUS and ID interrupts lcd_read_reg (SIE1_INT_EN_REG, &intStat, otg_cy_priv); intStat |= VBUS_IRQ_EN; intStat |= ID_IRQ_EN; intStat |= 0xa00; // MSE & SOF, IROS pg 103 lcd_write_reg(SIE1_INT_EN_REG, intStat, otg_cy_priv); } break;#endif } HWTrace (0x3104); otg_cy_priv->system_mode[SIE0] = new_role; }void otg_print_state(void){ unsigned short intStat; if (otg_cy_priv != NULL && otg_cy_priv->otg != NULL) { otg_t * otg = otg_cy_priv->otg; printk("\n"); printk("\n"); printk("\n"); printk("state = %s\n", state_names[otg->state]); printk("id = %s\n", otg->id == A_DEV ? "A_DEV" : "B_DEV"); printk("a_srp_det = %s\n", otg->a_srp_det == 0 ? "false" : "true"); printk("a_set_b_hnp_en = %s\n", otg->a_set_b_hnp_en == 0 ? "false" : "true"); printk("b_conn = %s\n", otg->b_conn == 0 ? "false" : "true"); printk("a_bus_drop = %s\n", otg->a_bus_drop == 0 ? "false" : "true"); printk("a_bus_req = %s\n", otg->a_bus_req == 0 ? "false" : "true"); printk("a_suspend_req = %s\n", otg->a_suspend_req == 0 ? "false" : "true"); printk("b_bus_suspend = %s\n", otg->b_bus_suspend == 0 ? "false" : "true"); printk("b_bus_resume = %s\n", otg->b_bus_resume == 0 ? "false" : "true"); printk("a_sess_vld = %s\n", otg->a_sess_vld == 0 ? "false" : "true"); printk("a_vbus_vld = %s\n", otg->a_vbus_vld == 0 ? "false" : "true"); printk("a_wait_vrise_tmout = %s\n", otg->a_wait_vrise_tmout == 0 ? "false" : "true"); printk("a_wait_bcon_tmout = %s\n", otg->a_wait_bcon_tmout == 0 ? "false" : "true"); printk("a_aidl_bdis_tmout = %s\n", otg->a_aidl_bdis_tmout == 0 ? "false" : "true"); printk("b_bus_req = %s\n", otg->b_bus_req == 0 ? "false" : "true"); printk("b_sess_end = %s\n", otg->b_sess_end == 0 ? "false" : "true"); printk("b_se0_srp = %s\n", otg->b_se0_srp == 0 ? "false" : "true"); printk("b_srp_done = %s\n", otg->b_srp_done == 0 ? "false" : "true"); printk("b_sess_vld = %s\n", otg->b_sess_vld == 0 ? "false" : "true"); printk("a_bus_resume = %s\n", otg->a_bus_resume == 0 ? "false" : "true"); printk("b_hnp_en = %s\n", otg->b_hnp_en == 0 ? "false" : "true"); printk("a_bus_suspend = %s\n", otg->a_bus_suspend == 0 ? "false" : "true"); printk("b_se0_brst_tmout = %s\n", otg->b_se0_brst_tmout == 0 ? "false" : "true"); printk("a_conn = %s\n", otg->a_conn == 0 ? "false" : "true"); printk("b_ase0_brst_tmout = %s\n", otg->b_ase0_brst_tmout == 0 ? "false" : "true"); printk("b_wait_acon_tmout = %s\n", otg->b_wait_acon_tmout == 0 ? "false" : "true"); lcd_read_reg (SIE1_INT_EN_REG, &intStat, otg_cy_priv); printk("SIE1_INT_EN_REG = 0x%X\n", intStat); printk("\n"); printk("\n"); }}int otg_state(int * state){ if (otg_cy_priv != NULL && otg_cy_priv->otg != NULL) { *state = ((otg_t*)otg_cy_priv->otg)->state; return 0; } return -1;}int otg_id(int * id){ int ret = -1; otg_t * otg; if (otg_cy_priv != NULL) { if (otg_cy_priv->otg != NULL) { otg = otg_cy_priv->otg; *id = otg->id; ret = 0; } } return ret;}int otg_start_session(void){ int ret = -1; otg_t * otg; if (otg_cy_priv != NULL) { if (otg_cy_priv->otg != NULL) { otg = otg_cy_priv->otg; otg->a_bus_drop = FALSE; otg->a_bus_req = TRUE; /* cy_err("otg_start_session: state = %s", state_names[otg->state]); */ update_otg_state(otg); ret = 0; } } return ret;}int otg_end_session(void){ int ret = -1; otg_t * otg; if (otg_cy_priv != NULL) { if (otg_cy_priv->otg != NULL) { otg = otg_cy_priv->otg; otg->a_bus_drop = TRUE; otg->a_bus_req = FALSE; otg->a_srp_det = FALSE; /* cy_err("otg_end_session: state = %s", state_names[otg->state]); */ update_otg_state(otg); ret = 0; } } return ret;}int otg_offer_hnp(void){ int ret = -1; otg_t * otg; if (otg_cy_priv != NULL) { if (otg_cy_priv->otg != NULL) { otg = otg_cy_priv->otg; if( otg->state == a_host ) { otg->a_set_b_hnp_en = TRUE; otg->a_bus_req = FALSE; otg->b_bus_resume = FALSE; update_otg_state(otg); ret = 0; } } } return ret;}int otg_end_hnp(void){ int ret = -1; otg_t * otg; if (otg_cy_priv != NULL) { if (otg_cy_priv->otg != NULL) { otg = otg_cy_priv->otg; if(otg->state == b_host) { otg->b_bus_req = FALSE; update_otg_state(otg); ret = 0; } } } return ret;}void otg_init(cy_priv_t * cy_priv){ unsigned short otg_ctl = 0; otg_t * otg; /* store the cy_priv to our global cy_priv structure */ otg_cy_priv = cy_priv; /* alloc and initialize OTG data structure */ otg = (otg_t *) kmalloc (sizeof(otg_t), GFP_KERNEL); memset(otg, 0, sizeof(otg_t)); /* Initialize timeout timer */ init_timer(&to_timer); to_timer.function = otg_timeout; /* Disable VBUS */ lcd_command(LCD_DISABLE_OTG_VBUS, 0, PORT0, NULL, 0, otg_cy_priv); /* read the OTG ID pin */ lcd_read_reg(OTG_CTL_REG, &otg_ctl, cy_priv); if (otg_ctl & OTG_ID_STAT) { otg->state = b_idle; otg->id = B_DEV; otg->b_sess_end = TRUE; } else { otg->state = a_idle; otg->id = A_DEV; } cy_priv->otg = otg;}void a_idle_state(otg_t * otg){ HWTrace (0x3020); if (otg->state != a_idle) { HWTrace (0x3021); otg->a_bus_drop = FALSE; otg->state = a_idle; } switch (otg->id) { case A_DEV: if ((otg->a_bus_drop == 0) && (otg->a_bus_req || otg->a_srp_det)) { HWTrace (0x3022); /* cy_err("a_bus_drop:%d, a_bus_req:%d, a_srp_det:%d", otg->a_bus_drop, otg->a_bus_req, otg->a_srp_det); */ switch_role(HOST_ROLE); a_wait_vrise_state(otg); } HWTrace (0x3023); break; case B_DEV: HWTrace (0x3024); b_idle_state(otg); break; }}void a_wait_vrise_state(otg_t * otg){ unsigned short otg_ctl; HWTrace (0x3030); if (otg->state != a_wait_vrise) { otg->state = a_wait_vrise; /* start a_wait_vrise timer */ otg_start_timer( &otg->a_wait_vrise_tmout, Ta_wait_vrise ); /* Notify the app if SRP detected */ if (otg->a_srp_det) { HWTrace (0x3031); otg->a_srp_det = FALSE; } HWTrace (0x3032); /* driver VBUS */ lcd_command(LCD_ENABLE_OTG_VBUS, 0, PORT0, NULL, 0, otg_cy_priv); } if( otg->a_wait_vrise_tmout ) { unsigned short value; lcd_read_reg(OTG_CTL_REG, &value, otg_cy_priv); if (value & VBUS_VALID_FLG) { otg->a_vbus_vld = TRUE; // HPI can not distinguish between the two thresholds. otg->a_sess_vld = otg->b_sess_vld = TRUE; otg->a_wait_vrise_tmout = FALSE; } else { otg->a_vbus_vld = FALSE; // HPI can not distinguish between the two thresholds. otg->a_sess_vld = otg->b_sess_vld = (value & OTG_DATA_STAT) ? TRUE : FALSE; } } HWData(otg->a_vbus_vld); switch (otg->id) { case A_DEV: if (otg->a_bus_drop || otg->a_vbus_vld || otg->a_wait_vrise_tmout) { HWTrace (0x3033); otg_cancel_timer( &otg->a_wait_vrise_tmout ); a_wait_bcon_state(otg); } HWTrace (0x3034); break; case B_DEV: HWTrace (0x3035); otg_cancel_timer( &otg->a_wait_vrise_tmout ); a_wait_bcon_state(otg); break; } }void a_wait_bcon_state(otg_t * otg){ HWTrace (0x3040); if (otg->state != a_wait_bcon) { unsigned short usb_ctl_val; /* Check for B-connected */ lcd_read_reg(USB1_CTL_REG, &usb_ctl_val, otg_cy_priv); /* if device is connected */ if ( usb_ctl_val & (A_DP_STAT | A_DM_STAT) ) { otg->b_conn = TRUE; } if (otg->state == a_host && otg->a_bus_req == TRUE) { HWTrace (0x3041); /* the previous state is a_host. This means that device has been * removed */ handle_device_removal(otg_cy_priv, PORT0); } HWTrace (0x3042); otg_start_timer( &otg->a_wait_bcon_tmout, Ta_wait_bcon ); otg->state = a_wait_bcon; otg->b_bus_suspend = FALSE; } switch (otg->id) { case A_DEV: if (otg->a_bus_drop || otg->a_wait_bcon_tmout) { HWTrace (0x3043); otg_cancel_timer( &otg->a_wait_bcon_tmout ); a_wait_vfall_state(otg); } else if (!otg->a_vbus_vld) { HWTrace (0x3044); otg_cancel_timer( &otg->a_wait_bcon_tmout ); a_vbus_err_state(otg); } else if (otg->b_conn) { HWTrace (0x3045); otg_cancel_timer( &otg->a_wait_bcon_tmout ); a_host_state(otg); } break; case B_DEV: HWTrace (0x3046); otg_cancel_timer( &otg->a_wait_bcon_tmout ); a_wait_vfall_state(otg); break; } }void a_host_state(otg_t * otg){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -