
This patch adds an SPI driver for the 440EPx processor.
Tested on Sequoia.
Signed-off-by: Steven A. Falco sfalco@harris.com --- Thanks for the comments.
I've added the in/out accessors, and included the other comments made by reviewers (inlines, etc). The patch passes a checkpatch test.
drivers/spi/Makefile | 1 + drivers/spi/ppc4xx_spi.c | 141 ++++++++++++++++++++++++++++++++++++++++++ include/asm-ppc/ppc4xx_spi.h | 58 +++++++++++++++++ 3 files changed, 200 insertions(+), 0 deletions(-) create mode 100644 drivers/spi/ppc4xx_spi.c create mode 100644 include/asm-ppc/ppc4xx_spi.h
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 15e0f7a..a699760 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -28,6 +28,7 @@ LIB := $(obj)libspi.a COBJS-$(CONFIG_ATMEL_SPI) += atmel_spi.o COBJS-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o COBJS-$(CONFIG_MXC_SPI) += mxc_spi.o +COBJS-$(CONFIG_PPC4xx_SPI) += ppc4xx_spi.o COBJS-$(CONFIG_SOFT_SPI) += soft_spi.o
COBJS := $(COBJS-y) diff --git a/drivers/spi/ppc4xx_spi.c b/drivers/spi/ppc4xx_spi.c new file mode 100644 index 0000000..273f8c4 --- /dev/null +++ b/drivers/spi/ppc4xx_spi.c @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2008 Harris Corporation + * Author: Steven A. Falco sfalco@harris.com + * + * 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/ppc4xx_spi.h> + +void spi_init(void) +{ + spi4xx_t *spi = (spi4xx_t *) SPI_BASE_ADDR; + + out_8(&spi->cdm, 0); /* Default to the highest speed */ + out_8(&spi->mode, SPI_MODE_SPE); /* Enable the port */ +} + +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs, + unsigned int max_hz, unsigned int mode) +{ + spi4xx_t *spi = (spi4xx_t *) SPI_BASE_ADDR; + + ulong opb = get_OPB_freq(); + ulong divisor; + struct spi_slave *s; + + if (!spi_cs_is_valid(bus, cs)) + return NULL; + + divisor = ((opb + (max_hz * 4) - 1) / (max_hz * 4)) - 1; + if (divisor > 255) + return NULL; + + out_8(&spi->cdm, divisor); + + s = malloc(sizeof(struct spi_slave)); + if (!s) + return NULL; + + if (mode & SPI_CPHA) + clrbits_8(&spi->mode, SPI_MODE_SCP); + else + setbits_8(&spi->mode, SPI_MODE_SCP); + + if (mode & SPI_CPOL) + setbits_8(&spi->mode, SPI_MODE_CI); + else + clrbits_8(&spi->mode, SPI_MODE_CI); + + s->bus = bus; + s->cs = cs; + + return s; +} + +void spi_free_slave(struct spi_slave *slave) +{ + free(slave); +} + +int spi_claim_bus(struct spi_slave *slave) +{ + return 0; +} + +void spi_release_bus(struct spi_slave *slave) +{ +} + +/* Start an 8-bit transaction. */ +static inline void spi_start(spi4xx_t *spi) +{ + out_8(&spi->cr, SPI_CR_STR); +} + +/* Wait for the TX to be empty. */ +static inline void spi_tx_wait(spi4xx_t *spi) +{ + while (in_8(&spi->sr) & SPI_SR_BSY) + ; +} + +/* Wait for the RX to have data. */ +static inline void spi_rx_wait(spi4xx_t *spi) +{ + while (!(in_8(&spi->sr) & SPI_SR_RBR)) + ; +} + +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, + const void *dout, void *din, unsigned long flags) +{ + spi4xx_t *spi = (spi4xx_t *) SPI_BASE_ADDR; + + const u8 *txd = dout; + u8 *rxd = din; + int ii; + + if (flags & SPI_XFER_BEGIN) + spi_cs_activate(slave); + + /* Do a byte at a time */ + for (ii = 0; ii < ((bitlen + 7) / 8); ii++) { + /* Wait for room, then load the next byte. */ + spi_tx_wait(spi); + out_8(&spi->txd, *txd++); + + /* Send/receive 8 bits. */ + spi_start(spi); + + /* Wait for the incoming byte, then store it. */ + spi_rx_wait(spi); + *rxd++ = in_8(&spi->rxd); + } + + if (flags & SPI_XFER_END) + spi_cs_deactivate(slave); + + return 0; +} diff --git a/include/asm-ppc/ppc4xx_spi.h b/include/asm-ppc/ppc4xx_spi.h new file mode 100644 index 0000000..f908ef8 --- /dev/null +++ b/include/asm-ppc/ppc4xx_spi.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2008 Harris Corporation + * Author: Steven A. Falco sfalco@harris.com + * + * 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 + */ + +#ifndef _4xx_spi_h_ +#define _4xx_spi_h_ + +#include <asm/types.h> + +#if defined(CONFIG_440EPX) || \ + defined(CONFIG_440GRX) +#define SPI_BASE_ADDR (CONFIG_SYS_PERIPHERAL_BASE + 0x00000900) +#endif + +/* Bits in the command register */ +#define SPI_CR_STR 0x01 + +/* Bits in the status register */ +#define SPI_SR_RBR 0x01 +#define SPI_SR_BSY 0x02 + +/* Bits in the mode register */ +#define SPI_MODE_IL 0x01 +#define SPI_MODE_CI 0x02 +#define SPI_MODE_RD 0x04 +#define SPI_MODE_SPE 0x08 +#define SPI_MODE_SCP 0x10 + +typedef struct spi4xx { + u8 mode; /* mode register */ + u8 rxd; /* receive register */ + u8 txd; /* transmit register */ + u8 cr; /* command register */ + u8 sr; /* status register */ + u8 res0; /* reserved */ + u8 cdm; /* clock divisor */ +} spi4xx_t; + +#endif /* _4xx_spi_h_ */