文章详情

  • 游戏榜单
  • 软件榜单
关闭导航
热搜榜
热门下载
热门标签
php爱好者> php文档>cq8401-spi-sc16IS751 驱动分析

cq8401-spi-sc16IS751 驱动分析

时间:2010-03-11  来源:cao5170

1 . 工作原理   CQ8401 spi总线(master)通过两个SC16IS752芯片(slave),外扩232,GPS,485,422;一块SC16IS752芯片最多只能扩两个设备。   涉及到的知识:SPI协议(参考网上资料有很多), UART工作原理(参考设备驱动)。   1.1 原理图:
 
      原理图说明:   SCLK: The divider of the SSICLK, I2SCLK and USB clock can be changed by programming CFCR1.SSIFR, CFCR2.I2SFR and CFCR1.UFR, respectively.   /* arch/mips/cq8401/common/setup.c */ clx_clocks.ssiclk = __cpm_get_ssiclk();   static __inline__ unsigned int __cpm_get_ssiclk(void) { unsigned int ssiclk; unsigned long cfcr = REG_CPM_CFCR; unsigned long plcr = REG_CPM_PLCR1; if ((plcr & CPM_PLCR1_PLL1EN) && (cfcr & CPM_CFCR_SSI)) ssiclk = __cpm_get_pllout() / (((cfcr&CPM_CFCR_SSIFR_MASK)>>CPM_CFCR_SSIFR_BIT)+1); else ssiclk = CLX_EXTAL; return ssiclk; }     CS:芯片片选信号,低有效;在安联板上有2块SC16IS752芯片,驱动中应该注意CS信号线   SO: 芯片输出 , CQ8401接收   SI: CQ8401 输出,芯片 接收   IRQ:中断线   GPIO 寄存器:该方案中没有用   16C45: 外接 232,GPS 或者 485,422   1.2数据流程
 
数据发送: CQ8401--> SPI ---> SC16IS752 -->232/485/GPS/422   数据接收: 232/485/GPS/422 有数据来产生中断,数据存储在SC16IS752 FIFO中--> SPI --->CQ8401处理中断,接收数据       2 驱动分析
 
本驱动最重要的是要注意在发送和接收的时候,对CS片选信号线要主动的去拉低。比如在发送中,你是知道要向那个芯片发数据的,所以在发送前要将对应的芯片CS信号线拉低。在接收过程中,由于2块芯片的接收中断是一直开启的,所以来了中断,你在接收中断函数中能通过struct uart_port *port = dev_id,port->line 来知道是那块芯片, port->line 对应如下:     port->line=0 芯片一 cs1  接232 port->line=1 芯片一 cs1 接GPS port->line=2 芯片二 cs2 接422 port->line=3 芯片二 cs2 接422   根据这个关系来确定去拉低那跟CS片选信号线。   关于初始化部分,这里不在阐述,重点讲UART的ops 操作   static struct uart_ops s752_pops = { tx_empty: s752_tx_empty, set_mctrl: s752_set_mctrl, get_mctrl: s752_get_mctrl, stop_tx: s752_stop_tx, start_tx: s752_start_tx, stop_rx: s752_stop_rx, enable_ms: s752_enable_ms, break_ctl: s752_break_ctl, startup: s752_startup, shutdown: s752_shutdown, set_termios: s752_set_termios, type: s752_type, release_port: s752_release_port, request_port: s752_request_port, config_port: s752_config_port, verify_port: s752_verify_port, };      这里主要讲以下几个部分:       2.1 start_tx:
s752_start_tx , UART open操作
  static int s752_startup(struct uart_port *port) { uint16_t ret; int retval=0; int i=0; /* 根据port->line 来选择ce1 或者 ce2 */ //spin_lock(&port->lock); while((!(__ssi_transfer_end())) || __ssi_is_busy()); if(port->line < 2){ __ssi_select_ce(); //spi_ce1 被片选中 sc752_ce1_init(port); // 初始化,分析如下 } else{ __ssi_select_ce2(); //spi_ce2 被片选中 sc752_ce2_init(port);   // 初始化,分析如下 } //spin_unlock(&port->lock);    #ifdef _DEBUG_S752 printk("=====>AFT REG_SSI_CR0=0x%08x\n",REG_SSI_CR0); printk("s752_startup exit\n"); #endif     return 0;     }     static void sc752_ce1_init(struct uart_port *port) {   int retval=0;   /* clears the contents of the transmit and receive FIFO and resets the FIFO level logic and enable the transmit and receive FIFO */     s752_write_reg(FCR,port->line,0x07); delay(5);   #if 0 /* 232 uart surport HardwareFlow*/ printk("set hartdware flow control!!\n"); if(!port->line) HardwareFlow(); //channel A 232 hardwareflow   /*Force RTS low level for sofeware flow control*/ s752_write_reg(MCR,ChannelA,0x02); #endif     /* 中断注册,这里用的是共享中断,中断号IRQ_GPIO0+GPIO */ retval = request_irq(port->irq, s752_int, IRQF_SHARED, "ttySC_CE1",port);   if (retval){ printk("request irq SPI_CE1 error:%d\n",retval); return retval; }   /* only enable the RHR interrupt in s752_startup*/ s752_write_reg(IER, port->line, 0x01);   }   static void sc752_ce2_init(struct uart_port *port) {   unsigned int line=0; int retval=0; line=port->line-2;     /* clears the contents of the transmit and receive FIFO and resets the FIFO * level logic and enable the transmit and receive FIFO */ s752_write_reg(FCR,line,0x07); delay(5);   /* set RS-485*/   rs_485_Multidrop(line);   /* 中断注册,这里用的是共享中断,中断号IRQ_GPIO0+GPIO */ retval = request_irq(port->irq, s752_int, IRQF_SHARED, "ttySC_CE2",port);   if (retval){ printk("request irq SPI_CE2 error:%d\n",retval); return retval; }     /* only enable the RHR interrupt */   s752_write_reg(IER,line, 0x01);     }   2.2 start_tx:
 
s752_start_tx, 开始发送数据   static void s752_start_tx(struct uart_port *port) {   unsigned int line=0;   /* 根据port->line 来选择ce1 或者 ce2 */ while((!(__ssi_transfer_end())) || __ssi_is_busy()); if(port->line < 2){ __ssi_select_ce(); line=port->line;   } else { __ssi_select_ce2(); line=port->line-2;   } /* enable trasmit interrupt */ s752_write_reg(IER,line, 0x03);   //s752_tx_chars(port);   }   2.3 set_termios:
s752_set_termios, set baud_rate,even-odd parity, stop bit,data bit
      static void s752_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) {     unsigned long flags; unsigned int baud, quot; unsigned short cval=0, ier, lsr,line=0;  
if(port->line < 2)
line=port->line; else line=port->line-2; /* * Ask the core to calculate the divisor for us. */   baud = uart_get_baud_rate(port, termios, old, 0, 56000*8); quot = uart_get_divisor(port, baud);   spin_lock_irqsave(port->lock,flags); /* LCR[7]=1,enable divisor latch*/ s752_write_reg(LCR,line,0x80); s752_write_reg(DLL,line,quot & 0xFF); //baud rate s752_write_reg(DLH,line,(quot >> 8) & 0xFF);   spin_unlock_irqrestore(port->lock, flags);   /* set data bit*/ switch (termios->c_cflag & CSIZE) { case CS5: cval = UART_LCR_WLEN5; break; case CS6: cval = UART_LCR_WLEN6; break; case CS7: cval = UART_LCR_WLEN7; break; default: case CS8: cval = UART_LCR_WLEN8; break; } /* set stop bit*/ if (termios->c_cflag & CSTOPB){   cval |= UART_LCR_STOP; } /* set parity bit*/ if (termios->c_cflag & PARENB){ //如果设置了parity bit,则LCR第3位置1;   cval |= UART_LCR_PARITY; if (!(termios->c_cflag & PARODD))   cval |= UART_LCR_EPAR;
 
}   s752_write_reg(LCR, line, cval);   }   2.4中断处理函数
 
