use super::{Config, ConfigError, Driver, RegisterBlock, configure_clock};
use crate::soc::clocks::{ClockTree, I2cFunctionClockConfig, I2cInstance};
pub(super) fn set_frequency(driver: &Driver<'_>, clock_config: &Config) -> Result<(), ConfigError> {
let timeout = clock_config.timeout;
let bus_freq = clock_config.frequency.as_hz();
let sclk = clock_config.clock_source;
let clock = driver.info.clock_instance;
let source_clk = I2cInstance::function_clock_source_frequency(sclk);
ClockTree::with(|clocks| {
let clkm_div: u32 = source_clk / (bus_freq * 1024) + 1;
clock.configure_function_clock(clocks, I2cFunctionClockConfig::new(sclk, clkm_div - 1));
});
let sclk_freq: u32 = clock.function_clock_frequency();
let half_cycle: u32 = sclk_freq / bus_freq / 2;
let scl_low = half_cycle;
let scl_wait_high = if bus_freq >= 80 * 1000 {
half_cycle / 2 - 2
} else {
half_cycle / 4
};
let scl_high = half_cycle - scl_wait_high;
let sda_hold = half_cycle / 4;
let sda_sample = half_cycle / 2;
let setup = half_cycle;
let hold = half_cycle;
let scl_low_period = scl_low - 1;
let scl_high_period = scl_high;
let scl_wait_high_period = scl_wait_high;
let sda_hold_time = sda_hold - 1;
let sda_sample_time = sda_sample - 1;
let scl_rstart_setup_time = setup - 1;
let scl_stop_setup_time = setup - 1;
let scl_start_hold_time = hold - 1;
let scl_stop_hold_time = hold - 1;
configure_clock(
driver.info,
scl_low_period,
scl_high_period,
scl_wait_high_period,
sda_hold_time,
sda_sample_time,
scl_rstart_setup_time,
scl_stop_setup_time,
scl_start_hold_time,
scl_stop_hold_time,
timeout.apb_cycles(half_cycle)?,
)
}
pub(super) fn reset_fifo(driver: &Driver<'_>) {
driver.regs().fifo_conf().write(|w| unsafe {
w.tx_fifo_rst().set_bit();
w.rx_fifo_rst().set_bit();
w.nonfifo_en().clear_bit();
w.fifo_prt_en().set_bit();
w.rxfifo_wm_thrhd().bits(1);
w.txfifo_wm_thrhd().bits(8)
});
driver.regs().fifo_conf().modify(|_, w| {
w.tx_fifo_rst().clear_bit();
w.rx_fifo_rst().clear_bit()
});
driver.regs().int_clr().write(|w| {
w.rxfifo_wm().clear_bit_by_one();
w.txfifo_wm().clear_bit_by_one()
});
driver.update_registers();
}
pub(super) fn read_fifo(register_block: &RegisterBlock) -> u8 {
register_block.data().read().fifo_rdata().bits()
}
pub(super) fn write_fifo(register_block: &RegisterBlock, data: u8) {
register_block
.data()
.write(|w| unsafe { w.fifo_rdata().bits(data) });
}