summaryrefslogtreecommitdiff
path: root/drivers/spi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/Makefile2
-rw-r--r--drivers/spi/atmel_spi.c210
-rw-r--r--drivers/spi/atmel_spi.h95
-rw-r--r--drivers/spi/davinci_spi.c284
-rw-r--r--drivers/spi/davinci_spi.h46
-rw-r--r--drivers/spi/mpc8xxx_spi.c54
-rw-r--r--drivers/spi/mxc_spi.c88
-rw-r--r--drivers/spi/spirom.c212
-rw-r--r--drivers/spi/spirom.h77
9 files changed, 1030 insertions, 38 deletions
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index bc8a104121..a917ba5c1d 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -26,7 +26,9 @@ include $(TOPDIR)/config.mk
LIB := $(obj)libspi.a
COBJS-y += mpc8xxx_spi.o
+COBJS-$(CONFIG_ATMEL_SPI) += atmel_spi.o
COBJS-$(CONFIG_MXC_SPI) += mxc_spi.o
+COBJS-$(CONFIG_DAVINCI_SPI) += davinci_spi.o
COBJS := $(COBJS-y)
SRCS := $(COBJS:.o=.c)
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
new file mode 100644
index 0000000000..317c0b41b6
--- /dev/null
+++ b/drivers/spi/atmel_spi.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2007 Atmel Corporation
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include <common.h>
+#include <spi.h>
+#include <malloc.h>
+
+#include <asm/io.h>
+
+#include <asm/arch/clk.h>
+#include <asm/arch/memory-map.h>
+
+#include "atmel_spi.h"
+
+void spi_init()
+{
+
+}
+
+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
+ unsigned int max_hz, unsigned int mode)
+{
+ struct atmel_spi_slave *as;
+ unsigned int scbr;
+ u32 csrx;
+ void *regs;
+
+ if (cs > 3 || !spi_cs_is_valid(bus, cs))
+ return NULL;
+
+ switch (bus) {
+ case 0:
+ regs = (void *)SPI0_BASE;
+ break;
+#ifdef SPI1_BASE
+ case 1:
+ regs = (void *)SPI1_BASE;
+ break;
+#endif
+#ifdef SPI2_BASE
+ case 2:
+ regs = (void *)SPI2_BASE;
+ break;
+#endif
+#ifdef SPI3_BASE
+ case 3:
+ regs = (void *)SPI3_BASE;
+ break;
+#endif
+ default:
+ return NULL;
+ }
+
+
+ scbr = (get_spi_clk_rate(bus) + max_hz - 1) / max_hz;
+ if (scbr > ATMEL_SPI_CSRx_SCBR_MAX)
+ /* Too low max SCK rate */
+ return NULL;
+ if (scbr < 1)
+ scbr = 1;
+
+ csrx = ATMEL_SPI_CSRx_SCBR(scbr);
+ csrx |= ATMEL_SPI_CSRx_BITS(ATMEL_SPI_BITS_8);
+ if (!(mode & SPI_CPHA))
+ csrx |= ATMEL_SPI_CSRx_NCPHA;
+ if (mode & SPI_CPOL)
+ csrx |= ATMEL_SPI_CSRx_CPOL;
+
+ as = malloc(sizeof(struct atmel_spi_slave));
+ if (!as)
+ return NULL;
+
+ as->slave.bus = bus;
+ as->slave.cs = cs;
+ as->regs = regs;
+ as->mr = ATMEL_SPI_MR_MSTR | ATMEL_SPI_MR_MODFDIS
+ | ATMEL_SPI_MR_PCS(~(1 << cs) & 0xf);
+ spi_writel(as, CSR(cs), csrx);
+
+ return &as->slave;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+ struct atmel_spi_slave *as = to_atmel_spi(slave);
+
+ free(as);
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+ struct atmel_spi_slave *as = to_atmel_spi(slave);
+
+ /* Enable the SPI hardware */
+ spi_writel(as, CR, ATMEL_SPI_CR_SPIEN);
+
+ /*
+ * Select the slave. This should set SCK to the correct
+ * initial state, etc.
+ */
+ spi_writel(as, MR, as->mr);
+
+ return 0;
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+ struct atmel_spi_slave *as = to_atmel_spi(slave);
+
+ /* Disable the SPI hardware */
+ spi_writel(as, CR, ATMEL_SPI_CR_SPIDIS);
+}
+
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
+{
+ struct atmel_spi_slave *as = to_atmel_spi(slave);
+ unsigned int len_tx;
+ unsigned int len_rx;
+ unsigned int len;
+ int ret;
+ u32 status;
+ const u8 *txp = dout;
+ u8 *rxp = din;
+ u8 value;
+
+ ret = 0;
+ if (bitlen == 0)
+ /* Finish any previously submitted transfers */
+ goto out;
+
+ /*
+ * TODO: The controller can do non-multiple-of-8 bit
+ * transfers, but this driver currently doesn't support it.
+ *
+ * It's also not clear how such transfers are supposed to be
+ * represented as a stream of bytes...this is a limitation of
+ * the current SPI interface.
+ */
+ if (bitlen % 8) {
+ /* Errors always terminate an ongoing transfer */
+ flags |= SPI_XFER_END;
+ goto out;
+ }
+
+ len = bitlen / 8;
+
+ /*
+ * The controller can do automatic CS control, but it is
+ * somewhat quirky, and it doesn't really buy us much anyway
+ * in the context of U-Boot.
+ */
+ if (flags & SPI_XFER_BEGIN)
+ spi_cs_activate(slave);
+
+ for (len_tx = 0, len_rx = 0; len_rx < len; ) {
+ status = spi_readl(as, SR);
+
+ if (status & ATMEL_SPI_SR_OVRES)
+ return -1;
+
+ if (len_tx < len && (status & ATMEL_SPI_SR_TDRE)) {
+ if (txp)
+ value = *txp++;
+ else
+ value = 0;
+ spi_writel(as, TDR, value);
+ len_tx++;
+ }
+ if (status & ATMEL_SPI_SR_RDRF) {
+ value = spi_readl(as, RDR);
+ if (rxp)
+ *rxp++ = value;
+ len_rx++;
+ }
+ }
+
+out:
+ if (flags & SPI_XFER_END) {
+ /*
+ * Wait until the transfer is completely done before
+ * we deactivate CS.
+ */
+ do {
+ status = spi_readl(as, SR);
+ } while (!(status & ATMEL_SPI_SR_TXEMPTY));
+
+ spi_cs_deactivate(slave);
+ }
+
+ return 0;
+}
diff --git a/drivers/spi/atmel_spi.h b/drivers/spi/atmel_spi.h
new file mode 100644
index 0000000000..2baf9c76ef
--- /dev/null
+++ b/drivers/spi/atmel_spi.h
@@ -0,0 +1,95 @@
+/*
+ * Register definitions for the DaVinci SPI Controller
+ */
+
+/* Register offsets */
+#define DAVINCI_SPI_CR 0x0000
+#define ATMEL_SPI_MR 0x0004
+#define ATMEL_SPI_RDR 0x0008
+#define ATMEL_SPI_TDR 0x000c
+#define ATMEL_SPI_SR 0x0010
+#define ATMEL_SPI_IER 0x0014
+#define ATMEL_SPI_IDR 0x0018
+#define ATMEL_SPI_IMR 0x001c
+#define ATMEL_SPI_CSR(x) (0x0030 + 4 * (x))
+#define ATMEL_SPI_VERSION 0x00fc
+
+/* Bits in CR */
+#define ATMEL_SPI_CR_SPIEN (1 << 0)
+#define ATMEL_SPI_CR_SPIDIS (1 << 1)
+#define ATMEL_SPI_CR_SWRST (1 << 7)
+#define ATMEL_SPI_CR_LASTXFER (1 << 24)
+
+/* Bits in MR */
+#define ATMEL_SPI_MR_MSTR (1 << 0)
+#define ATMEL_SPI_MR_PS (1 << 1)
+#define ATMEL_SPI_MR_PCSDEC (1 << 2)
+#define ATMEL_SPI_MR_FDIV (1 << 3)
+#define ATMEL_SPI_MR_MODFDIS (1 << 4)
+#define ATMEL_SPI_MR_LLB (1 << 7)
+#define ATMEL_SPI_MR_PCS(x) (((x) & 15) << 16)
+#define ATMEL_SPI_MR_DLYBCS(x) ((x) << 24)
+
+/* Bits in RDR */
+#define ATMEL_SPI_RDR_RD(x) (x)
+#define ATMEL_SPI_RDR_PCS(x) ((x) << 16)
+
+/* Bits in TDR */
+#define ATMEL_SPI_TDR_TD(x) (x)
+#define ATMEL_SPI_TDR_PCS(x) ((x) << 16)
+#define ATMEL_SPI_TDR_LASTXFER (1 << 24)
+
+/* Bits in SR/IER/IDR/IMR */
+#define ATMEL_SPI_SR_RDRF (1 << 0)
+#define ATMEL_SPI_SR_TDRE (1 << 1)
+#define ATMEL_SPI_SR_MODF (1 << 2)
+#define ATMEL_SPI_SR_OVRES (1 << 3)
+#define ATMEL_SPI_SR_ENDRX (1 << 4)
+#define ATMEL_SPI_SR_ENDTX (1 << 5)
+#define ATMEL_SPI_SR_RXBUFF (1 << 6)
+#define ATMEL_SPI_SR_TXBUFE (1 << 7)
+#define ATMEL_SPI_SR_NSSR (1 << 8)
+#define ATMEL_SPI_SR_TXEMPTY (1 << 9)
+#define ATMEL_SPI_SR_SPIENS (1 << 16)
+
+/* Bits in CSRx */
+#define ATMEL_SPI_CSRx_CPOL (1 << 0)
+#define ATMEL_SPI_CSRx_NCPHA (1 << 1)
+#define ATMEL_SPI_CSRx_CSAAT (1 << 3)
+#define ATMEL_SPI_CSRx_BITS(x) ((x) << 4)
+#define ATMEL_SPI_CSRx_SCBR(x) ((x) << 8)
+#define ATMEL_SPI_CSRx_SCBR_MAX 0xff
+#define ATMEL_SPI_CSRx_DLYBS(x) ((x) << 16)
+#define ATMEL_SPI_CSRx_DLYBCT(x) ((x) << 24)
+
+/* Bits in VERSION */
+#define ATMEL_SPI_VERSION_REV(x) ((x) << 0)
+#define ATMEL_SPI_VERSION_MFN(x) ((x) << 16)
+
+/* Constants for CSRx:BITS */
+#define ATMEL_SPI_BITS_8 0
+#define ATMEL_SPI_BITS_9 1
+#define ATMEL_SPI_BITS_10 2
+#define ATMEL_SPI_BITS_11 3
+#define ATMEL_SPI_BITS_12 4
+#define ATMEL_SPI_BITS_13 5
+#define ATMEL_SPI_BITS_14 6
+#define ATMEL_SPI_BITS_15 7
+#define ATMEL_SPI_BITS_16 8
+
+struct atmel_spi_slave {
+ struct spi_slave slave;
+ void *regs;
+ u32 mr;
+};
+
+static inline struct atmel_spi_slave *to_atmel_spi(struct spi_slave *slave)
+{
+ return container_of(slave, struct atmel_spi_slave, slave);
+}
+
+/* Register access macros */
+#define spi_readl(as, reg) \
+ readl(as->regs + ATMEL_SPI_##reg)
+#define spi_writel(as, reg, value) \
+ writel(value, as->regs + ATMEL_SPI_##reg)
diff --git a/drivers/spi/davinci_spi.c b/drivers/spi/davinci_spi.c
new file mode 100644
index 0000000000..ed895212bd
--- /dev/null
+++ b/drivers/spi/davinci_spi.c
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2008 Sekhar Nori, Texas Instruments, Inc <www.ti.com>
+ *
+ * Driver for SPI controller on DaVinci. Based on atmel_spi.c
+ * by Atmel Corporation
+ *
+ * Copyright (C) 2007 Atmel Corporation
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include <common.h>
+#include <spi.h>
+#include <malloc.h>
+
+#include <asm/io.h>
+
+#include <asm/arch/hardware.h>
+
+#include "davinci_spi.h"
+
+static unsigned int data1_reg_val;
+
+
+void spi_init()
+{
+ /* do nothing */
+
+}
+
+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
+ unsigned int max_hz, unsigned int mode)
+{
+ struct davinci_spi_slave *ds;
+ void *regs;
+ unsigned int fmt0;
+
+ ds = malloc(sizeof(struct davinci_spi_slave));
+ if (!ds)
+ return NULL;
+
+ ds->slave.bus = bus;
+ ds->slave.cs = cs;
+ ds->regs = CFG_SPI_BASE;
+ ds->freq = max_hz;
+
+ return &ds->slave;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+ struct davinci_spi_slave *ds = to_davinci_spi(slave);
+
+ free(ds);
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+ struct davinci_spi_slave *ds = to_davinci_spi(slave);
+ unsigned int scalar;
+
+ /* Enable the SPI hardware */
+ spi_writel(ds, GCR0, 0);
+ udelay(1000);
+ spi_writel(ds, GCR0, 1);
+
+ /* Set master mode, powered up and not activated */
+ spi_writel(ds, GCR1, 0x3);
+
+ /* CS, CLK, SIMO and SOMI are functional pins */
+ spi_writel(ds, PC0, (1 << 0) | (1 << 9) | (1 << 10) | (1 << 11));
+
+ /* setup format */
+ scalar = ((CFG_SPI_CLK / ds->freq) - 1 ) & 0xFF;
+
+ spi_writel(ds, FMT0, 8 | /* character length */
+ (scalar << 8) |
+ (1 << 16) | /* clock signal delayed by half clk cycle */
+ (0 << 17) | /* clock low in idle state - Mode 0 */
+ (0 << 20)); /* MSB shifted out first */
+
+ /* hold cs active at end of transfer until explicitly de-asserted */
+ data1_reg_val = (1 << 28) | (slave->cs << 16);
+ spi_writel(ds, DAT1, data1_reg_val);
+
+ /* including a minor delay. No science here. Should be good even with
+ * no delay
+ */
+ spi_writel(ds, DELAY, (50 << 24) | (50 << 16));
+
+ /* default chip select register */
+ spi_writel(ds, DEF, 1);
+
+ /* no interrupts */
+ spi_writel(ds, INT0, 0);
+ spi_writel(ds, LVL, 0);
+
+ /* enable SPI */
+ spi_writel(ds, GCR1, spi_readl(ds, GCR1) | (1 << 24));
+
+ return 0;
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+ struct davinci_spi_slave *ds = to_davinci_spi(slave);
+
+ /* Disable the SPI hardware */
+ spi_writel(ds, GCR0, 0);
+}
+
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
+ const void *dout, void *din, unsigned long flags)
+{
+ struct davinci_spi_slave *ds = to_davinci_spi(slave);
+ unsigned int len_tx;
+ unsigned int len_rx;
+ unsigned int len;
+ int ret, i;
+ u32 status;
+ const u8 *txp = dout;
+ u8 *rxp = din;
+ u8 value, dummy = 0;
+
+ ret = 0;
+
+ if (bitlen == 0)
+ /* Finish any previously submitted transfers */
+ goto out;
+
+ /*
+ * It's not clear how non-8-bit-aligned transfers are supposed to be
+ * represented as a stream of bytes...this is a limitation of
+ * the current SPI interface - here we terminate on receiving such a
+ * transfer request.
+ */
+ if (bitlen % 8) {
+ /* Errors always terminate an ongoing transfer */
+ flags |= SPI_XFER_END;
+ goto out;
+ }
+
+ len = bitlen / 8;
+
+ /* do an empty read to clear the current contents */
+ spi_readl(ds, BUF);
+
+ /* keep writing and reading 1 byte until done */
+ for (i = 0; i < len; i++) {
+
+ /* wait till TXFULL is asserted */
+ while(spi_readl(ds, BUF) & (1 << 29));
+
+ /* write the data */
+ data1_reg_val &= ~0xFFFF;
+ if(txp) {
+ data1_reg_val |= *txp & 0xFF;
+ txp++;
+ }
+
+ /* write to DAT1 is required to keep the serial transfer going */
+ /* we just terminate when we reach the end */
+ if((i == (len -1)) && (flags & SPI_XFER_END)) {
+ spi_writel(ds, DAT1, data1_reg_val & ~(1 << 28)); /* clear CS hold */
+ } else {
+ spi_writel(ds, DAT1, data1_reg_val);
+ }
+
+
+ /* read the data - wait for data availability */
+ while(spi_readl(ds, BUF) & (1 << 31));
+
+ if(rxp) {
+ *rxp = spi_readl(ds, BUF) & 0xFF;
+ rxp++;
+ } else {
+ spi_readl(ds, BUF); /* simply drop the read character */
+ }
+
+ }
+
+ return 0;
+
+out:
+ if (flags & SPI_XFER_END) {
+ spi_writel(ds, DAT1, data1_reg_val & ~(1 << 28));
+ }
+
+ return 0;
+}
+
+
+#ifdef CONFIG_CMD_EEPROM
+
+/* ------------------------------------------------------------------------ *
+ * SPI ROM Definitions *
+ * ------------------------------------------------------------------------ */
+#define SPIROM_SIZE 0x00008000
+#define SPIROM_BASE 0x00000000
+#define SPIROM_PAGESIZE 32
+#define SPIROM_PAGEMASK 0xffffffc0
+
+/* ------------------------------------------------------------------------ *
+ * SPI ROM Commands *
+ * ------------------------------------------------------------------------ */
+#define SPIROM_CMD_WRSR 0x01
+#define SPIROM_CMD_WRITE 0x02
+#define SPIROM_CMD_READ 0x03
+#define SPIROM_CMD_WRDI 0x04
+#define SPIROM_CMD_RDSR 0x05
+#define SPIROM_CMD_WREN 0x06
+
+static struct spi_slave *slave;
+
+void spi_init_f(void)
+{
+ slave = spi_setup_slave(0, 0, 1*1024*1024, 0);
+ spi_claim_bus(slave);
+}
+
+static char spirombuf[3];
+
+/* ------------------------------------------------------------------------ *
+ * spirom_status( ) *
+ * ------------------------------------------------------------------------ */
+static unsigned char spi_get_status( )
+{
+ /* Issue read status command */
+ spirombuf[0] = SPIROM_CMD_RDSR;
+ spirombuf[1] = 0;
+
+ spi_xfer(slave, (2)*8, spirombuf, spirombuf, SPI_XFER_BEGIN | SPI_XFER_END);
+
+ return spirombuf[1];
+}
+
+ssize_t spi_write(uchar *addr, int alen, uchar *buffer, int len)
+{
+
+ spirombuf[0] = SPIROM_CMD_WREN;
+ spi_xfer(slave, 1*8, spirombuf, NULL, SPI_XFER_BEGIN | SPI_XFER_END);
+
+ /* Create command block for program operation */
+ spirombuf[0] = SPIROM_CMD_WRITE;
+ spirombuf[1] = addr[0];
+ spirombuf[2] = addr[1];
+
+ spi_xfer(slave, 3 * 8, spirombuf, NULL, SPI_XFER_BEGIN);
+ spi_xfer(slave, len * 8, buffer, NULL, SPI_XFER_END);
+
+ /* Wait while busy */
+ while( (spi_get_status( ) & 0x01 ) );
+
+ return len;
+}
+
+ssize_t spi_read(uchar *addr, int alen, uchar *buffer, int len)
+{
+ spirombuf[0] = 0x3;
+ spirombuf[1] = addr[0];
+ spirombuf[2] = addr[1];
+
+ spi_xfer(slave, 3*8, spirombuf, NULL, SPI_XFER_BEGIN);
+ spi_xfer(slave, len*8, NULL, buffer, SPI_XFER_END);
+
+ return len;
+}
+
+#endif
diff --git a/drivers/spi/davinci_spi.h b/drivers/spi/davinci_spi.h
new file mode 100644
index 0000000000..0f2b0877ba
--- /dev/null
+++ b/drivers/spi/davinci_spi.h
@@ -0,0 +1,46 @@
+/*
+ * Register definitions for the DaVinci SPI Controller
+ */
+
+/* Register offsets */
+#define DAVINCI_SPI_GCR0 0x0000
+#define DAVINCI_SPI_GCR1 0x0004
+#define DAVINCI_SPI_INT0 0x0008
+#define DAVINCI_SPI_LVL 0x000c
+#define DAVINCI_SPI_FLG 0x0010
+#define DAVINCI_SPI_PC0 0x0014
+#define DAVINCI_SPI_PC1 0x0018
+#define DAVINCI_SPI_PC2 0x001c
+#define DAVINCI_SPI_PC3 0x0020
+#define DAVINCI_SPI_PC4 0x0024
+#define DAVINCI_SPI_PC5 0x0028
+#define DAVINCI_SPI_DAT0 0x0038
+#define DAVINCI_SPI_DAT1 0x003c
+#define DAVINCI_SPI_BUF 0x0040
+#define DAVINCI_SPI_EMU 0x0044
+#define DAVINCI_SPI_DELAY 0x0048
+#define DAVINCI_SPI_DEF 0x004c
+#define DAVINCI_SPI_FMT0 0x0050
+#define DAVINCI_SPI_FMT1 0x0054
+#define DAVINCI_SPI_FMT2 0x0058
+#define DAVINCI_SPI_FMT3 0x005c
+#define DAVINCI_SPI_INTVEC0 0x0060
+#define DAVINCI_SPI_INTVEC1 0x0064
+
+struct davinci_spi_slave {
+ struct spi_slave slave;
+ void *regs;
+ u32 mr;
+ unsigned int freq;
+};
+
+static inline struct davinci_spi_slave *to_davinci_spi(struct spi_slave *slave)
+{
+ return container_of(slave, struct davinci_spi_slave, slave);
+}
+
+#define spi_readl(as, reg) \
+ readl(CFG_SPI_BASE + DAVINCI_SPI_##reg)
+#define spi_writel(as, reg, value) \
+ writel(value, CFG_SPI_BASE + DAVINCI_SPI_##reg)
+
diff --git a/drivers/spi/mpc8xxx_spi.c b/drivers/spi/mpc8xxx_spi.c
index 2fe838c45d..136fb50052 100644
--- a/drivers/spi/mpc8xxx_spi.c
+++ b/drivers/spi/mpc8xxx_spi.c
@@ -24,6 +24,7 @@
#include <common.h>
#if defined(CONFIG_MPC8XXX_SPI) && defined(CONFIG_HARD_SPI)
+#include <malloc.h>
#include <spi.h>
#include <asm/mpc8xxx_spi.h>
@@ -37,6 +38,34 @@
#define SPI_TIMEOUT 1000
+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
+ unsigned int max_hz, unsigned int mode)
+{
+ struct spi_slave *slave;
+
+ if (!spi_cs_is_valid(bus, cs))
+ return NULL;
+
+ slave = malloc(sizeof(struct spi_slave));
+ if (!slave)
+ return NULL;
+
+ slave->bus = bus;
+ slave->cs = cs;
+
+ /*
+ * TODO: Some of the code in spi_init() should probably move
+ * here, or into spi_claim_bus() below.
+ */
+
+ return slave;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+ free(slave);
+}
+
void spi_init(void)
{
volatile spi8xxx_t *spi = &((immap_t *) (CFG_IMMR))->spi;
@@ -53,7 +82,18 @@ void spi_init(void)
spi->com = 0; /* LST bit doesn't do anything, so disregard */
}
-int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din)
+int spi_claim_bus(struct spi_slave *slave)
+{
+ return 0;
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+
+}
+
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
+ void *din, unsigned long flags)
{
volatile spi8xxx_t *spi = &((immap_t *) (CFG_IMMR))->spi;
unsigned int tmpdout, tmpdin, event;
@@ -61,11 +101,11 @@ int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din)
int tm, isRead = 0;
unsigned char charSize = 32;
- debug("spi_xfer: chipsel %08X dout %08X din %08X bitlen %d\n",
- (int)chipsel, *(uint *) dout, *(uint *) din, bitlen);
+ debug("spi_xfer: slave %u:%u dout %08X din %08X bitlen %u\n",
+ slave->bus, slave->cs, *(uint *) dout, *(uint *) din, bitlen);
- if (chipsel != NULL)
- (*chipsel) (1); /* select the target chip */
+ if (flags & SPI_XFER_BEGIN)
+ spi_cs_activate(slave);
spi->event = 0xffffffff; /* Clear all SPI events */
@@ -135,8 +175,8 @@ int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din)
debug("*** spi_xfer: transfer ended. Value=%08x\n", tmpdin);
}
- if (chipsel != NULL)
- (*chipsel) (0); /* deselect the target chip */
+ if (flags & SPI_XFER_END)
+ spi_cs_deactivate(slave);
return 0;
}
diff --git a/drivers/spi/mxc_spi.c b/drivers/spi/mxc_spi.c
index b2e3ab9b67..e0809593d1 100644
--- a/drivers/spi/mxc_spi.c
+++ b/drivers/spi/mxc_spi.c
@@ -19,6 +19,7 @@
*/
#include <common.h>
+#include <malloc.h>
#include <spi.h>
#include <asm/io.h>
@@ -61,17 +62,18 @@ static unsigned long spi_bases[] = {
0x53f84000,
};
-static unsigned long spi_base;
-
#endif
-spi_chipsel_type spi_chipsel[] = {
- (spi_chipsel_type)0,
- (spi_chipsel_type)1,
- (spi_chipsel_type)2,
- (spi_chipsel_type)3,
+struct mxc_spi_slave {
+ struct spi_slave slave;
+ unsigned long base;
+ u32 ctrl_reg;
};
-int spi_chipsel_cnt = sizeof(spi_chipsel) / sizeof(spi_chipsel[0]);
+
+static inline struct mxc_spi_slave *to_mxc_spi_slave(struct spi_slave *slave)
+{
+ return container_of(slave, struct mxc_spi_slave, slave);
+}
static inline u32 reg_read(unsigned long addr)
{
@@ -83,30 +85,31 @@ static inline void reg_write(unsigned long addr, u32 val)
*(volatile unsigned long*)addr = val;
}
-static u32 spi_xchg_single(u32 data, int bitlen)
+static u32 spi_xchg_single(struct spi_slave *slave, u32 data, int bitlen)
{
-
- unsigned int cfg_reg = reg_read(spi_base + MXC_CSPICTRL);
+ struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave);
+ unsigned int cfg_reg = reg_read(mxcs->base + MXC_CSPICTRL);
if (MXC_CSPICTRL_BITCOUNT(bitlen - 1) != (cfg_reg & MXC_CSPICTRL_BITCOUNT(31))) {
cfg_reg = (cfg_reg & ~MXC_CSPICTRL_BITCOUNT(31)) |
MXC_CSPICTRL_BITCOUNT(bitlen - 1);
- reg_write(spi_base + MXC_CSPICTRL, cfg_reg);
+ reg_write(mxcs->base + MXC_CSPICTRL, cfg_reg);
}
- reg_write(spi_base + MXC_CSPITXDATA, data);
+ reg_write(mxcs->base + MXC_CSPITXDATA, data);
cfg_reg |= MXC_CSPICTRL_XCH;
- reg_write(spi_base + MXC_CSPICTRL, cfg_reg);
+ reg_write(mxcs->base + MXC_CSPICTRL, cfg_reg);
- while (reg_read(spi_base + MXC_CSPICTRL) & MXC_CSPICTRL_XCH)
+ while (reg_read(mxcs->base + MXC_CSPICTRL) & MXC_CSPICTRL_XCH)
;
- return reg_read(spi_base + MXC_CSPIRXDATA);
+ return reg_read(mxcs->base + MXC_CSPIRXDATA);
}
-int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din)
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
+ void *din, unsigned long flags)
{
int n_blks = (bitlen + 31) / 32;
u32 *out_l, *in_l;
@@ -117,13 +120,10 @@ int spi_xfer(spi_chipsel_type chipsel, int bitlen, uchar *dout, uchar *din)
return 1;
}
- if (!spi_base)
- spi_select(CONFIG_MXC_SPI_IFACE, (int)chipsel, SPI_MODE_2 | SPI_CS_HIGH);
-
for (i = 0, in_l = (u32 *)din, out_l = (u32 *)dout;
i < n_blks;
i++, in_l++, out_l++, bitlen -= 32)
- *in_l = spi_xchg_single(*out_l, bitlen);
+ *in_l = spi_xchg_single(slave, *out_l, bitlen);
return 0;
}
@@ -132,17 +132,17 @@ void spi_init(void)
{
}
-int spi_select(unsigned int bus, unsigned int dev, unsigned long mode)
+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
+ unsigned int max_hz, unsigned int mode)
{
unsigned int ctrl_reg;
+ struct mxc_spi_slave *mxcs;
if (bus >= sizeof(spi_bases) / sizeof(spi_bases[0]) ||
- dev > 3)
- return 1;
-
- spi_base = spi_bases[bus];
+ cs > 3)
+ return NULL;
- ctrl_reg = MXC_CSPICTRL_CHIPSELECT(dev) |
+ ctrl_reg = MXC_CSPICTRL_CHIPSELECT(cs) |
MXC_CSPICTRL_BITCOUNT(31) |
MXC_CSPICTRL_DATARATE(7) | /* FIXME: calculate data rate */
MXC_CSPICTRL_EN |
@@ -155,12 +155,38 @@ int spi_select(unsigned int bus, unsigned int dev, unsigned long mode)
if (mode & SPI_CS_HIGH)
ctrl_reg |= MXC_CSPICTRL_SSPOL;
- reg_write(spi_base + MXC_CSPIRESET, 1);
+ mxcs = malloc(sizeof(struct mxc_spi_slave));
+ if (!mxcs)
+ return NULL;
+
+ mxcs->slave.bus = bus;
+ mxcs->slave.cs = cs;
+ mxcs->base = spi_bases[bus];
+ mxcs->ctrl_reg = ctrl_reg;
+
+ return &mxcs->slave;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+ free(slave);
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+ struct mxc_spi_slave *mxcs = to_mxc_spi_slave(slave);
+
+ reg_write(mxcs->base + MXC_CSPIRESET, 1);
udelay(1);
- reg_write(spi_base + MXC_CSPICTRL, ctrl_reg);
- reg_write(spi_base + MXC_CSPIPERIOD,
+ reg_write(mxcs->base + MXC_CSPICTRL, mxcs->ctrl_reg);
+ reg_write(mxcs->base + MXC_CSPIPERIOD,
MXC_CSPIPERIOD_32KHZ);
- reg_write(spi_base + MXC_CSPIINT, 0);
+ reg_write(mxcs->base + MXC_CSPIINT, 0);
return 0;
}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+ /* TODO: Shut the controller down */
+}
diff --git a/drivers/spi/spirom.c b/drivers/spi/spirom.c
new file mode 100644
index 0000000000..87c93668ed
--- /dev/null
+++ b/drivers/spi/spirom.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2007 b7 Spectrum Digital Incorporated.
+ * All rights reserved. Property of Spectrum Digital Incorporated.
+ */
+
+/*
+ * SPI ROM interface
+ *
+ */
+
+#include "spirom.h"
+
+static Uint8 spirombuf[SPIROM_PAGESIZE + 5];
+static Uint8 statusbuf[8];
+static Uint32 spidat1;
+
+/* ------------------------------------------------------------------------ *
+ * *
+ * _wait( delay ) *
+ * Wait in a software loop for 'x' delay *
+ * *
+ * ------------------------------------------------------------------------ */
+void DAVINCIHD_wait( Uint32 delay )
+{
+ volatile Uint32 i;
+ for ( i = 0 ; i < delay ; i++ ){ };
+}
+
+
+/* ------------------------------------------------------------------------ *
+ * spirom_init( ) *
+ * ------------------------------------------------------------------------ */
+void spirom_init( )
+{
+ /* Reset SPI */
+ SPI_SPIGCR0 = 0;
+ _wait( 1000 );
+
+ /* Release SPI */
+ SPI_SPIGCR0 = 1;
+
+ /* SPI 4-Pin Mode setup */
+ SPI_SPIGCR1 = 0
+ | ( 0 << 24 )
+ | ( 0 << 16 )
+ | ( 1 << 1 )
+ | ( 1 << 0 );
+
+ SPI_SPIPC0 = 0
+ | ( 1 << 11 ) // DI
+ | ( 1 << 10 ) // DO
+ | ( 1 << 9 ) // CLK
+ | ( 1 << 1 ) // EN1
+ | ( 1 << 0 ); // EN0
+
+ SPI_SPIFMT0 = 0
+ | ( 0 << 20 ) // SHIFTDIR
+ | ( 0 << 17 ) // Polarity
+ | ( 1 << 16 ) // Phase
+ | ( 50 << 8 ) // Prescale
+ | ( 8 << 0 ); // Char Len
+
+ spidat1 = 0
+ | ( 1 << 28 ) // CSHOLD
+ | ( 0 << 24 ) // Format [0]
+ | ( 2 << 16 ) // CSNR [only CS0 enbled]
+ | ( 0 << 0 ); //
+
+ SPI_SPIDAT1 = spidat1;
+
+ SPI_SPIDELAY = 0
+ | ( 8 << 24 ) // C2TDELAY
+ | ( 8 << 16 ); // T2CDELAY
+
+ SPI_SPIDEF = 0
+ | ( 1 << 1 ) // EN1 inactive high
+ | ( 1 << 0 ); // EN0 inactive high
+
+ SPI_SPIINT = 0
+ | ( 0 << 16 ) //
+ | ( 0 << 8 ) //
+ | ( 0 << 6 ) //
+ | ( 1 << 4 ); //
+
+ SPI_SPILVL = 0
+ | ( 0 << 8 ) // EN0
+ | ( 0 << 6 ) // EN0
+ | ( 0 << 4 ); // EN0
+
+
+ /* Enable SPI */
+ SPI_SPIGCR1 |= ( 1 << 24 );
+}
+
+/* ------------------------------------------------------------------------ *
+ * spirom_cycle( buf, len ) *
+ * *
+ * Execute a SPI spirom data transfer cycle. Each byte in buf is shifted *
+ * out and replaced with data coming back from the spirom. *
+ * ------------------------------------------------------------------------ */
+void spirom_cycle( Uint8 *buf, Uint16 len )
+{
+ Uint16 i;
+
+ /* Clear any old data */
+ SPI_SPIBUF;
+
+ /* SPIROM access cycle */
+ for ( i = 0 ; i <= len ; i++ )
+ {
+ /* Wait for transmit ready */
+ while ( SPI_SPIBUF & 0x10000000 );
+
+ if ( i == len )
+ SPI_SPIDAT1 = ( spidat1 & 0x0ffcffff ) | buf[i];
+ else
+ SPI_SPIDAT1 = spidat1 | buf[i];
+
+ /* Wait for receive data ready */
+ while ( SPI_SPIBUF & 0x80000000 );
+
+ /* Read 1 byte */
+ buf[i] = SPI_SPIBUF;
+ }
+}
+
+/* ------------------------------------------------------------------------ *
+ * spirom_status( ) *
+ * ------------------------------------------------------------------------ */
+Uint8 spirom_status( )
+{
+ /* Issue read status command */
+ statusbuf[0] = SPIROM_CMD_RDSR;
+ statusbuf[1] = 0;
+
+ spirom_cycle( statusbuf, 2 );
+
+ return statusbuf[1];
+}
+
+/* ------------------------------------------------------------------------ *
+ * spirom_read( src, dst, length ) *
+ * ------------------------------------------------------------------------ */
+void spirom_read( Uint16 src, Uint32 dst, Uint32 length )
+{
+ Int32 i;
+ Uint8 *psrc, *pdst;
+
+ // Setup command
+ spirombuf[0] = SPIROM_CMD_READ;
+ spirombuf[1] = ( src >> 8 );
+ spirombuf[2] = ( src >> 0 );
+
+ // Execute spirom read cycle
+ spirom_cycle( spirombuf, length + 3 );
+
+ // Copy returned data
+ pdst = ( Uint8 * )dst;
+ psrc = spirombuf + 3;
+ for ( i = 0 ; i < length ; i++ )
+ *pdst++ = *psrc++;
+}
+
+/* ------------------------------------------------------------------------ *
+ * spirom_write( src, dst, length ) *
+ * ------------------------------------------------------------------------ */
+void spirom_write( Uint32 src, Uint16 dst, Uint32 length )
+{
+ Int32 i;
+ Int32 bytes_left;
+ Int32 bytes_to_program;
+ Uint8 *psrc;
+
+ /* Establish source */
+ psrc = ( Uint8 * )src;
+ bytes_left = length;
+
+ while ( bytes_left > 0 )
+ {
+ bytes_to_program = bytes_left;
+
+ /* Most to program is SPIROM_CMD_BLOCKSIZE */
+ if ( bytes_to_program > SPIROM_PAGESIZE )
+ bytes_to_program = SPIROM_PAGESIZE;
+
+ /* Make sure you don't run off the end of a block */
+ if ( ( dst & SPIROM_PAGEMASK ) != ( ( dst + bytes_to_program ) & SPIROM_PAGEMASK ) )
+ bytes_to_program -= ( dst + bytes_to_program ) - ( ( dst + bytes_to_program ) & SPIROM_PAGEMASK );
+
+ /* Issue WPEN */
+ spirombuf[0] = SPIROM_CMD_WREN;
+ spirom_cycle( spirombuf, 0 );
+
+ /* Create command block for program operation */
+ spirombuf[0] = SPIROM_CMD_WRITE;
+ spirombuf[1] = ( Uint8 )( dst >> 8 );
+ spirombuf[2] = ( Uint8 )( dst );
+
+ for ( i = 0 ; i < bytes_to_program ; i++ )
+ spirombuf[3+i] = *psrc++;
+
+ /* Execute write command */
+ spirom_cycle( spirombuf, bytes_to_program + 2 );
+
+ /* Wait while busy */
+ while( ( spirom_status( ) & 0x01 ) );
+
+ /* Get ready for next iteration */
+ bytes_left -= bytes_to_program;
+ dst += bytes_to_program;
+ }
+}
diff --git a/drivers/spi/spirom.h b/drivers/spi/spirom.h
new file mode 100644
index 0000000000..2dfe3bc32f
--- /dev/null
+++ b/drivers/spi/spirom.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2007 by Spectrum Digital Incorporated.
+ * All rights reserved. Property of Spectrum Digital Incorporated.
+ */
+
+/*
+ * SPI ROM header file
+ *
+ */
+
+#ifndef SPIROM_
+#define SPIROM_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "davincihd.h"
+
+/* ------------------------------------------------------------------------ *
+ * SPI ROM Definitions *
+ * ------------------------------------------------------------------------ */
+#define SPIROM_SIZE 0x00008000
+#define SPIROM_BASE 0x00000000
+#define SPIROM_PAGESIZE 32
+#define SPIROM_PAGEMASK 0xffffffc0
+
+/* ------------------------------------------------------------------------ *
+ * SPI ROM Commands *
+ * ------------------------------------------------------------------------ */
+#define SPIROM_CMD_WRSR 0x01
+#define SPIROM_CMD_WRITE 0x02
+#define SPIROM_CMD_READ 0x03
+#define SPIROM_CMD_WRDI 0x04
+#define SPIROM_CMD_RDSR 0x05
+#define SPIROM_CMD_WREN 0x06
+
+/* ------------------------------------------------------------------------ *
+ * SPI Controller *
+ * ------------------------------------------------------------------------ */
+#define SPI_BASE 0x01c66800
+#define SPI_SPIGCR0 *( volatile Uint32* )( SPI_BASE + 0x0 )
+#define SPI_SPIGCR1 *( volatile Uint32* )( SPI_BASE + 0x4 )
+#define SPI_SPIINT *( volatile Uint32* )( SPI_BASE + 0x8 )
+#define SPI_SPILVL *( volatile Uint32* )( SPI_BASE + 0xc )
+#define SPI_SPIFLG *( volatile Uint32* )( SPI_BASE + 0x10 )
+#define SPI_SPIPC0 *( volatile Uint32* )( SPI_BASE + 0x14 )
+#define SPI_SPIPC2 *( volatile Uint32* )( SPI_BASE + 0x1c )
+#define SPI_SPIDAT1_TOP *( volatile Uint16* )( SPI_BASE + 0x3c )
+#define SPI_SPIDAT1 *( volatile Uint32* )( SPI_BASE + 0x3c )
+#define SPI_SPIDAT1_PTR16 *( volatile Uint16* )( SPI_BASE + 0x3e )
+#define SPI_SPIDAT1_PTR8 *( volatile Uint8* ) ( SPI_BASE + 0x3f )
+#define SPI_SPIBUF *( volatile Uint32* )( SPI_BASE + 0x40 )
+#define SPI_SPIBUF_PTR16 *( volatile Uint16* )( SPI_BASE + 0x42 )
+#define SPI_SPIBUF_PTR8 *( volatile Uint8* ) ( SPI_BASE + 0x43 )
+#define SPI_SPIEMU *( volatile Uint32* )( SPI_BASE + 0x44 )
+#define SPI_SPIDELAY *( volatile Uint32* )( SPI_BASE + 0x48 )
+#define SPI_SPIDEF *( volatile Uint32* )( SPI_BASE + 0x4c )
+#define SPI_SPIFMT0 *( volatile Uint32* )( SPI_BASE + 0x50 )
+#define SPI_SPIFMT1 *( volatile Uint32* )( SPI_BASE + 0x54 )
+#define SPI_SPIFMT2 *( volatile Uint32* )( SPI_BASE + 0x58 )
+#define SPI_SPIFMT3 *( volatile Uint32* )( SPI_BASE + 0x5c )
+#define SPI_INTVEC0 *( volatile Uint32* )( SPI_BASE + 0x60 )
+#define SPI_INTVEC1 *( volatile Uint32* )( SPI_BASE + 0x64 )
+
+/* ------------------------------------------------------------------------ *
+ * Prototype *
+ * ------------------------------------------------------------------------ */
+void spirom_init( );
+void spirom_read( Uint16 src, Uint32 dst, Uint32 length );
+void spirom_write( Uint32 src, Uint16 dst, Uint32 length );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif