1
use super::*;
2
use crate::{rtc_cntl::WakeLock, soc::clocks::ClockTree};
3

            
4
#[cfg_attr(i2c_master_version = "1", path = "v1.rs")]
5
#[cfg_attr(i2c_master_version = "2", path = "v2.rs")]
6
#[cfg_attr(
7
    any(i2c_master_version = "3", i2c_master_version = "4"),
8
    path = "v3.rs"
9
)]
10
mod version;
11

            
12
#[must_use = "futures do nothing unless you `.await` or poll them"]
13
pub(super) struct I2cFuture<'a> {
14
    events: EnumSet<Event>,
15
    driver: Driver<'a>,
16
    deadline: Option<Instant>,
17
    /// True if the Future has been polled to completion.
18
    finished: bool,
19
    _wake_lock: WakeLock,
20
}
21

            
22
impl<'a> I2cFuture<'a> {
23
219
    pub fn new(events: EnumSet<Event>, driver: Driver<'a>, deadline: Option<Instant>) -> Self {
24
        driver.regs().int_ena().modify(|_, w| {
25
438
            for event in events {
26
                match event {
27
                    Event::EndDetect => w.end_detect().set_bit(),
28
                    Event::TxComplete => w.trans_complete().set_bit(),
29
                    #[cfg(i2c_master_has_tx_fifo_watermark)]
30
                    Event::TxFifoWatermark => w.txfifo_wm().set_bit(),
31
                };
32
            }
33

            
34
            w.arbitration_lost().set_bit();
35
            w.time_out().set_bit();
36
            w.nack().set_bit();
37
            #[cfg(i2c_master_has_fsm_timeouts)]
38
            {
39
                w.scl_main_st_to().set_bit();
40
                w.scl_st_to().set_bit();
41
            }
42

            
43
            w
44
        });
45

            
46
        Self::new_blocking(events, driver, deadline)
47
219
    }
48

            
49
    pub fn new_blocking(
50
        events: EnumSet<Event>,
51
        driver: Driver<'a>,
52
        deadline: Option<Instant>,
53
    ) -> Self {
54
219
        Self {
55
            events,
56
            driver,
57
            deadline,
58
            finished: false,
59
            _wake_lock: WakeLock::new(),
60
        }
61
    }
62

            
63
    fn is_done(&self) -> bool {
64
        !self.driver.info.interrupts().is_disjoint(self.events)
65
    }
66

            
67
4328
    fn poll_completion(&mut self) -> Poll<Result<(), Error>> {
68
        // Grab the current time before doing anything. This will ensure that a long
69
        // interruption still allows the peripheral sufficient time to complete the
70
        // operation (i.e. it ensures that the deadline is "at least", not "at most").
71
4328
        let now = if self.deadline.is_some() {
72
            Instant::now()
73
        } else {
74
            Instant::EPOCH
75
        };
76
        let error = self.driver.check_errors();
77

            
78
4328
        let result = if self.is_done() {
79
            // Even though we are done, we have to check for NACK and arbitration loss.
80
229
            let result = if error == Err(Error::Timeout) {
81
                // We are both done, and timed out. Likely the transaction has completed, but we
82
                // checked too late?
83
                Ok(())
84
            } else {
85
                error
86
            };
87
            Poll::Ready(result)
88
4099
        } else if error.is_err() {
89
            Poll::Ready(error)
90
4095
        } else if let Some(deadline) = self.deadline
91
            && now > deadline
92
        {
93
            // If the deadline is reached, we return an error.
94
            Poll::Ready(Err(Error::Timeout))
95
        } else {
96
            Poll::Pending
97
        };
98

            
99
        if result.is_ready() {
100
233
            self.finished = true;
101
        }
102

            
103
        result
104
4328
    }
105
}
106

            
107
impl core::future::Future for I2cFuture<'_> {
108
    type Output = Result<(), Error>;
109

            
110
498
    fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
111
498
        self.driver.state.waker.register(ctx.waker());
112

            
113
498
        let result = self.poll_completion();
114

            
115
498
        if result.is_pending() && self.deadline.is_some() {
116
            ctx.waker().wake_by_ref();
117
        }
118

            
119
        result
120
498
    }
121
}
122

            
123
impl Drop for I2cFuture<'_> {
124
219
    fn drop(&mut self) {
125
219
        if !self.finished {
126
4
            let result = self.poll_completion();
127
4
            if result.is_pending() || result == Poll::Ready(Err(Error::Timeout)) {
128
4
                self.driver.reset_fsm(true);
129
            }
130
        }
131
215
    }
