summaryrefslogtreecommitdiffstats
path: root/shared/opensource/spi
diff options
context:
space:
mode:
authorroot <root@lamia.panaceas.james.local>2015-12-19 13:13:57 +0000
committerroot <root@lamia.panaceas.james.local>2015-12-19 14:18:03 +0000
commit1a2238d1bddc823df06f67312d96ccf9de2893cc (patch)
treec58a3944d674a667f133ea5a730f5037e57d3d2e /shared/opensource/spi
downloadbootloader-1a2238d1bddc823df06f67312d96ccf9de2893cc.tar.gz
bootloader-1a2238d1bddc823df06f67312d96ccf9de2893cc.tar.bz2
bootloader-1a2238d1bddc823df06f67312d96ccf9de2893cc.zip
CFE from danitool [without hostTools dir]: https://mega.nz/#!mwZyFK7a!CPT3BKC8dEw29kubtdYxhB91G9vIIismTkgzQ3iUy3k
Diffstat (limited to 'shared/opensource/spi')
-rwxr-xr-xshared/opensource/spi/Makefile30
-rwxr-xr-xshared/opensource/spi/bcmHsSpi.c898
-rwxr-xr-xshared/opensource/spi/bcmLegSpi.c774
-rwxr-xr-xshared/opensource/spi/bcmSpiRes.c660
4 files changed, 2362 insertions, 0 deletions
diff --git a/shared/opensource/spi/Makefile b/shared/opensource/spi/Makefile
new file mode 100755
index 0000000..b3eb2b1
--- /dev/null
+++ b/shared/opensource/spi/Makefile
@@ -0,0 +1,30 @@
+
+ifeq ($(CONFIG_MIPS_BRCM),y)
+
+ifeq ($(strip $(BRCM_CHIP)),6362)
+obj-y += \
+ bcmHsSpi.o
+else
+ifeq ($(strip $(BRCM_CHIP)),6816)
+obj-y += \
+ bcmHsSpi.o
+else
+ifeq ($(strip $(BRCM_CHIP)),6328)
+obj-y += \
+ bcmHsSpi.o
+endif
+endif
+endif
+
+ifneq ($(strip $(BRCM_CHIP)),6328)
+obj-y += \
+ bcmLegSpi.o
+endif
+
+obj-y += \
+ bcmSpiRes.o
+
+EXTRA_CFLAGS += -DCONFIG_BCM9$(BRCM_CHIP) -I$(INC_BRCMDRIVER_PUB_PATH)/$(BRCM_BOARD) -I$(INC_BRCMSHARED_PUB_PATH)/$(BRCM_BOARD)
+
+endif
+
diff --git a/shared/opensource/spi/bcmHsSpi.c b/shared/opensource/spi/bcmHsSpi.c
new file mode 100755
index 0000000..b32e9fc
--- /dev/null
+++ b/shared/opensource/spi/bcmHsSpi.c
@@ -0,0 +1,898 @@
+/*
+ Copyright 2000-2010 Broadcom Corporation
+
+ Unless you and Broadcom execute a separate written software license
+ agreement governing use of this software, this software is licensed
+ to you under the terms of the GNU General Public License version 2
+ (the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
+ with the following added to such license:
+
+ As a special exception, the copyright holders of this software give
+ you permission to link this software with independent modules, and to
+ copy and distribute the resulting executable under terms of your
+ choice, provided that you also meet, for each linked independent
+ module, the terms and conditions of the license of that module.
+ An independent module is a module which is not derived from this
+ software. The special exception does not apply to any modifications
+ of the software.
+
+ Notwithstanding the above, under no circumstances may you combine this
+ software in any way with any other Broadcom software provided under a
+ license other than the GPL, without Broadcom's express prior written
+ consent.
+*/
+
+#ifdef _CFE_
+#include "lib_types.h"
+#include "lib_printf.h"
+#include "lib_string.h"
+#include "bcm_map.h"
+#define printk printf
+#else
+#include <linux/autoconf.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/spi/spi.h>
+
+#include <bcm_map_part.h>
+#include <bcm_intr.h>
+#endif
+
+/* if HS_SPI is defined then the HS SPI controller is available, otherwise do not compile this code */
+
+#ifdef HS_SPI
+
+#include "bcmSpiRes.h"
+#include "bcmSpi.h"
+
+int BcmHsSpiRead(unsigned char * msg_buf, int prependcnt, int nbytes, int devId, int freqHz);
+int BcmHsSpiWrite(unsigned char * msg_buf, int nbytes, int devId, int freqHz);
+
+#define HS_SPI_STATE_CLOCK_POLARITY (1 << 31)
+#define HS_SPI_STATE_GATE_CLOCK_SSOFF (1 << 30)
+#define HS_SPI_STATE_LAUNCH_RISING (1 << 29)
+#define HS_SPI_STATE_LATCH_RISING (1 << 28)
+#define HS_SPI_STATE_ASYNC_CLOCK (1 << 27)
+#if defined(_BCM96816_) || defined(CONFIG_BCM96816)
+#define HS_SPI_CONTROLLER_STATE_DEF (HS_SPI_STATE_GATE_CLOCK_SSOFF)
+#endif
+#if defined(_BCM96328_) || defined(CONFIG_BCM96328)
+#define HS_SPI_CONTROLLER_STATE_DEF (HS_SPI_STATE_GATE_CLOCK_SSOFF | HS_SPI_STATE_LATCH_RISING)
+#endif
+#if defined(_BCM96362_) || defined(CONFIG_BCM96362)
+#define HS_SPI_CONTROLLER_STATE_DEF (HS_SPI_STATE_GATE_CLOCK_SSOFF | HS_SPI_STATE_LATCH_RISING | HS_SPI_STATE_ASYNC_CLOCK)
+#endif
+
+
+#ifndef _CFE_
+//#define HS_SPI_USE_INTERRUPTS /* define this to use interrupts instead of polling */
+static struct bcmspi BcmHsSpi = { SPIN_LOCK_UNLOCKED,
+ "bcmHsSpiDev",
+ };
+#else
+#define udelay(X) \
+ do { { int i; for( i = 0; i < (X) * 500; i++ ) ; } } while(0)
+#endif
+
+static int hsSpiRead( unsigned char *pRxBuf, int prependcnt, int nbytes, int devId )
+{
+ uint16 msgCtrl;
+
+ HS_SPI_PROFILES[devId].mode_ctrl = prependcnt<<HS_SPI_PREPENDBYTE_CNT | 0<<HS_SPI_MODE_ONE_WIRE |
+ 0<<HS_SPI_MULTIDATA_WR_SIZE | 0<<HS_SPI_MULTIDATA_RD_SIZE | 2<<HS_SPI_MULTIDATA_WR_STRT |
+ 2<<HS_SPI_MULTIDATA_RD_STRT | 0xff<<HS_SPI_FILLBYTE;
+
+ msgCtrl = (HS_SPI_OP_READ<<HS_SPI_OP_CODE) | nbytes;
+ memcpy((char *)HS_SPI_FIFO0, (void *)(&msgCtrl), 2);
+
+ if ( 0 != prependcnt )
+ {
+ memcpy((char *)(HS_SPI_FIFO0+2), (char *)pRxBuf, prependcnt);
+ }
+
+ HS_SPI_PINGPONG0->command = devId<<HS_SPI_SS_NUM | devId<<HS_SPI_PROFILE_NUM | 0<<HS_SPI_TRIGGER_NUM |
+ HS_SPI_COMMAND_START_NOW<<HS_SPI_COMMAND_VALUE;
+
+ return SPI_STATUS_OK;
+
+}
+
+static int hsSpiWriteFull( unsigned char *pTxBuf, int nbytes, int devId, int opcode )
+{
+ uint16 msgCtrl;
+
+ HS_SPI_PROFILES[devId].mode_ctrl = 0<<HS_SPI_PREPENDBYTE_CNT | 0<<HS_SPI_MODE_ONE_WIRE |
+ 0<<HS_SPI_MULTIDATA_WR_SIZE | 0<<HS_SPI_MULTIDATA_RD_SIZE | 2<<HS_SPI_MULTIDATA_WR_STRT |
+ 2<<HS_SPI_MULTIDATA_RD_STRT | 0xff<<HS_SPI_FILLBYTE;
+
+ if (BCM_SPI_FULL == opcode)
+ {
+ msgCtrl = (HS_SPI_OP_READ_WRITE<<HS_SPI_OP_CODE) | nbytes;
+ }
+ else
+ {
+ msgCtrl = (HS_SPI_OP_WRITE<<HS_SPI_OP_CODE) | nbytes;
+ }
+ memcpy((char *)HS_SPI_FIFO0, (void *)(&msgCtrl), 2);
+ memcpy((char *)(HS_SPI_FIFO0+2), (void *)pTxBuf, nbytes);
+
+ HS_SPI_PINGPONG0->command = devId<<HS_SPI_SS_NUM | devId<<HS_SPI_PROFILE_NUM | 0<<HS_SPI_TRIGGER_NUM |
+ HS_SPI_COMMAND_START_NOW<<HS_SPI_COMMAND_VALUE;
+
+ return SPI_STATUS_OK;
+
+}
+
+static int hsSpiTransEnd( unsigned char *rxBuf, int nbytes )
+{
+ if ( NULL != rxBuf )
+ {
+ memcpy((char *)rxBuf, (void *)HS_SPI_FIFO0, nbytes);
+ }
+
+ return SPI_STATUS_OK;
+
+}
+
+static int hsSpiTransPoll(void)
+{
+ unsigned int wait;
+
+ for (wait = (100*1000); wait>0; wait--)
+ {
+ if (!(HS_SPI_PINGPONG0->status & 1<<HS_SPI_SOURCE_BUSY ))
+ {
+ break;
+ }
+ udelay(1);
+ }
+
+ if (wait == 0)
+ {
+ return SPI_STATUS_ERR;
+ }
+
+ return SPI_STATUS_OK;
+}
+
+
+static void hsSpiClearIntStatus(void)
+{
+ HS_SPI->hs_spiIntStatus = HS_SPI_INTR_CLEAR_ALL;
+}
+
+#ifdef HS_SPI_USE_INTERRUPTS
+static void hsSpiEnableInt(bool bEnable)
+{
+ if ( bEnable )
+ {
+ HS_SPI->hs_spiIntMask = HS_SPI_IRQ_PING0_CMD_DONE;
+ }
+ else
+ {
+ HS_SPI->hs_spiIntMask = 0;
+ }
+}
+#endif
+
+#ifndef _CFE_
+static int hsSpiSetClock( int clockHz, int profile )
+{
+ int clock;
+
+ clock = HS_SPI_PLL_FREQ/clockHz;
+ if (HS_SPI_PLL_FREQ%HS_SPI_CLOCK_DEF)
+ clock++;
+
+ clock = 2048/clock;
+ if (2048%(clock))
+ clock++;
+
+ HS_SPI_PROFILES[profile].clk_ctrl = 1<<HS_SPI_ACCUM_RST_ON_LOOP | 0<<HS_SPI_SPI_CLK_2X_SEL | clock<<HS_SPI_FREQ_CTRL_WORD;
+
+ return SPI_STATUS_OK;
+}
+
+static void hsSpiSetControllerState(unsigned int ctrlState, unsigned char devId)
+{
+ unsigned int temp32;
+
+ temp32 = HS_SPI->hs_spiGlobalCtrl;
+ if ( 0 == (ctrlState & HS_SPI_STATE_GATE_CLOCK_SSOFF) )
+ {
+ temp32 &= ~HS_SPI_CLK_GATE_SSOFF;
+ }
+ else
+ {
+ temp32 |= HS_SPI_CLK_GATE_SSOFF;
+ }
+#if defined(_BCM96328_) || defined(CONFIG_BCM96328) || defined(_BCM96362_) || defined(CONFIG_BCM96362)
+ if ( 0 == (ctrlState & HS_SPI_STATE_CLOCK_POLARITY) )
+ {
+ temp32 &= ~HS_SPI_CLK_POLARITY;
+ }
+ else
+ {
+ temp32 |= HS_SPI_CLK_POLARITY;
+ }
+#endif
+ /* write value if required */
+ if ( temp32 != HS_SPI->hs_spiGlobalCtrl )
+ {
+ HS_SPI->hs_spiGlobalCtrl = temp32;
+ }
+
+ temp32 = HS_SPI_PROFILES[devId].signal_ctrl;
+ if ( 0 == (ctrlState & HS_SPI_STATE_LATCH_RISING) )
+ {
+ temp32 &= ~HS_SPI_LATCH_RISING;
+ }
+ else
+ {
+ temp32 |= HS_SPI_LATCH_RISING;
+ }
+ if ( 0 == (ctrlState & HS_SPI_STATE_LAUNCH_RISING) )
+ {
+ temp32 &= ~HS_SPI_LAUNCH_RISING;
+ }
+ else
+ {
+ temp32 |= HS_SPI_LAUNCH_RISING;
+ }
+
+#if defined(_BCM96328_) || defined(CONFIG_BCM96328) || defined(_BCM96362_) || defined(CONFIG_BCM96362)
+ if ( 0 == (ctrlState & HS_SPI_STATE_ASYNC_CLOCK) )
+ {
+ temp32 &= ~HS_SPI_ASYNC_INPUT_PATH;
+ }
+ else
+ {
+ temp32 |= HS_SPI_ASYNC_INPUT_PATH;
+ }
+#endif
+
+ /* write value if required */
+ if ( temp32 != HS_SPI_PROFILES[devId].signal_ctrl )
+ {
+ HS_SPI_PROFILES[devId].signal_ctrl = temp32;
+ }
+
+}
+#endif
+
+/* these interfaces are availble for the CFE and spi flash driver only
+ all modules must use the linux kernel framework
+ if this is called by a module and interrupts are being used there will
+ be a problem */
+int BcmHsSpiRead( unsigned char *msg_buf, int prependcnt, int nbytes, int devId, int freqHz )
+{
+#ifndef _CFE_
+ struct bcmspi *pBcmSpi = &BcmHsSpi;
+
+ if ( pBcmSpi->irq )
+ {
+ printk("BcmHsSpiRead error - Interrupts are enabled\n");
+ return( SPI_STATUS_ERR );
+ }
+
+ spin_lock(&pBcmSpi->lock);
+ hsSpiSetControllerState(HS_SPI_CONTROLLER_STATE_DEF, devId);
+ hsSpiSetClock(freqHz, devId);
+#endif
+ hsSpiClearIntStatus();
+ hsSpiRead(msg_buf, prependcnt, nbytes, devId);
+ hsSpiTransPoll();
+ hsSpiTransEnd(msg_buf, nbytes);
+ hsSpiClearIntStatus();
+#ifndef _CFE_
+ spin_unlock(&pBcmSpi->lock);
+#endif
+
+ return( SPI_STATUS_OK );
+}
+
+int BcmHsSpiWrite( unsigned char *msg_buf, int nbytes, int devId, int freqHz )
+{
+#ifndef _CFE_
+ struct bcmspi *pBcmSpi = &BcmHsSpi;
+
+ if ( pBcmSpi->irq )
+ {
+ printk("BcmHsSpiWrite error - Interrupts are enabled\n");
+ return( SPI_STATUS_ERR );
+ }
+
+ spin_lock(&pBcmSpi->lock);
+ hsSpiSetControllerState(HS_SPI_CONTROLLER_STATE_DEF, devId);
+ hsSpiSetClock(freqHz, devId);
+#endif
+ hsSpiClearIntStatus();
+ hsSpiWriteFull(msg_buf, nbytes, devId, BCM_SPI_WRITE);
+ hsSpiTransPoll();
+ hsSpiTransEnd(msg_buf, nbytes);
+ hsSpiClearIntStatus();
+#ifndef _CFE_
+ spin_unlock(&pBcmSpi->lock);
+#endif
+
+ return( SPI_STATUS_OK );
+}
+
+
+#ifndef _CFE_
+static void hsSpiNextMessage(struct bcmspi *pBcmSpi);
+
+static void hsSpiMsgDone(struct bcmspi *pBcmSpi, struct spi_message *msg, int status)
+{
+ list_del(&msg->queue);
+ msg->status = status;
+
+ spin_unlock(&pBcmSpi->lock);
+ msg->complete(msg->context);
+ spin_lock(&pBcmSpi->lock);
+
+ pBcmSpi->curTrans = NULL;
+
+ /* continue if needed */
+ if (list_empty(&pBcmSpi->queue) || pBcmSpi->stopping)
+ {
+ // disable controler ...
+ }
+ else
+ {
+ hsSpiNextMessage(pBcmSpi);
+ }
+}
+
+#ifdef HS_SPI_USE_INTERRUPTS
+static void hsSpiIntXfer(struct bcmspi *pBcmSpi, struct spi_message *msg)
+{
+ struct spi_transfer *xfer;
+ struct spi_transfer *nextXfer;
+ int length;
+ int prependCnt;
+ char *pTxBuf;
+ char *pRxBuf;
+ int opCode;
+
+ xfer = pBcmSpi->curTrans;
+ if ( NULL == xfer)
+ {
+ xfer = list_entry(msg->transfers.next, struct spi_transfer, transfer_list);
+ }
+ else
+ {
+ xfer = list_entry(xfer->transfer_list.next, struct spi_transfer, transfer_list);
+ }
+ pBcmSpi->curTrans = xfer;
+
+ length = xfer->len;
+ prependCnt = 0;
+ pRxBuf = xfer->rx_buf;
+ pTxBuf = (unsigned char *)xfer->tx_buf;
+
+ if ( (NULL != pRxBuf) && (NULL != pTxBuf) )
+ {
+ opCode = BCM_SPI_FULL;
+ }
+ else if ( NULL != pRxBuf )
+ {
+ opCode = BCM_SPI_READ;
+ }
+ else
+ {
+ opCode = BCM_SPI_WRITE;
+ }
+
+ if ( msg->state )
+ {
+ /* this controller does not support keeping the chip select active for all transfers
+ non NULL state indicates that we need to combine the transfers */
+ nextXfer = list_entry(xfer->transfer_list.next, struct spi_transfer, transfer_list);
+ prependCnt = length;
+ length = nextXfer->len;
+ pRxBuf = nextXfer->rx_buf;
+ opCode = BCM_SPI_READ;
+ pBcmSpi->curTrans = nextXfer;
+ }
+
+ hsSpiSetClock(xfer->speed_hz, msg->spi->chip_select);
+
+ hsSpiClearIntStatus();
+ hsSpiEnableInt(TRUE);
+ if ( BCM_SPI_READ == opCode )
+ {
+ hsSpiRead(pTxBuf, prependCnt, length, msg->spi->chip_select);
+ }
+ else
+ {
+ hsSpiWriteFull(pTxBuf, length, msg->spi->chip_select, opCode);
+ }
+
+ return;
+
+}
+#endif
+
+static void hsSpiPollXfer(struct bcmspi *pBcmSpi, struct spi_message *msg)
+{
+ struct spi_transfer *xfer;
+ struct spi_transfer *nextXfer;
+ int length;
+ int prependCnt;
+ char *pTxBuf;
+ char *pRxBuf;
+ int opCode;
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list)
+ {
+ pBcmSpi->curTrans = xfer;
+ length = xfer->len;
+ prependCnt = 0;
+ pRxBuf = xfer->rx_buf;
+ pTxBuf = (unsigned char *)xfer->tx_buf;
+
+ if ( (NULL != pRxBuf) && (NULL != pTxBuf) )
+ {
+ opCode = BCM_SPI_FULL;
+ }
+ else if ( NULL != pRxBuf )
+ {
+ opCode = BCM_SPI_READ;
+ }
+ else
+ {
+ opCode = BCM_SPI_WRITE;
+ }
+
+ if ( msg->state )
+ {
+ /* this controller does not support keeping the chip select active for all transfers
+ non NULL state indicates that we need to combine the transfers */
+ nextXfer = list_entry(xfer->transfer_list.next, struct spi_transfer, transfer_list);
+ prependCnt = length;
+ length = nextXfer->len;
+ pRxBuf = nextXfer->rx_buf;
+ opCode = BCM_SPI_READ;
+ xfer = nextXfer;
+ }
+
+ hsSpiSetClock(xfer->speed_hz, msg->spi->chip_select);
+
+ hsSpiClearIntStatus();
+ if ( BCM_SPI_READ == opCode )
+ {
+ hsSpiRead(pTxBuf, prependCnt, length, msg->spi->chip_select);
+ }
+ else
+ {
+ hsSpiWriteFull(pTxBuf, length, msg->spi->chip_select, opCode);
+ }
+
+ hsSpiTransPoll();
+ hsSpiTransEnd(pRxBuf, length);
+ hsSpiClearIntStatus();
+
+ if (xfer->delay_usecs)
+ {
+ udelay(xfer->delay_usecs);
+ }
+
+ msg->actual_length += length;
+ }
+
+ hsSpiMsgDone(pBcmSpi, msg, SPI_STATUS_OK);
+
+}
+
+
+static void hsSpiNextXfer(struct bcmspi *pBcmSpi, struct spi_message *msg)
+{
+#ifdef HS_SPI_USE_INTERRUPTS
+ if (pBcmSpi->irq)
+ hsSpiIntXfer(pBcmSpi, msg);
+ else
+#endif
+ hsSpiPollXfer(pBcmSpi, msg);
+}
+
+static void hsSpiNextMessage(struct bcmspi *pBcmSpi)
+{
+ struct spi_message *msg;
+ unsigned int ctrlState;
+
+ BUG_ON(pBcmSpi->curTrans);
+
+ msg = list_entry(pBcmSpi->queue.next, struct spi_message, queue);
+
+ /* set the controller state for this message */
+ ctrlState = (unsigned int)spi_get_ctldata(msg->spi);
+ hsSpiSetControllerState(ctrlState, msg->spi->chip_select);
+
+ /* there will always be one transfer in a given message */
+ hsSpiNextXfer(pBcmSpi, msg);
+
+}
+
+
+static int hsSpiSetup(struct spi_device *spi)
+{
+ struct bcmspi *pBcmSpi;
+ unsigned int spiCtrlData;
+ unsigned int spiCtrlState = 0;
+
+ pBcmSpi = spi_master_get_devdata(spi->master);
+
+ if (pBcmSpi->stopping)
+ return -ESHUTDOWN;
+
+ spiCtrlData = (unsigned int)spi->controller_data;
+ if ( 0 == spiCtrlData )
+ {
+ spiCtrlState = HS_SPI_CONTROLLER_STATE_DEF;
+ }
+ else
+ {
+ spiCtrlState = 0;
+ /* note that in HW, the meaning of latch and launch bits changes when CPOl = 1 */
+ if ( (0 == (spi->mode & SPI_CPHA)) &&
+ (0 == (spiCtrlData & SPI_CONTROLLER_STATE_CPHA_EXT)) )
+ {
+ /* latch rising, launch falling */
+ spiCtrlState = HS_SPI_STATE_LATCH_RISING;
+ }
+ else if ( (0 == (spi->mode & SPI_CPHA)) &&
+ (0 != (spiCtrlData & SPI_CONTROLLER_STATE_CPHA_EXT)) )
+ {
+ /* latch rising, launch rising */
+ spiCtrlState = HS_SPI_STATE_LATCH_RISING | HS_SPI_STATE_LAUNCH_RISING;
+ }
+ else if ( (0 != (spi->mode & SPI_CPHA)) &&
+ (0 == (spiCtrlData & SPI_CONTROLLER_STATE_CPHA_EXT)) )
+ {
+ /* latch falling, launch rising */
+ spiCtrlState = HS_SPI_STATE_LAUNCH_RISING;
+ }
+ // else - both set to 0, latch falling, launch falling
+
+ if ( 0 != (spi->mode & SPI_CPOL) )
+ {
+ spiCtrlState |= HS_SPI_STATE_CLOCK_POLARITY;
+ }
+
+ if ( spiCtrlData & SPI_CONTROLLER_STATE_GATE_CLK_SSOFF )
+ {
+ spiCtrlState |= HS_SPI_STATE_GATE_CLOCK_SSOFF;
+ }
+
+ if ( spiCtrlData & SPI_CONTROLLER_STATE_ASYNC_CLOCK )
+ {
+ spiCtrlState |= HS_SPI_STATE_ASYNC_CLOCK;
+ }
+ }
+
+ spi_set_ctldata(spi, (void *)spiCtrlState);
+
+ return 0;
+}
+
+
+static int hsSpiTransfer(struct spi_device *spi, struct spi_message *msg)
+{
+ struct bcmspi *pBcmSpi = &BcmHsSpi;
+ struct spi_transfer *xfer;
+ struct spi_transfer *nextXfer;
+ int xferCnt;
+ int bCsChange;
+ int xferLen;
+
+ if (unlikely(list_empty(&msg->transfers)))
+ return -EINVAL;
+
+ if (pBcmSpi->stopping)
+ return -ESHUTDOWN;
+
+ /* make sure a completion callback is set */
+ if ( NULL == msg->complete )
+ {
+ return -EINVAL;
+ }
+
+ xferCnt = 0;
+ bCsChange = 0;
+ xferLen = 0;
+ list_for_each_entry(xfer, &msg->transfers, transfer_list)
+ {
+ /* check transfer parameters */
+ if (!(xfer->tx_buf || xfer->rx_buf))
+ {
+ return -EINVAL;
+ }
+
+ /* check the clock setting - if it is 0 then set to max clock of the device */
+ if ( 0 == xfer->speed_hz )
+ {
+ if ( 0 == spi->max_speed_hz )
+ {
+ return -EINVAL;
+ }
+ xfer->speed_hz = spi->max_speed_hz;
+ }
+
+ xferCnt++;
+ xferLen += xfer->len;
+ bCsChange |= xfer->cs_change;
+
+ if ( xfer->len > HS_SPI_BUFFER_LEN )
+ {
+ return -EINVAL;
+ }
+ }
+
+ /* this controller does not support keeping the chip select active between
+ transfers. If a message is detected with a write transfer followed by a
+ read transfer and cs_change is set to 0 then the two transfers need to be
+ combined. The message state is used to indicate that the transfers
+ need to be combined */
+ msg->state = NULL;
+ if ( (2 == xferCnt) && (0 == bCsChange) )
+ {
+ xfer = list_entry(msg->transfers.next, struct spi_transfer, transfer_list);
+ if ( (NULL != xfer->tx_buf) && (NULL == xfer->rx_buf))
+ {
+ nextXfer = list_entry(xfer->transfer_list.next, struct spi_transfer, transfer_list);;
+ if ( (NULL == nextXfer->tx_buf) && (NULL != nextXfer->rx_buf))
+ {
+ msg->state = (void *)1;
+ }
+ }
+ }
+
+ msg->status = -EINPROGRESS;
+ msg->actual_length = 0;
+
+#ifdef HS_SPI_USE_INTERRUPTS
+ /* disable interrupts for the SPI controller
+ using spin_lock_irqsave would disable all interrupts */
+ if ( pBcmSpi->irq )
+ hsSpiEnableInt(FALSE);
+#endif
+ spin_lock(&pBcmSpi->lock);
+
+ list_add_tail(&msg->queue, &pBcmSpi->queue);
+ if (NULL == pBcmSpi->curTrans)
+ {
+ hsSpiNextMessage(pBcmSpi);
+ }
+
+ spin_unlock(&pBcmSpi->lock);
+#ifdef HS_SPI_USE_INTERRUPTS
+ if ( pBcmSpi->irq )
+ hsSpiEnableInt(TRUE);
+#endif
+
+ return 0;
+}
+
+
+#ifdef HS_SPI_USE_INTERRUPTS
+static irqreturn_t hsSpiIntHandler(int irq, void *dev_id)
+{
+ struct bcmspi *pBcmSpi = dev_id;
+ struct spi_message *msg;
+ struct spi_transfer *xfer;
+
+ if ( 0 == HS_SPI->hs_spiIntStatusMasked )
+ {
+ return ( IRQ_NONE );
+ }
+
+ hsSpiClearIntStatus();
+ hsSpiEnableInt(FALSE);
+
+ spin_lock(&pBcmSpi->lock);
+ if ( NULL == pBcmSpi->curTrans )
+ {
+ spin_unlock(&pBcmSpi->lock);
+ return IRQ_HANDLED;
+ }
+
+ xfer = pBcmSpi->curTrans;
+ msg = list_entry(pBcmSpi->queue.next, struct spi_message, queue);
+
+ hsSpiTransEnd(xfer->rx_buf, xfer->len);
+
+ /* xfer can specify a delay before the next transfer is started
+ this delay would be processed here normally. However, delay in the
+ interrupt handler is bad so it is ignored. It is used for polling
+ mode */
+
+ /* check to see if this is the last transfer in the message */
+ if (msg->transfers.prev == &xfer->transfer_list)
+ {
+ /* report completed message */
+ hsSpiMsgDone(pBcmSpi, msg, SPI_STATUS_OK);
+ }
+ else
+ {
+ /* Submit the next transfer */
+ hsSpiNextXfer(pBcmSpi, msg);
+ }
+
+ spin_unlock(&pBcmSpi->lock);
+
+ return IRQ_HANDLED;
+
+}
+
+int __init hsSpiIntrInit( void )
+{
+ int ret = 0;
+ struct bcmspi *pBcmSpi = &BcmHsSpi;
+
+ hsSpiEnableInt(FALSE);
+ ret = request_irq(INTERRUPT_ID_SPI, hsSpiIntHandler, (IRQF_DISABLED | IRQF_SAMPLE_RANDOM | IRQF_SHARED), pBcmSpi->devName, pBcmSpi);
+
+ spin_lock(&pBcmSpi->lock);
+ pBcmSpi->irq = INTERRUPT_ID_SPI;
+ spin_unlock(&pBcmSpi->lock);
+
+ BcmHalInterruptEnable(pBcmSpi->irq);
+
+ return( 0 );
+
+}
+/* we cannot initialize interrupts early
+ The flash module is intialized before an interrupt handler can be installed
+ and before the Linux framework can be used. This means it needs direct access
+ to the controller initially. This conflicts with the interrupt handling so we
+ need to wait for all modules to intialize */
+late_initcall(hsSpiIntrInit);
+#endif
+
+static void hsSpiCleanup(struct spi_device *spi)
+{
+ /* would free spi_controller memory here if any was allocated */
+
+}
+
+static int __init hsSpiProbe(struct platform_device *pdev)
+{
+ int ret;
+ struct spi_master *master;
+ struct bcmspi *pBcmSpi;
+
+ ret = -ENOMEM;
+ master = spi_alloc_master(&pdev->dev, 0);
+ if (!master)
+ goto out_free;
+
+ master->bus_num = pdev->id;
+ master->num_chipselect = 8;
+ master->setup = hsSpiSetup;
+ master->transfer = hsSpiTransfer;
+ master->cleanup = hsSpiCleanup;
+ platform_set_drvdata(pdev, master);
+
+ spi_master_set_devdata(master, (void *)&BcmHsSpi);
+ pBcmSpi = spi_master_get_devdata(master);
+
+ INIT_LIST_HEAD(&pBcmSpi->queue);
+
+ pBcmSpi->pdev = pdev;
+ pBcmSpi->bus_num = HS_SPI_BUS_NUM;
+ pBcmSpi->num_chipselect = 8;
+ pBcmSpi->curTrans = NULL;
+
+ /* make sure irq is 0 here
+ since this is used to identify when interrupts are enabled
+ the IRQ is initialized in hsSpiIntrInit */
+ pBcmSpi->irq = 0;
+
+ /* Initialize the hardware */
+
+ /* register and we are done */
+ ret = spi_register_master(master);
+ if (ret)
+ goto out_free;
+
+ return 0;
+
+out_free:
+ spi_master_put(master);
+
+ return ret;
+}
+
+
+static int __exit hsSpiRemove(struct platform_device *pdev)
+{
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct bcmspi *pBcmSpi = spi_master_get_devdata(master);
+ struct spi_message *msg;
+
+ /* reset the hardware and block queue progress */
+#ifdef HS_SPI_USE_INTERRUPTS
+ hsSpiEnableInt(FALSE);
+#endif
+ spin_lock(&pBcmSpi->lock);
+ pBcmSpi->stopping = 1;
+
+ /* HW shutdown */
+
+ spin_unlock(&pBcmSpi->lock);
+
+ /* Terminate remaining queued transfers */
+ list_for_each_entry(msg, &pBcmSpi->queue, queue)
+ {
+ msg->status = -ESHUTDOWN;
+ msg->complete(msg->context);
+ }
+
+#ifdef HS_SPI_USE_INTERRUPTS
+ if ( pBcmSpi->irq )
+ {
+ free_irq(pBcmSpi->irq, master);
+ }
+#endif
+ spi_unregister_master(master);
+
+ return 0;
+}
+
+//#ifdef CONFIG_PM
+#if 0
+static int hsSpiSuspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct bcmspi *pBcmSpi = spi_master_get_devdata(master);
+
+ return 0;
+}
+
+static int hsSpiResume(struct platform_device *pdev)
+{
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct bcmspi *pBcmSpi = spi_master_get_devdata(master);
+
+ return 0;
+}
+#else
+#define hsSpiSuspend NULL
+#define hsSpiResume NULL
+#endif
+
+static struct platform_device bcm_hsspi_device = {
+ .name = "bcmhs_spi",
+ .id = HS_SPI_BUS_NUM,
+};
+
+static struct platform_driver bcm_hsspi_driver = {
+ .driver =
+ {
+ .name = "bcmhs_spi",
+ .owner = THIS_MODULE,
+ },
+ .suspend = hsSpiSuspend,
+ .resume = hsSpiResume,
+ .remove = __exit_p(hsSpiRemove),
+};
+
+int __init hsSpiModInit( void )
+{
+ platform_device_register(&bcm_hsspi_device);
+ return platform_driver_probe(&bcm_hsspi_driver, hsSpiProbe);
+
+}
+subsys_initcall(hsSpiModInit);
+#endif
+
+#endif /* HS_SPI */
+
diff --git a/shared/opensource/spi/bcmLegSpi.c b/shared/opensource/spi/bcmLegSpi.c
new file mode 100755
index 0000000..6d1a391
--- /dev/null
+++ b/shared/opensource/spi/bcmLegSpi.c
@@ -0,0 +1,774 @@
+/*
+ Copyright 2000-2010 Broadcom Corporation
+
+ Unless you and Broadcom execute a separate written software license
+ agreement governing use of this software, this software is licensed
+ to you under the terms of the GNU General Public License version 2
+ (the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
+ with the following added to such license:
+
+ As a special exception, the copyright holders of this software give
+ you permission to link this software with independent modules, and to
+ copy and distribute the resulting executable under terms of your
+ choice, provided that you also meet, for each linked independent
+ module, the terms and conditions of the license of that module.
+ An independent module is a module which is not derived from this
+ software. The special exception does not apply to any modifications
+ of the software.
+
+ Notwithstanding the above, under no circumstances may you combine this
+ software in any way with any other Broadcom software provided under a
+ license other than the GPL, without Broadcom's express prior written
+ consent.
+*/
+
+#ifdef _CFE_
+#include "lib_types.h"
+#include "lib_printf.h"
+#include "lib_string.h"
+#include "bcm_map.h"
+#define printk printf
+#else
+#include <linux/autoconf.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/spi/spi.h>
+
+#include <bcm_map_part.h>
+#include <bcm_intr.h>
+#endif
+
+/* if SPI is defined then the legacy SPI controller is available, otherwise do not compile this code */
+#ifdef SPI
+
+#include "bcmSpiRes.h"
+#include "bcmSpi.h"
+
+int BcmLegSpiRead(unsigned char * msg_buf, int prependcnt, int nbytes, int devId, int freqHz);
+int BcmLegSpiWrite(unsigned char * msg_buf, int nbytes, int devId, int freqHz);
+
+#ifndef _CFE_
+//#define LEG_SPI_USE_INTERRUPTS /* define this to use interrupts instead of polling */
+static struct bcmspi BcmLegSpi = { SPIN_LOCK_UNLOCKED,
+ "bcmLegSpiDev",
+ };
+#endif
+
+/* following are the frequency tables for the SPI controllers
+ they are ordered by frequency in descending order with column
+ 2 represetning the register value */
+#define LEG_SPI_FREQ_TABLE_SIZE 7
+int legSpiClockFreq[LEG_SPI_FREQ_TABLE_SIZE][2] = {
+ { 20000000, 0},
+ { 12500000, 6},
+ { 6250000, 5},
+ { 3125000, 4},
+ { 1563000, 3},
+ { 781000, 2},
+ { 391000, 1} };
+
+static int legSpiRead( unsigned char *pRxBuf, int prependcnt, int nbytes, int devId )
+{
+ int i;
+
+ SPI->spiMsgCtl = (HALF_DUPLEX_R << SPI_MSG_TYPE_SHIFT) | (nbytes << SPI_BYTE_CNT_SHIFT);
+
+ for (i = 0; i < prependcnt; i++)
+ {
+ SPI->spiMsgData[i] = pRxBuf[i];
+ }
+
+ SPI->spiCmd = (SPI_CMD_START_IMMEDIATE << SPI_CMD_COMMAND_SHIFT |
+ devId << SPI_CMD_DEVICE_ID_SHIFT |
+ prependcnt << SPI_CMD_PREPEND_BYTE_CNT_SHIFT |
+ 0 << SPI_CMD_ONE_BYTE_SHIFT);
+
+ return SPI_STATUS_OK;
+
+}
+
+static int legSpiWriteFull( unsigned char *pTxBuf, int nbytes, int devId, int opcode )
+{
+ int i;
+
+ if ( opcode == BCM_SPI_FULL )
+ {
+ SPI->spiMsgCtl = (FULL_DUPLEX_RW << SPI_MSG_TYPE_SHIFT) | (nbytes << SPI_BYTE_CNT_SHIFT);
+ }
+ else
+ {
+ SPI->spiMsgCtl = (HALF_DUPLEX_W << SPI_MSG_TYPE_SHIFT) | (nbytes << SPI_BYTE_CNT_SHIFT);
+ }
+
+ for (i = 0; i < nbytes; i++)
+ {
+ SPI->spiMsgData[i] = pTxBuf[i];
+ }
+
+ SPI->spiCmd = (SPI_CMD_START_IMMEDIATE << SPI_CMD_COMMAND_SHIFT |
+ devId << SPI_CMD_DEVICE_ID_SHIFT |
+ 0 << SPI_CMD_PREPEND_BYTE_CNT_SHIFT |
+ 0 << SPI_CMD_ONE_BYTE_SHIFT);
+
+ return SPI_STATUS_OK;
+
+}
+
+
+static int legSpiTransEnd( unsigned char *rxBuf, int nbytes )
+{
+ int i;
+ if ( NULL != rxBuf )
+ {
+ for (i = 0; i < nbytes; i++)
+ {
+ rxBuf[i] = SPI->spiRxDataFifo[i];
+ }
+ }
+
+ return SPI_STATUS_OK;
+
+}
+
+static int legSpiTransPoll(void)
+{
+ while ( 1 )
+ {
+ if ( SPI->spiIntStatus & SPI_INTR_CMD_DONE )
+ {
+ break;
+ }
+ }
+
+ return SPI_STATUS_OK;
+}
+
+static void legSpiClearIntStatus(void)
+{
+ SPI->spiIntStatus = SPI_INTR_CLEAR_ALL;
+}
+
+#ifdef LEG_SPI_USE_INTERRUPTS
+static void legSpiEnableInt(bool bEnable)
+{
+ if ( bEnable )
+ {
+ SPI->spiIntMask = SPI_INTR_CMD_DONE;
+ }
+ else
+ {
+ SPI->spiIntMask = 0;
+ }
+}
+#endif
+
+#ifndef _CFE_
+static int legSpiSetClock( int clockHz )
+{
+ int i;
+ int clock = -1;
+
+ for( i = 0; i < LEG_SPI_FREQ_TABLE_SIZE; i++ )
+ {
+ /* look for the closest frequency that is less than the frequency passed in */
+ if ( legSpiClockFreq[i][0] <= clockHz )
+ {
+ clock = legSpiClockFreq[i][1];
+ break;
+ }
+ }
+ /* if no clock was found set to default */
+ if ( -1 == clock )
+ {
+ clock = LEG_SPI_CLOCK_DEF;
+ }
+ SPI->spiClkCfg = (SPI->spiClkCfg & ~SPI_CLK_MASK) | clock;
+
+ return SPI_STATUS_OK;
+}
+#endif
+
+/* these interfaces are availble for the CFE and spi flash driver only
+ all modules must use the linux kernel framework
+ if this is called by a module and interrupts are being used there will
+ be a problem */
+int BcmLegSpiRead( unsigned char *msg_buf, int prependcnt, int nbytes, int devId, int freqHz )
+{
+#ifndef _CFE_
+ struct bcmspi *pBcmSpi = &BcmLegSpi;
+
+ if ( pBcmSpi->irq )
+ {
+ printk("BcmLegSpiRead error - SPI Interrupts are enabled\n");
+ return( SPI_STATUS_ERR );
+ }
+
+ spin_lock(&pBcmSpi->lock);
+ legSpiSetClock(freqHz);
+#endif
+ legSpiClearIntStatus();
+ legSpiRead(msg_buf, prependcnt, nbytes, devId);
+ legSpiTransPoll();
+ legSpiTransEnd(msg_buf, nbytes);
+ legSpiClearIntStatus();
+#ifndef _CFE_
+ spin_unlock(&pBcmSpi->lock);
+#endif
+
+ return( SPI_STATUS_OK );
+}
+
+int BcmLegSpiWrite( unsigned char *msg_buf, int nbytes, int devId, int freqHz )
+{
+#ifndef _CFE_
+ struct bcmspi *pBcmSpi = &BcmLegSpi;
+
+ if ( pBcmSpi->irq )
+ {
+ printk("BcmLegSpiWrite error - SPI Interrupts are enabled\n");
+ return( SPI_STATUS_ERR );
+ }
+
+ spin_lock(&pBcmSpi->lock);
+ legSpiSetClock(freqHz);
+#endif
+ legSpiClearIntStatus();
+ legSpiWriteFull(msg_buf, nbytes, devId, BCM_SPI_WRITE);
+ legSpiTransPoll();
+ legSpiTransEnd(msg_buf, nbytes);
+ legSpiClearIntStatus();
+#ifndef _CFE_
+ spin_unlock(&pBcmSpi->lock);
+#endif
+
+ return( SPI_STATUS_OK );
+}
+
+
+#ifndef _CFE_
+static void legSpiNextMessage(struct bcmspi *pBcmSpi);
+
+static void legSpiMsgDone(struct bcmspi *pBcmSpi, struct spi_message *msg, int status)
+{
+ list_del(&msg->queue);
+ msg->status = status;
+
+ spin_unlock(&pBcmSpi->lock);
+ msg->complete(msg->context);
+ spin_lock(&pBcmSpi->lock);
+
+ pBcmSpi->curTrans = NULL;
+
+ /* continue if needed */
+ if (list_empty(&pBcmSpi->queue) || pBcmSpi->stopping)
+ {
+ // disable controler ...
+ }
+ else
+ {
+ legSpiNextMessage(pBcmSpi);
+ }
+}
+
+#ifdef LEG_SPI_USE_INTERRUPTS
+static void legSpiIntXfer(struct bcmspi *pBcmSpi, struct spi_message *msg)
+{
+ struct spi_transfer *xfer;
+ struct spi_transfer *nextXfer;
+ int length;
+ int prependCnt;
+ char *pTxBuf;
+ char *pRxBuf;
+ int opCode;
+
+ xfer = pBcmSpi->curTrans;
+ if ( NULL == xfer)
+ {
+ xfer = list_entry(msg->transfers.next, struct spi_transfer, transfer_list);
+ }
+ else
+ {
+ xfer = list_entry(xfer->transfer_list.next, struct spi_transfer, transfer_list);
+ }
+ pBcmSpi->curTrans = xfer;
+
+ length = xfer->len;
+ prependCnt = 0;
+ pRxBuf = xfer->rx_buf;
+ pTxBuf = (unsigned char *)xfer->tx_buf;
+
+ if ( (NULL != pRxBuf) && (NULL != pTxBuf) )
+ {
+ opCode = BCM_SPI_FULL;
+ }
+ else if ( NULL != pRxBuf )
+ {
+ opCode = BCM_SPI_READ;
+ }
+ else
+ {
+ opCode = BCM_SPI_WRITE;
+ }
+
+ if ( msg->state )
+ {
+ /* this controller does not support keeping the chip select active for all transfers
+ non NULL state indicates that we need to combine the transfers */
+ nextXfer = list_entry(xfer->transfer_list.next, struct spi_transfer, transfer_list);
+ prependCnt = length;
+ length = nextXfer->len;
+ pRxBuf = nextXfer->rx_buf;
+ opCode = BCM_SPI_READ;
+ pBcmSpi->curTrans = nextXfer;
+ }
+
+ legSpiSetClock(xfer->speed_hz);
+
+ legSpiClearIntStatus();
+ legSpiEnableInt(TRUE);
+ if ( BCM_SPI_READ == opCode )
+ {
+ legSpiRead(pTxBuf, prependCnt, length, msg->spi->chip_select);
+ }
+ else
+ {
+ legSpiWriteFull(pTxBuf, length, msg->spi->chip_select, opCode);
+ }
+
+ return;
+
+}
+#endif
+
+static void legSpiPollXfer(struct bcmspi *pBcmSpi, struct spi_message *msg)
+{
+ struct spi_transfer *xfer;
+ struct spi_transfer *nextXfer;
+ int length;
+ int prependCnt;
+ char *pTxBuf;
+ char *pRxBuf;
+ int opCode;
+
+ list_for_each_entry(xfer, &msg->transfers, transfer_list)
+ {
+ pBcmSpi->curTrans = xfer;
+ length = xfer->len;
+ prependCnt = 0;
+ pRxBuf = xfer->rx_buf;
+ pTxBuf = (unsigned char *)xfer->tx_buf;
+
+ if ( (NULL != pRxBuf) && (NULL != pTxBuf) )
+ {
+ opCode = BCM_SPI_FULL;
+ }
+ else if ( NULL != pRxBuf )
+ {
+ opCode = BCM_SPI_READ;
+ }
+ else
+ {
+ opCode = BCM_SPI_WRITE;
+ }
+
+ if ( msg->state )
+ {
+ /* this controller does not support keeping the chip select active for all transfers
+ non NULL state indicates that we need to combine the transfers */
+ nextXfer = list_entry(xfer->transfer_list.next, struct spi_transfer, transfer_list);
+ prependCnt = length;
+ length = nextXfer->len;
+ pRxBuf = nextXfer->rx_buf;
+ opCode = BCM_SPI_READ;
+ xfer = nextXfer;
+ }
+
+ legSpiSetClock(xfer->speed_hz);
+
+ legSpiClearIntStatus();
+ if ( BCM_SPI_READ == opCode )
+ {
+ legSpiRead(pTxBuf, prependCnt, length, msg->spi->chip_select);
+ }
+ else
+ {
+ legSpiWriteFull(pTxBuf, length, msg->spi->chip_select, opCode);
+ }
+
+ legSpiTransPoll();
+ legSpiTransEnd(pRxBuf, length);
+ legSpiClearIntStatus();
+
+ if (xfer->delay_usecs)
+ {
+ udelay(xfer->delay_usecs);
+ }
+
+ msg->actual_length += length;
+ }
+
+ legSpiMsgDone(pBcmSpi, msg, SPI_STATUS_OK);
+
+}
+
+
+static void legSpiNextXfer(struct bcmspi *pBcmSpi, struct spi_message *msg)
+{
+#ifdef LEG_SPI_USE_INTERRUPTS
+ if (pBcmSpi->irq)
+ legSpiIntXfer(pBcmSpi, msg);
+ else
+#endif
+ legSpiPollXfer(pBcmSpi, msg);
+
+}
+
+
+static void legSpiNextMessage(struct bcmspi *pBcmSpi)
+{
+ struct spi_message *msg;
+
+ BUG_ON(pBcmSpi->curTrans);
+
+ msg = list_entry(pBcmSpi->queue.next, struct spi_message, queue);
+
+ /* there will always be one transfer in a given message */
+ legSpiNextXfer(pBcmSpi, msg);
+
+}
+
+
+static int legSpiSetup(struct spi_device *spi)
+{
+ struct bcmspi *pBcmSpi;
+
+ pBcmSpi = spi_master_get_devdata(spi->master);
+
+ if (pBcmSpi->stopping)
+ return -ESHUTDOWN;
+
+ /* there is nothing to setup */
+
+ return 0;
+}
+
+
+int legSpiTransfer(struct spi_device *spi, struct spi_message *msg)
+{
+ struct bcmspi *pBcmSpi = &BcmLegSpi;
+ struct spi_transfer *xfer;
+ struct spi_transfer *nextXfer;
+ int xferCnt;
+ int bCsChange;
+ int xferLen;
+
+ if (unlikely(list_empty(&msg->transfers)))
+ return -EINVAL;
+
+ if (pBcmSpi->stopping)
+ return -ESHUTDOWN;
+
+ /* make sure a completion callback is set */
+ if ( NULL == msg->complete )
+ {
+ return -EINVAL;
+ }
+
+ xferCnt = 0;
+ bCsChange = 0;
+ xferLen = 0;
+ list_for_each_entry(xfer, &msg->transfers, transfer_list)
+ {
+ /* check transfer parameters */
+ if (!(xfer->tx_buf || xfer->rx_buf))
+ {
+ return -EINVAL;
+ }
+
+ /* check the clock setting - if it is 0 then set to max clock of the device */
+ if ( 0 == xfer->speed_hz )
+ {
+ if ( 0 == spi->max_speed_hz )
+ {
+ return -EINVAL;
+ }
+ xfer->speed_hz = spi->max_speed_hz;
+ }
+
+ xferCnt++;
+ xferLen += xfer->len;
+ bCsChange |= xfer->cs_change;
+
+ if ( xfer->len > (sizeof(SPI->spiMsgData) & ~0x3) )
+ {
+ return -EINVAL;
+ }
+ }
+
+ /* this controller does not support keeping the chip select active between
+ transfers. If a message is detected with a write transfer followed by a
+ read transfer and cs_change is set to 0 then the two transfers need to be
+ combined. The message state is used to indicate that the transfers
+ need to be combined */
+ msg->state = NULL;
+ if ( (2 == xferCnt) && (0 == bCsChange) )
+ {
+ xfer = list_entry(msg->transfers.next, struct spi_transfer, transfer_list);
+ if ( (NULL != xfer->tx_buf) && (NULL == xfer->rx_buf))
+ {
+ nextXfer = list_entry(xfer->transfer_list.next, struct spi_transfer, transfer_list);;
+ if ( (NULL == nextXfer->tx_buf) && (NULL != nextXfer->rx_buf))
+ {
+ msg->state = (void *)1;
+ }
+ }
+ }
+
+ msg->status = -EINPROGRESS;
+ msg->actual_length = 0;
+
+#ifdef LEG_SPI_USE_INTERRUPTS
+ /* disable interrupts for the SPI controller
+ using spin_lock_irqsave would disable all interrupts */
+ if ( pBcmSpi->irq )
+ legSpiEnableInt(FALSE);
+#endif
+ spin_lock(&pBcmSpi->lock);
+
+ list_add_tail(&msg->queue, &pBcmSpi->queue);
+ if (NULL == pBcmSpi->curTrans)
+ {
+ legSpiNextMessage(pBcmSpi);
+ }
+
+ spin_unlock(&pBcmSpi->lock);
+#ifdef LEG_SPI_USE_INTERRUPTS
+ if ( pBcmSpi->irq )
+ legSpiEnableInt(TRUE);
+#endif
+
+ return 0;
+}
+
+
+#ifdef LEG_SPI_USE_INTERRUPTS
+static irqreturn_t legSpiIntHandler(int irq, void *dev_id)
+{
+ struct bcmspi *pBcmSpi = dev_id;
+ struct spi_message *msg;
+ struct spi_transfer *xfer;
+
+ if ( 0 == SPI->spiMaskIntStatus )
+ {
+ return ( IRQ_NONE );
+ }
+
+ legSpiClearIntStatus();
+ legSpiEnableInt(FALSE);
+
+ spin_lock(&pBcmSpi->lock);
+ if ( NULL == pBcmSpi->curTrans )
+ {
+ spin_unlock(&pBcmSpi->lock);
+ return IRQ_HANDLED;
+ }
+
+ xfer = pBcmSpi->curTrans;
+ msg = list_entry(pBcmSpi->queue.next, struct spi_message, queue);
+
+ legSpiTransEnd(xfer->rx_buf, xfer->len);
+
+ /* xfer can specify a delay before the next transfer is started
+ this is only used for polling mode */
+
+ /* check to see if this is the last transfer in the message */
+ if (msg->transfers.prev == &xfer->transfer_list)
+ {
+ /* report completed message */
+ legSpiMsgDone(pBcmSpi, msg, SPI_STATUS_OK);
+ }
+ else
+ {
+ /* Submit the next transfer */
+ legSpiNextXfer(pBcmSpi, msg);
+ }
+
+ spin_unlock(&pBcmSpi->lock);
+
+ return IRQ_HANDLED;
+
+}
+
+int __init legSpiIntrInit( void )
+{
+ int ret = 0;
+ struct bcmspi *pBcmSpi = &BcmLegSpi;
+
+ legSpiEnableInt(FALSE);
+ ret = request_irq(INTERRUPT_ID_SPI, legSpiIntHandler, (IRQF_DISABLED | IRQF_SAMPLE_RANDOM | IRQF_SHARED), pBcmSpi->devName, pBcmSpi);
+
+ spin_lock(&pBcmSpi->lock);
+ pBcmSpi->irq = INTERRUPT_ID_SPI;
+ spin_unlock(&pBcmSpi->lock);
+
+ BcmHalInterruptEnable(pBcmSpi->irq);
+
+ return( 0 );
+
+}
+/* we cannot initialize interrupts early
+ The flash module is intialized before an interrupt handler can be installed
+ and before the Linux framework can be used. This means it needs direct access
+ to the controller initially. This conflicts with the interrupt handling so we
+ need to wait for all modules to intialize */
+late_initcall(legSpiIntrInit);
+#endif
+
+static void legSpiCleanup(struct spi_device *spi)
+{
+ /* would free spi_controller memory here if any was allocated */
+
+}
+
+static int __init legSpiProbe(struct platform_device *pdev)
+{
+ int ret;
+ struct spi_master *master;
+ struct bcmspi *pBcmSpi;
+
+ ret = -ENOMEM;
+ master = spi_alloc_master(&pdev->dev, 0);
+ if (!master)
+ goto out_free;
+
+ master->bus_num = pdev->id;
+ master->num_chipselect = 8;
+ master->setup = legSpiSetup;
+ master->transfer = legSpiTransfer;
+ master->cleanup = legSpiCleanup;
+ platform_set_drvdata(pdev, master);
+
+ spi_master_set_devdata(master, (void *)&BcmLegSpi);
+ pBcmSpi = spi_master_get_devdata(master);
+
+ INIT_LIST_HEAD(&pBcmSpi->queue);
+
+ pBcmSpi->pdev = pdev;
+ pBcmSpi->bus_num = LEG_SPI_BUS_NUM;
+ pBcmSpi->num_chipselect = 8;
+ pBcmSpi->curTrans = NULL;
+
+ /* make sure irq is 0 here
+ since this is used to identify when interrupts are enabled
+ the IRQ is initialized in legSpiIntrInit */
+ pBcmSpi->irq = 0;
+
+ /* Initialize the hardware */
+
+ /* register and we are done */
+ ret = spi_register_master(master);
+ if (ret)
+ goto out_free;
+
+ return 0;
+
+out_free:
+ spi_master_put(master);
+
+ return ret;
+}
+
+
+static int __exit legSpiRemove(struct platform_device *pdev)
+{
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct bcmspi *pBcmSpi = spi_master_get_devdata(master);
+ struct spi_message *msg;
+
+ /* reset the hardware and block queue progress */
+#ifdef LEG_SPI_USE_INTERRUPTS
+ legSpiEnableInt(FALSE);
+#endif
+ spin_lock(&pBcmSpi->lock);
+ pBcmSpi->stopping = 1;
+
+ /* HW shutdown */
+
+ spin_unlock(&pBcmSpi->lock);
+
+ /* Terminate remaining queued transfers */
+ list_for_each_entry(msg, &pBcmSpi->queue, queue)
+ {
+ msg->status = -ESHUTDOWN;
+ msg->complete(msg->context);
+ }
+
+#ifdef LEG_SPI_USE_INTERRUPTS
+ if ( pBcmSpi->irq )
+ {
+ free_irq(pBcmSpi->irq, master);
+ }
+#endif
+ spi_unregister_master(master);
+
+ return 0;
+}
+
+//#ifdef CONFIG_PM
+#if 0
+static int legSpiSuspend(struct platform_device *pdev, pm_message_t mesg)
+{
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct bcmspi *pBcmSpi = spi_master_get_devdata(master);
+
+ return 0;
+}
+
+static int legSpiResume(struct platform_device *pdev)
+{
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct bcmspi *pBcmSpi = spi_master_get_devdata(master);
+
+ return 0;
+}
+#else
+#define legSpiSuspend NULL
+#define legSpiResume NULL
+#endif
+
+
+static struct platform_device bcm_legacyspi_device = {
+ .name = "bcmleg_spi",
+ .id = LEG_SPI_BUS_NUM,
+};
+
+static struct platform_driver bcm_legspi_driver = {
+ .driver =
+ {
+ .name = "bcmleg_spi",
+ .owner = THIS_MODULE,
+ },
+ .suspend = legSpiSuspend,
+ .resume = legSpiResume,
+ .remove = __exit_p(legSpiRemove),
+};
+
+
+int __init legSpiModInit( void )
+{
+ platform_device_register(&bcm_legacyspi_device);
+ return platform_driver_probe(&bcm_legspi_driver, legSpiProbe);
+
+}
+subsys_initcall(legSpiModInit);
+#endif
+
+#endif /* SPI */
+
diff --git a/shared/opensource/spi/bcmSpiRes.c b/shared/opensource/spi/bcmSpiRes.c
new file mode 100755
index 0000000..ed16575
--- /dev/null
+++ b/shared/opensource/spi/bcmSpiRes.c
@@ -0,0 +1,660 @@
+/*
+ Copyright 2000-2010 Broadcom Corporation
+
+ Unless you and Broadcom execute a separate written software license
+ agreement governing use of this software, this software is licensed
+ to you under the terms of the GNU General Public License version 2
+ (the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
+ with the following added to such license:
+
+ As a special exception, the copyright holders of this software give
+ you permission to link this software with independent modules, and to
+ copy and distribute the resulting executable under terms of your
+ choice, provided that you also meet, for each linked independent
+ module, the terms and conditions of the license of that module.
+ An independent module is a module which is not derived from this
+ software. The special exception does not apply to any modifications
+ of the software.
+
+ Notwithstanding the above, under no circumstances may you combine this
+ software in any way with any other Broadcom software provided under a
+ license other than the GPL, without Broadcom's express prior written
+ consent.
+*/
+
+#ifdef _CFE_
+#include "lib_types.h"
+#include "lib_printf.h"
+#include "lib_string.h"
+#include "bcm_map.h"
+#define printk printf
+#else
+#include <linux/version.h>
+#include <linux/autoconf.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29)
+#include <linux/semaphore.h>
+#endif
+#include <linux/spi/spi.h>
+#include <linux/autoconf.h>
+
+#include <bcm_map_part.h>
+#endif
+#include "bcmSpiRes.h"
+
+extern int BcmLegSpiRead(unsigned char * msg_buf, int prependcnt, int nbytes, int devId, int freqHz);
+extern int BcmLegSpiWrite(unsigned char * msg_buf, int nbytes, int devId, int freqHz);
+extern int BcmHsSpiRead(unsigned char * msg_buf, int prependcnt, int nbytes, int devId, int freqHz);
+extern int BcmHsSpiWrite(unsigned char * msg_buf, int nbytes, int devId, int freqHz);
+
+#ifndef _CFE_
+#ifdef SPI
+/* the BCM legacy controller supports up to 8 devices */
+static struct spi_board_info bcmLegSpiDevInfo[8] =
+{
+ {
+ .modalias = "bcm_LegSpiDev0",
+ .chip_select = 0,
+ .max_speed_hz = 781000,
+ .bus_num = LEG_SPI_BUS_NUM,
+ .mode = SPI_MODE_3,
+ },
+ {
+ .modalias = "bcm_LegSpiDev1",
+ .chip_select = 1,
+ .max_speed_hz = 781000,
+ .bus_num = LEG_SPI_BUS_NUM,
+ .mode = SPI_MODE_3,
+ },
+ {
+ .modalias = "bcm_LegSpiDev2",
+ .chip_select = 2,
+ .max_speed_hz = 781000,
+ .bus_num = LEG_SPI_BUS_NUM,
+ .mode = SPI_MODE_3,
+ },
+ {
+ .modalias = "bcm_LegSpiDev3",
+ .chip_select = 3,
+ .max_speed_hz = 781000,
+ .bus_num = LEG_SPI_BUS_NUM,
+ .mode = SPI_MODE_3,
+ },
+ {
+ .modalias = "bcm_LegSpiDev4",
+ .chip_select = 4,
+ .max_speed_hz = 781000,
+ .bus_num = LEG_SPI_BUS_NUM,
+ .mode = SPI_MODE_3,
+ },
+ {
+ .modalias = "bcm_LegSpiDev5",
+ .chip_select = 5,
+ .max_speed_hz = 781000,
+ .bus_num = LEG_SPI_BUS_NUM,
+ .mode = SPI_MODE_3,
+ },
+ {
+ .modalias = "bcm_LegSpiDev6",
+ .chip_select = 6,
+ .max_speed_hz = 781000,
+ .bus_num = LEG_SPI_BUS_NUM,
+ .mode = SPI_MODE_3,
+ },
+ {
+ .modalias = "bcm_LegSpiDev7",
+ .chip_select = 7,
+ .max_speed_hz = 781000,
+ .bus_num = LEG_SPI_BUS_NUM,
+ .mode = SPI_MODE_3,
+ },
+};
+
+static struct spi_driver bcmLegSpiDevDrv[8] =
+{
+ {
+ .driver =
+ {
+ .name = "bcm_LegSpiDev0",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .driver =
+ {
+ .name = "bcm_LegSpiDev1",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .driver =
+ {
+ .name = "bcm_LegSpiDev2",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .driver =
+ {
+ .name = "bcm_LegSpiDev3",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .driver =
+ {
+ .name = "bcm_LegSpiDev4",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .driver =
+ {
+ .name = "bcm_LegSpiDev5",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .driver =
+ {
+ .name = "bcm_LegSpiDev6",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .driver =
+ {
+ .name = "bcm_LegSpiDev7",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ },
+};
+
+static struct spi_device * bcmLegSpiDevices[8];
+#endif
+
+#ifdef HS_SPI
+/* the BCM HS controller supports up to 8 devices */
+static struct spi_board_info bcmHSSpiDevInfo[8] =
+{
+ {
+ .modalias = "bcm_HSSpiDev0",
+ .controller_data = (void *)SPI_CONTROLLER_STATE_DEFAULT,
+ .chip_select = 0,
+ .max_speed_hz = 781000,
+ .bus_num = HS_SPI_BUS_NUM,
+ .mode = SPI_MODE_DEFAULT,
+ },
+ {
+ .modalias = "bcm_HSSpiDev1",
+ .controller_data = (void *)SPI_CONTROLLER_STATE_DEFAULT,
+ .chip_select = 1,
+ .max_speed_hz = 781000,
+ .bus_num = HS_SPI_BUS_NUM,
+ .mode = SPI_MODE_DEFAULT,
+ },
+ {
+ .modalias = "bcm_HSSpiDev2",
+ .controller_data = (void *)SPI_CONTROLLER_STATE_DEFAULT,
+ .chip_select = 2,
+ .max_speed_hz = 781000,
+ .bus_num = HS_SPI_BUS_NUM,
+ .mode = SPI_MODE_DEFAULT,
+ },
+ {
+ .modalias = "bcm_HSSpiDev3",
+ .controller_data = (void *)SPI_CONTROLLER_STATE_DEFAULT,
+ .chip_select = 3,
+ .max_speed_hz = 781000,
+ .bus_num = HS_SPI_BUS_NUM,
+ .mode = SPI_MODE_DEFAULT,
+ },
+ {
+ .modalias = "bcm_HSSpiDev4",
+ .controller_data = (void *)SPI_CONTROLLER_STATE_DEFAULT,
+ .chip_select = 4,
+ .max_speed_hz = 781000,
+ .bus_num = HS_SPI_BUS_NUM,
+ .mode = SPI_MODE_DEFAULT,
+ },
+ {
+ .modalias = "bcm_HSSpiDev5",
+ .controller_data = (void *)SPI_CONTROLLER_STATE_DEFAULT,
+ .chip_select = 5,
+ .max_speed_hz = 781000,
+ .bus_num = HS_SPI_BUS_NUM,
+ .mode = SPI_MODE_DEFAULT,
+ },
+ {
+ .modalias = "bcm_HSSpiDev6",
+ .controller_data = (void *)SPI_CONTROLLER_STATE_DEFAULT,
+ .chip_select = 6,
+ .max_speed_hz = 781000,
+ .bus_num = HS_SPI_BUS_NUM,
+ .mode = SPI_MODE_DEFAULT,
+ },
+ {
+ .modalias = "bcm_HSSpiDev7",
+ .controller_data = (void *)SPI_CONTROLLER_STATE_DEFAULT,
+ .chip_select = 7,
+ .max_speed_hz = 781000,
+ .bus_num = HS_SPI_BUS_NUM,
+ .mode = SPI_MODE_DEFAULT,
+ },
+};
+
+static struct spi_driver bcmHSSpiDevDrv[8] =
+{
+ {
+ .driver =
+ {
+ .name = "bcm_HSSpiDev0",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .driver =
+ {
+ .name = "bcm_HSSpiDev1",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .driver =
+ {
+ .name = "bcm_HSSpiDev2",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .driver =
+ {
+ .name = "bcm_HSSpiDev3",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .driver =
+ {
+ .name = "bcm_HSSpiDev4",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .driver =
+ {
+ .name = "bcm_HSSpiDev5",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .driver =
+ {
+ .name = "bcm_HSSpiDev6",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ },
+ {
+ .driver =
+ {
+ .name = "bcm_HSSpiDev7",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ },
+};
+
+static struct spi_device * bcmHSSpiDevices[8];
+#endif
+
+
+int BcmSpiReserveSlave2(int busNum, int slaveId, int maxFreq, int spiMode, int ctrlState)
+{
+ struct spi_master * pSpiMaster;
+ struct spi_driver * pSpiDriver;
+
+ if ( slaveId > 7 )
+ {
+ return SPI_STATUS_ERR;
+ }
+
+ if ( LEG_SPI_BUS_NUM == busNum )
+ {
+#ifndef SPI
+ return( SPI_STATUS_ERR );
+#else
+ if ( NULL != bcmLegSpiDevices[slaveId] )
+ {
+ printk(KERN_ERR "BcmSpiReserveSlave - slaveId %d, already registerd\n", slaveId);
+ return( SPI_STATUS_ERR );
+ }
+
+ bcmLegSpiDevInfo[slaveId].max_speed_hz = maxFreq;
+ bcmLegSpiDevInfo[slaveId].controller_data = (void *)ctrlState;
+ bcmLegSpiDevInfo[slaveId].mode = spiMode;
+
+ pSpiMaster = spi_busnum_to_master( busNum );
+ bcmLegSpiDevices[slaveId] = spi_new_device(pSpiMaster, &bcmLegSpiDevInfo[slaveId]);
+ pSpiDriver = &bcmLegSpiDevDrv[slaveId];
+#endif
+ }
+ else if ( HS_SPI_BUS_NUM == busNum )
+ {
+#ifndef HS_SPI
+ return( SPI_STATUS_ERR );
+#else
+ if ( NULL != bcmHSSpiDevices[slaveId] )
+ {
+ printk(KERN_ERR "BcmSpiReserveSlave - slaveId %d, already registerd\n", slaveId);
+ return( SPI_STATUS_ERR );
+ }
+
+ bcmHSSpiDevInfo[slaveId].max_speed_hz = maxFreq;
+ bcmHSSpiDevInfo[slaveId].controller_data = (void *)ctrlState;
+ bcmHSSpiDevInfo[slaveId].mode = spiMode;
+
+ pSpiMaster = spi_busnum_to_master( busNum );
+ bcmHSSpiDevices[slaveId] = spi_new_device(pSpiMaster, &bcmHSSpiDevInfo[slaveId]);
+ pSpiDriver = &bcmHSSpiDevDrv[slaveId];
+#endif
+ }
+ else
+ return( SPI_STATUS_ERR );
+
+ /* register the SPI driver */
+ spi_register_driver(pSpiDriver);
+
+ return 0;
+
+}
+EXPORT_SYMBOL(BcmSpiReserveSlave2);
+
+int BcmSpiReserveSlave(int busNum, int slaveId, int maxFreq)
+{
+ return( BcmSpiReserveSlave2(busNum, slaveId, maxFreq, SPI_MODE_DEFAULT, SPI_CONTROLLER_STATE_DEFAULT) );
+}
+EXPORT_SYMBOL(BcmSpiReserveSlave);
+
+int BcmSpiReleaseSlave(int busNum, int slaveId)
+{
+ if ( slaveId > 7 )
+ {
+ return SPI_STATUS_ERR;
+ }
+
+ if ( LEG_SPI_BUS_NUM == busNum )
+ {
+#ifndef SPI
+ return( SPI_STATUS_ERR );
+#else
+ if ( NULL == bcmLegSpiDevices[slaveId] )
+ {
+ printk(KERN_ERR "BcmSpiReleaseSlave - slaveId %d, already released\n", slaveId);
+ return( SPI_STATUS_ERR );
+ }
+
+ bcmLegSpiDevInfo[slaveId].max_speed_hz = 781000;
+ spi_unregister_driver(&bcmLegSpiDevDrv[slaveId]);
+ spi_unregister_device(bcmLegSpiDevices[slaveId]);
+ bcmLegSpiDevices[slaveId] = 0;
+#endif
+ }
+ else if ( HS_SPI_BUS_NUM == busNum )
+ {
+#ifndef HS_SPI
+ return( SPI_STATUS_ERR );
+#else
+ if ( NULL == bcmHSSpiDevices[slaveId] )
+ {
+ printk(KERN_ERR "BcmSpiReleaseSlave - slaveId %d, already released\n", slaveId);
+ return( SPI_STATUS_ERR );
+ }
+
+ bcmHSSpiDevInfo[slaveId].max_speed_hz = 781000;
+ spi_unregister_driver(&bcmHSSpiDevDrv[slaveId]);
+ spi_unregister_device(bcmHSSpiDevices[slaveId]);
+ bcmHSSpiDevices[slaveId] = 0;
+#endif
+ }
+ else
+ return( SPI_STATUS_ERR );
+
+ return 0;
+
+}
+EXPORT_SYMBOL(BcmSpiReleaseSlave);
+
+
+int BcmSpiSyncTrans(unsigned char *txBuf, unsigned char *rxBuf, int prependcnt, int nbytes, int busNum, int slaveId)
+{
+ struct spi_message msg;
+ struct spi_transfer xfer[2];
+ int status;
+ int maxLength;
+ struct spi_device *pSpiDevice;
+
+ maxLength = BcmSpi_GetMaxRWSize(busNum);
+ if ( (nbytes > maxLength) || (prependcnt > maxLength) )
+ {
+ printk(KERN_ERR "ERROR BcmSpiSyncTrans: invalid length len %d, pre %d, max %d\n", nbytes, prependcnt, maxLength);
+ return SPI_STATUS_ERR;
+ }
+
+ if ( slaveId > 7 )
+ {
+ printk(KERN_ERR "ERROR BcmSpiSyncTrans: invalid slave id %d\n", slaveId);
+ return SPI_STATUS_ERR;
+ }
+
+ if ( LEG_SPI_BUS_NUM == busNum )
+ {
+#ifndef SPI
+ return( SPI_STATUS_ERR );
+#else
+ if ( NULL == bcmLegSpiDevices[slaveId] )
+ {
+ printk(KERN_ERR "ERROR BcmSpiSyncTrans: device not registered\n");
+ return SPI_STATUS_ERR;
+ }
+ pSpiDevice = bcmLegSpiDevices[slaveId];
+#endif
+ }
+ else if ( HS_SPI_BUS_NUM == busNum )
+ {
+#ifndef HS_SPI
+ return( SPI_STATUS_ERR );
+#else
+ if ( NULL == bcmHSSpiDevices[slaveId] )
+ {
+ printk(KERN_ERR "ERROR BcmSpiSyncTrans: device not registered\n");
+ return SPI_STATUS_ERR;
+ }
+ pSpiDevice = bcmHSSpiDevices[slaveId];
+#endif
+ }
+ else
+ return( SPI_STATUS_ERR );
+
+ spi_message_init(&msg);
+ memset(xfer, 0, (sizeof xfer));
+
+ if ( prependcnt )
+ {
+ xfer[0].len = prependcnt;
+ xfer[0].speed_hz = pSpiDevice->max_speed_hz;
+ if ( txBuf )
+ {
+ xfer[0].tx_buf = txBuf;
+ }
+ else
+ {
+ xfer[0].tx_buf = rxBuf;
+ }
+ spi_message_add_tail(&xfer[0], &msg);
+ }
+
+ xfer[1].len = nbytes;
+ xfer[1].speed_hz = pSpiDevice->max_speed_hz;
+ xfer[1].rx_buf = rxBuf;
+
+ /* for the controller to use the prepend count correctly the first operation must be a read and the second a write
+ make sure tx is NULL for second transaction */
+ if ( 0 == prependcnt )
+ {
+ xfer[1].tx_buf = txBuf;
+ }
+ spi_message_add_tail(&xfer[1], &msg);
+
+ status = spi_sync(pSpiDevice, &msg);
+ if (status >= 0)
+ {
+ status = SPI_STATUS_OK;
+ }
+ else
+ {
+ status = SPI_STATUS_ERR;
+ }
+
+ return( status );
+
+}
+EXPORT_SYMBOL(BcmSpiSyncTrans);
+#endif
+
+int BcmSpi_SetFlashCtrl( int opCode, int addrBytes, int dummyBytes, int busNum, int devId )
+{
+ if ( HS_SPI_BUS_NUM == busNum )
+ {
+#ifndef HS_SPI
+ return SPI_STATUS_ERR;
+#else
+ int clock;
+
+ clock = HS_SPI_PLL_FREQ/HS_SPI_CLOCK_DEF;
+ if (HS_SPI_PLL_FREQ%HS_SPI_CLOCK_DEF)
+ clock++;
+
+ clock = 2048/clock;
+ if (2048%(clock))
+ clock++;
+
+ HS_SPI_PROFILES[0].clk_ctrl = 1<<HS_SPI_ACCUM_RST_ON_LOOP | 0<<HS_SPI_SPI_CLK_2X_SEL | clock<<HS_SPI_FREQ_CTRL_WORD;
+ HS_SPI->hs_spiFlashCtrl = devId<<HS_SPI_FCTRL_SS_NUM | 0<<HS_SPI_FCTRL_PROFILE_NUM | dummyBytes<<HS_SPI_FCTRL_DUMMY_BYTES |
+ addrBytes<<HS_SPI_FCTRL_ADDR_BYTES | opCode<<HS_SPI_FCTRL_READ_OPCODE;
+#endif
+ }
+ else if ( LEG_SPI_BUS_NUM == busNum )
+ {
+#ifndef SPI
+ return SPI_STATUS_ERR;
+#endif
+ }
+ else
+ return SPI_STATUS_ERR;
+
+ return SPI_STATUS_OK;
+
+}
+
+
+int BcmSpi_GetMaxRWSize( int busNum )
+{
+ int maxRWSize = 0;
+
+ if ( HS_SPI_BUS_NUM == busNum )
+ {
+#ifdef HS_SPI
+ maxRWSize = HS_SPI_BUFFER_LEN;
+#endif
+ }
+ else if ( LEG_SPI_BUS_NUM == busNum )
+ {
+#ifdef SPI
+ maxRWSize = sizeof(SPI->spiMsgData);
+#endif
+ }
+
+ maxRWSize &= ~0x3;
+
+ return(maxRWSize);
+
+}
+
+
+/* The interface bcmSpi_Read and bcmSpi_Write provide direct access to the SPI controller.
+ these interfaces should only be called by CFE and early spi flash code */
+int BcmSpi_Read( unsigned char *msg_buf, int prependcnt, int nbytes, int busNum, int devId, int freqHz )
+{
+ if ( LEG_SPI_BUS_NUM == busNum )
+ {
+#ifndef SPI
+ return SPI_STATUS_ERR;
+#else
+ return BcmLegSpiRead( msg_buf, prependcnt, nbytes, devId, freqHz );
+#endif
+ }
+ else if ( HS_SPI_BUS_NUM == busNum )
+ {
+#ifndef HS_SPI
+ return SPI_STATUS_ERR;
+#else
+ return BcmHsSpiRead( msg_buf, prependcnt, nbytes, devId, freqHz );
+#endif
+ }
+ else
+ {
+ return SPI_STATUS_ERR;
+ }
+
+}
+
+int BcmSpi_Write( unsigned char *msg_buf, int nbytes, int busNum, int devId, int freqHz )
+{
+ if ( LEG_SPI_BUS_NUM == busNum )
+ {
+#ifndef SPI
+ return SPI_STATUS_ERR;
+#else
+ return BcmLegSpiWrite( msg_buf, nbytes, devId, freqHz );
+#endif
+ }
+ else if ( HS_SPI_BUS_NUM == busNum )
+ {
+#ifndef HS_SPI
+ return SPI_STATUS_ERR;
+#else
+ return BcmHsSpiWrite( msg_buf, nbytes, devId, freqHz );
+#endif
+ }
+ else
+ {
+ return SPI_STATUS_ERR;
+ }
+}
+
+#ifndef _CFE_
+EXPORT_SYMBOL(BcmSpi_SetFlashCtrl);
+EXPORT_SYMBOL(BcmSpi_GetMaxRWSize);
+#endif
+