xref: /aosp_15_r20/external/pigweed/seed/0117.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1*61c4878aSAndroid Build Coastguard Worker.. _seed-0117:
2*61c4878aSAndroid Build Coastguard Worker
3*61c4878aSAndroid Build Coastguard Worker=============
4*61c4878aSAndroid Build Coastguard Worker0117: I3C
5*61c4878aSAndroid Build Coastguard Worker=============
6*61c4878aSAndroid Build Coastguard Worker.. seed::
7*61c4878aSAndroid Build Coastguard Worker   :number: 117
8*61c4878aSAndroid Build Coastguard Worker   :name: I3C
9*61c4878aSAndroid Build Coastguard Worker   :status: Accepted
10*61c4878aSAndroid Build Coastguard Worker   :proposal_date: 2023-10-30
11*61c4878aSAndroid Build Coastguard Worker   :authors: Jack Chen
12*61c4878aSAndroid Build Coastguard Worker   :cl: 178350
13*61c4878aSAndroid Build Coastguard Worker   :facilitator: Alexei Frolov
14*61c4878aSAndroid Build Coastguard Worker
15*61c4878aSAndroid Build Coastguard Worker-------
16*61c4878aSAndroid Build Coastguard WorkerSummary
17*61c4878aSAndroid Build Coastguard Worker-------
18*61c4878aSAndroid Build Coastguard WorkerA new peripheral protocol, I3C (pronounced eye-three-see) was introduced to
19*61c4878aSAndroid Build Coastguard Workerelectronic world and it has been widely accepted by SoC and sensor
20*61c4878aSAndroid Build Coastguard Workermanufacturers. This seed is to propose a new front-end library pw_i3c, to help
21*61c4878aSAndroid Build Coastguard Workercommunicate with devices on I3C bus.
22*61c4878aSAndroid Build Coastguard Worker
23*61c4878aSAndroid Build Coastguard Worker----------
24*61c4878aSAndroid Build Coastguard WorkerMotivation
25*61c4878aSAndroid Build Coastguard Worker----------
26*61c4878aSAndroid Build Coastguard WorkerThough widely used, I²C peripheral bus has several significant shortages, for
27*61c4878aSAndroid Build Coastguard Workerexample the low bus speed, extra physical line to carry interrupt from each
28*61c4878aSAndroid Build Coastguard Workerdevice on the I²C bus, etc. To cope with higher requirements and to address
29*61c4878aSAndroid Build Coastguard Workershortages of I²C, MIPI proposed a new fast, low-power and two-wire peripheral
30*61c4878aSAndroid Build Coastguard Workerprotocol, I3C.
31*61c4878aSAndroid Build Coastguard Worker
32*61c4878aSAndroid Build Coastguard WorkerI3C could be regarded as improved I²C. But in the meantime, it is a new protocol
33*61c4878aSAndroid Build Coastguard Workerwhich is different to I²C in both hardware and software. Some important
34*61c4878aSAndroid Build Coastguard Workerdifferences include:
35*61c4878aSAndroid Build Coastguard Worker
36*61c4878aSAndroid Build Coastguard Worker1. I3C SDA uses open-drain mode when necessary for legacy I²C compatibility,
37*61c4878aSAndroid Build Coastguard Worker   but switches to push-pull outputs whenever possible.
38*61c4878aSAndroid Build Coastguard Worker2. I3C SCL runs in only in pull-pull mode and can only be driven by I3C
39*61c4878aSAndroid Build Coastguard Worker   initiator.
40*61c4878aSAndroid Build Coastguard Worker3. I3C devices supports dynamic address assignment (DAA) and has higher address
41*61c4878aSAndroid Build Coastguard Worker   requirements.
42*61c4878aSAndroid Build Coastguard Worker4. I3C needs bus initialization and DAA before it is ready to use.
43*61c4878aSAndroid Build Coastguard Worker5. I3C has a standardized command set, called common command codes (CCC).
44*61c4878aSAndroid Build Coastguard Worker6. I3C supports In-Band interrupt and hot-join.
45*61c4878aSAndroid Build Coastguard Worker7. I3C device is identified by a 48-bit Provisioned ID (Manufacturer ID + Part
46*61c4878aSAndroid Build Coastguard Worker   ID + Instance ID).
47*61c4878aSAndroid Build Coastguard Worker
48*61c4878aSAndroid Build Coastguard WorkerIn conclusion, it is worth providing an independent library pw_i3c to help
49*61c4878aSAndroid Build Coastguard Workerinitialize I3C initiator and communicate with I3C devices on the bus.
50*61c4878aSAndroid Build Coastguard Worker
51*61c4878aSAndroid Build Coastguard Worker--------------------------
52*61c4878aSAndroid Build Coastguard WorkerProposal (Detailed design)
53*61c4878aSAndroid Build Coastguard Worker--------------------------
54*61c4878aSAndroid Build Coastguard WorkerSince I3C is very similar to I²C, following proposal is to create a standalone
55*61c4878aSAndroid Build Coastguard Workerlibrary pw_i3c, which shares a similar structure as pw_i2c.
56*61c4878aSAndroid Build Coastguard Worker
57*61c4878aSAndroid Build Coastguard Workerdevice type
58*61c4878aSAndroid Build Coastguard Worker-----------
59*61c4878aSAndroid Build Coastguard Worker
60*61c4878aSAndroid Build Coastguard WorkerThe ``DeviceType`` is used to help differentiate legacy I²C devices and I3C
61*61c4878aSAndroid Build Coastguard Workerdevices on one I3C bus.
62*61c4878aSAndroid Build Coastguard Worker
63*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++
64*61c4878aSAndroid Build Coastguard Worker
65*61c4878aSAndroid Build Coastguard Worker   enum class DeviceType : bool {
66*61c4878aSAndroid Build Coastguard Worker     kI2c,
67*61c4878aSAndroid Build Coastguard Worker     kI3c,
68*61c4878aSAndroid Build Coastguard Worker   };
69*61c4878aSAndroid Build Coastguard Worker
70*61c4878aSAndroid Build Coastguard WorkerAddress
71*61c4878aSAndroid Build Coastguard Worker-------
72*61c4878aSAndroid Build Coastguard Worker
73*61c4878aSAndroid Build Coastguard WorkerThe ``Address`` is a helper class to represent addresses which are used by
74*61c4878aSAndroid Build Coastguard Worker``pw_i3c`` APIs. In I3C protocol, addresses are differentiated by I²C (static)
75*61c4878aSAndroid Build Coastguard Workeraddress and I3C (active or dynamic) address. The reason why device type is
76*61c4878aSAndroid Build Coastguard Workerembedded into address is that transactions for I²C and I3C devices are
77*61c4878aSAndroid Build Coastguard Workerdifferent. So ``Initiator`` could tell the device type just by the provided
78*61c4878aSAndroid Build Coastguard Worker``Address`` object.
79*61c4878aSAndroid Build Coastguard Worker
80*61c4878aSAndroid Build Coastguard WorkerApart from creating and checking ``Address`` at compile time, a helper
81*61c4878aSAndroid Build Coastguard Workerconstructor to create and check ``Address`` at runtime is created, with
82*61c4878aSAndroid Build Coastguard Workerfollowing reasons:
83*61c4878aSAndroid Build Coastguard Worker
84*61c4878aSAndroid Build Coastguard Worker1. A new active/dynamic address could be assigned to I3C devices at run time.
85*61c4878aSAndroid Build Coastguard Worker2. New devices could hot-join the bus at run time.
86*61c4878aSAndroid Build Coastguard Worker
87*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++
88*61c4878aSAndroid Build Coastguard Worker
89*61c4878aSAndroid Build Coastguard Worker   class Address {
90*61c4878aSAndroid Build Coastguard Worker    public:
91*61c4878aSAndroid Build Coastguard Worker     static constexpr uint8_t kHotJoinAddress = 0x02;
92*61c4878aSAndroid Build Coastguard Worker     static constexpr uint8_t kBroadcastAddress = 0x7E;
93*61c4878aSAndroid Build Coastguard Worker     static constexpr uint8_t kStaticMaxAddress = 0x7F;
94*61c4878aSAndroid Build Coastguard Worker     // For I3C, the active (dynamic) address restriction is dynamic (depending
95*61c4878aSAndroid Build Coastguard Worker     // on devices on the bus, details can be found in "MIPI I3C Basic
96*61c4878aSAndroid Build Coastguard Worker     // Specification Version 1.1.1" chapter 5.1.2.2.5). But to simplify the
97*61c4878aSAndroid Build Coastguard Worker     // design, the strictest rule is applied. And there will be 108 addresses
98*61c4878aSAndroid Build Coastguard Worker     // free for dynamic address chosen.
99*61c4878aSAndroid Build Coastguard Worker     static constexpr uint8_t kDynamicMinAddress = 0x08;
100*61c4878aSAndroid Build Coastguard Worker     static constexpr uint8_t kDynamicMaxAddress = 0x7D;
101*61c4878aSAndroid Build Coastguard Worker
102*61c4878aSAndroid Build Coastguard Worker     // Helper constructor to ensure the address fits in the address space at
103*61c4878aSAndroid Build Coastguard Worker     // compile time, skipping the construction time assert.
104*61c4878aSAndroid Build Coastguard Worker     template <DeviceType kDeviceType, uint8_t kAddress>
105*61c4878aSAndroid Build Coastguard Worker     static constexpr Address Create() {
106*61c4878aSAndroid Build Coastguard Worker       static_assert(!IsOutOfRange(kDeviceType, kAddress));
107*61c4878aSAndroid Build Coastguard Worker       static_assert((DeviceType::kI2c == kDeviceType) ||
108*61c4878aSAndroid Build Coastguard Worker                     !SingleBitErrorDetection(kAddress));
109*61c4878aSAndroid Build Coastguard Worker       return Address{kDeviceType, kAddress};
110*61c4878aSAndroid Build Coastguard Worker     }
111*61c4878aSAndroid Build Coastguard Worker
112*61c4878aSAndroid Build Coastguard Worker     // Helper constructor to create the address at run time.
113*61c4878aSAndroid Build Coastguard Worker     // Returns std::nullopt if provided type and address does not fit address
114*61c4878aSAndroid Build Coastguard Worker     // rules.
115*61c4878aSAndroid Build Coastguard Worker     static constexpr std::optional<Address> Create(
116*61c4878aSAndroid Build Coastguard Worker         DeviceType device_type, uint8_t address) {
117*61c4878aSAndroid Build Coastguard Worker       if (IsOutOfRange(device_type, address)) {
118*61c4878aSAndroid Build Coastguard Worker         return std::nullopt;
119*61c4878aSAndroid Build Coastguard Worker       }
120*61c4878aSAndroid Build Coastguard Worker       if (DeviceType::kI3c == device_type && SingleBitErrorDetection(address)) {
121*61c4878aSAndroid Build Coastguard Worker         return std::nullopt;
122*61c4878aSAndroid Build Coastguard Worker       }
123*61c4878aSAndroid Build Coastguard Worker       return Address{type, address};
124*61c4878aSAndroid Build Coastguard Worker     }
125*61c4878aSAndroid Build Coastguard Worker
126*61c4878aSAndroid Build Coastguard Worker     // Return the type of address.
127*61c4878aSAndroid Build Coastguard Worker     constexpr DeviceType GetType() const;
128*61c4878aSAndroid Build Coastguard Worker
129*61c4878aSAndroid Build Coastguard Worker     // Return the address.
130*61c4878aSAndroid Build Coastguard Worker     constexpr uint8_t GetAddress() const;
131*61c4878aSAndroid Build Coastguard Worker
132*61c4878aSAndroid Build Coastguard Worker    private:
133*61c4878aSAndroid Build Coastguard Worker     static constexpr uint8_t kAddressMask = 0x7F;
134*61c4878aSAndroid Build Coastguard Worker     static constexpr int kTypeShift = 7;
135*61c4878aSAndroid Build Coastguard Worker     static constexpr uint8_t kTypeMask = 0x01;
136*61c4878aSAndroid Build Coastguard Worker
137*61c4878aSAndroid Build Coastguard Worker     constexpr Address(DeviceType type, uint8_t address)
138*61c4878aSAndroid Build Coastguard Worker         : packed_address_{Pack(type, address)} {}
139*61c4878aSAndroid Build Coastguard Worker
140*61c4878aSAndroid Build Coastguard Worker     uint8_t packed_address_;
141*61c4878aSAndroid Build Coastguard Worker   };
142*61c4878aSAndroid Build Coastguard Worker
143*61c4878aSAndroid Build Coastguard WorkerCcc
144*61c4878aSAndroid Build Coastguard Worker---
145*61c4878aSAndroid Build Coastguard Worker
146*61c4878aSAndroid Build Coastguard WorkerCommon Command Codes are categorized into broadcast(Command Codes from 0x00 to
147*61c4878aSAndroid Build Coastguard Worker0x7F) and direct(Command Codes from 0x80 to 0xFE). The rational behind it is
148*61c4878aSAndroid Build Coastguard Workerbroadcast CCC can only be write and is executed in one transaction, but direct
149*61c4878aSAndroid Build Coastguard WorkerCCC can be both write and read, and is executed in two transactions. We can
150*61c4878aSAndroid Build Coastguard Workereliminate extra CCC type check in initiator CCC API.
151*61c4878aSAndroid Build Coastguard Worker
152*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++
153*61c4878aSAndroid Build Coastguard Worker
154*61c4878aSAndroid Build Coastguard Worker   enum class CccBroadcast : uint8_t {
155*61c4878aSAndroid Build Coastguard Worker     kEnc = 0x00,
156*61c4878aSAndroid Build Coastguard Worker     kDisec = 0x01,
157*61c4878aSAndroid Build Coastguard Worker     kEntdas0 = 0x02,
158*61c4878aSAndroid Build Coastguard Worker     ...
159*61c4878aSAndroid Build Coastguard Worker     kSetxtime = 0x28,
160*61c4878aSAndroid Build Coastguard Worker     kSetaasa = 0x29,
161*61c4878aSAndroid Build Coastguard Worker   }
162*61c4878aSAndroid Build Coastguard Worker
163*61c4878aSAndroid Build Coastguard Worker   enum class CccDirect : uint8_t {
164*61c4878aSAndroid Build Coastguard Worker     kEnc = 0x80,
165*61c4878aSAndroid Build Coastguard Worker     kDisec = 0x81,
166*61c4878aSAndroid Build Coastguard Worker     kEntas0 = 0x82,
167*61c4878aSAndroid Build Coastguard Worker     ...
168*61c4878aSAndroid Build Coastguard Worker     kSetxtime = 0x98,
169*61c4878aSAndroid Build Coastguard Worker     kGetxtime = 0x99,
170*61c4878aSAndroid Build Coastguard Worker   };
171*61c4878aSAndroid Build Coastguard Worker
172*61c4878aSAndroid Build Coastguard Worker   inline constexpr uint8_t kCccDirectBit = 7;
173*61c4878aSAndroid Build Coastguard Worker
174*61c4878aSAndroid Build Coastguard Worker   enum class CccAction : bool {
175*61c4878aSAndroid Build Coastguard Worker     kWrite,
176*61c4878aSAndroid Build Coastguard Worker     kRead,
177*61c4878aSAndroid Build Coastguard Worker   };
178*61c4878aSAndroid Build Coastguard Worker
179*61c4878aSAndroid Build Coastguard WorkerInitiator
180*61c4878aSAndroid Build Coastguard Worker---------
181*61c4878aSAndroid Build Coastguard Worker
182*61c4878aSAndroid Build Coastguard Worker.. inclusive-language: disable
183*61c4878aSAndroid Build Coastguard Worker
184*61c4878aSAndroid Build Coastguard WorkerSimilar as ``pw::i2c``, ``Initiator`` is the common, base driver interface for
185*61c4878aSAndroid Build Coastguard Workerinitiating thread-safe transactions with devices on an I3C bus. Other
186*61c4878aSAndroid Build Coastguard Workerdocumentation may call this style of interface an “master”, “central”, or
187*61c4878aSAndroid Build Coastguard Worker“controller”.
188*61c4878aSAndroid Build Coastguard Worker
189*61c4878aSAndroid Build Coastguard Worker.. inclusive-language: enable
190*61c4878aSAndroid Build Coastguard Worker
191*61c4878aSAndroid Build Coastguard WorkerThe main difference by comparison with I²C, is I3C initiator needs a bus
192*61c4878aSAndroid Build Coastguard Workerinitialization and dynamic address assignment (DAA) step, before it is fully
193*61c4878aSAndroid Build Coastguard Workerfunctional. And after first bus initialization, I3C initiator should be able to
194*61c4878aSAndroid Build Coastguard Workerdo bus re-initialization anytime when the bus is free. However, different
195*61c4878aSAndroid Build Coastguard Workerbackend implementations may deal with this part differently. For example, Linux
196*61c4878aSAndroid Build Coastguard Workerdoes not expose I3C bus to userspace, which means users cannot control bus
197*61c4878aSAndroid Build Coastguard Workerinitialization. NXP Mcuxpresso SDK exposes I3C as a pure library to users, so it
198*61c4878aSAndroid Build Coastguard Workeris users' responsibility to initialize the bus and perform DAA to get a usable
199*61c4878aSAndroid Build Coastguard Workerinitiator. Zephyr provides more functions than Linux regarding I3C, which
200*61c4878aSAndroid Build Coastguard Workermakes I3C usage in Zephyr looks more likely to NXP Mcuxpresso SDK.
201*61c4878aSAndroid Build Coastguard Worker
202*61c4878aSAndroid Build Coastguard WorkerConsidering the complexity of different backend implementations of I3C bus, it
203*61c4878aSAndroid Build Coastguard Workeris better to have an "Initiator Maker" to take care of making an I3C
204*61c4878aSAndroid Build Coastguard Worker``Initiator``. And this is not considered in the first version of ``pw_i3c``
205*61c4878aSAndroid Build Coastguard Workerdesign.
206*61c4878aSAndroid Build Coastguard Worker
207*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++
208*61c4878aSAndroid Build Coastguard Worker
209*61c4878aSAndroid Build Coastguard Worker   // PID is the unique identifier to an I3C device.
210*61c4878aSAndroid Build Coastguard Worker   struct Pid {
211*61c4878aSAndroid Build Coastguard Worker     uint16_t manuf_id = 0;
212*61c4878aSAndroid Build Coastguard Worker     uint16_t part_id = 0;
213*61c4878aSAndroid Build Coastguard Worker     uint16_t instance_id = 0;
214*61c4878aSAndroid Build Coastguard Worker
215*61c4878aSAndroid Build Coastguard Worker     friend constexpr bool operator==(Pid const& lhs, Pid const& rhs) {
216*61c4878aSAndroid Build Coastguard Worker       return (lhs.manuf_id == rhs.manuf_id) && (lhs.part_id == rhs.part_id) &&
217*61c4878aSAndroid Build Coastguard Worker              (lhs.instance_id == rhs.instance_id);
218*61c4878aSAndroid Build Coastguard Worker     }
219*61c4878aSAndroid Build Coastguard Worker     friend constexpr bool operator!=(Pid const& lhs, Pid const& rhs) {
220*61c4878aSAndroid Build Coastguard Worker       return (lhs.manuf_id != rhs.manuf_id) || (lhs.part_id != rhs.part_id) ||
221*61c4878aSAndroid Build Coastguard Worker              (lhs.instance_id != rhs.instance_id);
222*61c4878aSAndroid Build Coastguard Worker     }
223*61c4878aSAndroid Build Coastguard Worker
224*61c4878aSAndroid Build Coastguard Worker    // Concat manuf_id, part_id and instance_id to a pid in 64-bit.
225*61c4878aSAndroid Build Coastguard Worker    constexpr uint64_t AsUint64(Pid const pid) {
226*61c4878aSAndroid Build Coastguard Worker      return (static_cast<uint64_t>(pid.manuf_id) << 33) |
227*61c4878aSAndroid Build Coastguard Worker             (static_cast<uint64_t>(pid.part_id) << 16) |
228*61c4878aSAndroid Build Coastguard Worker             (static_cast<uint64_t>(pid.instance_id) << 12);
229*61c4878aSAndroid Build Coastguard Worker    }
230*61c4878aSAndroid Build Coastguard Worker
231*61c4878aSAndroid Build Coastguard Worker    // Split a 64-bit pid into manuf_id, part_id and instance_id (struct Pid).
232*61c4878aSAndroid Build Coastguard Worker    static constexpr Pid FromUint64(const uint64_t pid) {
233*61c4878aSAndroid Build Coastguard Worker      return Pid{
234*61c4878aSAndroid Build Coastguard Worker          .manuf_id = ExtractBits<uint16_t, 47, 33>(pid),
235*61c4878aSAndroid Build Coastguard Worker          .part_id = ExtractBits<uint16_t, 31, 16>(pid),
236*61c4878aSAndroid Build Coastguard Worker          .instance_id = ExtractBits<uint16_t, 15, 12>(pid)};
237*61c4878aSAndroid Build Coastguard Worker    }
238*61c4878aSAndroid Build Coastguard Worker
239*61c4878aSAndroid Build Coastguard Worker  };
240*61c4878aSAndroid Build Coastguard Worker
241*61c4878aSAndroid Build Coastguard Worker  // I3C supports in-band interrupt (IBI), but generalize the name to cover
242*61c4878aSAndroid Build Coastguard Worker  // traditional interrupts.
243*61c4878aSAndroid Build Coastguard Worker  // For IBI, the argument can be used to store data transferred.
244*61c4878aSAndroid Build Coastguard Worker  // If the handler is queued in a workqueue, the data could be of any length.
245*61c4878aSAndroid Build Coastguard Worker  // If the handler is executed inside CPU ISR directly, the data should only
246*61c4878aSAndroid Build Coastguard Worker  // be mandatory data byte.
247*61c4878aSAndroid Build Coastguard Worker  using InterruptHandler = ::pw::Function<void(ByteSpan)>;
248*61c4878aSAndroid Build Coastguard Worker
249*61c4878aSAndroid Build Coastguard Worker  class Initiator {
250*61c4878aSAndroid Build Coastguard Worker   public:
251*61c4878aSAndroid Build Coastguard Worker    virtual ~Initiator() = default;
252*61c4878aSAndroid Build Coastguard Worker
253*61c4878aSAndroid Build Coastguard Worker    // Pid is the unique identifier to an I3C device and it should be known to
254*61c4878aSAndroid Build Coastguard Worker    // users through datasheets, like static addresses to I²C or I3C devices.
255*61c4878aSAndroid Build Coastguard Worker    // But active (dynamic) address to an I3C device is changeable during
256*61c4878aSAndroid Build Coastguard Worker    // run-time. Users could use this API to retrieve active address through
257*61c4878aSAndroid Build Coastguard Worker    // PID.
258*61c4878aSAndroid Build Coastguard Worker    //
259*61c4878aSAndroid Build Coastguard Worker    // There are other information which users may be interested to know about
260*61c4878aSAndroid Build Coastguard Worker    // an I3C device, like Bus Characteristics Register (BCR) and Device
261*61c4878aSAndroid Build Coastguard Worker    // Characteristic Register(s) (DCR). But they can be read through direct
262*61c4878aSAndroid Build Coastguard Worker    // read CCC API (ReadDirectCcc).
263*61c4878aSAndroid Build Coastguard Worker    //
264*61c4878aSAndroid Build Coastguard Worker    // Returns:
265*61c4878aSAndroid Build Coastguard Worker    // Dynamic Address - Success.
266*61c4878aSAndroid Build Coastguard Worker    // NOT_FOUND - Provided pid does not match with any active i3c device.
267*61c4878aSAndroid Build Coastguard Worker    Result<Address> RetrieveDynamicAddressByPid(Pid pid);
268*61c4878aSAndroid Build Coastguard Worker
269*61c4878aSAndroid Build Coastguard Worker    // Perform a broadcast CCC transaction.
270*61c4878aSAndroid Build Coastguard Worker    // ccc_id: the broadcast CCC ID.
271*61c4878aSAndroid Build Coastguard Worker    // buffer: payload to broadcast.
272*61c4878aSAndroid Build Coastguard Worker    //
273*61c4878aSAndroid Build Coastguard Worker    // Returns:
274*61c4878aSAndroid Build Coastguard Worker    // OK - Success.
275*61c4878aSAndroid Build Coastguard Worker    // INVALID_ARGUMENT - provided ccc_id is not supported.
276*61c4878aSAndroid Build Coastguard Worker    // UNAVAILABLE - NACK condition occurred, meaning there are no active I3C
277*61c4878aSAndroid Build Coastguard Worker    //   devices on the bus.
278*61c4878aSAndroid Build Coastguard Worker    // Other status codes as defined by backend.
279*61c4878aSAndroid Build Coastguard Worker    Status WriteBroadcastCcc(CccBroadcast ccc_id, ConstByteSpan buffer);
280*61c4878aSAndroid Build Coastguard Worker    Status WriteBroadcastCcc(CccBroadcast ccc_id,
281*61c4878aSAndroid Build Coastguard Worker                             const void* buffer,
282*61c4878aSAndroid Build Coastguard Worker                             size_t size_bytes);
283*61c4878aSAndroid Build Coastguard Worker
284*61c4878aSAndroid Build Coastguard Worker    // Perform a direct write CCC transaction.
285*61c4878aSAndroid Build Coastguard Worker    // ccc_id: the direct CCC ID.
286*61c4878aSAndroid Build Coastguard Worker    // device_address: the address which the CCC targets for.
287*61c4878aSAndroid Build Coastguard Worker    // buffer: payload to write.
288*61c4878aSAndroid Build Coastguard Worker    //
289*61c4878aSAndroid Build Coastguard Worker    // Returns:
290*61c4878aSAndroid Build Coastguard Worker    // OK - Success.
291*61c4878aSAndroid Build Coastguard Worker    // INVALID_ARGUMENT - provided ccc_id is not supported, or device_address is
292*61c4878aSAndroid Build Coastguard Worker    //   for I3C devices.
293*61c4878aSAndroid Build Coastguard Worker    // UNAVAILABLE - NACK condition occurred, meaning there is no active I3C
294*61c4878aSAndroid Build Coastguard Worker    //   device with the provided device_address or it is busy now.
295*61c4878aSAndroid Build Coastguard Worker    // Other status codes as defined by backend.
296*61c4878aSAndroid Build Coastguard Worker    Status WriteDirectCcc(CccDirect ccc_id,
297*61c4878aSAndroid Build Coastguard Worker                          Address device_address,
298*61c4878aSAndroid Build Coastguard Worker                          ConstByteSpan buffer);
299*61c4878aSAndroid Build Coastguard Worker    Status WriteDirectCcc(CccDirect ccc_id,
300*61c4878aSAndroid Build Coastguard Worker                          Address device_address,
301*61c4878aSAndroid Build Coastguard Worker                          const void* buffer,
302*61c4878aSAndroid Build Coastguard Worker                          size_t size_bytes);
303*61c4878aSAndroid Build Coastguard Worker
304*61c4878aSAndroid Build Coastguard Worker    // Perform a direct read CCC transaction.
305*61c4878aSAndroid Build Coastguard Worker    // ccc_id: the direct CCC ID.
306*61c4878aSAndroid Build Coastguard Worker    // device_address: the address which the CCC targets for.
307*61c4878aSAndroid Build Coastguard Worker    // buffer: payload to read.
308*61c4878aSAndroid Build Coastguard Worker    //
309*61c4878aSAndroid Build Coastguard Worker    // Returns:
310*61c4878aSAndroid Build Coastguard Worker    // OK - Success.
311*61c4878aSAndroid Build Coastguard Worker    // INVALID_ARGUMENT - provided ccc_id is not supported, or device_address is
312*61c4878aSAndroid Build Coastguard Worker    //   for I3C devices.
313*61c4878aSAndroid Build Coastguard Worker    // UNAVAILABLE - NACK condition occurred, meaning there is no active I3C
314*61c4878aSAndroid Build Coastguard Worker    //   device with the provided device_address or it is busy now.
315*61c4878aSAndroid Build Coastguard Worker    // Other status codes as defined by backend.
316*61c4878aSAndroid Build Coastguard Worker    Status ReadDirectCcc(CccDirect ccc_id,
317*61c4878aSAndroid Build Coastguard Worker                         Address device_address,
318*61c4878aSAndroid Build Coastguard Worker                         ByteSpan buffer);
319*61c4878aSAndroid Build Coastguard Worker    Status ReadDirectCcc(CccDirect ccc_id,
320*61c4878aSAndroid Build Coastguard Worker                         Address device_address,
321*61c4878aSAndroid Build Coastguard Worker                         void* buffer,
322*61c4878aSAndroid Build Coastguard Worker                         size_t size_bytes);
323*61c4878aSAndroid Build Coastguard Worker
324*61c4878aSAndroid Build Coastguard Worker    // Write bytes and read bytes (this is normally executed in two independent
325*61c4878aSAndroid Build Coastguard Worker    // transactions).
326*61c4878aSAndroid Build Coastguard Worker    //
327*61c4878aSAndroid Build Coastguard Worker    // Timeout is no longer needed in I3C transactions because only I3C
328*61c4878aSAndroid Build Coastguard Worker    // initiator drives the clock in push-pull mode, and devices on the bus
329*61c4878aSAndroid Build Coastguard Worker    // cannot stretch the clock.
330*61c4878aSAndroid Build Coastguard Worker    //
331*61c4878aSAndroid Build Coastguard Worker    // Returns:
332*61c4878aSAndroid Build Coastguard Worker    // Ok - Success.
333*61c4878aSAndroid Build Coastguard Worker    // UNAVAILABLE - NACK condition occurred, meaning the addressed device did
334*61c4878aSAndroid Build Coastguard Worker    //   not respond or was unable to process the request.
335*61c4878aSAndroid Build Coastguard Worker    // Other status codes as defined by backend.
336*61c4878aSAndroid Build Coastguard Worker    Status WriteReadFor(Address device_address,
337*61c4878aSAndroid Build Coastguard Worker                        ConstByteSpan tx_buffer,
338*61c4878aSAndroid Build Coastguard Worker                        ByteSpan rx_buffer);
339*61c4878aSAndroid Build Coastguard Worker    Status WriteReadFor(I3cResponder device,
340*61c4878aSAndroid Build Coastguard Worker                        const void* tx_buffer,
341*61c4878aSAndroid Build Coastguard Worker                        size_t tx_size_bytes,
342*61c4878aSAndroid Build Coastguard Worker                        void* rx_buffer,
343*61c4878aSAndroid Build Coastguard Worker                        size_t rx_size_bytes);
344*61c4878aSAndroid Build Coastguard Worker
345*61c4878aSAndroid Build Coastguard Worker    // Write bytes.
346*61c4878aSAndroid Build Coastguard Worker    //
347*61c4878aSAndroid Build Coastguard Worker    // Returns:
348*61c4878aSAndroid Build Coastguard Worker    // OK - Success.
349*61c4878aSAndroid Build Coastguard Worker    // UNAVAILABLE - NACK condition occurred, meaning the addressed device did
350*61c4878aSAndroid Build Coastguard Worker    //   not respond or was unable to process the request.
351*61c4878aSAndroid Build Coastguard Worker    // Other status codes as defined by backend.
352*61c4878aSAndroid Build Coastguard Worker    Status WriteFor(Address device_address, ConstByteSpan tx_buffer);
353*61c4878aSAndroid Build Coastguard Worker    Status WriteFor(Address device_address,
354*61c4878aSAndroid Build Coastguard Worker                    const void* tx_buffer,
355*61c4878aSAndroid Build Coastguard Worker                    size_t tx_size_bytes);
356*61c4878aSAndroid Build Coastguard Worker
357*61c4878aSAndroid Build Coastguard Worker    // Read bytes.
358*61c4878aSAndroid Build Coastguard Worker    //
359*61c4878aSAndroid Build Coastguard Worker    // Returns:
360*61c4878aSAndroid Build Coastguard Worker    // OK - Success.
361*61c4878aSAndroid Build Coastguard Worker    // UNAVAILABLE - NACK condition occurred, meaning the addressed device did
362*61c4878aSAndroid Build Coastguard Worker    //   not respond or was unable to process the request.
363*61c4878aSAndroid Build Coastguard Worker    // Other status codes as defined by backend.
364*61c4878aSAndroid Build Coastguard Worker    Status ReadFor(Address device_address, ByteSpan rx_buffer);
365*61c4878aSAndroid Build Coastguard Worker    Status ReadFor(Address device_address,
366*61c4878aSAndroid Build Coastguard Worker                   void* rx_buffer,
367*61c4878aSAndroid Build Coastguard Worker                   size_t rx_size_bytes);
368*61c4878aSAndroid Build Coastguard Worker
369*61c4878aSAndroid Build Coastguard Worker    // Probes the device for an ACK after only writing the address.
370*61c4878aSAndroid Build Coastguard Worker    // This is done by attempting to read a single byte from the specified
371*61c4878aSAndroid Build Coastguard Worker    // device.
372*61c4878aSAndroid Build Coastguard Worker    //
373*61c4878aSAndroid Build Coastguard Worker    // Returns:
374*61c4878aSAndroid Build Coastguard Worker    // OK - Success.
375*61c4878aSAndroid Build Coastguard Worker    // UNAVAILABLE - NACK condition occurred, meaning the addressed device did
376*61c4878aSAndroid Build Coastguard Worker    //   not respond or was unable to process the request.
377*61c4878aSAndroid Build Coastguard Worker    Status ProbeDeviceFor(Address device_address);
378*61c4878aSAndroid Build Coastguard Worker
379*61c4878aSAndroid Build Coastguard Worker    // Sets a (IBI) handler to execute when an interrupt is triggered from a
380*61c4878aSAndroid Build Coastguard Worker    // device with the provided address. Handler for one address should be
381*61c4878aSAndroid Build Coastguard Worker    // registered only once, unless it is cleared. Registration twice with
382*61c4878aSAndroid Build Coastguard Worker    // same address should fail.
383*61c4878aSAndroid Build Coastguard Worker    //
384*61c4878aSAndroid Build Coastguard Worker    // Note that hot-join handler could be registered with this function since
385*61c4878aSAndroid Build Coastguard Worker    // hot-join is sent through IBI.
386*61c4878aSAndroid Build Coastguard Worker    //
387*61c4878aSAndroid Build Coastguard Worker    // This handler is finally executed by I3C initiator, which means it may
388*61c4878aSAndroid Build Coastguard Worker    // include any valid I3C actions (write and read). When I3C write/read
389*61c4878aSAndroid Build Coastguard Worker    // happens, the interrupt handler is more like an I3C transaction than a
390*61c4878aSAndroid Build Coastguard Worker    // traditional interrupt. Different I3C initiators may execute the handler
391*61c4878aSAndroid Build Coastguard Worker    // in different ways. Some may queue the work on a workqueue and some may
392*61c4878aSAndroid Build Coastguard Worker    // execute the handler directly inside IBI IRQ. Users should be aware of the
393*61c4878aSAndroid Build Coastguard Worker    // backend algorithm and when execution happens in IBI IRQ, they should just
394*61c4878aSAndroid Build Coastguard Worker    // read the mandatory data byte out through the handler and perform other
395*61c4878aSAndroid Build Coastguard Worker    // actions in a different thread.
396*61c4878aSAndroid Build Coastguard Worker    //
397*61c4878aSAndroid Build Coastguard Worker    // Warning:
398*61c4878aSAndroid Build Coastguard Worker    // This method is not thread-safe and cannot be used in interrupt handlers.
399*61c4878aSAndroid Build Coastguard Worker    //
400*61c4878aSAndroid Build Coastguard Worker    // Returns:
401*61c4878aSAndroid Build Coastguard Worker    // OK - The interrupt handler was configured.
402*61c4878aSAndroid Build Coastguard Worker    // INVALID_ARGUMENT - The handler is empty, or the handler is for IBI but
403*61c4878aSAndroid Build Coastguard Worker    //   the address is not for an I3C device.
404*61c4878aSAndroid Build Coastguard Worker    // Other status codes as defined by the backend.
405*61c4878aSAndroid Build Coastguard Worker    Status SetInterruptHandler(Address device_address,
406*61c4878aSAndroid Build Coastguard Worker                               InterruptHandler&& handler);
407*61c4878aSAndroid Build Coastguard Worker
408*61c4878aSAndroid Build Coastguard Worker    // Clears the interrupt handler.
409*61c4878aSAndroid Build Coastguard Worker    //
410*61c4878aSAndroid Build Coastguard Worker    // Warning:
411*61c4878aSAndroid Build Coastguard Worker    // This method is not thread-safe and cannot be used in interrupt handlers.
412*61c4878aSAndroid Build Coastguard Worker    //
413*61c4878aSAndroid Build Coastguard Worker    // Returns:
414*61c4878aSAndroid Build Coastguard Worker    // OK - The interrupt handler was cleared
415*61c4878aSAndroid Build Coastguard Worker    // INVALID_ARGUMENT - the handler is for IBI but the address is not for an
416*61c4878aSAndroid Build Coastguard Worker    //    I3C device.
417*61c4878aSAndroid Build Coastguard Worker    // Other status codes as defined by the backend.
418*61c4878aSAndroid Build Coastguard Worker    Status ClearInterruptHandler(Address device_address);
419*61c4878aSAndroid Build Coastguard Worker
420*61c4878aSAndroid Build Coastguard Worker    // Enables interrupts which will trigger the interrupt handler.
421*61c4878aSAndroid Build Coastguard Worker    //
422*61c4878aSAndroid Build Coastguard Worker    // Warning:
423*61c4878aSAndroid Build Coastguard Worker    // This method is not thread-safe and cannot be used in interrupt handlers.
424*61c4878aSAndroid Build Coastguard Worker    //
425*61c4878aSAndroid Build Coastguard Worker    // Preconditions:
426*61c4878aSAndroid Build Coastguard Worker    // A handler has been set using `SetInterruptHandler()`.
427*61c4878aSAndroid Build Coastguard Worker    //
428*61c4878aSAndroid Build Coastguard Worker    // Returns:
429*61c4878aSAndroid Build Coastguard Worker    // OK - The interrupt handler was enabled.
430*61c4878aSAndroid Build Coastguard Worker    // INVALID_ARGUMENT - the handler is for IBI but the address is not for an
431*61c4878aSAndroid Build Coastguard Worker    //    I3C device.
432*61c4878aSAndroid Build Coastguard Worker    // Other status codes as defined by the backend.
433*61c4878aSAndroid Build Coastguard Worker    Status EnableInterruptHandler(Address device_address);
434*61c4878aSAndroid Build Coastguard Worker
435*61c4878aSAndroid Build Coastguard Worker    // Disables interrupts which will trigger the interrupt handler.
436*61c4878aSAndroid Build Coastguard Worker    //
437*61c4878aSAndroid Build Coastguard Worker    // Warning:
438*61c4878aSAndroid Build Coastguard Worker    // This method is not thread-safe and cannot be used in interrupt handlers.
439*61c4878aSAndroid Build Coastguard Worker    //
440*61c4878aSAndroid Build Coastguard Worker    // Preconditions:
441*61c4878aSAndroid Build Coastguard Worker    // A handler has been set using `SetInterruptHandler()`.
442*61c4878aSAndroid Build Coastguard Worker    //
443*61c4878aSAndroid Build Coastguard Worker    // Returns:
444*61c4878aSAndroid Build Coastguard Worker    // OK - The interrupt handler was disabled.
445*61c4878aSAndroid Build Coastguard Worker    // INVALID_ARGUMENT - the handler is for IBI but the address is not for an
446*61c4878aSAndroid Build Coastguard Worker    //    I3C device.
447*61c4878aSAndroid Build Coastguard Worker    // Other status codes as defined by the backend.
448*61c4878aSAndroid Build Coastguard Worker    Status DisableInterruptHandler(Address device_address);
449*61c4878aSAndroid Build Coastguard Worker
450*61c4878aSAndroid Build Coastguard Worker   private:
451*61c4878aSAndroid Build Coastguard Worker    virtual Result<Address> DoRetrieveDynamicAddressByPid(Pid pid) = 0;
452*61c4878aSAndroid Build Coastguard Worker    virtual Status DoTransferCcc(CccAction read_or_write,
453*61c4878aSAndroid Build Coastguard Worker                                 uint8_t ccc_id,
454*61c4878aSAndroid Build Coastguard Worker                                 std::optional<Address> device_address,
455*61c4878aSAndroid Build Coastguard Worker                                 ByteSpan buffer) = 0;
456*61c4878aSAndroid Build Coastguard Worker    virtual Status DoWriteReadFor(Address device_address,
457*61c4878aSAndroid Build Coastguard Worker                                  ConstByteSpan tx_buffer,
458*61c4878aSAndroid Build Coastguard Worker                                  ByteSpan rx_buffer) = 0;
459*61c4878aSAndroid Build Coastguard Worker    virtual Status DoSetInterruptHandler(Address address,
460*61c4878aSAndroid Build Coastguard Worker                                         InterruptHandler&& handler) = 0;
461*61c4878aSAndroid Build Coastguard Worker    virtual Status DoEnableInterruptHandler(Address address, bool enable) = 0;
462*61c4878aSAndroid Build Coastguard Worker  };
463*61c4878aSAndroid Build Coastguard Worker
464*61c4878aSAndroid Build Coastguard WorkerDevice
465*61c4878aSAndroid Build Coastguard Worker------
466*61c4878aSAndroid Build Coastguard Worker
467*61c4878aSAndroid Build Coastguard WorkerSame as ``pw::i2c::Device``, a ``Device`` class is used in ``pw::i3c`` to
468*61c4878aSAndroid Build Coastguard Workerwrite/read arbitrary chunks of data over a bus to a specific device, or perform
469*61c4878aSAndroid Build Coastguard Workerother I3C operations, e.g. direct CCC.
470*61c4878aSAndroid Build Coastguard WorkerThough PID is the unique identifier for I3C devices, considering backward
471*61c4878aSAndroid Build Coastguard Workercompatibility with I²C devices, this object also wraps the Initiator API with
472*61c4878aSAndroid Build Coastguard Workeran active ``Address``. Application should initiate or be notified the
473*61c4878aSAndroid Build Coastguard Worker``Address`` change and update the ``Address`` in ``Device`` object.
474*61c4878aSAndroid Build Coastguard Worker
475*61c4878aSAndroid Build Coastguard Worker.. code-block:: c++
476*61c4878aSAndroid Build Coastguard Worker
477*61c4878aSAndroid Build Coastguard Worker   class Device {
478*61c4878aSAndroid Build Coastguard Worker    public:
479*61c4878aSAndroid Build Coastguard Worker     // It is users' responsibility to get and pass the active (dynamic) address
480*61c4878aSAndroid Build Coastguard Worker     // when creating a ``Device``. If the dynamic address of an I3C device is
481*61c4878aSAndroid Build Coastguard Worker     // unknown, users could get it through initiator:
482*61c4878aSAndroid Build Coastguard Worker     // pw::i3c::Initiator::RetrieveDynamicAddressByPid();
483*61c4878aSAndroid Build Coastguard Worker     constexpr Device(Initiator& initiator, Address device_address, Pid pid)
484*61c4878aSAndroid Build Coastguard Worker        : initiator_(initiator),
485*61c4878aSAndroid Build Coastguard Worker          device_address_(device_address),
486*61c4878aSAndroid Build Coastguard Worker          pid_(pid) {}
487*61c4878aSAndroid Build Coastguard Worker
488*61c4878aSAndroid Build Coastguard Worker     // For I2C devices connected to I3C bus, pid_ is default-initialized to be
489*61c4878aSAndroid Build Coastguard Worker     // std::nullopt.
490*61c4878aSAndroid Build Coastguard Worker     constexpr Device(Initiator& initiator, Address device_address)
491*61c4878aSAndroid Build Coastguard Worker        : initiator_(initiator),
492*61c4878aSAndroid Build Coastguard Worker          device_address_(device_address) {}
493*61c4878aSAndroid Build Coastguard Worker
494*61c4878aSAndroid Build Coastguard Worker     Device(const Device&) = delete;
495*61c4878aSAndroid Build Coastguard Worker     Device(Device&&) = default;
496*61c4878aSAndroid Build Coastguard Worker     ~Device() = default;
497*61c4878aSAndroid Build Coastguard Worker
498*61c4878aSAndroid Build Coastguard Worker     // Perform a direct write CCC transaction.
499*61c4878aSAndroid Build Coastguard Worker     // ccc_id: the direct CCC ID.
500*61c4878aSAndroid Build Coastguard Worker     // buffer: payload to write.
501*61c4878aSAndroid Build Coastguard Worker     //
502*61c4878aSAndroid Build Coastguard Worker     // Returns:
503*61c4878aSAndroid Build Coastguard Worker     // OK - Success.
504*61c4878aSAndroid Build Coastguard Worker     // INVALID_ARGUMENT - provided ccc_id is not supported, or device_address_
505*61c4878aSAndroid Build Coastguard Worker     //   is not for I3C devices.
506*61c4878aSAndroid Build Coastguard Worker     // UNAVAILABLE - NACK condition occurred, meaning there is no active I3C
507*61c4878aSAndroid Build Coastguard Worker     //   device with the provided device_address or it is busy now.
508*61c4878aSAndroid Build Coastguard Worker     // Other status codes as defined by backend.
509*61c4878aSAndroid Build Coastguard Worker     Status WriteDirectCcc(CccDirect ccc_id, ConstByteSpan buffer);
510*61c4878aSAndroid Build Coastguard Worker     Status WriteDirectCcc(CccDirect ccc_id,
511*61c4878aSAndroid Build Coastguard Worker                           const void* buffer,
512*61c4878aSAndroid Build Coastguard Worker                           size_t size_bytes);
513*61c4878aSAndroid Build Coastguard Worker
514*61c4878aSAndroid Build Coastguard Worker     // Perform a direct read CCC transaction.
515*61c4878aSAndroid Build Coastguard Worker     // ccc_id: the direct CCC ID.
516*61c4878aSAndroid Build Coastguard Worker     // buffer: payload to read.
517*61c4878aSAndroid Build Coastguard Worker     //
518*61c4878aSAndroid Build Coastguard Worker     // Returns:
519*61c4878aSAndroid Build Coastguard Worker     // OK - Success.
520*61c4878aSAndroid Build Coastguard Worker     // INVALID_ARGUMENT - provided ccc_id is not supported, or device_address_
521*61c4878aSAndroid Build Coastguard Worker     //   is not for I3C devices.
522*61c4878aSAndroid Build Coastguard Worker     // UNAVAILABLE - NACK condition occurred, meaning there is no active I3C
523*61c4878aSAndroid Build Coastguard Worker     //   device with the provided device_address or it is busy now.
524*61c4878aSAndroid Build Coastguard Worker     // Other status codes as defined by backend.
525*61c4878aSAndroid Build Coastguard Worker     Status ReadDirectCcc(CccDirect ccc_id, ByteSpan buffer);
526*61c4878aSAndroid Build Coastguard Worker     Status ReadDirectCcc(CccDirect ccc_id,
527*61c4878aSAndroid Build Coastguard Worker                          const void* buffer,
528*61c4878aSAndroid Build Coastguard Worker                          size_t size_bytes);
529*61c4878aSAndroid Build Coastguard Worker
530*61c4878aSAndroid Build Coastguard Worker     // Write bytes and read bytes (this is normally executed in two independent
531*61c4878aSAndroid Build Coastguard Worker     // transactions).
532*61c4878aSAndroid Build Coastguard Worker     //
533*61c4878aSAndroid Build Coastguard Worker     // Timeout is no longer needed in I3C transactions because only I3C
534*61c4878aSAndroid Build Coastguard Worker     // initiator drives the clock in push-pull mode, and devices on the bus
535*61c4878aSAndroid Build Coastguard Worker     // cannot stretch the clock.
536*61c4878aSAndroid Build Coastguard Worker     //
537*61c4878aSAndroid Build Coastguard Worker     // Returns:
538*61c4878aSAndroid Build Coastguard Worker     // OK - Success.
539*61c4878aSAndroid Build Coastguard Worker     // UNAVAILABLE - NACK condition occurred, meaning the addressed device did
540*61c4878aSAndroid Build Coastguard Worker     //   not respond or was unable to process the request.
541*61c4878aSAndroid Build Coastguard Worker     // Other status codes as defined by backend.
542*61c4878aSAndroid Build Coastguard Worker     Status WriteReadFor(ConstByteSpan tx_buffer, ByteSpan rx_buffer);
543*61c4878aSAndroid Build Coastguard Worker     Status WriteReadFor(const void* tx_buffer,
544*61c4878aSAndroid Build Coastguard Worker                         size_t tx_size_bytes,
545*61c4878aSAndroid Build Coastguard Worker                         void* rx_buffer,
546*61c4878aSAndroid Build Coastguard Worker                         size_t rx_size_bytes);
547*61c4878aSAndroid Build Coastguard Worker
548*61c4878aSAndroid Build Coastguard Worker     // Write bytes.
549*61c4878aSAndroid Build Coastguard Worker     //
550*61c4878aSAndroid Build Coastguard Worker     // Returns:
551*61c4878aSAndroid Build Coastguard Worker     // OK - Success.
552*61c4878aSAndroid Build Coastguard Worker     // UNAVAILABLE - NACK condition occurred, meaning the addressed device did
553*61c4878aSAndroid Build Coastguard Worker     //   not respond or was unable to process the request.
554*61c4878aSAndroid Build Coastguard Worker     // Other status codes as defined by backend.
555*61c4878aSAndroid Build Coastguard Worker     Status WriteFor(ConstByteSpan tx_buffer);
556*61c4878aSAndroid Build Coastguard Worker     Status WriteFor(const void* tx_buffer, size_t tx_size_bytes);
557*61c4878aSAndroid Build Coastguard Worker
558*61c4878aSAndroid Build Coastguard Worker     // Read bytes.
559*61c4878aSAndroid Build Coastguard Worker     //
560*61c4878aSAndroid Build Coastguard Worker     // Returns:
561*61c4878aSAndroid Build Coastguard Worker     // Ok - Success.
562*61c4878aSAndroid Build Coastguard Worker     // UNAVAILABLE - NACK condition occurred, meaning the addressed device did
563*61c4878aSAndroid Build Coastguard Worker     //   not respond or was unable to process the request.
564*61c4878aSAndroid Build Coastguard Worker     // Other status codes as defined by backend.
565*61c4878aSAndroid Build Coastguard Worker     Status ReadFor(ByteSpan rx_buffer);
566*61c4878aSAndroid Build Coastguard Worker     Status ReadFor(void* rx_buffer, size_t rx_size_bytes);
567*61c4878aSAndroid Build Coastguard Worker
568*61c4878aSAndroid Build Coastguard Worker     // Probes the device for an ACK after only writing the address.
569*61c4878aSAndroid Build Coastguard Worker     // This is done by attempting to read a single byte from this device.
570*61c4878aSAndroid Build Coastguard Worker     //
571*61c4878aSAndroid Build Coastguard Worker     // Returns:
572*61c4878aSAndroid Build Coastguard Worker     // Ok - Success.
573*61c4878aSAndroid Build Coastguard Worker     // UNAVAILABLE - NACK condition occurred, meaning the addressed device did
574*61c4878aSAndroid Build Coastguard Worker     //   not respond or was unable to process the request.
575*61c4878aSAndroid Build Coastguard Worker     Status ProbeFor();
576*61c4878aSAndroid Build Coastguard Worker
577*61c4878aSAndroid Build Coastguard Worker     // Sets a (IBI) handler to execute when an interrupt is triggered from a
578*61c4878aSAndroid Build Coastguard Worker     // device with the provided address. Handler for one address should be
579*61c4878aSAndroid Build Coastguard Worker     // registered only once, unless it is cleared. Registration twice with
580*61c4878aSAndroid Build Coastguard Worker     // same address should fail.
581*61c4878aSAndroid Build Coastguard Worker     //
582*61c4878aSAndroid Build Coastguard Worker     // This handler is finally executed by I3C initiator, which means it may
583*61c4878aSAndroid Build Coastguard Worker     // include any valid I3C actions (write and read). When I3C write/read
584*61c4878aSAndroid Build Coastguard Worker     // happens, the interrupt handler is more like an I3C transaction than a
585*61c4878aSAndroid Build Coastguard Worker     // traditional interrupt. Different I3C initiators may execute the handler
586*61c4878aSAndroid Build Coastguard Worker     // in different ways. Some may queue the work on a workqueue and some may
587*61c4878aSAndroid Build Coastguard Worker     // execute the handler directly inside IBI IRQ. Users should be aware of the
588*61c4878aSAndroid Build Coastguard Worker     // backend algorithm and when execution happens in IBI IRQ, they should just
589*61c4878aSAndroid Build Coastguard Worker     // read the mandatory data byte out through the handler and perform other
590*61c4878aSAndroid Build Coastguard Worker     // actions in a different thread.
591*61c4878aSAndroid Build Coastguard Worker     //
592*61c4878aSAndroid Build Coastguard Worker     // Warning:
593*61c4878aSAndroid Build Coastguard Worker     // This method is not thread-safe and cannot be used in interrupt handlers.
594*61c4878aSAndroid Build Coastguard Worker     // Do not register hot-join handler for I3C devices as hot-join handler is
595*61c4878aSAndroid Build Coastguard Worker     // initiator specific, not for a single device.
596*61c4878aSAndroid Build Coastguard Worker     //
597*61c4878aSAndroid Build Coastguard Worker     // Returns:
598*61c4878aSAndroid Build Coastguard Worker     // OK - The interrupt handler was configured.
599*61c4878aSAndroid Build Coastguard Worker     // INVALID_ARGUMENT - The handler is empty, or the handler is for IBI but
600*61c4878aSAndroid Build Coastguard Worker     //   the device is an I3C device.
601*61c4878aSAndroid Build Coastguard Worker     // Other status codes as defined by the backend.
602*61c4878aSAndroid Build Coastguard Worker     Status SetInterruptHandler(InterruptHandler&& handler);
603*61c4878aSAndroid Build Coastguard Worker
604*61c4878aSAndroid Build Coastguard Worker     // Clears the interrupt handler.
605*61c4878aSAndroid Build Coastguard Worker     //
606*61c4878aSAndroid Build Coastguard Worker     // Warning:
607*61c4878aSAndroid Build Coastguard Worker     // This method is not thread-safe and cannot be used in interrupt handlers.
608*61c4878aSAndroid Build Coastguard Worker     //
609*61c4878aSAndroid Build Coastguard Worker     // Returns:
610*61c4878aSAndroid Build Coastguard Worker     // OK - The interrupt handler was cleared
611*61c4878aSAndroid Build Coastguard Worker     // INVALID_ARGUMENT - the handler is for IBI but the device is an I3C device.
612*61c4878aSAndroid Build Coastguard Worker     // Other status codes as defined by the backend.
613*61c4878aSAndroid Build Coastguard Worker     Status ClearInterruptHandler();
614*61c4878aSAndroid Build Coastguard Worker
615*61c4878aSAndroid Build Coastguard Worker     // Enables interrupts which will trigger the interrupt handler.
616*61c4878aSAndroid Build Coastguard Worker     //
617*61c4878aSAndroid Build Coastguard Worker     // Warning:
618*61c4878aSAndroid Build Coastguard Worker     // This method is not thread-safe and cannot be used in interrupt handlers.
619*61c4878aSAndroid Build Coastguard Worker     //
620*61c4878aSAndroid Build Coastguard Worker     // Preconditions:
621*61c4878aSAndroid Build Coastguard Worker     // A handler has been set using `SetInterruptHandler()`.
622*61c4878aSAndroid Build Coastguard Worker     //
623*61c4878aSAndroid Build Coastguard Worker     // Returns:
624*61c4878aSAndroid Build Coastguard Worker     // OK - The interrupt handler was enabled.
625*61c4878aSAndroid Build Coastguard Worker     // INVALID_ARGUMENT - the handler is for IBI but the device is an I3C device.
626*61c4878aSAndroid Build Coastguard Worker     // Other status codes as defined by the backend.
627*61c4878aSAndroid Build Coastguard Worker     Status EnableInterruptHandler();
628*61c4878aSAndroid Build Coastguard Worker
629*61c4878aSAndroid Build Coastguard Worker     // Disables interrupts which will trigger the interrupt handler.
630*61c4878aSAndroid Build Coastguard Worker     //
631*61c4878aSAndroid Build Coastguard Worker     // Warning:
632*61c4878aSAndroid Build Coastguard Worker     // This method is not thread-safe and cannot be used in interrupt handlers.
633*61c4878aSAndroid Build Coastguard Worker     //
634*61c4878aSAndroid Build Coastguard Worker     // Preconditions:
635*61c4878aSAndroid Build Coastguard Worker     // A handler has been set using `SetInterruptHandler()`.
636*61c4878aSAndroid Build Coastguard Worker     //
637*61c4878aSAndroid Build Coastguard Worker     // Returns:
638*61c4878aSAndroid Build Coastguard Worker     // OK - The interrupt handler was disabled.
639*61c4878aSAndroid Build Coastguard Worker     // INVALID_ARGUMENT - the handler is for IBI but the device is an I3C device.
640*61c4878aSAndroid Build Coastguard Worker     // Other status codes as defined by the backend.
641*61c4878aSAndroid Build Coastguard Worker     Status DisableInterruptHandler();
642*61c4878aSAndroid Build Coastguard Worker
643*61c4878aSAndroid Build Coastguard Worker     // Update device address during run-time actively.
644*61c4878aSAndroid Build Coastguard Worker     //
645*61c4878aSAndroid Build Coastguard Worker     // Warning:
646*61c4878aSAndroid Build Coastguard Worker     // This function is dedicatedly to I3C devices.
647*61c4878aSAndroid Build Coastguard Worker     void UpdateAddressActively(Address new_address);
648*61c4878aSAndroid Build Coastguard Worker
649*61c4878aSAndroid Build Coastguard Worker     // Update device address during run-time Passively.
650*61c4878aSAndroid Build Coastguard Worker     // initiator_ will be responsible for retrieving the dynamic address and
651*61c4878aSAndroid Build Coastguard Worker     // substitute the device_address_.
652*61c4878aSAndroid Build Coastguard Worker     //
653*61c4878aSAndroid Build Coastguard Worker     // Warning:
654*61c4878aSAndroid Build Coastguard Worker     // This function is dedicatedly to I3C devices.
655*61c4878aSAndroid Build Coastguard Worker     //
656*61c4878aSAndroid Build Coastguard Worker     // Returns:
657*61c4878aSAndroid Build Coastguard Worker     // OK - Success.
658*61c4878aSAndroid Build Coastguard Worker     // UNIMPLEMENTED - pid is empty (I²C device).
659*61c4878aSAndroid Build Coastguard Worker     // NOT_FOUND - initiator_ fails to retrieve dynamic address based on pid_.
660*61c4878aSAndroid Build Coastguard Worker     Status UpdateAddressPassively();
661*61c4878aSAndroid Build Coastguard Worker
662*61c4878aSAndroid Build Coastguard Worker    private:
663*61c4878aSAndroid Build Coastguard Worker     Initiator& initiator_;
664*61c4878aSAndroid Build Coastguard Worker     Address device_address_;
665*61c4878aSAndroid Build Coastguard Worker     std::optional<Pid> pid_;
666*61c4878aSAndroid Build Coastguard Worker   };
667*61c4878aSAndroid Build Coastguard Worker
668*61c4878aSAndroid Build Coastguard Worker------------
669*61c4878aSAndroid Build Coastguard WorkerAlternatives
670*61c4878aSAndroid Build Coastguard Worker------------
671*61c4878aSAndroid Build Coastguard WorkerSince I3C is similar to I²C and pw_i3c is similar to pw_i2c, instead of creating
672*61c4878aSAndroid Build Coastguard Workera standalone library, an alternative solution is to combine pw_i3c and pw_i2c,
673*61c4878aSAndroid Build Coastguard Workerand providing a single library pw_ixc, or other suitable names. And in this
674*61c4878aSAndroid Build Coastguard Workercomprehensive library, I3C-related features could be designed to be optional.
675*61c4878aSAndroid Build Coastguard Worker
676*61c4878aSAndroid Build Coastguard WorkerOn one hand, this solution could reuse a lot of code and simplify some work in
677*61c4878aSAndroid Build Coastguard Workeruser level, if users want to abstract usage of I²C and I3C in application.
678*61c4878aSAndroid Build Coastguard WorkerOn the other hand, it also brings churn to existing projects using pw_i2c, and
679*61c4878aSAndroid Build Coastguard Workerambiguity and confusion in the long run (I²C is mature, but I3C is new and
680*61c4878aSAndroid Build Coastguard Workeractively improving).
681*61c4878aSAndroid Build Coastguard Worker
682*61c4878aSAndroid Build Coastguard Worker--------------
683*61c4878aSAndroid Build Coastguard WorkerOpen Questions
684*61c4878aSAndroid Build Coastguard Worker--------------
685*61c4878aSAndroid Build Coastguard Worker1. As mentioned in the description of I3C ``Initiator`` class, the creation of a
686*61c4878aSAndroid Build Coastguard Worker   fully functional ``Initiator`` would be handled by a different class.
687*61c4878aSAndroid Build Coastguard Worker
688*61c4878aSAndroid Build Coastguard Worker2. Because there are two types of ``Address`` in I3C, the static and dynamic,
689*61c4878aSAndroid Build Coastguard Worker   the ``pw::i3c::Address`` is not compatible with ``pw::i2c::Address``. So when
690*61c4878aSAndroid Build Coastguard Worker   users try to create an ``Address`` for an I²C device, they need to carefully
691*61c4878aSAndroid Build Coastguard Worker   choose the correct class depending on which bus the device is connected to.
692*61c4878aSAndroid Build Coastguard Worker   This class may cause bigger concern if ``Address`` is needed to be shared
693*61c4878aSAndroid Build Coastguard Worker   through interface in application code.
694*61c4878aSAndroid Build Coastguard Worker   But the problem is resolvable by templating ``Address`` in caller code.
695*61c4878aSAndroid Build Coastguard Worker   Also, we can have a helper function in ``pw::i3c::Address``, which consumes a
696*61c4878aSAndroid Build Coastguard Worker   ``pw::i2c::Addres``s and create a ``pw::i3c::Address``. This helper will be
697*61c4878aSAndroid Build Coastguard Worker   added and discussed further in a following patch.
698*61c4878aSAndroid Build Coastguard Worker
699*61c4878aSAndroid Build Coastguard Worker3. ``DeviceType`` is embedded into ``Address``. So ``pw::i3c::Initiator`` could
700*61c4878aSAndroid Build Coastguard Worker   tell the device type (I²C or I3C) based on provided ``Address``. But this is
701*61c4878aSAndroid Build Coastguard Worker   not necessary because Initiator has performed DAA during initialization so it
702*61c4878aSAndroid Build Coastguard Worker   should know which addresses have been assigned to I3C devices.
703*61c4878aSAndroid Build Coastguard Worker   In this case, the only advantage of this design is to help applying address
704*61c4878aSAndroid Build Coastguard Worker   restriction during creating ``Address`` object. Should address restriction be
705*61c4878aSAndroid Build Coastguard Worker   taken care of by HAL? Though fewer, I²C has reserved addresses, too, but they
706*61c4878aSAndroid Build Coastguard Worker   are not checked in ``pw::i2c::Address``.
707*61c4878aSAndroid Build Coastguard Worker
708*61c4878aSAndroid Build Coastguard Worker4. ``RegisterDevice`` for I3C is the same as I²C, in protocol. To read/write
709*61c4878aSAndroid Build Coastguard Worker   from a register, the ``Initiator`` sends an active address on the bus. Once
710*61c4878aSAndroid Build Coastguard Worker   acknowledged, it will send the register address followed by data.
711*61c4878aSAndroid Build Coastguard Worker   So the ideal design is to abstract ``RegisterDevice`` across I²C and I3C, or
712*61c4878aSAndroid Build Coastguard Worker   maybe even other peripheral buses (e.g. SPI and DSI). However, the underlying
713*61c4878aSAndroid Build Coastguard Worker   register operation functions are different. It is better to be handled in a
714*61c4878aSAndroid Build Coastguard Worker   separate SEED.
715