From 05bbe9103b38c87bf137fc796046f843e38e9392 Mon Sep 17 00:00:00 2001 From: Werner Almesberger Date: Wed, 21 Sep 2011 09:20:23 -0300 Subject: [PATCH] spiio/: simple SPI I/O example --- spiio/Makefile | 12 ++++ spiio/spiio.c | 179 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 191 insertions(+) create mode 100644 spiio/Makefile create mode 100644 spiio/spiio.c diff --git a/spiio/Makefile b/spiio/Makefile new file mode 100644 index 0000000..cf59e2f --- /dev/null +++ b/spiio/Makefile @@ -0,0 +1,12 @@ +CC=mipsel-openwrt-linux-uclibc-gcc + +CFLAGS=-Wall -g + +.PHONY: all clean spotless + +all: spiio + +clean: + rm -f spiio + +spotless: clean diff --git a/spiio/spiio.c b/spiio/spiio.c new file mode 100644 index 0000000..3f29e41 --- /dev/null +++ b/spiio/spiio.c @@ -0,0 +1,179 @@ +/* + * spiio.c - Very simple SPI I/O example + * + * Written 2011 by Werner Almesberger + * Copyright 2011 Werner Almesberger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + + +#include +#include +#include +#include +#include +#include +#include + + +enum { + VDD_OFF = 1 << 2, /* VDD disable, PD02 */ + MMC_CMD = 1 << 8, /* CMD, PD08 */ + MMC_CLK = 1 << 9, /* CLK, PD09 */ + MMC_DAT0 = 1 << 10, /* DAT0, PD10 */ + MMC_DAT1 = 1 << 11, /* DAT1, PD11 */ + MMC_DAT2 = 1 << 12, /* DAT2, PD12 */ + MMC_DAT3 = 1 << 13, /* DAT3/CD, PD13 */ +}; + +#define MOSI MMC_CMD +#define MISO MMC_DAT0 +#define SCLK MMC_DAT2 +#define nSEL MMC_DAT3 + + +#define SOC_BASE 0x10000000 + +#define REG(n) (*(volatile uint32_t *) (mem+(n))) + +#define GPIO(n) REG(0x10000+(n)) + +#define PDPIN GPIO(0x300) /* port D pin level */ +#define PDDATS GPIO(0x314) /* port D data set */ +#define PDDATC GPIO(0x318) /* port D data clear */ +#define PDFUNS GPIO(0x344) /* port D function set */ +#define PDFUNC GPIO(0x348) /* port D function clear */ +#define PDDIRS GPIO(0x364) /* port D direction set */ +#define PDDIRC GPIO(0x368) /* port D direction clear */ + +#define PAGE_SIZE 4096 + + +static void *mem; + + +/* ----- Low-level SPI operations ------------------------------------------ */ + + +static void spi_begin(void) +{ + PDDATC = nSEL; +} + + +static void spi_end(void) +{ + PDDATS = nSEL; +} + + +static void spi_send(uint8_t v) +{ + uint8_t mask; + + for (mask = 0x80; mask; mask >>= 1) { + if (v & mask) + PDDATS = MOSI; + else + PDDATC = MOSI; + PDDATS = SCLK; + PDDATC = SCLK; + } +} + + +static uint8_t spi_recv(void) +{ + uint8_t res = 0; + uint8_t mask; + + for (mask = 0x80; mask; mask >>= 1) { + if (PDPIN & MISO) + res |= mask; + PDDATS = SCLK; + PDDATC = SCLK; + } + return res; +} + + +static uint8_t spi_bidir(uint8_t v) +{ + uint8_t res = 0; + uint8_t mask; + + for (mask = 0x80; mask; mask >>= 1) { + if (PDPIN & MISO) + res |= mask; + if (v & mask) + PDDATS = MOSI; + else + PDDATC = MOSI; + PDDATS = SCLK; + PDDATC = SCLK; + } + return res; +} + + +/* ---- High-level -------------------------------------------------------- */ + + +static void spi_io(const char *s) +{ + const char *p; + uint8_t ch; + + spi_begin(); + for (p = s; *p; p++) { + ch = spi_bidir(*s); + if (!ch) + continue; + if (strchr("\t\n\r", ch) || (ch >= ' ' && ch <= '~')) + putchar(ch); + else + putchar('?'); + } + spi_end(); + putchar('\n'); +} + + +int main(int argc, char **argv) +{ + int fd, i; + + fd = open("/dev/mem", O_RDWR | O_SYNC); + if (fd < 0) { + perror("/dev/mem"); + exit(1); + } + mem = mmap(NULL, PAGE_SIZE*3*16, PROT_READ | PROT_WRITE, + MAP_SHARED, fd, SOC_BASE); + if (mem == MAP_FAILED) { + perror("mmap"); + exit(1); + } + + /* set the output levels */ + PDDATS = nSEL | VDD_OFF; + PDDATC = SCLK; + + PDFUNC = MOSI | MISO | SCLK | nSEL; + + /* set the pin directions */ + PDDIRC = MISO; + PDDIRS = MOSI | SCLK | nSEL; + + for (i = 1; i != argc; i++) + spi_io(argv[i]); + + /* make all MMC pins inputs */ + PDDIRC = MOSI | MISO | SCLK | nSEL; + + return 0; +}