use crate::clocks;
use crate::resets;
use core::cell::Cell;
use kernel::debug;
use kernel::hil;
use kernel::utilities::cells::{OptionalCell, TakeCell};
use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
use kernel::utilities::registers::LocalRegisterCopy;
use kernel::utilities::registers::{register_bitfields, register_structs, ReadOnly, ReadWrite};
use kernel::utilities::StaticRef;
register_structs! {
I2cRegisters {
(0x00 => ic_con: ReadWrite<u32, IC_CON::Register>),
(0x04 => ic_tar: ReadWrite<u32, IC_TAR::Register>),
(0x08 => ic_sar: ReadWrite<u32, IC_SAR::Register>),
(0x0c => _reserved0),
(0x10 => ic_data_cmd: ReadWrite<u32, IC_DATA_CMD::Register>),
(0x14 => ic_ss_scl_hcnt: ReadWrite<u32, IC_SS_SCL_HCNT::Register>),
(0x18 => ic_ss_scl_lcnt: ReadWrite<u32, IC_SS_SCL_LCNT::Register>),
(0x1c => ic_fs_scl_hcnt: ReadWrite<u32, IC_FS_SCL_HCNT::Register>),
(0x20 => ic_fs_scl_lcnt: ReadWrite<u32, IC_FS_SCL_LCNT::Register>),
(0x24 => _reserved1),
(0x2c => ic_intr_stat: ReadOnly<u32, IC_INTR_STAT::Register>),
(0x30 => ic_intr_mask: ReadWrite<u32, IC_INTR_MASK::Register>),
(0x34 => ic_raw_intr_stat: ReadOnly<u32, IC_RAW_INTR_STAT::Register>),
(0x38 => ic_rx_tl: ReadWrite<u32, IC_RX_TL::Register>),
(0x3c => ic_tx_tl: ReadWrite<u32, IC_TX_TL::Register>),
(0x40 => ic_clr_intr: ReadOnly<u32, IC_CLR_INTR::Register>),
(0x44 => _reserved2), (0x54 => ic_clr_tx_abrt: ReadOnly<u32, IC_CLR_TX_ABRT::Register>),
(0x58 => _reserved3), (0x60 => ic_clr_stop_det: ReadOnly<u32, IC_CLR_STOP_DET::Register>),
(0x64 => _reserved4), (0x6c => ic_enable: ReadWrite<u32, IC_ENABLE::Register>),
(0x70 => _reserved5), (0x7c => ic_sda_hold: ReadWrite<u32, IC_SDA_HOLD::Register>),
(0x80 => ic_tx_abrt_source: ReadOnly<u32, IC_TX_ABRT_SOURCE::Register>),
(0x84 => _reserved6), (0x88 => ic_dma_cr: ReadWrite<u32, IC_DMA_CR::Register>),
(0x8c => _reserved7), (0xa0 => ic_fs_spklen: ReadWrite<u32, IC_FS_SPKLEN::Register>),
(0xa4 => @END), }
}
register_bitfields! [u32,
IC_CON [
MASTER_MODE OFFSET(0) NUMBITS(1) [],
SPEED OFFSET(1) NUMBITS(2) [
STANDARD = 0x1,
FAST = 0x2,
HIGH = 0x3,
],
IC_10BITADDR_SLAVE OFFSET(3) NUMBITS(1) [],
IC_10BITADDR_MASTER OFFSET(4) NUMBITS(1) [],
IC_RESTART_EN OFFSET(5) NUMBITS(1) [],
IC_SLAVE_DISABLE OFFSET(6) NUMBITS(1) [],
STOP_DET_IFADDRESSED OFFSET(7) NUMBITS(1) [],
TX_EMPTY_CTRL OFFSET(8) NUMBITS(1) [],
RX_FIFO_FULL_HLD_CTRL OFFSET(9) NUMBITS(1) [],
STOP_DET_IF_MASTER_ACTIVE OFFSET(10) NUMBITS(1) [],
],
IC_TAR [
IC_TAR OFFSET(0) NUMBITS(10) [],
GC_OR_START OFFSET(10) NUMBITS(1) [],
SPECIAL OFFSET(11) NUMBITS(1) [],
],
IC_SAR [
IC_SAR OFFSET(0) NUMBITS(10) [],
],
IC_DATA_CMD [
DAT OFFSET(0) NUMBITS(8) [],
CMD OFFSET(8) NUMBITS(1) [],
STOP OFFSET(9) NUMBITS(1) [],
RESTART OFFSET(10) NUMBITS(1) [],
FIRST_DATA_BYTE OFFSET(11) NUMBITS(1) [],
],
IC_SS_SCL_HCNT [
IC_SS_SCL_HCNT OFFSET(0) NUMBITS(16) [],
],
IC_SS_SCL_LCNT [
IC_SS_SCL_LCNT OFFSET(0) NUMBITS(16) [],
],
IC_FS_SCL_HCNT [
IC_FS_SCL_HCNT OFFSET(0) NUMBITS(16) [],
],
IC_FS_SCL_LCNT [
IC_FS_SCL_LCNT OFFSET(0) NUMBITS(16) [],
],
IC_INTR_STAT [
R_RX_UNDER OFFSET(0) NUMBITS(1) [],
R_RX_OVER OFFSET(1) NUMBITS(1) [],
R_RX_FULL OFFSET(2) NUMBITS(1) [],
R_TX_OVER OFFSET(3) NUMBITS(1) [],
R_TX_EMPTY OFFSET(4) NUMBITS(1) [],
R_RD_REQ OFFSET(5) NUMBITS(1) [],
R_TX_ABRT OFFSET(6) NUMBITS(1) [],
R_RX_DONE OFFSET(7) NUMBITS(1) [],
R_ACTIVITY OFFSET(8) NUMBITS(1) [],
R_STOP_DET OFFSET(9) NUMBITS(1) [],
R_START_DET OFFSET(10) NUMBITS(1) [],
R_GEN_CALL OFFSET(11) NUMBITS(1) [],
R_RESTART_DET OFFSET(12) NUMBITS(1) [],
],
IC_INTR_MASK [
M_RX_UNDER OFFSET(0) NUMBITS(1) [],
M_RX_OVER OFFSET(1) NUMBITS(1) [],
M_RX_FULL OFFSET(2) NUMBITS(1) [],
M_TX_OVER OFFSET(3) NUMBITS(1) [],
M_TX_EMPTY OFFSET(4) NUMBITS(1) [],
M_RD_REQ OFFSET(5) NUMBITS(1) [],
M_TX_ABRT OFFSET(6) NUMBITS(1) [],
M_RX_DONE OFFSET(7) NUMBITS(1) [],
M_ACTIVITY OFFSET(8) NUMBITS(1) [],
M_STOP_DET OFFSET(9) NUMBITS(1) [],
M_START_DET OFFSET(10) NUMBITS(1) [],
M_GEN_CALL OFFSET(11) NUMBITS(1) [],
M_RESTART_DET OFFSET(12) NUMBITS(1) [],
],
IC_RAW_INTR_STAT [
RX_UNDER OFFSET(0) NUMBITS(1) [],
RX_OVER OFFSET(1) NUMBITS(1) [],
RX_FULL OFFSET(2) NUMBITS(1) [],
TX_OVER OFFSET(3) NUMBITS(1) [],
TX_EMPTY OFFSET(4) NUMBITS(1) [],
RD_REQ OFFSET(5) NUMBITS(1) [],
TX_ABRT OFFSET(6) NUMBITS(1) [],
RX_DONE OFFSET(7) NUMBITS(1) [],
ACTIVITY OFFSET(8) NUMBITS(1) [],
STOP_DET OFFSET(9) NUMBITS(1) [],
START_DET OFFSET(10) NUMBITS(1) [],
GEN_CALL OFFSET(11) NUMBITS(1) [],
RESTART_DET OFFSET(12) NUMBITS(1) [],
],
IC_RX_TL [
IC_RX_TL OFFSET(0) NUMBITS(8) [],
],
IC_TX_TL [
IC_TX_TL OFFSET(0) NUMBITS(8) [],
],
IC_CLR_INTR [
CLR_INTR OFFSET(0) NUMBITS(1) [],
],
IC_CLR_TX_ABRT [
CLR_TX_ABRT OFFSET(0) NUMBITS(1) [],
],
IC_CLR_STOP_DET [
CLR_STOP_DET OFFSET(0) NUMBITS(1) [],
],
IC_ENABLE [
ENABLE OFFSET(0) NUMBITS(1) [],
ABORT OFFSET(1) NUMBITS(1) [],
TX_CMD_BLOCK OFFSET(2) NUMBITS(1) [],
],
IC_SDA_HOLD [
IC_SDA_TX_HOLD OFFSET(0) NUMBITS(16) [],
IC_SDA_RX_HOLD OFFSET(16) NUMBITS(8) [],
],
IC_TX_ABRT_SOURCE [
ABRT_7B_ADDR_NOACK OFFSET(0) NUMBITS(1) [],
ABRT_10ADDR1_NOACK OFFSET(1) NUMBITS(1) [],
ABRT_10ADDR2_NOACK OFFSET(2) NUMBITS(1) [],
ABRT_TXDATA_NOACK OFFSET(3) NUMBITS(1) [],
ABRT_GCALL_NOACK OFFSET(4) NUMBITS(1) [],
ABRT_GCALL_READ OFFSET(5) NUMBITS(1) [],
ABRT_HS_ACKDET OFFSET(6) NUMBITS(1) [],
ABRT_SBYTE_ACKDET OFFSET(7) NUMBITS(1) [],
ABRT_HS_NORSTRT OFFSET(8) NUMBITS(1) [],
ABRT_SBYTE_NORSTRT OFFSET(9) NUMBITS(1) [],
ABRT_10B_RD_NORSTRT OFFSET(10) NUMBITS(1) [],
ABRT_MASTER_DIS OFFSET(11) NUMBITS(1) [],
ARB_LOST OFFSET(12) NUMBITS(1) [],
ABRT_SLVFLUSH_TXFIFO OFFSET(13) NUMBITS(1) [],
ABRT_SLV_ARBLOST OFFSET(14) NUMBITS(1) [],
ABRT_SLVRD_INTX OFFSET(15) NUMBITS(1) [],
ABRT_USER_ABRT OFFSET(16) NUMBITS(1) [],
TX_FLUSH_CNT OFFSET(23) NUMBITS(9) [],
],
IC_DMA_CR [
RDMAE OFFSET(0) NUMBITS(1) [],
TDMAE OFFSET(1) NUMBITS(1) [],
],
IC_FS_SPKLEN [
IC_FS_SPKLEN OFFSET(0) NUMBITS(8) [],
],
];
const INSTANCES: [StaticRef<I2cRegisters>; 2] = unsafe {
[
StaticRef::new(0x40044000 as *const I2cRegisters),
StaticRef::new(0x40048000 as *const I2cRegisters),
]
};
#[derive(Clone, Copy, PartialEq)]
enum State {
Uninitialized,
Idle,
WaitingToWriteNextByte,
WaitingToReadNextByte,
WaitingToStartReading,
WaitingForStop,
}
pub struct I2c<'a, 'c> {
instance_num: u8,
registers: StaticRef<I2cRegisters>,
clocks: OptionalCell<&'a clocks::Clocks>,
resets: OptionalCell<&'a resets::Resets>,
client: OptionalCell<&'c dyn hil::i2c::I2CHwMasterClient>,
buf: TakeCell<'static, [u8]>,
state: Cell<State>,
addr: Cell<u8>,
write_len: Cell<i32>,
read_len: Cell<i32>,
rw_index: Cell<i32>,
abort_reason: OptionalCell<LocalRegisterCopy<u32, IC_TX_ABRT_SOURCE::Register>>,
}
impl<'a> I2c<'a, '_> {
fn new(instance_num: u8) -> Self {
Self {
instance_num,
registers: INSTANCES[instance_num as usize],
clocks: OptionalCell::empty(),
resets: OptionalCell::empty(),
client: OptionalCell::empty(),
buf: TakeCell::empty(),
state: Cell::new(State::Uninitialized),
addr: Cell::new(0),
write_len: Cell::new(0),
read_len: Cell::new(0),
rw_index: Cell::new(0),
abort_reason: OptionalCell::empty(),
}
}
pub fn new_i2c0() -> Self {
I2c::new(0)
}
pub fn new_i2c1() -> Self {
I2c::new(1)
}
pub fn resolve_dependencies(&self, clocks: &'a clocks::Clocks, resets: &'a resets::Resets) {
self.clocks.set(clocks);
self.resets.set(resets);
}
fn reset(&self) {
self.resets.map_or_else(
|| panic!("You should call resolve_dependencies before reset."),
|resets| match self.instance_num {
0 => resets.reset(&[resets::Peripheral::I2c0]),
1 => resets.reset(&[resets::Peripheral::I2c1]),
_ => unreachable!(),
},
);
}
fn unreset(&self) {
self.resets.map_or_else(
|| panic!("You should call resolve_dependencies before unreset."),
|resets| match self.instance_num {
0 => resets.unreset(&[resets::Peripheral::I2c0], true),
1 => resets.unreset(&[resets::Peripheral::I2c1], true),
_ => unreachable!(),
},
);
}
fn disable(&self) {
self.registers.ic_enable.set(0);
}
fn enable(&self) {
self.registers.ic_enable.modify(IC_ENABLE::ENABLE::SET);
}
fn set_baudrate(&self, baudrate: u32) -> u32 {
assert!(baudrate != 0);
let freq_in = self
.clocks
.map(|clocks| clocks.get_frequency(clocks::Clock::System))
.unwrap(); let period = (freq_in + baudrate / 2) / baudrate;
let lcnt = period * 3 / 5;
let hcnt = period - lcnt;
assert!(hcnt >= 8);
assert!(lcnt >= 8);
let sda_tx_hold_count = if baudrate < 1000000 {
((freq_in * 3) / 10000000) + 1
} else {
((freq_in * 3) / 25000000) + 1
};
assert!(sda_tx_hold_count <= lcnt - 2);
self.registers.ic_enable.modify(IC_ENABLE::ENABLE::CLEAR);
self.registers.ic_con.modify(IC_CON::SPEED::FAST);
self.registers.ic_fs_scl_hcnt.set(hcnt);
self.registers.ic_fs_scl_lcnt.set(lcnt);
self.registers.ic_fs_spklen.set({
if lcnt < 16 {
1
} else {
lcnt / 16
}
});
self.registers
.ic_sda_hold
.modify(IC_SDA_HOLD::IC_SDA_TX_HOLD.val(sda_tx_hold_count));
freq_in / period
}
pub fn init(&self, baudrate: u32) {
self.reset();
self.unreset();
self.disable();
self.registers
.ic_intr_mask
.write(IC_INTR_MASK::M_STOP_DET::SET);
self.registers.ic_con.write(
IC_CON::SPEED::FAST
+ IC_CON::MASTER_MODE::SET
+ IC_CON::IC_SLAVE_DISABLE::SET
+ IC_CON::IC_RESTART_EN::SET
+ IC_CON::TX_EMPTY_CTRL::SET,
);
self.registers.ic_tx_tl.set(0);
self.registers.ic_rx_tl.set(0);
self.registers
.ic_dma_cr
.write(IC_DMA_CR::TDMAE::SET + IC_DMA_CR::RDMAE::SET);
self.set_baudrate(baudrate);
self.enable();
self.state.set(State::Idle);
}
fn write_then_read(
&self,
addr: u8,
write_len: usize,
read_len: usize,
) -> Result<(), hil::i2c::Error> {
let state = self.state.get();
assert!(state != State::Uninitialized);
if state != State::Idle {
return Err(hil::i2c::Error::Busy);
}
let write_len = write_len as i32;
assert!(write_len >= 1);
self.addr.set(addr);
self.rw_index.set(0);
self.write_len.set(write_len);
self.read_len.set(read_len as i32);
self.registers.ic_enable.set(0);
self.registers.ic_tar.set(addr as u32);
self.registers.ic_enable.set(1);
self.state.set(State::WaitingToWriteNextByte);
self.registers
.ic_intr_mask
.modify(IC_INTR_MASK::M_TX_EMPTY::SET);
Ok(())
}
fn write_next_byte(&self) {
assert!(self.state.get() == State::WaitingToWriteNextByte);
self.registers
.ic_intr_mask
.modify(IC_INTR_MASK::M_TX_EMPTY::CLEAR);
let idx = self.rw_index.get();
let len = self.write_len.get();
let first = idx == 0;
let last = idx == len - 1;
let read_to_follow = self.read_len.get() != 0;
if first {
self.abort_reason.clear();
} else {
let abort_reason = self.registers.ic_tx_abrt_source.extract();
if abort_reason.get() != 0 {
self.abort_reason.set(abort_reason);
self.registers.ic_clr_tx_abrt.get();
self.state.set(State::WaitingForStop);
return;
}
}
let byte = self
.buf
.map_or(None, |buf| Some(buf[idx as usize]))
.unwrap(); let data_cmd = IC_DATA_CMD::DAT.val(byte as u32) + IC_DATA_CMD::RESTART::CLEAR;
let data_cmd = {
if last && !read_to_follow {
data_cmd + IC_DATA_CMD::STOP::SET
} else {
data_cmd + IC_DATA_CMD::STOP::CLEAR
}
};
if last {
if read_to_follow {
self.state.set(State::WaitingToStartReading);
self.registers
.ic_intr_mask
.modify(IC_INTR_MASK::M_TX_EMPTY::SET);
} else {
self.state.set(State::WaitingForStop);
}
} else {
self.state.set(State::WaitingToWriteNextByte);
self.registers
.ic_intr_mask
.modify(IC_INTR_MASK::M_TX_EMPTY::SET);
}
self.registers.ic_data_cmd.write(data_cmd);
self.rw_index.set(idx + 1);
}
fn read(&self, addr: u8, len: usize) -> Result<(), hil::i2c::Error> {
let state = self.state.get();
assert!(state != State::Uninitialized);
if state != State::Idle {
return Err(hil::i2c::Error::Busy);
}
let len = len as i32;
assert!(len >= 1);
self.addr.set(addr);
self.read_len.set(len);
self.start_reading();
Ok(())
}
fn start_reading(&self) {
self.abort_reason.clear();
self.rw_index.set(0);
self.registers.ic_enable.set(0);
self.registers.ic_tar.set(self.addr.get() as u32);
self.registers.ic_enable.set(1);
self.state.set(State::WaitingToReadNextByte);
self.registers
.ic_intr_mask
.modify(IC_INTR_MASK::M_RX_FULL::SET);
let data_cmd = IC_DATA_CMD::CMD::SET;
let data_cmd = {
if self.read_len.get() == 1 {
data_cmd + IC_DATA_CMD::STOP::SET
} else {
data_cmd
}
};
self.registers.ic_data_cmd.write(data_cmd);
}
fn read_next_byte(&self) {
assert!(self.state.get() == State::WaitingToReadNextByte);
self.registers
.ic_intr_mask
.modify(IC_INTR_MASK::M_RX_FULL::CLEAR);
let idx = self.rw_index.get();
let len = self.read_len.get();
let abort_reason = self.registers.ic_tx_abrt_source.extract();
if self.registers.ic_clr_tx_abrt.get() != 0 {
self.abort_reason.set(abort_reason);
return;
}
let byte = self.registers.ic_data_cmd.read(IC_DATA_CMD::DAT) as u8;
self.buf.map(|buf| buf[idx as usize] = byte);
let idx = idx + 1;
if idx > len - 1 {
self.state.set(State::WaitingForStop);
return;
}
self.rw_index.set(idx);
let data_cmd = IC_DATA_CMD::CMD::SET; let data_cmd = {
if idx == len - 1 {
data_cmd + IC_DATA_CMD::STOP::SET
} else {
data_cmd
}
};
self.state.set(State::WaitingToReadNextByte);
self.registers
.ic_intr_mask
.modify(IC_INTR_MASK::M_RX_FULL::SET);
self.registers.ic_data_cmd.write(data_cmd);
}
fn start_reading_after_write(&self) {
assert!(self.state.get() == State::WaitingToStartReading);
self.registers
.ic_intr_mask
.modify(IC_INTR_MASK::M_TX_EMPTY::CLEAR);
self.start_reading();
}
fn process_stop_det(&self) {
assert!(self.state.get() == State::WaitingForStop);
self.registers.ic_clr_stop_det.get();
let status = {
if let Some(reason) = self.abort_reason.take() {
if reason.matches_all(IC_TX_ABRT_SOURCE::ABRT_7B_ADDR_NOACK::SET) {
Err(hil::i2c::Error::AddressNak)
} else if reason.matches_all(IC_TX_ABRT_SOURCE::ABRT_TXDATA_NOACK::SET) {
Err(hil::i2c::Error::DataNak)
} else if reason.matches_all(IC_TX_ABRT_SOURCE::ARB_LOST::SET) {
Err(hil::i2c::Error::ArbitrationLost)
} else {
Err(hil::i2c::Error::NotSupported)
}
} else {
Ok(())
}
};
self.state.set(State::Idle);
self.client.map(|client| match self.buf.take() {
None => {}
Some(buf) => {
client.command_complete(buf, status);
}
});
}
pub fn handle_interrupt(&self) {
match self.state.get() {
State::Uninitialized => debug!(
"Unexpected IRQ for uninitialized I2C device {}",
self.instance_num
),
State::Idle => debug!("Unexpected IRQ for idle I2C device {}", self.instance_num),
State::WaitingToWriteNextByte => self.write_next_byte(),
State::WaitingToReadNextByte => self.read_next_byte(),
State::WaitingToStartReading => self.start_reading_after_write(),
State::WaitingForStop => self.process_stop_det(),
}
}
}
impl<'c> hil::i2c::I2CMaster<'c> for I2c<'_, 'c> {
fn set_master_client(&self, client: &'c dyn hil::i2c::I2CHwMasterClient) {
self.client.set(client);
}
fn enable(&self) {
self.enable();
}
fn disable(&self) {
self.disable();
}
fn write_read(
&self,
addr: u8,
data: &'static mut [u8],
write_len: usize,
read_len: usize,
) -> Result<(), (hil::i2c::Error, &'static mut [u8])> {
self.buf.put(Some(data));
if let Err(error) = self.write_then_read(addr, write_len, read_len) {
Err((error, self.buf.take().unwrap()))
} else {
Ok(())
}
}
fn write(
&self,
addr: u8,
data: &'static mut [u8],
len: usize,
) -> Result<(), (hil::i2c::Error, &'static mut [u8])> {
self.write_read(addr, data, len, 0)
}
fn read(
&self,
addr: u8,
buffer: &'static mut [u8],
len: usize,
) -> Result<(), (hil::i2c::Error, &'static mut [u8])> {
self.buf.put(Some(buffer));
if let Err(error) = self.read(addr, len) {
Err((error, self.buf.take().unwrap()))
} else {
Ok(())
}
}
}