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

📄 spi.c

📁 vxworks驱动:基于mpc860的spi配置文件及驱动
💻 C
字号:
/* spi driver */#include "vxworks.h"#include "stdio.h"#include "string.h"#include "ctype.h"#include "drv/multi/ppc860Siu.h"#include "drv/multi/ppc860Cpm.h"#include "drv/sio/ppc860Sio.h"#include "arch/ppc/vxPpcLib.h"#include "logLib.h"#include "intLib.h"/* SPI buffer descriptor */typedef struct spi_desc{	VUINT16 statusMode;			/* status and control */	VINT16 dataLength;			/* length of data buffer in bytes */	u_char *dataPointer;		/* points to data buffer */} SPI_DESC;#define BD_SC_EMPTY	((ushort)0x8000)	/* Recieve is empty */#define BD_SC_READY	((ushort)0x8000)	/* Transmit is ready */#define BD_SC_WRAP	((ushort)0x2000)	/* Last buffer descriptor */#define BD_SC_INTRPT	((ushort)0x1000)	/* Interrupt on change */#define BD_SC_LAST	((ushort)0x0800)	/* Last buffer in frame */#define BD_SC_TC	((ushort)0x0400)	/* Transmit CRC */#define BD_SC_CM	((ushort)0x0200)	/* Continous mode */#define BD_SC_ID	((ushort)0x0100)	/* Rec'd too many idles */#define BD_SC_P		((ushort)0x0100)	/* xmt preamble */#define BD_SC_BR	((ushort)0x0020)	/* Break received */#define BD_SC_FR	((ushort)0x0010)	/* Framing error */#define BD_SC_PR	((ushort)0x0008)	/* Parity error */#define BD_SC_OV	((ushort)0x0002)	/* Overrun */#define BD_SC_CD	((ushort)0x0001)	/* Carrier Detect lost *//* SPI parameter RAM. */typedef struct spi_param{	VINT16 spi_rbase;			/* Rx Buffer descriptor base address */	VINT16 spi_tbase;			/* Tx Buffer descriptor base address */	VINT8 spi_rfcr;				/* Rx function code */	VINT8 spi_tfcr;				/* Tx function code */	VINT16 spi_mrblr;			/* Max receive buffer length */	VINT32 spi_rstate;			/* Internal */	VINT32 spi_rdp;				/* Internal */	VINT16 spi_rbptr;			/* Internal */	VINT16 spi_rbc;				/* Internal */	VINT32 spi_rxtmp;			/* Internal */	VINT32 spi_tstate;			/* Internal */	VINT32 spi_tdp;				/* Internal */	VINT16 spi_tbptr;			/* Internal */	VINT16 spi_tbc;				/* Internal */	VINT32 spi_txtmp;			/* Internal */	VINT32 spi_res;	VINT16 spi_rpbase;			/* Relocation pointer */	VINT16 spi_res2;} SPI_PARAM;#define CPM_CR_INIT_TRX		((ushort)0x0000)/* SPI Event/Mask register. */#define SPI_EMASK		0x37	/* Event Mask               */#define SPI_MME			0x20	/* Multi-Master Error           */#define SPI_TXE			0x10	/* Transmit Error           */#define SPI_BSY			0x04	/* Busy                 */#define SPI_TXB			0x02	/* Tx Buffer Empty          */#define SPI_RXB			0x01	/* RX Buffer full/closed        */#define SPI_STR			0x80	/* SPCOM: Start transmit        */#define SPI_EB		((u_char)0x10)	/* big endian byte order *//* tx and rx buffer offset from dpram base */#define MAX_BUFFER	0x104#define SPI_RXBUF_OFFSET 0x810	/* immr + 0x2810 */#define SPI_TXBUF_OFFSET (SPI_RXBUF_OFFSET + MAX_BUFFER)/* tx and rx buffer descriptors offset from dpram base */#define CPM_SPI_BASE 0x800		/* immr + 0x2800 *//* rx & tx buffer */#if 0static u_char rxbuf[MAX_BUFFER];static u_char txbuf[MAX_BUFFER];#elsestatic u_char *rxbuf; static u_char *txbuf;#endif/* debug */int spi_debug = 0;extern int consoleFd;#define	DPRINT(a)	if (spi_debug) logMsg((a));#include "msgQLib.h "MSG_Q_ID spi_msg;/* ----------------------------------------------- * Helper functions to peek into tx and rx buffers * ----------------------------------------------- */static const char * const hex_digit = "0123456789ABCDEF";static char quickhex (int i){	return hex_digit[i];}static void memdump (void *pv, int num){	int i;	unsigned char *pc = (unsigned char *) pv;#if 0       char str[60] = {0};       	for (i = 0; i < num; i++) {            str[i*3] = quickhex (pc[i] >> 4);            str[i*3+1] = quickhex (pc[i] & 0x0f);            str[i*3+2] = ' ';	}            logMsg("%s\n", str, 0,0,0,0,0);    #else        	for (i = 0; i < num; i++) 		printf ("%c%c ", quickhex (pc[i] >> 4), quickhex (pc[i] & 0x0f)); 	printf ("\t");	for (i = 0; i < num; i++)		printf ("%c", isprint (pc[i]) ? pc[i] : '.');	printf ("\n");	/*       char str[60] = {0};    	for (i = 0; i < num; i++) {                sprintf(str, "%c%c ", quickhex (pc[i] >> 4), quickhex (pc[i] & 0x0f));		write (consoleFd, str, 3);     	}	write (consoleFd, "\t", 1);	for (i = 0; i < num; i++) {                        sprintf(str, "%c", isprint (pc[i]) ? pc[i] : '.');		write (consoleFd, 1);	}	write (consoleFd, "\n", 1);*/#endif}void spi_msg_init(void){        char str[16];    spi_msg = msgQCreate(256, 16, 0);     if (spi_msg == NULL) {        printf("create msgq failed!\n");        return;    }        while(1) {        if (msgQReceive(spi_msg, str, 16, -1) < 0) {            printf("msgq recv failed!\n");            return;        } else {                memdump((void *)str, 16);                printf("\n");        }    }}extern void udelay (unsigned long usec);void spi_init (void){	unsigned int dpaddr;	SPI_PARAM *spi;	VINT32 regBase = vxImmrGet ();	volatile SPI_DESC *tbdf, *rbdf;	spi = (SPI_PARAM *) ((UINT32)		PPC860_DPR_SPI (MPC860_DPRAM_BASE (regBase)));			rxbuf = (u_char *)(MPC860_DPRAM_BASE (regBase) + SPI_RXBUF_OFFSET);		txbuf = (u_char *)(MPC860_DPRAM_BASE (regBase) + SPI_TXBUF_OFFSET);		/* Disable relocation *//*	spi->spi_rpbase = 0x00;  */	/* 1+2 */	/* ------------------------------------------------	 * Initialize Port B SPI pins	 * (we are only in Master Mode !)	 * ------------------------------------------------ */	/* --------------------------------------------	 * GPIO or per. Function	 * PBPAR[28] = 1 [0x00000008] -> PERI: (SPIMISO)	 * PBPAR[29] = 1 [0x00000004] -> PERI: (SPIMOSI)	 * PBPAR[30] = 1 [0x00000002] -> PERI: (SPICLK)	 * PBPAR[31] = 0 [0x00000001] -> GPIO: (CS for SLIC)	 * -------------------------------------------- */	*MPC860_PBPAR (regBase) |= 0x0000000E;	/* set  bits    */	*MPC860_PBPAR (regBase) &= ~0x00000001;	/* reset bit    */	/* ----------------------------------------------	 * In/Out or per. Function 0/1	 * PBDIR[28] = 1 [0x00000008] -> PERI1: SPIMISO	 * PBDIR[29] = 1 [0x00000004] -> PERI1: SPIMOSI	 * PBDIR[30] = 1 [0x00000002] -> PERI1: SPICLK	 * PBDIR[31] = 1 [0x00000001] -> GPIO OUT: CS for SLIC	 * ---------------------------------------------- */	*MPC860_PBDIR (regBase) |= 0x0000000F;	/* ----------------------------------------------	 * open drain or active output	 * PBODR[28] = 1 [0x00000008] -> open drain: SPIMISO	 * PBODR[29] = 0 [0x00000004] -> active output SPIMOSI	 * PBODR[30] = 0 [0x00000002] -> active output: SPICLK	 * PBODR[31] = 0 [0x00000001] -> active output: GPIO OUT: CS for SLIC	 * ---------------------------------------------- *//*	*MPC860_PBODR (regBase) |= 0x00000008; */	*MPC860_PBODR (regBase) &= ~0x0000000f;	/* Initialize the parameter ram.	 * We need to make sure many things are initialized to zero	 */	spi->spi_rstate = 0;	spi->spi_rdp = 0;	spi->spi_rbptr = 0;	spi->spi_rbc = 0;	spi->spi_rxtmp = 0;	spi->spi_tstate = 0;	spi->spi_tdp = 0;	spi->spi_tbptr = 0;	spi->spi_tbc = 0;	spi->spi_txtmp = 0;	/* Allocate space for one transmit and one receive buffer	 * descriptor in the DP ram	 */	dpaddr = CPM_SPI_BASE;	/* 3 */	/* Set up the SPI parameters in the parameter ram */	spi->spi_rbase = dpaddr;	spi->spi_tbase = dpaddr + sizeof (SPI_DESC);	/***********IMPORTANT******************/	/*	 * Setting transmit and receive buffer descriptor pointers	 * initially to rbase and tbase. Only the microcode patches	 * documentation talks about initializing this pointer. This	 * is missing from the sample I2C driver. If you dont	 * initialize these pointers, the kernel hangs.	 */	spi->spi_rbptr = spi->spi_rbase;	spi->spi_tbptr = spi->spi_tbase;	/* 4 */	/* Init SPI Tx + Rx Parameters */	while (*CPCR (regBase) & CPM_CR_FLG);	*CPCR (regBase) = (CPM_CR_CHANNEL_SPI | CPM_CR_INIT_TRX) | CPM_CR_FLG;	while (*CPCR (regBase) & CPM_CR_FLG);	/* 5 */	/* Set SDMA configuration register */	*SDCR (regBase) = 0x0001;	/* 6 */	/* Set to big endian. */	spi->spi_tfcr = SPI_EB;	spi->spi_rfcr = SPI_EB;	/* 7 */	/* Set maximum receive size. */	spi->spi_mrblr = MAX_BUFFER;	/* 8 + 9 */	/* tx and rx buffer descriptors */	tbdf = (SPI_DESC *) (MPC860_DPRAM_BASE (regBase) + spi->spi_tbase);	rbdf = (SPI_DESC *) (MPC860_DPRAM_BASE (regBase) + spi->spi_rbase);	tbdf->statusMode &= ~BD_SC_READY;	rbdf->statusMode &= ~BD_SC_EMPTY;	/* Set the bd's rx and tx buffer address pointers */	rbdf->dataPointer = (u_char *) rxbuf;	tbdf->dataPointer = (u_char *) txbuf;	/* 10 + 11 */	*SPIM (regBase) = 0;		/* Mask  all SPI events */	*SPIE (regBase) = SPI_EMASK;	/* Clear all SPI events */	return;}ssize_t spi_xfer (size_t count){	SPI_PARAM *spi;	VINT32 regBase = vxImmrGet ();	volatile SPI_DESC *tbdf, *rbdf;	int loop, tm;	spi = (SPI_PARAM *) ((UINT32)		PPC860_DPR_SPI (MPC860_DPRAM_BASE (regBase)));	/* Disable relocation *//*	spi->spi_rpbase = 0x00;  */	tbdf = (SPI_DESC *) (MPC860_DPRAM_BASE (regBase) + spi->spi_tbase);	rbdf = (SPI_DESC *) (MPC860_DPRAM_BASE (regBase) + spi->spi_rbase);	/* Set CS for device */	*MPC860_PBDAT (regBase) &= ~0x0001;	/* Setting tx bd status and data length */	tbdf->statusMode = BD_SC_READY | BD_SC_LAST | BD_SC_WRAP /*| BD_SC_INTRPT */;	tbdf->dataLength = count;        if (spi_debug) {            /*            logMsg("*** spi_xfer: Bytes to be xferred: %d ***\n",			(int) tbdf->dataLength, 0,0,0,0,0);*/			        }	/* Setting rx bd status and data length */	rbdf->statusMode = BD_SC_EMPTY | BD_SC_WRAP/* | BD_SC_INTRPT*/;	rbdf->dataLength = 0;		/* rx length has no significance */	loop = *SPMODE(regBase);	*SPMODE (regBase) =	loop |/*SPMODE_DIV16   | */		SPMODE_REV | SPMODE_MS | /*SPMODE_EN |*/ SPMODE_LEN_8_BITS 		| SPMODE_PM_DIV36 /*| SPMODE_CP_BEGIN | SPMODE_CI_HIGH*/;		/* medium speed */	*SPMODE (regBase) |= SPMODE_EN;		*SPIM (regBase) = 0;		/* Mask  all SPI events */	*SPIE (regBase) = SPI_EMASK;	/* Clear all SPI events */	/* start spi transfer */	*SPCOM (regBase) |= SPI_STR;	/* Start transmit */	/* --------------------------------	 * Wait for SPI transmit to get out	 * or time out (1 second = 1000 ms)	 * -------------------------------- */	for (tm = 0; tm < 1000; ++tm) {#if 0				if (*SPIE (regBase) & SPI_TXB) {	/* Tx Buffer Empty */			DPRINT (("*** spi_xfer: Tx buffer empty\n"));			break;		}		if ((tbdf->statusMode & BD_SC_READY) == 0) {			DPRINT (("*** spi_xfer: Tx BD done\n"));			break;		}#else		if ((rbdf->statusMode & BD_SC_EMPTY) == 0) {                    break;		}#endif		udelay(1000);	}	if (tm >= 1000) {		logMsg ("*** spi_xfer: Time out while xferring to/from SPI!\n", 0,0,0,0,0,0);	}#if 1	if (spi_debug) {              char str[16] = {0};              memcpy(str, txbuf, 16);              msgQSend(spi_msg, str, 16, 0,0);              memcpy(str, rxbuf, 16);              msgQSend(spi_msg, str, 16, 0,0);              #if 0              		memdump ((void *) txbuf, 16);	/* dump of txbuf before transmit */		memdump ((void *) rxbuf, 16);	/* dump of rxbuf after transmit */#endif        	}#endif	/* Clear CS for device */	*MPC860_PBDAT (regBase) |= 0x0001;	return count;}int codec_xfer(unsigned char *wrbuf, unsigned char *rdbuf, int len){        int old;    	if (len > MAX_BUFFER) return -1;       old = intLock(); 	memset (rxbuf, 0, MAX_BUFFER);	memset (txbuf, 0, MAX_BUFFER);	memcpy (txbuf, wrbuf, len);	spi_xfer (len);	memcpy(rdbuf, rxbuf, len);        intUnlock(old); 	return 0;}/* * SPI test * * The Serial Peripheral Interface (SPI) is tested in the local loopback mode. * The interface is configured accordingly and several packets * are transfered. The configurable test parameters are: *   TEST_MIN_LENGTH - minimum size of packet to transfer *   TEST_MAX_LENGTH - maximum size of packet to transfer *   TEST_NUM - number of tests */#define TEST_MIN_LENGTH		1#define TEST_MAX_LENGTH		MAX_BUFFER#define TEST_NUM		1static void packet_fill (char *packet, int length){	char c = (char) length;	int i;	for (i = 0; i < length; i++) {		packet[i] = c++;	}}static int packet_check (char *packet, int length){	char c = (char) length;	int i;	for (i = 0; i < length; i++) {		if (packet[i] != c++)			return -1;	}	return 0;}int spi_post_test (int loop){	int res = -1;	int i;	int l;	VINT32 regBase = vxImmrGet ();	spi_init ();	if (loop) {		printf("use loop mode\n");		*SPMODE (regBase) |= SPMODE_LOOP;	}	for (i = 0; i < TEST_NUM; i++) {		for (l = TEST_MIN_LENGTH; l <= TEST_MAX_LENGTH; l += 8) {			packet_fill (txbuf, l);			spi_xfer (l);			if (packet_check (rxbuf, l) < 0) {				goto Done;			}		}	}	res = 0;  Done:	*SPMODE (regBase) &= ~SPMODE_LOOP;	if (res != 0) {		printf ("SPI test failed\n");	}	return res;}void codec_reset(void){	txbuf[0] = 0x40;	spi_xfer(1);}void codec_read(int reg, char off){#if 1	char str[15];	char buf[15];	int i;	/*	spi_init (); */	str[0] = reg;	str[1] = off;		codec_xfer(str, buf, 12);		for (i = 0; i < 15; i++)		printf("%x ", buf[i]);	printf("\n");	#else	spi_init();	txbuf[0] = 0xc4;	txbuf[1] = off;	spi_xfer(12);#endif	}void codec_write(int reg, char off, int val){#if 1	char str[15];	char buf[15];	int i;	/*	spi_init (); */	str[0] = reg;	str[1] = off;       str[2] = val;		codec_xfer(str, buf, 12);		for (i = 0; i < 15; i++)		printf("%x ", buf[i]);	printf("\n");#else	spi_init();	txbuf[0] = 0xc4;	txbuf[1] = off;	spi_xfer(12);#endif	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -