use gpio;
use spi;
-use storage::Storage;
+use storage::{Storage, Error};
const SECTOR_SIZE: usize = 4096;
+const PAGE_SIZE: usize = 256;
pub struct Mx25l {
cs_gpio: u32,
}
enum Command {
+ PP = 0x02,
READ = 0x03,
RDSR = 0x05,
WREN = 0x06,
SE = 0x20,
+ CE = 0x60,
RDID = 0x9f,
}
-pub enum Error {
- UnalignedAddress = 1,
-}
-
const SR_WIP: u8 = 1 << 0;
impl Mx25l {
})
}
+ pub fn erase_all(&self) {
+ self.write_enable();
+
+ self.with_selected(|| {
+ spi::tx8(spi::SPI0, Command::CE as u8);
+ });
+
+ while self.write_in_progress() {
+ }
+ }
+
pub fn erase_sector(&self, address: usize) -> Result<(), Error> {
if (address & (SECTOR_SIZE - 1)) != 0 {
return Err(Error::UnalignedAddress);
Ok(())
}
+ pub fn program_page(&self, address: usize, buffer: &[u8; PAGE_SIZE])
+ -> Result<(), Error> {
+ if (address & (PAGE_SIZE - 1)) != 0 {
+ return Err(Error::UnalignedAddress);
+ }
+
+ if buffer.iter().all(|&b| b == 0xff) {
+ return Ok(());
+ }
+
+ self.write_enable();
+
+ self.with_selected(|| {
+ spi::tx8(spi::SPI0, Command::PP as u8);
+
+ spi::tx8(spi::SPI0, (address >> 16) as u8);
+ spi::tx8(spi::SPI0, (address >> 8) as u8);
+ spi::tx8(spi::SPI0, (address >> 0) as u8);
+
+ for &b in buffer.iter() {
+ spi::tx8(spi::SPI0, b);
+ }
+ });
+
+ while self.write_in_progress() {
+ }
+
+ Ok(())
+ }
+
fn write_enable(&self) {
self.with_selected(|| {
spi::tx8(spi::SPI0, Command::WREN as u8);
}
impl Storage for Mx25l {
+ fn size(&self) -> usize {
+ 2 << 20
+ }
+
fn read(&self, address: usize, buffer: &mut [u8]) {
self.with_selected(|| {
spi::tx8(spi::SPI0, Command::READ as u8);
}
})
}
+
+ fn write(&mut self, address: usize, buffer: &[u8; SECTOR_SIZE])
+ -> Result<(), Error> {
+ if let Err(e) = self.erase_sector(address) {
+ return Err(e);
+ }
+
+ for (i, page_bytes) in buffer.chunks(PAGE_SIZE).enumerate() {
+ let page_address = address + (i * PAGE_SIZE);
+
+ // XXX: Inefficient.
+ let mut ba = [0xff; PAGE_SIZE];
+ ba.copy_from_slice(&page_bytes);
+
+ if let Err(e) = self.program_page(page_address, &ba) {
+ return Err(e);
+ }
+ }
+
+ Ok(())
+ }
+
+ fn erase(&mut self, address: usize) -> Result<(), Error> {
+ self.erase_sector(address)
+ }
+
+ fn clear(&mut self) {
+ self.erase_all();
+ }
}