libxr
Embedded C++ framework for bare-metal, RTOS and Linux
Loading...
Searching...
No Matches
hpm_i2c.cpp
1#include "hpm_i2c.hpp"
2
3#include <cstdint>
4
5using namespace LibXR;
6
7namespace
8{
9
10constexpr uint16_t kSharedMax7BitAddress = 0x7FU;
11constexpr uint16_t kSharedMax10BitAddress = 0x3FFU;
12
13uint16_t ResolveHpmI2cMaxSlaveAddress(HPMI2C::AddressMode mode)
14{
15 return mode == HPMI2C::AddressMode::ADDR_10BIT ? kSharedMax10BitAddress
16 : kSharedMax7BitAddress;
17}
18
19ErrorCode ValidateHpmI2cSlaveAddress(HPMI2C::AddressMode mode, uint16_t slave_addr)
20{
21 return (slave_addr <= ResolveHpmI2cMaxSlaveAddress(mode)) ? ErrorCode::OK
22 : ErrorCode::ARG_ERR;
23}
24
25ErrorCode ResolveHpmI2cMemAddressSize(I2C::MemAddrLength len, uint32_t& addr_size)
26{
27 switch (len)
28 {
29 case I2C::MemAddrLength::BYTE_8:
30 addr_size = 1U;
31 return ErrorCode::OK;
32 case I2C::MemAddrLength::BYTE_16:
33 addr_size = 2U;
34 return ErrorCode::OK;
35 default:
36 addr_size = 0U;
37 return ErrorCode::ARG_ERR;
38 }
39}
40
41void FillHpmI2cMemAddress(uint16_t mem_addr, I2C::MemAddrLength len, uint8_t out[2])
42{
43 if (len == I2C::MemAddrLength::BYTE_16)
44 {
45 out[0] = static_cast<uint8_t>((mem_addr >> 8) & 0xFFU);
46 out[1] = static_cast<uint8_t>(mem_addr & 0xFFU);
47 }
48 else
49 {
50 out[0] = static_cast<uint8_t>(mem_addr & 0xFFU);
51 }
52}
53
54} // namespace
55
56uint16_t HPMI2C::GetMaxSlaveAddress(AddressMode mode)
57{
58 return ResolveHpmI2cMaxSlaveAddress(mode);
59}
60
61ErrorCode HPMI2C::ValidateSlaveAddress(uint16_t slave_addr) const
62{
63 return ValidateHpmI2cSlaveAddress(address_mode_, slave_addr);
64}
65
66ErrorCode HPMI2C::ResolveMemAddressSize(MemAddrLength len, uint32_t& addr_size)
67{
68 return ResolveHpmI2cMemAddressSize(len, addr_size);
69}
70
71void HPMI2C::FillMemAddress(uint16_t mem_addr, MemAddrLength len, uint8_t out[2])
72{
73 FillHpmI2cMemAddress(mem_addr, len, out);
74}
75
77{
78 if (policy.addr_hit_timeout_us == 0U || policy.stop_timeout_us == 0U ||
79 policy.bus_idle_timeout_us == 0U || policy.transfer_timeout_us == 0U)
80 {
81 return ErrorCode::ARG_ERR;
82 }
83
84 if (AsyncTransferActive())
85 {
86 return ErrorCode::BUSY;
87 }
88
89 wait_policy_ = policy;
90 return ErrorCode::OK;
91}
92
93#if LIBXR_HPM_I2C_SUPPORTED
94
95#if __has_include("hpm_interrupt.h")
96#include "hpm_interrupt.h"
97#define LIBXR_HPM_I2C_HAS_INTERRUPT 1
98#else
99#define LIBXR_HPM_I2C_HAS_INTERRUPT 0
100#endif
101
102#if __has_include("hpm_l1c_drv.h")
103#include "hpm_l1c_drv.h"
104#define LIBXR_HPM_I2C_HAS_L1C 1
105#else
106#define LIBXR_HPM_I2C_HAS_L1C 0
107#endif
108
109#if defined(__GNUC__) || defined(__clang__)
115extern "C" void libxr_hpm_i2c_wait_relax_hook(void) __attribute__((weak));
116#define LIBXR_HPM_I2C_HAS_WAIT_RELAX_HOOK 1
117#else
118#define LIBXR_HPM_I2C_HAS_WAIT_RELAX_HOOK 0
119#endif
120
121#include "hpm_i2c_platform.hpp"
122
123namespace
124{
125
126// Core blocking flags and timeout policy shared by polling and async setup paths.
127constexpr uint16_t kI2CFlagRead = I2C_RD;
128constexpr uint16_t kI2CFlagAddr10Bit = I2C_ADDR_10BIT;
129constexpr uint16_t kI2CFlagNoStart = I2C_NO_START;
130constexpr uint16_t kI2CFlagNoAddress = I2C_NO_ADDRESS;
131constexpr uint16_t kI2CFlagNoStop = I2C_NO_STOP;
132constexpr uint16_t kI2CFlagWriteCheckAck = I2C_WRITE_CHECK_ACK;
133
134// DMA manager state and ISR instance slots stay in this TU to avoid build-system
135// churn; platform resource resolution lives in hpm_i2c_platform.hpp.
136static_assert(sizeof(uintptr_t) <= sizeof(uint32_t),
137 "HPM I2C DMA helper assumes a 32-bit address space.");
138
139uint32_t ToHpmI2cDmaAddress(const volatile void* addr)
140{
141 return static_cast<uint32_t>(reinterpret_cast<uintptr_t>(addr));
142}
143
144#if defined(HPM_I2C7)
145constexpr size_t kHpmI2cInstanceCount = 8U;
146#elif defined(HPM_I2C6)
147constexpr size_t kHpmI2cInstanceCount = 7U;
148#elif defined(HPM_I2C5)
149constexpr size_t kHpmI2cInstanceCount = 6U;
150#elif defined(HPM_I2C4)
151constexpr size_t kHpmI2cInstanceCount = 5U;
152#else
153constexpr size_t kHpmI2cInstanceCount = 4U;
154#endif
155HPMI2C* g_hpm_i2c_instance_map[kHpmI2cInstanceCount] = {};
156
157using HPMI2CPlatform::kInvalidDmaSource;
158using HPMI2CPlatform::ResolveI2cDmaSource;
159using HPMI2CPlatform::ResolveI2cIndex;
160using HPMI2CPlatform::ResolveI2cIrq;
161
162#if LIBXR_HPM_I2C_HAS_L1C
163static bool ResolveDCacheRange(const void* addr, uint32_t size, uint32_t& start,
164 uint32_t& aligned_size)
165{
166 if (addr == nullptr || size == 0U)
167 {
168 start = 0U;
169 aligned_size = 0U;
170 return false;
171 }
172
173 const uint64_t line_size = HPM_L1C_CACHELINE_SIZE;
174 const uint64_t address = ToHpmI2cDmaAddress(addr);
175 const uint64_t end = address + static_cast<uint64_t>(size);
176 constexpr uint64_t kAddressSpaceSize = static_cast<uint64_t>(UINT32_MAX) + 1ULL;
177 if (end > kAddressSpaceSize)
178 {
179 start = 0U;
180 aligned_size = 0U;
181 return false;
182 }
183
184 const uint64_t aligned_start = address - (address % line_size);
185 const uint64_t aligned_end = ((end + line_size - 1U) / line_size) * line_size;
186 const uint64_t range_size = aligned_end - aligned_start;
187 if (aligned_end > kAddressSpaceSize || range_size > UINT32_MAX)
188 {
189 start = 0U;
190 aligned_size = 0U;
191 return false;
192 }
193
194 start = static_cast<uint32_t>(aligned_start);
195 aligned_size = static_cast<uint32_t>(range_size);
196 return aligned_size > 0U;
197}
198#endif
199
200static void FlushDCacheIfNeeded(const void* addr, uint32_t size)
201{
202#if LIBXR_HPM_I2C_HAS_L1C
203 if (addr != nullptr && size > 0U && l1c_dc_is_enabled())
204 {
205 uint32_t start = 0U;
206 uint32_t aligned_size = 0U;
207 if (ResolveDCacheRange(addr, size, start, aligned_size))
208 {
209 l1c_dc_flush(start, aligned_size);
210 }
211 }
212#else
213 UNUSED(addr);
214 UNUSED(size);
215#endif
216}
217
218static void InvalidateDCacheIfNeeded(const void* addr, uint32_t size)
219{
220#if LIBXR_HPM_I2C_HAS_L1C
221 if (addr != nullptr && size > 0U && l1c_dc_is_enabled())
222 {
223 uint32_t start = 0U;
224 uint32_t aligned_size = 0U;
225 if (ResolveDCacheRange(addr, size, start, aligned_size))
226 {
227 l1c_dc_invalidate(start, aligned_size);
228 }
229 }
230#else
231 UNUSED(addr);
232 UNUSED(size);
233#endif
234}
235
236void I2cWaitRelax()
237{
238#if LIBXR_HPM_I2C_HAS_WAIT_RELAX_HOOK
239 if (libxr_hpm_i2c_wait_relax_hook != nullptr)
240 {
241 libxr_hpm_i2c_wait_relax_hook();
242 return;
243 }
244#endif
245 __asm volatile("nop");
246}
247
248uint32_t GetI2cWaitTicksPerUs()
249{
250 static uint32_t ticks_per_us = 0U;
251 if (ticks_per_us == 0U)
252 {
253 ticks_per_us = clock_get_core_clock_ticks_per_us();
254 }
255 return ticks_per_us;
256}
257
258uint64_t GetI2cWaitTimeoutTicks(uint64_t timeout_us)
259{
260 const uint64_t ticks_per_us = GetI2cWaitTicksPerUs();
261 if (ticks_per_us != 0U && timeout_us > (UINT64_MAX / ticks_per_us))
262 {
263 return UINT64_MAX;
264 }
265 return ticks_per_us * timeout_us;
266}
267
268uint64_t GetI2cWaitCycle() { return hpm_csr_get_core_cycle(); }
269
270template <typename Predicate>
271bool WaitUntil(const Predicate& predicate, uint64_t timeout_us)
272{
273 const uint64_t start = GetI2cWaitCycle();
274 const uint64_t timeout_ticks = GetI2cWaitTimeoutTicks(timeout_us);
275 while (!predicate())
276 {
277 if ((GetI2cWaitCycle() - start) > timeout_ticks)
278 {
279 return false;
280 }
281 I2cWaitRelax();
282 }
283 return true;
284}
285
286bool WaitForBusIdle(I2C_Type* i2c, uint64_t timeout_us)
287{
288 return WaitUntil([i2c]()
289 { return (i2c_get_status(i2c) & I2C_STATUS_BUSBUSY_MASK) == 0U; },
290 timeout_us);
291}
292
293void IssueStopAndWait(I2C_Type* i2c, const HPMI2C::WaitPolicy& policy)
294{
295 if (i2c == nullptr)
296 {
297 return;
298 }
299
300 i2c_clear_status(i2c, I2C_STATUS_CMPL_MASK);
301 i2c->CTRL = I2C_CTRL_PHASE_STOP_MASK;
302 i2c_master_issue_data_transmission(i2c);
303 (void)WaitUntil(
304 [i2c]()
305 {
306 const uint32_t status = i2c_get_status(i2c);
307 return ((status & I2C_STATUS_CMPL_MASK) != 0U) ||
308 ((status & I2C_STATUS_BUSBUSY_MASK) == 0U);
309 },
310 policy.stop_timeout_us);
311 i2c_clear_status(
312 i2c, I2C_STATUS_CMPL_MASK | I2C_STATUS_ADDRHIT_MASK | I2C_STATUS_BYTETRANS_MASK);
313 i2c_clear_fifo(i2c);
314}
315
316hpm_stat_t DoManualTransferWithFlagsImpl(I2C_Type* i2c, uint16_t slave_addr, RawData data,
317 uint16_t flags, const HPMI2C::WaitPolicy& policy)
318{
319 if (i2c == nullptr || data.addr_ == nullptr || data.size_ == 0U)
320 {
321 return status_invalid_argument;
322 }
323
324 i2c_enable_10bit_address_mode(i2c, (flags & I2C_ADDR_10BIT) != 0U);
325 i2c_clear_status(
326 i2c, I2C_STATUS_CMPL_MASK | I2C_STATUS_ADDRHIT_MASK | I2C_STATUS_BYTETRANS_MASK);
327 i2c_clear_fifo(i2c);
328 i2c_master_set_slave_address(i2c, slave_addr);
329
330 if ((flags & I2C_RD) != 0U)
331 {
332 i2c_set_direction(i2c, I2C_DIR_MASTER_READ);
333 }
334 else
335 {
336 i2c_set_direction(i2c, I2C_DIR_MASTER_WRITE);
337 }
338
339 if ((flags & I2C_NO_START) != 0U)
340 {
341 i2c_master_disable_start_phase(i2c);
342 }
343 else
344 {
345 i2c_master_enable_start_phase(i2c);
346 }
347
348 if ((flags & I2C_NO_ADDRESS) != 0U)
349 {
350 i2c_master_disable_addr_phase(i2c);
351 }
352 else
353 {
354 i2c_master_enable_addr_phase(i2c);
355 }
356
357 if ((flags & I2C_NO_STOP) != 0U)
358 {
359 i2c_master_disable_stop_phase(i2c);
360 }
361 else
362 {
363 i2c_master_enable_stop_phase(i2c);
364 }
365
366 i2c_master_enable_data_phase(i2c);
367 i2c_set_data_count(i2c, static_cast<uint32_t>(data.size_));
368 const uint32_t saved_inten = i2c->INTEN;
369 i2c->INTEN = saved_inten | I2C_EVENT_BYTE_RECEIVED;
370 i2c_master_issue_data_transmission(i2c);
371
372 hpm_stat_t raw_status = status_success;
373 auto* bytes = static_cast<uint8_t*>(data.addr_);
374 uint32_t left = static_cast<uint32_t>(data.size_);
375
376 if ((flags & I2C_NO_ADDRESS) == 0U)
377 {
378 const bool addr_hit = WaitUntil(
379 [i2c]() { return (i2c_get_status(i2c) & I2C_STATUS_ADDRHIT_MASK) != 0U; },
380 policy.addr_hit_timeout_us);
381 if (!addr_hit)
382 {
383 raw_status = status_i2c_no_addr_hit;
384 }
385 else
386 {
387 i2c_clear_status(i2c, I2C_STATUS_ADDRHIT_MASK);
388 }
389 }
390
391 if (raw_status == status_success && (flags & I2C_RD) != 0U)
392 {
393 while (left > 0U)
394 {
395 const bool ready = WaitUntil(
396 [i2c]() { return (i2c_get_status(i2c) & I2C_STATUS_FIFOEMPTY_MASK) == 0U; },
397 policy.transfer_timeout_us);
398 if (!ready)
399 {
400 raw_status = status_timeout;
401 break;
402 }
403
404 *(bytes++) = i2c_read_byte(i2c);
405 left--;
406 if (left == 0U)
407 {
408 i2c_respond_Nack(i2c);
409 }
410 else if ((flags & I2C_NO_READ_ACK) == 0U)
411 {
412 i2c_respond_ack(i2c);
413 }
414 }
415 }
416 else if (raw_status == status_success)
417 {
418 while (left > 0U)
419 {
420 if ((flags & I2C_WRITE_CHECK_ACK) != 0U)
421 {
422 i2c_write_byte(i2c, *(bytes++));
423 left--;
424
425 const bool ready = WaitUntil(
426 [i2c]() { return (i2c_get_status(i2c) & I2C_STATUS_BYTETRANS_MASK) != 0U; },
427 policy.transfer_timeout_us);
428 if (!ready)
429 {
430 raw_status = status_timeout;
431 break;
432 }
433
434 const uint32_t status = i2c_get_status(i2c);
435 i2c_clear_status(i2c, I2C_STATUS_BYTETRANS_MASK);
436 if (!I2C_STATUS_ACK_GET(status))
437 {
438 raw_status = status_i2c_no_ack;
439 break;
440 }
441 }
442 else
443 {
444 const bool ready = WaitUntil(
445 [i2c]() { return (i2c_get_status(i2c) & I2C_STATUS_FIFOFULL_MASK) == 0U; },
446 policy.transfer_timeout_us);
447 if (!ready)
448 {
449 raw_status = status_timeout;
450 break;
451 }
452
453 i2c_write_byte(i2c, *(bytes++));
454 left--;
455 }
456 }
457 }
458
459 if (raw_status == status_success)
460 {
461 const bool complete =
462 WaitUntil([i2c]() { return (i2c_get_status(i2c) & I2C_STATUS_CMPL_MASK) != 0U; },
463 policy.transfer_timeout_us);
464 if (!complete)
465 {
466 raw_status = status_timeout;
467 }
468 else
469 {
470 i2c_clear_status(i2c, I2C_STATUS_CMPL_MASK);
471 if (i2c_get_data_count(i2c) != 0U)
472 {
473 raw_status = status_i2c_transmit_not_completed;
474 }
475 }
476 }
477
478 if (raw_status != status_success)
479 {
480 IssueStopAndWait(i2c, policy);
481 i2c_clear_status(
482 i2c, I2C_STATUS_CMPL_MASK | I2C_STATUS_ADDRHIT_MASK | I2C_STATUS_BYTETRANS_MASK);
483 i2c_master_disable_data_phase(i2c);
484 i2c_master_disable_addr_phase(i2c);
485 i2c_master_disable_start_phase(i2c);
486 i2c_master_disable_stop_phase(i2c);
487 }
488
489 i2c->INTEN = saved_inten;
490 return raw_status;
491}
492
493} // namespace
494
495#if LIBXR_HPM_I2C_HAS_INTERRUPT
496extern "C" void libxr_hpm_i2c_process_interrupt(I2C_Type* ptr)
497{
498 const int32_t index = ResolveI2cIndex(ptr);
499 if (index >= 0 && static_cast<size_t>(index) < kHpmI2cInstanceCount &&
500 g_hpm_i2c_instance_map[index] != nullptr)
501 {
502 g_hpm_i2c_instance_map[index]->HandleAsyncInterrupt(true);
503 }
504}
505
506#if defined(IRQn_I2C0) && defined(HPM_I2C0)
507SDK_DECLARE_EXT_ISR_M(IRQn_I2C0, libxr_hpm_i2c0_isr)
508void libxr_hpm_i2c0_isr(void) { libxr_hpm_i2c_process_interrupt(HPM_I2C0); }
509#endif
510#if defined(IRQn_I2C1) && defined(HPM_I2C1)
511SDK_DECLARE_EXT_ISR_M(IRQn_I2C1, libxr_hpm_i2c1_isr)
512void libxr_hpm_i2c1_isr(void) { libxr_hpm_i2c_process_interrupt(HPM_I2C1); }
513#endif
514#if defined(IRQn_I2C2) && defined(HPM_I2C2)
515SDK_DECLARE_EXT_ISR_M(IRQn_I2C2, libxr_hpm_i2c2_isr)
516void libxr_hpm_i2c2_isr(void) { libxr_hpm_i2c_process_interrupt(HPM_I2C2); }
517#endif
518#if defined(IRQn_I2C3) && defined(HPM_I2C3)
519SDK_DECLARE_EXT_ISR_M(IRQn_I2C3, libxr_hpm_i2c3_isr)
520void libxr_hpm_i2c3_isr(void) { libxr_hpm_i2c_process_interrupt(HPM_I2C3); }
521#endif
522#if defined(IRQn_I2C4) && defined(HPM_I2C4)
523SDK_DECLARE_EXT_ISR_M(IRQn_I2C4, libxr_hpm_i2c4_isr)
524void libxr_hpm_i2c4_isr(void) { libxr_hpm_i2c_process_interrupt(HPM_I2C4); }
525#endif
526#if defined(IRQn_I2C5) && defined(HPM_I2C5)
527SDK_DECLARE_EXT_ISR_M(IRQn_I2C5, libxr_hpm_i2c5_isr)
528void libxr_hpm_i2c5_isr(void) { libxr_hpm_i2c_process_interrupt(HPM_I2C5); }
529#endif
530#if defined(IRQn_I2C6) && defined(HPM_I2C6)
531SDK_DECLARE_EXT_ISR_M(IRQn_I2C6, libxr_hpm_i2c6_isr)
532void libxr_hpm_i2c6_isr(void) { libxr_hpm_i2c_process_interrupt(HPM_I2C6); }
533#endif
534#if defined(IRQn_I2C7) && defined(HPM_I2C7)
535SDK_DECLARE_EXT_ISR_M(IRQn_I2C7, libxr_hpm_i2c7_isr)
536void libxr_hpm_i2c7_isr(void) { libxr_hpm_i2c_process_interrupt(HPM_I2C7); }
537#endif
538#else
539extern "C" void libxr_hpm_i2c_process_interrupt(I2C_Type* ptr) { UNUSED(ptr); }
540#endif
541
542HPMI2C::HPMI2C(I2C_Type* i2c, clock_name_t clock, I2C::Configuration config)
543 : i2c_(i2c), clock_(clock), current_config_(config)
544{
545 ASSERT(i2c_ != nullptr);
546
547 // Shared dma_mgr init must run in thread context, before any async request.
549
550 clock_add_to_group(clock_, 0);
551 source_clock_hz_ = clock_get_frequency(clock_);
552
553 REQUIRE(source_clock_hz_ != 0);
554 const ErrorCode ans = SetConfig(config);
555 REQUIRE(ans == ErrorCode::OK);
556}
557
558ErrorCode HPMI2C::SetAddressMode(AddressMode mode)
559{
560 if (i2c_ == nullptr)
561 {
562 return ErrorCode::PTR_NULL;
563 }
564
565 if (address_mode_ == mode && configured_)
566 {
567 return ErrorCode::OK;
568 }
569
570 if (AsyncTransferActive())
571 {
572 return ErrorCode::BUSY;
573 }
574 DisableAsyncI2cIrq();
575 StopAsyncDma();
576 IssueStopAndWait(i2c_, wait_policy_);
577 (void)WaitForBusIdle(i2c_, wait_policy_.bus_idle_timeout_us);
578
579 const AddressMode previous_mode = address_mode_;
580 address_mode_ = mode;
581 const ErrorCode ans = ApplyConfig(current_config_);
582 (void)WaitForBusIdle(i2c_, wait_policy_.bus_idle_timeout_us);
583 if (ans != ErrorCode::OK)
584 {
585 address_mode_ = previous_mode;
586 if (configured_)
587 {
588 (void)ApplyConfig(current_config_);
589 }
590 }
591 return ans;
592}
593
594ErrorCode HPMI2C::ConvertStatus(hpm_stat_t status)
595{
596 switch (status)
597 {
598 case status_success:
599 return ErrorCode::OK;
600 case status_timeout:
601 return ErrorCode::TIMEOUT;
602 case status_invalid_argument:
603 return ErrorCode::ARG_ERR;
604 case status_i2c_bus_busy:
605 return ErrorCode::BUSY;
606 case status_i2c_not_supported:
608 case status_i2c_no_ack:
609 case status_i2c_no_addr_hit:
611 case status_i2c_invalid_data:
613 case status_i2c_transmit_not_completed:
614 return ErrorCode::FAILED;
615 default:
616 return ErrorCode::FAILED;
617 }
618}
619
620ErrorCode HPMI2C::ResolveMode(uint32_t clock_speed, i2c_mode_t& mode)
621{
622 if (clock_speed == 100000UL)
623 {
624 mode = i2c_mode_normal;
625 }
626 else if (clock_speed == 400000UL)
627 {
628 mode = i2c_mode_fast;
629 }
630 else if (clock_speed == 1000000UL)
631 {
632 mode = i2c_mode_fast_plus;
633 }
634 else if (clock_speed == 0)
635 {
636 return ErrorCode::ARG_ERR;
637 }
638 else
639 {
641 }
642
643 return ErrorCode::OK;
644}
645
646ErrorCode HPMI2C::ConvertDmaStatus(hpm_stat_t status)
647{
648 switch (status)
649 {
650 case status_success:
651 return ErrorCode::OK;
652 case status_invalid_argument:
653 return ErrorCode::ARG_ERR;
654 case status_dma_mgr_no_resource:
655 return ErrorCode::FULL;
656 default:
657 return ErrorCode::FAILED;
658 }
659}
660
661i2c_seq_transfer_opt_t HPMI2C::ConvertSequenceFrame(SequenceFrame frame)
662{
663 switch (frame)
664 {
666 return i2c_frist_frame;
668 return i2c_next_frame;
670 default:
671 return i2c_last_frame;
672 }
673}
674
675uint16_t HPMI2C::BuildTransferFlags(uint16_t flags) const
676{
677 return (address_mode_ == AddressMode::ADDR_10BIT) ? (flags | kI2CFlagAddr10Bit) : flags;
678}
679
680ErrorCode HPMI2C::EnsureClockReady()
681{
682 if (i2c_ == nullptr)
683 {
684 return ErrorCode::PTR_NULL;
685 }
686
687 // Runtime reconfiguration must use the current clock, not the constructor's cache.
688 clock_add_to_group(clock_, 0);
689 source_clock_hz_ = clock_get_frequency(clock_);
690 if (source_clock_hz_ == 0)
691 {
692 return ErrorCode::INIT_ERR;
693 }
694
695 return ErrorCode::OK;
696}
697
698ErrorCode HPMI2C::EnsureControllerReady()
699{
700 if (i2c_ == nullptr)
701 {
702 return ErrorCode::PTR_NULL;
703 }
704
705 if (configured_)
706 {
707 return ErrorCode::OK;
708 }
709
710 return ApplyConfig(current_config_);
711}
712
713ErrorCode HPMI2C::ApplyConfig(const Configuration& config)
714{
715 if (i2c_ == nullptr)
716 {
717 return ErrorCode::PTR_NULL;
718 }
719
720 i2c_mode_t mode = i2c_mode_normal;
721 ErrorCode ans = ResolveMode(config.clock_speed, mode);
722 if (ans != ErrorCode::OK)
723 {
724 return ans;
725 }
726
727 ans = EnsureClockReady();
728 if (ans != ErrorCode::OK)
729 {
730 return ans;
731 }
732
733 i2c_config_t i2c_config{};
734 i2c_config.i2c_mode = mode;
735 i2c_config.is_10bit_addressing = (address_mode_ == AddressMode::ADDR_10BIT);
736
737 const uint32_t previous_setup = i2c_->SETUP;
738 const uint32_t previous_tpm = i2c_->TPM;
739 const uint32_t previous_interrupts = i2c_->INTEN;
740 ans = ConvertStatus(i2c_init_master(i2c_, source_clock_hz_, &i2c_config));
741 if (ans == ErrorCode::OK)
742 {
743 current_config_ = config;
744 configured_ = true;
745 }
746 else if (configured_)
747 {
748 // The SDK resets the controller before validating its timing configuration.
749 // Restore the previous idle configuration without reissuing a transaction.
750 i2c_->TPM = previous_tpm;
751 i2c_->SETUP = previous_setup;
752 i2c_->INTEN = previous_interrupts;
753 }
754
755 return ans;
756}
757
758bool HPMI2C::ShouldRecover(hpm_stat_t status)
759{
760 switch (status)
761 {
762 case status_timeout:
763 case status_i2c_bus_busy:
764 case status_i2c_no_ack:
765 case status_i2c_no_addr_hit:
766 return true;
767 default:
768 return false;
769 }
770}
771
772void HPMI2C::RecoverController()
773{
774 if (i2c_ == nullptr)
775 {
776 return;
777 }
778
779 IssueStopAndWait(i2c_, wait_policy_);
780 (void)WaitForBusIdle(i2c_, wait_policy_.bus_idle_timeout_us);
781 TryRecoverBusLines();
782 i2c_reset(i2c_);
783 if (configured_)
784 {
785 (void)ApplyConfig(current_config_);
786 }
787 (void)WaitForBusIdle(i2c_, wait_policy_.bus_idle_timeout_us);
788}
789
790void HPMI2C::TryRecoverBusLines()
791{
792 if (i2c_ == nullptr)
793 {
794 return;
795 }
796
797#if defined(HPM_IP_FEATURE_I2C_SUPPORT_RESET) && (HPM_IP_FEATURE_I2C_SUPPORT_RESET == 1)
798 if (i2c_get_line_scl_status(i2c_) && !i2c_get_line_sda_status(i2c_))
799 {
800 i2c_gen_reset_signal(i2c_, 9);
801 }
802#endif
803}
804
805uint32_t HPMI2C::ToSystemAddress(const void* addr)
806{
807 return core_local_mem_to_sys_address(HPM_CORE0, ToHpmI2cDmaAddress(addr));
808}
809
810ErrorCode HPMI2C::PrepareAsyncTransfer(uint16_t slave_addr, uint16_t flags, uint32_t size,
811 bool clear_fifo, bool require_bus_idle)
812{
813 if (i2c_ == nullptr)
814 {
815 return ErrorCode::PTR_NULL;
816 }
817
818 if (require_bus_idle)
819 {
820 if (!WaitForBusIdle(i2c_, wait_policy_.transfer_timeout_us))
821 {
822 return ErrorCode::BUSY;
823 }
824 }
825
826 i2c_clear_status(i2c_, I2C_STATUS_CMPL_MASK);
827 if (clear_fifo)
828 {
829 i2c_clear_fifo(i2c_);
830 }
831
832 const uint16_t final_flags = BuildTransferFlags(flags);
833 i2c_master_set_slave_address(i2c_, slave_addr);
834 if ((final_flags & I2C_RD) != 0U)
835 {
836 i2c_set_direction(i2c_, I2C_DIR_MASTER_READ);
837 }
838 else
839 {
840 i2c_set_direction(i2c_, I2C_DIR_MASTER_WRITE);
841 }
842
843 if ((final_flags & I2C_NO_START) != 0U)
844 {
845 i2c_master_disable_start_phase(i2c_);
846 }
847 else
848 {
849 i2c_master_enable_start_phase(i2c_);
850 }
851
852 if ((final_flags & I2C_NO_ADDRESS) != 0U)
853 {
854 i2c_master_disable_addr_phase(i2c_);
855 }
856 else
857 {
858 i2c_master_enable_addr_phase(i2c_);
859 }
860
861 if ((final_flags & I2C_NO_STOP) != 0U)
862 {
863 i2c_master_disable_stop_phase(i2c_);
864 }
865 else
866 {
867 i2c_master_enable_stop_phase(i2c_);
868 }
869
870 if (size > 0U)
871 {
872 i2c_master_enable_data_phase(i2c_);
873 i2c_set_data_count(i2c_, size);
874 }
875 else
876 {
877 i2c_master_disable_data_phase(i2c_);
878 }
879
880 i2c_dma_disable(i2c_);
881 i2c_master_issue_data_transmission(i2c_);
882
883 if ((final_flags & I2C_NO_ADDRESS) == 0U)
884 {
885 const bool addr_hit = WaitUntil(
886 [this]() { return (i2c_get_status(i2c_) & I2C_STATUS_ADDRHIT_MASK) != 0U; },
887 wait_policy_.addr_hit_timeout_us);
888 if (!addr_hit)
889 {
890 StopAndReleaseAsyncBus();
892 }
893 i2c_clear_status(i2c_, I2C_STATUS_ADDRHIT_MASK);
894 }
895
896 return ErrorCode::OK;
897}
898
899ErrorCode HPMI2C::StartAsyncReadDma(void* dst, uint32_t size)
900{
901 if (i2c_ == nullptr || dst == nullptr || size == 0U)
902 {
903 return ErrorCode::ARG_ERR;
904 }
905 ErrorCode ans = EnsureAsyncDmaReady();
906 if (ans != ErrorCode::OK)
907 {
908 return ans;
909 }
910
911 FlushDCacheIfNeeded(dst, size);
912
913 hpm_stat_t status =
914 dma_mgr_set_chn_dst_addr(&async_dma_resource_, ToSystemAddress(dst));
915 if (status != status_success)
916 {
917 return ConvertDmaStatus(status);
918 }
919 status =
920 dma_mgr_set_chn_dst_work_mode(&async_dma_resource_, DMA_MGR_HANDSHAKE_MODE_NORMAL);
921 if (status != status_success)
922 {
923 return ConvertDmaStatus(status);
924 }
925 status = dma_mgr_set_chn_dst_addr_ctrl(&async_dma_resource_,
926 DMA_MGR_ADDRESS_CONTROL_INCREMENT);
927 if (status != status_success)
928 {
929 return ConvertDmaStatus(status);
930 }
931 status =
932 dma_mgr_set_chn_src_addr(&async_dma_resource_, ToHpmI2cDmaAddress(&i2c_->DATA));
933 if (status != status_success)
934 {
935 return ConvertDmaStatus(status);
936 }
937 status = dma_mgr_set_chn_src_work_mode(&async_dma_resource_,
938 DMA_MGR_HANDSHAKE_MODE_HANDSHAKE);
939 if (status != status_success)
940 {
941 return ConvertDmaStatus(status);
942 }
943 status =
944 dma_mgr_set_chn_src_addr_ctrl(&async_dma_resource_, DMA_MGR_ADDRESS_CONTROL_FIXED);
945 if (status != status_success)
946 {
947 return ConvertDmaStatus(status);
948 }
949 status = dma_mgr_set_chn_src_width(&async_dma_resource_, DMA_MGR_TRANSFER_WIDTH_BYTE);
950 if (status != status_success)
951 {
952 return ConvertDmaStatus(status);
953 }
954 status = dma_mgr_set_chn_dst_width(&async_dma_resource_, DMA_MGR_TRANSFER_WIDTH_BYTE);
955 if (status != status_success)
956 {
957 return ConvertDmaStatus(status);
958 }
959 status = dma_mgr_set_chn_transize(&async_dma_resource_, size);
960 if (status != status_success)
961 {
962 return ConvertDmaStatus(status);
963 }
964
965 i2c_dma_enable(i2c_);
966 dma_clear_transfer_status(async_dma_resource_.base, async_dma_resource_.channel);
967 status = dma_mgr_enable_channel(&async_dma_resource_);
968 if (status != status_success)
969 {
970 i2c_dma_disable(i2c_);
971 return ConvertDmaStatus(status);
972 }
973 return ErrorCode::OK;
974}
975
976ErrorCode HPMI2C::StartAsyncWriteDma(const void* src, uint32_t size)
977{
978 if (i2c_ == nullptr || src == nullptr || size == 0U)
979 {
980 return ErrorCode::ARG_ERR;
981 }
982 ErrorCode ans = EnsureAsyncDmaReady();
983 if (ans != ErrorCode::OK)
984 {
985 return ans;
986 }
987
988 FlushDCacheIfNeeded(src, size);
989
990 hpm_stat_t status =
991 dma_mgr_set_chn_src_addr(&async_dma_resource_, ToSystemAddress(src));
992 if (status != status_success)
993 {
994 return ConvertDmaStatus(status);
995 }
996 status =
997 dma_mgr_set_chn_src_work_mode(&async_dma_resource_, DMA_MGR_HANDSHAKE_MODE_NORMAL);
998 if (status != status_success)
999 {
1000 return ConvertDmaStatus(status);
1001 }
1002 status = dma_mgr_set_chn_src_addr_ctrl(&async_dma_resource_,
1003 DMA_MGR_ADDRESS_CONTROL_INCREMENT);
1004 if (status != status_success)
1005 {
1006 return ConvertDmaStatus(status);
1007 }
1008 status =
1009 dma_mgr_set_chn_dst_addr(&async_dma_resource_, ToHpmI2cDmaAddress(&i2c_->DATA));
1010 if (status != status_success)
1011 {
1012 return ConvertDmaStatus(status);
1013 }
1014 status = dma_mgr_set_chn_dst_work_mode(&async_dma_resource_,
1015 DMA_MGR_HANDSHAKE_MODE_HANDSHAKE);
1016 if (status != status_success)
1017 {
1018 return ConvertDmaStatus(status);
1019 }
1020 status =
1021 dma_mgr_set_chn_dst_addr_ctrl(&async_dma_resource_, DMA_MGR_ADDRESS_CONTROL_FIXED);
1022 if (status != status_success)
1023 {
1024 return ConvertDmaStatus(status);
1025 }
1026 status = dma_mgr_set_chn_src_width(&async_dma_resource_, DMA_MGR_TRANSFER_WIDTH_BYTE);
1027 if (status != status_success)
1028 {
1029 return ConvertDmaStatus(status);
1030 }
1031 status = dma_mgr_set_chn_dst_width(&async_dma_resource_, DMA_MGR_TRANSFER_WIDTH_BYTE);
1032 if (status != status_success)
1033 {
1034 return ConvertDmaStatus(status);
1035 }
1036 status = dma_mgr_set_chn_transize(&async_dma_resource_, size);
1037 if (status != status_success)
1038 {
1039 return ConvertDmaStatus(status);
1040 }
1041
1042 i2c_dma_enable(i2c_);
1043 dma_clear_transfer_status(async_dma_resource_.base, async_dma_resource_.channel);
1044 status = dma_mgr_enable_channel(&async_dma_resource_);
1045 if (status != status_success)
1046 {
1047 i2c_dma_disable(i2c_);
1048 return ConvertDmaStatus(status);
1049 }
1050 return ErrorCode::OK;
1051}
1052
1053void HPMI2C::StopAsyncDma()
1054{
1055 if (async_dma_ready_)
1056 {
1057 (void)dma_mgr_disable_channel(&async_dma_resource_);
1058 }
1059 if (i2c_ != nullptr)
1060 {
1061 i2c_dma_disable(i2c_);
1062 }
1063}
1064
1065void HPMI2C::StopAndReleaseAsyncBus()
1066{
1067 IssueStopAndWait(i2c_, wait_policy_);
1068 ReleaseAsyncBus();
1069}
1070
1071void HPMI2C::AsyncCompletionStateMachine::Reset(AsyncTransferContext& ctx)
1072{
1073 ctx.final_status.store(status_success, std::memory_order_release);
1074 ctx.should_recover.store(false, std::memory_order_release);
1075 ctx.dma_done.store(false, std::memory_order_release);
1076 ctx.cmpl_done.store(false, std::memory_order_release);
1077}
1078
1079void HPMI2C::AsyncCompletionStateMachine::MarkDmaDone(AsyncTransferContext& ctx)
1080{
1081 ctx.dma_done.store(true, std::memory_order_release);
1082}
1083
1084void HPMI2C::AsyncCompletionStateMachine::MarkI2cDone(AsyncTransferContext& ctx,
1085 hpm_stat_t status, bool recover)
1086{
1087 ctx.cmpl_done.store(true, std::memory_order_release);
1088 ctx.final_status.store(status, std::memory_order_release);
1089 ctx.should_recover.store(recover, std::memory_order_release);
1090}
1091
1092void HPMI2C::AsyncCompletionStateMachine::MarkFailure(AsyncTransferContext& ctx,
1093 hpm_stat_t status, bool recover)
1094{
1095 ctx.final_status.store(status, std::memory_order_release);
1096 ctx.should_recover.store(recover, std::memory_order_release);
1097}
1098
1099void HPMI2C::AsyncCompletionStateMachine::SetFinalStatus(AsyncTransferContext& ctx,
1100 hpm_stat_t status)
1101{
1102 ctx.final_status.store(status, std::memory_order_release);
1103}
1104
1105bool HPMI2C::AsyncCompletionStateMachine::DmaDone(const AsyncTransferContext& ctx)
1106{
1107 return ctx.dma_done.load(std::memory_order_acquire);
1108}
1109
1110bool HPMI2C::AsyncCompletionStateMachine::Ready(const AsyncTransferContext& ctx)
1111{
1112 return DmaDone(ctx) && ctx.cmpl_done.load(std::memory_order_acquire);
1113}
1114
1115hpm_stat_t HPMI2C::AsyncCompletionStateMachine::FinalStatus(
1116 const AsyncTransferContext& ctx)
1117{
1118 return ctx.final_status.load(std::memory_order_acquire);
1119}
1120
1121bool HPMI2C::AsyncCompletionStateMachine::ShouldRecover(const AsyncTransferContext& ctx)
1122{
1123 return ctx.should_recover.load(std::memory_order_acquire);
1124}
1125
1126void HPMI2C::ClearAsyncContext()
1127{
1128 async_ctx_.kind = AsyncTransferKind::NONE;
1129 async_ctx_.slave_addr = 0U;
1130 async_ctx_.mem_addr_size = MemAddrLength::BYTE_8;
1131 async_ctx_.mem_addr = 0U;
1132 async_ctx_.mem_addr_size_in_byte = 0U;
1133 async_ctx_.mem_addr_bytes[0] = 0U;
1134 async_ctx_.mem_addr_bytes[1] = 0U;
1135 async_ctx_.flags = 0U;
1136 async_ctx_.read_data = {nullptr, 0};
1137 async_ctx_.write_data = {nullptr, 0};
1138 async_ctx_.read_op = {};
1139 async_ctx_.write_op = {};
1140 AsyncCompletionStateMachine::Reset(async_ctx_);
1141}
1142
1143void HPMI2C::ResetAsyncState()
1144{
1145 ClearAsyncContext();
1146 async_busy_.store(0U, std::memory_order_release);
1147 async_completion_claim_.store(0U, std::memory_order_release);
1148}
1149
1150void HPMI2C::AbortAsyncStart(bool stop_dma, bool disable_irq, bool recover_controller)
1151{
1152 if (stop_dma)
1153 {
1154 StopAsyncDma();
1155 }
1156 if (disable_irq)
1157 {
1158 DisableAsyncI2cIrq();
1159 }
1160
1161 if (recover_controller)
1162 {
1163 RecoverController();
1164 }
1165 else
1166 {
1167 ReleaseAsyncBus();
1168 }
1169
1170 ResetAsyncState();
1171}
1172
1173void HPMI2C::CompleteAsyncTransfer(bool in_isr, ErrorCode ans)
1174{
1175 if (!TryClaimAsyncCompletion())
1176 {
1177 return;
1178 }
1179 DisableAsyncI2cIrq();
1180 StopAsyncDma();
1181 ReleaseAsyncBus();
1182
1183 const bool should_recover = AsyncCompletionStateMachine::ShouldRecover(async_ctx_);
1184 if (ans != ErrorCode::OK && should_recover)
1185 {
1186 RecoverController();
1187 }
1188
1189 const AsyncTransferKind kind = async_ctx_.kind;
1190 ReadOperation read_op = async_ctx_.read_op;
1191 WriteOperation write_op = async_ctx_.write_op;
1192 async_ctx_.kind = AsyncTransferKind::NONE;
1193 ResetAsyncState();
1194
1195 if (kind == AsyncTransferKind::WRITE)
1196 {
1197 CompleteAsyncOperation(write_op, in_isr, ans);
1198 }
1199 else
1200 {
1201 CompleteAsyncOperation(read_op, in_isr, ans);
1202 }
1203}
1204
1205ErrorCode HPMI2C::StartWriteAsync(uint16_t slave_addr, ConstRawData write_data,
1206 WriteOperation& op)
1207{
1208 if (AsyncTransferActive())
1209 {
1210 return ErrorCode::BUSY;
1211 }
1212
1213 ErrorCode ans = EnsureControllerReady();
1214 if (ans != ErrorCode::OK)
1215 {
1216 return ans;
1217 }
1218
1219 async_busy_.store(1U, std::memory_order_release);
1220 ClearAsyncContext();
1221 async_ctx_.kind = AsyncTransferKind::WRITE;
1222 async_ctx_.slave_addr = slave_addr;
1223 async_ctx_.write_data = write_data;
1224 async_ctx_.write_op = op;
1225 async_ctx_.flags = BuildTransferFlags(kI2CFlagWriteCheckAck);
1226 async_completion_claim_.store(0U, std::memory_order_release);
1227
1228 op.MarkAsRunning();
1229 StartAsyncBlockWaitIfNeeded(op);
1230
1231 ans = EnableAsyncI2cIrq();
1232 if (ans != ErrorCode::OK)
1233 {
1234 AsyncCompletionStateMachine::MarkFailure(async_ctx_, status_fail, true);
1235 AbortAsyncStart(false, false, false);
1236 CancelAsyncBlockWaitIfNeeded(op);
1238 }
1239
1240 i2c_clear_fifo(i2c_);
1241 ans = StartAsyncWriteDma(write_data.addr_, static_cast<uint32_t>(write_data.size_));
1242 if (ans != ErrorCode::OK)
1243 {
1244 AsyncCompletionStateMachine::MarkFailure(async_ctx_, status_fail, true);
1245 AbortAsyncStart(false, true, false);
1246 CancelAsyncBlockWaitIfNeeded(op);
1247 return ans;
1248 }
1249
1250 hpm_stat_t start_status = i2c_master_start_dma_write(
1251 i2c_, slave_addr, static_cast<uint32_t>(write_data.size_));
1252 ans = ConvertStatus(start_status);
1253 if (ans != ErrorCode::OK)
1254 {
1255 AsyncCompletionStateMachine::MarkFailure(async_ctx_, start_status,
1256 ShouldRecover(start_status));
1257 AbortAsyncStart(true, true, ShouldRecover(start_status));
1258 CancelAsyncBlockWaitIfNeeded(op);
1259 return ans;
1260 }
1261
1262 if (op.type == WriteOperation::OperationType::BLOCK)
1263 {
1264 return WaitForAsyncBlockResult(op.data.sem_info.timeout);
1265 }
1266 return ErrorCode::OK;
1267}
1268
1269ErrorCode HPMI2C::StartReadAsync(uint16_t slave_addr, RawData read_data,
1270 ReadOperation& op)
1271{
1272 if (AsyncTransferActive())
1273 {
1274 return ErrorCode::BUSY;
1275 }
1276
1277 ErrorCode ans = EnsureControllerReady();
1278 if (ans != ErrorCode::OK)
1279 {
1280 return ans;
1281 }
1282
1283 async_busy_.store(1U, std::memory_order_release);
1284 ClearAsyncContext();
1285 async_ctx_.kind = AsyncTransferKind::READ;
1286 async_ctx_.slave_addr = slave_addr;
1287 async_ctx_.read_data = read_data;
1288 async_ctx_.read_op = op;
1289 async_ctx_.flags = kI2CFlagRead;
1290 async_completion_claim_.store(0U, std::memory_order_release);
1291
1292 op.MarkAsRunning();
1293 StartAsyncBlockWaitIfNeeded(op);
1294
1295 ans = EnableAsyncI2cIrq();
1296 if (ans != ErrorCode::OK)
1297 {
1298 AsyncCompletionStateMachine::MarkFailure(async_ctx_, status_fail, true);
1299 AbortAsyncStart(false, false, false);
1300 CancelAsyncBlockWaitIfNeeded(op);
1302 }
1303
1304 i2c_clear_fifo(i2c_);
1305 ans = StartAsyncReadDma(read_data.addr_, static_cast<uint32_t>(read_data.size_));
1306 if (ans != ErrorCode::OK)
1307 {
1308 AsyncCompletionStateMachine::MarkFailure(async_ctx_, status_fail, true);
1309 AbortAsyncStart(false, true, false);
1310 CancelAsyncBlockWaitIfNeeded(op);
1311 return ans;
1312 }
1313
1314 hpm_stat_t start_status =
1315 i2c_master_start_dma_read(i2c_, slave_addr, static_cast<uint32_t>(read_data.size_));
1316 ans = ConvertStatus(start_status);
1317 if (ans != ErrorCode::OK)
1318 {
1319 AsyncCompletionStateMachine::MarkFailure(async_ctx_, start_status,
1320 ShouldRecover(start_status));
1321 AbortAsyncStart(true, true, ShouldRecover(start_status));
1322 CancelAsyncBlockWaitIfNeeded(op);
1323 return ans;
1324 }
1325
1326 if (op.type == ReadOperation::OperationType::BLOCK)
1327 {
1328 return WaitForAsyncBlockResult(op.data.sem_info.timeout);
1329 }
1330 return ErrorCode::OK;
1331}
1332
1333ErrorCode HPMI2C::StartMemReadAsync(uint16_t slave_addr, uint16_t mem_addr,
1334 RawData read_data, ReadOperation& op,
1335 MemAddrLength mem_addr_size)
1336{
1337 if (AsyncTransferActive())
1338 {
1339 return ErrorCode::BUSY;
1340 }
1341
1342 uint32_t addr_size = 0U;
1343 ErrorCode ans = ResolveMemAddressSize(mem_addr_size, addr_size);
1344 if (ans != ErrorCode::OK)
1345 {
1346 return ans;
1347 }
1348 if (addr_size > I2C_SOC_TRANSFER_COUNT_MAX)
1349 {
1350 return ErrorCode::SIZE_ERR;
1351 }
1352
1353 ans = EnsureControllerReady();
1354 if (ans != ErrorCode::OK)
1355 {
1356 return ans;
1357 }
1358
1359 async_busy_.store(1U, std::memory_order_release);
1360 ClearAsyncContext();
1361 async_ctx_.kind = AsyncTransferKind::MEM_READ;
1362 async_ctx_.slave_addr = slave_addr;
1363 async_ctx_.mem_addr = mem_addr;
1364 async_ctx_.mem_addr_size = mem_addr_size;
1365 async_ctx_.mem_addr_size_in_byte = addr_size;
1366 FillMemAddress(mem_addr, mem_addr_size, async_ctx_.mem_addr_bytes);
1367 async_ctx_.read_data = read_data;
1368 async_ctx_.read_op = op;
1369 async_ctx_.flags = kI2CFlagRead;
1370 async_completion_claim_.store(0U, std::memory_order_release);
1371
1372 op.MarkAsRunning();
1373 StartAsyncBlockWaitIfNeeded(op);
1374
1375 ans = PrepareAsyncTransfer(slave_addr, kI2CFlagNoStop, async_ctx_.mem_addr_size_in_byte,
1376 true, true);
1377 if (ans != ErrorCode::OK)
1378 {
1379 ResetAsyncState();
1380 CancelAsyncBlockWaitIfNeeded(op);
1381 return ans;
1382 }
1383
1384 for (uint32_t i = 0U; i < async_ctx_.mem_addr_size_in_byte; ++i)
1385 {
1386 i2c_write_byte(i2c_, async_ctx_.mem_addr_bytes[i]);
1387 }
1388
1389 const bool mem_addr_complete =
1390 WaitUntil([this]() { return (i2c_get_status(i2c_) & I2C_STATUS_CMPL_MASK) != 0U; },
1391 wait_policy_.transfer_timeout_us);
1392 if (!mem_addr_complete)
1393 {
1394 AsyncCompletionStateMachine::MarkFailure(async_ctx_, status_timeout, true);
1395 StopAndReleaseAsyncBus();
1396 ResetAsyncState();
1397 CancelAsyncBlockWaitIfNeeded(op);
1398 return ErrorCode::TIMEOUT;
1399 }
1400 i2c_clear_status(i2c_, I2C_STATUS_CMPL_MASK);
1401 i2c_clear_fifo(i2c_);
1402
1403 const uint16_t final_flags = BuildTransferFlags(kI2CFlagRead);
1404 i2c_master_set_slave_address(i2c_, slave_addr);
1405 i2c_set_direction(i2c_, I2C_DIR_MASTER_READ);
1406 i2c_master_enable_start_phase(i2c_);
1407 i2c_master_enable_addr_phase(i2c_);
1408 i2c_master_enable_stop_phase(i2c_);
1409 i2c_master_enable_data_phase(i2c_);
1410 i2c_set_data_count(i2c_, static_cast<uint32_t>(read_data.size_));
1411 i2c_dma_disable(i2c_);
1412 if ((final_flags & kI2CFlagAddr10Bit) != 0U)
1413 {
1414 i2c_enable_10bit_address_mode(i2c_, true);
1415 }
1416
1417 ans = EnableAsyncI2cIrq();
1418 if (ans != ErrorCode::OK)
1419 {
1420 AsyncCompletionStateMachine::MarkFailure(async_ctx_, status_fail, true);
1421 StopAndReleaseAsyncBus();
1422 ResetAsyncState();
1423 CancelAsyncBlockWaitIfNeeded(op);
1425 }
1426
1427 ans = StartAsyncReadDma(read_data.addr_, static_cast<uint32_t>(read_data.size_));
1428 if (ans != ErrorCode::OK)
1429 {
1430 AsyncCompletionStateMachine::MarkFailure(async_ctx_, status_fail, true);
1431 DisableAsyncI2cIrq();
1432 StopAndReleaseAsyncBus();
1433 ResetAsyncState();
1434 CancelAsyncBlockWaitIfNeeded(op);
1435 return ans;
1436 }
1437
1438 i2c_master_issue_data_transmission(i2c_);
1439 const bool addr_hit = WaitUntil(
1440 [this]() { return (i2c_get_status(i2c_) & I2C_STATUS_ADDRHIT_MASK) != 0U; },
1441 wait_policy_.addr_hit_timeout_us);
1442 if (!addr_hit)
1443 {
1444 AsyncCompletionStateMachine::MarkFailure(async_ctx_, status_i2c_no_addr_hit, true);
1445 AbortAsyncStart(true, true, true);
1446 CancelAsyncBlockWaitIfNeeded(op);
1448 }
1449 i2c_clear_status(i2c_, I2C_STATUS_ADDRHIT_MASK);
1450
1451 if (op.type == ReadOperation::OperationType::BLOCK)
1452 {
1453 return WaitForAsyncBlockResult(op.data.sem_info.timeout);
1454 }
1455 return ErrorCode::OK;
1456}
1457
1458ErrorCode HPMI2C::EnsureAsyncDmaReady()
1459{
1460 if (async_dma_ready_)
1461 {
1462 return ErrorCode::OK;
1463 }
1464
1465 if (i2c_ == nullptr)
1466 {
1467 return ErrorCode::PTR_NULL;
1468 }
1469
1470 async_dma_source_ = ResolveI2cDmaSource(i2c_);
1471 if (async_dma_source_ == kInvalidDmaSource)
1472 {
1474 }
1475
1476 // dma_mgr was initialized once by the constructor.
1477 hpm_stat_t status = dma_mgr_request_resource(&async_dma_resource_);
1478 if (status != status_success)
1479 {
1480 return ConvertDmaStatus(status);
1481 }
1482
1483 dma_mgr_chn_conf_t cfg{};
1484 dma_mgr_get_default_chn_config(&cfg);
1485 cfg.src_width = DMA_MGR_TRANSFER_WIDTH_BYTE;
1486 cfg.dst_width = DMA_MGR_TRANSFER_WIDTH_BYTE;
1487 cfg.en_dmamux = true;
1488 cfg.dmamux_src = async_dma_source_;
1489 cfg.interrupt_mask = DMA_MGR_INTERRUPT_MASK_ALL;
1490 status = dma_mgr_setup_channel(&async_dma_resource_, &cfg);
1491 if (status != status_success)
1492 {
1493 (void)dma_mgr_release_resource(&async_dma_resource_);
1494 async_dma_resource_ = {nullptr, 0U, -1};
1495 return ConvertDmaStatus(status);
1496 }
1497
1498 status = dma_mgr_install_chn_tc_callback(&async_dma_resource_, &HPMI2C::OnDmaTcCallback,
1499 this);
1500 if (status != status_success)
1501 {
1502 (void)dma_mgr_release_resource(&async_dma_resource_);
1503 async_dma_resource_ = {nullptr, 0U, -1};
1504 return ConvertDmaStatus(status);
1505 }
1506 status = dma_mgr_install_chn_error_callback(&async_dma_resource_,
1507 &HPMI2C::OnDmaErrorCallback, this);
1508 if (status != status_success)
1509 {
1510 (void)dma_mgr_release_resource(&async_dma_resource_);
1511 async_dma_resource_ = {nullptr, 0U, -1};
1512 return ConvertDmaStatus(status);
1513 }
1514 status = dma_mgr_install_chn_abort_callback(&async_dma_resource_,
1515 &HPMI2C::OnDmaAbortCallback, this);
1516 if (status != status_success)
1517 {
1518 (void)dma_mgr_release_resource(&async_dma_resource_);
1519 async_dma_resource_ = {nullptr, 0U, -1};
1520 return ConvertDmaStatus(status);
1521 }
1522 status = dma_mgr_enable_chn_irq(&async_dma_resource_, DMA_MGR_INTERRUPT_MASK_TC |
1523 DMA_MGR_INTERRUPT_MASK_ERROR |
1524 DMA_MGR_INTERRUPT_MASK_ABORT);
1525 if (status != status_success)
1526 {
1527 (void)dma_mgr_release_resource(&async_dma_resource_);
1528 async_dma_resource_ = {nullptr, 0U, -1};
1529 return ConvertDmaStatus(status);
1530 }
1531 status = dma_mgr_enable_dma_irq_with_priority(&async_dma_resource_, 1U);
1532 if (status != status_success)
1533 {
1534 (void)dma_mgr_release_resource(&async_dma_resource_);
1535 async_dma_resource_ = {nullptr, 0U, -1};
1536 return ConvertDmaStatus(status);
1537 }
1538
1539 async_dma_ready_ = true;
1540 return ErrorCode::OK;
1541}
1542
1543ErrorCode HPMI2C::WaitForAsyncBlockResult(uint32_t timeout)
1544{
1545 const ErrorCode ans = block_wait_.Wait(timeout);
1546 if (ans == ErrorCode::TIMEOUT && AsyncTransferActive())
1547 {
1548 AsyncCompletionStateMachine::MarkFailure(async_ctx_, status_timeout, true);
1550 }
1551 return ans;
1552}
1553
1554void HPMI2C::ReleaseAsyncBus()
1555{
1556 if (i2c_ == nullptr)
1557 {
1558 return;
1559 }
1560
1561 i2c_clear_status(i2c_, I2C_STATUS_CMPL_MASK | I2C_STATUS_ADDRHIT_MASK);
1562 i2c_master_disable_data_phase(i2c_);
1563 i2c_master_disable_addr_phase(i2c_);
1564 i2c_master_disable_start_phase(i2c_);
1565 i2c_master_disable_stop_phase(i2c_);
1566 i2c_master_issue_data_transmission(i2c_);
1567}
1568
1569ErrorCode HPMI2C::EnableAsyncI2cIrq()
1570{
1571#if !LIBXR_HPM_I2C_HAS_INTERRUPT
1573#else
1574 const int32_t irq = ResolveI2cIrq(i2c_);
1575 const int32_t index = ResolveI2cIndex(i2c_);
1576 if (irq < 0 || index < 0 || static_cast<size_t>(index) >= kHpmI2cInstanceCount)
1577 {
1579 }
1580 if (g_hpm_i2c_instance_map[index] != nullptr && g_hpm_i2c_instance_map[index] != this)
1581 {
1583 }
1584
1585 g_hpm_i2c_instance_map[index] = this;
1586 i2c_clear_status(
1587 i2c_, I2C_STATUS_CMPL_MASK | I2C_STATUS_ADDRHIT_MASK | I2C_STATUS_ARBLOSE_MASK);
1588 i2c_enable_irq(i2c_, I2C_EVENT_TRANSACTION_COMPLETE | I2C_EVENT_LOSS_ARBITRATION);
1589 intc_m_enable_irq_with_priority(static_cast<uint32_t>(irq), 1U);
1590 return ErrorCode::OK;
1591#endif
1592}
1593
1594void HPMI2C::DisableAsyncI2cIrq()
1595{
1596#if LIBXR_HPM_I2C_HAS_INTERRUPT
1597 if (i2c_ != nullptr)
1598 {
1599 i2c_disable_irq(i2c_, I2C_EVENT_TRANSACTION_COMPLETE | I2C_EVENT_LOSS_ARBITRATION);
1600 const int32_t irq = ResolveI2cIrq(i2c_);
1601 if (irq >= 0)
1602 {
1603 intc_m_disable_irq(static_cast<uint32_t>(irq));
1604 }
1605 }
1606 const int32_t index = ResolveI2cIndex(i2c_);
1607 if (index >= 0 && static_cast<size_t>(index) < kHpmI2cInstanceCount &&
1608 g_hpm_i2c_instance_map[index] == this)
1609 {
1610 g_hpm_i2c_instance_map[index] = nullptr;
1611 }
1612#endif
1613}
1614
1615void HPMI2C::HandleAsyncInterrupt(bool in_isr)
1616{
1617 if (!AsyncTransferActive() || i2c_ == nullptr)
1618 {
1619 return;
1620 }
1621
1622 const uint32_t status = i2c_get_status(i2c_);
1623 if ((status & I2C_STATUS_ARBLOSE_MASK) != 0U)
1624 {
1625 i2c_clear_status(i2c_, I2C_STATUS_ARBLOSE_MASK);
1626 AsyncCompletionStateMachine::MarkI2cDone(async_ctx_, status_timeout, true);
1628 return;
1629 }
1630
1631 if ((status & I2C_STATUS_CMPL_MASK) != 0U)
1632 {
1633 i2c_clear_status(i2c_, I2C_STATUS_CMPL_MASK);
1634 if (async_ctx_.kind == AsyncTransferKind::WRITE &&
1635 (async_ctx_.flags & kI2CFlagWriteCheckAck) != 0U && !I2C_STATUS_ACK_GET(status))
1636 {
1637 AsyncCompletionStateMachine::MarkI2cDone(async_ctx_, status_i2c_no_ack, true);
1638 }
1639 else
1640 {
1641 AsyncCompletionStateMachine::MarkI2cDone(async_ctx_, status_success, false);
1642 }
1643 }
1644
1645 MaybeCompleteAsyncTransfer(in_isr);
1646}
1647
1648void HPMI2C::MaybeCompleteAsyncTransfer(bool in_isr)
1649{
1650 if (!AsyncTransferActive() || !AsyncCompletionStateMachine::Ready(async_ctx_))
1651 {
1652 return;
1653 }
1654
1655 if (async_ctx_.kind == AsyncTransferKind::READ ||
1656 async_ctx_.kind == AsyncTransferKind::MEM_READ)
1657 {
1658 InvalidateDCacheIfNeeded(async_ctx_.read_data.addr_,
1659 static_cast<uint32_t>(async_ctx_.read_data.size_));
1660 }
1661 hpm_stat_t final_status = AsyncCompletionStateMachine::FinalStatus(async_ctx_);
1662 if (final_status == status_success && i2c_get_data_count(i2c_) != 0U)
1663 {
1664 final_status = status_i2c_transmit_not_completed;
1665 AsyncCompletionStateMachine::SetFinalStatus(async_ctx_, final_status);
1666 }
1667 CompleteAsyncTransfer(in_isr, ConvertStatus(final_status));
1668}
1669
1670bool HPMI2C::TryClaimAsyncCompletion()
1671{
1672 uint32_t expected = 0U;
1673 return async_completion_claim_.compare_exchange_strong(
1674 expected, 1U, std::memory_order_acq_rel, std::memory_order_acquire);
1675}
1676
1677void HPMI2C::OnDmaTcCallback(DMA_Type* base, uint32_t channel, void* cb_data_ptr)
1678{
1679 UNUSED(base);
1680 UNUSED(channel);
1681 auto* self = static_cast<HPMI2C*>(cb_data_ptr);
1682 if (self == nullptr || !self->AsyncTransferActive())
1683 {
1684 return;
1685 }
1686
1687 AsyncCompletionStateMachine::MarkDmaDone(self->async_ctx_);
1688 self->MaybeCompleteAsyncTransfer(true);
1689}
1690
1691void HPMI2C::OnDmaErrorCallback(DMA_Type* base, uint32_t channel, void* cb_data_ptr)
1692{
1693 UNUSED(base);
1694 UNUSED(channel);
1695 auto* self = static_cast<HPMI2C*>(cb_data_ptr);
1696 if (self == nullptr || !self->AsyncTransferActive())
1697 {
1698 return;
1699 }
1700 if (AsyncCompletionStateMachine::DmaDone(self->async_ctx_))
1701 {
1702 return;
1703 }
1704 AsyncCompletionStateMachine::MarkFailure(self->async_ctx_, status_fail, true);
1705 self->CompleteAsyncTransfer(true, ErrorCode::FAILED);
1706}
1707
1708void HPMI2C::OnDmaAbortCallback(DMA_Type* base, uint32_t channel, void* cb_data_ptr)
1709{
1710 UNUSED(base);
1711 UNUSED(channel);
1712 auto* self = static_cast<HPMI2C*>(cb_data_ptr);
1713 if (self == nullptr || !self->AsyncTransferActive())
1714 {
1715 return;
1716 }
1717 if (AsyncCompletionStateMachine::DmaDone(self->async_ctx_))
1718 {
1719 return;
1720 }
1721 AsyncCompletionStateMachine::MarkFailure(self->async_ctx_, status_fail, true);
1722 self->CompleteAsyncTransfer(true, ErrorCode::FAILED);
1723}
1724
1725ErrorCode HPMI2C::ValidateTransferArgs(uint16_t slave_addr, RawData data,
1726 bool allow_zero_size) const
1727{
1728 if (data.size_ == 0)
1729 {
1730 return allow_zero_size ? ErrorCode::OK : ErrorCode::ARG_ERR;
1731 }
1732 if (data.addr_ == nullptr)
1733 {
1734 return ErrorCode::PTR_NULL;
1735 }
1736 if (data.size_ > I2C_SOC_TRANSFER_COUNT_MAX)
1737 {
1738 return ErrorCode::SIZE_ERR;
1739 }
1740 return ValidateSlaveAddress(slave_addr);
1741}
1742
1743ErrorCode HPMI2C::ValidateTransferArgs(uint16_t slave_addr, ConstRawData data,
1744 bool allow_zero_size) const
1745{
1746 if (data.size_ == 0)
1747 {
1748 return allow_zero_size ? ErrorCode::OK : ErrorCode::ARG_ERR;
1749 }
1750 if (data.addr_ == nullptr)
1751 {
1752 return ErrorCode::PTR_NULL;
1753 }
1754 if (data.size_ > I2C_SOC_TRANSFER_COUNT_MAX)
1755 {
1756 return ErrorCode::SIZE_ERR;
1757 }
1758 return ValidateSlaveAddress(slave_addr);
1759}
1760
1761ErrorCode HPMI2C::ValidateMemWriteArgs(uint16_t slave_addr, ConstRawData write_data,
1762 MemAddrLength mem_addr_size,
1763 uint32_t& addr_size) const
1764{
1765 if (write_data.size_ > 0 && write_data.addr_ == nullptr)
1766 {
1767 return ErrorCode::PTR_NULL;
1768 }
1769
1770 ErrorCode ans = ResolveMemAddressSize(mem_addr_size, addr_size);
1771 if (ans != ErrorCode::OK)
1772 {
1773 return ans;
1774 }
1775 if ((addr_size + write_data.size_) > I2C_SOC_TRANSFER_COUNT_MAX)
1776 {
1777 return ErrorCode::SIZE_ERR;
1778 }
1779 return ValidateSlaveAddress(slave_addr);
1780}
1781
1782ErrorCode HPMI2C::SetConfig(Configuration config)
1783{
1784 if (i2c_ == nullptr)
1785 {
1786 return ErrorCode::PTR_NULL;
1787 }
1788 if (AsyncTransferActive())
1789 {
1790 return ErrorCode::BUSY;
1791 }
1792 if ((i2c_get_status(i2c_) & I2C_STATUS_BUSBUSY_MASK) != 0U)
1793 {
1794 return ErrorCode::BUSY;
1795 }
1796
1797 return ApplyConfig(config);
1798}
1799
1800ErrorCode HPMI2C::Read(uint16_t slave_addr, RawData read_data, ReadOperation& op,
1801 bool in_isr)
1802{
1803 const ErrorCode arg_ans = ValidateTransferArgs(slave_addr, read_data, true);
1804 if (arg_ans != ErrorCode::OK || read_data.size_ == 0)
1805 {
1806 return FinishOperation(op, in_isr, arg_ans);
1807 }
1808
1809 if (AsyncTransferActive())
1810 {
1811 return FinishOperation(op, in_isr, ErrorCode::BUSY);
1812 }
1813
1814 if (op.type != ReadOperation::OperationType::BLOCK)
1815 {
1816 const ErrorCode ans = StartReadAsync(slave_addr, read_data, op);
1817 if (ans != ErrorCode::OK)
1818 {
1819 op.UpdateStatus(in_isr, ans);
1820 }
1821 return ans;
1822 }
1823
1824 ErrorCode ans = EnsureControllerReady();
1825 if (ans != ErrorCode::OK)
1826 {
1827 return FinishOperation(op, in_isr, ans);
1828 }
1829
1830 hpm_stat_t status =
1831 i2c_master_read(i2c_, slave_addr, static_cast<uint8_t*>(read_data.addr_),
1832 static_cast<uint32_t>(read_data.size_));
1833 ans = ConvertStatus(status);
1834 if (ShouldRecover(status))
1835 {
1836 RecoverController();
1837 }
1838 return FinishOperation(op, in_isr, ans);
1839}
1840
1841ErrorCode HPMI2C::DoSequenceWrite(uint16_t slave_addr, ConstRawData write_data,
1842 SequenceFrame frame, bool check_ack)
1843{
1844 if (AsyncTransferActive())
1845 {
1846 return ErrorCode::BUSY;
1847 }
1848
1849 ErrorCode ans = EnsureControllerReady();
1850 if (ans != ErrorCode::OK)
1851 {
1852 return ans;
1853 }
1854
1855 hpm_stat_t status;
1856 if (address_mode_ == AddressMode::ADDR_10BIT)
1857 {
1858 uint16_t flags = kI2CFlagWriteCheckAck;
1859 if (!check_ack)
1860 {
1861 flags = 0U;
1862 }
1863 switch (frame)
1864 {
1866 flags |= 0U;
1867 flags |= kI2CFlagAddr10Bit;
1868 flags |= kI2CFlagNoStop;
1869 break;
1871 flags |= kI2CFlagAddr10Bit | I2C_NO_START | I2C_NO_ADDRESS | kI2CFlagNoStop;
1872 break;
1874 default:
1875 flags |= kI2CFlagAddr10Bit | I2C_NO_START | I2C_NO_ADDRESS;
1876 break;
1877 }
1878 const hpm_stat_t raw_status = DoManualTransferWithFlags(
1879 slave_addr, RawData(const_cast<void*>(write_data.addr_), write_data.size_),
1880 flags);
1881 status = raw_status;
1882 }
1883 else
1884 {
1885 status = i2c_master_seq_transmit_check_ack(
1886 i2c_, slave_addr,
1887 const_cast<uint8_t*>(static_cast<const uint8_t*>(write_data.addr_)),
1888 static_cast<uint32_t>(write_data.size_), ConvertSequenceFrame(frame), check_ack);
1889 }
1890
1891 ans = ConvertStatus(status);
1892 if (ShouldRecover(status))
1893 {
1894 RecoverController();
1895 }
1896 return ans;
1897}
1898
1899ErrorCode HPMI2C::DoSequenceRead(uint16_t slave_addr, RawData read_data,
1900 SequenceFrame frame)
1901{
1902 if (AsyncTransferActive())
1903 {
1904 return ErrorCode::BUSY;
1905 }
1906
1907 ErrorCode ans = EnsureControllerReady();
1908 if (ans != ErrorCode::OK)
1909 {
1910 return ans;
1911 }
1912
1913 hpm_stat_t status;
1914 if (address_mode_ == AddressMode::ADDR_10BIT)
1915 {
1916 uint16_t flags = kI2CFlagRead | kI2CFlagAddr10Bit;
1917 switch (frame)
1918 {
1920 flags |= kI2CFlagNoStop;
1921 break;
1923 flags |= I2C_NO_START | I2C_NO_ADDRESS | kI2CFlagNoStop;
1924 break;
1926 default:
1927 flags |= I2C_NO_START | I2C_NO_ADDRESS;
1928 break;
1929 }
1930 status = DoManualTransferWithFlags(slave_addr, read_data, flags);
1931 }
1932 else
1933 {
1934 status = i2c_master_seq_receive(
1935 i2c_, slave_addr, static_cast<uint8_t*>(read_data.addr_),
1936 static_cast<uint32_t>(read_data.size_), ConvertSequenceFrame(frame));
1937 }
1938
1939 ans = ConvertStatus(status);
1940 if (ShouldRecover(status))
1941 {
1942 RecoverController();
1943 }
1944 return ans;
1945}
1946
1947ErrorCode HPMI2C::DoTransferWithFlags(uint16_t slave_addr, RawData data, uint16_t flags)
1948{
1949 if (AsyncTransferActive())
1950 {
1951 return ErrorCode::BUSY;
1952 }
1953
1954 ErrorCode ans = EnsureControllerReady();
1955 if (ans != ErrorCode::OK)
1956 {
1957 return ans;
1958 }
1959
1960 const uint16_t final_flags = BuildTransferFlags(flags);
1961 const hpm_stat_t status = DoManualTransferWithFlags(slave_addr, data, final_flags);
1962 ans = ConvertStatus(status);
1963 if (ShouldRecover(status))
1964 {
1965 RecoverController();
1966 }
1967 return ans;
1968}
1969
1970hpm_stat_t HPMI2C::DoManualTransferWithFlags(uint16_t slave_addr, RawData data,
1971 uint16_t flags)
1972{
1973 if (AsyncTransferActive())
1974 {
1975 return status_i2c_bus_busy;
1976 }
1977
1978 return DoManualTransferWithFlagsImpl(i2c_, slave_addr, data, flags, wait_policy_);
1979}
1980
1981ErrorCode HPMI2C::SequenceWrite(uint16_t slave_addr, ConstRawData write_data,
1982 SequenceFrame frame, bool check_ack, WriteOperation& op,
1983 bool in_isr)
1984{
1985 const ErrorCode arg_ans = ValidateTransferArgs(slave_addr, write_data, false);
1986 if (arg_ans != ErrorCode::OK)
1987 {
1988 return FinishOperation(op, in_isr, arg_ans);
1989 }
1990 if (AsyncTransferActive())
1991 {
1992 return FinishOperation(op, in_isr, ErrorCode::BUSY);
1993 }
1994 return FinishOperation(op, in_isr,
1995 DoSequenceWrite(slave_addr, write_data, frame, check_ack));
1996}
1997
1998ErrorCode HPMI2C::SequenceRead(uint16_t slave_addr, RawData read_data,
1999 SequenceFrame frame, ReadOperation& op, bool in_isr)
2000{
2001 const ErrorCode arg_ans = ValidateTransferArgs(slave_addr, read_data, false);
2002 if (arg_ans != ErrorCode::OK)
2003 {
2004 return FinishOperation(op, in_isr, arg_ans);
2005 }
2006 if (AsyncTransferActive())
2007 {
2008 return FinishOperation(op, in_isr, ErrorCode::BUSY);
2009 }
2010 return FinishOperation(op, in_isr, DoSequenceRead(slave_addr, read_data, frame));
2011}
2012
2013ErrorCode HPMI2C::TransferWithFlags(uint16_t slave_addr, RawData data, uint16_t flags,
2014 ReadOperation& op, bool in_isr)
2015{
2016 const ErrorCode arg_ans = ValidateTransferArgs(slave_addr, data, false);
2017 if (arg_ans != ErrorCode::OK)
2018 {
2019 return FinishOperation(op, in_isr, arg_ans);
2020 }
2021 if (AsyncTransferActive())
2022 {
2023 return FinishOperation(op, in_isr, ErrorCode::BUSY);
2024 }
2025 return FinishOperation(op, in_isr, DoTransferWithFlags(slave_addr, data, flags));
2026}
2027
2028ErrorCode HPMI2C::TransferWithFlags(uint16_t slave_addr, ConstRawData data,
2029 uint16_t flags, WriteOperation& op, bool in_isr)
2030{
2031 const ErrorCode arg_ans = ValidateTransferArgs(slave_addr, data, false);
2032 if (arg_ans != ErrorCode::OK)
2033 {
2034 return FinishOperation(op, in_isr, arg_ans);
2035 }
2036 if (AsyncTransferActive())
2037 {
2038 return FinishOperation(op, in_isr, ErrorCode::BUSY);
2039 }
2040 return FinishOperation(
2041 op, in_isr,
2042 DoTransferWithFlags(slave_addr, RawData(const_cast<void*>(data.addr_), data.size_),
2043 static_cast<uint16_t>(flags & ~kI2CFlagRead)));
2044}
2045
2046ErrorCode HPMI2C::Write(uint16_t slave_addr, ConstRawData write_data, WriteOperation& op,
2047 bool in_isr)
2048{
2049 const ErrorCode arg_ans = ValidateTransferArgs(slave_addr, write_data, true);
2050 if (arg_ans != ErrorCode::OK || write_data.size_ == 0)
2051 {
2052 return FinishOperation(op, in_isr, arg_ans);
2053 }
2054
2055 if (AsyncTransferActive())
2056 {
2057 return FinishOperation(op, in_isr, ErrorCode::BUSY);
2058 }
2059
2060 if (op.type != WriteOperation::OperationType::BLOCK)
2061 {
2062 const ErrorCode ans = StartWriteAsync(slave_addr, write_data, op);
2063 if (ans != ErrorCode::OK)
2064 {
2065 op.UpdateStatus(in_isr, ans);
2066 }
2067 return ans;
2068 }
2069
2070 ErrorCode ans = EnsureControllerReady();
2071 if (ans != ErrorCode::OK)
2072 {
2073 return FinishOperation(op, in_isr, ans);
2074 }
2075
2076 hpm_stat_t status = i2c_master_write(
2077 i2c_, slave_addr,
2078 const_cast<uint8_t*>(static_cast<const uint8_t*>(write_data.addr_)),
2079 static_cast<uint32_t>(write_data.size_));
2080 ans = ConvertStatus(status);
2081 if (ShouldRecover(status))
2082 {
2083 RecoverController();
2084 }
2085 return FinishOperation(op, in_isr, ans);
2086}
2087
2088ErrorCode HPMI2C::MemRead(uint16_t slave_addr, uint16_t mem_addr, RawData read_data,
2089 ReadOperation& op, MemAddrLength mem_addr_size, bool in_isr)
2090{
2091 const ErrorCode arg_ans = ValidateTransferArgs(slave_addr, read_data, true);
2092 if (arg_ans != ErrorCode::OK || read_data.size_ == 0)
2093 {
2094 return FinishOperation(op, in_isr, arg_ans);
2095 }
2096
2097 if (AsyncTransferActive())
2098 {
2099 return FinishOperation(op, in_isr, ErrorCode::BUSY);
2100 }
2101
2102 if (op.type != ReadOperation::OperationType::BLOCK)
2103 {
2104 const ErrorCode ans =
2105 StartMemReadAsync(slave_addr, mem_addr, read_data, op, mem_addr_size);
2106 if (ans != ErrorCode::OK)
2107 {
2108 op.UpdateStatus(in_isr, ans);
2109 }
2110 return ans;
2111 }
2112
2113 uint32_t addr_size = 0;
2114 ErrorCode ans = ResolveMemAddressSize(mem_addr_size, addr_size);
2115 if (ans != ErrorCode::OK)
2116 {
2117 return FinishOperation(op, in_isr, ans);
2118 }
2119 if (addr_size > I2C_SOC_TRANSFER_COUNT_MAX)
2120 {
2121 return FinishOperation(op, in_isr, ErrorCode::SIZE_ERR);
2122 }
2123
2124 ans = EnsureControllerReady();
2125 if (ans != ErrorCode::OK)
2126 {
2127 return FinishOperation(op, in_isr, ans);
2128 }
2129
2130 uint8_t addr[2] = {};
2131 FillMemAddress(mem_addr, mem_addr_size, addr);
2132
2133 if (address_mode_ == AddressMode::ADDR_10BIT)
2134 {
2135 ans = DoSequenceWrite(slave_addr, ConstRawData(addr, addr_size), SequenceFrame::FIRST,
2136 true);
2137 if (ans == ErrorCode::OK)
2138 {
2139 ans = DoSequenceRead(slave_addr, read_data, SequenceFrame::LAST);
2140 }
2141 }
2142 else
2143 {
2144 const hpm_stat_t status = i2c_master_address_read(
2145 i2c_, slave_addr, addr, addr_size, static_cast<uint8_t*>(read_data.addr_),
2146 static_cast<uint32_t>(read_data.size_));
2147 ans = ConvertStatus(status);
2148 if (ShouldRecover(status))
2149 {
2150 RecoverController();
2151 }
2152 }
2153 return FinishOperation(op, in_isr, ans);
2154}
2155
2156ErrorCode HPMI2C::MemWrite(uint16_t slave_addr, uint16_t mem_addr,
2157 ConstRawData write_data, WriteOperation& op,
2158 MemAddrLength mem_addr_size, bool in_isr)
2159{
2160 uint32_t addr_size = 0;
2161 ErrorCode ans = ValidateMemWriteArgs(slave_addr, write_data, mem_addr_size, addr_size);
2162 if (ans != ErrorCode::OK)
2163 {
2164 return FinishOperation(op, in_isr, ans);
2165 }
2166
2167 if (AsyncTransferActive())
2168 {
2169 return FinishOperation(op, in_isr, ErrorCode::BUSY);
2170 }
2171
2172 ans = EnsureControllerReady();
2173 if (ans != ErrorCode::OK)
2174 {
2175 return FinishOperation(op, in_isr, ans);
2176 }
2177
2178 uint8_t addr[2] = {};
2179 FillMemAddress(mem_addr, mem_addr_size, addr);
2180
2181 if (address_mode_ == AddressMode::ADDR_10BIT)
2182 {
2183 if (write_data.size_ == 0)
2184 {
2185 hpm_stat_t status =
2186 DoManualTransferWithFlags(slave_addr, RawData(addr, addr_size),
2187 kI2CFlagAddr10Bit | kI2CFlagWriteCheckAck);
2188 ans = ConvertStatus(status);
2189 if (ShouldRecover(status))
2190 {
2191 RecoverController();
2192 }
2193 }
2194 else
2195 {
2196 ans = DoSequenceWrite(slave_addr, ConstRawData(addr, addr_size),
2197 SequenceFrame::FIRST, true);
2198 if (ans == ErrorCode::OK)
2199 {
2200 ans = DoSequenceWrite(slave_addr, write_data, SequenceFrame::LAST, true);
2201 }
2202 }
2203 }
2204 else
2205 {
2206 hpm_stat_t status;
2207 if (write_data.size_ == 0)
2208 {
2209 status = i2c_master_write(i2c_, slave_addr, addr, addr_size);
2210 }
2211 else
2212 {
2213 status = i2c_master_address_write(
2214 i2c_, slave_addr, addr, addr_size,
2215 const_cast<uint8_t*>(static_cast<const uint8_t*>(write_data.addr_)),
2216 static_cast<uint32_t>(write_data.size_));
2217 }
2218
2219 ans = ConvertStatus(status);
2220 if (ShouldRecover(status))
2221 {
2222 RecoverController();
2223 }
2224 }
2225 return FinishOperation(op, in_isr, ans);
2226}
2227
2228#else
2229
2230extern "C" void libxr_hpm_i2c_process_interrupt(LibXRHpmI2cType* ptr) { UNUSED(ptr); }
2231
2232HPMI2C::HPMI2C(LibXRHpmI2cType* i2c, clock_name_t clock, I2C::Configuration config)
2233 : i2c_(i2c), clock_(clock), current_config_(config)
2234{
2235 (void)i2c_;
2236 (void)clock_;
2237}
2238
2240{
2241 address_mode_ = mode;
2243}
2244
2245ErrorCode HPMI2C::ConvertStatus(hpm_stat_t status)
2246{
2247 UNUSED(status);
2249}
2250
2251uint16_t HPMI2C::BuildTransferFlags(uint16_t flags) const { return flags; }
2252
2253ErrorCode HPMI2C::DoSequenceWrite(uint16_t slave_addr, ConstRawData write_data,
2254 SequenceFrame frame, bool check_ack)
2255{
2256 UNUSED(slave_addr);
2257 UNUSED(write_data);
2258 UNUSED(frame);
2259 UNUSED(check_ack);
2261}
2262
2263ErrorCode HPMI2C::DoSequenceRead(uint16_t slave_addr, RawData read_data,
2264 SequenceFrame frame)
2265{
2266 UNUSED(slave_addr);
2267 UNUSED(read_data);
2268 UNUSED(frame);
2270}
2271
2272ErrorCode HPMI2C::DoTransferWithFlags(uint16_t slave_addr, RawData data, uint16_t flags)
2273{
2274 UNUSED(slave_addr);
2275 UNUSED(data);
2276 UNUSED(flags);
2278}
2279
2280hpm_stat_t HPMI2C::DoManualTransferWithFlags(uint16_t slave_addr, RawData data,
2281 uint16_t flags)
2282{
2283 UNUSED(slave_addr);
2284 UNUSED(data);
2285 UNUSED(flags);
2286 return status_fail;
2287}
2288
2289ErrorCode HPMI2C::EnsureClockReady() { return ErrorCode::NOT_SUPPORT; }
2290
2291ErrorCode HPMI2C::EnsureControllerReady() { return ErrorCode::NOT_SUPPORT; }
2292
2293ErrorCode HPMI2C::ApplyConfig(const Configuration& config)
2294{
2295 current_config_ = config;
2296 configured_ = false;
2298}
2299
2300bool HPMI2C::ShouldRecover(hpm_stat_t status)
2301{
2302 UNUSED(status);
2303 return false;
2304}
2305
2306void HPMI2C::RecoverController() {}
2307
2308void HPMI2C::TryRecoverBusLines() {}
2309
2311{
2312 current_config_ = config;
2313 configured_ = false;
2315}
2316
2317ErrorCode HPMI2C::Read(uint16_t slave_addr, RawData read_data, ReadOperation& op,
2318 bool in_isr)
2319{
2320 UNUSED(slave_addr);
2321 UNUSED(read_data);
2322 return FinishOperation(op, in_isr, ErrorCode::NOT_SUPPORT);
2323}
2324
2325ErrorCode HPMI2C::Write(uint16_t slave_addr, ConstRawData write_data, WriteOperation& op,
2326 bool in_isr)
2327{
2328 UNUSED(slave_addr);
2329 UNUSED(write_data);
2330 return FinishOperation(op, in_isr, ErrorCode::NOT_SUPPORT);
2331}
2332
2333ErrorCode HPMI2C::MemRead(uint16_t slave_addr, uint16_t mem_addr, RawData read_data,
2334 ReadOperation& op, MemAddrLength mem_addr_size, bool in_isr)
2335{
2336 UNUSED(slave_addr);
2337 UNUSED(mem_addr);
2338 UNUSED(read_data);
2339 UNUSED(mem_addr_size);
2340 return FinishOperation(op, in_isr, ErrorCode::NOT_SUPPORT);
2341}
2342
2343ErrorCode HPMI2C::MemWrite(uint16_t slave_addr, uint16_t mem_addr,
2344 ConstRawData write_data, WriteOperation& op,
2345 MemAddrLength mem_addr_size, bool in_isr)
2346{
2347 UNUSED(slave_addr);
2348 UNUSED(mem_addr);
2349 UNUSED(write_data);
2350 UNUSED(mem_addr_size);
2351 return FinishOperation(op, in_isr, ErrorCode::NOT_SUPPORT);
2352}
2353
2354ErrorCode HPMI2C::SequenceWrite(uint16_t slave_addr, ConstRawData write_data,
2355 SequenceFrame frame, bool check_ack, WriteOperation& op,
2356 bool in_isr)
2357{
2358 UNUSED(slave_addr);
2359 UNUSED(write_data);
2360 UNUSED(frame);
2361 UNUSED(check_ack);
2362 return FinishOperation(op, in_isr, ErrorCode::NOT_SUPPORT);
2363}
2364
2365ErrorCode HPMI2C::SequenceRead(uint16_t slave_addr, RawData read_data,
2366 SequenceFrame frame, ReadOperation& op, bool in_isr)
2367{
2368 UNUSED(slave_addr);
2369 UNUSED(read_data);
2370 UNUSED(frame);
2371 return FinishOperation(op, in_isr, ErrorCode::NOT_SUPPORT);
2372}
2373
2374ErrorCode HPMI2C::TransferWithFlags(uint16_t slave_addr, RawData data, uint16_t flags,
2375 ReadOperation& op, bool in_isr)
2376{
2377 UNUSED(slave_addr);
2378 UNUSED(data);
2379 UNUSED(flags);
2380 return FinishOperation(op, in_isr, ErrorCode::NOT_SUPPORT);
2381}
2382
2384 uint16_t flags, WriteOperation& op, bool in_isr)
2385{
2386 UNUSED(slave_addr);
2387 UNUSED(data);
2388 UNUSED(flags);
2389 return FinishOperation(op, in_isr, ErrorCode::NOT_SUPPORT);
2390}
2391
2392#endif
ErrorCode Wait(uint32_t timeout)
等待完成或超时交接 / Wait for completion or a timeout handoff.
只读原始数据视图 / Immutable raw data view
size_t size_
数据字节数 / Data size in bytes
const void * addr_
数据起始地址 / Data start address
static void EnsureInitialized()
确保 dma_mgr_init() 已执行且只执行一次 / Ensure dma_mgr_init() has run, exactly once.
Definition hpm_dma.cpp:13
HPM SDK I2C 主机驱动,适配 LibXR I2C 接口 / HPM SDK based I2C master driver for the LibXR I2C interface.
Definition hpm_i2c.hpp:143
ErrorCode MemRead(uint16_t slave_addr, uint16_t mem_addr, RawData read_data, ReadOperation &op, MemAddrLength mem_addr_size=MemAddrLength::BYTE_8, bool in_isr=false) override
从 I2C 从设备寄存器或存储器地址读取字节 / Read bytes from an I2C slave register or memory address.
Definition hpm_i2c.cpp:2333
ErrorCode TransferWithFlags(uint16_t slave_addr, RawData data, uint16_t flags, ReadOperation &op, bool in_isr=false)
执行一段 HPM 扩展标志主机事务 / Execute one HPM master transfer with extended SDK flags.
Definition hpm_i2c.cpp:2374
ErrorCode SequenceRead(uint16_t slave_addr, RawData read_data, SequenceFrame frame, ReadOperation &op, bool in_isr=false)
执行一段 HPM 主机顺序读事务 / Execute one HPM master sequential read frame.
Definition hpm_i2c.cpp:2365
HPMI2C(LibXRHpmI2cType *i2c, clock_name_t clock, I2C::Configuration config)
构造 HPM I2C 主机对象 / Construct an HPM I2C master object.
Definition hpm_i2c.cpp:2232
ErrorCode SetWaitPolicy(WaitPolicy policy)
设置当前实例的忙等超时策略 / Set the busy-wait timeout policy for this instance.
Definition hpm_i2c.cpp:76
ErrorCode Write(uint16_t slave_addr, ConstRawData write_data, WriteOperation &op, bool in_isr=false) override
向 I2C 从设备写入字节 / Write bytes to an I2C slave.
Definition hpm_i2c.cpp:2325
ErrorCode Read(uint16_t slave_addr, RawData read_data, ReadOperation &op, bool in_isr=false) override
从 I2C 从设备读取字节 / Read bytes from an I2C slave.
Definition hpm_i2c.cpp:2317
ErrorCode SetAddressMode(AddressMode mode)
设置 HPM 主机寻址模式并重建控制器 / Set HPM master addressing mode and rebuild the controller.
Definition hpm_i2c.cpp:2239
ErrorCode MemWrite(uint16_t slave_addr, uint16_t mem_addr, ConstRawData write_data, WriteOperation &op, MemAddrLength mem_addr_size=MemAddrLength::BYTE_8, bool in_isr=false) override
向 I2C 从设备寄存器或存储器地址写入字节 / Write bytes to an I2C slave register or memory address.
Definition hpm_i2c.cpp:2343
AddressMode
HPM I2C 主机寻址模式 / HPM I2C master addressing mode.
Definition hpm_i2c.hpp:149
@ ADDR_10BIT
10-bit 从地址 / 10-bit slave addressing.
AsyncTransferKind
HPM I2C 后台事务类型 / HPM I2C asynchronous transfer kind.
Definition hpm_i2c.hpp:193
SequenceFrame
HPM 主机顺序事务分段类型 / HPM master sequential transfer frame type.
Definition hpm_i2c.hpp:158
@ FIRST
带 START 和地址阶段 / Includes START and address phase.
@ NEXT
中间段,不带 START/STOP / Middle frame without START/STOP.
@ LAST
末段,带 STOP / Final frame with STOP.
ErrorCode SequenceWrite(uint16_t slave_addr, ConstRawData write_data, SequenceFrame frame, bool check_ack, WriteOperation &op, bool in_isr=false)
执行一段 HPM 主机顺序写事务 / Execute one HPM master sequential write frame.
Definition hpm_i2c.cpp:2354
void CompleteAsyncTransfer(bool in_isr, ErrorCode ans)
供 DMA / 中断完成路径调用的完成入口 / Completion entry used by DMA / interrupt driven paths.
ErrorCode SetConfig(Configuration config) override
应用 I2C 时序配置 / Apply I2C timing configuration.
Definition hpm_i2c.cpp:2310
uint32_t timeout
等待超时值 / Wait timeout.
void UpdateStatus(bool in_isr, Status &&status)
按通知方式报告完成结果 / Report completion using the selected mode.
union LibXR::Operation::@6 data
完成通知对象,由 type 选择有效成员 / Notification target selected by type.
void MarkAsRunning()
标记轮询操作正在执行 / Mark a polling operation as running.
OperationType type
当前通知方式 / Current notification mode.
可写原始数据视图 / Mutable raw data view
size_t size_
数据字节数 / Data size in bytes
void * addr_
数据起始地址 / Data start address
HPM I2C 主机驱动适配头文件 / Adapter header for the HPM I2C master driver.
HPM I2C 平台资源解析 helper / Platform resource resolver for HPM I2C.
LibXR 命名空间 / LibXR namespace.
Definition ch32_can.hpp:14
ErrorCode
定义错误码枚举 / Defines an enumeration for error codes
@ TIMEOUT
超时 / Timeout
@ SIZE_ERR
尺寸错误 / Size error
@ CHECK_ERR
校验错误 / Check error
@ INIT_ERR
初始化错误 / Initialization error
@ BUSY
忙碌 / Busy
@ NO_RESPONSE
无响应 / No response
@ PTR_NULL
空指针 / Null pointer
@ NOT_SUPPORT
不支持 / Not supported
@ FAILED
操作失败 / Operation failed
@ FULL
已满 / Full
@ OK
操作成功 / Operation successful
@ ARG_ERR
参数错误 / Argument error
HPM I2C 忙等超时策略 / HPM I2C busy-wait timeout policy.
Definition hpm_i2c.hpp:211
I2C 设备的配置信息结构体。 Configuration structure for an I2C device.
Definition i2c.hpp:24