dif_i2c.h
To use this DIF, include the following C header:
#include "sw/device/lib/dif/dif_i2c.h"
This header provides the following device interface functions:
dif_i2c_ack_ctrl_set_enabledEnables or disables the ACK Control Mode functionality.dif_i2c_acquire_byteRead acquired data from the ACQ FIFO, including record of starts, stops, address and written data.dif_i2c_addr_nack_set_enabledEnables or disables the functionality to NACK when timing out on an address (N)ACK phase stretch.dif_i2c_clear_controller_halt_eventsClear the selected events that contributed to the controller halting, if any.dif_i2c_clear_target_tx_halt_eventsClear the selected events that are contributing or would contribute to the target halting and stretching the clock on a read.dif_i2c_compute_timingComputes timing parameters for an I2C host and stores them inconfig.dif_i2c_configureConfigures I2C with runtime information.dif_i2c_device_set_enabledEnables or disables the "Device I2C" functionality, This function should be called to enable the device once address, and interrupts are all configured.dif_i2c_enable_clock_timeoutEnables clock timeout after a number of I2C block clock cycles when I2C block is configured as host.dif_i2c_get_auto_ack_countRead the current value of the Auto ACK Counter.dif_i2c_get_controller_halt_eventsGet the events that contributed to the controller halting, if any.dif_i2c_get_fifo_levelsReturns the current levels, i.e., number of entries, in the FMT, RX, TX and ACQ FIFOs.dif_i2c_get_pending_acq_byteGet the pending data byte when stretching due to Auto Ack Count exhaustion.dif_i2c_get_statusGet I2C status.dif_i2c_get_target_tx_halt_eventsGet the events that are contributing or would contribute to the target halting and stretching the clock on a read.dif_i2c_host_set_enabledEnables or disables the "Host I2C" functionality, This function should be called to enable the device once timings, interrupts, and watermarks are all configured.dif_i2c_line_loopback_set_enabledEnables or disables the Line Loopback functionality, This function should be called to assist debugging by setting the i2c block or host to use received transactions to populate outgoing transactions.dif_i2c_multi_controller_monitor_set_enabledEnables or disables the bus monitor's multi-controller functionality.dif_i2c_nack_transactionInstruct the I2C Target module to issue a NACK for the current transaction.dif_i2c_override_drive_pinsDrives the SCL and SDA pins to the given values when "override mode" is enabled.dif_i2c_override_sample_pinsReturns oversampling of the last 16 values of the SCL and SDA pins, with the zeroth bit being the most recent.dif_i2c_override_set_enabledEnables or disables the "override mode".dif_i2c_read_bytePops an entry (a byte) off of the RX FIFO.dif_i2c_read_bytesReads off a chunk of bytes from the RX FIFO.dif_i2c_reset_acq_fifoResets the state of the ACQ FIFO, essentially dropping all received bytes for the target device.dif_i2c_reset_fmt_fifoResets the state of the FMT FIFO, essentially dropping all scheduled operations.dif_i2c_reset_rx_fifoResets the state of the RX FIFO, essentially dropping all received bytes for the host.dif_i2c_reset_tx_fifoResets the state of the TX FIFO, essentially dropping all scheduled responses.dif_i2c_set_auto_ack_countReloads the Auto ACK Counter with the provided value.dif_i2c_set_device_idSets the I2C device to listen for a pair of masked addresses.dif_i2c_set_host_timeoutSet host timeout.dif_i2c_set_host_watermarksSets watermarks for the RX and FMT FIFOs, which will assert the corresponding interrupts whenever the levels in the FIFOs are above (RX) and below (FMT) the set levels.dif_i2c_set_target_watermarksSets watermarks for the TX and ACQ FIFOs, which will assert the corresponding interrupts whenever the levels in the FIFOs are below (TX) and above (ACQ) the set levels.dif_i2c_target_tx_stretch_ctrl_set_enabledEnables or disables the target FSM's stretch control for the start of read transactions.dif_i2c_transmit_bytePushes a byte into the TX FIFO to make it available when this I2C block responds to an I2C Read as a target device.dif_i2c_write_bytePushes a write entry onto the FMT FIFO, consisting of a byte and a format code.dif_i2c_write_byte_rawPushes a raw write entry onto the FMT FIFO, consisting of a byte and format flags.dif_i2c_write_bytes_rawWrites a chunk of raw bytes and format flags onto the FMT FIFO.
Generated from dif_i2c.h
// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
#ifndef OPENTITAN_SW_DEVICE_LIB_DIF_DIF_I2C_H_
#define OPENTITAN_SW_DEVICE_LIB_DIF_DIF_I2C_H_
/**
* @file
* @brief <a href="/book/hw/ip/i2c/">I2C</a> Device Interface Functions
*/
#include <stdbool.h>
#include <stdint.h>
#include "sw/device/lib/base/macros.h"
#include "sw/device/lib/base/mmio.h"
#include "sw/device/lib/dif/dif_base.h"
#include "sw/device/lib/dif/autogen/dif_i2c_autogen.h"
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
/**
* Represents a speed setting for an I2C component: standard, fast, and
* fast plus, corresponding to 100 kbaud, 400 kbaud, and 1 Mbaud,
* respectively.
*/
typedef enum dif_i2c_speed {
/**
* Standard speed, 100 kilobaud.
*/
kDifI2cSpeedStandard,
/**
* Fast speed, 400 kilobaud.
*/
kDifI2cSpeedFast,
/**
* Fast plus speed, 1 megabaud.
*/
kDifI2cSpeedFastPlus,
} dif_i2c_speed_t;
// TODO(#23786) The i2c IP has a parameter (InputDelayCycles), use this when
// topgen supports exposing it in the headers.
enum {
/**
* Input Delay Cycles; for clock stretching detection to work, the SCL high
* and low time must be at least 4 cycles.
*/
kDifI2cInputDelayCycles = 4,
};
/**
* Timing configuration parameters for I2C.
*
* While the I2C device requires ten parameters to describe its timing
* configuration, the degrees of freedom of those parameters is constrained to
* the ones in this struct.
*
* See `dif_i2c_compute_timing()`
*/
typedef struct dif_i2c_timing_config {
/**
* The lowest speed at which an I2C target connected to this host will
* operate.
*
* In other words, this is the maximum speed at which the host can operate
* without going over what the target devices can handle.
*/
dif_i2c_speed_t lowest_target_device_speed;
/**
* The period of the clock driving this device, in nanoseconds.
*
* This value should not be zero, since it is used as a divisor for
* division.
*/
uint32_t clock_period_nanos;
/**
* The expected time it takes for the I2C bus signal to rise, in nanoseconds.
*
* This value is dependent on properties of the hardware's interconnect, and
* not under actual firmware control.
*/
uint32_t sda_rise_nanos;
/**
* The expected time for the bus signal to fall, similar to `sda_rise_nanos`.
*/
uint32_t sda_fall_nanos;
/**
* The desired period of the SCL line, in nanoseconds.
*
* Normally, this should just be `1'000'000 / lowest_target_device_speed`,
* but the period may be larger if desired.
*
* Setting this value to zero will result in the minimum period being used.
*/
uint32_t scl_period_nanos;
} dif_i2c_timing_config_t;
/**
* Configuration for the addressing behavior of the I2C, can be disabled or
* configured to look for multiple addresses by masking certain bits. A mask of
* 0x7f will match only a single address.
*/
typedef struct dif_i2c_id {
/**
* Mask the received I2C address before checking for a match. Received Address
* & mask must equal the programmed address to activate I2C Device. If Address
* & ~mask != 0, this will not match any addresses. A mask of 0x7f will cause
* device to only respond to an exact match. The mask is 7 bits and LSB
* aligned.
*/
uint8_t mask;
/**
* The 7-bit I2C address that should be matched after masking to cause the
* activated I2C Target device to begin to act in a transaction. Address is
* LSB aligned.
*/
uint8_t address;
} dif_i2c_id_t;
/**
* Runtime configuration for I2C.
*
* This struct describes runtime timing parameters. Computing these values is
* somewhat complicated, so these fields should be initialized using the
* `dif_i2c_compute_timing()` function. A caller is, however, free to compute
* these values themselves if they prefer, so long as the I2C spec is
* respected.
*
* These values correspond to those in Table 10 of the I2C spec, and are given
* in units of input clock cycles.
*/
typedef struct dif_i2c_config {
uint16_t scl_time_high_cycles;
uint16_t scl_time_low_cycles;
uint16_t rise_cycles;
uint16_t fall_cycles;
uint16_t start_signal_setup_cycles;
uint16_t start_signal_hold_cycles;
uint16_t data_signal_setup_cycles;
uint16_t data_signal_hold_cycles;
uint16_t stop_signal_setup_cycles;
/**
* This parameter is referred to in the I2C documents as the
* "bus free time".
*/
uint16_t stop_signal_hold_cycles;
} dif_i2c_config_t;
/**
* Represents a watermark or data level for one of the I2C FIFOs.
*/
typedef uint16_t dif_i2c_level_t;
/**
* Flags for a formatted I2C byte, used by the `dif_i2c_write_byte_raw()`
* function.
*/
typedef struct dif_i2c_fmt_flags {
/**
* Causes a start signal to be sent before the byte.
*
* If a start has been issued during the current transaction, this will issue
* a repeated start.
*/
bool start;
/**
* Causes a stop signal to be sent after the byte.
*
* This flag cannot be set when both `read` and `read_cont` are set.
*/
bool stop;
/**
* Causes the byte to be interpreted as an unsigned number of bytes to read
* from the target; 0 is interpreted as 256.
*/
bool read;
/**
* Requires `read` to be set; if so, once the final byte associated with this
* read is received, it will be acknowledged, allowing the read operation to
* continue.
*/
bool read_cont;
/**
* By default, the hardware expects an ACK after every byte sent, and raises
* an exception (contributing to the `kDifi2cIrqControllerHalt` interrupt).
* This flag disables that behavior.
*
* This flag cannot be set along with `read` or `read_cont`.
*/
bool suppress_nak_irq;
} dif_i2c_fmt_flags_t;
/**
* The I2C Target device records the following signals with received data
*/
typedef enum dif_i2c_signal {
/**
* The associated byte was received with a START signal, and should be the
* matching address and R/W bit
*/
kDifI2cSignalStart = 1,
/**
* The associated byte was received after a STOP signal, so the transaction is
* over and the byte is junk
*/
kDifI2cSignalStop = 2,
/**
* The associated byte was received with a repeated START signal and
* represents the address for the subsequent transaction.
*/
kDifI2cSignalRepeat = 3,
/**
* The associated data byte was NACK'd.
*/
kDifI2cSignalNack = 4,
/**
* There was a stretch timeout on the associated address byte, leading to
* NACKing all subsequent incoming bytes for the rest of the transaction (and
* returning 0xFF bytes on any subsequent reads in that transaction).
*/
kDifI2cSignalNackStart = 5,
/**
* A STOP signal was received to end a transaction that experienced a stretch
* timeout or other I/O error condition.
*/
kDifI2cSignalNackStop = 6,
/**
* There's no associated STOP or START signal this is just a byte that's been
* written to the I2C target in an ongoing transaction, and it was ACK'd.
*/
kDifI2cSignalNone = 0,
} dif_i2c_signal_t;
/**
* Available formatting codes for `dif_i2c_write_byte_raw()`.
*
* Each code describes how to interpret the `byte` parameter, referred to below
* as "the byte".
*
* It is the caller's responsibility to observe the state transitions in the
* comments below.
*/
typedef enum dif_i2c_fmt {
/**
* Start a transaction. This sends a START signal followed by the byte.
* The byte sent will form (potentially part of) the target address for the
* transaction.
*
* May be followed by any format code.
*/
kDifI2cFmtStart,
/**
* Transmit byte. This simply sends the byte. It may need to be used in
* conjunction with `Start` to send a multi-byte target address.
*
* May be followed by any format code.
*/
kDifI2cFmtTx,
/**
* Transmit byte and stop. This sends the byte, and then sends a stop
* signal, completing a transaction.
*
* Only `Start` may follow this code.
*/
kDifI2cFmtTxStop,
/**
* Request `n` bytes, where `n` is the byte interpreted as an unsigned
* integer; a byte value of `0` will be interpreted as requesting `256`
* bytes. This will NAK the last byte.
*
* Only `Start` may follow this code (this code does not stop a transaction;
* see `RxStop`).
*/
kDifI2cFmtRx,
/**
* Request `n` bytes, same as `Rx`, but ACK the last byte so that more data
* can be requested.
*
* May be followed by `RxContinue`, `Rx`, or `RxStop`.
*/
kDifI2cFmtRxContinue,
/**
* Request `n` bytes, same as `Rx`, but, after NAKing the last byte, send a
* stop signal to end the transaction.
*
* Only `Start` may follow this code.
*/
kDifI2cFmtRxStop,
} dif_i2c_fmt_t;
/**
* Flags representing the status of an I2C block
*/
typedef struct dif_i2c_status {
/**
* Enable Host, I2C block has been initialized and enabled to act as a host,
* consuming entries from the FMT FIFO to perform I2C transactions, and
* writing the results of I2C Reads to the RX FIFO
*/
bool enable_host;
/**
* Enable Target, I2C block has been initialized and enabled to act as a
* target device, using the TX FIFO to respond to I2C Reads and the ACQ FIFO
* to store data received from I2C Writes
*/
bool enable_target;
/**
* Line Loopback enabled
*/
bool line_loopback;
/**
* ACK Control Mode enabled
*/
bool ack_control_en;
/**
* Format FIFO is full, SW cannot write commands to transact into the FIFO
* until I2C host is able to act on the contents.
*/
bool fmt_fifo_full;
/**
* RX FIFO is full, I2C cannot continue to read data until SW reads from the
* FIFO.
*/
bool rx_fifo_full;
/**
* Format FIFO is empty, I2C host will stop transacting until the FIFO is
* written to.
*/
bool fmt_fifo_empty;
/**
* RX FIFO Empty, Software has handled all bytes read by the I2C Host.
*/
bool rx_fifo_empty;
/**
* I2C Host is not carrying out a transaction
*/
bool host_idle;
/**
* I2C Device is not carrying out a transaction
*/
bool target_idle;
/**
* TX FIFO Full, I2C device must respond to I2C reads or have the FIFO cleared
* before SW can write to the FIFO.
*/
bool tx_fifo_full;
/**
* Acquire FIFO is full of data from I2C writes to the target device. Software
* must handle data before I2C device can continue
*/
bool acq_fifo_full;
/**
* TX FIFO is empty, device is unprepared to respond to I2C Reads until SW
* writes to FIFO
*/
bool tx_fifo_empty;
/**
* Acquire FIFO is empty and will remain so until I2C Device receives a Write
*/
bool acq_fifo_empty;
/**
* Target is stretching due to the Auto ACK Counter expiring.
*/
bool ack_ctrl_stretch;
} dif_i2c_status_t;
/**
* Get I2C status.
*
* @param i2c An I2C handle.
* @param[out] status I2C status as understood by the block.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_get_status(const dif_i2c_t *i2c, dif_i2c_status_t *status);
typedef struct dif_i2c_controller_halt_events {
/** Received a NACK from the target. */
bool nack_received;
/** Failed to handle a NACK before the handling timeout. */
bool unhandled_nack_timeout;
/**
* The bus timed out due to SCL held low for too long while the controller was
* transmitting.
*/
bool bus_timeout;
/**
* The controller was unable to transmit a symbol and lost arbitration.
*/
bool arbitration_lost;
} dif_i2c_controller_halt_events_t;
/**
* Get the events that contributed to the controller halting, if any.
*
* @param i2c handle,
* @param[out] events The events causing the controller FSM to halt.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_get_controller_halt_events(
const dif_i2c_t *i2c, dif_i2c_controller_halt_events_t *events);
/**
* Clear the selected events that contributed to the controller halting, if any.
*
* @param i2c handle,
* @param events The events to clear.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_clear_controller_halt_events(
const dif_i2c_t *i2c, dif_i2c_controller_halt_events_t events);
typedef struct dif_i2c_target_tx_halt_events {
/** Received a new read transfer, and TX stretch controls were enabled. */
bool tx_pending;
/** The bus timed out during a read transfer. */
bool bus_timeout;
/**
* The target was unable to transmit a symbol and lost arbitration. For
* targets, a loss of arbitration might be an ordinary mechanism in specific
* contexts, such as broadcast commands.
*/
bool arbitration_lost;
} dif_i2c_target_tx_halt_events_t;
/**
* Get the events that are contributing or would contribute to the target
* halting and stretching the clock on a read.
*
* @param i2c handle,
* @param[out] events The events causing the target FSM to stretch on reads.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_get_target_tx_halt_events(
const dif_i2c_t *i2c, dif_i2c_target_tx_halt_events_t *events);
/**
* Clear the selected events that are contributing or would contribute to the
* target halting and stretching the clock on a read.
*
* @param i2c handle,
* @param events The events to clear.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_clear_target_tx_halt_events(
const dif_i2c_t *i2c, dif_i2c_target_tx_halt_events_t events);
/**
* Computes timing parameters for an I2C host and stores them in `config`.
*
* Timing is based on requirements for devices attached to OpenTitan
*
* The values returned may be tweaked by callers that require finer control over
* some of the calculations, such as how the allocation of a lengthened SCL
* period.
*
* @param timing_config Configuration values for producing timing parameters.
* @param[out] config I2C configuration to which to apply the computed
* parameters.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_compute_timing(dif_i2c_timing_config_t timing_config,
dif_i2c_config_t *config);
/**
* Configures I2C with runtime information.
*
* This function should need to be called once for the lifetime of `handle`.
*
* @param i2c An I2C handle.
* @param config Runtime configuration parameters.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_configure(const dif_i2c_t *i2c, dif_i2c_config_t config);
/**
* Resets the state of the RX FIFO, essentially dropping all received bytes for
* the host.
*
* @param i2c An I2c handle.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_reset_rx_fifo(const dif_i2c_t *i2c);
/**
* Resets the state of the FMT FIFO, essentially dropping all scheduled
* operations.
*
* @param i2c An I2c handle.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_reset_fmt_fifo(const dif_i2c_t *i2c);
/**
* Resets the state of the TX FIFO, essentially dropping all scheduled
* responses.
*
* @param i2c An I2c handle.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_reset_tx_fifo(const dif_i2c_t *i2c);
/**
* Resets the state of the ACQ FIFO, essentially dropping all received bytes for
* the target device.
*
* @param i2c An I2c handle.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_reset_acq_fifo(const dif_i2c_t *i2c);
/**
* Sets watermarks for the RX and FMT FIFOs, which will assert the
* corresponding interrupts whenever the levels in the FIFOs are above (RX)
* and below (FMT) the set levels.
*
* @param i2c An I2C handle.
* @param rx_level The desired watermark level for the RX FIFO.
* @param fmt_level The desired watermark level for the FMT FIFO.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_set_host_watermarks(const dif_i2c_t *i2c,
dif_i2c_level_t rx_level,
dif_i2c_level_t fmt_level);
/**
* Sets watermarks for the TX and ACQ FIFOs, which will assert the
* corresponding interrupts whenever the levels in the FIFOs are below (TX)
* and above (ACQ) the set levels.
*
* @param i2c An I2C handle.
* @param tx_level The desired watermark level for the TX FIFO.
* @param acq_level The desired watermark level for the ACQ FIFO.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_set_target_watermarks(const dif_i2c_t *i2c,
dif_i2c_level_t tx_level,
dif_i2c_level_t acq_level);
/**
* Enables or disables the "Host I2C" functionality,
* This function should be called to enable the device
* once timings, interrupts, and watermarks are all configured.
*
* @param i2c An I2C handle.
* @param state The new toggle state for the host functionality.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_host_set_enabled(const dif_i2c_t *i2c, dif_toggle_t state);
/**
* Enables or disables the "Device I2C" functionality,
* This function should be called to enable the device
* once address, and interrupts are all configured.
*
* @param i2c An I2C handle.
* @param state The new toggle state for the device functionality.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_device_set_enabled(const dif_i2c_t *i2c,
dif_toggle_t state);
/**
* Enables or disables the Line Loopback functionality,
* This function should be called to assist debugging by setting the i2c block
* or host to use received transactions to populate outgoing transactions.
*
* @param i2c An I2C handle.
* @param state The new toggle state for the host functionality.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_line_loopback_set_enabled(const dif_i2c_t *i2c,
dif_toggle_t state);
/**
* Enables or disables the functionality to NACK when timing out on an address
* (N)ACK phase stretch.
* This function should be called prior to enabling the i2c target module.
*
* @param i2c An I2C handle.
* @param state The new toggle state for the device functionality.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_addr_nack_set_enabled(const dif_i2c_t *i2c,
dif_toggle_t state);
/**
* Enables or disables the ACK Control Mode functionality.
*
* This function should be called prior to enabling the i2c target module.
*
* @param i2c An I2C handle.
* @param state The new toggle state for the device functionality.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_ack_ctrl_set_enabled(const dif_i2c_t *i2c,
dif_toggle_t state);
/**
* Enables or disables the bus monitor's multi-controller functionality.
*
* This function should be called prior to enabling the host or target.
*
* @param i2c An I2C handle.
* @param state The new toggle state for the device functionality.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_multi_controller_monitor_set_enabled(const dif_i2c_t *i2c,
dif_toggle_t state);
/**
* Enables or disables the target FSM's stretch control for the start of read
* transactions.
*
* This function should be called prior to enabling the target.
*
* @param i2c An I2C handle.
* @param state The new toggle state for the device functionality.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_target_tx_stretch_ctrl_set_enabled(const dif_i2c_t *i2c,
dif_toggle_t state);
/**
* Enables or disables the "override mode". In override mode, software is able
* to directly control the driven values of the SCL and SDA lines using
* `dif_i2c_override_drive_pins()`.
*
* @param i2c An I2C handle.
* @param state The new toggle state for override mode.'
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_override_set_enabled(const dif_i2c_t *i2c,
dif_toggle_t state);
/**
* Drives the SCL and SDA pins to the given values when "override mode" is
* enabled.
*
* @param i2c An I2C handle.
* @param scl The value to drive SCL to.
* @param sda The value to drive SDA to.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_override_drive_pins(const dif_i2c_t *i2c, bool scl,
bool sda);
/**
* Returns oversampling of the last 16 values of the SCL and SDA pins, with the
* zeroth bit being the most recent.
*
* @param i2c An I2C handle.
* @param[out] scl_samples SCL sample bits; may be `NULL`.
* @param[out] sda_samples SDA sample bits; may be `NULL`.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_override_sample_pins(const dif_i2c_t *i2c,
uint16_t *scl_samples,
uint16_t *sda_samples);
/**
* Returns the current levels, i.e., number of entries, in the FMT, RX, TX and
* ACQ FIFOs.
* These values represent the number of entries pending for send by host
* hardware, entries pending for read by host software, entries pending for send
* by device hardware, and entries pending for read by device software
* respectively.
*
* @param i2c An I2C handle.
* @param[out] fmt_fifo_level The number of unsent FMT bytes; may be `NULL`.
* @param[out] rx_fifo_level The number of unread RX bytes; may be `NULL`.
* @param[out] tx_fifo_level The number of unread TX bytes; may be `NULL`.
* @param[out] acq_fifo_level The number of unread ACQ bytes; may be `NULL`.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_get_fifo_levels(const dif_i2c_t *i2c,
dif_i2c_level_t *fmt_fifo_level,
dif_i2c_level_t *rx_fifo_level,
dif_i2c_level_t *tx_fifo_level,
dif_i2c_level_t *acq_fifo_level);
/**
* Read the current value of the Auto ACK Counter.
*
* The counter is only active if ACK Control Mode is enabled.
*
* The Auto ACK Counter represents the remaining number of bytes the Target
* module will ACK automatically, so long as the ACQ FIFO has capacity.
*
* @param i2c An I2C handle.
* @param count[out] The number of additional bytes to ACK in the current
* transfer.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_get_auto_ack_count(const dif_i2c_t *i2c, uint16_t *count);
/**
* Reloads the Auto ACK Counter with the provided value.
*
* The count will only be accepted if the I2C target module is currently
* stretching the clock, and the count is currently 0. In other words, the
* target module is stretching because the Auto ACK Count was exhausted.
*
* In addition, the counter is only active if ACK Control Mode is enabled.
*
* Set the value to 1 to ACK only the current pending data byte. Increase the
* `count` argument for each additional byte desired to be automatically ACK'd,
* assuming the ACQ FIFO has capacity.
*
* @param i2c An I2C handle.
* @param count The number of additional bytes to ACK in the current transfer.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_set_auto_ack_count(const dif_i2c_t *i2c, uint16_t count);
/**
* Instruct the I2C Target module to issue a NACK for the current transaction.
*
* Only takes effect if the Target module is stretching the clock because the
* Auto ACK Count has expired. ACK Control Mode must be enabled.
*
* @param i2c An I2C handle.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_nack_transaction(const dif_i2c_t *i2c);
/**
* Get the pending data byte when stretching due to Auto Ack Count exhaustion.
*
* This value is only valid if ACK Control Mode is enabled.
*
* @param i2c An I2C handle.
* @param[out] data The data pending for (N)ACK.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_get_pending_acq_byte(const dif_i2c_t *i2c, uint8_t *data);
/**
* Pops an entry (a byte) off of the RX FIFO. Passing in `NULL` to the out-param
* will still trigger a byte pop.
*
* @param i2c An I2C handle.
* @param[out] byte The popped byte; may be `NULL`.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_read_byte(const dif_i2c_t *i2c, uint8_t *byte);
/**
* Reads off a chunk of bytes from the RX FIFO.
*
* @param i2c An I2C handle.
* @param[out] size The size of the buffer.
* @param[out] buffer A buffer to receive the bytes read.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_read_bytes(const dif_i2c_t *i2c, size_t size,
uint8_t *buffer);
/**
* Pushes a raw write entry onto the FMT FIFO, consisting of a byte and format
* flags. This function can be called in sequence to enqueue an I2C
* transmission.
*
* Callers should prefer `dif_i2c_write_byte()` instead, since that function
* provides clearer semantics. This function should only really be used for
* testing or troubleshooting a device.
*
* @param i2c An I2C handle.
* @param byte The value to push onto the FIFO.
* @param flags The flags to use for this write.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_write_byte_raw(const dif_i2c_t *i2c, uint8_t byte,
dif_i2c_fmt_flags_t flags);
/**
* Writes a chunk of raw bytes and format flags onto the FMT FIFO.
*
* @param i2c An I2C handle.
* @param size The number of bytes to push onto the FIFO.
* @param bytes Buffer with the values to push onto the FIFO.
* @param flags The format flags to use for this write.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_write_bytes_raw(const dif_i2c_t *i2c, size_t size,
const uint8_t *bytes,
dif_i2c_fmt_flags_t flags);
/**
* Pushes a write entry onto the FMT FIFO, consisting of a byte and a format
* code. This function can be called in sequence to enqueue an I2C
* transmission.
*
* @param i2c An I2C handle.
* @param byte The value to push onto the FIFO.
* @param code The code to use for this write.
* @param suppress_nak_irq Whether to supress the NAK IRQ for this one byte.
* May not be used in combination with `Rx` codes.
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_write_byte(const dif_i2c_t *i2c, uint8_t byte,
dif_i2c_fmt_t code, bool suppress_nak_irq);
/**
* Pushes a byte into the TX FIFO to make it available when this I2C block
* responds to an I2C Read as a target device.
*
* @param i2c handle.
* @param byte to write to FIFO
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_transmit_byte(const dif_i2c_t *i2c, uint8_t byte);
/**
* Read acquired data from the ACQ FIFO, including record of starts, stops,
* address and written data
*
* @param i2c handle.
* @param[out] byte, Data received in the transaction, Could be the address or
* junk
* @param[out] signal, Signal received in the transaction
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_acquire_byte(const dif_i2c_t *i2c, uint8_t *byte,
dif_i2c_signal_t *signal);
typedef enum dif_i2c_scl_timeout {
/** To disable the clock timeout */
kDifI2cSclTimeoutDisabled = 0,
/** To select the stretch timeout */
kDifI2cSclTimeoutStretch,
/** To select the bus timeout (continuous SCL low) */
kDifI2cSclTimeoutBus,
} dif_i2c_scl_timeout_t;
/**
* Enables clock timeout after a number of I2C block clock cycles
* when I2C block is configured as host.
*
* If `kDifI2cSclTimeoutDisabled` is selected, the clock timeout is disabled.
*
* If a `kDifI2cSclTimeoutStretch` timeout is selected, the target stretching
* timeout function is enabled and the bus timeout is disabled. The timeout
* duration is the maximum time a target is allowed to stretch the clock for
* any given bit when this i2c controller is transmitting.
*
* If a `kDifI2cSclTimeoutBus` timeout is selected, the bus timeout function is
* enabled, and the target stretching timeout is disabled. The timeout duration
* is the maximum time the clock may remain continuously low, even if it is this
* i2c controller or target that is pulling SCL low. The bus timeout should be
* selected for SMBus compatibility.
*
* @param i2c An I2C handle,
* @param timeout_type Whether to enable the timeout and which one
* @param cycles How many cycles to wait before timing out
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_enable_clock_timeout(const dif_i2c_t *i2c,
dif_i2c_scl_timeout_t timeout_type,
uint32_t cycles);
/**
* Sets the I2C device to listen for a pair of masked addresses
*
* @param i2c handle,
* @param id0 address and mask pair to listen for can be null
* @param id1 address and mask pair to listen for can be null
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_set_device_id(const dif_i2c_t *i2c,
const dif_i2c_id_t *id0,
const dif_i2c_id_t *id1);
/**
* Set host timeout. When OT is acting as target device, set the number of
* counts after which to trigger a host_timeout interrupt
*
* @param i2c handle,
* @param duration in clock counts
* @return The result of the operation.
*/
OT_WARN_UNUSED_RESULT
dif_result_t dif_i2c_set_host_timeout(const dif_i2c_t *i2c, uint32_t duration);
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
#endif // OPENTITAN_SW_DEVICE_LIB_DIF_DIF_I2C_H_