mirror of
git://projects.qi-hardware.com/wernermisc.git
synced 2024-12-01 01:26:13 +02:00
180 lines
3.2 KiB
C
180 lines
3.2 KiB
C
/*
|
|
* 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;
|
|
}
|