Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/khorben-n900]: src/sys/arch/arm/omap Imported omapspi(4), a driver for M...
details: https://anonhg.NetBSD.org/src/rev/f6239b93fdac
branches: khorben-n900
changeset: 786699:f6239b93fdac
user: khorben <khorben%NetBSD.org@localhost>
date: Sat May 11 17:19:41 2013 +0000
description:
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).
diffstat:
sys/arch/arm/omap/files.omap2 | 7 +-
sys/arch/arm/omap/omap2_spi.c | 538 +++++++++++++++++++++++++++++++++++++++
sys/arch/arm/omap/omap2_spireg.h | 162 +++++++++++
3 files changed, 706 insertions(+), 1 deletions(-)
diffs (truncated from 729 to 300 lines):
diff -r 2b9367e07760 -r f6239b93fdac sys/arch/arm/omap/files.omap2
--- a/sys/arch/arm/omap/files.omap2 Fri May 10 01:25:07 2013 +0000
+++ b/sys/arch/arm/omap/files.omap2 Sat May 11 17:19:41 2013 +0000
@@ -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 @@
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
diff -r 2b9367e07760 -r f6239b93fdac sys/arch/arm/omap/omap2_spi.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/arm/omap/omap2_spi.c Sat May 11 17:19:41 2013 +0000
@@ -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 (khorben%defora.org@localhost).
+ *
+ * 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;
+
Home |
Main Index |
Thread Index |
Old Index