Module Name: src
Committed By: khorben
Date: Sat May 11 17:19:42 UTC 2013
Modified Files:
src/sys/arch/arm/omap [khorben-n900]: files.omap2
Added Files:
src/sys/arch/arm/omap [khorben-n900]: omap2_spi.c omap2_spireg.h
Log Message:
Imported omapspi(4), a driver for Multichannel SPI as found on the OMAP 2/3
from Texas Instruments.
Partly tested on the Nokia N900 (OMAP 3430).
To generate a diff of this commit:
cvs rdiff -u -r1.25 -r1.25.2.1 src/sys/arch/arm/omap/files.omap2
cvs rdiff -u -r0 -r1.1.2.1 src/sys/arch/arm/omap/omap2_spi.c \
src/sys/arch/arm/omap/omap2_spireg.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/arm/omap/files.omap2
diff -u src/sys/arch/arm/omap/files.omap2:1.25 src/sys/arch/arm/omap/files.omap2:1.25.2.1
--- src/sys/arch/arm/omap/files.omap2:1.25 Wed Apr 17 14:34:02 2013
+++ src/sys/arch/arm/omap/files.omap2 Sat May 11 17:19:41 2013
@@ -1,4 +1,4 @@
-# $NetBSD: files.omap2,v 1.25 2013/04/17 14:34:02 bouyer Exp $
+# $NetBSD: files.omap2,v 1.25.2.1 2013/05/11 17:19:41 khorben Exp $
#
# Configuration info for Texas Instruments OMAP2/OMAP3 CPU support
# Based on xscale/files.pxa2x0
@@ -64,6 +64,11 @@ device omapiic: i2cbus, i2cexec
attach omapiic at obio with omap3_i2c
file arch/arm/omap/omap3_i2c.c omap3_i2c
+# OMAP2 SPI controllers
+device omapspi: spibus
+attach omapspi at obio with omap2_spi
+file arch/arm/omap/omap2_spi.c (omap2 | omap3) & omapspi
+
# OMAP3 system control module
device omapscm: sysmon_envsys
attach omapscm at obio with omap3_scm
Added files:
Index: src/sys/arch/arm/omap/omap2_spi.c
diff -u /dev/null src/sys/arch/arm/omap/omap2_spi.c:1.1.2.1
--- /dev/null Sat May 11 17:19:42 2013
+++ src/sys/arch/arm/omap/omap2_spi.c Sat May 11 17:19:41 2013
@@ -0,0 +1,538 @@
+/* $NetBSD: omap2_spi.c,v 1.1.2.1 2013/05/11 17:19:41 khorben Exp $ */
+
+/*
+ * Texas Instruments OMAP2/3 Multichannel SPI driver.
+ *
+ * Copyright (c) 2013 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Pierre Pronchery ([email protected]).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: omap2_spi.c,v 1.1.2.1 2013/05/11 17:19:41 khorben Exp $");
+
+#include "opt_omap.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/bus.h>
+
+#include <dev/spi/spivar.h>
+
+#include <arm/omap/omap2_obiovar.h>
+
+#include <arm/omap/omap2_reg.h>
+#include <arm/omap/omap2_spireg.h>
+
+#define OMAP2_MCSPI_MAX_CHANNELS 4
+
+struct omap2_spi_channel {
+ SIMPLEQ_HEAD(,spi_transfer) queue;
+ struct spi_transfer *transfer;
+ struct spi_chunk *wchunk;
+ struct spi_chunk *rchunk;
+
+ bool running;
+};
+
+struct omap2_spi_softc {
+ device_t sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+ void *sc_intr;
+
+ struct spi_controller sc_spi;
+
+ struct omap2_spi_channel sc_channels[OMAP2_MCSPI_MAX_CHANNELS];
+};
+
+#define SPI_READ_REG(sc, reg) \
+ bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))
+#define SPI_WRITE_REG(sc, reg, val) \
+ bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
+
+static int omap2_spi_match(device_t, cfdata_t, void *);
+static void omap2_spi_attach(device_t, device_t, void *);
+
+static int omap2_spi_configure(void *, int, int, int);
+static int omap2_spi_transfer(void *, struct spi_transfer *);
+
+static void omap2_spi_start(struct omap2_spi_softc * const, int);
+static void omap2_spi_stop(struct omap2_spi_softc * const, int);
+static int omap2_spi_intr(void *v);
+
+static int omap2_spi_reset(struct omap2_spi_softc * const);
+static void omap2_spi_send(struct omap2_spi_softc * const, int);
+static void omap2_spi_recv(struct omap2_spi_softc * const, int);
+
+CFATTACH_DECL_NEW(omap2_spi, sizeof(struct omap2_spi_softc),
+ omap2_spi_match, omap2_spi_attach, NULL, NULL);
+
+
+static int
+omap2_spi_match(device_t parent, cfdata_t match, void *opaque)
+{
+ struct obio_attach_args *obio = opaque;
+
+#if defined(OMAP_3430) || defined(OMAP_3530)
+ if (obio->obio_addr == SPI1_BASE_3530 ||
+ obio->obio_addr == SPI2_BASE_3530 ||
+ obio->obio_addr == SPI3_BASE_3530 ||
+ obio->obio_addr == SPI4_BASE_3530)
+ return 1;
+#endif
+
+ return 0;
+}
+
+static void
+omap2_spi_attach(device_t parent, device_t self, void *opaque)
+{
+ struct omap2_spi_softc *sc = device_private(self);
+ struct obio_attach_args *obio = opaque;
+ int nslaves;
+ uint32_t rev;
+ struct spibus_attach_args sba;
+ int i;
+
+ aprint_naive("\n");
+
+ sc->sc_dev = self;
+ sc->sc_iot = obio->obio_iot;
+
+#if defined(OMAP_3430) || defined(OMAP_3530)
+ switch (obio->obio_addr) {
+ case SPI1_BASE_3530:
+ nslaves = 4;
+ break;
+ case SPI2_BASE_3530:
+ case SPI3_BASE_3530:
+ nslaves = 2;
+ break;
+ case SPI4_BASE_3530:
+ nslaves = 1;
+ break;
+ default:
+ return;
+ }
+#endif
+
+ if (bus_space_map(obio->obio_iot, obio->obio_addr, obio->obio_size, 0,
+ &sc->sc_ioh) != 0) {
+ aprint_error(": couldn't map address space\n");
+ return;
+ }
+
+ rev = SPI_READ_REG(sc, OMAP2_MCSPI_REVISION);
+ aprint_normal(": rev %u.%u\n",
+ (unsigned int)((rev & OMAP2_MCSPI_REV_MAJ_MASK)
+ >> OMAP2_MCSPI_REV_MAJ_SHIFT),
+ (unsigned int)((rev & OMAP2_MCSPI_REV_MIN_MASK)
+ >> OMAP2_MCSPI_REV_MIN_SHIFT));
+
+ omap2_spi_reset(sc);
+
+ if (obio->obio_intr < 0) {
+ sc->sc_intr = NULL;
+ } else {
+ sc->sc_intr = intr_establish(obio->obio_intr, IPL_BIO,
+ IST_LEVEL, omap2_spi_intr, sc);
+ if (sc->sc_intr == NULL) {
+ aprint_error_dev(self,
+ "couldn't establish interrupt\n");
+ }
+ }
+
+ sc->sc_spi.sct_cookie = sc;
+ sc->sc_spi.sct_configure = omap2_spi_configure;
+ sc->sc_spi.sct_transfer = omap2_spi_transfer;
+ sc->sc_spi.sct_nslaves = nslaves;
+
+ /* initialize the channels */
+ for (i = 0; i < nslaves; i++) {
+ spi_transq_init(&sc->sc_channels[i].queue);
+ }
+
+ /* initialize and attach the SPI bus */
+ sba.sba_controller = &sc->sc_spi;
+ config_found_ia(self, "spibus", &sba, spibus_print);
+}
+
+static int
+omap2_spi_configure(void *cookie, int slave, int mode, int speed)
+{
+ struct omap2_spi_softc *sc = cookie;
+ uint32_t conf = 0;
+ uint32_t div;
+
+ aprint_normal_dev(sc->sc_dev, "%s(%d)\n", __func__, slave);
+
+ if (slave >= sc->sc_spi.sct_nslaves)
+ return EINVAL;
+
+ if (speed <= 0)
+ return EINVAL;
+
+ /* set the speed */
+ /* XXX implement lower speeds */
+ if (speed <= 187500)
+ div = 0x8;
+ else if (speed <= 375000)
+ div = 0x7;
+ else if (speed <= 750000)
+ div = 0x6;
+ else if (speed <= 1500000)
+ div = 0x5;
+ else if (speed <= 3000000)
+ div = 0x4;
+ else if (speed <= 6000000)
+ div = 0x3;
+ else if (speed <= 12000000)
+ div = 0x2;
+ else if (speed <= 24000000)
+ div = 0x1;
+ else
+ div = 0;
+ conf |= (div << OMAP2_MCSPI_CHXCONF_CLKD_SHIFT);
+
+ /* set the word size to 8 bits */
+ conf &= ~OMAP2_MCSPI_CHXCONF_WL;
+ conf |= (0x7 << OMAP2_MCSPI_CHXCONF_WL_SHIFT);
+
+ /* disable the FIFO */
+ conf &= ~OMAP2_MCSPI_CHXCONF_FFER;
+ conf &= ~OMAP2_MCSPI_CHXCONF_FFEW;
+
+ switch (mode) {
+ case SPI_MODE_0:
+ break;
+ case SPI_MODE_1:
+ conf |= OMAP2_MCSPI_CHXCONF_PHA;
+ break;
+ case SPI_MODE_2:
+ conf |= OMAP2_MCSPI_CHXCONF_POL;
+ break;
+ case SPI_MODE_3:
+ conf |= OMAP2_MCSPI_CHXCONF_POL
+ | OMAP2_MCSPI_CHXCONF_PHA;
+ break;
+ default:
+ return EINVAL;
+ }
+
+ SPI_WRITE_REG(sc, OMAP2_MCSPI_CHXCONF(slave), conf);
+
+ return 0;
+}
+
+static int
+omap2_spi_transfer(void *cookie, struct spi_transfer *st)
+{
+ struct omap2_spi_softc *sc = cookie;
+ int s;
+ int channel;
+
+ channel = st->st_slave;
+ s = splbio();
+ spi_transq_enqueue(&sc->sc_channels[channel].queue, st);
+ omap2_spi_start(sc, channel);
+ splx(s);
+ return 0;
+}
+
+static void
+omap2_spi_start(struct omap2_spi_softc * const sc, int channel)
+{
+ struct omap2_spi_channel *chan;
+ struct spi_transfer *st;
+ uint32_t enableval = 0;
+ uint32_t ctrlreg;
+ uint32_t ctrlval;
+ uint32_t u32;
+
+ aprint_normal_dev(sc->sc_dev, "%s(%d)\n", __func__, channel);
+
+ chan = &sc->sc_channels[channel];
+ if (chan->running)
+ return;
+
+ if ((st = spi_transq_first(&chan->queue)) == NULL)
+ return;
+ spi_transq_dequeue(&chan->queue);
+
+ chan->running = true;
+
+ KASSERT(chan->transfer == NULL);
+ chan->transfer = st;
+ chan->rchunk = chan->wchunk = st->st_chunks;
+
+ switch (channel) {
+ case 0:
+ enableval = OMAP2_MCSPI_IRQENABLE_RX0_FULL
+ | OMAP2_MCSPI_IRQENABLE_TX0_UNDERFLOW
+ | OMAP2_MCSPI_IRQENABLE_TX0_EMPTY;
+ break;
+ case 1:
+ enableval = OMAP2_MCSPI_IRQENABLE_RX1_FULL
+ | OMAP2_MCSPI_IRQENABLE_TX1_UNDERFLOW
+ | OMAP2_MCSPI_IRQENABLE_TX1_EMPTY;
+ break;
+ case 2:
+ enableval = OMAP2_MCSPI_IRQENABLE_RX2_FULL
+ | OMAP2_MCSPI_IRQENABLE_TX2_UNDERFLOW
+ | OMAP2_MCSPI_IRQENABLE_TX2_EMPTY;
+ break;
+ case 3:
+ enableval = OMAP2_MCSPI_IRQENABLE_RX3_FULL
+ | OMAP2_MCSPI_IRQENABLE_TX3_UNDERFLOW
+ | OMAP2_MCSPI_IRQENABLE_TX3_EMPTY;
+ break;
+ }
+
+ /* enable interrupts */
+ u32 = SPI_READ_REG(sc, OMAP2_MCSPI_IRQENABLE);
+ SPI_WRITE_REG(sc, OMAP2_MCSPI_IRQENABLE, u32 | enableval);
+
+ /* start the channel */
+ ctrlreg = OMAP2_MCSPI_CHXCTRL(channel);
+ u32 = SPI_READ_REG(sc, ctrlreg);
+ ctrlval = OMAP2_MCSPI_CHXCTRL_EN;
+ SPI_WRITE_REG(sc, ctrlreg, u32 | ctrlval);
+}
+
+static void
+omap2_spi_stop(struct omap2_spi_softc * const sc, int channel)
+{
+ struct omap2_spi_channel *chan;
+ uint32_t ctrlreg;
+ uint32_t u32;
+
+ chan = &sc->sc_channels[channel];
+
+ chan->running = false;
+
+ /* stop the channel */
+ ctrlreg = OMAP2_MCSPI_CHXCTRL(channel);
+ u32 = SPI_READ_REG(sc, ctrlreg);
+ u32 &= ~OMAP2_MCSPI_CHXCTRL_EN;
+ SPI_WRITE_REG(sc, ctrlreg, u32);
+}
+
+static int
+omap2_spi_intr(void *v)
+{
+ struct omap2_spi_softc *sc = v;
+ int i;
+ struct omap2_spi_channel *chan;
+ struct spi_transfer *st;
+ uint32_t status;
+ uint32_t u32;
+ uint32_t tx_empty = 0;
+ uint32_t rx_full = 0;
+
+ aprint_normal_dev(sc->sc_dev, "%s()\n", __func__);
+
+ /* reset the channel status bits */
+ status = SPI_READ_REG(sc, OMAP2_MCSPI_IRQSTATUS);
+ u32 = 0;
+
+ /* check every channel */
+ for (i = 0; i < sc->sc_spi.sct_nslaves; i++) {
+ chan = &sc->sc_channels[i];
+
+ switch (i) {
+ case 0:
+ u32 |= OMAP2_MCSPI_IRQSTATUS_RX0_OVERFLOW
+ | OMAP2_MCSPI_IRQSTATUS_RX0_FULL
+ | OMAP2_MCSPI_IRQSTATUS_TX0_UNDERFLOW
+ | OMAP2_MCSPI_IRQSTATUS_TX0_EMPTY;
+ tx_empty = status
+ & OMAP2_MCSPI_IRQSTATUS_TX0_EMPTY;
+ rx_full = status
+ & OMAP2_MCSPI_IRQSTATUS_RX0_FULL;
+ break;
+ case 1:
+ u32 |= OMAP2_MCSPI_IRQSTATUS_RX1_FULL
+ | OMAP2_MCSPI_IRQSTATUS_TX1_UNDERFLOW
+ | OMAP2_MCSPI_IRQSTATUS_TX1_EMPTY;
+ tx_empty = status
+ & OMAP2_MCSPI_IRQSTATUS_TX1_EMPTY;
+ rx_full = status
+ & OMAP2_MCSPI_IRQSTATUS_RX1_FULL;
+ break;
+ case 2:
+ u32 |= OMAP2_MCSPI_IRQSTATUS_RX2_FULL
+ | OMAP2_MCSPI_IRQSTATUS_TX2_UNDERFLOW
+ | OMAP2_MCSPI_IRQSTATUS_TX2_EMPTY;
+ tx_empty = status
+ & OMAP2_MCSPI_IRQSTATUS_TX2_EMPTY;
+ rx_full = status
+ & OMAP2_MCSPI_IRQSTATUS_RX2_FULL;
+ break;
+ case 3:
+ u32 |= OMAP2_MCSPI_IRQSTATUS_RX3_FULL
+ | OMAP2_MCSPI_IRQSTATUS_TX3_UNDERFLOW
+ | OMAP2_MCSPI_IRQSTATUS_TX3_EMPTY;
+ tx_empty = status
+ & OMAP2_MCSPI_IRQSTATUS_TX3_EMPTY;
+ rx_full = status
+ & OMAP2_MCSPI_IRQSTATUS_RX3_FULL;
+ break;
+ }
+
+ if (chan->wchunk != NULL) {
+ if (tx_empty) {
+ omap2_spi_send(sc, i);
+ if (chan->wchunk == NULL)
+ omap2_spi_recv(sc, i);
+ }
+ }
+ else if (rx_full) {
+ omap2_spi_recv(sc, i);
+ }
+
+ aprint_normal_dev(sc->sc_dev, "%s() %p %p\n", __func__,
+ chan->wchunk, chan->rchunk);
+ if (chan->wchunk == NULL && chan->rchunk == NULL) {
+ st = chan->transfer;
+ chan->transfer = NULL;
+
+ KASSERT(st != NULL);
+ spi_done(st, 0);
+
+ spi_transq_dequeue(&chan->queue);
+ if ((st = spi_transq_first(&chan->queue)) == NULL)
+ omap2_spi_stop(sc, i);
+ else
+ chan->transfer = st;
+
+ }
+ }
+
+ /* acknowledge the interrupt */
+ SPI_WRITE_REG(sc, OMAP2_MCSPI_IRQSTATUS, u32);
+
+ return 1;
+}
+
+static int
+omap2_spi_reset(struct omap2_spi_softc * const sc)
+{
+ int retry;
+ uint32_t status;
+ int i;
+
+ aprint_normal_dev(sc->sc_dev, "%s()\n", __func__);
+
+ /* proceed to a software reset */
+ SPI_WRITE_REG(sc, OMAP2_MCSPI_SYSCONFIG,
+ OMAP2_MCSPI_SYSCONFIG_SOFTRESET);
+
+ /* poll until the reset is done */
+ retry = 1000;
+ status = SPI_READ_REG(sc, OMAP2_MCSPI_SYSSTATUS);
+ while ((status & OMAP2_MCSPI_SYSSTATUS_RESETDONE) == 0) {
+ if (--retry == 0)
+ return EBUSY;
+ delay(1000);
+ status = SPI_READ_REG(sc, OMAP2_MCSPI_SYSSTATUS);
+ }
+
+ /* disable every channel available */
+ for (i = 0; i < sc->sc_spi.sct_nslaves; i++) {
+ SPI_WRITE_REG(sc, OMAP2_MCSPI_CHXCTRL(i), 0);
+ }
+
+ /* disable and clear all interrupts */
+ SPI_WRITE_REG(sc, OMAP2_MCSPI_IRQENABLE, 0);
+ SPI_WRITE_REG(sc, OMAP2_MCSPI_IRQSTATUS, 0x1777f);
+
+ /* set the module in master and multichannel mode */
+ SPI_WRITE_REG(sc, OMAP2_MCSPI_MODULCTRL, 0);
+
+ return 0;
+}
+
+static void
+omap2_spi_send(struct omap2_spi_softc * const sc, int channel)
+{
+ struct spi_chunk *chunk;
+ const uint32_t stat = OMAP2_MCSPI_CHXSTAT(channel);
+ uint32_t u32;
+ uint32_t data;
+
+ aprint_normal_dev(sc->sc_dev, "%s(%d)\n", __func__, channel);
+
+ if ((chunk = sc->sc_channels[channel].wchunk) == NULL)
+ return;
+
+ if (chunk->chunk_wresid) {
+ u32 = SPI_READ_REG(sc, stat);
+ if ((u32 & OMAP2_MCSPI_CHXSTAT_TXS) == 0)
+ return;
+ if (chunk->chunk_wptr) {
+ data = *chunk->chunk_wptr++;
+ SPI_WRITE_REG(sc, OMAP2_MCSPI_TX(channel), data);
+ }
+ }
+
+ if (--chunk->chunk_wresid == 0) {
+ sc->sc_channels[channel].wchunk
+ = sc->sc_channels[channel].wchunk->chunk_next;
+ }
+}
+
+static void
+omap2_spi_recv(struct omap2_spi_softc * const sc, int channel)
+{
+ struct spi_chunk *chunk;
+ const uint32_t stat = OMAP2_MCSPI_CHXSTAT(channel);
+ uint32_t u32;
+ uint32_t data;
+
+ aprint_normal_dev(sc->sc_dev, "%s(%d)\n", __func__, channel);
+
+ while ((chunk = sc->sc_channels[channel].rchunk) != NULL
+ && chunk->chunk_rresid == 0) {
+ sc->sc_channels[channel].rchunk = chunk->chunk_next;
+ }
+
+ if (chunk == NULL)
+ return;
+
+ u32 = SPI_READ_REG(sc, stat);
+ if ((u32 & OMAP2_MCSPI_CHXSTAT_RXS) == 0)
+ return;
+ data = SPI_READ_REG(sc, OMAP2_MCSPI_RX(channel));
+ if (chunk->chunk_rptr) {
+ *chunk->chunk_rptr++ = data & 0xff;
+ }
+
+ if (--chunk->chunk_rresid == 0) {
+ sc->sc_channels[channel].rchunk
+ = sc->sc_channels[channel].rchunk->chunk_next;
+ }
+}
Index: src/sys/arch/arm/omap/omap2_spireg.h
diff -u /dev/null src/sys/arch/arm/omap/omap2_spireg.h:1.1.2.1
--- /dev/null Sat May 11 17:19:42 2013
+++ src/sys/arch/arm/omap/omap2_spireg.h Sat May 11 17:19:41 2013
@@ -0,0 +1,162 @@
+/* $NetBSD: omap2_spireg.h,v 1.1.2.1 2013/05/11 17:19:41 khorben Exp $ */
+
+/*
+ * Texas Instruments OMAP2/3 Multichannel SPI driver.
+ *
+ * Copyright (c) 2013 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Pierre Pronchery ([email protected]).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _OMAP2_SPIREG_H
+#define _OMAP2_SPIREG_H
+
+/*
+ * Multichannel SPI Controller registers
+ */
+
+#define OMAP2_MCSPI_REVISION 0x00
+#define OMAP2_MCSPI_REV_MAJ_MASK __BITS(4,7)
+#define OMAP2_MCSPI_REV_MAJ_SHIFT 4
+#define OMAP2_MCSPI_REV_MIN_MASK __BITS(0,3)
+#define OMAP2_MCSPI_REV_MIN_SHIFT 0
+
+#define OMAP2_MCSPI_SYSCONFIG 0x10
+#define OMAP2_MCSPI_SYSCONFIG_CLOCKACTIVITY __BITS(8,9)
+#define OMAP2_MCSPI_SYSCONFIG_SIDLEMODE __BITS(3,4)
+#define OMAP2_MCSPI_SYSCONFIG_ENAWAKEUP __BIT(2)
+#define OMAP2_MCSPI_SYSCONFIG_SOFTRESET __BIT(1)
+#define OMAP2_MCSPI_SYSCONFIG_AUTOIDLE __BIT(0)
+
+#define OMAP2_MCSPI_SYSSTATUS 0x14
+#define OMAP2_MCSPI_SYSSTATUS_RESETDONE __BIT(0)
+
+#define OMAP2_MCSPI_IRQSTATUS 0x18
+#define OMAP2_MCSPI_IRQSTATUS_EOW __BIT(16)
+#define OMAP2_MCSPI_IRQSTATUS_RX3_FULL __BIT(14)
+#define OMAP2_MCSPI_IRQSTATUS_TX3_UNDERFLOW __BIT(13)
+#define OMAP2_MCSPI_IRQSTATUS_TX3_EMPTY __BIT(12)
+#define OMAP2_MCSPI_IRQSTATUS_RX2_FULL __BIT(10)
+#define OMAP2_MCSPI_IRQSTATUS_TX2_UNDERFLOW __BIT(9)
+#define OMAP2_MCSPI_IRQSTATUS_TX2_EMPTY __BIT(8)
+#define OMAP2_MCSPI_IRQSTATUS_RX1_FULL __BIT(6)
+#define OMAP2_MCSPI_IRQSTATUS_TX1_UNDERFLOW __BIT(5)
+#define OMAP2_MCSPI_IRQSTATUS_TX1_EMPTY __BIT(4)
+#define OMAP2_MCSPI_IRQSTATUS_RX0_OVERFLOW __BIT(3)
+#define OMAP2_MCSPI_IRQSTATUS_RX0_FULL __BIT(2)
+#define OMAP2_MCSPI_IRQSTATUS_TX0_UNDERFLOW __BIT(1)
+#define OMAP2_MCSPI_IRQSTATUS_TX0_EMPTY __BIT(0)
+
+#define OMAP2_MCSPI_IRQENABLE 0x1c
+#define OMAP2_MCSPI_IRQENABLE_EOWKE __BIT(17)
+#define OMAP2_MCSPI_IRQENABLE_WKE __BIT(16)
+#define OMAP2_MCSPI_IRQENABLE_RX3_FULL __BIT(14)
+#define OMAP2_MCSPI_IRQENABLE_TX3_UNDERFLOW __BIT(13)
+#define OMAP2_MCSPI_IRQENABLE_TX3_EMPTY __BIT(12)
+#define OMAP2_MCSPI_IRQENABLE_RX2_FULL __BIT(10)
+#define OMAP2_MCSPI_IRQENABLE_TX2_UNDERFLOW __BIT(9)
+#define OMAP2_MCSPI_IRQENABLE_TX2_EMPTY __BIT(8)
+#define OMAP2_MCSPI_IRQENABLE_RX1_FULL __BIT(6)
+#define OMAP2_MCSPI_IRQENABLE_TX1_UNDERFLOW __BIT(5)
+#define OMAP2_MCSPI_IRQENABLE_TX1_EMPTY __BIT(4)
+#define OMAP2_MCSPI_IRQENABLE_RX0_OVERFLOW __BIT(3)
+#define OMAP2_MCSPI_IRQENABLE_RX0_FULL __BIT(2)
+#define OMAP2_MCSPI_IRQENABLE_TX0_UNDERFLOW __BIT(1)
+#define OMAP2_MCSPI_IRQENABLE_TX0_EMPTY __BIT(0)
+
+#define OMAP2_MCSPI_WAKEUPENABLE 0x20
+
+#define OMAP2_MCSPI_SYST 0x24
+#define OMAP2_MCSPI_SYST_SSB __BIT(11)
+#define OMAP2_MCSPI_SYST_SPIENDIR __BIT(10)
+#define OMAP2_MCSPI_SYST_SPIDATDIR1 __BIT(9)
+#define OMAP2_MCSPI_SYST_SPIDATDIR0 __BIT(8)
+#define OMAP2_MCSPI_SYST_WAKD __BIT(7)
+#define OMAP2_MCSPI_SYST_SPICLK __BIT(6)
+#define OMAP2_MCSPI_SYST_SPIDAT_1 __BIT(5)
+#define OMAP2_MCSPI_SYST_SPIDAT_0 __BIT(4)
+#define OMAP2_MCSPI_SYST_SPIEN_3 __BIT(3)
+#define OMAP2_MCSPI_SYST_SPIEN_2 __BIT(2)
+#define OMAP2_MCSPI_SYST_SPIEN_1 __BIT(1)
+#define OMAP2_MCSPI_SYST_SPIEN_0 __BIT(0)
+
+#define OMAP2_MCSPI_MODULCTRL 0x28
+#define OMAP2_MCSPI_MODULCTRL_SYSTEM_TEST __BIT(3)
+#define OMAP2_MCSPI_MODULCTRL_MS __BIT(2)
+#define OMAP2_MCSPI_MODULCTRL_SINGLE __BIT(0)
+
+#define OMAP2_MCSPI_CHXCONF(channel) (0x2c + (channel * 0x14))
+#define OMAP2_MCSPI_CH0CONF OMAP2_MCSPI_CHXCONF(0)
+#define OMAP2_MCSPI_CH1CONF OMAP2_MCSPI_CHXCONF(1)
+#define OMAP2_MCSPI_CH2CONF OMAP2_MCSPI_CHXCONF(2)
+#define OMAP2_MCSPI_CH3CONF OMAP2_MCSPI_CH0CONF(3)
+#define OMAP2_MCSPI_CHXCONF_FFER __BIT(28)
+#define OMAP2_MCSPI_CHXCONF_FFEW __BIT(27)
+#define OMAP2_MCSPI_CHXCONF_TCS __BITS(25,26)
+#define OMAP2_MCSPI_CHXCONF_SBE __BIT(23)
+#define OMAP2_MCSPI_CHXCONF_TRM __BITS(12,13)
+#define OMAP2_MCSPI_CHXCONF_TRM_SHIFT 12
+#define OMAP2_MCSPI_CHXCONF_WL __BITS(7,11)
+#define OMAP2_MCSPI_CHXCONF_WL_SHIFT 7
+#define OMAP2_MCSPI_CHXCONF_EPOL __BIT(6)
+#define OMAP2_MCSPI_CHXCONF_CLKD __BITS(2,5)
+#define OMAP2_MCSPI_CHXCONF_CLKD_SHIFT 2
+#define OMAP2_MCSPI_CHXCONF_POL __BIT(1)
+#define OMAP2_MCSPI_CHXCONF_PHA __BIT(0)
+
+#define OMAP2_MCSPI_CHXSTAT(channel) (0x30 + ((channel) * 0x14))
+#define OMAP2_MCSPI_CH0STAT OMAP2_MCSPI_CHXSTAT(0)
+#define OMAP2_MCSPI_CH1STAT OMAP2_MCSPI_CHXSTAT(1)
+#define OMAP2_MCSPI_CH2STAT OMAP2_MCSPI_CHXSTAT(2)
+#define OMAP2_MCSPI_CH3STAT OMAP2_MCSPI_CHXSTAT(3)
+# define OMAP2_MCSPI_CHXSTAT_EOT __BIT(2)
+# define OMAP2_MCSPI_CHXSTAT_TXS __BIT(1)
+# define OMAP2_MCSPI_CHXSTAT_RXS __BIT(0)
+
+#define OMAP2_MCSPI_CHXCTRL(channel) (0x34 + ((channel) * 0x14))
+#define OMAP2_MCSPI_CH0CTRL OMAP2_MCSPI_CHXCTRL(0)
+#define OMAP2_MCSPI_CH1CTRL OMAP2_MCSPI_CHXCTRL(1)
+#define OMAP2_MCSPI_CH2CTRL OMAP2_MCSPI_CHXCTRL(2)
+#define OMAP2_MCSPI_CH3CTRL OMAP2_MCSPI_CHXCTRL(3)
+#define OMAP2_MCSPI_CHXCTRL_EN __BIT(0)
+
+#define OMAP2_MCSPI_TX(channel) (0x38 + ((channel) * 0x14))
+#define OMAP2_MCSPI_TX0 OMAP2_MCSPI_TX(0)
+#define OMAP2_MCSPI_TX1 OMAP2_MCSPI_TX(1)
+#define OMAP2_MCSPI_TX2 OMAP2_MCSPI_TX(2)
+#define OMAP2_MCSPI_TX3 OMAP2_MCSPI_TX(3)
+
+#define OMAP2_MCSPI_RX(channel) (0x3c + (channel * 0x14))
+#define OMAP2_MCSPI_RX0 OMAP2_MCSPI_RX(0)
+#define OMAP2_MCSPI_RX1 OMAP2_MCSPI_RX(1)
+#define OMAP2_MCSPI_RX2 OMAP2_MCSPI_RX(2)
+#define OMAP2_MCSPI_RX3 OMAP2_MCSPI_RX(3)
+
+#define OMAP2_MCSPI_XFERLEVEL 0x7c
+#define OMAP2_MCSPI_XFERLEVEL_WCNT __BITS(16,31)
+#define OMAP2_MCSPI_XFERLEVEL_AFL __BITS(8,13)
+#define OMAP2_MCSPI_XFERLEVEL_AEL __BITS(0,5)
+
+#endif /* !_OMAP2_SPIREG_H */