📄 cy7c67200_300_pcd.c
字号:
/******************************************************************************* * * Copyright (c) 2003 Cypress Semiconductor * * * 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, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */#include <linux/config.h>#include <linux/module.h>#include "../usbd-export.h"#include "../usbd-build.h"// #include "../usbd-module.h"MODULE_AUTHOR("Cypress Semiconductor");MODULE_DESCRIPTION("CY7C67200_300 Peripheral Bus Interface");#include <linux/kernel.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/init.h>#include <linux/timer.h>#include <asm/atomic.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/system.h>#include <asm/types.h>#include <asm/uaccess.h>#include <asm/io.h>#include <linux/delay.h>#include "../usbd.h"extern int __init usbd_device_init(void);#include "../usbd-func.h"#include "../usbd-bus.h"#include "../usbd-inline.h"#include "usbd-bi.h"extern int __init bi_modinit(void);#include "../../cy7c67200_300.h"#include "../../lcp_cmd.h"#include "../../cy7c67200_300_common.h"#include "../../cy7c67200_300_lcd.h"#include "../../cy7c67200_300_otg.h"#include "../../cy7c67200_300_debug.h"#include "cy7c67200_300_pcd.h"extern void de1_modinit(void);extern void de3_modinit(void);extern void de4_modinit(void);#define MIN(a,b) ((a) < (b) ? (a) : (b))#define MAX(a,b) ((a) > (b) ? (a) : (b))/* Local functions */static void ep_receive_data(struct usb_endpoint_instance *, int, cy_priv_t *);static int load_configuration_data(cy_priv_t *);static int pcd_dbg_on = 0;#define pcd_dbg(format, arg...) \ if( pcd_dbg_on != 0 ) \ printk(KERN_DEBUG __FILE__ ":" "%d: " format "\n" ,__LINE__, ## arg)static struct timer_list vbus_timer;static sie_info *sie;static sie_info sie_init_data[] ={ { susb_recv_interrupt: SUSB1_RECEIVE_INT, susb_stall_interrupt: SUSB1_STALL_INT, susb_standard_int: SUSB1_STANDARD_INT, susb_standard_loader_vec: SUSB1_STANDARD_LOADER_VEC, susb_vendor_interrupt: SUSB1_VENDOR_INT, susb_vendor_loader_vec: SUSB1_VENDOR_LOADER_VEC, susb_class_interrupt: SUSB1_CLASS_INT, susb_class_loader_vec: SUSB1_CLASS_LOADER_VEC, susb_finish_interrupt: SUSB1_FINISH_INT, susb_dev_desc_vec: SUSB1_DEV_DESC_VEC, susb_config_desc_vec: SUSB1_CONFIG_DESC_VEC, susb_string_desc_vec: SUSB1_STRING_DESC_VEC, susb_parse_config_interrupt: SUSB1_PARSE_CONFIG_INT, susb_loader_interrupt: SUSB1_LOADER_INT, susb_delta_config_interrupt: SUSB1_DELTA_CONFIG_INT, susb_init_interrupt: SUSB_INIT_INT, susb_remote_wakeup_interrupt: REMOTE_WAKEUP_INT, susb_start_srp_interrupt: START_SRP_INT, recv_buffer_length: RECV_BUFF_LENGTH, send_buffer_length: SEND_BUFF_LENGTH, bus: 0, cy_priv: 0, usb_address: 0, udc_suspended: TRUE, sie_number: SIE1 }, { susb_recv_interrupt: SUSB2_RECEIVE_INT, susb_stall_interrupt: SUSB2_STALL_INT, susb_standard_int: SUSB2_STANDARD_INT, susb_standard_loader_vec: SUSB2_STANDARD_LOADER_VEC, susb_vendor_interrupt: SUSB2_VENDOR_INT, susb_vendor_loader_vec: SUSB2_VENDOR_LOADER_VEC, susb_class_interrupt: SUSB2_CLASS_INT, susb_class_loader_vec: SUSB2_CLASS_LOADER_VEC, susb_finish_interrupt: SUSB2_FINISH_INT, susb_dev_desc_vec: SUSB2_DEV_DESC_VEC, susb_config_desc_vec: SUSB2_CONFIG_DESC_VEC, susb_string_desc_vec: SUSB2_STRING_DESC_VEC, susb_parse_config_interrupt: SUSB2_PARSE_CONFIG_INT, susb_loader_interrupt: SUSB2_LOADER_INT, susb_delta_config_interrupt: SUSB2_DELTA_CONFIG_INT, susb_init_interrupt: SUSB_INIT_INT, susb_remote_wakeup_interrupt: REMOTE_WAKEUP_INT, susb_start_srp_interrupt: START_SRP_INT, recv_buffer_length: RECV_BUFF_LENGTH, send_buffer_length: SEND_BUFF_LENGTH, bus: 0, cy_priv: 0, usb_address: 0, udc_suspended: TRUE, sie_number: SIE2 }};/****************************************************************************** * FUNCTION: pcd_init * * DESCRIPTION: Records boot time configuration of desired sie and design * example to be used later. */int pcd_init(int sie_num, int de_num, cy_priv_t *cy_priv){ size_t i; unsigned short mem_start = cy_priv->cy_buf_addr; pcd_dbg("pcd_init enter"); /* Check for valid SIE */ if( sie_num >= sizeof(sie_init_data)/sizeof(sie_info) ) { return ERROR; } /* Initialize some SIE members */ sie = &sie_init_data[sie_num]; sie->cy_priv = cy_priv; cy_priv->pcdi = sie; if( sie_num == SIE1 ) { sie->sie_dev_desc_location = SIE1_DEVICE_DESCRIPTOR_LOCATION; sie->sie_config_desc_location = SIE1_CONFIG_DESCRIPTOR_LOCATION; sie->sie_string_desc_location = SIE1_STRING_DESCRIPTOR_LOCATION; sie->recv_struct_location = SIE1_RECV_STRUCT_ADDR; sie->recv_buffer_location = SIE1_RECV_BUFF_ADDR; sie->send_struct_location = SIE1_SEND_STRUCT_ADDR; sie->send_buffer_location = SIE1_SEND_BUFF_ADDR; cy_priv->cy_buf_addr = SIE1_MEM_END; } else { sie->sie_dev_desc_location = SIE2_DEVICE_DESCRIPTOR_LOCATION; sie->sie_config_desc_location = SIE2_CONFIG_DESCRIPTOR_LOCATION; sie->sie_string_desc_location = SIE2_STRING_DESCRIPTOR_LOCATION; sie->recv_struct_location = SIE2_RECV_STRUCT_ADDR; sie->recv_buffer_location = SIE2_RECV_BUFF_ADDR; sie->send_struct_location = SIE2_SEND_STRUCT_ADDR; sie->send_buffer_location = SIE2_SEND_BUFF_ADDR; cy_priv->cy_buf_addr = SIE2_MEM_END; } pcd_dbg("PCD memory usage: start:0x%04x, end+1:0x%04x, size:0x%04x", mem_start, cy_priv->cy_buf_addr, cy_priv->cy_buf_addr - mem_start); for(i=0; i<UDC_MAX_ENDPOINTS; i++) { sie->rcv_data_pend_ep[i] = 0; } /* Initialize device core */ if (usbd_device_init()) { cy_err("usbd_device_init failed"); sie = 0; return ERROR; } /* setup function driver based upon design example */ switch( de_num ) { case DE1: { lcd_int_data_t int_data; pcd_dbg("Initializing peripheral function driver for DE1"); de1_modinit(); // Initialize BIOS for debug port int_data.int_num = SUSB_INIT_INT; int_data.reg[1] = FULL_SPEED; int_data.reg[2] = 2; // SIE2 pcd_dbg("Initializing debug port"); lcd_exec_interrupt(&int_data, 0, 0, cy_priv); } break; case DE3: pcd_dbg("Initializing peripheral function driver for DE3"); de3_modinit(); break; case DE4: pcd_dbg("Initializing peripheral function driver for DE4"); de4_modinit(); break; default: cy_err("unhandled design example %d", de_num); return ERROR; break; } /* Initialize bus interface */ if( bi_modinit() ) { cy_err("bi_modinit failed"); sie = 0; return ERROR; } init_timer(&vbus_timer); return SUCCESS;}/***************************************************************** * * Function Name: pcd_switch_role * * Description: This function activates/deactivates the peripheral * code when doing a role switch. * * Input: role - the role to switch to. * * Return: none * *****************************************************************/int pcd_switch_role(int role, cy_priv_t *cy_priv){ unsigned short intStat; lcd_int_data_t int_data; int i; pcd_dbg("pcd_switch_role enter"); if( cy_priv == 0 || sie == 0 ) { return ERROR; } switch(role) { case PERIPHERAL_ROLE: pcd_dbg("pcd role switch to PERIPHERAL_ROLE"); // Setup interrupt steering lcd_read_reg(HPI_IRQ_ROUTING_REG, &intStat, cy_priv); intStat &= ~SOFEOP1_TO_HPI_EN; intStat &= ~SOFEOP2_TO_HPI_EN; intStat |= SOFEOP1_TO_CPU_EN; intStat |= SOFEOP2_TO_CPU_EN; lcd_write_reg(HPI_IRQ_ROUTING_REG, intStat, cy_priv); // Save descriptors to BIOS if( load_configuration_data(cy_priv) == ERROR ) { cy_err("load_configuration_data failed"); return ERROR; } // Initialize BIOS for slave int_data.int_num = SUSB_INIT_INT; int_data.reg[1] = FULL_SPEED; int_data.reg[2] = sie->sie_number + 1; if( lcd_exec_interrupt(&int_data, 0, 0, cy_priv) == ERROR ) { cy_err("lcd_exec_interrupt failed"); return ERROR; } for(i=0; i<10; i++) { lcd_read_reg(USB1_CTL_REG, &intStat, cy_priv); if( (intStat & (A_DP_STAT | A_DM_STAT)) ) break; mdelay(1); } // Turn on VBUS and ID interrupts lcd_read_reg (HOST1_IRQ_EN_REG, &intStat, cy_priv); intStat |= VBUS_IRQ_EN; intStat |= ID_IRQ_EN; intStat |= SOF_EOP_TMOUT_IRQ_EN; // MSE lcd_write_reg(HOST1_IRQ_EN_REG, intStat, cy_priv); break; case HOST_ROLE: pcd_dbg("pcd role switch to HOST_ROLE"); usbd_device_event_irq(sie->bus->device, DEVICE_BUS_INACTIVE, 0); usbd_device_event(sie->bus->device, DEVICE_RESET, 0); break; case HOST_INACTIVE_ROLE: pcd_dbg("pcd role switch to HOST_INACTIVE_ROLE"); usbd_device_event_irq(sie->bus->device, DEVICE_BUS_INACTIVE, 0); usbd_device_event(sie->bus->device, DEVICE_RESET, 0); // Setup interrupt steering lcd_read_reg(HPI_IRQ_ROUTING_REG, &intStat, cy_priv); intStat &= ~SOFEOP1_TO_HPI_EN; intStat &= ~SOFEOP2_TO_HPI_EN; intStat |= SOFEOP1_TO_CPU_EN; intStat |= SOFEOP2_TO_CPU_EN; lcd_write_reg(HPI_IRQ_ROUTING_REG, intStat, cy_priv); // Turn on VBUS and ID interrupts lcd_read_reg (HOST1_IRQ_EN_REG, &intStat, cy_priv); intStat |= VBUS_IRQ_EN; intStat |= ID_IRQ_EN; intStat |= 0x800; // MSE, IROS pg 103 intStat &= ~A_CHG_IRQ_EN; intStat &= ~B_CHG_IRQ_EN; lcd_write_reg(HOST1_IRQ_EN_REG, intStat, cy_priv); // for initialization when we don't get an IRQ for connection at // reset pcd_irq_vbus(cy_priv); break; } return SUCCESS;}/***************************************************************** * * Function Name: pcd_signal_srp * * Description: This function performs a session request protocol. * *****************************************************************/int pcd_signal_srp(size_t vbus_pulse_time, cy_priv_t *cy_priv){ unsigned short reg_val; /* Check SE0 state for 2ms */ lcd_read_reg(USB1_CTL_REG, ®_val, cy_priv); if( reg_val & (A_DP_STAT | A_DM_STAT) ) { cy_err("Not SE0 state"); /* Not SE0 state */ return ERROR; } mdelay(2); lcd_read_reg(USB1_CTL_REG, ®_val, cy_priv); if( reg_val & (A_DP_STAT | A_DM_STAT) ) { cy_err("Not SE0 state"); /* Not SE0 state */ return ERROR; } /* check session ended */ lcd_read_reg(OTG_CTL_REG, ®_val, cy_priv); if( reg_val & VBUS_VALID_FLG ) { cy_err("VBUS high 1"); /* A-Device still driving VBUS.*/ return ERROR; } else { /* Pulse VBUS discharge resistor */ lcd_read_reg(OTG_CTL_REG, ®_val, cy_priv); lcd_write_reg(OTG_CTL_REG, reg_val | VBUS_DISCH_EN, cy_priv); mdelay(30); lcd_read_reg(OTG_CTL_REG, ®_val, cy_priv); lcd_write_reg(OTG_CTL_REG, reg_val & ~VBUS_DISCH_EN, cy_priv); lcd_read_reg(OTG_CTL_REG, ®_val, cy_priv); if( reg_val & OTG_DATA_STAT ) { cy_err("VBUS high 2"); /* Error: The USB host may be driving the VBUS */ return ERROR; } /* Pulse D+ data line */ //pcd_dbg("START D+ PULLUP");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -