orange 0.1.3

Hardware support crate for OrangeSoC.
use crate::comm;
use crate::interrupt::without_interrupts;

pub struct SpiMaster {
    selector: u8,
}

pub const SPI1: SpiMaster = SpiMaster { selector: 0x3 };
pub const SPI2: SpiMaster = SpiMaster { selector: 0x4 };

const SPICR0: u8 = 0x08;
const SPICR1: u8 = 0x09;
const SPICR2: u8 = 0x0A;
const SPIBR: u8 = 0x0B;
const SPITXDR: u8 = 0x0D;
const SPIRXDR: u8 = 0x0E;
const SPICSR: u8 = 0x0F;
const SPISR: u8 = 0x0C;
const SPIINTSR: u8 = 0x06;
const SPIINTCR: u8 = 0x07;

impl SpiMaster {
    unsafe fn reg_read(&self, index: u8) -> u32 {
        comm::reg_read(self.selector, index)
    }

    unsafe fn reg_write(&self, index: u8, value: u32) {
        comm::reg_write(self.selector, index, value)
    }

    unsafe fn wait_trdy(&self) {
        while self.reg_read(SPISR) & 0x10 == 0 {}
    }
    
    unsafe fn wait_rrdy(&self) {
        while self.reg_read(SPISR) & 0x08 == 0 {}
    }

    pub fn init(&self) {
        without_interrupts(|| {
            unsafe {
                self.wait_trdy();
                self.reg_write(SPICR1, 0x80);
                self.wait_trdy();
                self.reg_write(SPIBR, 0x02);
                self.wait_trdy();
                self.reg_write(SPICR2, 0xc0);
            }
        });
    }

    pub fn deinit(&self) {
        unsafe {
            while self.reg_read(SPISR) & 0x80 != 0 {}
        }
    }

    pub fn write(&self, data: u8) -> u8 {
        without_interrupts(|| {
            unsafe {
                self.wait_trdy();
                self.reg_write(SPITXDR, data as u32);
                self.wait_rrdy();
                self.reg_read(SPIRXDR) as u8
            }
        })
    }
}

pub fn spi_init() {
    SPI1.init();
}

pub fn spi_write(data: u8) -> u8 {
    SPI1.write(data)
}