Simplify the SPI driver.
This commit is contained in:
@@ -12,6 +12,9 @@
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
/*
|
||||
* User-level interface to the SPI port.
|
||||
*/
|
||||
#define SPICTL_SETMODE _IO ('p', 0) /* set SPI mode */
|
||||
#define SPICTL_SETRATE _IO ('p', 1) /* set clock rate, kHz */
|
||||
#define SPICTL_SETSELPIN _IO ('p', 2) /* set select pin */
|
||||
@@ -35,13 +38,54 @@
|
||||
#ifdef KERNEL
|
||||
#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_close (dev_t dev, int flag, int mode);
|
||||
int spidev_read (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);
|
||||
|
||||
extern const struct devspec spidevs[];
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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
|
||||
@@ -828,6 +828,27 @@ struct gpioreg {
|
||||
#define SPI2BRGSET PIC32_R (0x5A38)
|
||||
#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.
|
||||
*/
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include <sys/systm.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/picga.h>
|
||||
#include <sys/spi_bus.h>
|
||||
#include <sys/spi.h>
|
||||
#include <sys/debug.h>
|
||||
|
||||
const struct devspec picgadevs[] = {
|
||||
@@ -105,10 +105,9 @@ int picga_close(dev_t dev, int flag, int mode)
|
||||
int channel;
|
||||
|
||||
channel = minor(dev);
|
||||
if(channel>0)
|
||||
if (channel>0)
|
||||
return ENODEV;
|
||||
|
||||
spi_close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <sys/errno.h>
|
||||
#include <sys/dk.h>
|
||||
#include <sys/rdisk.h>
|
||||
#include <sys/spi_bus.h>
|
||||
#include <sys/spi.h>
|
||||
#include <sys/debug.h>
|
||||
|
||||
#define MRAM_WREN 0x06
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
#include <sys/errno.h>
|
||||
#include <sys/dk.h>
|
||||
#include <sys/rdisk.h>
|
||||
#include <sys/spi_bus.h>
|
||||
#include <sys/spi.h>
|
||||
#include <sys/debug.h>
|
||||
#include <sys/kconfig.h>
|
||||
|
||||
@@ -67,6 +67,7 @@
|
||||
#define TIMO_WAIT_WSTOP 5000
|
||||
|
||||
int sd_type[NSD]; /* Card type */
|
||||
struct spiio sd_io[NSD]; /* Data for SPI driver */
|
||||
int sd_dkn = -1; /* Statistics slot number */
|
||||
|
||||
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 WRITE_MULTIPLE_TOKEN 0xFC /* start data for write multiple */
|
||||
|
||||
int sd_fd[NSD];
|
||||
|
||||
// Add extra clocks after a deselect
|
||||
void sd_deselect(unsigned int fd)
|
||||
void sd_deselect(struct spiio *io)
|
||||
{
|
||||
spi_deselect(fd);
|
||||
spi_transfer(fd,0xFF);
|
||||
spi_deselect(io);
|
||||
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)
|
||||
{
|
||||
int i;
|
||||
struct spiio *io = &sd_io[unit];
|
||||
|
||||
spi_transfer(sd_fd[unit],0xFF);
|
||||
spi_transfer(io, 0xFF);
|
||||
for (i=0; i<limit; i++)
|
||||
{
|
||||
if (spi_transfer(sd_fd[unit],0xFF) == 0xFF)
|
||||
if (spi_transfer(io, 0xFF) == 0xFF)
|
||||
{
|
||||
if (*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)
|
||||
{
|
||||
int i, reply;
|
||||
struct spiio *io = &sd_io[unit];
|
||||
|
||||
/* Wait for not busy, up to 300 msec. */
|
||||
if (cmd != CMD_GO_IDLE)
|
||||
spi_wait_ready(unit, TIMO_WAIT_CMD, &sd_timo_wait_cmd);
|
||||
|
||||
/* Send a comand packet (6 bytes). */
|
||||
spi_transfer(sd_fd[unit],cmd | 0x40);
|
||||
spi_transfer(sd_fd[unit],addr >> 24);
|
||||
spi_transfer(sd_fd[unit],addr >> 16);
|
||||
spi_transfer(sd_fd[unit],addr >> 8);
|
||||
spi_transfer(sd_fd[unit],addr);
|
||||
spi_transfer(io, cmd | 0x40);
|
||||
spi_transfer(io, addr >> 24);
|
||||
spi_transfer(io, addr >> 16);
|
||||
spi_transfer(io, addr >> 8);
|
||||
spi_transfer(io, addr);
|
||||
|
||||
/* Send cmd checksum for CMD_GO_IDLE.
|
||||
* For all other commands, CRC is ignored. */
|
||||
if (cmd == CMD_GO_IDLE)
|
||||
spi_transfer(sd_fd[unit],0x95);
|
||||
spi_transfer(io, 0x95);
|
||||
else if (cmd == CMD_SEND_IF_COND)
|
||||
spi_transfer(sd_fd[unit],0x87);
|
||||
spi_transfer(io, 0x87);
|
||||
else
|
||||
spi_transfer(sd_fd[unit],0xFF);
|
||||
spi_transfer(io, 0xFF);
|
||||
|
||||
/* Wait for a response. */
|
||||
for (i=0; i<TIMO_CMD; i++)
|
||||
{
|
||||
reply = spi_transfer(sd_fd[unit],0xFF);
|
||||
reply = spi_transfer(io, 0xFF);
|
||||
if (! (reply & 0x80))
|
||||
{
|
||||
if (sd_timo_cmd < i)
|
||||
@@ -203,28 +204,29 @@ int card_init(int unit)
|
||||
int i, reply;
|
||||
unsigned char response[4];
|
||||
int timeout = 4;
|
||||
struct spiio *io = &sd_io[unit];
|
||||
|
||||
/* Slow speed: 250 kHz */
|
||||
spi_brg(sd_fd[unit], 250);
|
||||
spi_brg(io, 250);
|
||||
|
||||
sd_type[unit] = 0;
|
||||
|
||||
do {
|
||||
/* Unselect the card. */
|
||||
sd_deselect(sd_fd[unit]);
|
||||
sd_deselect(io);
|
||||
|
||||
/* Send 80 clock cycles for start up. */
|
||||
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. */
|
||||
spi_select(sd_fd[unit]);
|
||||
spi_select(io);
|
||||
timeout--;
|
||||
reply = card_cmd(unit, CMD_GO_IDLE, 0);
|
||||
|
||||
} while ((reply != 0x01) && (timeout != 0));
|
||||
|
||||
sd_deselect(sd_fd[unit]);
|
||||
sd_deselect(io);
|
||||
if (reply != 1)
|
||||
{
|
||||
/* It must return Idle. */
|
||||
@@ -232,19 +234,19 @@ int card_init(int unit)
|
||||
}
|
||||
|
||||
/* Check SD version. */
|
||||
spi_select(sd_fd[unit]);
|
||||
spi_select(io);
|
||||
reply = card_cmd(unit, CMD_SEND_IF_COND, 0x1AA);
|
||||
if (reply & 4)
|
||||
{
|
||||
/* Illegal command: card type 1. */
|
||||
sd_deselect(sd_fd[unit]);
|
||||
sd_deselect(io);
|
||||
sd_type[unit] = 1;
|
||||
} else {
|
||||
response[0] = spi_transfer(sd_fd[unit], 0xFF);
|
||||
response[1] = spi_transfer(sd_fd[unit], 0xFF);
|
||||
response[2] = spi_transfer(sd_fd[unit], 0xFF);
|
||||
response[3] = spi_transfer(sd_fd[unit], 0xFF);
|
||||
sd_deselect(sd_fd[unit]);
|
||||
response[0] = spi_transfer(io, 0xFF);
|
||||
response[1] = spi_transfer(io, 0xFF);
|
||||
response[2] = spi_transfer(io, 0xFF);
|
||||
response[3] = spi_transfer(io, 0xFF);
|
||||
sd_deselect(io);
|
||||
if (response[3] != 0xAA)
|
||||
{
|
||||
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. */
|
||||
for (i=0; ; i++)
|
||||
{
|
||||
spi_select(sd_fd[unit]);
|
||||
spi_select(io);
|
||||
card_cmd(unit,CMD_APP, 0);
|
||||
reply = card_cmd(unit,CMD_SEND_OP_SDC,
|
||||
(sd_type[unit] == 2) ? 0x40000000 : 0);
|
||||
spi_select(sd_fd[unit]);
|
||||
spi_select(io);
|
||||
if (reply == 0)
|
||||
break;
|
||||
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 (sd_type[unit] == 2)
|
||||
{
|
||||
spi_select(sd_fd[unit]);
|
||||
spi_select(io);
|
||||
reply = card_cmd(unit, CMD_READ_OCR, 0);
|
||||
if (reply != 0)
|
||||
{
|
||||
sd_deselect(sd_fd[unit]);
|
||||
sd_deselect(io);
|
||||
printf ("sd%d: READ_OCR failed, reply=%02x\n", unit, reply);
|
||||
return 0;
|
||||
}
|
||||
response[0] = spi_transfer(sd_fd[unit],0xFF);
|
||||
response[1] = spi_transfer(sd_fd[unit],0xFF);
|
||||
response[2] = spi_transfer(sd_fd[unit],0xFF);
|
||||
response[3] = spi_transfer(sd_fd[unit],0xFF);
|
||||
sd_deselect(sd_fd[unit]);
|
||||
response[0] = spi_transfer(io, 0xFF);
|
||||
response[1] = spi_transfer(io, 0xFF);
|
||||
response[2] = spi_transfer(io, 0xFF);
|
||||
response[3] = spi_transfer(io, 0xFF);
|
||||
sd_deselect(io);
|
||||
if ((response[0] & 0xC0) == 0xC0)
|
||||
{
|
||||
sd_type[unit] = 3;
|
||||
@@ -297,7 +299,7 @@ int card_init(int unit)
|
||||
}
|
||||
|
||||
/* Fast speed. */
|
||||
spi_brg(sd_fd[unit],SD0_MHZ * 1000);
|
||||
spi_brg(io, SD0_MHZ * 1000);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -311,25 +313,26 @@ int sdsize(int unit)
|
||||
unsigned csize, n;
|
||||
int reply, i;
|
||||
int nsectors;
|
||||
struct spiio *io = &sd_io[unit];
|
||||
|
||||
spi_select(sd_fd[unit]);
|
||||
spi_select(io);
|
||||
reply = card_cmd(unit,CMD_SEND_CSD, 0);
|
||||
if (reply != 0)
|
||||
{
|
||||
/* Command rejected. */
|
||||
sd_deselect(sd_fd[unit]);
|
||||
sd_deselect(io);
|
||||
return 0;
|
||||
}
|
||||
/* Wait for a response. */
|
||||
for (i=0; ; i++)
|
||||
{
|
||||
reply = spi_transfer(sd_fd[unit],0xFF);
|
||||
reply = spi_transfer(io, 0xFF);
|
||||
if (reply == DATA_START_BLOCK)
|
||||
break;
|
||||
if (i >= TIMO_SEND_CSD)
|
||||
{
|
||||
/* Command timed out. */
|
||||
sd_deselect(sd_fd[unit]);
|
||||
sd_deselect(io);
|
||||
printf ("sd%d: card_size: SEND_CSD timed out, reply = %d\n",
|
||||
unit, reply);
|
||||
return 0;
|
||||
@@ -341,14 +344,14 @@ int sdsize(int unit)
|
||||
/* Read data. */
|
||||
for (i=0; i<sizeof(csd); i++)
|
||||
{
|
||||
csd [i] = spi_transfer(sd_fd[unit],0xFF);
|
||||
csd [i] = spi_transfer(io, 0xFF);
|
||||
}
|
||||
/* Ignore CRC. */
|
||||
spi_transfer(sd_fd[unit],0xFF);
|
||||
spi_transfer(sd_fd[unit],0xFF);
|
||||
spi_transfer(io, 0xFF);
|
||||
spi_transfer(io, 0xFF);
|
||||
|
||||
/* Disable the card. */
|
||||
sd_deselect(sd_fd[unit]);
|
||||
sd_deselect(io);
|
||||
|
||||
/* CSD register has different structure
|
||||
* 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 reply, i;
|
||||
struct spiio *io = &sd_io[unit];
|
||||
|
||||
/* Send read-multiple command. */
|
||||
spi_select(sd_fd[unit]);
|
||||
if (sd_type[unit] != 3) offset <<= 9;
|
||||
spi_select(io);
|
||||
if (sd_type[unit] != 3)
|
||||
offset <<= 9;
|
||||
reply = card_cmd(unit, CMD_READ_MULTIPLE, offset<<1);
|
||||
if (reply != 0)
|
||||
{
|
||||
/* Command rejected. */
|
||||
printf ("sd%d: card_read: bad READ_MULTIPLE reply = %d, offset = %08x\n",
|
||||
unit, reply, offset<<1);
|
||||
sd_deselect(sd_fd[unit]);
|
||||
sd_deselect(io);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -395,7 +400,7 @@ again:
|
||||
for (i=0; ; i++)
|
||||
{
|
||||
int x = spl0();
|
||||
reply = spi_transfer(sd_fd[unit],0xFF);
|
||||
reply = spi_transfer(io, 0xFF);
|
||||
splx(x);
|
||||
if (reply == DATA_START_BLOCK)
|
||||
break;
|
||||
@@ -404,7 +409,7 @@ again:
|
||||
/* Command timed out. */
|
||||
printf ("sd%d: card_read: READ_MULTIPLE timed out, reply = %d\n",
|
||||
unit, reply);
|
||||
sd_deselect(sd_fd[unit]);
|
||||
sd_deselect(io);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -414,17 +419,17 @@ again:
|
||||
/* Read data. */
|
||||
if (bcount >= SECTSIZE)
|
||||
{
|
||||
spi_bulk_read_32_be(sd_fd[unit],SECTSIZE,data);
|
||||
spi_bulk_read_32_be(io, SECTSIZE,data);
|
||||
data += SECTSIZE;
|
||||
} else {
|
||||
spi_bulk_read(sd_fd[unit],bcount,(unsigned char *)data);
|
||||
spi_bulk_read(io, bcount, (unsigned char *)data);
|
||||
data += bcount;
|
||||
for (i=bcount; i<SECTSIZE; i++)
|
||||
spi_transfer(sd_fd[unit],0xFF);
|
||||
spi_transfer(io, 0xFF);
|
||||
}
|
||||
/* Ignore CRC. */
|
||||
spi_transfer(sd_fd[unit],0xFF);
|
||||
spi_transfer(sd_fd[unit],0xFF);
|
||||
spi_transfer(io, 0xFF);
|
||||
spi_transfer(io, 0xFF);
|
||||
|
||||
if (bcount > SECTSIZE)
|
||||
{
|
||||
@@ -435,7 +440,7 @@ again:
|
||||
|
||||
/* Stop a read-multiple sequence. */
|
||||
card_cmd(unit, CMD_STOP, 0);
|
||||
sd_deselect(sd_fd[unit]);
|
||||
sd_deselect(io);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -447,15 +452,16 @@ int
|
||||
card_write (int unit, unsigned offset, char *data, unsigned bcount)
|
||||
{
|
||||
unsigned reply, i;
|
||||
struct spiio *io = &sd_io[unit];
|
||||
|
||||
/* Send pre-erase count. */
|
||||
spi_select(sd_fd[unit]);
|
||||
spi_select(io);
|
||||
card_cmd(unit, CMD_APP, 0);
|
||||
reply = card_cmd(unit, CMD_SET_WBECNT, (bcount + SECTSIZE - 1) / SECTSIZE);
|
||||
if (reply != 0)
|
||||
{
|
||||
/* Command rejected. */
|
||||
sd_deselect(sd_fd[unit]);
|
||||
sd_deselect(io);
|
||||
printf("sd%d: card_write: bad SET_WBECNT reply = %02x, count = %u\n",
|
||||
unit, reply, (bcount + SECTSIZE - 1) / SECTSIZE);
|
||||
return 0;
|
||||
@@ -467,38 +473,38 @@ card_write (int unit, unsigned offset, char *data, unsigned bcount)
|
||||
if (reply != 0)
|
||||
{
|
||||
/* Command rejected. */
|
||||
sd_deselect(sd_fd[unit]);
|
||||
sd_deselect(io);
|
||||
printf("sd%d: card_write: bad WRITE_MULTIPLE reply = %02x\n", unit, reply);
|
||||
return 0;
|
||||
}
|
||||
sd_deselect(sd_fd[unit]);
|
||||
sd_deselect(io);
|
||||
again:
|
||||
/* Select, wait while busy. */
|
||||
spi_select(sd_fd[unit]);
|
||||
spi_select(io);
|
||||
spi_wait_ready(unit, TIMO_WAIT_WDATA, &sd_timo_wait_wdata);
|
||||
|
||||
/* Send data. */
|
||||
spi_transfer(sd_fd[unit],WRITE_MULTIPLE_TOKEN);
|
||||
spi_transfer(io, WRITE_MULTIPLE_TOKEN);
|
||||
if (bcount >= SECTSIZE)
|
||||
{
|
||||
spi_bulk_write_32_be(sd_fd[unit],SECTSIZE,data);
|
||||
spi_bulk_write_32_be(io, SECTSIZE, data);
|
||||
data += SECTSIZE;
|
||||
} else {
|
||||
spi_bulk_write(sd_fd[unit],bcount,(unsigned char *)data);
|
||||
spi_bulk_write(io, bcount, (unsigned char *)data);
|
||||
data += bcount;
|
||||
for (i=bcount; i<SECTSIZE; i++)
|
||||
spi_transfer(sd_fd[unit],0xFF);
|
||||
spi_transfer(io, 0xFF);
|
||||
}
|
||||
/* Send dummy CRC. */
|
||||
spi_transfer(sd_fd[unit],0xFF);
|
||||
spi_transfer(sd_fd[unit],0xFF);
|
||||
spi_transfer(io, 0xFF);
|
||||
spi_transfer(io, 0xFF);
|
||||
|
||||
/* Check if data accepted. */
|
||||
reply = spi_transfer(sd_fd[unit],0xFF);
|
||||
reply = spi_transfer(io, 0xFF);
|
||||
if ((reply & 0x1f) != 0x05)
|
||||
{
|
||||
/* Data rejected. */
|
||||
sd_deselect(sd_fd[unit]);
|
||||
sd_deselect(io);
|
||||
printf("sd%d: card_write: data rejected, reply = %02x\n", unit,reply);
|
||||
return 0;
|
||||
}
|
||||
@@ -507,7 +513,7 @@ again:
|
||||
int x = spl0();
|
||||
spi_wait_ready(unit, TIMO_WAIT_WDONE, &sd_timo_wait_wdone);
|
||||
splx(x);
|
||||
sd_deselect(sd_fd[unit]);
|
||||
sd_deselect(io);
|
||||
|
||||
if (bcount > SECTSIZE)
|
||||
{
|
||||
@@ -517,11 +523,11 @@ again:
|
||||
}
|
||||
|
||||
/* 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_transfer(sd_fd[unit],STOP_TRAN_TOKEN);
|
||||
spi_transfer(io, STOP_TRAN_TOKEN);
|
||||
spi_wait_ready(unit, TIMO_WAIT_WIDLE, &sd_timo_wait_widle);
|
||||
sd_deselect(sd_fd[unit]);
|
||||
sd_deselect(io);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -529,10 +535,13 @@ void sd_preinit (int unit)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Detect a card.
|
||||
*/
|
||||
int sdinit (int unit, int flag)
|
||||
{
|
||||
struct spiio *io = &sd_io[unit];
|
||||
unsigned nsectors;
|
||||
/* Detect a card. */
|
||||
|
||||
#ifdef SD0_ENA_PORT
|
||||
/* 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);
|
||||
return ENODEV;
|
||||
}
|
||||
if(!(flag & S_SILENT))
|
||||
if (! (flag & S_SILENT))
|
||||
{
|
||||
printf ("sd%d: type %s, size %u kbytes, speed %u Mbit/sec\n", unit,
|
||||
sd_type[unit]==3 ? "SDHC" :
|
||||
sd_type[unit]==2 ? "II" : "I",
|
||||
nsectors,
|
||||
spi_get_brg(sd_fd[unit]) / 1000);
|
||||
spi_get_brg(io) / 1000);
|
||||
}
|
||||
DEBUG("sd%d: init done\n",unit);
|
||||
return 0;
|
||||
@@ -612,6 +621,7 @@ sdprobe(config)
|
||||
{
|
||||
int unit = config->dev_unit;
|
||||
int cs = config->dev_pins[0];
|
||||
struct spiio *io = &sd_io[unit];
|
||||
|
||||
if (unit < 0 || unit >= NSD)
|
||||
return 0;
|
||||
@@ -622,12 +632,10 @@ sdprobe(config)
|
||||
int pin = cs & 15;
|
||||
struct gpioreg *base = port + (struct gpioreg*) &TRISA;
|
||||
|
||||
int fd = spi_open(config->dev_ctlr, (unsigned int*) base, pin);
|
||||
if (fd < 0) {
|
||||
printf("sd%d: Cannot open SPI port\n", unit);
|
||||
if (spi_setup(io, config->dev_ctlr, (unsigned int*) base, pin) != 0) {
|
||||
printf("sd%u: cannot open SPI%u port\n", unit, config->dev_ctlr);
|
||||
return 0;
|
||||
}
|
||||
sd_fd[unit] = fd;
|
||||
|
||||
#ifdef SD0_ENA_PORT
|
||||
if (unit == 0) {
|
||||
@@ -647,8 +655,8 @@ sdprobe(config)
|
||||
}
|
||||
#endif
|
||||
|
||||
spi_brg(fd, SD0_MHZ * 1000);
|
||||
spi_set(fd, PIC32_SPICON_CKE);
|
||||
spi_brg(io, SD0_MHZ * 1000);
|
||||
spi_set(io, PIC32_SPICON_CKE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <sys/errno.h>
|
||||
#include <sys/dk.h>
|
||||
#include <sys/rdisk.h>
|
||||
#include <sys/spi_bus.h>
|
||||
#include <sys/spi.h>
|
||||
#include <sys/debug.h>
|
||||
|
||||
#define SPIRAM_WREN 0x06
|
||||
|
||||
132
sys/pic32/spi.c
132
sys/pic32/spi.c
@@ -29,7 +29,6 @@
|
||||
#include <sys/uio.h>
|
||||
#include <sys/kconfig.h>
|
||||
#include <sys/spi.h>
|
||||
#include <sys/spi_bus.h>
|
||||
|
||||
const struct devspec spidevs[] = {
|
||||
{ 0, "spi1" },
|
||||
@@ -49,7 +48,7 @@ const struct devspec spidevs[] = {
|
||||
# define PRINTDBG(...) /*empty*/
|
||||
#endif
|
||||
|
||||
int spi_fd[NSPI];
|
||||
struct spiio spi_io[NSPI]; /* Data for SPI driver */
|
||||
|
||||
/*
|
||||
* Open /dev/spi# device.
|
||||
@@ -57,9 +56,10 @@ int spi_fd[NSPI];
|
||||
* - rate 250 kHz;
|
||||
* - 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)
|
||||
return ENXIO;
|
||||
@@ -67,15 +67,14 @@ int spidev_open (dev_t dev, int flag, int mode)
|
||||
if (u.u_uid != 0)
|
||||
return EPERM;
|
||||
|
||||
spi_fd[channel] = spi_open(channel+1,NULL,NULL);
|
||||
if(spi_fd[channel]==-1)
|
||||
if (! io->bus)
|
||||
return ENODEV;
|
||||
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)
|
||||
return ENXIO;
|
||||
@@ -83,16 +82,15 @@ int spidev_close (dev_t dev, int flag, int mode)
|
||||
if (u.u_uid != 0)
|
||||
return EPERM;
|
||||
|
||||
spi_close(spi_fd[channel]);
|
||||
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;
|
||||
}
|
||||
|
||||
int spidev_write (dev_t dev, struct uio *uio, int flag)
|
||||
int spidev_write(dev_t dev, struct uio *uio, int flag)
|
||||
{
|
||||
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_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;
|
||||
int nelem;
|
||||
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;
|
||||
|
||||
//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)
|
||||
return ENXIO;
|
||||
|
||||
@@ -141,124 +140,140 @@ int spidev_ioctl (dev_t dev, u_int cmd, caddr_t addr, int flag)
|
||||
* 2 1 0
|
||||
* 3 1 1
|
||||
*/
|
||||
if((unsigned int) addr & 0x01)
|
||||
spi_set(spi_fd[channel], PIC32_SPICON_CKE);
|
||||
if((unsigned int) addr & 0x02)
|
||||
spi_set(spi_fd[channel], PIC32_SPICON_CKP);
|
||||
if ((unsigned) addr & 1)
|
||||
spi_set(io, PIC32_SPICON_CKE);
|
||||
if ((unsigned) addr & 2)
|
||||
spi_set(io, PIC32_SPICON_CKP);
|
||||
return 0;
|
||||
|
||||
case SPICTL_SETRATE: /* set clock rate, kHz */
|
||||
spi_brg(spi_fd[channel], (unsigned int) addr);
|
||||
spi_brg(io, (unsigned int) addr);
|
||||
return 0;
|
||||
|
||||
case SPICTL_SETSELPIN: /* set select pin */
|
||||
portnum = ((unsigned int) addr >> 8) & 7;
|
||||
if (! portnum)
|
||||
return 0;
|
||||
spi_set_cspin(spi_fd[channel],
|
||||
(unsigned int *)tris[portnum],
|
||||
(unsigned int) addr & 15);
|
||||
spi_set_cspin(io, (unsigned*) tris[portnum], (unsigned) addr & 15);
|
||||
return 0;
|
||||
|
||||
case SPICTL_IO8(0): /* transfer n*8 bits */
|
||||
spi_select(spi_fd[channel]);
|
||||
spi_select(io);
|
||||
nelem = (cmd >> 16) & IOCPARM_MASK;
|
||||
if (baduaddr (addr) || baduaddr (addr + nelem - 1))
|
||||
if (baduaddr(addr) || baduaddr(addr + nelem - 1))
|
||||
return EFAULT;
|
||||
spi_bulk_rw(spi_fd[channel], nelem, cval);
|
||||
spi_deselect(spi_fd[channel]);
|
||||
spi_bulk_rw(io, nelem, cval);
|
||||
spi_deselect(io);
|
||||
break;
|
||||
|
||||
case SPICTL_IO16(0): /* transfer n*16 bits */
|
||||
spi_select(io);
|
||||
nelem = (cmd >> 16) & IOCPARM_MASK;
|
||||
if (((unsigned) addr & 1) ||
|
||||
baduaddr (addr) || baduaddr (addr + nelem*2 - 1))
|
||||
baduaddr(addr) || baduaddr(addr + nelem*2 - 1))
|
||||
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;
|
||||
|
||||
case SPICTL_IO32(0): /* transfer n*32 bits */
|
||||
spi_select(io);
|
||||
nelem = (cmd >> 16) & IOCPARM_MASK;
|
||||
if (((unsigned) addr & 3) ||
|
||||
baduaddr (addr) || baduaddr (addr + nelem*4 - 1))
|
||||
baduaddr(addr) || baduaddr(addr + nelem*4 - 1))
|
||||
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;
|
||||
|
||||
// IM: added R and W and BE modes
|
||||
case SPICTL_IO8R(0): /* transfer n*8 bits */
|
||||
spi_select(spi_fd[channel]);
|
||||
spi_select(io);
|
||||
nelem = (cmd >> 16) & IOCPARM_MASK;
|
||||
if (baduaddr (addr) || baduaddr (addr + nelem - 1))
|
||||
if (baduaddr(addr) || baduaddr(addr + nelem - 1))
|
||||
return EFAULT;
|
||||
spi_bulk_read(spi_fd[channel], nelem, cval);
|
||||
spi_deselect(spi_fd[channel]);
|
||||
spi_bulk_read(io, nelem, cval);
|
||||
spi_deselect(io);
|
||||
break;
|
||||
|
||||
case SPICTL_IO16R(0): /* transfer n*16 bits */
|
||||
spi_select(io);
|
||||
nelem = (cmd >> 16) & IOCPARM_MASK;
|
||||
if (((unsigned) addr & 1) ||
|
||||
baduaddr (addr) || baduaddr (addr + nelem*2 - 1))
|
||||
baduaddr(addr) || baduaddr(addr + nelem*2 - 1))
|
||||
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;
|
||||
|
||||
case SPICTL_IO32R(0): /* transfer n*32 bits */
|
||||
spi_select(io);
|
||||
nelem = (cmd >> 16) & IOCPARM_MASK;
|
||||
if (((unsigned) addr & 3) ||
|
||||
baduaddr (addr) || baduaddr (addr + nelem*4 - 1))
|
||||
baduaddr(addr) || baduaddr(addr + nelem*4 - 1))
|
||||
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;
|
||||
|
||||
case SPICTL_IO8W(0): /* transfer n*8 bits */
|
||||
spi_select(spi_fd[channel]);
|
||||
spi_select(io);
|
||||
nelem = (cmd >> 16) & IOCPARM_MASK;
|
||||
if (baduaddr (addr) || baduaddr (addr + nelem - 1))
|
||||
if (baduaddr(addr) || baduaddr(addr + nelem - 1))
|
||||
return EFAULT;
|
||||
spi_bulk_write(spi_fd[channel], nelem, cval);
|
||||
spi_deselect(spi_fd[channel]);
|
||||
spi_bulk_write(io, nelem, cval);
|
||||
spi_deselect(io);
|
||||
break;
|
||||
|
||||
case SPICTL_IO16W(0): /* transfer n*16 bits */
|
||||
spi_select(io);
|
||||
nelem = (cmd >> 16) & IOCPARM_MASK;
|
||||
if (((unsigned) addr & 1) ||
|
||||
baduaddr (addr) || baduaddr (addr + nelem*2 - 1))
|
||||
baduaddr(addr) || baduaddr(addr + nelem*2 - 1))
|
||||
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;
|
||||
|
||||
case SPICTL_IO32W(0): /* transfer n*32 bits */
|
||||
spi_select(io);
|
||||
nelem = (cmd >> 16) & IOCPARM_MASK;
|
||||
if (((unsigned) addr & 3) ||
|
||||
baduaddr (addr) || baduaddr (addr + nelem*4 - 1))
|
||||
baduaddr(addr) || baduaddr(addr + nelem*4 - 1))
|
||||
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;
|
||||
|
||||
case SPICTL_IO32RB(0): /* transfer n*32 bits */
|
||||
spi_select(io);
|
||||
nelem = (cmd >> 16) & IOCPARM_MASK;
|
||||
if (((unsigned) addr & 3) ||
|
||||
baduaddr (addr) || baduaddr (addr + nelem*4 - 1))
|
||||
baduaddr(addr) || baduaddr(addr + nelem*4 - 1))
|
||||
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;
|
||||
|
||||
case SPICTL_IO32WB(0): /* transfer n*32 bits */
|
||||
spi_select(io);
|
||||
nelem = (cmd >> 16) & IOCPARM_MASK;
|
||||
if (((unsigned) addr & 3) ||
|
||||
baduaddr (addr) || baduaddr (addr + nelem*4 - 1))
|
||||
baduaddr(addr) || baduaddr(addr + nelem*4 - 1))
|
||||
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;
|
||||
|
||||
case SPICTL_IO32B(0): /* transfer n*32 bits */
|
||||
spi_select(io);
|
||||
nelem = (cmd >> 16) & IOCPARM_MASK;
|
||||
if (((unsigned) addr & 3) ||
|
||||
baduaddr (addr) || baduaddr (addr + nelem*4 - 1))
|
||||
baduaddr(addr) || baduaddr(addr + nelem*4 - 1))
|
||||
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;
|
||||
//
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -273,6 +288,7 @@ spiprobe(config)
|
||||
struct conf_ctlr *config;
|
||||
{
|
||||
int channel = config->ctlr_unit - 1;
|
||||
struct spiio *io = &spi_io[channel];
|
||||
int sdi, sdo, sck;
|
||||
static const int sdi_tab[NSPI] = {
|
||||
GPIO_PIN('C',4), /* SDI1 */
|
||||
@@ -304,15 +320,15 @@ spiprobe(config)
|
||||
sdo = GPIO_PIN('F',8);
|
||||
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(sdo), gpio_pinno(sdo),
|
||||
gpio_portname(sck), gpio_pinno(sck));
|
||||
|
||||
//TODO
|
||||
//struct spiio *io = &spitab[channel];
|
||||
//io->reg = spi_base[channel];
|
||||
//spi_setup(io, 0, 0);
|
||||
if (spi_setup(io, channel+1, 0, 0) != 0) {
|
||||
printf("spi%u: setup failed\n", channel+1);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,13 +4,16 @@
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/spi_bus.h>
|
||||
#include <sys/spi.h>
|
||||
|
||||
#define NSPI 4 /* Ports SPI1...SPI4 */
|
||||
|
||||
#define MAXSPIDEV 20
|
||||
|
||||
struct spi_dev spi_devices[MAXSPIDEV];
|
||||
static struct spireg *const spi_base[NSPI] = {
|
||||
(struct spireg*) &SPI1CON,
|
||||
(struct spireg*) &SPI2CON,
|
||||
(struct spireg*) &SPI3CON,
|
||||
(struct spireg*) &SPI4CON,
|
||||
};
|
||||
|
||||
//
|
||||
// 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 -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;
|
||||
struct spi_dev *dev;
|
||||
|
||||
// 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];
|
||||
if (channel <= 0 || channel > NSPI)
|
||||
return ENXIO;
|
||||
|
||||
// Set up the device
|
||||
switch (bus) {
|
||||
case 1:
|
||||
dev->bus = (struct spireg *)&SPI1CON;
|
||||
break;
|
||||
case 2:
|
||||
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;
|
||||
io->bus = spi_base[channel-1];
|
||||
io->cs_tris = tris;
|
||||
io->cs_pin = pin;
|
||||
io->baud = (BUS_KHZ / SPI_MHZ / 1000 + 1) / 2 - 1;
|
||||
io->mode = PIC32_SPICON_MSTEN | PIC32_SPICON_ON;
|
||||
|
||||
if (tris) {
|
||||
// Configure the CS pin
|
||||
LAT_SET(*tris) = 1<<pin;
|
||||
TRIS_CLR(*tris) = 1<<pin;
|
||||
}
|
||||
// return the ID of the device.
|
||||
return dno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
if (dev->cs_tris) {
|
||||
if (io->cs_tris) {
|
||||
// Configure the CS pin
|
||||
TRIS_SET(*dev->cs_tris) = 1<<pin;
|
||||
TRIS_SET(*io->cs_tris) = 1<<pin;
|
||||
}
|
||||
|
||||
dev->cs_tris = tris;
|
||||
dev->cs_pin = pin;
|
||||
io->cs_tris = tris;
|
||||
io->cs_pin = pin;
|
||||
if (tris) {
|
||||
// Configure the CS 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.
|
||||
// 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.
|
||||
//
|
||||
void spi_select(int dno)
|
||||
void spi_select(struct spiio *io)
|
||||
{
|
||||
struct spi_dev *dev;
|
||||
|
||||
if (dno >= MAXSPIDEV)
|
||||
if (io->cs_tris == NULL)
|
||||
return;
|
||||
|
||||
dev = &spi_devices[dno];
|
||||
if (! dev->bus)
|
||||
return;
|
||||
io->bus->brg = io->baud;
|
||||
io->bus->con = io->mode;
|
||||
|
||||
if (dev->cs_tris == NULL)
|
||||
return;
|
||||
|
||||
dev->bus->brg = dev->baud;
|
||||
dev->bus->con = dev->mode;
|
||||
|
||||
LAT_CLR(*dev->cs_tris) = 1 << dev->cs_pin;
|
||||
LAT_CLR(*io->cs_tris) = 1 << io->cs_pin;
|
||||
}
|
||||
|
||||
//
|
||||
// Deassert the CS pin of a device.
|
||||
//
|
||||
void spi_deselect(int dno)
|
||||
void spi_deselect(struct spiio *io)
|
||||
{
|
||||
struct spi_dev *dev;
|
||||
|
||||
if (dno >= MAXSPIDEV)
|
||||
if (io->cs_tris == NULL)
|
||||
return;
|
||||
|
||||
dev = &spi_devices[dno];
|
||||
if (! dev->bus)
|
||||
return;
|
||||
|
||||
if (dev->cs_tris == NULL)
|
||||
return;
|
||||
|
||||
LAT_SET(*dev->cs_tris) = 1 << dev->cs_pin;
|
||||
LAT_SET(*io->cs_tris) = 1 << io->cs_pin;
|
||||
}
|
||||
|
||||
//
|
||||
// Set a mode setting or two - just updates the internal records, the
|
||||
// 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;
|
||||
|
||||
if (dno >= MAXSPIDEV)
|
||||
return;
|
||||
|
||||
dev = &spi_devices[dno];
|
||||
if (! dev->bus)
|
||||
return;
|
||||
|
||||
dev->mode |= set;
|
||||
io->mode |= set;
|
||||
}
|
||||
|
||||
//
|
||||
// Clear a mode setting or two - just updates the internal records, the
|
||||
// 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;
|
||||
|
||||
if (dno >= MAXSPIDEV)
|
||||
return;
|
||||
|
||||
dev = &spi_devices[dno];
|
||||
if (! dev->bus)
|
||||
return;
|
||||
|
||||
dev->mode &= ~set;
|
||||
io->mode &= ~set;
|
||||
}
|
||||
|
||||
//
|
||||
// Return the current status of the SPI bus for the device in question
|
||||
// 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;
|
||||
|
||||
if (dno >= MAXSPIDEV)
|
||||
return 0;
|
||||
|
||||
dev = &spi_devices[dno];
|
||||
if (! dev->bus)
|
||||
return 0;
|
||||
|
||||
return dev->bus->stat;
|
||||
return io->bus->stat;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -226,22 +126,16 @@ unsigned int spi_status(int dno)
|
||||
// This is blocking, and waits for the transfer to complete
|
||||
// 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;
|
||||
struct spireg *reg = io->bus;
|
||||
unsigned int to = 100000;
|
||||
|
||||
if (dno >= MAXSPIDEV)
|
||||
return 0xF0;
|
||||
|
||||
dev = &spi_devices[dno];
|
||||
reg = dev->bus;
|
||||
if (! reg)
|
||||
return 0xF1;
|
||||
|
||||
reg->con = dev->mode;
|
||||
reg->brg = dev->baud;
|
||||
reg->con = io->mode;
|
||||
reg->brg = io->baud;
|
||||
|
||||
reg->buf = data;
|
||||
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.
|
||||
// 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;
|
||||
struct spireg *reg = io->bus;
|
||||
int *data32 = (int *)data;
|
||||
unsigned int words = len >> 2;
|
||||
unsigned int nread;
|
||||
unsigned int nwritten;
|
||||
|
||||
if (dno >= MAXSPIDEV)
|
||||
return;
|
||||
|
||||
dev = &spi_devices[dno];
|
||||
reg = dev->bus;
|
||||
if (! reg)
|
||||
return;
|
||||
|
||||
@@ -294,23 +182,17 @@ void spi_bulk_write_32_be(int dno, unsigned int len, char *data)
|
||||
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;
|
||||
struct spireg *reg = io->bus;
|
||||
int *data32 = (int *)data;
|
||||
unsigned int words = len >> 2;
|
||||
unsigned int nread;
|
||||
unsigned int nwritten;
|
||||
|
||||
if (dno >= MAXSPIDEV)
|
||||
return;
|
||||
|
||||
dev = &spi_devices[dno];
|
||||
reg = dev->bus;
|
||||
if (! reg)
|
||||
return;
|
||||
|
||||
@@ -332,23 +214,17 @@ void spi_bulk_write_32(int dno, unsigned int len, char *data)
|
||||
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;
|
||||
struct spireg *reg = io->bus;
|
||||
short *data16 = (short *)data;
|
||||
unsigned int words = len >> 1;
|
||||
unsigned int nread;
|
||||
unsigned int nwritten;
|
||||
|
||||
if (dno >= MAXSPIDEV)
|
||||
return;
|
||||
|
||||
dev = &spi_devices[dno];
|
||||
reg = dev->bus;
|
||||
if (! reg)
|
||||
return;
|
||||
|
||||
@@ -370,26 +246,18 @@ void spi_bulk_write_16(int dno, unsigned int len, char *data)
|
||||
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 int i;
|
||||
unsigned char out;
|
||||
|
||||
if (dno >= MAXSPIDEV)
|
||||
return;
|
||||
|
||||
dev = &spi_devices[dno];
|
||||
if (! dev->bus)
|
||||
return;
|
||||
|
||||
for (i=0; i<len; i++) {
|
||||
out = *data8;
|
||||
spi_transfer(dno, out);
|
||||
spi_transfer(io, out);
|
||||
data8++;
|
||||
}
|
||||
}
|
||||
@@ -400,20 +268,14 @@ void spi_bulk_write(int dno, unsigned int len, unsigned char *data)
|
||||
// the enhanced buffer mode.
|
||||
// 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;
|
||||
struct spireg *reg = io->bus;
|
||||
int *data32 = (int *)data;
|
||||
unsigned int words = len >> 2;
|
||||
unsigned int nread;
|
||||
unsigned int nwritten;
|
||||
|
||||
if (dno >= MAXSPIDEV)
|
||||
return;
|
||||
|
||||
dev = &spi_devices[dno];
|
||||
reg = dev->bus;
|
||||
if (! reg)
|
||||
return;
|
||||
|
||||
@@ -435,23 +297,17 @@ void spi_bulk_read_32_be(int dno, unsigned int len, char *data)
|
||||
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;
|
||||
struct spireg *reg = io->bus;
|
||||
int *data32 = (int *)data;
|
||||
unsigned int words = len >> 2;
|
||||
unsigned int nread;
|
||||
unsigned int nwritten;
|
||||
|
||||
if (dno >= MAXSPIDEV)
|
||||
return;
|
||||
|
||||
dev = &spi_devices[dno];
|
||||
reg = dev->bus;
|
||||
if (! reg)
|
||||
return;
|
||||
|
||||
@@ -473,23 +329,17 @@ void spi_bulk_read_32(int dno, unsigned int len, char *data)
|
||||
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;
|
||||
struct spireg *reg = io->bus;
|
||||
short *data16 = (short *)data;
|
||||
unsigned int words = len >> 1;
|
||||
unsigned int nread;
|
||||
unsigned int nwritten;
|
||||
|
||||
if (dno >= MAXSPIDEV)
|
||||
return;
|
||||
|
||||
dev = &spi_devices[dno];
|
||||
reg = dev->bus;
|
||||
if (! reg)
|
||||
return;
|
||||
|
||||
@@ -511,46 +361,32 @@ void spi_bulk_read_16(int dno, unsigned int len, char *data)
|
||||
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 int i;
|
||||
unsigned char in,out;
|
||||
|
||||
if (dno >= MAXSPIDEV)
|
||||
return;
|
||||
|
||||
dev = &spi_devices[dno];
|
||||
if (! dev->bus)
|
||||
return;
|
||||
|
||||
for (i=0; i<len; i++) {
|
||||
out = 0xFF;
|
||||
in = spi_transfer(dno, out);
|
||||
in = spi_transfer(io, out);
|
||||
*data8 = in;
|
||||
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;
|
||||
struct spireg *reg = io->bus;
|
||||
int *read32 = (int *)data;
|
||||
int *write32 = (int *)data;
|
||||
unsigned int words = len >> 2;
|
||||
unsigned int nread;
|
||||
unsigned int nwritten;
|
||||
|
||||
if (dno >= MAXSPIDEV)
|
||||
return;
|
||||
|
||||
dev = &spi_devices[dno];
|
||||
reg = dev->bus;
|
||||
if (! reg)
|
||||
return;
|
||||
|
||||
@@ -572,24 +408,18 @@ void spi_bulk_rw_32_be(int dno, unsigned int len, char *data)
|
||||
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;
|
||||
struct spireg *reg = io->bus;
|
||||
int *read32 = (int *)data;
|
||||
int *write32 = (int *)data;
|
||||
unsigned int words = len >> 2;
|
||||
unsigned int nread;
|
||||
unsigned int nwritten;
|
||||
|
||||
if (dno >= MAXSPIDEV)
|
||||
return;
|
||||
|
||||
dev = &spi_devices[dno];
|
||||
reg = dev->bus;
|
||||
if (! reg)
|
||||
return;
|
||||
|
||||
@@ -611,24 +441,18 @@ void spi_bulk_rw_32(int dno, unsigned int len, char *data)
|
||||
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;
|
||||
struct spireg *reg = io->bus;
|
||||
short *read16 = (short *)data;
|
||||
short *write16 = (short *)data;
|
||||
unsigned int words = len >> 1;
|
||||
unsigned int nread;
|
||||
unsigned int nwritten;
|
||||
|
||||
if (dno >= MAXSPIDEV)
|
||||
return;
|
||||
|
||||
dev = &spi_devices[dno];
|
||||
reg = dev->bus;
|
||||
if (! reg)
|
||||
return;
|
||||
|
||||
@@ -650,26 +474,18 @@ void spi_bulk_rw_16(int dno, unsigned int len, char *data)
|
||||
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 int i;
|
||||
unsigned char in,out;
|
||||
|
||||
if (dno >= MAXSPIDEV)
|
||||
return;
|
||||
|
||||
dev = &spi_devices[dno];
|
||||
if (! dev->bus)
|
||||
return;
|
||||
|
||||
for (i=0; i<len; i++) {
|
||||
out = *data8;
|
||||
in = spi_transfer(dno, out);
|
||||
in = spi_transfer(io, out);
|
||||
*data8 = in;
|
||||
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)
|
||||
//
|
||||
void spi_brg(int dno, unsigned int baud)
|
||||
void spi_brg(struct spiio *io, unsigned int baud)
|
||||
{
|
||||
struct spi_dev *dev;
|
||||
|
||||
if (dno >= MAXSPIDEV)
|
||||
return;
|
||||
|
||||
dev = &spi_devices[dno];
|
||||
if (! dev->bus)
|
||||
return;
|
||||
|
||||
dev->baud = (BUS_KHZ / baud + 1) / 2 - 1;
|
||||
io->baud = (BUS_KHZ / baud + 1) / 2 - 1;
|
||||
}
|
||||
|
||||
//
|
||||
// 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 (dno >= MAXSPIDEV)
|
||||
return "SPI?";
|
||||
|
||||
dev = &spi_devices[dno];
|
||||
if (! dev->bus)
|
||||
return "NO SPI BUS";
|
||||
|
||||
if (dev->bus == (struct spireg *)&SPI1CON)
|
||||
if (io->bus == spi_base[0])
|
||||
return "SPI1";
|
||||
|
||||
if (dev->bus == (struct spireg *)&SPI2CON)
|
||||
if (io->bus == spi_base[1])
|
||||
return "SPI2";
|
||||
|
||||
if (dev->bus == (struct spireg *)&SPI3CON)
|
||||
if (io->bus == spi_base[2])
|
||||
return "SPI3";
|
||||
|
||||
if (dev->bus == (struct spireg *)&SPI4CON)
|
||||
if (io->bus == spi_base[3])
|
||||
return "SPI4";
|
||||
|
||||
return "SPI?";
|
||||
@@ -724,18 +522,9 @@ char *spi_name(int dno)
|
||||
//
|
||||
// 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;
|
||||
|
||||
if (dno >= MAXSPIDEV)
|
||||
return '?';
|
||||
|
||||
dev = &spi_devices[dno];
|
||||
if (! dev->bus)
|
||||
return '?';
|
||||
|
||||
switch ((unsigned)dev->cs_tris) {
|
||||
switch ((unsigned)io->cs_tris) {
|
||||
case (unsigned)&TRISA: return 'A';
|
||||
case (unsigned)&TRISB: return 'B';
|
||||
case (unsigned)&TRISC: return 'C';
|
||||
@@ -747,30 +536,12 @@ char spi_csname(int dno)
|
||||
return '?';
|
||||
}
|
||||
|
||||
int spi_cspin(int dno)
|
||||
int spi_cspin(struct spiio *io)
|
||||
{
|
||||
struct spi_dev *dev;
|
||||
|
||||
if (dno >= MAXSPIDEV)
|
||||
return '?';
|
||||
|
||||
dev = &spi_devices[dno];
|
||||
if (! dev->bus)
|
||||
return '?';
|
||||
|
||||
return dev->cs_pin;
|
||||
return io->cs_pin;
|
||||
}
|
||||
|
||||
unsigned int spi_get_brg(int dno)
|
||||
unsigned int spi_get_brg(struct spiio *io)
|
||||
{
|
||||
struct spi_dev *dev;
|
||||
|
||||
if (dno >= MAXSPIDEV)
|
||||
return 0;
|
||||
|
||||
dev = &spi_devices[dno];
|
||||
if (! dev->bus)
|
||||
return 0;
|
||||
|
||||
return BUS_KHZ / (dev->baud + 1) / 2;
|
||||
return BUS_KHZ / (io->baud + 1) / 2;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user