132
}
133

            
134
#[ram]
135
215
pub(super) fn async_handler(info: &Info, state: &State) {
136
    // Disable all interrupts. The I2C Future will check events based on the
137
    // interrupt status bits.
138
    info.regs().int_ena().write(|w| unsafe { w.bits(0) });
139

            
140
215
    state.waker.wake();
141
}
142

            
143
/// Sets the filter with a supplied threshold in clock cycles for which a
144
/// pulse must be present to pass the filter.
145
fn set_filter(
146
    register_block: &RegisterBlock,
147
    sda_threshold: Option<u8>,
148
    scl_threshold: Option<u8>,
149
) {
150
    cfg_select! {
151
        i2c_master_separate_filter_config_registers => {
152
            register_block.sda_filter_cfg().modify(|_, w| {
153
                if let Some(threshold) = sda_threshold {
154
                    unsafe { w.sda_filter_thres().bits(threshold) };
155
                }
156
                w.sda_filter_en().bit(sda_threshold.is_some())
157
            });
158
            register_block.scl_filter_cfg().modify(|_, w| {
159
                if let Some(threshold) = scl_threshold {
160
                    unsafe { w.scl_filter_thres().bits(threshold) };
161
                }
162
                w.scl_filter_en().bit(scl_threshold.is_some())
163
            });
164
        }
165
        _ => {
166
            register_block.filter_cfg().modify(|_, w| {
167
57
                if let Some(threshold) = sda_threshold {
168
                    unsafe { w.sda_filter_thres().bits(threshold) };
169
                }
170
                if let Some(threshold) = scl_threshold {
171
                    unsafe { w.scl_filter_thres().bits(threshold) };
172
                }
173
                w.sda_filter_en().bit(sda_threshold.is_some());
174
                w.scl_filter_en().bit(scl_threshold.is_some())
175
            });
176
        }
177
    }
178
}
179

            
180
#[expect(clippy::too_many_arguments)]
181
#[allow(unused)]
182
/// Configures the timing parameters for the I2C peripheral.
183
///
184
/// Clock source selection is handled separately via the clock tree.
185
fn configure_clock(
186
    info: &Info,
187
    scl_low_period: u32,
188
    scl_high_period: u32,
189
    scl_wait_high_period: u32,
190
    sda_hold_time: u32,
191
    sda_sample_time: u32,
192
    scl_rstart_setup_time: u32,
193
    scl_stop_setup_time: u32,
194
    scl_start_hold_time: u32,
195
    scl_stop_hold_time: u32,
196
    timeout: Option<u32>,
197
) -> Result<(), ConfigError> {
198
    unsafe {
199
        // scl period
200
        info.regs()
201
            .scl_low_period()
202
            .write(|w| w.scl_low_period().bits(scl_low_period as u16));
203

            
204
        #[cfg(not(i2c_master_version = "1"))]
205
        let scl_wait_high_period = scl_wait_high_period
206
            .try_into()
207
            .map_err(|_| ConfigError::FrequencyOutOfRange)?;
208

            
209
        info.regs().scl_high_period().write(|w| {
210
            #[cfg(not(i2c_master_version = "1"))] // ESP32 does not have a wait_high field
211
            w.scl_wait_high_period().bits(scl_wait_high_period);
212
            w.scl_high_period().bits(scl_high_period as u16)
213
        });
214

            
215
        // sda sample
216
        info.regs()
217
            .sda_hold()
218
            .write(|w| w.time().bits(sda_hold_time as u16));
219
        info.regs()
220
            .sda_sample()
221
            .write(|w| w.time().bits(sda_sample_time as u16));
222

            
223
        // setup
224
        info.regs()
225
            .scl_rstart_setup()
226
            .write(|w| w.time().bits(scl_rstart_setup_time as u16));
227
        info.regs()
228
            .scl_stop_setup()
229
            .write(|w| w.time().bits(scl_stop_setup_time as u16));
230

            
231
        // hold
232
        info.regs()
233
            .scl_start_hold()
234
            .write(|w| w.time().bits(scl_start_hold_time as u16));
235
        info.regs()
236
            .scl_stop_hold()
237
            .write(|w| w.time().bits(scl_stop_hold_time as u16));
238

            
239
        cfg_select! {
240
            i2c_master_has_bus_timeout_enable => {
241
                info.regs().to().write(|w| {
242
                    w.time_out_en().bit(timeout.is_some());
243
                    w.time_out_value().bits(timeout.unwrap_or(1) as _)
244
                });
245
            }
246
            _ => {
247
                info.regs()
248
                    .to()
249
                    .write(|w| w.time_out().bits(timeout.unwrap_or(1)));
250
            }
251
        }
252
    }
253
    Ok(())
254
}
255

            
256
/// Peripheral data describing a particular I2C instance.
257
#[doc(hidden)]
258
#[derive(Debug)]
259
#[non_exhaustive]
260
#[allow(private_interfaces, reason = "Unstable details")]
261
pub struct Info {
262
    /// Numeric instance id (0 = I2C0, 1 = I2C1, ...)
263
    #[cfg(soc_has_i2c1)]
264
    pub id: u8,
265

            
266
    /// Pointer to the register block for this I2C instance.
267
    ///
268
    /// Used with [`Self::register_block`] to access the register block.
269
    pub register_block: *const RegisterBlock,
270

            
271
    /// System peripheral marker.
272
    pub peripheral: crate::system::Peripheral,
273

            
274
    /// Interrupt handler for the asynchronous operations of this I2C instance.
275
    pub async_handler: InterruptHandler,
276

            
277
    /// SCL output signal.
278
    pub scl_output: OutputSignal,
279

            
280
    /// SCL input signal.
281
    pub scl_input: InputSignal,
282

            
283
    /// SDA output signal.
284
    pub sda_output: OutputSignal,
285

            
286
    /// SDA input signal.
287
    pub sda_input: InputSignal,
288

            
289
    /// I2C clock group instance.
290
    pub clock_instance: crate::soc::clocks::I2cInstance,
291
}
292

            
293
impl Info {
294
    /// Returns the register block for this I2C instance.
295
    pub fn regs(&self) -> &RegisterBlock {
296
3506
        unsafe { &*self.register_block }
297
    }
298

            
299
    /// Listens for the given interrupts.
300
    pub(super) fn enable_listen(&self, interrupts: EnumSet<Event>, enable: bool) {
301
        let reg_block = self.regs();
302

            
303
        reg_block.int_ena().modify(|_, w| {
304
            for interrupt in interrupts {
305
                match interrupt {
306
                    Event::EndDetect => w.end_detect().bit(enable),
307
                    Event::TxComplete => w.trans_complete().bit(enable),
308
                    #[cfg(i2c_master_has_tx_fifo_watermark)]
309
                    Event::TxFifoWatermark => w.txfifo_wm().bit(enable),
310
                };
311
            }
312
            w
313
        });
314
    }
315

            
316
    pub(super) fn interrupts(&self) -> EnumSet<Event> {
317
        let mut res = EnumSet::new();
318
        let reg_block = self.regs();
319

            
320
        let ints = reg_block.int_raw().read();
321

            
322
4328
        if ints.end_detect().bit_is_set() {
323
            res.insert(Event::EndDetect);
324
        }
325
4328
        if ints.trans_complete().bit_is_set() {
326
            res.insert(Event::TxComplete);
327
        }
328
        #[cfg(i2c_master_has_tx_fifo_watermark)]
329
4328
        if ints.txfifo_wm().bit_is_set() {
330
            res.insert(Event::TxFifoWatermark);
331
        }
332

            
333
        res
334
    }
335

            
336
    pub(super) fn clear_interrupts(&self, interrupts: EnumSet<Event>) {
337
        let reg_block = self.regs();
338

            
339
        reg_block.int_clr().write(|w| {
340
            for interrupt in interrupts {
341
                match interrupt {
342
                    Event::EndDetect => w.end_detect().clear_bit_by_one(),
343
                    Event::TxComplete => w.trans_complete().clear_bit_by_one(),
344
                    #[cfg(i2c_master_has_tx_fifo_watermark)]
345
                    Event::TxFifoWatermark => w.txfifo_wm().clear_bit_by_one(),
346
                };
347
            }
348
            w
349
        });
350
    }
351
}
352

            
353
impl PartialEq for Info {
354
    fn eq(&self, other: &Self) -> bool {
355
        core::ptr::eq(self.register_block, other.register_block)
356
    }
357
}
358

            
359
unsafe impl Sync for Info {}
360

            
361
pub(super) struct I2cClockGuard {
362
    clock: crate::clock::ll::I2cInstance,
363
}
364

            
365
impl I2cClockGuard {
366
129
    pub(super) fn new(i2c: AnyI2c<'_>) -> Self {
367
        let clock = i2c.info().clock_instance;
368
129
        ClockTree::with(|clocks| clock.request_function_clock(clocks));
369
        Self { clock }
370
129
    }
371
}
372

            
373
impl Drop for I2cClockGuard {
374
129
    fn drop(&mut self) {
375
129
        ClockTree::with(|clocks| self.clock.release_function_clock(clocks));
376
129
    }
377
}
378

            
379
#[derive(Clone, Copy)]
380
enum Deadline {
381
    None,
382
    Fixed(Instant),
383
    PerByte(Duration),
384
}
385

            
386
impl Deadline {
387
237
    fn start(self, data_len: usize) -> Option<Instant> {
388
237
        match self {
389
            Deadline::None => None,
390
            Deadline::Fixed(deadline) => Some(deadline),
391
7
            Deadline::PerByte(duration) => Some(Instant::now() + duration * data_len as u32),
392
        }
393
237
    }
394
}
395

            
396
#[allow(dead_code)] // Some versions don't need `state`
397
#[derive(Clone, Copy)]
398
pub(super) struct Driver<'a> {
399
    pub(super) info: &'a Info,
400
    pub(super) state: &'a State,
401
    pub(super) config: &'a DriverConfig,
402
}
403

            
404
impl Driver<'_> {
405
    fn regs(&self) -> &RegisterBlock {
406
3506
        self.info.regs()
407
    }
408

            
409
60
    pub(super) fn connect_pin(
410
        pin: crate::gpio::interconnect::OutputSignal<'_>,
411
        input: InputSignal,
412
        output: OutputSignal,
413
        guard: &mut PinGuard,
414
    ) {
415
        // avoid the pin going low during configuration
416
        pin.set_output_high(true);
417

            
418
        pin.apply_output_config(
419
            &OutputConfig::default()
420
                .with_drive_mode(DriveMode::OpenDrain)
421
                .with_pull(Pull::Up),
422
        );
423
        pin.set_output_enable(true);
424
        pin.set_input_enable(true);
425

            
426
        input.connect_to(&pin);
427

            
428
60
        *guard = interconnect::OutputSignal::connect_with_guard(pin, output);
429
60
    }
430

            
431
    fn init_master(&self, config: &Config) {
432
        self.regs().ctr().write(|w| {
433
            // Set I2C controller to master mode
434
            w.ms_mode().set_bit();
435
            w.sda_force_out().open_drain();
436
            w.scl_force_out().open_drain();
437
            // Use Most Significant Bit first for sending and receiving data
438
            w.tx_lsb_first().clear_bit();
439
            w.rx_lsb_first().clear_bit();
440

            
441
            w.sample_scl_level()
442
                .bit(config.scl_sample_level == Level::Low);
443

            
444
            #[cfg(i2c_master_has_arbitration_en)]
445
            w.arbitration_en().bit(config.bus_arbitration);
446

            
447
            #[cfg(i2c_master_version = "2")]
448
            w.ref_always_on().set_bit();
449

            
450
            // Ensure that clock is enabled
451
            w.clk_en().set_bit()
452
        });
453
    }
454

            
455
    /// Configures the I2C peripheral with the specified frequency, clocks, and
456
    /// optional timeout.
