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 */

Reply via email to