static irqreturn_t s752_int(int irq, void *dev_id) {   struct uart_port *port = dev_id; uint8_t ret=0,chip; int i=0; unsigned int status,line;   spin_lock(&port->lock); /* 根据port->line 来选择ce1 或者 ce2 */ while((!(__ssi_transfer_end())) || __ssi_is_busy());   if(port->line < 2){ __ssi_select_ce(); line=port->line; chip=0; } else{ __ssi_select_ce2(); line=port->line-2; chip=1; }     ret=s752_read_reg(IIR,line);    
if(!(ret & 0x01)){
status = s752_read_reg(LSR,line); if(ret&0x04 && status&0x01) //rx intterrupt s752_rx_chars(port,status); if(ret&0x02) //tx interrupt s752_tx_chars(port); }   spin_unlock(&port->lock); return IRQ_HANDLED;   }     2.5 具体发送,接收函数分析
s752_rx_chars(port,status)---接收 ,s752_tx_chars(port)--发送,跟普通的串口一样,
  不具体分析。   2.6 485,422,232 介绍
 
RS-422的最大传输距离为4000英尺(约1219米),最大传输速率为10Mb/s;RS-485是从RS-422基础上发展而来的,所以RS-485许多电气规定与RS-422相仿。RS-485与RS-422一样,其最大传输距离约为1219米,最大传输速率为10Mb/s而RS-232传输距离很短只有50m。   485是半双工的,422是全双工的,232全双工。 4根线:RX,TX,RTS,CTS;一般RTS,CTS没怎么用 RX: 数据接收(pc-->8401) TX: 数据发送 (8401-->pc) RTS: 请求发送,输出信号(请求数据从外设pc-->8401,低有效,驱动需要控制) CTS:清除发送,输入信号(表明外设PC已准备好,8401可以发数据给外设PC了,驱动中需要去读取寄存器的这位)   232一般只需要2根线(RX,TX),有时在需要流控的时候才需要(RTS,CTS)   485:RX,TX,RTS(控制是发送还是接收)   422:RX,TX,RTS(控制是发送还是接收)       3 建议 建议在后续开发中,在2.6的内核中把SSI总线驱动移植了,可参考2.4内核SSI总线驱动;还有 一些SSI驱动的参考如下
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/yinkaizhong/archive/2009/05/19/4202229.aspx
相关阅读 更多 +
排行榜 更多 +
弓箭手战士酷跑

弓箭手战士酷跑

飞行射击 下载
三角洲行动全面战场攀升A点进攻指南

三角洲行动全面战场攀升A点进攻指南

飞行射击 下载
僵尸射手世界大战

僵尸射手世界大战

飞行射击 下载