mirror of https://gerrit.osmocom.org/libusrp
382 lines
7.3 KiB
C
382 lines
7.3 KiB
C
/* -*- c++ -*- */
|
|
/*
|
|
* Copyright 2004,2006 Free Software Foundation, Inc.
|
|
*
|
|
* This file is part of GNU Radio
|
|
*
|
|
* GNU Radio is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3, or (at your option)
|
|
* any later version.
|
|
*
|
|
* GNU Radio is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with GNU Radio; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "spi.h"
|
|
#include "usrp_rev2_regs.h"
|
|
|
|
static void
|
|
setup_enables (unsigned char enables)
|
|
{
|
|
// Software eanbles are active high.
|
|
// Hardware enables are active low.
|
|
|
|
// Uhh, the CODECs are active low, but the FPGA is active high...
|
|
enables ^= SPI_ENABLE_FPGA;
|
|
|
|
// KLUDGE: This code is fragile, but reasonably fast...
|
|
// low three bits of enables go into port A
|
|
USRP_PA = USRP_PA | (0x7 << 3); // disable FPGA, CODEC_A, CODEC_B
|
|
USRP_PA ^= (enables & 0x7) << 3; // enable specified devs
|
|
|
|
// high four bits of enables go into port E
|
|
USRP_PE = USRP_PE | (0xf << 4); // disable TX_A, RX_A, TX_B, RX_B
|
|
USRP_PE ^= (enables & 0xf0); // enable specified devs
|
|
}
|
|
|
|
#define disable_all() setup_enables (0)
|
|
|
|
void
|
|
init_spi (void)
|
|
{
|
|
disable_all (); /* disable all devs */
|
|
bitS_OUT = 0; /* idle state has CLK = 0 */
|
|
}
|
|
|
|
#if 0
|
|
static unsigned char
|
|
count_bits8 (unsigned char v)
|
|
{
|
|
static unsigned char count4[16] = {
|
|
0, // 0
|
|
1, // 1
|
|
1, // 2
|
|
2, // 3
|
|
1, // 4
|
|
2, // 5
|
|
2, // 6
|
|
3, // 7
|
|
1, // 8
|
|
2, // 9
|
|
2, // a
|
|
3, // b
|
|
2, // c
|
|
3, // d
|
|
3, // e
|
|
4 // f
|
|
};
|
|
return count4[v & 0xf] + count4[(v >> 4) & 0xf];
|
|
}
|
|
|
|
#else
|
|
|
|
static unsigned char
|
|
count_bits8 (unsigned char v)
|
|
{
|
|
unsigned char count = 0;
|
|
if (v & (1 << 0)) count++;
|
|
if (v & (1 << 1)) count++;
|
|
if (v & (1 << 2)) count++;
|
|
if (v & (1 << 3)) count++;
|
|
if (v & (1 << 4)) count++;
|
|
if (v & (1 << 5)) count++;
|
|
if (v & (1 << 6)) count++;
|
|
if (v & (1 << 7)) count++;
|
|
return count;
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
write_byte_msb (unsigned char v);
|
|
|
|
static void
|
|
write_bytes_msb (const xdata unsigned char *buf, unsigned char len);
|
|
|
|
static void
|
|
read_bytes_msb (xdata unsigned char *buf, unsigned char len);
|
|
|
|
|
|
// returns non-zero if successful, else 0
|
|
unsigned char
|
|
spi_read (unsigned char header_hi, unsigned char header_lo,
|
|
unsigned char enables, unsigned char format,
|
|
xdata unsigned char *buf, unsigned char len)
|
|
{
|
|
if (count_bits8 (enables) > 1)
|
|
return 0; // error, too many enables set
|
|
|
|
setup_enables (enables);
|
|
|
|
if (format & SPI_FMT_LSB){ // order: LSB
|
|
#if 1
|
|
return 0; // error, not implemented
|
|
#else
|
|
switch (format & SPI_FMR_HDR_MASK){
|
|
case SPI_FMT_HDR_0:
|
|
break;
|
|
case SPI_FMT_HDR_1:
|
|
write_byte_lsb (header_lo);
|
|
break;
|
|
case SPI_FMT_HDR_2:
|
|
write_byte_lsb (header_lo);
|
|
write_byte_lsb (header_hi);
|
|
break;
|
|
default:
|
|
return 0; // error
|
|
}
|
|
if (len != 0)
|
|
read_bytes_lsb (buf, len);
|
|
#endif
|
|
}
|
|
|
|
else { // order: MSB
|
|
|
|
switch (format & SPI_FMT_HDR_MASK){
|
|
case SPI_FMT_HDR_0:
|
|
break;
|
|
case SPI_FMT_HDR_1:
|
|
write_byte_msb (header_lo);
|
|
break;
|
|
case SPI_FMT_HDR_2:
|
|
write_byte_msb (header_hi);
|
|
write_byte_msb (header_lo);
|
|
break;
|
|
default:
|
|
return 0; // error
|
|
}
|
|
if (len != 0)
|
|
read_bytes_msb (buf, len);
|
|
}
|
|
|
|
disable_all ();
|
|
return 1; // success
|
|
}
|
|
|
|
|
|
// returns non-zero if successful, else 0
|
|
unsigned char
|
|
spi_write (unsigned char header_hi, unsigned char header_lo,
|
|
unsigned char enables, unsigned char format,
|
|
const xdata unsigned char *buf, unsigned char len)
|
|
{
|
|
setup_enables (enables);
|
|
|
|
if (format & SPI_FMT_LSB){ // order: LSB
|
|
#if 1
|
|
return 0; // error, not implemented
|
|
#else
|
|
switch (format & SPI_FMR_HDR_MASK){
|
|
case SPI_FMT_HDR_0:
|
|
break;
|
|
case SPI_FMT_HDR_1:
|
|
write_byte_lsb (header_lo);
|
|
break;
|
|
case SPI_FMT_HDR_2:
|
|
write_byte_lsb (header_lo);
|
|
write_byte_lsb (header_hi);
|
|
break;
|
|
default:
|
|
return 0; // error
|
|
}
|
|
if (len != 0)
|
|
write_bytes_lsb (buf, len);
|
|
#endif
|
|
}
|
|
|
|
else { // order: MSB
|
|
|
|
switch (format & SPI_FMT_HDR_MASK){
|
|
case SPI_FMT_HDR_0:
|
|
break;
|
|
case SPI_FMT_HDR_1:
|
|
write_byte_msb (header_lo);
|
|
break;
|
|
case SPI_FMT_HDR_2:
|
|
write_byte_msb (header_hi);
|
|
write_byte_msb (header_lo);
|
|
break;
|
|
default:
|
|
return 0; // error
|
|
}
|
|
if (len != 0)
|
|
write_bytes_msb (buf, len);
|
|
}
|
|
|
|
disable_all ();
|
|
return 1; // success
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
|
|
static void
|
|
write_byte_msb (unsigned char v)
|
|
{
|
|
v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit)
|
|
bitS_OUT = v & 0x1;
|
|
bitS_CLK = 1;
|
|
bitS_CLK = 0;
|
|
|
|
v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit)
|
|
bitS_OUT = v & 0x1;
|
|
bitS_CLK = 1;
|
|
bitS_CLK = 0;
|
|
|
|
v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit)
|
|
bitS_OUT = v & 0x1;
|
|
bitS_CLK = 1;
|
|
bitS_CLK = 0;
|
|
|
|
v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit)
|
|
bitS_OUT = v & 0x1;
|
|
bitS_CLK = 1;
|
|
bitS_CLK = 0;
|
|
|
|
v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit)
|
|
bitS_OUT = v & 0x1;
|
|
bitS_CLK = 1;
|
|
bitS_CLK = 0;
|
|
|
|
v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit)
|
|
bitS_OUT = v & 0x1;
|
|
bitS_CLK = 1;
|
|
bitS_CLK = 0;
|
|
|
|
v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit)
|
|
bitS_OUT = v & 0x1;
|
|
bitS_CLK = 1;
|
|
bitS_CLK = 0;
|
|
|
|
v = (v << 1) | (v >> 7); // rotate left (MSB into bottom bit)
|
|
bitS_OUT = v & 0x1;
|
|
bitS_CLK = 1;
|
|
bitS_CLK = 0;
|
|
}
|
|
|
|
static void
|
|
write_bytes_msb (const xdata unsigned char *buf, unsigned char len)
|
|
{
|
|
while (len-- != 0){
|
|
write_byte_msb (*buf++);
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
/*
|
|
* This is incorrectly compiled by SDCC 2.4.0
|
|
*/
|
|
static unsigned char
|
|
read_byte_msb (void)
|
|
{
|
|
unsigned char v = 0;
|
|
|
|
bitS_CLK = 1;
|
|
v |= bitS_IN;
|
|
bitS_CLK = 0;
|
|
|
|
v = v << 1;
|
|
bitS_CLK = 1;
|
|
v |= bitS_IN;
|
|
bitS_CLK = 0;
|
|
|
|
v = v << 1;
|
|
bitS_CLK = 1;
|
|
v |= bitS_IN;
|
|
bitS_CLK = 0;
|
|
|
|
v = v << 1;
|
|
bitS_CLK = 1;
|
|
v |= bitS_IN;
|
|
bitS_CLK = 0;
|
|
|
|
v = v << 1;
|
|
bitS_CLK = 1;
|
|
v |= bitS_IN;
|
|
bitS_CLK = 0;
|
|
|
|
v = v << 1;
|
|
bitS_CLK = 1;
|
|
v |= bitS_IN;
|
|
bitS_CLK = 0;
|
|
|
|
v = v << 1;
|
|
bitS_CLK = 1;
|
|
v |= bitS_IN;
|
|
bitS_CLK = 0;
|
|
|
|
v = v << 1;
|
|
bitS_CLK = 1;
|
|
v |= bitS_IN;
|
|
bitS_CLK = 0;
|
|
|
|
return v;
|
|
}
|
|
#else
|
|
static unsigned char
|
|
read_byte_msb (void) _naked
|
|
{
|
|
_asm
|
|
clr a
|
|
|
|
setb _bitS_CLK
|
|
mov c, _bitS_IN
|
|
rlc a
|
|
clr _bitS_CLK
|
|
|
|
setb _bitS_CLK
|
|
mov c, _bitS_IN
|
|
rlc a
|
|
clr _bitS_CLK
|
|
|
|
setb _bitS_CLK
|
|
mov c, _bitS_IN
|
|
rlc a
|
|
clr _bitS_CLK
|
|
|
|
setb _bitS_CLK
|
|
mov c, _bitS_IN
|
|
rlc a
|
|
clr _bitS_CLK
|
|
|
|
setb _bitS_CLK
|
|
mov c, _bitS_IN
|
|
rlc a
|
|
clr _bitS_CLK
|
|
|
|
setb _bitS_CLK
|
|
mov c, _bitS_IN
|
|
rlc a
|
|
clr _bitS_CLK
|
|
|
|
setb _bitS_CLK
|
|
mov c, _bitS_IN
|
|
rlc a
|
|
clr _bitS_CLK
|
|
|
|
setb _bitS_CLK
|
|
mov c, _bitS_IN
|
|
rlc a
|
|
clr _bitS_CLK
|
|
|
|
mov dpl,a
|
|
ret
|
|
_endasm;
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
read_bytes_msb (xdata unsigned char *buf, unsigned char len)
|
|
{
|
|
while (len-- != 0){
|
|
*buf++ = read_byte_msb ();
|
|
}
|
|
}
|
|
|