Forum Discussion
Altera_Forum
Honored Contributor
19 years ago/******************************************************************************
* File: quartus60\sopc_builder\components\altera_avalon_spi\ * * HAL\inc\altera_avalon_spi.c * * Auth: lvjian (lvjian75@126.com) * * date: 2006.8.1 * * version: 0.1 * ******************************************************************************/ # include <string.h># include <fcntl.h># include <errno.h># include <limits.h> # include <sys/stat.h># include <os/alt_sem.h># include "sys/alt_dev.h"# include "sys/alt_irq.h"# include "sys/alt_alarm.h"# include "sys/ioctl.h"# include "alt_types.h" # include "altera_avalon_spi_regs.h"# include "altera_avalon_spi.h" # include "sys/alt_log_printf.h" /* ----------------------------------------------------------------------- */ /* ---------------------- ROUTINES FOR FAST DRIVER ----------------------- */ int alt_avalon_spi_read(alt_fd* fd, char * buffer, int space) { alt_avalon_spi_dev* dev = (alt_avalon_spi_dev*) fd->dev; spi_data_buf *pbuf; int copylen; int copypos; int i; pbuf = &(dev->rx_data); ALT_SEM_PEND(dev->rx_wait,0); copylen = space>pbuf->datalen?pbuf->datalen:space; copypos = pbuf->pos; for(i=0;i<copylen;i++){ *(buffer+i) = *(pbuf->buf+copypos); copypos = (copypos+1)%ALT_AVALON_SPI_BUF_LEN; } pbuf->datalen -= copylen; pbuf->pos = copypos; return copylen; } int alt_avalon_spi_write(alt_fd* fd, const char * ptr, int count) { int copylen; int copypos; int alltxlen; spi_data_buf *pbuf; alt_avalon_spi_dev* dev = (alt_avalon_spi_dev*) fd->dev; pbuf = &(dev->tx_data); alltxlen = count; while(count){ ALT_SEM_PEND(dev->tx_wait,0); copylen = ALT_AVALON_SPI_BUF_LEN-pbuf->datalen; copylen = copylen>count?count:copylen; copypos = (pbuf->pos+pbuf->datalen)%ALT_AVALON_SPI_BUF_LEN; count -= copylen; pbuf->datalen+=copylen; while(copylen){ pbuf->buf[copypos] = *(ptr++); copypos = (copypos+1)%ALT_AVALON_SPI_BUF_LEN; copylen--; } dev->irq_enable |= ALTERA_AVALON_SPI_CONTROL_ITRDY_MSK; IOWR_ALTERA_AVALON_SPI_CONTROL(dev->base,dev->irq_enable); } return alltxlen; } static void alt_avalon_spi_hw_tx_data(alt_avalon_spi_dev* dev) { spi_data_buf *pbuf; pbuf = &(dev->tx_data); if(pbuf->datalen==0){ dev->irq_enable &= ~ALTERA_AVALON_SPI_CONTROL_ITRDY_MSK; IOWR_ALTERA_AVALON_SPI_CONTROL(dev->base,dev->irq_enable); ALT_SEM_POST(dev->tx_wait); } else{ if(dev->databits==8){ IOWR_ALTERA_AVALON_SPI_TXDATA(dev->base,pbuf->buf[pbuf->pos]); pbuf->pos = (pbuf->pos+1)%ALT_AVALON_SPI_BUF_LEN; pbuf->datalen--; } else if(dev->databits==16){ IOWR_ALTERA_AVALON_SPI_TXDATA(dev->base,*(alt_u16*)(pbuf->buf+pbuf->pos)); pbuf->pos = (pbuf->pos+2)%ALT_AVALON_SPI_BUF_LEN; pbuf->datalen-=2; } } } /* * Interrupt routine */ static void alt_avalon_spi_hw_rx_data (alt_avalon_spi_dev* dev) { spi_data_buf *pbuf; int copypos; pbuf = &(dev->rx_data); copypos = (pbuf->pos+pbuf->datalen)%ALT_AVALON_SPI_BUF_LEN; if(dev->databits==8){ *(pbuf->buf+copypos) = IORD_ALTERA_AVALON_SPI_RXDATA(dev->base); pbuf->datalen++; } else if(dev->databits==16){ *(alt_u16*)(pbuf->buf+copypos)=IORD_ALTERA_AVALON_SPI_RXDATA(dev->base); pbuf->datalen+=2; } ALT_SEM_POST(dev->rx_wait); } static void alt_avalon_spi_irq(void* context, alt_u32 id) { alt_u16 status; alt_avalon_spi_dev* dev = (alt_avalon_spi_dev*) context; status = IORD_ALTERA_AVALON_SPI_STATUS(dev->base); if(status & ALTERA_AVALON_SPI_STATUS_TRDY_MSK){ alt_avalon_spi_hw_tx_data(dev); } if(status & ALTERA_AVALON_SPI_STATUS_RRDY_MSK){ alt_avalon_spi_hw_rx_data(dev); }# if 0 case ALTERA_AVALON_SPI_STATUS_ROE_MSK: case ALTERA_AVALON_SPI_STATUS_TOE_MSK: case ALTERA_AVALON_SPI_STATUS_TMT_MSK: case ALTERA_AVALON_SPI_STATUS_E_MSK:# endif } int alt_avalon_spi_ioctl (alt_fd* fd, int req, void* arg) { alt_avalon_spi_dev* dev = (alt_avalon_spi_dev*) fd->dev; int rc = -ENOTTY; switch (req) { case SPI_MASTER_IOCTL_SELECT_SLAVE: if(dev->ismaster){ IOWR_ALTERA_AVALON_SPI_SLAVE_SEL(dev->base,1<<(*(alt_u8*)arg)); } break; default: break; } return rc; } /* Driver initialisation code. Register interrupts and start a timer * which we can use to check whether the host is there. */ void alt_avalon_spi_init(alt_avalon_spi_dev* dev, int base, int irq) { ALT_FLAG_CREATE(&dev->events, 0); ALT_SEM_CREATE(&dev->rx_wait, 0); ALT_SEM_CREATE(&dev->tx_wait, 1); memset(&(dev->tx_data),0,sizeof(spi_data_buf)); memset(&(dev->rx_data),0,sizeof(spi_data_buf)); dev->base = (void *)base; /* enable read interrupts at the device */ dev->irq_enable = ALTERA_AVALON_SPI_CONTROL_IRRDY_MSK; IOWR_ALTERA_AVALON_SPI_CONTROL(dev->base,dev->irq_enable); /* register the interrupt handler */ if (alt_irq_register(irq, dev, alt_avalon_spi_irq) >= 0) { /* make the device available to the system */ alt_dev_reg(&dev->dev); } }