⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cy7c67200_300_pcd.c

📁 cypress usb芯片驱动程序,该程序实现了cypress63700的3个驱动
💻 C
📖 第 1 页 / 共 4 页
字号:
/******************************************************************************* * * 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, &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, &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, &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, &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, &reg_val, cy_priv);        lcd_write_reg(OTG_CTL_REG, reg_val & ~VBUS_DISCH_EN, cy_priv);        lcd_read_reg(OTG_CTL_REG, &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 + -