use core::cell::Cell;
use kernel::utilities::cells::{OptionalCell, TakeCell};
use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
use kernel::utilities::registers::{register_bitfields, ReadOnly, ReadWrite};
use kernel::hil;
use kernel::platform::chip::ClockInterface;
use kernel::utilities::StaticRef;
use kernel::ErrorCode;
use crate::{ccm, dma};
#[repr(C)]
struct LpuartRegisters {
verid: ReadOnly<u32, VERID::Register>,
param: ReadOnly<u32, PARAM::Register>,
global: ReadWrite<u32, GLOBAL::Register>,
pincfg: ReadWrite<u32, PINCFG::Register>,
baud: ReadWrite<u32, BAUD::Register>,
stat: ReadWrite<u32, STAT::Register>,
ctrl: ReadWrite<u32, CTRL::Register>,
data: ReadWrite<u32, DATA::Register>,
r#match: ReadWrite<u32, MATCH::Register>,
modir: ReadWrite<u32, MODIR::Register>,
fifo: ReadWrite<u32, FIFO::Register>,
water: ReadWrite<u32, WATER::Register>,
}
register_bitfields![u32,
VERID [
MAJOR OFFSET(24) NUMBITS(8) [],
MINOR OFFSET(16) NUMBITS(8) [],
FEATURE OFFSET(0) NUMBITS(16) []
],
PARAM [
RXFIFO OFFSET(8) NUMBITS(8) [],
TXFIFO OFFSET(0) NUMBITS(8) []
],
GLOBAL [
RST OFFSET(1) NUMBITS(1) []
],
PINCFG [
TRGSEL OFFSET(0) NUMBITS(2) []
],
BAUD [
MAEN1 OFFSET(31) NUMBITS(1) [],
MAEN2 OFFSET(30) NUMBITS(1) [],
M10 OFFSET(29) NUMBITS(1) [],
OSR OFFSET(24) NUMBITS(5) [],
TDMAE OFFSET(23) NUMBITS(1) [],
RDMAE OFFSET(21) NUMBITS(1) [],
RIDMAE OFFSET(20) NUMBITS(1) [],
MATCFG OFFSET(18) NUMBITS(2) [],
BOTHEDGE OFFSET(17) NUMBITS(1) [],
RESYNCDIS OFFSET(16) NUMBITS(1) [],
LBKDIE OFFSET(15) NUMBITS(1) [],
RXEDGIE OFFSET(14) NUMBITS(1) [],
SBNS OFFSET(13) NUMBITS(1) [],
SBR OFFSET(0) NUMBITS(13) []
],
STAT [
LBKDIF OFFSET(31) NUMBITS(1) [],
RXEDGIF OFFSET(30) NUMBITS(1) [],
MSBF OFFSET(29) NUMBITS(1) [],
RXINV OFFSET(28) NUMBITS(1) [],
RWUID OFFSET(27) NUMBITS(1) [],
BRK13 OFFSET(26) NUMBITS(1) [],
LBKDE OFFSET(25) NUMBITS(1) [],
RAF OFFSET(24) NUMBITS(1) [],
TDRE OFFSET(23) NUMBITS(1) [],
TC OFFSET(22) NUMBITS(1) [],
RDRF OFFSET(21) NUMBITS(1) [],
IDLE OFFSET(20) NUMBITS(1) [],
OR OFFSET(19) NUMBITS(1) [],
NF OFFSET(18) NUMBITS(1) [],
FE OFFSET(17) NUMBITS(1) [],
PF OFFSET(16) NUMBITS(1) [],
MA1F OFFSET(15) NUMBITS(1) [],
MA2F OFFSET(14) NUMBITS(1) []
],
CTRL [
R8T9 OFFSET(31) NUMBITS(1) [],
R9T8 OFFSET(30) NUMBITS(1) [],
TXDIR OFFSET(29) NUMBITS(1) [],
TXINV OFFSET(28) NUMBITS(1) [],
ORIE OFFSET(27) NUMBITS(1) [],
NEIE OFFSET(26) NUMBITS(1) [],
FEIE OFFSET(25) NUMBITS(1) [],
PEIE OFFSET(24) NUMBITS(1) [],
TIE OFFSET(23) NUMBITS(1) [],
TCIE OFFSET(22) NUMBITS(1) [],
RIE OFFSET(21) NUMBITS(1) [],
ILIE OFFSET(20) NUMBITS(1) [],
TE OFFSET(19) NUMBITS(1) [],
RE OFFSET(18) NUMBITS(1) [],
RWU OFFSET(17) NUMBITS(1) [],
SBK OFFSET(16) NUMBITS(1) [],
MA1IE OFFSET(15) NUMBITS(1) [],
MA2IE OFFSET(14) NUMBITS(1) [],
M7 OFFSET(11) NUMBITS(1) [],
IDLECFG OFFSET(8) NUMBITS(3) [],
LOOPS OFFSET(7) NUMBITS(1) [],
DOZEEN OFFSET(6) NUMBITS(1) [],
RSRC OFFSET(5) NUMBITS(1) [],
M OFFSET(4) NUMBITS(1) [],
WAKE OFFSET(3) NUMBITS(1) [],
ILT OFFSET(2) NUMBITS(1) [],
PE OFFSET(1) NUMBITS(1) [],
PT OFFSET(0) NUMBITS(1) []
],
DATA [
NOISY OFFSET(15) NUMBITS(8) [],
PARITYE OFFSET(14) NUMBITS(8) [],
FRETSC OFFSET(13) NUMBITS(8) [],
RXEMPT OFFSET(12) NUMBITS(8) [],
IDLINE OFFSET(11) NUMBITS(8) [],
R9T9 OFFSET(9) NUMBITS(8) [],
R8T8 OFFSET(8) NUMBITS(8) [],
R7T7 OFFSET(7) NUMBITS(8) [],
R6T6 OFFSET(6) NUMBITS(8) [],
R5T5 OFFSET(5) NUMBITS(8) [],
R4T4 OFFSET(4) NUMBITS(8) [],
R3T3 OFFSET(3) NUMBITS(8) [],
R2T2 OFFSET(2) NUMBITS(8) [],
R1T1 OFFSET(1) NUMBITS(8) [],
R0T0 OFFSET(0) NUMBITS(8) []
],
MATCH [
MA2 OFFSET(16) NUMBITS(10) [],
MA1 OFFSET(0) NUMBITS(10) []
],
MODIR [
IREN OFFSET(18) NUMBITS(1) [],
TNP OFFSET(16) NUMBITS(2) [],
RTSWATER OFFSET(8) NUMBITS(2) [],
TXCTSSRC OFFSET(5) NUMBITS(1) [],
TXCTSC OFFSET(4) NUMBITS(1) [],
RXRTSE OFFSET(3) NUMBITS(1) [],
TXRTSPOL OFFSET(2) NUMBITS(1) [],
TXRTSE OFFSET(1) NUMBITS(1) [],
TXCTSE OFFSET(0) NUMBITS(1) []
],
FIFO [
TXEMPT OFFSET(23) NUMBITS(1) [],
RXEMPT OFFSET(22) NUMBITS(1) [],
TXOF OFFSET(17) NUMBITS(1) [],
RXUF OFFSET(16) NUMBITS(1) [],
TXFLUSH OFFSET(15) NUMBITS(1) [],
RXFLUSH OFFSET(14) NUMBITS(1) [],
RXIDEN OFFSET(10) NUMBITS(2) [],
TXOFE OFFSET(9) NUMBITS(1) [],
RXUFE OFFSET(8) NUMBITS(1) [],
TXFE OFFSET(7) NUMBITS(1) [],
TXFIFOSIZE OFFSET(4) NUMBITS(3) [],
RXFE OFFSET(3) NUMBITS(1) [],
RXFIFOSIZE OFFSET(0) NUMBITS(3) []
],
WATER [
RXCOUNT OFFSET(24) NUMBITS(3) [],
RXWATER OFFSET(16) NUMBITS(2) [],
TXCOUNT OFFSET(8) NUMBITS(3) [],
TXWATER OFFSET(0) NUMBITS(2) []
]
];
const LPUART1_BASE: StaticRef<LpuartRegisters> =
unsafe { StaticRef::new(0x40184000 as *const LpuartRegisters) };
const LPUART2_BASE: StaticRef<LpuartRegisters> =
unsafe { StaticRef::new(0x4018_8000 as *const LpuartRegisters) };
#[derive(Copy, Clone, PartialEq)]
enum LPUARTStateTX {
Idle,
Transmitting,
AbortRequested,
}
#[derive(Copy, Clone, PartialEq)]
enum USARTStateRX {
Idle,
Receiving,
AbortRequested,
}
pub struct Lpuart<'a> {
registers: StaticRef<LpuartRegisters>,
clock: LpuartClock<'a>,
tx_client: OptionalCell<&'a dyn hil::uart::TransmitClient>,
rx_client: OptionalCell<&'a dyn hil::uart::ReceiveClient>,
tx_buffer: TakeCell<'static, [u8]>,
tx_position: Cell<usize>,
tx_len: Cell<usize>,
tx_status: Cell<LPUARTStateTX>,
tx_dma_channel: OptionalCell<&'a dma::DmaChannel>,
tx_dma_source: dma::DmaHardwareSource,
rx_buffer: TakeCell<'static, [u8]>,
rx_position: Cell<usize>,
rx_len: Cell<usize>,
rx_status: Cell<USARTStateRX>,
rx_dma_channel: OptionalCell<&'a dma::DmaChannel>,
rx_dma_source: dma::DmaHardwareSource,
}
impl<'a> Lpuart<'a> {
pub fn new_lpuart1(ccm: &'a ccm::Ccm) -> Self {
Lpuart::new(
LPUART1_BASE,
LpuartClock(ccm::PeripheralClock::ccgr5(ccm, ccm::HCLK5::LPUART1)),
dma::DmaHardwareSource::Lpuart1Transfer,
dma::DmaHardwareSource::Lpuart1Receive,
)
}
pub fn new_lpuart2(ccm: &'a ccm::Ccm) -> Self {
Lpuart::new(
LPUART2_BASE,
LpuartClock(ccm::PeripheralClock::ccgr0(ccm, ccm::HCLK0::LPUART2)),
dma::DmaHardwareSource::Lpuart2Transfer,
dma::DmaHardwareSource::Lpuart2Receive,
)
}
fn new(
base_addr: StaticRef<LpuartRegisters>,
clock: LpuartClock<'a>,
tx_dma_source: dma::DmaHardwareSource,
rx_dma_source: dma::DmaHardwareSource,
) -> Lpuart<'a> {
Lpuart {
registers: base_addr,
clock,
tx_client: OptionalCell::empty(),
rx_client: OptionalCell::empty(),
tx_buffer: TakeCell::empty(),
tx_position: Cell::new(0),
tx_len: Cell::new(0),
tx_status: Cell::new(LPUARTStateTX::Idle),
tx_dma_channel: OptionalCell::empty(),
tx_dma_source,
rx_buffer: TakeCell::empty(),
rx_position: Cell::new(0),
rx_len: Cell::new(0),
rx_status: Cell::new(USARTStateRX::Idle),
rx_dma_channel: OptionalCell::empty(),
rx_dma_source,
}
}
pub fn set_tx_dma_channel(&'static self, dma_channel: &'static dma::DmaChannel) {
dma_channel.set_client(self, self.tx_dma_source);
unsafe {
dma_channel.set_destination(core::ptr::addr_of!(self.registers.data) as *const u8);
}
dma_channel.set_interrupt_on_completion(true);
dma_channel.set_disable_on_completion(true);
self.tx_dma_channel.set(dma_channel);
}
pub fn set_rx_dma_channel(&'static self, dma_channel: &'static dma::DmaChannel) {
dma_channel.set_client(self, self.rx_dma_source);
unsafe {
dma_channel.set_source(core::ptr::addr_of!(self.registers.data) as *const u8);
}
dma_channel.set_interrupt_on_completion(true);
dma_channel.set_disable_on_completion(true);
self.rx_dma_channel.set(dma_channel);
}
pub fn is_enabled_clock(&self) -> bool {
self.clock.is_enabled()
}
pub fn enable_clock(&self) {
self.clock.enable();
}
pub fn disable_clock(&self) {
self.clock.disable();
}
pub fn set_baud(&self) {
self.registers.baud.modify(BAUD::SBR.val(139_u32));
}
pub fn send_byte(&self, byte: u8) {
while !self.registers.stat.is_set(STAT::TDRE) {}
self.registers.data.set(byte.into());
while !self.registers.stat.is_set(STAT::TC) {}
}
pub fn is_transmit_enabled(&self) -> bool {
self.registers.ctrl.is_set(CTRL::TE)
}
pub fn is_receive_enabled(&self) -> bool {
self.registers.ctrl.is_set(CTRL::RE)
}
fn enable_transmit_complete_interrupt(&self) {
self.registers.ctrl.modify(CTRL::TIE::SET);
}
fn disable_transmit_complete_interrupt(&self) {
self.registers.ctrl.modify(CTRL::TIE::CLEAR);
}
fn clear_transmit_complete(&self) {
self.registers.stat.modify(STAT::TDRE::CLEAR);
}
fn enable_receive_interrupt(&self) {
self.registers.ctrl.modify(CTRL::RIE::SET);
}
fn disable_receive_interrupt(&self) {
self.registers.ctrl.modify(CTRL::RIE::CLEAR);
}
fn clear_overrun(&self) {
self.registers.ctrl.modify(CTRL::ORIE::CLEAR);
}
pub fn handle_interrupt(&self) {
if self.registers.stat.is_set(STAT::TDRE) {
self.clear_transmit_complete();
self.disable_transmit_complete_interrupt();
if self.tx_status.get() == LPUARTStateTX::Transmitting {
let position = self.tx_position.get();
if position < self.tx_len.get() {
self.tx_buffer.map(|buf| {
self.registers.data.set(buf[position].into());
self.tx_position.replace(self.tx_position.get() + 1);
self.enable_transmit_complete_interrupt();
});
} else {
self.tx_status.replace(LPUARTStateTX::Idle);
}
if self.tx_status.get() == LPUARTStateTX::Idle {
self.tx_client.map(|client| {
if let Some(buf) = self.tx_buffer.take() {
client.transmitted_buffer(buf, self.tx_len.get(), Ok(()));
}
});
}
} else if self.tx_status.get() == LPUARTStateTX::AbortRequested {
self.tx_status.replace(LPUARTStateTX::Idle);
self.tx_client.map(|client| {
if let Some(buf) = self.tx_buffer.take() {
client.transmitted_buffer(
buf,
self.tx_position.get(),
Err(ErrorCode::CANCEL),
);
}
});
}
}
if self.registers.stat.is_set(STAT::RDRF) {
let byte = self.registers.data.get() as u8;
self.disable_receive_interrupt();
if self.rx_status.get() == USARTStateRX::Receiving {
if self.rx_position.get() < self.rx_len.get() {
self.rx_buffer.map(|buf| {
buf[self.rx_position.get()] = byte;
self.rx_position.replace(self.rx_position.get() + 1);
});
}
if self.rx_position.get() == self.rx_len.get() {
self.rx_status.replace(USARTStateRX::Idle);
} else {
self.enable_receive_interrupt();
}
if self.rx_status.get() == USARTStateRX::Idle {
self.rx_client.map(|client| {
if let Some(buf) = self.rx_buffer.take() {
client.received_buffer(
buf,
self.rx_len.get(),
Ok(()),
hil::uart::Error::None,
);
}
});
}
} else if self.rx_status.get() == USARTStateRX::AbortRequested {
self.rx_status.replace(USARTStateRX::Idle);
self.rx_client.map(|client| {
if let Some(buf) = self.rx_buffer.take() {
client.received_buffer(
buf,
self.rx_position.get(),
Err(ErrorCode::CANCEL),
hil::uart::Error::Aborted,
);
}
});
}
}
if self.registers.stat.is_set(STAT::OR) {
self.clear_overrun();
self.rx_status.replace(USARTStateRX::Idle);
self.rx_client.map(|client| {
if let Some(buf) = self.rx_buffer.take() {
client.received_buffer(
buf,
self.rx_position.get(),
Err(ErrorCode::CANCEL),
hil::uart::Error::OverrunError,
);
}
});
}
}
fn check_status(&self) -> kernel::hil::uart::Error {
use kernel::hil::uart::Error;
let stat = self.registers.stat.extract();
if stat.is_set(STAT::PF) {
Error::ParityError
} else if stat.is_set(STAT::FE) {
Error::FramingError
} else if stat.is_set(STAT::OR) {
Error::OverrunError
} else {
Error::None
}
}
fn clear_status(&self) {
self.registers.stat.modify(
STAT::IDLE::SET
+ STAT::OR::SET
+ STAT::NF::SET
+ STAT::FE::SET
+ STAT::PF::SET
+ STAT::RXEDGIF::SET
+ STAT::MA1F::SET
+ STAT::MA2F::SET,
)
}
fn transmit_buffer_interrupt(
&self,
tx_data: &'static mut [u8],
tx_len: usize,
) -> Result<(), (ErrorCode, &'static mut [u8])> {
if self.tx_status.get() == LPUARTStateTX::Idle {
if tx_len <= tx_data.len() {
self.tx_buffer.put(Some(tx_data));
self.tx_position.set(0);
self.tx_len.set(tx_len);
self.tx_status.set(LPUARTStateTX::Transmitting);
self.enable_transmit_complete_interrupt();
Ok(())
} else {
Err((ErrorCode::SIZE, tx_data))
}
} else {
Err((ErrorCode::BUSY, tx_data))
}
}
fn transmit_buffer_dma(
&self,
tx_buffer: &'static mut [u8],
tx_len: usize,
) -> Result<(), (ErrorCode, &'static mut [u8])> {
if self.tx_buffer.is_some() {
return Err((ErrorCode::BUSY, tx_buffer));
} else if !self.is_transmit_enabled() {
return Err((ErrorCode::OFF, tx_buffer));
} else if tx_len > tx_buffer.len() {
return Err((ErrorCode::SIZE, tx_buffer));
} else if self.tx_dma_channel.is_none() {
return Err((ErrorCode::FAIL, tx_buffer));
}
self.tx_dma_channel
.map(move |dma_channel| unsafe {
dma_channel.set_source_buffer(&tx_buffer[..tx_len]);
self.tx_buffer.put(Some(tx_buffer));
self.tx_len.set(tx_len);
dma_channel.enable();
self.registers.baud.modify(BAUD::TDMAE::SET);
Ok(())
})
.unwrap() }
fn transmit_abort_interrupt(&self) -> Result<(), ErrorCode> {
if self.tx_status.get() != LPUARTStateTX::Idle {
self.tx_status.set(LPUARTStateTX::AbortRequested);
Err(ErrorCode::BUSY)
} else {
Ok(())
}
}
fn transmit_abort_dma(&self) -> Result<(), ErrorCode> {
self.registers.baud.modify(BAUD::TDMAE::CLEAR);
while self.registers.baud.is_set(BAUD::TDMAE) {
cortexm7::support::nop();
}
self.tx_dma_channel.map(|dma_channel| {
while dma_channel.is_hardware_signaling() {
cortexm7::support::nop();
}
dma_channel.disable();
});
Ok(())
}
fn receive_buffer_interrupt(
&self,
rx_buffer: &'static mut [u8],
rx_len: usize,
) -> Result<(), (ErrorCode, &'static mut [u8])> {
if self.rx_status.get() == USARTStateRX::Idle {
if rx_len <= rx_buffer.len() {
self.rx_buffer.put(Some(rx_buffer));
self.rx_position.set(0);
self.rx_len.set(rx_len);
self.rx_status.set(USARTStateRX::Receiving);
self.enable_receive_interrupt();
Ok(())
} else {
Err((ErrorCode::SIZE, rx_buffer))
}
} else {
Err((ErrorCode::BUSY, rx_buffer))
}
}
fn receive_buffer_dma(
&self,
rx_buffer: &'static mut [u8],
rx_size: usize,
) -> Result<(), (ErrorCode, &'static mut [u8])> {
if self.rx_buffer.is_some() {
return Err((ErrorCode::BUSY, rx_buffer));
} else if !self.is_receive_enabled() {
return Err((ErrorCode::OFF, rx_buffer));
} else if rx_size > rx_buffer.len() {
return Err((ErrorCode::SIZE, rx_buffer));
} else if self.rx_dma_channel.is_none() {
return Err((ErrorCode::FAIL, rx_buffer));
}
self.rx_dma_channel
.map(move |dma_channel| unsafe {
dma_channel.set_destination_buffer(&mut rx_buffer[..rx_size]);
self.clear_status();
self.rx_buffer.put(Some(rx_buffer));
self.rx_len.set(rx_size);
dma_channel.enable();
self.registers.baud.modify(BAUD::RDMAE::SET);
Ok(())
})
.unwrap() }
fn receive_abort_interrupt(&self) -> Result<(), ErrorCode> {
if self.rx_status.get() != USARTStateRX::Idle {
self.rx_status.set(USARTStateRX::AbortRequested);
Err(ErrorCode::BUSY)
} else {
Ok(())
}
}
fn receive_abort_dma(&self) -> Result<(), ErrorCode> {
self.registers.baud.modify(BAUD::RDMAE::CLEAR);
while self.registers.baud.is_set(BAUD::RDMAE) {
cortexm7::support::nop();
}
self.rx_dma_channel.map(|dma_channel| {
while dma_channel.is_hardware_signaling() {
cortexm7::support::nop();
}
dma_channel.disable()
});
Ok(())
}
}
impl<'a> hil::uart::Transmit<'a> for Lpuart<'a> {
fn set_transmit_client(&self, client: &'a dyn hil::uart::TransmitClient) {
self.tx_client.set(client);
}
fn transmit_buffer(
&self,
tx_data: &'static mut [u8],
tx_len: usize,
) -> Result<(), (ErrorCode, &'static mut [u8])> {
if self.tx_dma_channel.is_some() {
self.transmit_buffer_dma(tx_data, tx_len)
} else {
self.transmit_buffer_interrupt(tx_data, tx_len)
}
}
fn transmit_word(&self, _word: u32) -> Result<(), ErrorCode> {
Err(ErrorCode::FAIL)
}
fn transmit_abort(&self) -> Result<(), ErrorCode> {
if self.tx_dma_channel.is_some() {
self.transmit_abort_dma()
} else {
self.transmit_abort_interrupt()
}
}
}
impl hil::uart::Configure for Lpuart<'_> {
fn configure(&self, params: hil::uart::Parameters) -> Result<(), ErrorCode> {
if params.baud_rate != 115200
|| params.stop_bits != hil::uart::StopBits::One
|| params.parity != hil::uart::Parity::None
|| params.hw_flow_control
|| params.width != hil::uart::Width::Eight
{
panic!(
"Currently we only support uart setting of 115200bps 8N1, no hardware flow control"
);
}
self.enable_clock();
self.registers.global.modify(GLOBAL::RST::SET);
self.registers.global.modify(GLOBAL::RST::CLEAR);
self.registers.baud.modify(BAUD::BOTHEDGE::SET);
self.registers.baud.modify(BAUD::OSR.val(0b100_u32));
self.registers.baud.modify(BAUD::SBR.val(139_u32));
self.registers.baud.modify(BAUD::M10::CLEAR);
self.registers.ctrl.modify(CTRL::PE::CLEAR);
self.registers.ctrl.modify(CTRL::PT::CLEAR);
self.registers.ctrl.modify(CTRL::M::CLEAR);
self.registers.ctrl.modify(CTRL::ILT::CLEAR);
self.registers.ctrl.modify(CTRL::IDLECFG::CLEAR);
self.registers.baud.modify(BAUD::SBNS::CLEAR);
self.registers.water.modify(WATER::RXWATER::CLEAR);
self.registers.water.modify(WATER::TXWATER::CLEAR);
self.registers.fifo.modify(FIFO::TXFE::CLEAR);
self.registers.fifo.modify(FIFO::RXFE::CLEAR);
self.registers.fifo.modify(FIFO::TXFLUSH::SET);
self.registers.fifo.modify(FIFO::RXFLUSH::SET);
self.clear_status();
self.registers.modir.modify(MODIR::TXCTSC::CLEAR);
self.registers.modir.modify(MODIR::TXCTSSRC::CLEAR);
self.registers.stat.modify(STAT::MSBF::CLEAR);
self.registers.ctrl.modify(CTRL::TE::SET);
self.registers.ctrl.modify(CTRL::RE::SET);
Ok(())
}
}
impl<'a> hil::uart::Receive<'a> for Lpuart<'a> {
fn set_receive_client(&self, client: &'a dyn hil::uart::ReceiveClient) {
self.rx_client.set(client);
}
fn receive_buffer(
&self,
rx_buffer: &'static mut [u8],
rx_len: usize,
) -> Result<(), (ErrorCode, &'static mut [u8])> {
if self.rx_dma_channel.is_some() {
self.receive_buffer_dma(rx_buffer, rx_len)
} else {
self.receive_buffer_interrupt(rx_buffer, rx_len)
}
}
fn receive_word(&self) -> Result<(), ErrorCode> {
Err(ErrorCode::FAIL)
}
fn receive_abort(&self) -> Result<(), ErrorCode> {
if self.rx_dma_channel.is_some() {
self.receive_abort_dma()
} else {
self.receive_abort_interrupt()
}
}
}
struct LpuartClock<'a>(ccm::PeripheralClock<'a>);
impl ClockInterface for LpuartClock<'_> {
fn is_enabled(&self) -> bool {
self.0.is_enabled()
}
fn enable(&self) {
self.0.enable();
}
fn disable(&self) {
self.0.disable();
}
}
impl dma::DmaClient for Lpuart<'_> {
fn transfer_complete(&self, result: dma::Result) {
match result {
Ok(source) if source == self.tx_dma_source => {
self.registers.baud.modify(BAUD::TDMAE::CLEAR);
let result = if self.registers.fifo.is_set(FIFO::TXOF) {
Err(ErrorCode::FAIL)
} else {
Ok(())
};
self.tx_client.map(|client| {
client.transmitted_buffer(
self.tx_buffer.take().unwrap(),
self.tx_len.take(),
result,
);
});
}
Err(source) if source == self.tx_dma_source => {
self.registers.baud.modify(BAUD::TDMAE::CLEAR);
self.tx_client.map(|client| {
client.transmitted_buffer(
self.tx_buffer.take().unwrap(),
self.tx_len.take(),
Err(ErrorCode::FAIL),
);
});
}
Ok(source) if source == self.rx_dma_source => {
self.registers.baud.modify(BAUD::RDMAE::CLEAR);
let err = self.check_status();
let code = if kernel::hil::uart::Error::None == err {
Ok(())
} else {
Err(ErrorCode::FAIL)
};
self.rx_client.map(|client| {
client.received_buffer(
self.rx_buffer.take().unwrap(),
self.rx_len.take(),
code,
err,
);
});
}
Err(source) if source == self.rx_dma_source => {
self.registers.baud.modify(BAUD::RDMAE::CLEAR);
self.rx_client.map(|client| {
client.received_buffer(
self.rx_buffer.take().unwrap(),
self.rx_len.take(),
Err(ErrorCode::FAIL),
kernel::hil::uart::Error::Aborted,
);
});
}
_ => panic!("DMA channel has reference to the wrong DMA client"),
}
}
}