Simplify the SPI driver.

This commit is contained in:
Serge Vakulenko
2015-09-20 22:01:19 -07:00
parent a36504720c
commit 80ab2d4721
9 changed files with 321 additions and 524 deletions

View File

@@ -12,6 +12,9 @@
#include <sys/ioctl.h> #include <sys/ioctl.h>
/*
* User-level interface to the SPI port.
*/
#define SPICTL_SETMODE _IO ('p', 0) /* set SPI mode */ #define SPICTL_SETMODE _IO ('p', 0) /* set SPI mode */
#define SPICTL_SETRATE _IO ('p', 1) /* set clock rate, kHz */ #define SPICTL_SETRATE _IO ('p', 1) /* set clock rate, kHz */
#define SPICTL_SETSELPIN _IO ('p', 2) /* set select pin */ #define SPICTL_SETSELPIN _IO ('p', 2) /* set select pin */
@@ -35,13 +38,54 @@
#ifdef KERNEL #ifdef KERNEL
#include "conf.h" #include "conf.h"
extern const struct devspec spidevs[]; /*
* Kernel-level interface to the SPI port.
*/
struct spiio {
struct spireg *bus;
unsigned int *cs_tris;
unsigned int cs_pin;
unsigned int baud;
unsigned int mode;
};
extern int spi_setup(struct spiio *io, int channel, unsigned int *tris, unsigned int pin);
extern void spi_set_cspin(struct spiio *io, unsigned int *tris, unsigned int pin);
extern void spi_select(struct spiio *io);
extern void spi_deselect(struct spiio *io);
extern void spi_set(struct spiio *io, unsigned int set);
extern void spi_clr(struct spiio *io, unsigned int set);
extern unsigned int spi_status(struct spiio *io);
extern unsigned char spi_transfer(struct spiio *io, unsigned char data);
extern void spi_bulk_write_32_be(struct spiio *io, unsigned int len, char *data);
extern void spi_bulk_write_32(struct spiio *io, unsigned int len, char *data);
extern void spi_bulk_write_16(struct spiio *io, unsigned int len, char *data);
extern void spi_bulk_write(struct spiio *io, unsigned int len, unsigned char *data);
extern void spi_bulk_read_32_be(struct spiio *io, unsigned int len, char *data);
extern void spi_bulk_read_32(struct spiio *io, unsigned int len, char *data);
extern void spi_bulk_read_16(struct spiio *io, unsigned int len, char *data);
extern void spi_bulk_read(struct spiio *io, unsigned int len, unsigned char *data);
extern void spi_bulk_rw_32_be(struct spiio *io, unsigned int len, char *data);
extern void spi_bulk_rw_32(struct spiio *io, unsigned int len, char *data);
extern void spi_bulk_rw_16(struct spiio *io, unsigned int len, char *data);
extern void spi_bulk_rw(struct spiio *io, unsigned int len, unsigned char *data);
extern void spi_brg(struct spiio *io, unsigned int baud);
extern char *spi_name(struct spiio *io);
extern char spi_csname(struct spiio *io);
extern int spi_cspin(struct spiio *io);
extern unsigned int spi_get_brg(struct spiio *io);
/*
* Routines of the SPI device driver.
*/
int spidev_open (dev_t dev, int flag, int mode); int spidev_open (dev_t dev, int flag, int mode);
int spidev_close (dev_t dev, int flag, int mode); int spidev_close (dev_t dev, int flag, int mode);
int spidev_read (dev_t dev, struct uio *uio, int flag); int spidev_read (dev_t dev, struct uio *uio, int flag);
int spidev_write (dev_t dev, struct uio *uio, int flag); int spidev_write (dev_t dev, struct uio *uio, int flag);
int spidev_ioctl (dev_t dev, u_int cmd, caddr_t addr, int flag); int spidev_ioctl (dev_t dev, u_int cmd, caddr_t addr, int flag);
extern const struct devspec spidevs[];
#endif #endif
#endif #endif

View File

@@ -1,62 +0,0 @@
#ifndef _SPI_BUS_H
#define _SPI_BUS_H
#ifdef KERNEL
struct spireg {
volatile unsigned con; /* Control */
volatile unsigned conclr;
volatile unsigned conset;
volatile unsigned coninv;
volatile unsigned stat; /* Status */
volatile unsigned statclr;
volatile unsigned statset;
volatile unsigned statinv;
volatile unsigned buf; /* Transmit and receive buffer */
volatile unsigned unused1;
volatile unsigned unused2;
volatile unsigned unused3;
volatile unsigned brg; /* Baud rate generator */
volatile unsigned brgclr;
volatile unsigned brgset;
volatile unsigned brginv;
};
struct spi_dev {
struct spireg *bus;
unsigned int *cs_tris;
unsigned int cs_pin;
unsigned int baud;
unsigned int mode;
};
extern int spi_open(unsigned int bus, unsigned int *tris, unsigned int pin);
extern void spi_close(int dno);
extern void spi_set_cspin(int dno, unsigned int *tris, unsigned int pin);
extern void spi_select(int dno);
extern void spi_deselect(int dno);
extern void spi_set(int dno, unsigned int set);
extern void spi_clr(int dno, unsigned int set);
extern unsigned int spi_status(int dno);
extern unsigned char spi_transfer(int dno, unsigned char data);
extern void spi_bulk_write_32_be(int dno, unsigned int len, char *data);
extern void spi_bulk_write_32(int dno, unsigned int len, char *data);
extern void spi_bulk_write_16(int dno, unsigned int len, char *data);
extern void spi_bulk_write(int dno, unsigned int len, unsigned char *data);
extern void spi_bulk_read_32_be(int dno, unsigned int len, char *data);
extern void spi_bulk_read_32(int dno, unsigned int len, char *data);
extern void spi_bulk_read_16(int dno, unsigned int len, char *data);
extern void spi_bulk_read(int dno, unsigned int len, unsigned char *data);
extern void spi_bulk_rw_32_be(int dno, unsigned int len, char *data);
extern void spi_bulk_rw_32(int dno, unsigned int len, char *data);
extern void spi_bulk_rw_16(int dno, unsigned int len, char *data);
extern void spi_bulk_rw(int dno, unsigned int len, unsigned char *data);
extern void spi_brg(int dno, unsigned int baud);
extern char *spi_name(int dno);
extern char spi_csname(int dno);
extern int spi_cspin(int dno);
extern unsigned int spi_get_brg(int dno);
#endif
#endif

View File

