xref: /aosp_15_r20/external/pigweed/pw_i2c_linux/docs.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1.. _module-pw_i2c_linux:
2
3============
4pw_i2c_linux
5============
6.. pigweed-module::
7   :name: pw_i2c_linux
8
9``pw_i2c_linux`` implements the ``pw_i2c`` interface using the Linux userspace
10``i2c-dev`` driver. Transfers are executed using blocking ``ioctl`` calls.
11Write+read transactions are implemented atomically using a single system call,
12and a retry mechanism is used to support bus arbitration between multiple
13controllers.
14
15-------------
16API reference
17-------------
18.. doxygenclass:: pw::i2c::LinuxInitiator
19   :members:
20
21--------
22Examples
23--------
24A simple example illustrating the usage:
25
26.. code-block:: C++
27
28   #include "pw_i2c/address.h"
29   #include "pw_i2c/device.h"
30   #include "pw_i2c_linux/initiator.h"
31   #include "pw_log/log.h"
32   #include "pw_result/result.h"
33
34   constexpr auto kBusPath = "/dev/i2c-0";
35   constexpr auto kAddress = pw::i2c::Address::SevenBit<0x42>();
36
37   pw::Result<int> result = pw::i2c::LinuxInitiator::OpenI2cBus(kBusPath);
38   if (!result.ok()) {
39     PW_LOG_ERROR("Failed to open I2C bus [%s]", kBusPath);
40     return result.status();
41   }
42   pw::i2c::LinuxInitiator initiator(*result);
43   pw::i2c::Device device(initiator, address);
44   // Use device to talk to address.
45
46In real-world use cases, you may want to create an initiator singleton. This
47can be done by initializing a function-local static variable with a lambda:
48
49.. code-block:: C++
50
51   #include <functional>
52
53   #include "pw_i2c/address.h"
54   #include "pw_i2c/device.h"
55   #include "pw_i2c/initiator.h"
56   #include "pw_i2c_linux/initiator.h"
57   #include "pw_log/log.h"
58   #include "pw_result/result.h"
59   #include "pw_status/status.h"
60
61   // Open the I2C bus and return an initiator singleton.
62   pw::i2c::Initiator* GetInitiator() {
63     static constexpr auto kBusPath = "/dev/i2c-0";
64     static auto* initiator = std::invoke([]() -> pw::i2c::Initiator* {
65       pw::Result<int> result = pw::i2c::LinuxInitiator::OpenI2cBus(kBusPath);
66       if (!result.ok()) {
67         PW_LOG_ERROR("Failed to open I2C bus [%s]", kBusPath);
68         return nullptr;
69       }
70       return new pw::i2c::Initiator(*result);
71     });
72     return initiator;
73   }
74
75   // Use the initiator from anywhere.
76   constexpr auto kAddress = pw::i2c::Address::SevenBit<0x42>();
77   auto* initiator = GetInitiator();
78   if (initiator == nullptr) {
79     PW_LOG_ERROR("I2C initiator unavailable");
80     return pw::Status::Internal();
81   }
82   pw::i2c::Device device(*initiator, address);
83   // Use device to talk to address.
84
85-------
86Caveats
87-------
88Only 7-bit addresses are supported right now, but it should be possible to add
89support for 10-bit addresses with minimal changes - as long as the Linux driver
90supports 10-bit addresses.
91