From: Thomas Chou <thomas@wytron.com.tw>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH] spi: add new driver for OpenCores tiny_spi
Date: Sun, 9 Jan 2011 07:56:03 +0800 [thread overview]
Message-ID: <1294530963-8606-1-git-send-email-thomas@wytron.com.tw> (raw)
This patch adds support for OpenCores tiny_spi.
http://opencores.org/project,tiny_spi
Signed-off-by: Thomas Chou <thomas@wytron.com.tw>
---
drivers/spi/Makefile | 1 +
drivers/spi/oc_tiny_spi.c | 241 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 242 insertions(+), 0 deletions(-)
create mode 100644 drivers/spi/oc_tiny_spi.c
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index e34a124..8ad1d7f 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -35,6 +35,7 @@ COBJS-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
COBJS-$(CONFIG_MPC52XX_SPI) += mpc52xx_spi.o
COBJS-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o
COBJS-$(CONFIG_MXC_SPI) += mxc_spi.o
+COBJS-$(CONFIG_OC_TINY_SPI) += oc_tiny_spi.o
COBJS-$(CONFIG_OMAP3_SPI) += omap3_spi.o
COBJS-$(CONFIG_SOFT_SPI) += soft_spi.o
diff --git a/drivers/spi/oc_tiny_spi.c b/drivers/spi/oc_tiny_spi.c
new file mode 100644
index 0000000..c234d90
--- /dev/null
+++ b/drivers/spi/oc_tiny_spi.c
@@ -0,0 +1,241 @@
+/*
+ * Opencore tiny_spi driver
+ *
+ * http://opencores.org/project,tiny_spi
+ *
+ * based on bfin_spi.c
+ * Copyright (c) 2005-2008 Analog Devices Inc.
+ * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+#include <common.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <spi.h>
+#include <asm/gpio.h>
+#define TINY_SPI_RXDATA 0
+#define TINY_SPI_TXDATA 4
+#define TINY_SPI_STATUS 8
+#define TINY_SPI_CONTROL 12
+#define TINY_SPI_BAUD 16
+
+#define TINY_SPI_STATUS_TXE 0x1
+#define TINY_SPI_STATUS_TXR 0x2
+
+struct tiny_spi_host {
+ ulong base;
+ uint freq;
+ uint baudwidth;
+};
+static struct tiny_spi_host tiny_spi_host_list[] = CONFIG_SYS_TINY_SPI_LIST;
+
+struct tiny_spi_slave {
+ struct spi_slave slave;
+ struct tiny_spi_host *host;
+ uint mode;
+ uint baud;
+ uint flg;
+};
+#define to_tiny_spi_slave(s) container_of(s, struct tiny_spi_slave, slave)
+
+__attribute__((weak))
+int spi_cs_is_valid(unsigned int bus, unsigned int cs)
+{
+ return bus < ARRAY_SIZE(tiny_spi_host_list) && gpio_is_valid(cs);
+}
+
+__attribute__((weak))
+void spi_cs_activate(struct spi_slave *slave)
+{
+ struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
+ unsigned int cs = slave->cs;
+ gpio_set_value(cs, tiny_spi->flg);
+ debug("%s: SPI_CS_GPIO:%x\n", __func__, gpio_get_value(cs));
+}
+
+__attribute__((weak))
+void spi_cs_deactivate(struct spi_slave *slave)
+{
+ struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
+ unsigned int cs = slave->cs;
+ gpio_set_value(cs, !tiny_spi->flg);
+ debug("%s: SPI_CS_GPIO:%x\n", __func__, gpio_get_value(cs));
+}
+
+void spi_set_speed(struct spi_slave *slave, uint hz)
+{
+ struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
+ struct tiny_spi_host *host = tiny_spi->host;
+ tiny_spi->baud = DIV_ROUND_UP(host->freq, hz * 2) - 1;
+ if (tiny_spi->baud > (1 << host->baudwidth) - 1)
+ tiny_spi->baud = (1 << host->baudwidth) - 1;
+ debug("%s: speed %u actual %u\n", __func__, hz,
+ host->freq / ((tiny_spi->baud + 1) * 2));
+}
+
+void spi_init(void)
+{
+}
+
+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
+ unsigned int hz, unsigned int mode)
+{
+ struct tiny_spi_slave *tiny_spi;
+
+ if (!spi_cs_is_valid(bus, cs) || gpio_request(cs, "tiny_spi"))
+ return NULL;
+
+ tiny_spi = malloc(sizeof(*tiny_spi));
+ if (!tiny_spi)
+ return NULL;
+ memset(tiny_spi, 0, sizeof(*tiny_spi));
+
+ tiny_spi->slave.bus = bus;
+ tiny_spi->slave.cs = cs;
+ tiny_spi->host = &tiny_spi_host_list[bus];
+ tiny_spi->mode = mode & (SPI_CPOL | SPI_CPHA);
+ tiny_spi->flg = mode & SPI_CS_HIGH ? 1 : 0;
+ spi_set_speed(&tiny_spi->slave, hz);
+
+ debug("%s: bus:%i cs:%i base:%lx\n", __func__,
+ bus, cs, tiny_spi->host->base);
+ return &tiny_spi->slave;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+ struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
+ gpio_free(slave->cs);
+ free(tiny_spi);
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+ struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
+ struct tiny_spi_host *host = tiny_spi->host;
+ debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
+ gpio_direction_output(slave->cs, !tiny_spi->flg);
+ writel(tiny_spi->mode, host->base + TINY_SPI_CONTROL);
+ writel(tiny_spi->baud, host->base + TINY_SPI_BAUD);
+ return 0;
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+ debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
+}
+
+#ifndef CONFIG_TINY_SPI_IDLE_VAL
+# define CONFIG_TINY_SPI_IDLE_VAL 0xff
+#endif
+
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
+ void *din, unsigned long flags)
+{
+ struct tiny_spi_host *host = to_tiny_spi_slave(slave)->host;
+ const u8 *txp = dout;
+ u8 *rxp = din;
+ uint bytes = bitlen / 8;
+ uint i;
+
+ 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;
+
+ /* assume to do 8 bits transfers */
+ if (bitlen % 8) {
+ flags |= SPI_XFER_END;
+ goto done;
+ }
+
+ if (flags & SPI_XFER_BEGIN)
+ spi_cs_activate(slave);
+
+ /* we need to tighten the transfer loop */
+ if (txp && rxp) {
+ writeb(*txp++, host->base + TINY_SPI_TXDATA);
+ if (bytes > 1) {
+ writeb(*txp++, host->base + TINY_SPI_TXDATA);
+ for (i = 2; i < bytes; i++) {
+ u8 rx, tx = *txp++;
+ while (!(readb(host->base + TINY_SPI_STATUS) &
+ TINY_SPI_STATUS_TXR))
+ ;
+ rx = readb(host->base + TINY_SPI_TXDATA);
+ writeb(tx, host->base + TINY_SPI_TXDATA);
+ *rxp++ = rx;
+ }
+ while (!(readb(host->base + TINY_SPI_STATUS) &
+ TINY_SPI_STATUS_TXR))
+ ;
+ *rxp++ = readb(host->base + TINY_SPI_TXDATA);
+ }
+ while (!(readb(host->base + TINY_SPI_STATUS) &
+ TINY_SPI_STATUS_TXE))
+ ;
+ *rxp++ = readb(host->base + TINY_SPI_RXDATA);
+ } else if (rxp) {
+ writeb(CONFIG_TINY_SPI_IDLE_VAL, host->base + TINY_SPI_TXDATA);
+ if (bytes > 1) {
+ writeb(CONFIG_TINY_SPI_IDLE_VAL,
+ host->base + TINY_SPI_TXDATA);
+ for (i = 2; i < bytes; i++) {
+ u8 rx;
+ while (!(readb(host->base + TINY_SPI_STATUS) &
+ TINY_SPI_STATUS_TXR))
+ ;
+ rx = readb(host->base + TINY_SPI_TXDATA);
+ writeb(CONFIG_TINY_SPI_IDLE_VAL,
+ host->base + TINY_SPI_TXDATA);
+ *rxp++ = rx;
+ }
+ while (!(readb(host->base + TINY_SPI_STATUS) &
+ TINY_SPI_STATUS_TXR))
+ ;
+ *rxp++ = readb(host->base + TINY_SPI_TXDATA);
+ }
+ while (!(readb(host->base + TINY_SPI_STATUS) &
+ TINY_SPI_STATUS_TXE))
+ ;
+ *rxp++ = readb(host->base + TINY_SPI_RXDATA);
+ } else if (txp) {
+ writeb(*txp++, host->base + TINY_SPI_TXDATA);
+ if (bytes > 1) {
+ writeb(*txp++, host->base + TINY_SPI_TXDATA);
+ for (i = 2; i < bytes; i++) {
+ u8 tx = *txp++;
+ while (!(readb(host->base + TINY_SPI_STATUS) &
+ TINY_SPI_STATUS_TXR))
+ ;
+ writeb(tx, host->base + TINY_SPI_TXDATA);
+ }
+ }
+ while (!(readb(host->base + TINY_SPI_STATUS) &
+ TINY_SPI_STATUS_TXE))
+ ;
+ } else {
+ writeb(CONFIG_TINY_SPI_IDLE_VAL, host->base + TINY_SPI_TXDATA);
+ if (bytes > 1) {
+ writeb(CONFIG_TINY_SPI_IDLE_VAL,
+ host->base + TINY_SPI_TXDATA);
+ for (i = 2; i < bytes; i++) {
+ while (!(readb(host->base + TINY_SPI_STATUS) &
+ TINY_SPI_STATUS_TXR))
+ ;
+ writeb(CONFIG_TINY_SPI_IDLE_VAL,
+ host->base + TINY_SPI_TXDATA);
+ }
+ }
+ while (!(readb(host->base + TINY_SPI_STATUS) &
+ TINY_SPI_STATUS_TXE))
+ ;
+ }
+
+ done:
+ if (flags & SPI_XFER_END)
+ spi_cs_deactivate(slave);
+
+ return 0;
+}
--
1.7.3.4
next reply other threads:[~2011-01-08 23:56 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-01-08 23:56 Thomas Chou [this message]
2011-01-09 1:44 ` [U-Boot] [PATCH] spi: add new driver for OpenCores tiny_spi Mike Frysinger
2011-01-10 2:24 ` [U-Boot] [PATCH v2] " Thomas Chou
2011-01-17 21:23 ` Wolfgang Denk
2011-01-18 2:08 ` Thomas Chou
2011-01-18 4:09 ` [U-Boot] [PATCH v3] " Thomas Chou
2011-04-11 19:54 ` Wolfgang Denk
2011-04-12 5:48 ` [U-Boot] [PATCH v4] " Thomas Chou
2011-04-30 19:02 ` Wolfgang Denk
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=1294530963-8606-1-git-send-email-thomas@wytron.com.tw \
--to=thomas@wytron.com.tw \
--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.