457
57
    pub(super) fn setup(&self, config: &Config) -> Result<(), ConfigError> {
458
57
        self.init_master(config);
459

            
460
        // Configure filter
461
        // FIXME if we ever change this we need to adapt `set_frequency` for ESP32
462
        set_filter(self.regs(), Some(7), Some(7));
463

            
464
        // Configure frequency
465
        self.set_frequency(config)?;
466

            
467
        // Configure additional timeouts
468
        #[cfg(i2c_master_has_fsm_timeouts)]
469
        {
470
            self.regs()
471
                .scl_st_time_out()
472
                .write(|w| unsafe { w.scl_st_to().bits(config.scl_st_timeout.value()) });
473
            self.regs()
474
                .scl_main_st_time_out()
475
                .write(|w| unsafe { w.scl_main_st_to().bits(config.scl_main_st_timeout.value()) });
476
        }
477

            
478
        self.update_registers();
479

            
480
        Ok(())
481
57
    }
482

            
483
35
    fn do_fsm_reset(&self) {
484
        cfg_select! {
485
            i2c_master_has_reliable_fsm_reset => {
486
                // Device has a working FSM reset mechanism
487
                self.regs().ctr().modify(|_, w| w.fsm_rst().set_bit());
488
            }
489
            _ => {
490
                // Even though C2 and C3 have a FSM reset bit, esp-idf does not
491
                // define I2C_LL_SUPPORT_HW_FSM_RST for them, so include them in the fallback impl.
492

            
493
35
                crate::system::PeripheralClockControl::reset(self.info.peripheral);
494

            
495
                // Restore configuration. This operation has succeeded once, so we can
496
                // assume that the config is valid and we can ignore the result.
497
35
                self.setup(&self.config.config).ok();
498
            }
499
        }
500
    }
501

            
502
    /// Resets the I2C controller (FIFO + FSM + command list).
503
    // This function implements esp-idf's `s_i2c_hw_fsm_reset`
504
    // https://github.com/espressif/esp-idf/blob/27d68f57e6bdd3842cd263585c2c352698a9eda2/components/esp_driver_i2c/i2c_master.c#L115
505
    //
506
    // Make sure you don't call this function in the middle of a transaction. If the
507
    // first command in the command list is not a START, the hardware will hang
508
    // with no timeouts.
509
31
    pub(super) fn reset_fsm(&self, clear_bus: bool) {
510
31
        if clear_bus {
511
4
            self.clear_bus_blocking(true);
512
        } else {
513
31
            self.do_fsm_reset();
514
        }
515
    }
516

            
517
    fn bus_busy(&self) -> bool {
518
        self.regs().sr().read().bus_busy().bit_is_set()
519
115
    }
520

            
521
    fn ensure_idle_blocking(&self) {
522
11
        if self.bus_busy() {
523
            // If the bus is busy, we need to clear it.
524
            self.clear_bus_blocking(false);
525
        }
526
11
    }
527

            
528
115
    async fn ensure_idle(&self) {
529
115
        if self.bus_busy() {
530
            // If the bus is busy, we need to clear it.
531
            self.clear_bus().await;
532
        }
533
    }
534

            
535
237
    fn reset_before_transmission(&self) {
536
        // Clear all I2C interrupts
537
237
        self.clear_all_interrupts();
538

            
539
        // Reset fifo
540
        self.reset_fifo();
541

            
542
        // Reset the command list
543
        self.reset_command_list();
544
237
    }
545

            
546
    /// Implements s_i2c_master_clear_bus.
547
    ///
548
    /// If a transaction ended incorrectly for some reason, the slave may drive SDA
549
    /// indefinitely. Forces the slave to release the bus by sending 9 clock pulses.
550
4
    fn clear_bus_blocking(&self, reset_fsm: bool) {
551
        let mut future = ClearBusFuture::new(*self, reset_fsm);
552
        let start = Instant::now();
553
4
        while future.poll_completion().is_pending() {
554
            if start.elapsed() > CLEAR_BUS_TIMEOUT_MS {
555
                break;
556
            }
557
        }
558
4
    }
559

            
560
    async fn clear_bus(&self) {
561
        let clear_bus = ClearBusFuture::new(*self, true);
562
        let start = Instant::now();
563

            
564
        embassy_futures::select::select(clear_bus, async {
565
            while start.elapsed() < CLEAR_BUS_TIMEOUT_MS {
566
                embassy_futures::yield_now().await;
567
            }
568
        })
569
        .await;
570
    }
571

            
572
1
    pub(super) fn force_scl_low(&self, low: bool) {
573
        cfg_select! {
574
1
            i2c_master_has_pd_en => self.set_scl_pd(low),
575
            _ => self.force_pin_low(low, self.config.scl_pin.pin_number(), &self.info.scl_output),
576
        }
577
1
    }
578

            
579
1
    pub(super) fn force_sda_low(&self, low: bool) {
580
        cfg_select! {
581
1
            i2c_master_has_pd_en => self.set_sda_pd(low),
582
            _ => self.force_pin_low(low, self.config.sda_pin.pin_number(), &self.info.sda_output),
583
        }
584
1
    }
585

            
586
    /// Restores force_out to open-drain mode for both lines.
587
    #[cfg(i2c_master_has_pd_en)]
588
    fn restore_force_out(&self) {
589
        self.regs().ctr().modify(|_, w| {
590
            w.scl_force_out().open_drain();
591
            w.sda_force_out().open_drain()
592
        });
593
        self.update_registers();
594
    }
595

            
596
    #[cfg(not(i2c_master_has_pd_en))]
597
    fn force_pin_low(
598
        &self,
599
        low: bool,
600
        pin_number: Option<u8>,
601
        output_signal: &crate::gpio::OutputSignal,
602
    ) {
603
        use crate::gpio::AnyPin;
604
        let Some(n) = pin_number else { return };
605
        let pin = unsafe { AnyPin::steal(n) };
606
        if low {
607
            pin.set_output_high(false);
608
            output_signal.disconnect_from(&pin);
609
        } else {
610
            output_signal.connect_to(&pin);
611
        }
612
    }
613

            
614
    /// Sets or clears `scl_pd_en`. Switches `scl_force_out` to direct-output while
615
    /// pd_en is active (required on all chips), restoring OD mode when both pd_en
616
    /// bits clear.
617
    #[cfg(i2c_master_has_pd_en)]
618
    fn set_scl_pd(&self, low: bool) {
619
1
        if low {
620
            self.regs()
621
                .ctr()
622
                .modify(|_, w| w.scl_force_out().direct_output());
623
        }
624
        self.regs()
625
            .scl_sp_conf()
626
            .modify(|_, w| w.scl_pd_en().bit(low));
627
1
        if !low {
628
            let sp = self.regs().scl_sp_conf().read();
629
            if sp.scl_pd_en().bit_is_clear() && sp.sda_pd_en().bit_is_clear() {
630
                self.restore_force_out();
631
                return;
632
            }
633
        }
634
        self.update_registers();
635
    }
636

            
637
    /// Sets or clears `sda_pd_en`. Switches `sda_force_out` to direct-output while
638
    /// pd_en is active (required on all chips), restoring OD mode when both pd_en
639
    /// bits clear.
640
    #[cfg(i2c_master_has_pd_en)]
641
    fn set_sda_pd(&self, low: bool) {
642
1
        if low {
643
            self.regs()
644
                .ctr()
645
                .modify(|_, w| w.sda_force_out().direct_output());
646
        }
647
        self.regs()
648
            .scl_sp_conf()
649
            .modify(|_, w| w.sda_pd_en().bit(low));
650
1
        if !low {
651
            let sp = self.regs().scl_sp_conf().read();
652
            if sp.scl_pd_en().bit_is_clear() && sp.sda_pd_en().bit_is_clear() {
653
                self.restore_force_out();
654
                return;
655
            }
656
        }
657
        self.update_registers();
658
    }
659

            
660
    /// Resets the I2C peripheral's command registers.
661
    fn reset_command_list(&self) {
662
        for cmd in self.regs().comd_iter() {
663
            cmd.reset();
664
        }
665
    }
666

            
667
    /// Configures the I2C peripheral for a write operation.
668
    /// - `addr` is the address of the slave device.
669
    /// - `bytes` is the data to be sent
670
    /// - `start` indicates whether the operation should start by a START condition and sending the
671
    ///   address.
672
    /// - `stop` indicates whether the operation will end with a STOP condition.
673
    /// - `cmd_iterator` is an iterator over the command registers.
674
    fn setup_write<'a, I>(
675
        &self,
676
        addr: I2cAddress,
677
        bytes: &[u8],
678
        start: bool,
679
        stop: bool,
680
        cmd_iterator: &mut I,
