From: Graeme Smecher <graeme.smecher@mail.mcgill.ca>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH] Adds driver for Xilinx' xps_spi SPI controller
Date: Tue, 27 Jul 2010 10:02:22 -0400 [thread overview]
Message-ID: <4C4EE6EE.1060008@mail.mcgill.ca> (raw)
In-Reply-To: <1280238970-21591-2-git-send-email-graeme.smecher@mail.mcgill.ca>
Hi all,
I neglected to point out that this driver has been tested with Thomas
Chou's mmc_spi patches, and appears to work with SPI flash (Winbond
w25q64) as well.
A quick diff shows this driver is nearly identical to the altera_spi
driver. The only differences are:
* the CS register is active-low here, and
* the control register requires some additional setup.
cheers,
Graeme Smecher
On 10-07-27 09:56 AM, Graeme Smecher wrote:
> ---
> drivers/spi/Makefile | 1 +
> drivers/spi/xilinx_spi.c | 171 ++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 172 insertions(+), 0 deletions(-)
> create mode 100644 drivers/spi/xilinx_spi.c
>
> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
> index dfcbb8b..34e0f31 100644
> --- a/drivers/spi/Makefile
> +++ b/drivers/spi/Makefile
> @@ -26,6 +26,7 @@ include $(TOPDIR)/config.mk
> LIB := $(obj)libspi.a
>
> COBJS-$(CONFIG_ALTERA_SPI) += altera_spi.o
> +COBJS-$(CONFIG_XILINX_SPI) += xilinx_spi.o
> COBJS-$(CONFIG_ATMEL_DATAFLASH_SPI) += atmel_dataflash_spi.o
> COBJS-$(CONFIG_ATMEL_SPI) += atmel_spi.o
> COBJS-$(CONFIG_BFIN_SPI) += bfin_spi.o
> diff --git a/drivers/spi/xilinx_spi.c b/drivers/spi/xilinx_spi.c
> new file mode 100644
> index 0000000..99ce661
> --- /dev/null
> +++ b/drivers/spi/xilinx_spi.c
> @@ -0,0 +1,171 @@
> +/*
> + * Xilinx SPI driver
> + *
> + * based on bfin_spi.c, by way of altera_spi.c
> + * Copyright (c) 2005-2008 Analog Devices Inc.
> + * Copyright (c) 2010 Thomas Chou<thomas@wytron.com.tw>
> + * Copyright (c) 2010 Graeme Smecher<graeme.smecher@mail.mcgill.ca>
> + *
> + * Licensed under the GPL-2 or later.
> + */
> +#include<common.h>
> +#include<asm/io.h>
> +#include<malloc.h>
> +#include<spi.h>
> +
> +#define debug printf
> +
> +#define XILINX_SPI_RR 0x6c
> +#define XILINX_SPI_TR 0x68
> +#define XILINX_SPI_SR 0x64
> +#define XILINX_SPI_CR 0x60
> +#define XILINX_SPI_SSR 0x70
> +
> +#define XILINX_SPI_SR_RX_EMPTY_MSK 0x01
> +
> +#define XILINX_SPI_CR_DEFAULT (0x0086)
> +
> +#if XPAR_XSPI_NUM_INSTANCES> 4
> +# warning "The xilinx_spi driver will ignore some of your SPI peripherals!"
> +#endif
> +
> +static ulong xilinx_spi_base_list[] = {
> +#ifdef XPAR_SPI_0_BASEADDR
> + XPAR_SPI_0_BASEADDR,
> +#endif
> +#ifdef XPAR_SPI_1_BASEADDR
> + XPAR_SPI_1_BASEADDR,
> +#endif
> +#ifdef XPAR_SPI_2_BASEADDR
> + XPAR_SPI_2_BASEADDR,
> +#endif
> +#ifdef XPAR_SPI_3_BASEADDR
> + XPAR_SPI_3_BASEADDR,
> +#endif
> +};
> +
> +struct xilinx_spi_slave {
> + struct spi_slave slave;
> + ulong base;
> +};
> +#define to_xilinx_spi_slave(s) container_of(s, struct xilinx_spi_slave, slave)
> +
> +__attribute__((weak))
> +int spi_cs_is_valid(unsigned int bus, unsigned int cs)
> +{
> + return bus< ARRAY_SIZE(xilinx_spi_base_list)&& cs< 32;
> +}
> +
> +__attribute__((weak))
> +void spi_cs_activate(struct spi_slave *slave)
> +{
> + struct xilinx_spi_slave *xilspi = to_xilinx_spi_slave(slave);
> + writel(~(1<< slave->cs), xilspi->base + XILINX_SPI_SSR);
> +}
> +
> +__attribute__((weak))
> +void spi_cs_deactivate(struct spi_slave *slave)
> +{
> + struct xilinx_spi_slave *xilspi = to_xilinx_spi_slave(slave);
> + writel(~0, xilspi->base + XILINX_SPI_SSR);
> +}
> +
> +void spi_init(void)
> +{
> +}
> +
> +struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
> + unsigned int max_hz, unsigned int mode)
> +{
> + struct xilinx_spi_slave *xilspi;
> +
> + if (!spi_cs_is_valid(bus, cs))
> + return NULL;
> +
> + xilspi = malloc(sizeof(*xilspi));
> + if (!xilspi)
> + return NULL;
> +
> + xilspi->slave.bus = bus;
> + xilspi->slave.cs = cs;
> + xilspi->base = xilinx_spi_base_list[bus];
> + debug("%s: bus:%i cs:%i base:%lx\n", __func__,
> + bus, cs, xilspi->base);
> +
> + writel(XILINX_SPI_CR_DEFAULT, xilspi->base + XILINX_SPI_CR);
> +
> + return&xilspi->slave;
> +}
> +
> +void spi_free_slave(struct spi_slave *slave)
> +{
> + struct xilinx_spi_slave *xilspi = to_xilinx_spi_slave(slave);
> + free(xilspi);
> +}
> +
> +int spi_claim_bus(struct spi_slave *slave)
> +{
> + struct xilinx_spi_slave *xilspi = to_xilinx_spi_slave(slave);
> +
> + debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
> + writel(~0, xilspi->base + XILINX_SPI_SSR);
> + return 0;
> +}
> +
> +void spi_release_bus(struct spi_slave *slave)
> +{
> + struct xilinx_spi_slave *xilspi = to_xilinx_spi_slave(slave);
> +
> + debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
> + writel(~0, xilspi->base + XILINX_SPI_SSR);
> +}
> +
> +#ifndef CONFIG_XILINX_SPI_IDLE_VAL
> +# define CONFIG_XILINX_SPI_IDLE_VAL 0xff
> +#endif
> +
> +int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
> + void *din, unsigned long flags)
> +{
> + struct xilinx_spi_slave *xilspi = to_xilinx_spi_slave(slave);
> + /* assume spi core configured to do 8 bit transfers */
> + uint bytes = bitlen / 8;
> + const uchar *txp = dout;
> + uchar *rxp = din;
> +
> + debug("%s: bus:%i cs:%i bitlen:%i bytes:%i flags:%lx\n", __func__,
> + slave->bus, slave->cs, bitlen, bytes, flags);
> + if (bitlen == 0)
> + goto done;
> +
> + if (bitlen % 8) {
> + flags |= SPI_XFER_END;
> + goto done;
> + }
> +
> + /* empty read buffer */
> + while (!(readl(xilspi->base + XILINX_SPI_SR)&
> + XILINX_SPI_SR_RX_EMPTY_MSK))
> + readl(xilspi->base + XILINX_SPI_RR);
> +
> + if (flags& SPI_XFER_BEGIN)
> + spi_cs_activate(slave);
> +
> + while (bytes--) {
> + uchar d = txp ? *txp++ : CONFIG_XILINX_SPI_IDLE_VAL;
> + debug("%s: tx:%x ", __func__, d);
> + writel(d, xilspi->base + XILINX_SPI_TR);
> + while (readl(xilspi->base + XILINX_SPI_SR)&
> + XILINX_SPI_SR_RX_EMPTY_MSK)
> + ;
> + d = readl(xilspi->base + XILINX_SPI_RR);
> + if (rxp)
> + *rxp++ = d;
> + debug("rx:%x\n", d);
> + }
> + done:
> + if (flags& SPI_XFER_END)
> + spi_cs_deactivate(slave);
> +
> + return 0;
> +}
next prev parent reply other threads:[~2010-07-27 14:02 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-07-27 13:56 [U-Boot] Adds driver for Xilinx' xps_spi SPI controller Graeme Smecher
2010-07-27 13:56 ` [U-Boot] [PATCH] " Graeme Smecher
2010-07-27 14:02 ` Graeme Smecher [this message]
-- strict thread matches above, loose matches on Subject: below --
2010-08-03 15:47 Graeme Smecher
2010-08-03 17:59 ` Mike Frysinger
2010-08-04 21:01 ` Graeme Smecher
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4C4EE6EE.1060008@mail.mcgill.ca \
--to=graeme.smecher@mail.mcgill.ca \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.