1
0
mirror of git://projects.qi-hardware.com/wernermisc.git synced 2024-11-15 12:55:20 +02:00
wernermisc/spiio/spiio.c

180 lines
3.2 KiB
C
Raw Normal View History

2011-09-21 15:20:23 +03:00
/*
* 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 <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
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;
}