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