blob: 6185a13550a3d82cbfb92e6444677935eb77ef91 [file] [log] [blame]
.. _module-pw_i2c_linux:
============
pw_i2c_linux
============
.. pigweed-module::
:name: pw_i2c_linux
``pw_i2c_linux`` implements the ``pw_i2c`` interface using the Linux userspace
``i2c-dev`` driver. Transfers are executed using blocking ``ioctl`` calls.
Write+read transactions are implemented atomically using a single system call,
and a retry mechanism is used to support bus arbitration between multiple
controllers.
-------------
API reference
-------------
.. doxygenclass:: pw::i2c::LinuxInitiator
:members:
--------
Examples
--------
A simple example illustrating the usage:
.. code-block:: C++
#include "pw_i2c/address.h"
#include "pw_i2c/device.h"
#include "pw_i2c_linux/initiator.h"
#include "pw_log/log.h"
#include "pw_result/result.h"
constexpr auto kBusPath = "/dev/i2c-0";
constexpr auto kAddress = pw::i2c::Address::SevenBit<0x42>();
pw::Result<int> result = pw::i2c::LinuxInitiator::OpenI2cBus(kBusPath);
if (!result.ok()) {
PW_LOG_ERROR("Failed to open I2C bus [%s]", kBusPath);
return result.status();
}
pw::i2c::LinuxInitiator initiator(*result);
pw::i2c::Device device(initiator, address);
// Use device to talk to address.
In real-world use cases, you may want to create an initiator singleton. This
can be done by initializing a function-local static variable with a lambda:
.. code-block:: C++
#include <functional>
#include "pw_i2c/address.h"
#include "pw_i2c/device.h"
#include "pw_i2c/initiator.h"
#include "pw_i2c_linux/initiator.h"
#include "pw_log/log.h"
#include "pw_result/result.h"
#include "pw_status/status.h"
// Open the I2C bus and return an initiator singleton.
pw::i2c::Initiator* GetInitiator() {
static constexpr auto kBusPath = "/dev/i2c-0";
static auto* initiator = std::invoke([]() -> pw::i2c::Initiator* {
pw::Result<int> result = pw::i2c::LinuxInitiator::OpenI2cBus(kBusPath);
if (!result.ok()) {
PW_LOG_ERROR("Failed to open I2C bus [%s]", kBusPath);
return nullptr;
}
return new pw::i2c::Initiator(*result);
});
return initiator;
}
// Use the initiator from anywhere.
constexpr auto kAddress = pw::i2c::Address::SevenBit<0x42>();
auto* initiator = GetInitiator();
if (initiator == nullptr) {
PW_LOG_ERROR("I2C initiator unavailable");
return pw::Status::Internal();
}
pw::i2c::Device device(*initiator, address);
// Use device to talk to address.
-------
Caveats
-------
Only 7-bit addresses are supported right now, but it should be possible to add
support for 10-bit addresses with minimal changes - as long as the Linux driver
supports 10-bit addresses.