@@ -828,6 +828,27 @@ struct gpioreg {
#define SPI2BRGSET PIC32_R (0x5A38) #define SPI2BRGSET PIC32_R (0x5A38)
#define SPI2BRGINV PIC32_R (0x5A3C) #define SPI2BRGINV PIC32_R (0x5A3C)
#ifndef __ASSEMBLER__
struct spireg {
volatile unsigned con; /* Control */
volatile unsigned conclr;
volatile unsigned conset;
volatile unsigned coninv;
volatile unsigned stat; /* Status */
volatile unsigned statclr;
volatile unsigned statset;
volatile unsigned statinv;
volatile unsigned buf; /* Transmit and receive buffer */
volatile unsigned unused1;
volatile unsigned unused2;
volatile unsigned unused3;
volatile unsigned brg; /* Baud rate generator */
volatile unsigned brgclr;
volatile unsigned brgset;
volatile unsigned brginv;
};
#endif
/* /*
* SPI Control register. * SPI Control register.
*/ */

View File

@@ -28,7 +28,7 @@
#include <sys/systm.h> #include <sys/systm.h>
#include <sys/uio.h> #include <sys/uio.h>
#include <sys/picga.h> #include <sys/picga.h>
#include <sys/spi_bus.h> #include <sys/spi.h>
#include <sys/debug.h> #include <sys/debug.h>
const struct devspec picgadevs[] = { const struct devspec picgadevs[] = {
@@ -105,10 +105,9 @@ int picga_close(dev_t dev, int flag, int mode)
int channel; int channel;
channel = minor(dev); channel = minor(dev);
if(channel>0) if (channel>0)
return ENODEV; return ENODEV;
spi_close(fd);
return 0; return 0;
} }

View File

@@ -4,7 +4,7 @@
#include <sys/errno.h> #include <sys/errno.h>
#include <sys/dk.h> #include <sys/dk.h>
#include <sys/rdisk.h> #include <sys/rdisk.h>
#include <sys/spi_bus.h> #include <sys/spi.h>
#include <sys/debug.h> #include <sys/debug.h>
#define MRAM_WREN 0x06 #define MRAM_WREN 0x06

View File

@@ -35,7 +35,7 @@
#include <sys/errno.h> #include <sys/errno.h>
#include <sys/dk.h> #include <sys/dk.h>
#include <sys/rdisk.h> #include <sys/rdisk.h>
#include <sys/spi_bus.h> #include <sys/spi.h>
#include <sys/debug.h> #include <sys/debug.h>
#include <sys/kconfig.h> #include <sys/kconfig.h>
@@ -67,6 +67,7 @@
#define TIMO_WAIT_WSTOP 5000 #define TIMO_WAIT_WSTOP 5000
int sd_type[NSD]; /* Card type */ int sd_type[NSD]; /* Card type */
struct spiio sd_io[NSD]; /* Data for SPI driver */
int sd_dkn = -1; /* Statistics slot number */ int sd_dkn = -1; /* Statistics slot number */
int sd_timo_cmd; /* Max timeouts, for sysctl */ int sd_timo_cmd; /* Max timeouts, for sysctl */
@@ -104,13 +105,11 @@ int sd_timo_wait_widle;
#define STOP_TRAN_TOKEN 0xFD /* stop token for write multiple */ #define STOP_TRAN_TOKEN 0xFD /* stop token for write multiple */
#define WRITE_MULTIPLE_TOKEN 0xFC /* start data for write multiple */ #define WRITE_MULTIPLE_TOKEN 0xFC /* start data for write multiple */
int sd_fd[NSD];
// Add extra clocks after a deselect // Add extra clocks after a deselect
void sd_deselect(unsigned int fd) void sd_deselect(struct spiio *io)
{ {
spi_deselect(fd); spi_deselect(io);
spi_transfer(fd,0xFF); spi_transfer(io, 0xFF);
} }
/* /*
@@ -120,11 +119,12 @@ void sd_deselect(unsigned int fd)
static void spi_wait_ready (int unit, int limit, int *maxcount) static void spi_wait_ready (int unit, int limit, int *maxcount)
{ {
int i; int i;
struct spiio *io = &sd_io[unit];
spi_transfer(sd_fd[unit],0xFF); spi_transfer(io, 0xFF);
for (i=0; i<limit; i++) for (i=0; i<limit; i++)
{ {
if (spi_transfer(sd_fd[unit],0xFF) == 0xFF) if (spi_transfer(io, 0xFF) == 0xFF)
{ {
if (*maxcount < i) if (*maxcount < i)
*maxcount = i; *maxcount = i;
@@ -154,31 +154,32 @@ static void spi_wait_ready (int unit, int limit, int *maxcount)
static int card_cmd(unsigned int unit, unsigned int cmd, unsigned int addr) static int card_cmd(unsigned int unit, unsigned int cmd, unsigned int addr)
{ {
int i, reply; int i, reply;
struct spiio *io = &sd_io[unit];
/* Wait for not busy, up to 300 msec. */ /* Wait for not busy, up to 300 msec. */
if (cmd != CMD_GO_IDLE) if (cmd != CMD_GO_IDLE)
spi_wait_ready(unit, TIMO_WAIT_CMD, &sd_timo_wait_cmd); spi_wait_ready(unit, TIMO_WAIT_CMD, &sd_timo_wait_cmd);
/* Send a comand packet (6 bytes). */ /* Send a comand packet (6 bytes). */
spi_transfer(sd_fd[unit],cmd | 0x40); spi_transfer(io, cmd | 0x40);
spi_transfer(sd_fd[unit],addr >> 24); spi_transfer(io, addr >> 24);
spi_transfer(sd_fd[unit],addr >> 16); spi_transfer(io, addr >> 16);
spi_transfer(sd_fd[unit],addr >> 8); spi_transfer(io, addr >> 8);
spi_transfer(sd_fd[unit],addr); spi_transfer(io, addr);
/* Send cmd checksum for CMD_GO_IDLE. /* Send cmd checksum for CMD_GO_IDLE.
* For all other commands, CRC is ignored. */ * For all other commands, CRC is ignored. */
if (cmd == CMD_GO_IDLE) if (cmd == CMD_GO_IDLE)
spi_transfer(sd_fd[unit],0x95); spi_transfer(io, 0x95);
else if (cmd == CMD_SEND_IF_COND) else if (cmd == CMD_SEND_IF_COND)
spi_transfer(sd_fd[unit],0x87); spi_transfer(io, 0x87);
else else
spi_transfer(sd_fd[unit],0xFF); spi_transfer(io, 0xFF);
/* Wait for a response. */ /* Wait for a response. */
for (i=0; i<TIMO_CMD; i++) for (i=0; i<TIMO_CMD; i++)
{ {
reply = spi_transfer(sd_fd[unit],0xFF); reply = spi_transfer(io, 0xFF);
if (! (reply & 0x80)) if (! (reply & 0x80))
{ {
if (sd_timo_cmd < i) if (sd_timo_cmd < i)
@@ -203,28 +204,29 @@ int card_init(int unit)
int i, reply; int i, reply;
unsigned char response[4]; unsigned char response[4];
int timeout = 4; int timeout = 4;
struct spiio *io = &sd_io[unit];
/* Slow speed: 250 kHz */ /* Slow speed: 250 kHz */
spi_brg(sd_fd[unit], 250); spi_brg(io, 250);
sd_type[unit] = 0; sd_type[unit] = 0;
do { do {
/* Unselect the card. */ /* Unselect the card. */
sd_deselect(sd_fd[unit]); sd_deselect(io);
/* Send 80 clock cycles for start up. */ /* Send 80 clock cycles for start up. */
for (i=0; i<10; i++) for (i=0; i<10; i++)
spi_transfer(sd_fd[unit], 0xFF); spi_transfer(io, 0xFF);
/* Select the card and send a single GO_IDLE command. */ /* Select the card and send a single GO_IDLE command. */
spi_select(sd_fd[unit]); spi_select(io);
timeout--; timeout--;
reply = card_cmd(unit, CMD_GO_IDLE, 0); reply = card_cmd(unit, CMD_GO_IDLE, 0);
} while ((reply != 0x01) && (timeout != 0)); } while ((reply != 0x01) && (timeout != 0));
sd_deselect(sd_fd[unit]); sd_deselect(io);
if (reply != 1) if (reply != 1)
{ {
/* It must return Idle. */ /* It must return Idle. */
@@ -232,19 +234,19 @@ int card_init(int unit)
} }
/* Check SD version. */ /* Check SD version. */
spi_select(sd_fd[unit]); spi_select(io);
reply = card_cmd(unit, CMD_SEND_IF_COND, 0x1AA); reply = card_cmd(unit, CMD_SEND_IF_COND, 0x1AA);
if (reply & 4) if (reply & 4)
{ {
/* Illegal command: card type 1. */ /* Illegal command: card type 1. */
sd_deselect(sd_fd[unit]); sd_deselect(io);
sd_type[unit] = 1; sd_type[unit] = 1;
} else { } else {
response[0] = spi_transfer(sd_fd[unit], 0xFF); response[0] = spi_transfer(io, 0xFF);
response[1] = spi_transfer(sd_fd[unit], 0xFF); response[1] = spi_transfer(io, 0xFF);
response[2] = spi_transfer(sd_fd[unit], 0xFF); response[2] = spi_transfer(io, 0xFF);
response[3] = spi_transfer(sd_fd[unit], 0xFF); response[3] = spi_transfer(io, 0xFF);
sd_deselect(sd_fd[unit]); sd_deselect(io);
if (response[3] != 0xAA) if (response[3] != 0xAA)
{ {
printf ("sd%d: cannot detect card type, response=%02x-%02x-%02x-%02x\n", printf ("sd%d: cannot detect card type, response=%02x-%02x-%02x-%02x\n",
@@ -257,11 +259,11 @@ int card_init(int unit)
/* Send repeatedly SEND_OP until Idle terminates. */ /* Send repeatedly SEND_OP until Idle terminates. */
for (i=0; ; i++) for (i=0; ; i++)
{ {
spi_select(sd_fd[unit]); spi_select(io);
card_cmd(unit,CMD_APP, 0); card_cmd(unit,CMD_APP, 0);
reply = card_cmd(unit,CMD_SEND_OP_SDC, reply = card_cmd(unit,CMD_SEND_OP_SDC,
(sd_type[unit] == 2) ? 0x40000000 : 0); (sd_type[unit] == 2) ? 0x40000000 : 0);
spi_select(sd_fd[unit]); spi_select(io);
if (reply == 0) if (reply == 0)
break; break;
if (i >= TIMO_SEND_OP) if (i >= TIMO_SEND_OP)
@@ -277,19 +279,19 @@ int card_init(int unit)
/* If SD2 read OCR register to check for SDHC card. */ /* If SD2 read OCR register to check for SDHC card. */
if (sd_type[unit] == 2) if (sd_type[unit] == 2)
{ {
spi_select(sd_fd[unit]); spi_select(io);
reply = card_cmd(unit, CMD_READ_OCR, 0); reply = card_cmd(unit, CMD_READ_OCR, 0);
if (reply != 0) if (reply != 0)
{ {
sd_deselect(sd_fd[unit]); sd_deselect(io);
printf ("sd%d: READ_OCR failed, reply=%02x\n", unit, reply); printf ("sd%d: READ_OCR failed, reply=%02x\n", unit, reply);
return 0; return 0;
} }
response[0] = spi_transfer(sd_fd[unit],0xFF); response[0] = spi_transfer(io, 0xFF);
response[1] = spi_transfer(sd_fd[unit],0xFF); response[1] = spi_transfer(io, 0xFF);
response[2] = spi_transfer(sd_fd[unit],0xFF); response[2] = spi_transfer(io, 0xFF);
response[3] = spi_transfer(sd_fd[unit],0xFF); response[3] = spi_transfer(io, 0xFF);
sd_deselect(sd_fd[unit]); sd_deselect(io);
if ((response[0] & 0xC0) == 0xC0) if ((response[0] & 0xC0) == 0xC0)
{ {
sd_type[unit] = 3; sd_type[unit] = 3;
@@ -297,7 +299,7 @@ int card_init(int unit)
} }
/* Fast speed. */ /* Fast speed. */
spi_brg(sd_fd[unit],SD0_MHZ * 1000); spi_brg(io, SD0_MHZ * 1000);
return 1; return 1;
} }
@@ -311,25 +313,26 @@ int sdsize(int unit)
unsigned csize, n; unsigned csize, n;
int reply, i; int reply, i;
int nsectors; int nsectors;
struct spiio *io = &sd_io[unit];
spi_select(sd_fd[unit]); spi_select(io);
reply = card_cmd(unit,CMD_SEND_CSD, 0); reply = card_cmd(unit,CMD_SEND_CSD, 0);
if (reply != 0) if (reply != 0)
{ {
/* Command rejected. */ /* Command rejected. */
sd_deselect(sd_fd[unit]); sd_deselect(io);
return 0; return 0;
} }
/* Wait for a response. */ /* Wait for a response. */
for (i=0; ; i++) for (i=0; ; i++)
{ {
reply = spi_transfer(sd_fd[unit],0xFF); reply = spi_transfer(io, 0xFF);
if (reply == DATA_START_BLOCK) if (reply == DATA_START_BLOCK)
break; break;
if (i >= TIMO_SEND_CSD) if (i >= TIMO_SEND_CSD)
{ {
/* Command timed out. */ /* Command timed out. */
sd_deselect(sd_fd[unit]); sd_deselect(io);
printf ("sd%d: card_size: SEND_CSD timed out, reply = %d\n", printf ("sd%d: card_size: SEND_CSD timed out, reply = %d\n",
unit, reply); unit, reply);
return 0; return 0;
@@ -341,14 +344,14 @@ int sdsize(int unit)
/* Read data. */ /* Read data. */
for (i=0; i<sizeof(csd); i++) for (i=0; i<sizeof(csd); i++)
{ {
csd [i] = spi_transfer(sd_fd[unit],0xFF); csd [i] = spi_transfer(io, 0xFF);
} }
/* Ignore CRC. */ /* Ignore CRC. */
spi_transfer(sd_fd[unit],0xFF); spi_transfer(io, 0xFF);
spi_transfer(sd_fd[unit],0xFF); spi_transfer(io, 0xFF);
/* Disable the card. */ /* Disable the card. */
sd_deselect(sd_fd[unit]); sd_deselect(io);
/* CSD register has different structure /* CSD register has different structure
* depending upon protocol version. */ * depending upon protocol version. */
@@ -376,17 +379,19 @@ int sdsize(int unit)
int card_read(int unit, unsigned int offset, char *data, unsigned int bcount) int card_read(int unit, unsigned int offset, char *data, unsigned int bcount)
{ {
int reply, i; int reply, i;
struct spiio *io = &sd_io[unit];
/* Send read-multiple command. */ /* Send read-multiple command. */
spi_select(sd_fd[unit]); spi_select(io);
if (sd_type[unit] != 3) offset <<= 9; if (sd_type[unit] != 3)
offset <<= 9;
reply = card_cmd(unit, CMD_READ_MULTIPLE, offset<<1); reply = card_cmd(unit, CMD_READ_MULTIPLE, offset<<1);
if (reply != 0) if (reply != 0)
{ {
/* Command rejected. */ /* Command rejected. */
printf ("sd%d: card_read: bad READ_MULTIPLE reply = %d, offset = %08x\n", printf ("sd%d: card_read: bad READ_MULTIPLE reply = %d, offset = %08x\n",
unit, reply, offset<<1); unit, reply, offset<<1);
sd_deselect(sd_fd[unit]); sd_deselect(io);
return 0; return 0;
} }
@@ -395,7 +400,7 @@ again:
for (i=0; ; i++) for (i=0; ; i++)
{ {
int x = spl0(); int x = spl0();
reply = spi_transfer(sd_fd[unit],0xFF); reply = spi_transfer(io, 0xFF);
splx(x); splx(x);
if (reply == DATA_START_BLOCK) if (reply == DATA_START_BLOCK)
break; break;
@@ -404,7 +409,7 @@ again:
/* Command timed out. */ /* Command timed out. */
printf ("sd%d: card_read: READ_MULTIPLE timed out, reply = %d\n", printf ("sd%d: card_read: READ_MULTIPLE timed out, reply = %d\n",
unit, reply); unit, reply);
sd_deselect(sd_fd[unit]); sd_deselect(io);
return 0; return 0;
} }
} }
@@ -414,17 +419,17 @@ again:
/* Read data. */ /* Read data. */
if (bcount >= SECTSIZE) if (bcount >= SECTSIZE)
{ {
spi_bulk_read_32_be(sd_fd[unit],SECTSIZE,data); spi_bulk_read_32_be(io, SECTSIZE,data);
data += SECTSIZE; data += SECTSIZE;
} else { } else {
spi_bulk_read(sd_fd[unit],bcount,(unsigned char *)data); spi_bulk_read(io, bcount, (unsigned char *)data);
data += bcount; data += bcount;
for (i=bcount; i<SECTSIZE; i++) for (i=bcount; i<SECTSIZE; i++)
spi_transfer(sd_fd[unit],0xFF); spi_transfer(io, 0xFF);
} }
/* Ignore CRC. */ /* Ignore CRC. */
spi_transfer(sd_fd[unit],0xFF); spi_transfer(io, 0xFF);
spi_transfer(sd_fd[unit],0xFF); spi_transfer(io, 0xFF);
if (bcount > SECTSIZE) if (bcount > SECTSIZE)
{ {
@@ -435,7 +440,7 @@ again:
/* Stop a read-multiple sequence. */ /* Stop a read-multiple sequence. */
card_cmd(unit, CMD_STOP, 0); card_cmd(unit, CMD_STOP, 0);
sd_deselect(sd_fd[unit]); sd_deselect(io);
return 1; return 1;
} }
@@ -447,15 +452,16 @@ int
card_write (int unit, unsigned offset, char *data, unsigned bcount) card_write (int unit, unsigned offset, char *data, unsigned bcount)
{ {
unsigned reply, i; unsigned reply, i;
struct spiio *io = &sd_io[unit];
/* Send pre-erase count. */ /* Send pre-erase count. */
spi_select(sd_fd[unit]); spi_select(io);
card_cmd(unit, CMD_APP, 0); card_cmd(unit, CMD_APP, 0);
reply = card_cmd(unit, CMD_SET_WBECNT, (bcount + SECTSIZE - 1) / SECTSIZE); reply = card_cmd(unit, CMD_SET_WBECNT, (bcount + SECTSIZE - 1) / SECTSIZE);
if (reply != 0) if (reply != 0)
{ {
/* Command rejected. */ /* Command rejected. */
sd_deselect(sd_fd[unit]); sd_deselect(io);
printf("sd%d: card_write: bad SET_WBECNT reply = %02x, count = %u\n", printf("sd%d: card_write: bad SET_WBECNT reply = %02x, count = %u\n",
unit, reply, (bcount + SECTSIZE - 1) / SECTSIZE); unit, reply, (bcount + SECTSIZE - 1) / SECTSIZE);
return 0; return 0;
@@ -467,38 +473,38 @@ card_write (int unit, unsigned offset, char *data, unsigned bcount)
if (reply != 0) if (reply != 0)
{ {
/* Command rejected. */ /* Command rejected. */
sd_deselect(sd_fd[unit]); sd_deselect(io);
printf("sd%d: card_write: bad WRITE_MULTIPLE reply = %02x\n", unit, reply); printf("sd%d: card_write: bad WRITE_MULTIPLE reply = %02x\n", unit, reply);
return 0; return 0;
} }
sd_deselect(sd_fd[unit]); sd_deselect(io);
again: again:
/* Select, wait while busy. */ /* Select, wait while busy. */
spi_select(sd_fd[unit]); spi_select(io);
spi_wait_ready(unit, TIMO_WAIT_WDATA, &sd_timo_wait_wdata); spi_wait_ready(unit, TIMO_WAIT_WDATA, &sd_timo_wait_wdata);
/* Send data. */ /* Send data. */
spi_transfer(sd_fd[unit],WRITE_MULTIPLE_TOKEN); spi_transfer(io, WRITE_MULTIPLE_TOKEN);
if (bcount >= SECTSIZE) if (bcount >= SECTSIZE)
{ {
spi_bulk_write_32_be(sd_fd[unit],SECTSIZE,data); spi_bulk_write_32_be(io, SECTSIZE, data);
data += SECTSIZE; data += SECTSIZE;
} else { } else {
spi_bulk_write(sd_fd[unit],bcount,(unsigned char *)data); spi_bulk_write(io, bcount, (unsigned char *)data);
data += bcount; data += bcount;
for (i=bcount; i<SECTSIZE; i++) for (i=bcount; i<SECTSIZE; i++)
spi_transfer(sd_fd[unit],0xFF); spi_transfer(io, 0xFF);
} }
/* Send dummy CRC. */ /* Send dummy CRC. */
spi_transfer(sd_fd[unit],0xFF); spi_transfer(io, 0xFF);
spi_transfer(sd_fd[unit],0xFF); spi_transfer(io, 0xFF);
/* Check if data accepted. */ /* Check if data accepted. */
reply = spi_transfer(sd_fd[unit],0xFF); reply = spi_transfer(io, 0xFF);
if ((reply & 0x1f) != 0x05) if ((reply & 0x1f) != 0x05)
{ {
/* Data rejected. */ /* Data rejected. */
sd_deselect(sd_fd[unit]); sd_deselect(io);
printf("sd%d: card_write: data rejected, reply = %02x\n", unit,reply); printf("sd%d: card_write: data rejected, reply = %02x\n", unit,reply);
return 0; return 0;
} }
@@ -507,7 +513,7 @@ again:
int x = spl0(); int x = spl0();
spi_wait_ready(unit, TIMO_WAIT_WDONE, &sd_timo_wait_wdone); spi_wait_ready(unit, TIMO_WAIT_WDONE, &sd_timo_wait_wdone);
splx(x); splx(x);
sd_deselect(sd_fd[unit]); sd_deselect(io);
if (bcount > SECTSIZE) if (bcount > SECTSIZE)
{ {
@@ -517,11 +523,11 @@ again:
} }
/* Stop a write-multiple sequence. */ /* Stop a write-multiple sequence. */
spi_select(sd_fd[unit]); spi_select(io);
spi_wait_ready(unit, TIMO_WAIT_WSTOP, &sd_timo_wait_wstop); spi_wait_ready(unit, TIMO_WAIT_WSTOP, &sd_timo_wait_wstop);
spi_transfer(sd_fd[unit],STOP_TRAN_TOKEN); spi_transfer(io, STOP_TRAN_TOKEN);
spi_wait_ready(unit, TIMO_WAIT_WIDLE, &sd_timo_wait_widle); spi_wait_ready(unit, TIMO_WAIT_WIDLE, &sd_timo_wait_widle);
sd_deselect(sd_fd[unit]); sd_deselect(io);
return 1; return 1;
} }
@@ -529,10 +535,13 @@ void sd_preinit (int unit)
{ {
} }
/*
* Detect a card.
*/
int sdinit (int unit, int flag) int sdinit (int unit, int flag)
{ {
struct spiio *io = &sd_io[unit];
unsigned nsectors; unsigned nsectors;
/* Detect a card. */
#ifdef SD0_ENA_PORT #ifdef SD0_ENA_PORT
/* On Duinomite Mega board, pin B13 set low /* On Duinomite Mega board, pin B13 set low
@@ -562,13 +571,13 @@ int sdinit (int unit, int flag)
printf ("sd%d: cannot get card size\n", unit); printf ("sd%d: cannot get card size\n", unit);
return ENODEV; return ENODEV;
} }
if(!(flag & S_SILENT)) if (! (flag & S_SILENT))
{ {
printf ("sd%d: type %s, size %u kbytes, speed %u Mbit/sec\n", unit, printf ("sd%d: type %s, size %u kbytes, speed %u Mbit/sec\n", unit,
sd_type[unit]==3 ? "SDHC" : sd_type[unit]==3 ? "SDHC" :
sd_type[unit]==2 ? "II" : "I", sd_type[unit]==2 ? "II" : "I",
nsectors, nsectors,
spi_get_brg(sd_fd[unit]) / 1000); spi_get_brg(io) / 1000);
} }
DEBUG("sd%d: init done\n",unit); DEBUG("sd%d: init done\n",unit);
return 0; return 0;
@@ -612,6 +621,7 @@ sdprobe(config)
{ {
int unit = config->dev_unit; int unit = config->dev_unit;
int cs = config->dev_pins[0]; int cs = config->dev_pins[0];
struct spiio *io = &sd_io[unit];
if (unit < 0 || unit >= NSD) if (unit < 0 || unit >= NSD)
return 0; return 0;
@@ -622,12 +632,10 @@ sdprobe(config)
int pin = cs & 15; int pin = cs & 15;
struct gpioreg *base = port + (struct gpioreg*) &TRISA; struct gpioreg *base = port + (struct gpioreg*) &TRISA;
int fd = spi_open(config->dev_ctlr, (unsigned int*) base, pin); if (spi_setup(io, config->dev_ctlr, (unsigned int*) base, pin) != 0) {
if (fd < 0) { printf("sd%u: cannot open SPI%u port\n", unit, config->dev_ctlr);
printf("sd%d: Cannot open SPI port\n", unit);
return 0; return 0;
} }
sd_fd[unit] = fd;
#ifdef SD0_ENA_PORT #ifdef SD0_ENA_PORT
if (unit == 0) { if (unit == 0) {
@@ -647,8 +655,8 @@ sdprobe(config)
} }
#endif #endif
spi_brg(fd, SD0_MHZ * 1000); spi_brg(io, SD0_MHZ * 1000);
spi_set(fd, PIC32_SPICON_CKE); spi_set(io, PIC32_SPICON_CKE);
return 1; return 1;
} }

View File

@@ -4,7 +4,7 @@
#include <sys/errno.h> #include <sys/errno.h>
#include <sys/dk.h> #include <sys/dk.h>
#include <sys/rdisk.h> #include <sys/rdisk.h>
#include <sys/spi_bus.h> #include <sys/spi.h>
#include <sys/debug.h> #include <sys/debug.h>
#define SPIRAM_WREN 0x06 #define SPIRAM_WREN 0x06

View File

@@ -29,7 +29,6 @@
#include <sys/uio.h> #include <sys/uio.h>
#include <sys/kconfig.h> #include <sys/kconfig.h>
#include <sys/spi.h> #include <sys/spi.h>
#include <sys/spi_bus.h>
const struct devspec spidevs[] = { const struct devspec spidevs[] = {
{ 0, "spi1" }, { 0, "spi1" },
@@ -49,7 +48,7 @@ const struct devspec spidevs[] = {
# define PRINTDBG(...) /*empty*/ # define PRINTDBG(...) /*empty*/
#endif #endif
int spi_fd[NSPI]; struct spiio spi_io[NSPI]; /* Data for SPI driver */
/* /*
* Open /dev/spi# device. * Open /dev/spi# device.
@@ -57,9 +56,10 @@ int spi_fd[NSPI];
* - rate 250 kHz; * - rate 250 kHz;
* - no sleect pin. * - no sleect pin.
*/ */
int spidev_open (dev_t dev, int flag, int mode) int spidev_open(dev_t dev, int flag, int mode)
{ {
int channel = minor (dev); int channel = minor(dev);
struct spiio *io = &spi_io[channel];
if (channel >= NSPI) if (channel >= NSPI)
return ENXIO; return ENXIO;
@@ -67,15 +67,14 @@ int spidev_open (dev_t dev, int flag, int mode)
if (u.u_uid != 0) if (u.u_uid != 0)
return EPERM; return EPERM;
spi_fd[channel] = spi_open(channel+1,NULL,NULL); if (! io->bus)
if(spi_fd[channel]==-1)
return ENODEV; return ENODEV;
return 0; return 0;
} }
int spidev_close (dev_t dev, int flag, int mode) int spidev_close(dev_t dev, int flag, int mode)
{ {
int channel = minor (dev); int channel = minor(dev);
if (channel >= NSPI) if (channel >= NSPI)
return ENXIO; return ENXIO;
@@ -83,16 +82,15 @@ int spidev_close (dev_t dev, int flag, int mode)
if (u.u_uid != 0) if (u.u_uid != 0)
return EPERM; return EPERM;
spi_close(spi_fd[channel]);
return 0; return 0;
} }
int spidev_read (dev_t dev, struct uio *uio, int flag) int spidev_read(dev_t dev, struct uio *uio, int flag)
{ {
return 0; return 0;
} }
int spidev_write (dev_t dev, struct uio *uio, int flag) int spidev_write(dev_t dev, struct uio *uio, int flag)
{ {
return 0; return 0;
} }
@@ -115,9 +113,10 @@ int spidev_write (dev_t dev, struct uio *uio, int flag)
* - SPICTL_IO32WB(n) - n*32 bit WB transaction * - SPICTL_IO32WB(n) - n*32 bit WB transaction
* - SPICTL_IO32B(n) - n*32 bit B transaction * - SPICTL_IO32B(n) - n*32 bit B transaction
*/ */
int spidev_ioctl (dev_t dev, u_int cmd, caddr_t addr, int flag) int spidev_ioctl(dev_t dev, u_int cmd, caddr_t addr, int flag)
{ {
int channel = minor (dev); int channel = minor(dev);
struct spiio *io = &spi_io[channel];
unsigned char *cval = (unsigned char *)addr; unsigned char *cval = (unsigned char *)addr;
int nelem; int nelem;
static unsigned volatile *const tris[8] = { static unsigned volatile *const tris[8] = {
@@ -125,7 +124,7 @@ int spidev_ioctl (dev_t dev, u_int cmd, caddr_t addr, int flag)
}; };
int portnum; int portnum;
//PRINTDBG ("spi%d: ioctl (cmd=%08x, addr=%08x)\n", channel+1, cmd, addr); //PRINTDBG("spi%d: ioctl(cmd=%08x, addr=%08x)\n", channel+1, cmd, addr);
if (channel >= NSPI) if (channel >= NSPI)
return ENXIO; return ENXIO;
@@ -141,124 +140,140 @@ int spidev_ioctl (dev_t dev, u_int cmd, caddr_t addr, int flag)
* 2 1 0 * 2 1 0
* 3 1 1 * 3 1 1
*/ */
if((unsigned int) addr & 0x01) if ((unsigned) addr & 1)
spi_set(spi_fd[channel], PIC32_SPICON_CKE); spi_set(io, PIC32_SPICON_CKE);
if((unsigned int) addr & 0x02) if ((unsigned) addr & 2)
spi_set(spi_fd[channel], PIC32_SPICON_CKP); spi_set(io, PIC32_SPICON_CKP);
return 0; return 0;
case SPICTL_SETRATE: /* set clock rate, kHz */ case SPICTL_SETRATE: /* set clock rate, kHz */
spi_brg(spi_fd[channel], (unsigned int) addr); spi_brg(io, (unsigned int) addr);
return 0; return 0;
case SPICTL_SETSELPIN: /* set select pin */ case SPICTL_SETSELPIN: /* set select pin */
portnum = ((unsigned int) addr >> 8) & 7; portnum = ((unsigned int) addr >> 8) & 7;
if (! portnum) if (! portnum)
return 0; return 0;
spi_set_cspin(spi_fd[channel], spi_set_cspin(io, (unsigned*) tris[portnum], (unsigned) addr & 15);
(unsigned int *)tris[portnum],
(unsigned int) addr & 15);
return 0; return 0;
case SPICTL_IO8(0): /* transfer n*8 bits */ case SPICTL_IO8(0): /* transfer n*8 bits */
spi_select(spi_fd[channel]); spi_select(io);
nelem = (cmd >> 16) & IOCPARM_MASK; nelem = (cmd >> 16) & IOCPARM_MASK;
if (baduaddr (addr) || baduaddr (addr + nelem - 1)) if (baduaddr(addr) || baduaddr(addr + nelem - 1))
return EFAULT; return EFAULT;
spi_bulk_rw(spi_fd[channel], nelem, cval); spi_bulk_rw(io, nelem, cval);
spi_deselect(spi_fd[channel]); spi_deselect(io);
break; break;
case SPICTL_IO16(0): /* transfer n*16 bits */ case SPICTL_IO16(0): /* transfer n*16 bits */
spi_select(io);
nelem = (cmd >> 16) & IOCPARM_MASK; nelem = (cmd >> 16) & IOCPARM_MASK;
if (((unsigned) addr & 1) || if (((unsigned) addr & 1) ||
baduaddr (addr) || baduaddr (addr + nelem*2 - 1)) baduaddr(addr) || baduaddr(addr + nelem*2 - 1))
return EFAULT; return EFAULT;
spi_bulk_rw_16(spi_fd[channel], nelem<<1, (char *)addr); spi_bulk_rw_16(io, nelem<<1, (char *)addr);
spi_deselect(io);
break; break;
case SPICTL_IO32(0): /* transfer n*32 bits */ case SPICTL_IO32(0): /* transfer n*32 bits */
spi_select(io);
nelem = (cmd >> 16) & IOCPARM_MASK; nelem = (cmd >> 16) & IOCPARM_MASK;
if (((unsigned) addr & 3) || if (((unsigned) addr & 3) ||
baduaddr (addr) || baduaddr (addr + nelem*4 - 1)) baduaddr(addr) || baduaddr(addr + nelem*4 - 1))
return EFAULT; return EFAULT;
spi_bulk_rw_32(spi_fd[channel], nelem<<2, (char *)addr); spi_bulk_rw_32(io, nelem<<2, (char *)addr);
spi_deselect(io);
break; break;
// IM: added R and W and BE modes // IM: added R and W and BE modes
case SPICTL_IO8R(0): /* transfer n*8 bits */ case SPICTL_IO8R(0): /* transfer n*8 bits */
spi_select(spi_fd[channel]); spi_select(io);
nelem = (cmd >> 16) & IOCPARM_MASK; nelem = (cmd >> 16) & IOCPARM_MASK;
if (baduaddr (addr) || baduaddr (addr + nelem - 1)) if (baduaddr(addr) || baduaddr(addr + nelem - 1))
return EFAULT; return EFAULT;
spi_bulk_read(spi_fd[channel], nelem, cval); spi_bulk_read(io, nelem, cval);
spi_deselect(spi_fd[channel]); spi_deselect(io);
break; break;
case SPICTL_IO16R(0): /* transfer n*16 bits */ case SPICTL_IO16R(0): /* transfer n*16 bits */
spi_select(io);
nelem = (cmd >> 16) & IOCPARM_MASK; nelem = (cmd >> 16) & IOCPARM_MASK;
if (((unsigned) addr & 1) || if (((unsigned) addr & 1) ||
baduaddr (addr) || baduaddr (addr + nelem*2 - 1)) baduaddr(addr) || baduaddr(addr + nelem*2 - 1))
return EFAULT; return EFAULT;
spi_bulk_read_16(spi_fd[channel], nelem<<1, (char *)addr); spi_bulk_read_16(io, nelem<<1, (char *)addr);
spi_deselect(io);
break; break;
case SPICTL_IO32R(0): /* transfer n*32 bits */ case SPICTL_IO32R(0): /* transfer n*32 bits */
spi_select(io);
nelem = (cmd >> 16) & IOCPARM_MASK; nelem = (cmd >> 16) & IOCPARM_MASK;
if (((unsigned) addr & 3) || if (((unsigned) addr & 3) ||
baduaddr (addr) || baduaddr (addr + nelem*4 - 1)) baduaddr(addr) || baduaddr(addr + nelem*4 - 1))
return EFAULT; return EFAULT;
spi_bulk_read_32(spi_fd[channel], nelem<<2, (char *)addr); spi_bulk_read_32(io, nelem<<2, (char *)addr);
spi_deselect(io);
break; break;
case SPICTL_IO8W(0): /* transfer n*8 bits */ case SPICTL_IO8W(0): /* transfer n*8 bits */
spi_select(spi_fd[channel]); spi_select(io);
nelem = (cmd >> 16) & IOCPARM_MASK; nelem = (cmd >> 16) & IOCPARM_MASK;
if (baduaddr (addr) || baduaddr (addr + nelem - 1)) if (baduaddr(addr) || baduaddr(addr + nelem - 1))
return EFAULT; return EFAULT;
spi_bulk_write(spi_fd[channel], nelem, cval); spi_bulk_write(io, nelem, cval);
spi_deselect(spi_fd[channel]); spi_deselect(io);
break; break;
case SPICTL_IO16W(0): /* transfer n*16 bits */ case SPICTL_IO16W(0): /* transfer n*16 bits */
spi_select(io);
nelem = (cmd >> 16) & IOCPARM_MASK; nelem = (cmd >> 16) & IOCPARM_MASK;
if (((unsigned) addr & 1) || if (((unsigned) addr & 1) ||
baduaddr (addr) || baduaddr (addr + nelem*2 - 1)) baduaddr(addr) || baduaddr(addr + nelem*2 - 1))
return EFAULT; return EFAULT;
spi_bulk_write_16(spi_fd[channel], nelem<<1, (char *)addr); spi_bulk_write_16(io, nelem<<1, (char *)addr);
spi_deselect(io);
break; break;
case SPICTL_IO32W(0): /* transfer n*32 bits */ case SPICTL_IO32W(0): /* transfer n*32 bits */
spi_select(io);
nelem = (cmd >> 16) & IOCPARM_MASK; nelem = (cmd >> 16) & IOCPARM_MASK;
if (((unsigned) addr & 3) || if (((unsigned) addr & 3) ||
baduaddr (addr) || baduaddr (addr + nelem*4 - 1)) baduaddr(addr) || baduaddr(addr + nelem*4 - 1))
return EFAULT; return EFAULT;
spi_bulk_write_32(spi_fd[channel], nelem<<2, (char *)addr); spi_bulk_write_32(io, nelem<<2, (char *)addr);
spi_deselect(io);
break; break;
case SPICTL_IO32RB(0): /* transfer n*32 bits */ case SPICTL_IO32RB(0): /* transfer n*32 bits */
spi_select(io);
nelem = (cmd >> 16) & IOCPARM_MASK; nelem = (cmd >> 16) & IOCPARM_MASK;
if (((unsigned) addr & 3) || if (((unsigned) addr & 3) ||
baduaddr (addr) || baduaddr (addr + nelem*4 - 1)) baduaddr(addr) || baduaddr(addr + nelem*4 - 1))
return EFAULT; return EFAULT;
spi_bulk_read_32_be(spi_fd[channel], nelem<<2, (char *)addr); spi_bulk_read_32_be(io, nelem<<2, (char *)addr);
spi_deselect(io);
break; break;
case SPICTL_IO32WB(0): /* transfer n*32 bits */ case SPICTL_IO32WB(0): /* transfer n*32 bits */
spi_select(io);
nelem = (cmd >> 16) & IOCPARM_MASK; nelem = (cmd >> 16) & IOCPARM_MASK;
if (((unsigned) addr & 3) || if (((unsigned) addr & 3) ||
baduaddr (addr) || baduaddr (addr + nelem*4 - 1)) baduaddr(addr) || baduaddr(addr + nelem*4 - 1))
return EFAULT; return EFAULT;
spi_bulk_write_32_be(spi_fd[channel], nelem<<2, (char *)addr); spi_bulk_write_32_be(io, nelem<<2, (char *)addr);
spi_deselect(io);
break; break;
case SPICTL_IO32B(0): /* transfer n*32 bits */ case SPICTL_IO32B(0): /* transfer n*32 bits */
spi_select(io);
nelem = (cmd >> 16) & IOCPARM_MASK; nelem = (cmd >> 16) & IOCPARM_MASK;
if (((unsigned) addr & 3) || if (((unsigned) addr & 3) ||
baduaddr (addr) || baduaddr (addr + nelem*4 - 1)) baduaddr(addr) || baduaddr(addr + nelem*4 - 1))
return EFAULT; return EFAULT;
spi_bulk_write_32_be(spi_fd[channel], nelem<<2, (char *)addr); spi_bulk_write_32_be(io, nelem<<2, (char *)addr);
spi_deselect(io);
break; break;
//
} }
return 0; return 0;
} }
@@ -273,6 +288,7 @@ spiprobe(config)
struct conf_ctlr *config; struct conf_ctlr *config;
{ {
int channel = config->ctlr_unit - 1; int channel = config->ctlr_unit - 1;
struct spiio *io = &spi_io[channel];
int sdi, sdo, sck; int sdi, sdo, sck;
static const int sdi_tab[NSPI] = { static const int sdi_tab[NSPI] = {
GPIO_PIN('C',4), /* SDI1 */ GPIO_PIN('C',4), /* SDI1 */
@@ -304,15 +320,15 @@ spiprobe(config)
sdo = GPIO_PIN('F',8); sdo = GPIO_PIN('F',8);
sck = GPIO_PIN('D',15); sck = GPIO_PIN('D',15);
} }
printf ("spi%u: pins sdi=R%c%d/sdo=R%c%d/sck=R%c%d\n", channel+1, printf("spi%u: pins sdi=R%c%d/sdo=R%c%d/sck=R%c%d\n", channel+1,
gpio_portname(sdi), gpio_pinno(sdi), gpio_portname(sdi), gpio_pinno(sdi),
gpio_portname(sdo), gpio_pinno(sdo), gpio_portname(sdo), gpio_pinno(sdo),
gpio_portname(sck), gpio_pinno(sck)); gpio_portname(sck), gpio_pinno(sck));
//TODO if (spi_setup(io, channel+1, 0, 0) != 0) {
//struct spiio *io = &spitab[channel]; printf("spi%u: setup failed\n", channel+1);
//io->reg = spi_base[channel]; return 0;
//spi_setup(io, 0, 0); }
return 1; return 1;
} }

View File

@@ -4,13 +4,16 @@
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/systm.h> #include <sys/systm.h>
#include <sys/uio.h> #include <sys/uio.h>
#include <sys/spi_bus.h> #include <sys/spi.h>
#define NSPI 4 /* Ports SPI1...SPI4 */ #define NSPI 4 /* Ports SPI1...SPI4 */
#define MAXSPIDEV 20 static struct spireg *const spi_base[NSPI] = {
(struct spireg*) &SPI1CON,
struct spi_dev spi_devices[MAXSPIDEV]; (struct spireg*) &SPI2CON,
(struct spireg*) &SPI3CON,
(struct spireg*) &SPI4CON,
};
// //
// Default SPI bus speed // Default SPI bus speed
@@ -25,69 +28,36 @@ struct spi_dev spi_devices[MAXSPIDEV];
// Returns an integer for the number of the device (ala fd). // Returns an integer for the number of the device (ala fd).
// Returns -1 if no devices are available. // Returns -1 if no devices are available.
// //
int spi_open(unsigned int bus, unsigned int *tris, unsigned int pin) int spi_setup(struct spiio *io, int channel, unsigned int *tris, unsigned int pin)
{ {
int dno; if (channel <= 0 || channel > NSPI)
struct spi_dev *dev; return ENXIO;
// Find a free device
for (dno=0; dno<MAXSPIDEV && spi_devices[dno].bus != NULL; dno++);
// or return if not found
if (dno == MAXSPIDEV)
return -1;
dev = &spi_devices[dno];
// Set up the device // Set up the device
switch (bus) { io->bus = spi_base[channel-1];
case 1: io->cs_tris = tris;
dev->bus = (struct spireg *)&SPI1CON; io->cs_pin = pin;
break; io->baud = (BUS_KHZ / SPI_MHZ / 1000 + 1) / 2 - 1;
case 2: io->mode = PIC32_SPICON_MSTEN | PIC32_SPICON_ON;
dev->bus = (struct spireg *)&SPI2CON;
break;
case 3:
dev->bus = (struct spireg *)&SPI3CON;
break;
case 4:
dev->bus = (struct spireg *)&SPI4CON;
break;
default:
return -1;
}
dev->cs_tris = tris;
dev->cs_pin = pin;
dev->baud = (BUS_KHZ / SPI_MHZ / 1000 + 1) / 2 - 1;
dev->mode = PIC32_SPICON_MSTEN | PIC32_SPICON_ON;
if (tris) { if (tris) {
// Configure the CS pin // Configure the CS pin
LAT_SET(*tris) = 1<<pin; LAT_SET(*tris) = 1<<pin;
TRIS_CLR(*tris) = 1<<pin; TRIS_CLR(*tris) = 1<<pin;
} }
// return the ID of the device. return 0;
return dno;
} }
void spi_set_cspin(int dno, unsigned int *tris, unsigned int pin) void spi_set_cspin(struct spiio *io, unsigned int *tris, unsigned int pin)
{ {
struct spi_dev *dev;
if (dno >= MAXSPIDEV)
return;
dev = &spi_devices[dno];
if (! dev->bus)
return;
// Revert the old CS pin to an input (release it) // Revert the old CS pin to an input (release it)
if (dev->cs_tris) { if (io->cs_tris) {
// Configure the CS pin // Configure the CS pin
TRIS_SET(*dev->cs_tris) = 1<<pin; TRIS_SET(*io->cs_tris) = 1<<pin;
} }
dev->cs_tris = tris; io->cs_tris = tris;
dev->cs_pin = pin; io->cs_pin = pin;
if (tris) { if (tris) {
// Configure the CS pin // Configure the CS pin
LAT_SET(*tris) = 1<<pin; LAT_SET(*tris) = 1<<pin;
@@ -95,128 +65,58 @@ void spi_set_cspin(int dno, unsigned int *tris, unsigned int pin)
} }
} }
//
// Close an SPI device
// Free up the device entry, and turn off the CS pin (set it to input)
//
void spi_close(int dno)
{
struct spi_dev *dev;
if (dno >= MAXSPIDEV)
return;
dev = &spi_devices[dno];
if (! dev->bus)
return;
if (dev->cs_tris != NULL) {
// Revert the CS pin to input.
TRIS_CLR(*dev->cs_tris) = 1 << dev->cs_pin;
}
dev->cs_tris = NULL;
// Disable the device (remove the bus pointer)
dev->bus = NULL;
}
// //
// Assert the CS pin of a device. // Assert the CS pin of a device.
// Not only do we set the CS pin, but before we do so we also reconfigure // Not only do we set the CS pin, but before we do so we also reconfigure
// the SPI bus to the required settings for this device. // the SPI bus to the required settings for this device.
// //
void spi_select(int dno) void spi_select(struct spiio *io)
{ {
struct spi_dev *dev; if (io->cs_tris == NULL)
if (dno >= MAXSPIDEV)
return; return;
dev = &spi_devices[dno]; io->bus->brg = io->baud;
if (! dev->bus) io->bus->con = io->mode;
return;
if (dev->cs_tris == NULL) LAT_CLR(*io->cs_tris) = 1 << io->cs_pin;
return;
dev->bus->brg = dev->baud;
dev->bus->con = dev->mode;
LAT_CLR(*dev->cs_tris) = 1 << dev->cs_pin;
} }
// //
// Deassert the CS pin of a device. // Deassert the CS pin of a device.
// //
void spi_deselect(int dno) void spi_deselect(struct spiio *io)
{ {
struct spi_dev *dev; if (io->cs_tris == NULL)
if (dno >= MAXSPIDEV)
return; return;
dev = &spi_devices[dno]; LAT_SET(*io->cs_tris) = 1 << io->cs_pin;
if (! dev->bus)
return;
if (dev->cs_tris == NULL)
return;
LAT_SET(*dev->cs_tris) = 1 << dev->cs_pin;
} }
// //
// Set a mode setting or two - just updates the internal records, the // Set a mode setting or two - just updates the internal records, the
// actual mode is changed next time the CS is asserted // actual mode is changed next time the CS is asserted
// //
void spi_set(int dno, unsigned int set) void spi_set(struct spiio *io, unsigned int set)
{ {
struct spi_dev *dev; io->mode |= set;
if (dno >= MAXSPIDEV)
return;
dev = &spi_devices[dno];
if (! dev->bus)
return;
dev->mode |= set;
} }
// //
// Clear a mode setting or two - just updates the internal records, the // Clear a mode setting or two - just updates the internal records, the
// actual mode is changed next time the CS is asserted // actual mode is changed next time the CS is asserted
// //
void spi_clr(int dno, unsigned int set) void spi_clr(struct spiio *io, unsigned int set)
{ {
struct spi_dev *dev; io->mode &= ~set;
if (dno >= MAXSPIDEV)
return;
dev = &spi_devices[dno];
if (! dev->bus)
return;
dev->mode &= ~set;
} }
// //
// Return the current status of the SPI bus for the device in question // Return the current status of the SPI bus for the device in question
// Just returns the ->stat entry in the register set. // Just returns the ->stat entry in the register set.
// //
unsigned int spi_status(int dno) unsigned int spi_status(struct spiio *io)
{ {
struct spi_dev *dev; return io->bus->stat;
if (dno >= MAXSPIDEV)
return 0;
dev = &spi_devices[dno];
if (! dev->bus)
return 0;
return dev->bus->stat;
} }
// //
@@ -226,22 +126,16 @@ unsigned int spi_status(int dno)
// This is blocking, and waits for the transfer to complete // This is blocking, and waits for the transfer to complete
// before returning. Times out after a certain period. // before returning. Times out after a certain period.
// //
unsigned char spi_transfer(int dno, unsigned char data) unsigned char spi_transfer(struct spiio *io, unsigned char data)
{ {
struct spi_dev *dev; struct spireg *reg = io->bus;
struct spireg *reg;
unsigned int to = 100000; unsigned int to = 100000;
if (dno >= MAXSPIDEV)
return 0xF0;
dev = &spi_devices[dno];
reg = dev->bus;
if (! reg) if (! reg)
return 0xF1; return 0xF1;
reg->con = dev->mode; reg->con = io->mode;
reg->brg = dev->baud; reg->brg = io->baud;
reg->buf = data; reg->buf = data;
while ((--to > 0) && ! (reg->stat & PIC32_SPISTAT_SPIRBF)) while ((--to > 0) && ! (reg->stat & PIC32_SPISTAT_SPIRBF))
@@ -259,20 +153,14 @@ unsigned char spi_transfer(int dno, unsigned char data)
// the enhanced buffer mode. // the enhanced buffer mode.
// Data should be a multiple of 32 bits. // Data should be a multiple of 32 bits.
// //
void spi_bulk_write_32_be(int dno, unsigned int len, char *data) void spi_bulk_write_32_be(struct spiio *io, unsigned int len, char *data)
{ {
struct spi_dev *dev; struct spireg *reg = io->bus;
struct spireg *reg;
int *data32 = (int *)data; int *data32 = (int *)data;
unsigned int words = len >> 2; unsigned int words = len >> 2;
unsigned int nread; unsigned int nread;
unsigned int nwritten; unsigned int nwritten;
if (dno >= MAXSPIDEV)
return;
dev = &spi_devices[dno];
reg = dev->bus;
if (! reg) if (! reg)
return; return;
@@ -294,23 +182,17 @@ void spi_bulk_write_32_be(int dno, unsigned int len, char *data)
nread++; nread++;
} }
} }
reg->con = dev->mode; reg->con = io->mode;
} }
void spi_bulk_write_32(int dno, unsigned int len, char *data) void spi_bulk_write_32(struct spiio *io, unsigned int len, char *data)
{ {
struct spi_dev *dev; struct spireg *reg = io->bus;
struct spireg *reg;
int *data32 = (int *)data; int *data32 = (int *)data;
unsigned int words = len >> 2; unsigned int words = len >> 2;
unsigned int nread; unsigned int nread;
unsigned int nwritten; unsigned int nwritten;
if (dno >= MAXSPIDEV)
return;
dev = &spi_devices[dno];
reg = dev->bus;
if (! reg) if (! reg)
return; return;
@@ -332,23 +214,17 @@ void spi_bulk_write_32(int dno, unsigned int len, char *data)
nread++; nread++;
} }
} }
reg->con = dev->mode; reg->con = io->mode;
} }
void spi_bulk_write_16(int dno, unsigned int len, char *data) void spi_bulk_write_16(struct spiio *io, unsigned int len, char *data)
{ {
struct spi_dev *dev; struct spireg *reg = io->bus;
struct spireg *reg;
short *data16 = (short *)data; short *data16 = (short *)data;
unsigned int words = len >> 1; unsigned int words = len >> 1;
unsigned int nread; unsigned int nread;
unsigned int nwritten; unsigned int nwritten;
if (dno >= MAXSPIDEV)
return;
dev = &spi_devices[dno];
reg = dev->bus;
if (! reg) if (! reg)
return; return;
@@ -370,26 +246,18 @@ void spi_bulk_write_16(int dno, unsigned int len, char *data)
nread++; nread++;
} }
} }
reg->con = dev->mode; reg->con = io->mode;
} }
void spi_bulk_write(int dno, unsigned int len, unsigned char *data) void spi_bulk_write(struct spiio *io, unsigned int len, unsigned char *data)
{ {
struct spi_dev *dev;
unsigned char *data8 = data; unsigned char *data8 = data;
unsigned int i; unsigned int i;
unsigned char out; unsigned char out;
if (dno >= MAXSPIDEV)
return;
dev = &spi_devices[dno];
if (! dev->bus)
return;
for (i=0; i<len; i++) { for (i=0; i<len; i++) {
out = *data8; out = *data8;
spi_transfer(dno, out); spi_transfer(io, out);
data8++; data8++;
} }
} }
@@ -400,20 +268,14 @@ void spi_bulk_write(int dno, unsigned int len, unsigned char *data)
// the enhanced buffer mode. // the enhanced buffer mode.
// Data should be a multiple of 32 bits. // Data should be a multiple of 32 bits.
// //
void spi_bulk_read_32_be(int dno, unsigned int len, char *data) void spi_bulk_read_32_be(struct spiio *io, unsigned int len, char *data)
{ {
struct spi_dev *dev; struct spireg *reg = io->bus;
struct spireg *reg;
int *data32 = (int *)data; int *data32 = (int *)data;
unsigned int words = len >> 2; unsigned int words = len >> 2;
unsigned int nread; unsigned int nread;
unsigned int nwritten; unsigned int nwritten;
if (dno >= MAXSPIDEV)
return;
dev = &spi_devices[dno];
reg = dev->bus;
if (! reg) if (! reg)
return; return;
@@ -435,23 +297,17 @@ void spi_bulk_read_32_be(int dno, unsigned int len, char *data)
nread++; nread++;
} }
} }
reg->con = dev->mode; reg->con = io->mode;
} }
void spi_bulk_read_32(int dno, unsigned int len, char *data) void spi_bulk_read_32(struct spiio *io, unsigned int len, char *data)
{ {
struct spi_dev *dev; struct spireg *reg = io->bus;
struct spireg *reg;
int *data32 = (int *)data; int *data32 = (int *)data;
unsigned int words = len >> 2; unsigned int words = len >> 2;
unsigned int nread; unsigned int nread;
unsigned int nwritten; unsigned int nwritten;
if (dno >= MAXSPIDEV)
return;
dev = &spi_devices[dno];
reg = dev->bus;
if (! reg) if (! reg)
return; return;
@@ -473,23 +329,17 @@ void spi_bulk_read_32(int dno, unsigned int len, char *data)
nread++; nread++;
} }
} }
reg->con = dev->mode; reg->con = io->mode;
} }
void spi_bulk_read_16(int dno, unsigned int len, char *data) void spi_bulk_read_16(struct spiio *io, unsigned int len, char *data)
{ {
struct spi_dev *dev; struct spireg *reg = io->bus;
struct spireg *reg;
short *data16 = (short *)data; short *data16 = (short *)data;
unsigned int words = len >> 1; unsigned int words = len >> 1;
unsigned int nread; unsigned int nread;
unsigned int nwritten; unsigned int nwritten;
if (dno >= MAXSPIDEV)
return;
dev = &spi_devices[dno];
reg = dev->bus;
if (! reg) if (! reg)
return; return;
@@ -511,46 +361,32 @@ void spi_bulk_read_16(int dno, unsigned int len, char *data)
nread++; nread++;
} }
} }
reg->con = dev->mode; reg->con = io->mode;
} }
void spi_bulk_read(int dno, unsigned int len, unsigned char *data) void spi_bulk_read(struct spiio *io, unsigned int len, unsigned char *data)
{ {
struct spi_dev *dev;
unsigned char *data8 = data; unsigned char *data8 = data;
unsigned int i; unsigned int i;
unsigned char in,out; unsigned char in,out;
if (dno >= MAXSPIDEV)
return;
dev = &spi_devices[dno];
if (! dev->bus)
return;
for (i=0; i<len; i++) { for (i=0; i<len; i++) {
out = 0xFF; out = 0xFF;
in = spi_transfer(dno, out); in = spi_transfer(io, out);
*data8 = in; *data8 = in;
data8++; data8++;
} }
} }
void spi_bulk_rw_32_be(int dno, unsigned int len, char *data) void spi_bulk_rw_32_be(struct spiio *io, unsigned int len, char *data)
{ {
struct spi_dev *dev; struct spireg *reg = io->bus;
struct spireg *reg;
int *read32 = (int *)data; int *read32 = (int *)data;
int *write32 = (int *)data; int *write32 = (int *)data;
unsigned int words = len >> 2; unsigned int words = len >> 2;
unsigned int nread; unsigned int nread;
unsigned int nwritten; unsigned int nwritten;
if (dno >= MAXSPIDEV)
return;
dev = &spi_devices[dno];
reg = dev->bus;
if (! reg) if (! reg)
return; return;
@@ -572,24 +408,18 @@ void spi_bulk_rw_32_be(int dno, unsigned int len, char *data)
nread++; nread++;
} }
} }
reg->con = dev->mode; reg->con = io->mode;
} }
void spi_bulk_rw_32(int dno, unsigned int len, char *data) void spi_bulk_rw_32(struct spiio *io, unsigned int len, char *data)
{ {
struct spi_dev *dev; struct spireg *reg = io->bus;
struct spireg *reg;
int *read32 = (int *)data; int *read32 = (int *)data;
int *write32 = (int *)data; int *write32 = (int *)data;
unsigned int words = len >> 2; unsigned int words = len >> 2;
unsigned int nread; unsigned int nread;
unsigned int nwritten; unsigned int nwritten;
if (dno >= MAXSPIDEV)
return;
dev = &spi_devices[dno];
reg = dev->bus;
if (! reg) if (! reg)
return; return;
@@ -611,24 +441,18 @@ void spi_bulk_rw_32(int dno, unsigned int len, char *data)
nread++; nread++;
} }
} }
reg->con = dev->mode; reg->con = io->mode;
} }
void spi_bulk_rw_16(int dno, unsigned int len, char *data) void spi_bulk_rw_16(struct spiio *io, unsigned int len, char *data)
{ {
struct spi_dev *dev; struct spireg *reg = io->bus;
struct spireg *reg;
short *read16 = (short *)data; short *read16 = (short *)data;
short *write16 = (short *)data; short *write16 = (short *)data;
unsigned int words = len >> 1; unsigned int words = len >> 1;
unsigned int nread; unsigned int nread;
unsigned int nwritten; unsigned int nwritten;
if (dno >= MAXSPIDEV)
return;
dev = &spi_devices[dno];
reg = dev->bus;
if (! reg) if (! reg)
return; return;
@@ -650,26 +474,18 @@ void spi_bulk_rw_16(int dno, unsigned int len, char *data)
nread++; nread++;
} }
} }
reg->con = dev->mode; reg->con = io->mode;
} }
void spi_bulk_rw(int dno, unsigned int len, unsigned char *data) void spi_bulk_rw(struct spiio *io, unsigned int len, unsigned char *data)
{ {
struct spi_dev *dev;
unsigned char *data8 = data; unsigned char *data8 = data;
unsigned int i; unsigned int i;
unsigned char in,out; unsigned char in,out;
if (dno >= MAXSPIDEV)
return;
dev = &spi_devices[dno];
if (! dev->bus)
return;
for (i=0; i<len; i++) { for (i=0; i<len; i++) {
out = *data8; out = *data8;
in = spi_transfer(dno, out); in = spi_transfer(io, out);
*data8 = in; *data8 = in;
data8++; data8++;
} }
@@ -678,44 +494,26 @@ void spi_bulk_rw(int dno, unsigned int len, unsigned char *data)
// //
// Set the SPI baud rate for a device (in KHz) // Set the SPI baud rate for a device (in KHz)
// //
void spi_brg(int dno, unsigned int baud) void spi_brg(struct spiio *io, unsigned int baud)
{ {
struct spi_dev *dev; io->baud = (BUS_KHZ / baud + 1) / 2 - 1;
if (dno >= MAXSPIDEV)
return;
dev = &spi_devices[dno];
if (! dev->bus)
return;
dev->baud = (BUS_KHZ / baud + 1) / 2 - 1;
} }
// //
// Return the name of the SPI bus for a device // Return the name of the SPI bus for a device
// //
char *spi_name(int dno) char *spi_name(struct spiio *io)
{ {
struct spi_dev *dev; if (io->bus == spi_base[0])
if (dno >= MAXSPIDEV)
return "SPI?";
dev = &spi_devices[dno];
if (! dev->bus)
return "NO SPI BUS";
if (dev->bus == (struct spireg *)&SPI1CON)
return "SPI1"; return "SPI1";
if (dev->bus == (struct spireg *)&SPI2CON) if (io->bus == spi_base[1])
return "SPI2"; return "SPI2";
if (dev->bus == (struct spireg *)&SPI3CON) if (io->bus == spi_base[2])
return "SPI3"; return "SPI3";
if (dev->bus == (struct spireg *)&SPI4CON) if (io->bus == spi_base[3])
return "SPI4"; return "SPI4";
return "SPI?"; return "SPI?";
@@ -724,18 +522,9 @@ char *spi_name(int dno)
// //
// Return the port name of the CS pin for a device // Return the port name of the CS pin for a device
// //
char spi_csname(int dno) char spi_csname(struct spiio *io)
{ {
struct spi_dev *dev; switch ((unsigned)io->cs_tris) {
if (dno >= MAXSPIDEV)
return '?';
dev = &spi_devices[dno];
if (! dev->bus)
return '?';
switch ((unsigned)dev->cs_tris) {
case (unsigned)&TRISA: return 'A'; case (unsigned)&TRISA: return 'A';
case (unsigned)&TRISB: return 'B'; case (unsigned)&TRISB: return 'B';
case (unsigned)&TRISC: return 'C'; case (unsigned)&TRISC: return 'C';
@@ -747,30 +536,12 @@ char spi_csname(int dno)
return '?'; return '?';
} }
int spi_cspin(int dno) int spi_cspin(struct spiio *io)
{ {
struct spi_dev *dev; return io->cs_pin;
if (dno >= MAXSPIDEV)
return '?';
dev = &spi_devices[dno];
if (! dev->bus)
return '?';
return dev->cs_pin;
} }
unsigned int spi_get_brg(int dno) unsigned int spi_get_brg(struct spiio *io)
{ {
struct spi_dev *dev; return BUS_KHZ / (io->baud + 1) / 2;
if (dno >= MAXSPIDEV)
return 0;
dev = &spi_devices[dno];
if (! dev->bus)
return 0;
return BUS_KHZ / (dev->baud + 1) / 2;
} }