681
    ) -> Result<(), Error>
682
    where
683
        I: Iterator<Item = &'a COMD>,
684
    {
685
        // If start is true we need to send the address, too, which takes up a data
686
        // byte.
687
126
        let max_len = if start {
688
            I2C_CHUNK_SIZE
689
        } else {
690
            I2C_CHUNK_SIZE + 1
691
        };
692
126
        if bytes.len() > max_len {
693
            return Err(Error::FifoExceeded);
694
        }
695

            
696
126
        if start {
697
            add_cmd(cmd_iterator, Command::Start)?;
698
        }
699

            
700
        let write_len = if start { bytes.len() + 1 } else { bytes.len() };
701
        // don't issue write if there is no data to write
702
        if write_len > 0 {
703
            // ESP32 can't alter the position of END, so we need to split the chunk always into
704
            // 3-command sequences. Chunking makes sure not to place a 1-byte
705
            // command at the end, which would cause an arithmetic underflow.
706
            // The sequences we can generate are:
707
            // - START-WRITE-STOP
708
            // - START-WRITE-END-WRITE-STOP
709
            // - START-WRITE-END-(WRITE-WRITE-END)*-WRITE-STOP sequence.
710
            if cfg!(i2c_master_version = "1") && !(start || stop) {
711
                // Chunks that do not have a START or STOP command need to be split into multiple
712
                // commands.
713
                add_cmd(
714
                    cmd_iterator,
715
                    Command::Write {
716
                        ack_exp: Ack::Ack,
717
                        ack_check_en: true,
718
                        length: (write_len as u8) - 1,
719
                    },
720
                )?;
721
                add_cmd(
722
                    cmd_iterator,
723
                    Command::Write {
724
                        ack_exp: Ack::Ack,
725
                        ack_check_en: true,
726
                        length: 1,
727
                    },
728
                )?;
729
            } else {
730
                add_cmd(
731
                    cmd_iterator,
732
                    Command::Write {
733
                        ack_exp: Ack::Ack,
734
                        ack_check_en: true,
735
                        length: write_len as u8,
736
                    },
737
                )?;
738
            }
739
        }
740

            
741
        if start {
742
            // Load address and R/W bit into FIFO
743
            match addr {
744
                I2cAddress::SevenBit(addr) => {
745
                    self.write_fifo((addr << 1) | OperationType::Write as u8);
746
                }
747
            }
748
        }
749
        for b in bytes {
750
117
            self.write_fifo(*b);
751
        }
752

            
753
        Ok(())
754
    }
755

            
756
    /// Configures the I2C peripheral for a read operation.
757
    /// - `addr` is the address of the slave device.
758
    /// - `buffer` is the buffer to store the read data.
759
    /// - `start` indicates whether the operation should start by a START condition and sending the
760
    ///   address.
761
    /// - `stop` indicates whether the operation will end with a STOP condition.
762
    /// - `will_continue` indicates whether there is another read operation following this one and
763
    ///   the last byte must not be nacked.
764
    /// - `cmd_iterator` is an iterator over the command registers.
765
    fn setup_read<'a, I>(
766
        &self,
767
        addr: I2cAddress,
768
        buffer: &mut [u8],
769
        start: bool,
770
        stop: bool,
771
        will_continue: bool,
772
        cmd_iterator: &mut I,
773
    ) -> Result<(), Error>
774
    where
775
        I: Iterator<Item = &'a COMD>,
776
    {
777
111
        if buffer.is_empty() {
778
            return Err(Error::ZeroLengthInvalid);
779
        }
780
111
        let (max_len, initial_len) = if will_continue {
781
            (I2C_CHUNK_SIZE + 1, buffer.len())
782
        } else {
783
            (I2C_CHUNK_SIZE, buffer.len() - 1)
784
        };
785
111
        if buffer.len() > max_len {
786
            return Err(Error::FifoExceeded);
787
        }
788

            
789
111
        if start {
790
            add_cmd(cmd_iterator, Command::Start)?;
791
            // WRITE 7-bit address
792
            add_cmd(
793
                cmd_iterator,
794
                Command::Write {
795
                    ack_exp: Ack::Ack,
796
                    ack_check_en: true,
797
                    length: 1,
798
                },
799
            )?;
800
        }
801

            
802
111
        if initial_len > 0 {
803
            let extra_commands = if cfg!(i2c_master_version = "1") {
804
                match (start, will_continue) {
805
                    // No chunking (START-WRITE-READ-STOP) or first chunk (START-WRITE-READ-END)
806
                    (true, _) => 0,
807
                    // Middle chunk - (READ-READ-READ-END)
808
                    (false, true) => 2,
809
                    // Last chunk - (READ-READ-STOP-END)
810
                    (false, false) => 1 - stop as u8,
811
                }
812
            } else {
813
                0
814
            };
815

            
816
            add_cmd(
817
                cmd_iterator,
818
                Command::Read {
819
                    ack_value: Ack::Ack,
820
                    length: initial_len as u8 - extra_commands,
821
                },
822
            )?;
823
            for _ in 0..extra_commands {
824
                add_cmd(
825
                    cmd_iterator,
826
                    Command::Read {
827
                        ack_value: Ack::Ack,
828
                        length: 1,
829
                    },
830
                )?;
831
            }
832
        }
833

            
834
        if !will_continue {
835
            // this is the last read so we need to nack the last byte
836
            // READ w/o ACK
837
            add_cmd(
838
                cmd_iterator,
839
                Command::Read {
840
                    ack_value: Ack::Nack,
841
                    length: 1,
842
                },
843
            )?;
844
        }
845

            
846
        self.update_registers();
847

            
848
111
        if start {
849
            // Load address and R/W bit into FIFO
850
            match addr {
851
                I2cAddress::SevenBit(addr) => {
852
111
                    self.write_fifo((addr << 1) | OperationType::Read as u8);
853
                }
854
            }
855
        }
856
        Ok(())
857
    }
858

            
859
    /// Reads from RX FIFO into the given buffer.
860
103
    fn read_all_from_fifo(&self, buffer: &mut [u8]) -> Result<(), Error> {
861
103
        if self.regs().sr().read().rxfifo_cnt().bits() < buffer.len() as u8 {
862
            return Err(Error::ExecutionIncomplete);
863
        }
864

            
865
        // Read bytes from FIFO
866
        for byte in buffer.iter_mut() {
867
2266
            *byte = self.read_fifo();
868
        }
869

            
870
        // The RX FIFO should be empty now. If it is not, it means we queued up reading
871
        // more data than we read, which is an error.
872
103
        debug_assert!(self.regs().sr().read().rxfifo_cnt().bits() == 0);
873

            
874
        Ok(())
875
103
    }
876

            
877
    /// Clears all pending interrupts for the I2C peripheral.
878
    fn clear_all_interrupts(&self) {
879
        self.regs()
880
            .int_clr()
881
            .write(|w| unsafe { w.bits(property!("i2c_master.ll_intr_mask")) });
882
    }
883

            
884
498
    async fn wait_for_completion(&self, deadline: Option<Instant>) -> Result<(), Error> {
885
498
        I2cFuture::new(Event::TxComplete | Event::EndDetect, *self, deadline).await?;
886
211
        self.check_all_commands_done(deadline).await
887
    }
888

            
889
    /// Waits for the completion of an I2C transaction.
890
18
    fn wait_for_completion_blocking(&self, deadline: Option<Instant>) -> Result<(), Error> {
891
        let mut future =
892
            I2cFuture::new_blocking(Event::TxComplete | Event::EndDetect, *self, deadline);
893
        loop {
894
3826
            if let Poll::Ready(result) = future.poll_completion() {
895
                result?;
896
                return self.check_all_commands_done_blocking(deadline);
897
            }
898
        }
899
18
    }
