* [U-Boot] [PATCH] spi: add new driver for OpenCores tiny_spi
@ 2011-01-08 23:56 Thomas Chou
2011-01-09 1:44 ` Mike Frysinger
0 siblings, 1 reply; 9+ messages in thread
From: Thomas Chou @ 2011-01-08 23:56 UTC (permalink / raw)
To: u-boot
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
^ permalink raw reply related [flat|nested] 9+ messages in thread* [U-Boot] [PATCH] spi: add new driver for OpenCores tiny_spi
2011-01-08 23:56 [U-Boot] [PATCH] spi: add new driver for OpenCores tiny_spi Thomas Chou
@ 2011-01-09 1:44 ` Mike Frysinger
2011-01-10 2:24 ` [U-Boot] [PATCH v2] " Thomas Chou
0 siblings, 1 reply; 9+ messages in thread
From: Mike Frysinger @ 2011-01-09 1:44 UTC (permalink / raw)
To: u-boot
On Saturday, January 08, 2011 18:56:03 Thomas Chou wrote:
> + */
> +#include <common.h>
space between comment and includes
> +#include <asm/gpio.h>
> +#define TINY_SPI_RXDATA 0
space between includes and defines
> +static struct tiny_spi_host tiny_spi_host_list[] =
CONFIG_SYS_TINY_SPI_LIST;
i think you only read this, so you'll want to add "const"
> +__attribute__((weak))
> +int spi_cs_is_valid(unsigned int bus, unsigned int cs)
> +
> +__attribute__((weak))
> +void spi_cs_activate(struct spi_slave *slave)
> +
> +__attribute__((weak))
> +void spi_cs_deactivate(struct spi_slave *slave)
only reason i had these marked weak in the Blackfin SPI driver was because i
didn't support GPIO CS's. now that that's fixed, i dropped the weak markings.
either way is fine of course; just giving some background info.
> + 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;
might be simpler to use:
tiny_spi->baud = max(DIV_ROUND_UP(host->freq, hz * 2),
(1 << host->baudwidth)) - 1;
otherwise code looks fine
-mike
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: This is a digitally signed message part.
Url : http://lists.denx.de/pipermail/u-boot/attachments/20110108/25ee407c/attachment.pgp
^ permalink raw reply [flat|nested] 9+ messages in thread
* [U-Boot] [PATCH v2] spi: add new driver for OpenCores tiny_spi
2011-01-09 1:44 ` Mike Frysinger
@ 2011-01-10 2:24 ` Thomas Chou
2011-01-17 21:23 ` Wolfgang Denk
0 siblings, 1 reply; 9+ messages in thread
From: Thomas Chou @ 2011-01-10 2:24 UTC (permalink / raw)
To: u-boot
This patch adds support for OpenCores tiny_spi.
http://opencores.org/project,tiny_spi
Signed-off-by: Thomas Chou <thomas@wytron.com.tw>
---
for u-boot
v2, use const and clean up as Mike suggested.
drivers/spi/Makefile | 1 +
drivers/spi/oc_tiny_spi.c | 240 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 241 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..b61cb7a
--- /dev/null
+++ b/drivers/spi/oc_tiny_spi.c
@@ -0,0 +1,240 @@
+/*
+ * 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 const struct tiny_spi_host tiny_spi_host_list[] =
+ CONFIG_SYS_TINY_SPI_LIST;
+
+struct tiny_spi_slave {
+ struct spi_slave slave;
+ const 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)
+
+int spi_cs_is_valid(unsigned int bus, unsigned int cs)
+{
+ return bus < ARRAY_SIZE(tiny_spi_host_list) && gpio_is_valid(cs);
+}
+
+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));
+}
+
+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);
+ const struct tiny_spi_host *host = tiny_spi->host;
+ tiny_spi->baud = min(DIV_ROUND_UP(host->freq, hz * 2),
+ (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);
+ const 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)
+{
+ const 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
^ permalink raw reply related [flat|nested] 9+ messages in thread* [U-Boot] [PATCH v2] spi: add new driver for OpenCores tiny_spi
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
0 siblings, 2 replies; 9+ messages in thread
From: Wolfgang Denk @ 2011-01-17 21:23 UTC (permalink / raw)
To: u-boot
Dear Thomas Chou,
In message <1294626279-8601-1-git-send-email-thomas@wytron.com.tw> you wrote:
> This patch adds support for OpenCores tiny_spi.
>
> http://opencores.org/project,tiny_spi
>
> Signed-off-by: Thomas Chou <thomas@wytron.com.tw>
> ---
> for u-boot
> v2, use const and clean up as Mike suggested.
...
> +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));
> +}
Please separate declartations and code with a blank line. Please fix
globally.
...
> +int spi_claim_bus(struct spi_slave *slave)
> +{
> + struct tiny_spi_slave *tiny_spi = to_tiny_spi_slave(slave);
> + const 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);
Please do not use base + offset notation. Use a proper C struct
instead. Please fix globally.
Best regards,
Wolfgang Denk
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
A conservative is a man who believes that nothing should be done for
the first time. - Alfred E. Wiggam
^ permalink raw reply [flat|nested] 9+ messages in thread* [U-Boot] [PATCH v2] spi: add new driver for OpenCores tiny_spi
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
1 sibling, 0 replies; 9+ messages in thread
From: Thomas Chou @ 2011-01-18 2:08 UTC (permalink / raw)
To: u-boot
Dear Wolfgang,
On 01/18/2011 05:23 AM, Wolfgang Denk wrote:
> Please separate declartations and code with a blank line. Please fix
> globally.
> Please do not use base + offset notation. Use a proper C struct
> instead. Please fix globally.
Thank you very much for the coding style correction. I will follow them.
Best regards,
Thomas
^ permalink raw reply [flat|nested] 9+ messages in thread
* [U-Boot] [PATCH v3] spi: add new driver for OpenCores tiny_spi
2011-01-17 21:23 ` Wolfgang Denk
2011-01-18 2:08 ` Thomas Chou
@ 2011-01-18 4:09 ` Thomas Chou
2011-04-11 19:54 ` Wolfgang Denk
1 sibling, 1 reply; 9+ messages in thread
From: Thomas Chou @ 2011-01-18 4:09 UTC (permalink / raw)
To: u-boot
This patch adds support for OpenCores tiny_spi.
http://opencores.org/project,tiny_spi
Signed-off-by: Thomas Chou <thomas@wytron.com.tw>
---
for u-boot
v2, use const and clean up as Mike suggested.
v3, use struct instead of base+offset as Wolfgang suggested.
drivers/spi/Makefile | 1 +
drivers/spi/oc_tiny_spi.c | 248 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 249 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..f379da1
--- /dev/null
+++ b/drivers/spi/oc_tiny_spi.c
@@ -0,0 +1,248 @@
+/*
+ * 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_STATUS_TXE 0x1
+#define TINY_SPI_STATUS_TXR 0x2
+
+struct tiny_spi_regs {
+ volatile unsigned rxdata; /* Rx data reg */
+ volatile unsigned txdata; /* Tx data reg */
+ volatile unsigned status; /* Status reg */
+ volatile unsigned control; /* Control reg */
+ volatile unsigned baud; /* Baud reg */
+};
+
+struct tiny_spi_host {
+ uint base;
+ uint freq;
+ uint baudwidth;
+};
+static const struct tiny_spi_host tiny_spi_host_list[] =
+ CONFIG_SYS_TINY_SPI_LIST;
+
+struct tiny_spi_slave {
+ struct spi_slave slave;
+ const 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)
+
+int spi_cs_is_valid(unsigned int bus, unsigned int cs)
+{
+ return bus < ARRAY_SIZE(tiny_spi_host_list) && gpio_is_valid(cs);
+}
+
+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));
+}
+
+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);
+ const struct tiny_spi_host *host = tiny_spi->host;
+
+ tiny_spi->baud = min(DIV_ROUND_UP(host->freq, hz * 2),
+ (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_regs *regs = (void *)tiny_spi->host->base;
+
+ debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
+ gpio_direction_output(slave->cs, !tiny_spi->flg);
+ writel(tiny_spi->mode, ®s->control);
+ writel(tiny_spi->baud, ®s->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_slave *tiny_spi = to_tiny_spi_slave(slave);
+ struct tiny_spi_regs *regs = (void *)tiny_spi->host->base;
+ 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++, ®s->txdata);
+ if (bytes > 1) {
+ writeb(*txp++, ®s->txdata);
+ for (i = 2; i < bytes; i++) {
+ u8 rx, tx = *txp++;
+ while (!(readb(®s->status) &
+ TINY_SPI_STATUS_TXR))
+ ;
+ rx = readb(®s->txdata);
+ writeb(tx, ®s->txdata);
+ *rxp++ = rx;
+ }
+ while (!(readb(®s->status) &
+ TINY_SPI_STATUS_TXR))
+ ;
+ *rxp++ = readb(®s->txdata);
+ }
+ while (!(readb(®s->status) &
+ TINY_SPI_STATUS_TXE))
+ ;
+ *rxp++ = readb(®s->rxdata);
+ } else if (rxp) {
+ writeb(CONFIG_TINY_SPI_IDLE_VAL, ®s->txdata);
+ if (bytes > 1) {
+ writeb(CONFIG_TINY_SPI_IDLE_VAL,
+ ®s->txdata);
+ for (i = 2; i < bytes; i++) {
+ u8 rx;
+ while (!(readb(®s->status) &
+ TINY_SPI_STATUS_TXR))
+ ;
+ rx = readb(®s->txdata);
+ writeb(CONFIG_TINY_SPI_IDLE_VAL,
+ ®s->txdata);
+ *rxp++ = rx;
+ }
+ while (!(readb(®s->status) &
+ TINY_SPI_STATUS_TXR))
+ ;
+ *rxp++ = readb(®s->txdata);
+ }
+ while (!(readb(®s->status) &
+ TINY_SPI_STATUS_TXE))
+ ;
+ *rxp++ = readb(®s->rxdata);
+ } else if (txp) {
+ writeb(*txp++, ®s->txdata);
+ if (bytes > 1) {
+ writeb(*txp++, ®s->txdata);
+ for (i = 2; i < bytes; i++) {
+ u8 tx = *txp++;
+ while (!(readb(®s->status) &
+ TINY_SPI_STATUS_TXR))
+ ;
+ writeb(tx, ®s->txdata);
+ }
+ }
+ while (!(readb(®s->status) &
+ TINY_SPI_STATUS_TXE))
+ ;
+ } else {
+ writeb(CONFIG_TINY_SPI_IDLE_VAL, ®s->txdata);
+ if (bytes > 1) {
+ writeb(CONFIG_TINY_SPI_IDLE_VAL,
+ ®s->txdata);
+ for (i = 2; i < bytes; i++) {
+ while (!(readb(®s->status) &
+ TINY_SPI_STATUS_TXR))
+ ;
+ writeb(CONFIG_TINY_SPI_IDLE_VAL,
+ ®s->txdata);
+ }
+ }
+ while (!(readb(®s->status) &
+ TINY_SPI_STATUS_TXE))
+ ;
+ }
+
+ done:
+ if (flags & SPI_XFER_END)
+ spi_cs_deactivate(slave);
+
+ return 0;
+}
--
1.7.3.4
^ permalink raw reply related [flat|nested] 9+ messages in thread* [U-Boot] [PATCH v3] spi: add new driver for OpenCores tiny_spi
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
0 siblings, 1 reply; 9+ messages in thread
From: Wolfgang Denk @ 2011-04-11 19:54 UTC (permalink / raw)
To: u-boot
Dear Thomas Chou,
In message <1295323751-12085-1-git-send-email-thomas@wytron.com.tw> you wrote:
> This patch adds support for OpenCores tiny_spi.
>
> http://opencores.org/project,tiny_spi
>
> Signed-off-by: Thomas Chou <thomas@wytron.com.tw>
> ---
> for u-boot
> v2, use const and clean up as Mike suggested.
> v3, use struct instead of base+offset as Wolfgang suggested.
>
> drivers/spi/Makefile | 1 +
> drivers/spi/oc_tiny_spi.c | 248 +++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 249 insertions(+), 0 deletions(-)
> create mode 100644 drivers/spi/oc_tiny_spi.c
Sorry, but I see only now trhat there is an issue left:
> +struct tiny_spi_regs {
> + volatile unsigned rxdata; /* Rx data reg */
> + volatile unsigned txdata; /* Tx data reg */
> + volatile unsigned status; /* Status reg */
> + volatile unsigned control; /* Control reg */
> + volatile unsigned baud; /* Baud reg */
> +};
Please drop all these volatiles; see
Documentation/volatile-considered-harmful.txt in the Linux source
tree.
Thanks.
Wolfgang Denk
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
Accident: A condition in which presence of mind is good, but absence
of body is better.
^ permalink raw reply [flat|nested] 9+ messages in thread* [U-Boot] [PATCH v4] spi: add new driver for OpenCores tiny_spi
2011-04-11 19:54 ` Wolfgang Denk
@ 2011-04-12 5:48 ` Thomas Chou
2011-04-30 19:02 ` Wolfgang Denk
0 siblings, 1 reply; 9+ messages in thread
From: Thomas Chou @ 2011-04-12 5:48 UTC (permalink / raw)
To: u-boot
This patch adds support for OpenCores tiny_spi.
http://opencores.org/project,tiny_spi
Signed-off-by: Thomas Chou <thomas@wytron.com.tw>
---
for u-boot
v2, use const and clean up as Mike suggested.
v3, use struct instead of base+offset as Wolfgang suggested.
v4, remove volatile in regs def.
drivers/spi/Makefile | 1 +
drivers/spi/oc_tiny_spi.c | 248 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 249 insertions(+), 0 deletions(-)
create mode 100644 drivers/spi/oc_tiny_spi.c
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index d582fbb..a9fcfe7 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
COBJS-$(CONFIG_SH_SPI) += sh_spi.o
diff --git a/drivers/spi/oc_tiny_spi.c b/drivers/spi/oc_tiny_spi.c
new file mode 100644
index 0000000..fc01fb8
--- /dev/null
+++ b/drivers/spi/oc_tiny_spi.c
@@ -0,0 +1,248 @@
+/*
+ * 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_STATUS_TXE 0x1
+#define TINY_SPI_STATUS_TXR 0x2
+
+struct tiny_spi_regs {
+ unsigned rxdata; /* Rx data reg */
+ unsigned txdata; /* Tx data reg */
+ unsigned status; /* Status reg */
+ unsigned control; /* Control reg */
+ unsigned baud; /* Baud reg */
+};
+
+struct tiny_spi_host {
+ uint base;
+ uint freq;
+ uint baudwidth;
+};
+static const struct tiny_spi_host tiny_spi_host_list[] =
+ CONFIG_SYS_TINY_SPI_LIST;
+
+struct tiny_spi_slave {
+ struct spi_slave slave;
+ const 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)
+
+int spi_cs_is_valid(unsigned int bus, unsigned int cs)
+{
+ return bus < ARRAY_SIZE(tiny_spi_host_list) && gpio_is_valid(cs);
+}
+
+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));
+}
+
+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);
+ const struct tiny_spi_host *host = tiny_spi->host;
+
+ tiny_spi->baud = min(DIV_ROUND_UP(host->freq, hz * 2),
+ (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_regs *regs = (void *)tiny_spi->host->base;
+
+ debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
+ gpio_direction_output(slave->cs, !tiny_spi->flg);
+ writel(tiny_spi->mode, ®s->control);
+ writel(tiny_spi->baud, ®s->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_slave *tiny_spi = to_tiny_spi_slave(slave);
+ struct tiny_spi_regs *regs = (void *)tiny_spi->host->base;
+ 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++, ®s->txdata);
+ if (bytes > 1) {
+ writeb(*txp++, ®s->txdata);
+ for (i = 2; i < bytes; i++) {
+ u8 rx, tx = *txp++;
+ while (!(readb(®s->status) &
+ TINY_SPI_STATUS_TXR))
+ ;
+ rx = readb(®s->txdata);
+ writeb(tx, ®s->txdata);
+ *rxp++ = rx;
+ }
+ while (!(readb(®s->status) &
+ TINY_SPI_STATUS_TXR))
+ ;
+ *rxp++ = readb(®s->txdata);
+ }
+ while (!(readb(®s->status) &
+ TINY_SPI_STATUS_TXE))
+ ;
+ *rxp++ = readb(®s->rxdata);
+ } else if (rxp) {
+ writeb(CONFIG_TINY_SPI_IDLE_VAL, ®s->txdata);
+ if (bytes > 1) {
+ writeb(CONFIG_TINY_SPI_IDLE_VAL,
+ ®s->txdata);
+ for (i = 2; i < bytes; i++) {
+ u8 rx;
+ while (!(readb(®s->status) &
+ TINY_SPI_STATUS_TXR))
+ ;
+ rx = readb(®s->txdata);
+ writeb(CONFIG_TINY_SPI_IDLE_VAL,
+ ®s->txdata);
+ *rxp++ = rx;
+ }
+ while (!(readb(®s->status) &
+ TINY_SPI_STATUS_TXR))
+ ;
+ *rxp++ = readb(®s->txdata);
+ }
+ while (!(readb(®s->status) &
+ TINY_SPI_STATUS_TXE))
+ ;
+ *rxp++ = readb(®s->rxdata);
+ } else if (txp) {
+ writeb(*txp++, ®s->txdata);
+ if (bytes > 1) {
+ writeb(*txp++, ®s->txdata);
+ for (i = 2; i < bytes; i++) {
+ u8 tx = *txp++;
+ while (!(readb(®s->status) &
+ TINY_SPI_STATUS_TXR))
+ ;
+ writeb(tx, ®s->txdata);
+ }
+ }
+ while (!(readb(®s->status) &
+ TINY_SPI_STATUS_TXE))
+ ;
+ } else {
+ writeb(CONFIG_TINY_SPI_IDLE_VAL, ®s->txdata);
+ if (bytes > 1) {
+ writeb(CONFIG_TINY_SPI_IDLE_VAL,
+ ®s->txdata);
+ for (i = 2; i < bytes; i++) {
+ while (!(readb(®s->status) &
+ TINY_SPI_STATUS_TXR))
+ ;
+ writeb(CONFIG_TINY_SPI_IDLE_VAL,
+ ®s->txdata);
+ }
+ }
+ while (!(readb(®s->status) &
+ TINY_SPI_STATUS_TXE))
+ ;
+ }
+
+ done:
+ if (flags & SPI_XFER_END)
+ spi_cs_deactivate(slave);
+
+ return 0;
+}
--
1.7.4.2
^ permalink raw reply related [flat|nested] 9+ messages in thread* [U-Boot] [PATCH v4] spi: add new driver for OpenCores tiny_spi
2011-04-12 5:48 ` [U-Boot] [PATCH v4] " Thomas Chou
@ 2011-04-30 19:02 ` Wolfgang Denk
0 siblings, 0 replies; 9+ messages in thread
From: Wolfgang Denk @ 2011-04-30 19:02 UTC (permalink / raw)
To: u-boot
Dear Thomas Chou,
In message <1302587327-4699-1-git-send-email-thomas@wytron.com.tw> you wrote:
> This patch adds support for OpenCores tiny_spi.
>
> http://opencores.org/project,tiny_spi
>
> Signed-off-by: Thomas Chou <thomas@wytron.com.tw>
> ---
> for u-boot
> v2, use const and clean up as Mike suggested.
> v3, use struct instead of base+offset as Wolfgang suggested.
> v4, remove volatile in regs def.
>
> drivers/spi/Makefile | 1 +
> drivers/spi/oc_tiny_spi.c | 248 +++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 249 insertions(+), 0 deletions(-)
> create mode 100644 drivers/spi/oc_tiny_spi.c
Applied, thanks.
Best regards,
Wolfgang Denk
--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
"A complex system that works is invariably found to have evolved from
a simple system that worked." - John Gall, _Systemantics_
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2011-04-30 19:02 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-01-08 23:56 [U-Boot] [PATCH] spi: add new driver for OpenCores tiny_spi Thomas Chou
2011-01-09 1:44 ` 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
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox