use crate::clocks;
use core::cell::Cell;
use core::cmp;
use kernel::hil;
use kernel::hil::spi::cs::ChipSelectPolar;
use kernel::hil::spi::SpiMaster;
use kernel::hil::spi::SpiMasterClient;
use kernel::hil::spi::{ClockPhase, ClockPolarity};
use kernel::utilities::cells::MapCell;
use kernel::utilities::cells::OptionalCell;
use kernel::utilities::leasable_buffer::SubSliceMut;
use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
use kernel::utilities::registers::{register_bitfields, register_structs, ReadOnly, ReadWrite};
use kernel::utilities::StaticRef;
use kernel::ErrorCode;
const SPI_READ_IN_PROGRESS: u8 = 0b001;
const SPI_WRITE_IN_PROGRESS: u8 = 0b010;
const SPI_IN_PROGRESS: u8 = 0b100;
const SPI_IDLE: u8 = 0b000;
register_structs! {
SpiRegisters {
(0x000 => sspcr0: ReadWrite<u32, SSPCR0::Register>),
(0x004 => sspcr1: ReadWrite<u32, SSPCR1::Register>),
(0x008 => sspdr: ReadWrite<u32, SSPDR::Register>),
(0x00C => sspsr: ReadOnly<u32, SSPSR::Register>),
(0x010 => sspcpsr: ReadWrite<u32, SSPCPSR::Register>),
(0x014 => sspimsc: ReadWrite<u32, SSPIMSC::Register>),
(0x018 => sspris: ReadOnly<u32, SSPRIS::Register>),
(0x01C => sspmis: ReadOnly<u32, SSPMIS::Register>),
(0x020 => sspicr: ReadWrite<u32, SSPICR::Register>),
(0x024 => sspdmacr: ReadWrite<u32, SSPDMACR::Register>),
(0x028 => _reserved0),
(0xFE0 => sspperiphid0: ReadOnly<u32, SSPPERIPHID0::Register>),
(0xFE4 => sspperiphid1: ReadOnly<u32, SSPPERIPHID1::Register>),
(0xFE8 => sspperiphid2: ReadOnly<u32, SSPPERIPHID2::Register>),
(0xFEC => sspperiphid3: ReadOnly<u32, SSPPERIPHID3::Register>),
(0xFF0 => ssppcellid0: ReadOnly<u32, SSPPCELLID0::Register>),
(0xFF4 => ssppcellid1: ReadOnly<u32, SSPPCELLID1::Register>),
(0xFF8 => ssppcellid2: ReadOnly<u32, SSPPCELLID2::Register>),
(0xFFC => ssppcellid3: ReadOnly<u32, SSPPCELLID3::Register>),
(0x1000 => @END),
}
}
register_bitfields![u32,
SSPCR0 [
SCR OFFSET(8) NUMBITS(8) [],
SPH OFFSET(7) NUMBITS(1) [],
SPO OFFSET(6) NUMBITS(1) [],
FRF OFFSET(4) NUMBITS(2) [
MOTOROLA_SPI = 0b00,
TI_SINC_SERIAL = 0b01,
NAT_MICROWIRE = 0b10,
RESERVED = 0b11
],
DSS OFFSET(0) NUMBITS(4) [
RESERVED_0 = 0b0000,
RESERVED_1 = 0b0001,
RESERVED_2 = 0b0010,
DATA_4_BIT = 0b0011,
DATA_5_BIT = 0b0100,
DATA_6_BIT = 0b0101,
DATA_7_BIT = 0b0110,
DATA_8_BIT = 0b0111,
DATA_9_BIT = 0b1000,
DATA_10_BIT = 0b1001,
DATA_11_BIT = 0b1010,
DATA_12_BIT = 0b1011,
DATA_13_BIT = 0b1100,
DATA_14_BIT = 0b1101,
DATA_15_BIT = 0b1110,
DATA_16_BIT = 0b1111
]
],
SSPCR1 [
SOD OFFSET(3) NUMBITS(1) [],
MS OFFSET(2) NUMBITS(1) [],
SSE OFFSET(1) NUMBITS(1) [],
LBM OFFSET(0) NUMBITS(1) []
],
SSPDR [
DATA OFFSET(0) NUMBITS(16) []
],
SSPSR [
BSY OFFSET(4) NUMBITS(1) [],
RFF OFFSET(3) NUMBITS(1) [],
RNE OFFSET(2) NUMBITS(1) [],
TNF OFFSET(1) NUMBITS(1) [],
TFE OFFSET(0) NUMBITS(1) []
],
SSPCPSR [
CPSDVSR OFFSET(0) NUMBITS(8) []
],
SSPIMSC [
TXIM OFFSET(3) NUMBITS(1) [],
RXIM OFFSET(2) NUMBITS(1) [],
RTIM OFFSET(1) NUMBITS(1) [],
RORIM OFFSET(0) NUMBITS(1) []
],
SSPRIS [
TXRIS OFFSET(3) NUMBITS(1) [],
RXRIS OFFSET(2) NUMBITS(1) [],
RTRIS OFFSET(1) NUMBITS(1) [],
RORRIS OFFSET(0) NUMBITS(1) []
],
SSPMIS [
TXMIS OFFSET(3) NUMBITS(1) [],
RXMIS OFFSET(2) NUMBITS(1) [],
RTMIS OFFSET(1) NUMBITS(1) [],
RORMIS OFFSET(0) NUMBITS(1) []
],
SSPICR [
RTIC OFFSET(1) NUMBITS(1) [],
RORIC OFFSET(0) NUMBITS(1) []
],
SSPDMACR [
TXDMAE OFFSET(1) NUMBITS(1) [],
RXDMAE OFFSET(0) NUMBITS(1) []
],
SSPPERIPHID0 [
PARTNUMBER0 OFFSET(0) NUMBITS(8) []
],
SSPPERIPHID1 [
DESIGNER0 OFFSET(4) NUMBITS(4) [],
PARTNUMBER1 OFFSET(0) NUMBITS(4) []
],
SSPPERIPHID2 [
REVISION OFFSET(4) NUMBITS(4) [],
DESIGNER1 OFFSET(0) NUMBITS(4) []
],
SSPPERIPHID3 [
CONFIGURATION OFFSET(0) NUMBITS(8) []
],
SSPPCELLID0 [
SSPPCELLID0 OFFSET(0) NUMBITS(8) []
],
SSPPCELLID1 [
SSPPCELLID1 OFFSET(0) NUMBITS(8) []
],
SSPPCELLID2 [
SSPPCELLID2 OFFSET(0) NUMBITS(8) []
],
SSPPCELLID3 [
SSPPCELLID3 OFFSET(0) NUMBITS(8) []
]
];
const SPI0_BASE: StaticRef<SpiRegisters> =
unsafe { StaticRef::new(0x4003C000 as *const SpiRegisters) };
const SPI1_BASE: StaticRef<SpiRegisters> =
unsafe { StaticRef::new(0x40040000 as *const SpiRegisters) };
pub struct Spi<'a> {
registers: StaticRef<SpiRegisters>,
clocks: OptionalCell<&'a clocks::Clocks>,
master_client: OptionalCell<&'a dyn hil::spi::SpiMasterClient>,
active_slave: OptionalCell<ChipSelectPolar<'a, crate::gpio::RPGpioPin<'a>>>,
tx_buffer: MapCell<SubSliceMut<'static, u8>>,
tx_position: Cell<usize>,
rx_buffer: MapCell<SubSliceMut<'static, u8>>,
rx_position: Cell<usize>,
len: Cell<usize>,
transfers: Cell<u8>,
active_after: Cell<bool>,
}
impl<'a> Spi<'a> {
pub fn new_spi0() -> Self {
Self {
registers: SPI0_BASE,
clocks: OptionalCell::empty(),
master_client: OptionalCell::empty(),
active_slave: OptionalCell::empty(),
tx_buffer: MapCell::empty(),
tx_position: Cell::new(0),
rx_buffer: MapCell::empty(),
rx_position: Cell::new(0),
len: Cell::new(0),
transfers: Cell::new(SPI_IDLE),
active_after: Cell::new(false),
}
}
pub fn new_spi1() -> Self {
Self {
registers: SPI1_BASE,
clocks: OptionalCell::empty(),
master_client: OptionalCell::empty(),
active_slave: OptionalCell::empty(),
tx_buffer: MapCell::empty(),
tx_position: Cell::new(0),
rx_buffer: MapCell::empty(),
rx_position: Cell::new(0),
len: Cell::new(0),
transfers: Cell::new(SPI_IDLE),
active_after: Cell::new(false),
}
}
pub(crate) fn set_clocks(&self, clocks: &'a clocks::Clocks) {
self.clocks.set(clocks);
}
fn enable(&self) {
self.registers.sspcr1.modify(SSPCR1::SSE::SET);
}
fn disable(&self) {
self.registers.sspcr1.modify(SSPCR1::SSE::CLEAR);
}
pub fn handle_interrupt(&self) {
if self.registers.sspsr.is_set(SSPSR::TFE) {
if self.tx_buffer.is_some() {
while self.registers.sspsr.is_set(SSPSR::TNF)
&& self.tx_position.get() < self.len.get()
{
self.tx_buffer.map(|buf| {
self.registers
.sspdr
.write(SSPDR::DATA.val(buf[self.tx_position.get()].into()));
self.tx_position.set(self.tx_position.get() + 1);
});
}
if self.tx_position.get() >= self.len.get() {
self.transfers
.set(self.transfers.get() & !SPI_WRITE_IN_PROGRESS);
}
} else {
self.registers.sspimsc.modify(SSPIMSC::TXIM::CLEAR);
}
}
while self.registers.sspsr.is_set(SSPSR::RNE) {
let byte = self.registers.sspdr.read(SSPDR::DATA) as u8;
if self.rx_buffer.is_some() {
if self.rx_position.get() < self.len.get() {
self.rx_buffer.map(|buf| {
buf[self.rx_position.get()] = byte;
});
self.rx_position.set(self.rx_position.get() + 1);
} else {
self.transfers
.set(self.transfers.get() & !SPI_READ_IN_PROGRESS);
}
}
}
if self.transfers.get() == SPI_IN_PROGRESS {
if !self.active_after.get() {
self.active_slave.map(|p| {
p.deactivate();
});
}
self.master_client.map(|client| {
self.registers.sspimsc.modify(SSPIMSC::TXIM::CLEAR);
self.registers.sspimsc.modify(SSPIMSC::RXIM::CLEAR);
self.disable();
self.transfers.set(SPI_IDLE);
self.tx_buffer.take().map(|buf| {
client.read_write_done(buf, self.rx_buffer.take(), Ok(self.len.get()))
});
});
}
}
fn read_write_bytes(
&self,
write_buffer: Option<SubSliceMut<'static, u8>>,
read_buffer: Option<SubSliceMut<'static, u8>>,
) -> Result<
(),
(
ErrorCode,
Option<SubSliceMut<'static, u8>>,
Option<SubSliceMut<'static, u8>>,
),
> {
if write_buffer.is_none() && read_buffer.is_none() {
return Err((ErrorCode::INVAL, write_buffer, read_buffer));
}
if self.transfers.get() == SPI_IDLE {
self.enable();
self.registers.sspimsc.modify(SSPIMSC::TXIM::CLEAR);
self.registers.sspimsc.modify(SSPIMSC::RXIM::CLEAR);
self.active_slave.map(|p| {
p.activate();
});
self.transfers.set(SPI_IN_PROGRESS);
let len = match (
write_buffer.as_ref().map(|b| b.len()),
read_buffer.as_ref().map(|b| b.len()),
) {
(Some(wl), Some(rl)) => cmp::min(wl, rl),
(Some(wl), None) => wl,
(None, Some(rl)) => rl,
(None, None) => 0,
};
if write_buffer.is_some() {
self.transfers
.set(self.transfers.get() | SPI_WRITE_IN_PROGRESS);
}
if read_buffer.is_some() {
self.transfers
.set(self.transfers.get() | SPI_READ_IN_PROGRESS);
}
read_buffer.map(|buf| {
self.rx_buffer.replace(buf);
self.len.set(len);
self.rx_position.set(0);
self.registers.sspimsc.modify(SSPIMSC::RXIM::SET);
});
write_buffer.map(|buf| {
self.tx_buffer.replace(buf);
self.len.set(len);
self.tx_position.set(0);
self.registers.sspimsc.modify(SSPIMSC::TXIM::SET);
});
Ok(())
} else {
Err((ErrorCode::BUSY, write_buffer, read_buffer))
}
}
fn set_polarity(&self, polarity: ClockPolarity) -> Result<(), ErrorCode> {
if !self.is_busy() {
self.enable();
match polarity {
ClockPolarity::IdleHigh => self.registers.sspcr0.modify(SSPCR0::SPO::SET),
ClockPolarity::IdleLow => self.registers.sspcr0.modify(SSPCR0::SPO::CLEAR),
}
self.disable();
Ok(())
} else {
Err(ErrorCode::BUSY)
}
}
fn get_polarity(&self) -> ClockPolarity {
if !self.registers.sspcr0.is_set(SSPCR0::SPO) {
ClockPolarity::IdleLow
} else {
ClockPolarity::IdleHigh
}
}
fn set_phase(&self, phase: ClockPhase) -> Result<(), ErrorCode> {
if !self.is_busy() {
self.enable();
match phase {
ClockPhase::SampleLeading => self.registers.sspcr0.modify(SSPCR0::SPH::CLEAR),
ClockPhase::SampleTrailing => self.registers.sspcr0.modify(SSPCR0::SPH::SET),
}
self.disable();
Ok(())
} else {
Err(ErrorCode::BUSY)
}
}
fn get_phase(&self) -> ClockPhase {
if !self.registers.sspcr0.is_set(SSPCR0::SPH) {
ClockPhase::SampleLeading
} else {
ClockPhase::SampleTrailing
}
}
fn set_format(&self) {
self.registers.sspcr0.modify(SSPCR0::DSS::DATA_8_BIT);
self.registers.sspcr0.modify(SSPCR0::SPO::CLEAR);
self.registers.sspcr0.modify(SSPCR0::SPH::CLEAR);
}
}
impl<'a> SpiMaster<'a> for Spi<'a> {
type ChipSelect = ChipSelectPolar<'a, crate::gpio::RPGpioPin<'a>>;
fn set_client(&self, client: &'a dyn SpiMasterClient) {
self.master_client.set(client);
}
fn init(&self) -> Result<(), ErrorCode> {
match self.set_rate(16 * 1000 * 1000) {
Err(error) => Err(error),
Ok(_) => Ok(()),
}?;
self.set_format();
self.registers.sspdmacr.modify(SSPDMACR::TXDMAE::SET);
self.registers.sspdmacr.modify(SSPDMACR::RXDMAE::SET);
self.registers.sspcr1.modify(SSPCR1::MS::CLEAR);
Ok(())
}
fn is_busy(&self) -> bool {
self.transfers.get() != SPI_IDLE
}
fn read_write_bytes(
&self,
write_buffer: SubSliceMut<'static, u8>,
read_buffer: Option<SubSliceMut<'static, u8>>,
) -> Result<
(),
(
ErrorCode,
SubSliceMut<'static, u8>,
Option<SubSliceMut<'static, u8>>,
),
> {
if self.is_busy() {
return Err((ErrorCode::BUSY, write_buffer, read_buffer));
}
match self.read_write_bytes(Some(write_buffer), read_buffer) {
Err((error, some_write_buffer, read_buffer)) => {
Err((error, some_write_buffer.unwrap(), read_buffer))
}
Ok(()) => Ok(()),
}
}
fn write_byte(&self, out_val: u8) -> Result<(), ErrorCode> {
if !self.is_busy() {
while !self.registers.sspsr.is_set(SSPSR::TFE) {}
self.registers.sspdr.modify(SSPDR::DATA.val(out_val as u32));
Ok(())
} else {
Err(ErrorCode::BUSY)
}
}
fn read_byte(&self) -> Result<u8, ErrorCode> {
self.read_write_byte(0)
}
fn read_write_byte(&self, val: u8) -> Result<u8, ErrorCode> {
if !self.is_busy() {
self.write_byte(val)?;
while !self.registers.sspsr.is_set(SSPSR::RNE) {}
Ok(self.registers.sspdr.read(SSPDR::DATA) as u8)
} else {
Err(ErrorCode::BUSY)
}
}
fn specify_chip_select(&self, cs: Self::ChipSelect) -> Result<(), ErrorCode> {
if !self.is_busy() {
self.active_slave.set(cs);
Ok(())
} else {
Err(ErrorCode::BUSY)
}
}
fn set_rate(&self, baudrate: u32) -> Result<u32, ErrorCode> {
let freq_in = self.clocks.map_or(125_000_000, |clocks| {
clocks.get_frequency(clocks::Clock::Peripheral)
});
if baudrate > freq_in {
return Err(ErrorCode::INVAL);
}
let mut prescale = 0;
let mut postdiv = 0;
for p in (2..254).step_by(2) {
if (freq_in as u64) < (((p + 2) * 256) as u64 * baudrate as u64) {
prescale = p;
break;
}
}
for p in (2..256).rev() {
if (freq_in / (prescale * (p - 1))) > baudrate {
postdiv = p;
break;
}
}
if prescale > 0 && postdiv > 0 {
self.registers
.sspcpsr
.modify(SSPCPSR::CPSDVSR.val(prescale));
self.registers.sspcr0.modify(SSPCR0::SCR.val(postdiv - 1));
Ok(freq_in / (prescale * postdiv))
} else {
Err(ErrorCode::INVAL)
}
}
fn get_rate(&self) -> u32 {
let freq_in = self.clocks.map_or(125_000_000, |clocks| {
clocks.get_frequency(clocks::Clock::Peripheral)
});
let prescale = self.registers.sspcpsr.read(SSPCPSR::CPSDVSR);
let postdiv = self.registers.sspcr0.read(SSPCR0::SCR) + 1;
freq_in / (prescale * postdiv)
}
fn set_polarity(&self, polarity: ClockPolarity) -> Result<(), ErrorCode> {
self.set_polarity(polarity)
}
fn get_polarity(&self) -> ClockPolarity {
self.get_polarity()
}
fn set_phase(&self, phase: ClockPhase) -> Result<(), ErrorCode> {
self.set_phase(phase)
}
fn get_phase(&self) -> ClockPhase {
self.get_phase()
}
fn hold_low(&self) {
self.active_after.set(true);
}
fn release_low(&self) {
self.active_after.set(false);
}
}