900

            
901
227
    fn all_commands_done(&self, deadline: Option<Instant>) -> Result<bool, Error> {
902
        // NOTE: on esp32 executing the end command generates the end_detect interrupt
903
        //       but does not seem to clear the done bit! So we don't check the done
904
        //       status of an end command
905
227
        let now = if deadline.is_some() {
906
            Instant::now()
907
        } else {
908
            Instant::EPOCH
909
        };
910

            
911
        self.check_errors()?;
912

            
913
        for cmd_reg in self.regs().comd_iter() {
914
            let cmd = cmd_reg.read();
915

            
916
            // if there is a valid command which is not END, check if it's marked as done
917
227
            if cmd.bits() != 0x0 && !cmd.opcode().is_end() && !cmd.command_done().bit_is_set() {
918
                // Let's retry
919
                if let Some(deadline) = deadline
920
                    && now > deadline
921
                {
922
                    return Err(Error::ExecutionIncomplete);
923
                }
924

            
925
                return Ok(false);
926
            }
927

            
928
            // once we hit END or STOP we can break the loop
929
227
            if cmd.opcode().is_end() {
930
                break;
931
            }
932
            if cmd.opcode().is_stop() {
933
                #[cfg(i2c_master_version = "1")]
934
                // wait for STOP - apparently on ESP32 we otherwise miss the ACK error for an
935
                // empty write
936
                if self.regs().sr().read().scl_state_last() == 6 {
937
                    self.check_errors()?;
938
                } else {
939
                    continue;
940
                }
941
                break;
942
            }
943
        }
944
        Ok(true)
945
227
    }
946

            
947
    /// Returns whether all I2C commands have completed execution.
948
    fn check_all_commands_done_blocking(&self, deadline: Option<Instant>) -> Result<(), Error> {
949
        // loop until commands are actually done
950
16
        while !self.all_commands_done(deadline)? {}
951
        self.check_errors()?;
952

            
953
        Ok(())
954
    }
955

            
956
    /// Returns whether all I2C commands have completed execution.
957
211
    async fn check_all_commands_done(&self, deadline: Option<Instant>) -> Result<(), Error> {
958
        // loop until commands are actually done
959
211
        while !self.all_commands_done(deadline)? {
960
            embassy_futures::yield_now().await;
961
        }
962
211
        self.check_errors()?;
963

            
964
        Ok(())
965
211
    }
966

            
967
    /// Checks for I2C transmission errors and handles them.
968
    ///
969
    /// Inspects specific I2C-related interrupts to detect errors during
970
    /// communication, such as timeouts, failed acknowledgments, or arbitration loss.
971
    /// If an error is detected, resets the I2C peripheral to clear the error condition
972
    /// and returns an appropriate error.
973
4322
    fn check_errors(&self) -> Result<(), Error> {
974
        let r = self.regs().int_raw().read();
975

            
976
        // Handle error cases
977
4328
        if r.nack().bit_is_set() {
978
            return Err(Error::AcknowledgeCheckFailed(estimate_ack_failed_reason(
979
                self.regs(),
980
            )));
981
        }
982
4324
        if r.arbitration_lost().bit_is_set() {
983
            return Err(Error::ArbitrationLost);
984
        }
985

            
986
        #[cfg(not(i2c_master_version = "1"))]
987
4322
        if r.trans_complete().bit_is_set() && self.regs().sr().read().resp_rec().bit_is_clear() {
988
            return Err(Error::AcknowledgeCheckFailed(
989
                AcknowledgeCheckFailedReason::Data,
990
            ));
991
        }
992

            
993
        #[cfg(i2c_master_has_fsm_timeouts)]
994
        {
995
4322
            if r.scl_st_to().bit_is_set() {
996
                return Err(Error::Timeout);
997
            }
998
            if r.scl_main_st_to().bit_is_set() {
999
                return Err(Error::Timeout);
            }
        }
        if r.time_out().bit_is_set() {
            return Err(Error::Timeout);
        }
        Ok(())
211
    }
    /// Updates the configuration of the I2C peripheral.
    ///
    /// Ensures that configuration values, such as clock settings, SDA/SCL filtering,
    /// timeouts, and other operational parameters configured in other methods, are
    /// propagated to the I2C hardware. This step synchronizes the software-configured
    /// settings with the peripheral's internal registers.
    fn update_registers(&self) {
        // Ensure that the configuration of the peripheral is correctly propagated
        // (only necessary for C2, C3, C6, H2 and S3 variant)
        #[cfg(i2c_master_has_conf_update)]
        self.regs().ctr().modify(|_, w| w.conf_upgate().set_bit());
    }
    fn set_frequency(&self, config: &Config) -> Result<(), ConfigError> {
        version::set_frequency(self, config)
    }
    fn reset_fifo(&self) {
        version::reset_fifo(self);
    }
    fn read_fifo(&self) -> u8 {
        version::read_fifo(self.regs())
    }
    fn write_fifo(&self, data: u8) {
        version::write_fifo(self.regs(), data);
    }
    /// Starts an I2C transmission.
    fn start_transmission(&self) {
        // Start transmission
        self.regs().ctr().modify(|_, w| w.trans_start().set_bit());
    }
126
    fn start_write_operation(
        &self,
        address: I2cAddress,
        buffer: &[u8],
        start: bool,
        stop: bool,
        deadline: Deadline,
    ) -> Result<Option<Instant>, Error> {
        let cmd_iterator = &mut self.regs().comd_iter();
        self.setup_write(address, buffer, start, stop, cmd_iterator)?;
126
        if stop {
            add_cmd(cmd_iterator, Command::Stop)?;
        }
9
        if !(start && stop) {
            // Multi-chunk write, terminate with END. ESP32 TRM suggests a write should work with
            // only a STOP at the end, but STOP does not seem to generate a TX_COMPLETE interrupt
            // without END.
            add_cmd(cmd_iterator, Command::End)?;
        }
        self.start_transmission();
126
        Ok(deadline.start(buffer.len() + address.bytes()))
126
    }
    /// Executes an I2C read operation.
    /// - `addr` is the address of the slave device.
    /// - `buffer` is the buffer to store the read data.
    /// - `start` indicates whether the operation should start by a START condition and sending the
    ///   address.
    /// - `stop` indicates whether the operation should end with a STOP condition.
    /// - `will_continue` indicates whether there is another read operation following this one and
    ///   the last byte must not be nacked.
    /// - `cmd_iterator` is an iterator over the command registers.
