?? 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 + -