diff --git a/repos/os/src/drivers/i2c/i2c_interface.h b/repos/os/src/drivers/i2c/i2c_interface.h index 0209639ee9..35a4fef552 100644 --- a/repos/os/src/drivers/i2c/i2c_interface.h +++ b/repos/os/src/drivers/i2c/i2c_interface.h @@ -1,5 +1,5 @@ /* - * \brief I2C driver base class to be implemented by platform specific + * \brief I2C driver base class to be implemented by platform specific * \author Jean-Adrien Domage * \date 2021-02-08 */ diff --git a/repos/os/src/drivers/i2c/imx8q_evk/driver.cc b/repos/os/src/drivers/i2c/imx8q_evk/driver.cc index d58cf9f1c4..bc324e6ca2 100644 --- a/repos/os/src/drivers/i2c/imx8q_evk/driver.cc +++ b/repos/os/src/drivers/i2c/imx8q_evk/driver.cc @@ -17,6 +17,27 @@ #include "driver.h" +namespace { + + Genode::uint8_t _bus_speed_to_divider(Genode::uint16_t bus_speed_khz) + { + /* the table can be found: + * IMX8MMRM.pdf on 5233 + * + * The bus base frequency is 25MHz. + */ + + if (bus_speed_khz >= 400) return 0x2a; /* divide by 64 maximal speed supported */ + if (bus_speed_khz >= 200) return 0x2f; /* divide by 128 */ + if (bus_speed_khz >= 100) return 0x33; /* divide by 256 */ + if (bus_speed_khz >= 50) return 0x37; /* divide by 512 */ + if (bus_speed_khz >= 25) return 0x3B; /* divide by 1024 */ + + return 0x3F; /* divide by 2048 minimal speed */ + } +} + + void I2c::Driver::_wait_for_irq() { _sem_cnt++; @@ -58,8 +79,8 @@ void I2c::Driver::_bus_reset() void I2c::Driver::_bus_start() { - /* input root 90 is 25Mhz target is 400Khz, divide by 64 */ - _mmio.write(0x2a); + /* input root 90 is 25Mhz select divisor to approximate desired bus speed */ + _mmio.write(_bus_speed_to_divider(_args.bus_speed_khz)); _mmio.write(0); _mmio.write(Mmio::Control::Enable::bits(1)); diff --git a/repos/os/src/drivers/i2c/imx8q_evk/driver.h b/repos/os/src/drivers/i2c/imx8q_evk/driver.h index 3df6a10e2e..169de0fb8f 100644 --- a/repos/os/src/drivers/i2c/imx8q_evk/driver.h +++ b/repos/os/src/drivers/i2c/imx8q_evk/driver.h @@ -43,6 +43,7 @@ class I2c::Driver: public I2c::Driver_base bool verbose; unsigned bus_no; Device_name device_name; + uint16_t bus_speed_khz; }; private: diff --git a/repos/os/src/drivers/i2c/imx8q_evk/mmio.h b/repos/os/src/drivers/i2c/imx8q_evk/mmio.h index 83e41c21b8..b1bd254aac 100644 --- a/repos/os/src/drivers/i2c/imx8q_evk/mmio.h +++ b/repos/os/src/drivers/i2c/imx8q_evk/mmio.h @@ -29,7 +29,7 @@ struct I2c::Mmio: Platform::Device::Mmio struct Freq_divider : Mmio::Register<0x4, 16> {}; struct Control : Mmio::Register<0x8, 16> { - struct Repeat_start : Mmio::Register<0x8, 16>::Bitfield<2, 1> {}; + struct Repeat_start : Mmio::Register<0x8, 16>::Bitfield<2, 1> {}; struct Tx_ack_enable : Mmio::Register<0x8, 16>::Bitfield<3, 1> {}; struct Tx_rx_select : Mmio::Register<0x8, 16>::Bitfield<4, 1> {}; struct Master_slave_select : Mmio::Register<0x8, 16>::Bitfield<5, 1> {}; diff --git a/repos/os/src/drivers/i2c/main.cc b/repos/os/src/drivers/i2c/main.cc index 5855eb15b3..b855dc10c8 100644 --- a/repos/os/src/drivers/i2c/main.cc +++ b/repos/os/src/drivers/i2c/main.cc @@ -37,10 +37,12 @@ struct I2c::Main static I2c::Driver::Args _driver_args_from_config(Xml_node config) { + constexpr uint16_t const default_bus_speed_khz { 400 }; return { - .verbose = config.attribute_value("verbose", false), - .bus_no = config.attribute_value("bus_no", 0u), - .device_name = config.attribute_value("device_name", Device_name()) + .verbose = config.attribute_value("verbose", false), + .bus_no = config.attribute_value("bus_no", 0u), + .device_name = config.attribute_value("device_name", Device_name()), + .bus_speed_khz = config.attribute_value("bus_speed_khz", default_bus_speed_khz) }; }