111
    fn start_read_operation(
        &self,
        address: I2cAddress,
        buffer: &mut [u8],
        start: bool,
        will_continue: bool,
        stop: bool,
        deadline: Deadline,
    ) -> Result<Option<Instant>, Error> {
        // We don't support single I2C reads larger than the FIFO. This should be
        // enforced by `VariableChunkIterMut` used in `Driver::read` and
        // `Driver::read_async`.
111
        debug_assert!(buffer.len() <= I2C_FIFO_SIZE);
        let cmd_iterator = &mut self.regs().comd_iter();
        self.setup_read(address, buffer, start, stop, will_continue, cmd_iterator)?;
111
        if stop {
            add_cmd(cmd_iterator, Command::Stop)?;
        }
110
        if !(start && stop) {
            // Multi-chunk read, terminate with END. On ESP32, assume same limitation as writes.
            add_cmd(cmd_iterator, Command::End)?;
        }
        self.start_transmission();
111
        Ok(deadline.start(buffer.len() + address.bytes()))
111
    }
    /// Executes an I2C write operation.
    /// - `addr` is the address of the slave device.
    /// - `bytes` is the data to be sent
    /// - `start` indicates whether the operation should start by a START condition and sending the
    ///   address.
    /// - `stop` indicates whether the operation should end with a STOP condition.
    /// - `cmd_iterator` is an iterator over the command registers.
    fn write_operation_blocking(
        &self,
        address: I2cAddress,
        bytes: &[u8],
        start: bool,
        stop: bool,
        deadline: Deadline,
    ) -> Result<(), Error> {
        address.validate()?;
8
        self.reset_before_transmission();
        // Short circuit for zero length writes without start or end as that would be an
        // invalid operation write lengths in the TRM (at least for ESP32-S3) are 1-255
3
        if bytes.is_empty() && !start && !stop {
            return Ok(());
        }
8
        let deadline = self.start_write_operation(address, bytes, start, stop, deadline)?;
8
        self.wait_for_completion_blocking(deadline)?;
        Ok(())
    }
    /// Executes an I2C read operation.
    /// - `addr` is the address of the slave device.
    /// - `buffer` is the buffer to store the read data.
    /// - `start` indicates whether the operation should start by a START condition and sending the
    ///   address.
    /// - `stop` indicates whether the operation should end with a STOP condition.
    /// - `will_continue` indicates whether there is another read operation following this one and
    ///   the last byte must not be nacked.
    /// - `cmd_iterator` is an iterator over the command registers.
    fn read_operation_blocking(
        &self,
        address: I2cAddress,
        buffer: &mut [u8],
        start: bool,
        stop: bool,
        will_continue: bool,
        deadline: Deadline,
    ) -> Result<(), Error> {
        address.validate()?;
7
        self.reset_before_transmission();
        // Short circuit for zero length reads as that would be an invalid operation
        // read lengths in the TRM (at least for ESP32-S3) are 1-255
        if buffer.is_empty() {
            return Ok(());
        }
        let deadline =
7
            self.start_read_operation(address, buffer, start, will_continue, stop, deadline)?;
7
        self.wait_for_completion_blocking(deadline)?;
        self.read_all_from_fifo(buffer)?;
        Ok(())
    }
    /// Executes an async I2C write operation.
    /// - `addr` is the address of the slave device.
    /// - `bytes` is the data to be sent
    /// - `start` indicates whether the operation should start by a START condition and sending the
    ///   address.
    /// - `stop` indicates whether the operation should end with a STOP condition.
    /// - `cmd_iterator` is an iterator over the command registers.
    async fn write_operation(
115
        &self,
115
        address: I2cAddress,
        bytes: &[u8],
        start: bool,
        stop: bool,
        deadline: Deadline,
237
    ) -> Result<(), Error> {
115
        address.validate()?;
115
        self.reset_before_transmission();
        // Short circuit for zero length writes without start or end as that would be an
        // invalid operation write lengths in the TRM (at least for ESP32-S3) are 1-255
115
        if bytes.is_empty() && !start && !stop {
            return Ok(());
        }
115
        let deadline = self.start_write_operation(address, bytes, start, stop, deadline)?;
125
        self.wait_for_completion(deadline).await?;
        Ok(())
112
    }
    /// Executes an async I2C read operation.
    /// - `addr` is the address of the slave device.
    /// - `buffer` is the buffer to store the read data.
    /// - `start` indicates whether the operation should start by a START condition and sending the
    ///   address.
    /// - `stop` indicates whether the operation should end with a STOP condition.
    /// - `will_continue` indicates whether there is another read operation following this one and
    ///   the last byte must not be nacked.
    /// - `cmd_iterator` is an iterator over the command registers.
    async fn read_operation(
104
        &self,
104
        address: I2cAddress,
104
        buffer: &mut [u8],
        start: bool,
        stop: bool,
        will_continue: bool,
        deadline: Deadline,
157
    ) -> Result<(), Error> {
104
        address.validate()?;
104
        self.reset_before_transmission();
        // Short circuit for zero length reads as that would be an invalid operation
        // read lengths in the TRM (at least for ESP32-S3) are 1-255
104
        if buffer.is_empty() {
            return Ok(());
        }
        let deadline =
104
            self.start_read_operation(address, buffer, start, will_continue, stop, deadline)?;
261
        self.wait_for_completion(deadline).await?;
103
        self.read_all_from_fifo(buffer)?;
        Ok(())
103
    }
7
    fn read_blocking(
        &self,
        address: I2cAddress,
        buffer: &mut [u8],
        start: bool,
        stop: bool,
        will_continue: bool,
        deadline: Deadline,
    ) -> Result<(), Error> {
        let chunk_count = VariableChunkIterMut::new(buffer).count();
        for (idx, chunk) in VariableChunkIterMut::new(buffer).enumerate() {
            self.read_operation_blocking(
                address,
                chunk,
                start && idx == 0,
7
                stop && idx == chunk_count - 1,
7
                will_continue || idx < chunk_count - 1,
                deadline,
            )?;
        }
        Ok(())
7
    }
11
    fn write_blocking(
        &self,
        address: I2cAddress,
        buffer: &[u8],
        start: bool,
        stop: bool,
        deadline: Deadline,
    ) -> Result<(), Error> {
11
        if buffer.is_empty() {
            return self.write_operation_blocking(address, &[], start, stop, deadline);
        }
        let chunk_count = VariableChunkIter::new(buffer).count();
        for (idx, chunk) in VariableChunkIter::new(buffer).enumerate() {
            self.write_operation_blocking(
                address,
                chunk,
8
                start && idx == 0,
                stop && idx == chunk_count - 1,
                deadline,
            )?;
        }
        Ok(())
11
    }
    async fn read(
104
        &self,
104
        address: I2cAddress,
104
        buffer: &mut [u8],
104
        start: bool,
        stop: bool,
104
        will_continue: bool,
104
        deadline: Deadline,
157
    ) -> Result<(), Error> {
104
        let chunk_count = VariableChunkIterMut::new(buffer).count();
104
        for (idx, chunk) in VariableChunkIterMut::new(buffer).enumerate() {
104
            self.read_operation(
104
                address,
                chunk,
104
                start && idx == 0,
104
                stop && idx == chunk_count - 1,
104
                will_continue || idx < chunk_count - 1,
104
                deadline,
            )
158
            .await?;
        }
        Ok(())
103
    }
    async fn write(
115
        &self,
115
        address: I2cAddress,
115
        buffer: &[u8],
115
        start: bool,
115
        stop: bool,
115
        deadline: Deadline,
122
    ) -> Result<(), Error> {
115
        if buffer.is_empty() {
6
            return self
                .write_operation(address, &[], start, stop, deadline)
120
                .await;
        }
109
        let chunk_count = VariableChunkIter::new(buffer).count();
109
        for (idx, chunk) in VariableChunkIter::new(buffer).enumerate() {
109
            self.write_operation(
109
                address,
                chunk,
109
                start && idx == 0,
109
                stop && idx == chunk_count - 1,
109
                deadline,
            )
226
            .await?;
        }
        Ok(())
112
    }
11
    pub(super) fn transaction_impl<'a>(
        &self,
        address: I2cAddress,
        operations: impl Iterator<Item = Operation<'a>>,
    ) -> Result<(), Error> {
        address.validate()?;
11
        self.ensure_idle_blocking();
        let mut deadline = Deadline::None;
11
        if let SoftwareTimeout::Transaction(timeout) = self.config.config.software_timeout {
            deadline = Deadline::Fixed(Instant::now() + timeout);
        }
        let mut last_op: Option<OpKind> = None;
        // filter out 0 length read operations
        let mut op_iter = operations
            .filter(|op| op.is_write() || !op.is_empty())
            .peekable();
        while let Some(op) = op_iter.next() {
            let next_op = op_iter.peek().map(|v| v.kind());
            let kind = op.kind();
18
            match op {
                Operation::Write(buffer) => {
                    // execute a write operation:
                    // - issue START/RSTART if op is different from previous
                    // - issue STOP if op is the last one
11
                    if let SoftwareTimeout::PerByte(timeout) = self.config.config.software_timeout {
                        deadline = Deadline::PerByte(timeout);
                    }
11
                    self.write_blocking(
                        address,
                        buffer,
11
                        !matches!(last_op, Some(OpKind::Write)),
                        next_op.is_none(),
                        deadline,
                    )?;
                }
                Operation::Read(buffer) => {
7
                    if let SoftwareTimeout::PerByte(timeout) = self.config.config.software_timeout {
                        deadline = Deadline::PerByte(timeout);
                    }
                    // execute a read operation:
                    // - issue START/RSTART if op is different from previous
                    // - issue STOP if op is the last one
                    // - will_continue is true if there is another read operation next
7
                    self.read_blocking(
                        address,
                        buffer,
7
                        !matches!(last_op, Some(OpKind::Read)),
                        next_op.is_none(),
                        matches!(next_op, Some(OpKind::Read)),
                        deadline,
                    )?;
                }
            }
16
            last_op = Some(kind);
        }
        Ok(())
11
    }
    pub(super) async fn transaction_impl_async<'a>(
115
        &self,
115
        address: I2cAddress,
115
        operations: impl Iterator<Item = Operation<'a>>,
