diff --git a/repos/base-hw/src/bootstrap/board/imx8q_evk/platform.cc b/repos/base-hw/src/bootstrap/board/imx8q_evk/platform.cc index 7823ac7ac0..cf5bd10b2d 100644 --- a/repos/base-hw/src/bootstrap/board/imx8q_evk/platform.cc +++ b/repos/base-hw/src/bootstrap/board/imx8q_evk/platform.cc @@ -60,8 +60,8 @@ Bootstrap::Platform::Board::Board() { 0x303301EC, 0x0 }, { 0x303301FC, 0x1 }, { 0x30330200, 0x1 }, - { 0x3033021C, 0x5 }, - { 0x30330220, 0x5 }, + { 0x3033021C, 0x10 }, /* Enable SION I2c2_scl */ + { 0x30330220, 0x10 }, /* Enable SION I2c2_sda */ { 0x30330224, 0x10 }, { 0x30330228, 0x10 }, { 0x3033022C, 0x12 }, @@ -126,8 +126,8 @@ Bootstrap::Platform::Board::Board() { 0x30330464, 0x49 }, { 0x30330468, 0x49 }, { 0x3033046C, 0x16 }, - { 0x30330484, 0x16 }, - { 0x30330488, 0x16 }, + { 0x30330484, 0x67 }, /* I2c2_scl pullup resistor 40 ohm */ + { 0x30330488, 0x67 }, /* I2c2_sda pullup resistor 40 ohm */ { 0x3033048C, 0x67 }, { 0x30330490, 0x67 }, { 0x30330494, 0x76 }, diff --git a/repos/os/include/i2c_session/capability.h b/repos/os/include/i2c_session/capability.h new file mode 100644 index 0000000000..602446b742 --- /dev/null +++ b/repos/os/include/i2c_session/capability.h @@ -0,0 +1,23 @@ +/* + * \brief I2C session capability type + * \author Jean-Adrien Domage + * \date 2021-02-26 + */ + +/* + * Copyright (C) 2013-2021 Genode Labs GmbH + * Copyright (C) 2021 gapfruit AG + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__I2C_SESSION__CAPABILITY_H_ +#define _INCLUDE__I2C_SESSION__CAPABILITY_H_ + +#include +#include + +namespace I2c { typedef Genode::Capability Session_capability; } + +#endif /*_INCLUDE__I2C_SESSION__CAPABILITY_H_ */ diff --git a/repos/os/include/i2c_session/client.h b/repos/os/include/i2c_session/client.h new file mode 100644 index 0000000000..730c0e47df --- /dev/null +++ b/repos/os/include/i2c_session/client.h @@ -0,0 +1,52 @@ +/* + * \brief I2C session client implementation + * \author Jean-Adrien Domage + * \date 2021-02-25 + */ + +/* + * Copyright (C) 2013-2021 Genode Labs GmbH + * Copyright (C) 2021 gapfruit AG + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__I2C_SESSION__CLIENT_H_ +#define _INCLUDE__I2C_SESSION__CLIENT_H_ + +#include +#include + +namespace I2c { struct Session_client; } + + +struct I2c::Session_client : Rpc_client +{ + explicit Session_client(I2c::Session_capability session) + : + Rpc_client(session) + { } + + void write_8bits(uint8_t byte) override + { + call(byte); + } + + uint8_t read_8bits() override + { + return call(); + } + + void write_16bits(uint16_t word) override + { + call(word); + } + + uint16_t read_16bits() override + { + return call(); + } +}; + +#endif /* _INCLUDE__I2C_SESSION__CLIENT_H_ */ diff --git a/repos/os/include/i2c_session/connection.h b/repos/os/include/i2c_session/connection.h new file mode 100644 index 0000000000..a7f724730e --- /dev/null +++ b/repos/os/include/i2c_session/connection.h @@ -0,0 +1,33 @@ +/* + * \brief I2C session connection + * \author Jean-Adrien Domage + * \date 2021-02-26 + */ + +/* + * Copyright (C) 2013-2021 Genode Labs GmbH + * Copyright (C) 2021 gapfruit AG + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__I2C_SESSION__CONNECTION_H_ +#define _INCLUDE__I2C_SESSION__CONNECTION_H_ + +#include +#include + +namespace I2c { struct Connection; } + + +struct I2c::Connection : Genode::Connection, I2c::Session_client +{ + Connection(Genode::Env &env, char const *label = "") + : + Genode::Connection(env, session(env.parent(), "ram_quota=8K, label=%s", label)), + Session_client(cap()) + { } +}; + +#endif /* _INCLUDE__I2C_SESSION__CONNECTION_H_ */ diff --git a/repos/os/include/i2c_session/i2c_session.h b/repos/os/include/i2c_session/i2c_session.h new file mode 100644 index 0000000000..ab240f08d0 --- /dev/null +++ b/repos/os/include/i2c_session/i2c_session.h @@ -0,0 +1,106 @@ +/* + * \brief I2C session client implementation + * \author Jean-Adrien Domage + * \date 2021-02-25 + */ + +/* + * Copyright (C) 2013-2021 Genode Labs GmbH + * Copyright (C) 2021 gapfruit AG + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _INCLUDE__I2C_SESSION__I2C_SESSION_H_ +#define _INCLUDE__I2C_SESSION__I2C_SESSION_H_ + +#include +#include + +namespace I2c { + using namespace Genode; + struct Session; +} + + +struct I2c::Session : public Genode::Session +{ + /** + * \noapi + */ + static char const *service_name() { return "I2c"; } + + enum { CAP_QUOTA = 2 }; + + + /*************** + ** Exception ** + ***************/ + + /** + * Execption thrown in case of a bus error + * + * This exception is thrown by the driver incase of a timeout, device missing + * acknoledgement and bus arbitration lost. The driver can be configured in the run script + * to log descriptive messages incase of errors. + */ + class Bus_error : public Exception {}; + + + /*********************** + ** Session interface ** + ***********************/ + + /** + * Write 8 bits on the bus + * + * \param byte The 8 bits to be sent + * + * \throw I2c::Session::Bus_error An error occured while performing an operation on the bus + */ + virtual void write_8bits(uint8_t byte) = 0; + + /** + * Read 8 bits from the bus + * + * \throw I2c::Session::Bus_error An error occured while performing an operation on the bus + * + * \return The 8 received bits + */ + virtual uint8_t read_8bits() = 0; + + /** + * Write 16 bits on the bus + * + * \param word The 16 bits to be sent + * + * \throw I2c::Session::Bus_error An error occured while performing an operation on the bus + */ + virtual void write_16bits(uint16_t word) = 0; + + /** + * Read 16 bits from the bus + * + * \throw I2c::Session::Bus_error An error occured while performing an operation on the bus + * + * \return The 16 received bits + */ + virtual uint16_t read_16bits() = 0; + + GENODE_RPC_THROW(Rpc_write_8bits, void, write_8bits, + GENODE_TYPE_LIST(Bus_error), + uint8_t); + GENODE_RPC_THROW(Rpc_read_8bits, uint8_t, read_8bits, + GENODE_TYPE_LIST(Bus_error)); + GENODE_RPC_THROW(Rpc_write_16bits, void, write_16bits, + GENODE_TYPE_LIST(Bus_error), + uint16_t); + GENODE_RPC_THROW(Rpc_read_16bits, uint16_t, read_16bits, + GENODE_TYPE_LIST(Bus_error)); + + GENODE_RPC_INTERFACE(Rpc_write_8bits, Rpc_read_8bits, + Rpc_write_16bits, Rpc_read_16bits); +}; + +#endif /* _INCLUDE__I2C_SESSION__I2C_SESSION_H_ */ diff --git a/repos/os/run/i2c_mcp9808.run b/repos/os/run/i2c_mcp9808.run new file mode 100644 index 0000000000..f09c2c71ae --- /dev/null +++ b/repos/os/run/i2c_mcp9808.run @@ -0,0 +1,106 @@ + +assert_spec arm_v8a + +create_boot_directory + +import_from_depot [depot_user]/src/[base_src] +import_from_depot [depot_user]/src/init +import_from_depot [depot_user]/src/platform_drv + +set build_components { + core + timer + drivers/i2c + test/i2c_mcp9808 +} + +source ${genode_dir}/repos/base/run/platform_drv.inc + +build $build_components + +set config { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} + +install_config $config + +set boot_modules { + core + timer + imx8q_evk_i2c_drv + i2c_mcp9808 +} + +build_boot_image $boot_modules + +run_genode_until forever diff --git a/repos/os/src/drivers/i2c/README b/repos/os/src/drivers/i2c/README new file mode 100644 index 0000000000..cf4e69f76d --- /dev/null +++ b/repos/os/src/drivers/i2c/README @@ -0,0 +1,72 @@ +This directory contains the implementation of the I2C driver component. + +Brief +===== + +The driver supports I2C bus controller for imx8q_evk only for master mode. +A platform connection is used to retrieve device's capabilities. +The platform driver must provide a device with the following configuration: + +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! +! + +The io_mem address, irq number and clock might change from one I2C bus +controller to another. The io_mem address for iomux configuration may +remain the same across I2C bus controllers. + +The driver can be extended to another platform. An 'I2c::Driver_base' +interface is provided in 'i2c_interface.h'. The specific platform +implementation must expose a 'driver.h' header file that contains a +declaration of 'I2c::Driver' that implements the 'I2c::Driver_base' +interface. An example of a specific platform implementation can be found +in 'os/src/drivers/i2c/imx8q_evk'. + +Configuration +============= + +The driver acts as a server that must be configured via a policy, that states +which client can access a certain device(s) on the bus: + +! +! +! +! +! +! +! +! +! +! +! +! + +The driver's config must contain the 'bus_no' (bus number) attribute, +'bus_no="2"' for bus 2. And device(s) policy with two attributes +'label_prefix' and 'bus_address' which is an address of a slave +device on the bus. A 'verbose' boolean attribute might be specified +if you want the driver to log error messages. + +Example +======= + +An example of how to use the I2C driver can be found in the test +script 'os/run/i2c_mcp9808.run'. diff --git a/repos/os/src/drivers/i2c/component.h b/repos/os/src/drivers/i2c/component.h new file mode 100644 index 0000000000..05f6f448a1 --- /dev/null +++ b/repos/os/src/drivers/i2c/component.h @@ -0,0 +1,113 @@ +/* + * \brief I2C session component + * \author Jean-Adrien Domage + * \date 2021-02-26 + */ + +/* + * Copyright (C) 2013-2021 Genode Labs GmbH + * Copyright (C) 2021 gapfruit AG + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _I2C_DRIVER__COMPONENT_H_ +#define _I2C_DRIVER__COMPONENT_H_ + +#include +#include +#include +#include "i2c_interface.h" + +namespace I2c { + using namespace Genode; + class Session_component; + class Root; +} + + +class I2c::Session_component : public Rpc_object +{ + private: + + Rpc_entrypoint &_ep; + I2c::Driver_base &_driver; + uint8_t const _device_address; + + public: + + Session_component(Rpc_entrypoint &ep, + I2c::Driver_base &driver, + uint8_t device_address) + : + _ep(ep), _driver(driver), _device_address(device_address) + { } + + void write_8bits(uint8_t byte) override + { + _driver.write(_device_address, &byte, sizeof(byte)); + } + + uint8_t read_8bits() override + { + uint8_t data = 0; + _driver.read(_device_address, reinterpret_cast(&data), sizeof(data)); + return data; + } + + void write_16bits(uint16_t word) override + { + _driver.write(_device_address, reinterpret_cast(&word), sizeof(word)); + } + + uint16_t read_16bits() override + { + uint16_t data = 0; + _driver.read(_device_address, reinterpret_cast(&data), sizeof(data)); + return data; + } +}; + + +class I2c::Root : public Root_component +{ + private: + + Rpc_entrypoint &_ep; + I2c::Driver_base &_driver; + Xml_node const _config; + + protected: + + Session_component *_create_session(char const *args) override + { + char device_name_c_string[I2c::Device_name::capacity()] { }; + Arg_string::find_arg(args, "label").string(device_name_c_string, sizeof(device_name_c_string), ""); + Device_name const device_name(device_name_c_string); + + Genode::Session_policy policy(device_name, _config); + uint8_t const device_address = policy.attribute_value("bus_address", static_cast(0)); + + /* address 0x0 is reserved, so if we return 0x0 it is an error */ + if (device_address == 0) { + warning("Session with label '", + device_name, + "' could not be created, no such policy"); + throw Service_denied(); + } + + return new (md_alloc()) I2c::Session_component(_ep, _driver, device_address); + } + + public: + + Root(Rpc_entrypoint &ep, Allocator &md_alloc, + I2c::Driver_base &driver, Xml_node const &config) + : + Root_component(&ep, &md_alloc), + _ep(ep), _driver(driver), _config(config) + { } +}; + +#endif /* _I2C_DRIVER__COMPONENT_H_ */ diff --git a/repos/os/src/drivers/i2c/i2c_interface.h b/repos/os/src/drivers/i2c/i2c_interface.h new file mode 100644 index 0000000000..1200d7c673 --- /dev/null +++ b/repos/os/src/drivers/i2c/i2c_interface.h @@ -0,0 +1,75 @@ +/* + * \brief I2C driver base class to be implemented by platform specific + * \author Jean-Adrien Domage + * \date 2021-02-08 + */ + +/* + * Copyright (C) 2013-2021 Genode Labs GmbH + * Copyright (C) 2021 gapfruit AG + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _I2C_DRIVER__INTERFACE_H_ +#define _I2C_DRIVER__INTERFACE_H_ + +/* Genode includes */ +#include +#include + +namespace I2c { + using namespace Genode; + using Device_name = String<64>; + class Driver_base; +} + + +/** + * Base class for platform specific driver to implement + * + * Note about the endianess: the driver is transparent. + * + * The driver read/write bytes to memory in the order they are + * read/write to the bus. + * It is the responsability of the component interacting with + * a slave device on the bus to figure out how to interpret the data. + */ +struct I2c::Driver_base : Interface +{ + class Bad_bus_no: Exception {}; + + /** + * Write to the I2C bus + * + * \param address device address + * \param buffer_in buffer containing data to be send + * \param buffer_size size of the buffer to be send + * + * \throw I2c::Session::Bus_error An error occured while performing an operation on the bus + */ + virtual void write(uint8_t address, uint8_t const *buffer_in, size_t buffer_size) = 0; + + /** + * Read from the I2C bus + * + * \param address device address + * \param buffer_out preallocated buffer to store the data in + * \param buffer_size size of the buffer and to be read + * + * \throw I2c::Session::Bus_error An error occure while performing an operation on the bus + */ + virtual void read(uint8_t address, uint8_t *buffer_out, size_t buffer_size) = 0; + + /** + * Driver name getter + * + * \return Driver name string + * + * Details this method is overridable to customise the name based on the platform. + */ + virtual char const *name() const { return "i2c driver"; } +}; + +#endif /* _I2C_INTERFACE_H_ */ diff --git a/repos/os/src/drivers/i2c/imx8q_evk/driver.cc b/repos/os/src/drivers/i2c/imx8q_evk/driver.cc new file mode 100644 index 0000000000..a1a44efc11 --- /dev/null +++ b/repos/os/src/drivers/i2c/imx8q_evk/driver.cc @@ -0,0 +1,165 @@ +/* + * \brief Platform specific I2C's driver for imx8q_evk + * \author Jean-Adrien Domage + * \date 2021-02-08 + */ + +/* + * Copyright (C) 2013-2021 Genode Labs GmbH + * Copyright (C) 2021 gapfruit AG + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#include +#include "driver.h" + + +void I2c::Driver::_wait_for_irq() +{ + _sem_cnt++; + while (_sem_cnt > 0) + _env.ep().wait_and_dispatch_one_io_signal(); + + if (_mmio.read() == 0) { + _bus_stop(); + if (_args.verbose) { + error("Arbitrationtion lost on bus ", _args.bus_no); + } + throw I2c::Session::Bus_error(); + } +} + + +void I2c::Driver::_bus_busy() +{ + uint64_t const start_time = _timer.elapsed_ms(); + while (!_mmio.read()) { + uint64_t const current = _timer.elapsed_ms(); + if (current - start_time > 1000) { + _bus_stop(); + if (_args.verbose) { + error("Timeout on bus ", _args.bus_no); + } + throw I2c::Session::Bus_error(); + } + } +} + + +void I2c::Driver::_bus_reset() +{ + _mmio.write(0); + _mmio.write(0); +} + + +void I2c::Driver::_bus_start() +{ + _bus_reset(); + + /* input root 90 is 25Mhz target is 400Khz, divide by 64 */ + _mmio.write(0x2a); + _mmio.write(0); + _mmio.write(Mmio::Control::Enable::bits(1)); + + uint64_t const start_time = _timer.elapsed_ms(); + while (!_mmio.read()) { + uint64_t const current = _timer.elapsed_ms(); + if (current - start_time > 1000) { + _bus_stop(); + if (_args.verbose) { + error("Timeout on bus ", _args.bus_no); + } + throw I2c::Session::Bus_error(); + } + } + + _mmio.write(1); + + _bus_busy(); + + _mmio.write(Mmio::Control::Tx_rx_select::bits(1) | + Mmio::Control::Tx_ack_enable::bits(1) | + Mmio::Control::Irq_enable::bits(1) | + Mmio::Control::Master_slave_select::bits(1) | + Mmio::Control::Enable::bits(1)); + + _mmio.write(0); +} + + +void I2c::Driver::_bus_stop() +{ + _mmio.write(0); +} + + +void I2c::Driver::_bus_write(uint8_t data) +{ + _mmio.write(data); + + do { _wait_for_irq(); } + while (!_mmio.read()); + + _mmio.write(0); + _irq.ack_irq(); + + if (_mmio.read()) { + _bus_stop(); + if (_args.verbose) { + error("Slave did not acknoledge on bus ", _args.bus_no); + } + throw I2c::Session::Bus_error(); + } +} + + +void I2c::Driver::write(uint8_t address, uint8_t const *buffer_in, size_t const buffer_size) +{ + _bus_start(); + + /* LSB must be 0 for writing on the bus, address is on the 7 hightest bits */ + _bus_write(address << 1); + for (size_t idx = 0; idx < buffer_size; ++idx) { + _bus_write(buffer_in[idx]); + } + _bus_stop(); +} + + +void I2c::Driver::read(uint8_t address, uint8_t *buffer_out, size_t const buffer_size) +{ + _bus_start(); + + /* LSB must be 1 for reading on the bus, address is on the 7 hightest bits */ + _bus_write(address << 1 | 1); + + _mmio.write(0); + if (buffer_size > 1) { + _mmio.write(0); + } + _mmio.read(); + + for (size_t i = 0; i < buffer_size; ++i) { + + do { _wait_for_irq(); } + while (!_mmio.read()); + + _mmio.write(0); + + if (i == buffer_size - 1) { + _mmio.write(0); + _mmio.write(0); + while (_mmio.read()); + } else if (i == buffer_size - 2) { + _mmio.write(1); + } + + buffer_out[i] = _mmio.read(); + _irq.ack_irq(); + } + + _bus_stop(); +} diff --git a/repos/os/src/drivers/i2c/imx8q_evk/driver.h b/repos/os/src/drivers/i2c/imx8q_evk/driver.h new file mode 100644 index 0000000000..ea27812a89 --- /dev/null +++ b/repos/os/src/drivers/i2c/imx8q_evk/driver.h @@ -0,0 +1,92 @@ +/* + * \brief Platform specific I2C's driver for imx8q_evk + * \author Jean-Adrien Domage + * \date 2021-02-08 + */ + +/* + * Copyright (C) 2013-2021 Genode Labs GmbH + * Copyright (C) 2021 gapfruit AG + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _I2C_DRIVER__IMX8Q_EVK_H_ +#define _I2C_DRIVER__IMX8Q_EVK_H_ + +/* Genode includes */ +#include +#include +#include +#include +#include +#include +#include + +/* Local include */ +#include +#include "mmio.h" + +namespace I2c { + using namespace Genode; + class Driver; +} + + +class I2c::Driver: public I2c::Driver_base +{ + public: + + struct Args + { + bool verbose; + unsigned bus_no; + Device_name device_name; + }; + + private: + + Env &_env; + Args const _args; + + Platform::Connection _platform_connection { _env }; + Platform::Device_client _device { _platform_connection.device_by_index(0) }; + + /* iomem region for I2C control register */ + Attached_dataspace _i2c_ctl_ds { _env.rm(), _device.io_mem_dataspace(0) }; + I2c::Mmio _mmio { reinterpret_cast(_i2c_ctl_ds.local_addr()) }; + + /* interrupt handler */ + Irq_session_client _irq { _device.irq() }; + Io_signal_handler _irq_handler; + + unsigned _sem_cnt = 1; + Timer::Connection _timer { _env }; + + void _bus_reset(); + void _bus_start(); + void _bus_stop(); + void _bus_write(Genode::uint8_t data); + void _bus_busy(); + + void _wait_for_irq(); + void _irq_handle() { _sem_cnt = 0; } + + public: + + Driver(Env &env, Args const &args) + : + _env(env), _args(args), + _irq_handler(_env.ep(), *this, &Driver::_irq_handle) + { + _irq.sigh(_irq_handler); + _irq_handle(); + _irq.ack_irq(); + } + + void write(uint8_t, uint8_t const *, size_t) override; + void read(uint8_t, uint8_t *, size_t) override; +}; + +#endif /* _I2C_DRIVER__IMX8Q_EVK_H_ */ diff --git a/repos/os/src/drivers/i2c/imx8q_evk/mmio.h b/repos/os/src/drivers/i2c/imx8q_evk/mmio.h new file mode 100644 index 0000000000..2abb63e403 --- /dev/null +++ b/repos/os/src/drivers/i2c/imx8q_evk/mmio.h @@ -0,0 +1,55 @@ +/* + * \brief I2C mmio region for platform imx8q_evk + * \author Jean-Adrien Domage + * \date 2021-02-08 + */ + +/* + * Copyright (C) 2013-2021 Genode Labs GmbH + * Copyright (C) 2021 gapfruit AG + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#ifndef _I2C_MMIO_H_ +#define _I2C_MMIO_H_ + +#include + +namespace I2c { struct Mmio; } + + +struct I2c::Mmio: Genode::Mmio +{ + struct Address : Mmio::Register<0x0, 16> { + struct Adr : Mmio::Register<0x0, 16>::Bitfield<1, 7> {}; + }; + + struct Freq_divider : Mmio::Register<0x4, 16> {}; + + struct Control : Mmio::Register<0x8, 16> { + 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> {}; + struct Irq_enable : Mmio::Register<0x8, 16>::Bitfield<6, 1> {}; + struct Enable : Mmio::Register<0x8, 16>::Bitfield<7, 1> {}; + }; + + struct Status : Mmio::Register<0x0C, 16> { + struct Rcv_ack : Mmio::Register<0x0C, 16>::Bitfield<0, 1> {}; + struct Irq : Mmio::Register<0x0C, 16>::Bitfield<1, 1> {}; + struct Srw : Mmio::Register<0x0C, 16>::Bitfield<2, 1> {}; + struct Ial : Mmio::Register<0x0C, 16>::Bitfield<4, 1> {}; + struct Busy : Mmio::Register<0x0C, 16>::Bitfield<5, 1> {}; + struct Iaas : Mmio::Register<0x0C, 16>::Bitfield<6, 1> {}; + struct Icf : Mmio::Register<0x0C, 16>::Bitfield<7, 1> {}; + }; + + struct Data : Mmio::Register<0x10, 16> {}; + + Mmio(Genode::addr_t base) : Genode::Mmio { base } { } +}; + +#endif /* _I2C_MMIO_H_ */ diff --git a/repos/os/src/drivers/i2c/imx8q_evk/target.mk b/repos/os/src/drivers/i2c/imx8q_evk/target.mk new file mode 100644 index 0000000000..f3d4b67240 --- /dev/null +++ b/repos/os/src/drivers/i2c/imx8q_evk/target.mk @@ -0,0 +1,9 @@ +TARGET = imx8q_evk_i2c_drv + +REQUIRES = arm_v8 + +SRC_CC += driver.cc + +INC_DIR += $(PRG_DIR)/src/drivers/i2c/imx8q_evk + +include $(REP_DIR)/src/drivers/i2c/target.inc diff --git a/repos/os/src/drivers/i2c/main.cc b/repos/os/src/drivers/i2c/main.cc new file mode 100644 index 0000000000..5855eb15b3 --- /dev/null +++ b/repos/os/src/drivers/i2c/main.cc @@ -0,0 +1,62 @@ +/* + * \brief I2C driver main + * \author Jean-Adrien Domage + * \date 2021-02-08 + */ + +/* + * Copyright (C) 2013-2021 Genode Labs GmbH + * Copyright (C) 2021 gapfruit AG + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +/* Genode includes */ +#include +#include +#include +#include +#include + +/* Local includes */ +#include "component.h" +#include "driver.h" + +namespace I2c { struct Main; } + + +struct I2c::Main +{ + private: + + Env &_env; + Sliced_heap _sliced_heap { _env.ram(), _env.rm() }; + + Attached_rom_dataspace _config { _env, "config" }; + + static I2c::Driver::Args _driver_args_from_config(Xml_node config) + { + return { + .verbose = config.attribute_value("verbose", false), + .bus_no = config.attribute_value("bus_no", 0u), + .device_name = config.attribute_value("device_name", Device_name()) + }; + } + + I2c::Driver _driver { _env, _driver_args_from_config(_config.xml()) }; + I2c::Root _root { _env.ep().rpc_ep(), _sliced_heap, + _driver, _config.xml() }; + + public: + + Main(Env &env) : _env(env) + { + _env.parent().announce(env.ep().manage(_root)); + + log(_driver.name(), " started"); + } +}; + + +void Component::construct(Genode::Env &env) { static I2c::Main main(env); } diff --git a/repos/os/src/drivers/i2c/target.inc b/repos/os/src/drivers/i2c/target.inc new file mode 100644 index 0000000000..b08a390136 --- /dev/null +++ b/repos/os/src/drivers/i2c/target.inc @@ -0,0 +1,9 @@ +LIBS += base + +INC_DIR += $(PRG_DIR) +INC_DIR += $(REP_DIR)/src/drivers/i2c + +SRC_CC += main.cc + +vpath %.cc $(REP_DIR)/src/drivers/i2c +vpath %.cc $(REP_DIR) diff --git a/repos/os/src/test/i2c_mcp9808/README b/repos/os/src/test/i2c_mcp9808/README new file mode 100644 index 0000000000..d2c01ee2e4 --- /dev/null +++ b/repos/os/src/test/i2c_mcp9808/README @@ -0,0 +1,15 @@ +i2c_mcp9808 read ambient temperature from an mcp9808 sensor connected +on an I2c bus and print it to standard output. + +Example config of a component using the imx8q_evk_i2c_drv driver: + +! +! +! +! +! +! +! +! +! +! diff --git a/repos/os/src/test/i2c_mcp9808/main.cc b/repos/os/src/test/i2c_mcp9808/main.cc new file mode 100644 index 0000000000..17bca69d06 --- /dev/null +++ b/repos/os/src/test/i2c_mcp9808/main.cc @@ -0,0 +1,81 @@ +/* + * \brief Test I2C driver with MCP9808 sensor + * \author Jean-Adrien Domage + * \date 2021-02-26 + */ + +/* + * Copyright (C) 2013-2021 Genode Labs GmbH + * Copyright (C) 2021 gapfruit AG + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#include +#include + +namespace Test { + using namespace Genode; + struct Main; +} + + +struct Test::Main +{ + Env &_env; + + I2c::Connection _sensor { _env, "MCP_9808" }; + + Main(Env &env) : _env(env) + { + uint16_t raw_data = 0; + + try{ + /* Config ambient mode */ + _sensor.write_8bits(0x05); + + /* Read ambient temperature */ + raw_data = _sensor.read_16bits(); + } catch (I2c::Session::Bus_error) { + error("Bus operation could not be completed."); + return; + } + + uint8_t* temp_data = reinterpret_cast(&raw_data); + + /* Convert the temperature data */ + /* Check flag bits */ + if ((temp_data[0] & 0x80) == 0x80) { + /* T A is T CRIT */ + warning("Temperature is critical for the sensor."); + } + if ((temp_data[0] & 0x40) == 0x40) { + /* T A > T UPPER */ + warning("Temperature is upper the bound of the sensor."); + } + if ((temp_data[0] & 0x20) == 0x20) { + /* T A < T LOWER */ + warning("Temperature is lower the bound of the sensor."); + } + + /* Clear the flag's bits */ + temp_data[0] = temp_data[0] & 0x1F; + int temperature = 0; + + /* T A is negative */ + if ((temp_data[0] & 0x10) == 0x10){ + /* Clear SIGN */ + temp_data[0] = temp_data[0] & 0x0F; + temperature = 256 - (temp_data[0] * 16 + temp_data[1] / 16); + } else { + /* T A is positive */ + temperature = (temp_data[0] * 16 + temp_data [1] / 16); + } + + log("temperature is ", temperature, " C"); + } +}; + + +void Component::construct(Genode::Env &env) { static Test::Main main(env); } diff --git a/repos/os/src/test/i2c_mcp9808/target.mk b/repos/os/src/test/i2c_mcp9808/target.mk new file mode 100644 index 0000000000..2d510b139f --- /dev/null +++ b/repos/os/src/test/i2c_mcp9808/target.mk @@ -0,0 +1,3 @@ +TARGET = i2c_mcp9808 +SRC_CC = main.cc +LIBS = base