394
    ) -> Result<(), Error> {
115
        address.validate()?;
115
        self.ensure_idle().await;
115
        let mut deadline = Deadline::None;
115
        if let SoftwareTimeout::Transaction(timeout) = self.config.config.software_timeout {
            deadline = Deadline::Fixed(Instant::now() + timeout);
        }
        let mut last_op: Option<OpKind> = None;
        // filter out 0 length read operations
115
        let mut op_iter = operations
            .filter(|op| op.is_write() || !op.is_empty())
            .peekable();
219
        while let Some(op) = op_iter.next() {
219
            let next_op = op_iter.peek().map(|v| v.kind());
219
            let kind = op.kind();
219
            match op {
                Operation::Write(buffer) => {
115
                    if let SoftwareTimeout::PerByte(timeout) = self.config.config.software_timeout {
1
                        deadline = Deadline::PerByte(timeout);
                    }
                    // execute a write operation:
                    // - issue START/RSTART if op is different from previous
                    // - issue STOP if op is the last one
115
                    self.write(
115
                        address,
                        buffer,
115
                        !matches!(last_op, Some(OpKind::Write)),
                        next_op.is_none(),
114
                        deadline,
                    )
237
                    .await?;
                }
                Operation::Read(buffer) => {
104
                    if let SoftwareTimeout::PerByte(timeout) = self.config.config.software_timeout {
1
                        deadline = Deadline::PerByte(timeout);
                    }
                    // execute a read operation:
                    // - issue START/RSTART if op is different from previous
                    // - issue STOP if op is the last one
                    // - will_continue is true if there is another read operation next
104
                    self.read(
104
                        address,
                        buffer,
104
                        !matches!(last_op, Some(OpKind::Read)),
                        next_op.is_none(),
                        matches!(next_op, Some(OpKind::Read)),
103
                        deadline,
                    )
158
                    .await?;
                }
            }
211
            last_op = Some(kind);
        }
        Ok(())
111
    }
}
/// Chunks a slice by I2C_CHUNK_SIZE in a way to avoid the last chunk being
/// sized smaller than 2
struct VariableChunkIterMut<'a, T> {
    buffer: &'a mut [T],
}
impl<'a, T> VariableChunkIterMut<'a, T> {
    fn new(buffer: &'a mut [T]) -> Self {
        Self { buffer }
    }
}
impl<'a, T> Iterator for VariableChunkIterMut<'a, T> {
    type Item = &'a mut [T];
    fn next(&mut self) -> Option<Self::Item> {
111
        if self.buffer.is_empty() {
            return None;
        }
        let s = calculate_chunk_size(self.buffer.len());
104
        let (chunk, remaining) = core::mem::take(&mut self.buffer).split_at_mut(s);
104
        self.buffer = remaining;
        Some(chunk)
    }
}
/// Chunks a slice by I2C_CHUNK_SIZE in a way to avoid the last chunk being
/// sized smaller than 2
struct VariableChunkIter<'a, T> {
    buffer: &'a [T],
}
impl<'a, T> VariableChunkIter<'a, T> {
    fn new(buffer: &'a [T]) -> Self {
        Self { buffer }
    }
}
impl<'a, T> Iterator for VariableChunkIter<'a, T> {
    type Item = &'a [T];
    fn next(&mut self) -> Option<Self::Item> {
109
        if self.buffer.is_empty() {
            return None;
        }
        let s = calculate_chunk_size(self.buffer.len());
109
        let (chunk, remaining) = core::mem::take(&mut self.buffer).split_at(s);
109
        self.buffer = remaining;
        Some(chunk)
    }
}
fn calculate_chunk_size(remaining: usize) -> usize {
111
    if remaining <= I2C_CHUNK_SIZE {
        remaining
    } else if remaining > I2C_CHUNK_SIZE + 2 {
        I2C_CHUNK_SIZE
    } else {
        I2C_CHUNK_SIZE - 2
    }
}
#[cfg(i2c_master_has_hw_bus_clear)]
mod bus_clear {
    use esp_rom_sys::rom::ets_delay_us;
    use super::*;
    #[must_use = "futures do nothing unless you `.await` or poll them"]
    pub struct ClearBusFuture<'a> {
        driver: Driver<'a>,
    }
    impl<'a> ClearBusFuture<'a> {
        // Number of SCL pulses to clear the bus
        const BUS_CLEAR_BITS: u8 = 9;
        const DELAY_US: u32 = 5; // 5us -> 100kHz
        pub fn new(driver: Driver<'a>, reset_fsm: bool) -> Self {
            // If we have a HW implementation, reset FSM to make sure it's not trying to transmit
            // while we clear the bus.
4
            if reset_fsm {
                // Resetting the FSM may still generate a short SCL pulse, but I don't know how to
                // work around it - just waiting doesn't solve anything if the hardware is running.
4
                driver.do_fsm_reset();
            }
4
            let mut this = Self { driver };
            // Prevent SCL from going low immediately after FSM reset/previous operation has set
            // it high
            ets_delay_us(Self::DELAY_US);
            this.configure(Self::BUS_CLEAR_BITS);
4
            this
        }
        fn configure(&mut self, bits: u8) {
            self.driver.regs().scl_sp_conf().modify(|_, w| {
                unsafe { w.scl_rst_slv_num().bits(bits) };
                w.scl_rst_slv_en().bit(bits > 0)
            });
            self.driver.update_registers();
        }
        fn is_done(&self) -> bool {
            self.driver
                .regs()
                .scl_sp_conf()
                .read()
                .scl_rst_slv_en()
                .bit_is_clear()
        }
        pub fn poll_completion(&mut self) -> Poll<()> {
            if self.is_done() {
                Poll::Ready(())
            } else {
                Poll::Pending
            }
        }
    }
    impl Drop for ClearBusFuture<'_> {
4
        fn drop(&mut self) {
            use crate::gpio::AnyPin;
4
            if !self.is_done() {
                self.configure(0);
            }
            // Generate a stop condition
4
            let sda = self
                .driver
                .config
                .sda_pin
                .pin_number()
                .map(|n| unsafe { AnyPin::steal(n) });
            let scl = self
                .driver
                .config
                .scl_pin
                .pin_number()
                .map(|n| unsafe { AnyPin::steal(n) });
4
            if let (Some(sda), Some(scl)) = (sda, scl) {
                // Prevent short SCL pulse right after HW clearing completes
                ets_delay_us(Self::DELAY_US);
                sda.set_output_high(true);
                scl.set_output_high(false);
                self.driver.info.scl_output.disconnect_from(&scl);
                self.driver.info.sda_output.disconnect_from(&sda);
                // Set SDA low - whatever state it was in, we need a low -> high transition.
                sda.set_output_high(false);
                ets_delay_us(Self::DELAY_US);
                // Set SCL high to prepare for STOP condition
                scl.set_output_high(true);
                ets_delay_us(Self::DELAY_US);
                // STOP
                sda.set_output_high(true);
                ets_delay_us(Self::DELAY_US);
4
                self.driver.info.sda_output.connect_to(&sda);
4
                self.driver.info.scl_output.connect_to(&scl);
            }
            // We don't care about errors during bus clearing
            self.driver.clear_all_interrupts();
4
        }
    }
}
#[cfg(not(i2c_master_has_hw_bus_clear))]
mod bus_clear {
    use super::*;
    use crate::gpio::AnyPin;
    /// State of the bus clearing operation.
    ///
    /// Pins are changed on the start of the state, and a wait is scheduled
    /// for the end of the state. At the end of the wait, the state is
    /// updated to the next state.
    enum State {
        Idle,
        SendStop,
        // Number of SCL pulses left to send, and the last SCL level.
        //
        // Our job is to send 9 high->low SCL transitions, followed by a STOP condition.
        SendClock(u8, bool),
    }
    #[must_use = "futures do nothing unless you `.await` or poll them"]
    pub struct ClearBusFuture<'a> {
        driver: Driver<'a>,
        wait: Instant,
        state: State,
        reset_fsm: bool,
        pins: Option<(AnyPin<'static>, AnyPin<'static>)>,
    }
    impl<'a> ClearBusFuture<'a> {
        // Number of SCL pulses to clear the bus (max 8 data bits sent by the device, + NACK)
        const BUS_CLEAR_BITS: u8 = 9;
        // use standard 100kHz data rate
        const SCL_DELAY: Duration = Duration::from_micros(5);
        pub fn new(driver: Driver<'a>, reset_fsm: bool) -> Self {
            let sda = driver
                .config
                .sda_pin
                .pin_number()
                .map(|n| unsafe { AnyPin::steal(n) });
            let scl = driver
                .config
                .scl_pin
                .pin_number()
                .map(|n| unsafe { AnyPin::steal(n) });
            let (Some(sda), Some(scl)) = (sda, scl) else {
                // If we don't have the pins, we can't clear the bus.
                if reset_fsm {
                    driver.do_fsm_reset();
                }
                return Self {
                    driver,
                    wait: Instant::now(),
                    state: State::Idle,
                    reset_fsm: false,
                    pins: None,
                };
            };
            sda.set_output_high(true);
            scl.set_output_high(false);
            driver.info.scl_output.disconnect_from(&scl);
            driver.info.sda_output.disconnect_from(&sda);
            // Starting from (9, false), becase:
            // - we start with SCL low
            // - a complete SCL cycle consists of a high period and a low period
            // - we decrement the remaining counter at the beginning of a cycle, which gives us 9
            //   complete SCL cycles.
            let state = State::SendClock(Self::BUS_CLEAR_BITS, false);
            Self {
                driver,
                wait: Instant::now() + Self::SCL_DELAY,
                state,
                reset_fsm,
                pins: Some((sda, scl)),
            }
        }
    }
    impl ClearBusFuture<'_> {
        pub fn poll_completion(&mut self) -> Poll<()> {
            let now = Instant::now();
            match self.state {
                State::Idle => {
                    if let Some((sda, _scl)) = self.pins.as_ref() {
                        // Pins are disconnected from the peripheral, we can't use `bus_busy`.
                        if !sda.is_input_high() {
                            return Poll::Pending;
                        }
                    }
                    return Poll::Ready(());
                }
                _ if now < self.wait => {
                    // Still waiting for the end of the SCL pulse
                    return Poll::Pending;
                }
                State::SendStop => {
                    if let Some((sda, _scl)) = self.pins.as_ref() {
                        sda.set_output_high(true); // STOP, SDA low -> high while SCL is HIGH
                    }
                    self.state = State::Idle;
                    return Poll::Pending;
                }
                State::SendClock(0, false) => {
                    if let Some((sda, scl)) = self.pins.as_ref() {
                        // Set up for STOP condition
                        sda.set_output_high(false);
                        scl.set_output_high(true);
                    }
                    self.state = State::SendStop;
                }
                State::SendClock(n, false) => {
                    if let Some((sda, scl)) = self.pins.as_ref() {
                        scl.set_output_high(true);
                        if sda.is_input_high() {
                            sda.set_output_high(false);
                            // The device has released SDA, we can move on to generating a STOP
                            // condition
                            self.wait = Instant::now() + Self::SCL_DELAY;
                            self.state = State::SendStop;
                            return Poll::Pending;
                        }
                    }
                    self.state = State::SendClock(n - 1, true);
                }
                State::SendClock(n, true) => {
                    if let Some((_sda, scl)) = self.pins.as_ref() {
                        scl.set_output_high(false);
                    }
                    self.state = State::SendClock(n, false);
                }
            }
            self.wait = Instant::now() + Self::SCL_DELAY;
            Poll::Pending
        }
    }
    impl Drop for ClearBusFuture<'_> {
        fn drop(&mut self) {
            if let Some((sda, scl)) = self.pins.take() {
                // Make sure _we_ release the bus.
                scl.set_output_high(true);
                sda.set_output_high(true);
                // If we don't have a HW implementation, reset the peripheral after clearing the
                // bus, but before we reconnect the pins in Drop. This should prevent glitches.
                if self.reset_fsm {
                    self.driver.do_fsm_reset();
                }
                self.driver.info.sda_output.connect_to(&sda);
                self.driver.info.scl_output.connect_to(&scl);
                // We don't care about errors during bus clearing. There shouldn't be any,
                // anyway.
                self.driver.clear_all_interrupts();
            }
        }
    }
}
use bus_clear::ClearBusFuture;
impl Future for ClearBusFuture<'_> {
    type Output = ();
    fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
        let pending = self.poll_completion();
        if pending.is_pending() {
            ctx.waker().wake_by_ref();
        }
        pending
    }
}
/// Peripheral state for an I2C instance.
#[doc(hidden)]
#[non_exhaustive]
pub struct State {
    /// Waker for the asynchronous operations.
    pub waker: AtomicWaker,
}
/// A peripheral singleton compatible with the I2C master driver.
pub trait Instance: crate::private::Sealed + any::Degrade {
    #[doc(hidden)]
    /// Returns the peripheral data and state describing this instance.
    fn parts(&self) -> (&Info, &State);
    /// Returns the peripheral data describing this instance.
    #[doc(hidden)]
    #[inline(always)]
    fn info(&self) -> &Info {
        self.parts().0
    }
    /// Returns the peripheral state for this instance.
    #[doc(hidden)]
    #[inline(always)]
    fn state(&self) -> &State {
        self.parts().1
    }
}
/// Adds a command to the I2C command sequence.
///
/// The first command after a FSM reset must be a START, otherwise
/// the hardware will hang with no timeouts.
fn add_cmd<'a, I>(cmd_iterator: &mut I, command: Command) -> Result<(), Error>
where
    I: Iterator<Item = &'a COMD>,
{
    let cmd = cmd_iterator.next().ok_or(Error::CommandNumberExceeded)?;
    cmd.write(|w| match command {
        Command::Start => w.opcode().rstart(),
        Command::Stop => w.opcode().stop(),
        Command::End => w.opcode().end(),
        Command::Write {
            ack_exp,
            ack_check_en,
            length,
        } => unsafe {
            w.opcode().write();
            w.ack_exp().bit(ack_exp == Ack::Nack);
            w.ack_check_en().bit(ack_check_en);
            w.byte_num().bits(length);
            w
        },
        Command::Read { ack_value, length } => unsafe {
            w.opcode().read();
            w.ack_value().bit(ack_value == Ack::Nack);
            w.byte_num().bits(length);
            w
        },
    });
    Ok(())
}
// Estimate the reason for an acknowledge check failure on a best effort basis.
// When in doubt it's better to return `Unknown` than to return a wrong reason.
fn estimate_ack_failed_reason(_register_block: &RegisterBlock) -> AcknowledgeCheckFailedReason {
    cfg_select! {
        i2c_master_can_estimate_nack_reason => {
            // this is based on observations rather than documented behavior
            if _register_block.fifo_st().read().txfifo_raddr().bits() <= 1 {
                AcknowledgeCheckFailedReason::Address
            } else {
                AcknowledgeCheckFailedReason::Data
            }
        }
        _ => AcknowledgeCheckFailedReason::Unknown,
    }
}
for_each_i2c_master!(
    ($id:literal, $inst:ident, $peri:ident, $scl:ident, $sda:ident) => {
        impl Instance for crate::peripherals::$inst<'_> {
            fn parts(&self) -> (&Info, &State) {
                #[handler]
                #[ram]
215
                pub(super) fn irq_handler() {
215
                    async_handler(&PERIPHERAL, &STATE);
                }
                static STATE: State = State {
                    waker: AtomicWaker::new(),
                };
                static PERIPHERAL: Info = Info {
                    #[cfg(soc_has_i2c1)]
                    id: $id,
                    register_block: crate::peripherals::$inst::ptr(),
                    peripheral: crate::system::Peripheral::$peri,
                    async_handler: irq_handler,
                    scl_output: OutputSignal::$scl,
                    scl_input: InputSignal::$scl,
                    sda_output: OutputSignal::$sda,
                    sda_input: InputSignal::$sda,
                    clock_instance: paste::paste! { crate::soc::clocks::I2cInstance::[<I2c $id>] },
                };
                (&PERIPHERAL, &STATE)
            }
        }
    };
);
crate::any_peripheral! {
    /// Any I2C peripheral.
    pub peripheral AnyI2c<'d> {
        #[cfg(i2c_master_i2c0)]
        I2c0(crate::peripherals::I2C0<'d>),
        #[cfg(i2c_master_i2c1)]
        I2c1(crate::peripherals::I2C1<'d>),
    }
}
impl Instance for AnyI2c<'_> {
    fn parts(&self) -> (&Info, &State) {
        any::delegate!(self, i2c => { i2c.parts() })
    }
}
impl AnyI2c<'_> {
    fn bind_peri_interrupt(&self, handler: InterruptHandler) {
        any::delegate!(self, i2c => { i2c.bind_peri_interrupt(handler) })
    }
    pub(super) fn disable_peri_interrupt_on_all_cores(&self) {
        any::delegate!(self, i2c => { i2c.disable_peri_interrupt_on_all_cores() })
    }
    pub(super) fn set_interrupt_handler(&self, handler: InterruptHandler) {
        self.disable_peri_interrupt_on_all_cores();
        self.info().enable_listen(EnumSet::all(), false);
        self.info().clear_interrupts(EnumSet::all());
        self.bind_peri_interrupt(handler);
    }
}