Newer
Older
mbed-os / targets / TARGET_Maxim / TARGET_MAX32670 / Libraries / PeriphDrivers / Include / MAX32670 / mxc_i2c.h
/**
* @file     i2c.h
* @brief    Inter-integrated circuit (I2C) communications interface driver.
*/

/******************************************************************************
 * Copyright (C) 2023 Maxim Integrated Products, Inc., All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 * Except as contained in this notice, the name of Maxim Integrated
 * Products, Inc. shall not be used except as stated in the Maxim Integrated
 * Products, Inc. Branding Policy.
 *
 * The mere transfer of this software does not imply any licenses
 * of trade secrets, proprietary technology, copyrights, patents,
 * trademarks, maskwork rights, or any other form of intellectual
 * property whatsoever. Maxim Integrated Products, Inc. retains all
 * ownership rights.
 *
 ******************************************************************************/

/* Define to prevent redundant inclusion */
#ifndef LIBRARIES_PERIPHDRIVERS_INCLUDE_MAX32670_I2C_H_
#define LIBRARIES_PERIPHDRIVERS_INCLUDE_MAX32670_I2C_H_

#include <stdint.h>
#include "mxc_sys.h"
#include "i2c_regs.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @defgroup i2c I2C
 * @ingroup periphlibs
 * @{
 */

typedef struct _i2c_req_t mxc_i2c_req_t;

/**
 * @brief   The callback used by the MXC_I2C_ReadByteInteractive() function.
 *
 * The callback routine used by the MXC_I2C_ReadByteInteractive() function. This
 * function allows the application to determine whether the byte received
 * should be acknowledged or not.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 * @param   byte        The byte received.
 *
 * @return  0 if the byte should not be acknowledged (NACK), non-zero to
 *          acknowledge the byte.
 */
typedef int (*mxc_i2c_getAck_t)(mxc_i2c_regs_t *i2c, unsigned char byte);

/**
 * @brief   The callback routine used by the MXC_I2C_MasterTransactionAsync()
 *          function to indicate the transaction has completed.
 *
 * @param   req         The details of the transaction.
 * @param   result      0 if all bytes are acknowledged, 1 if any byte
 *                      transmitted is not acknowledged, negative if error.
 *                      See \ref MXC_Error_Codes for the list of error codes.
 */
typedef void (*mxc_i2c_complete_cb_t)(mxc_i2c_req_t *req, int result);

/**
 * @brief   The callback routine used by the I2C Read/Write FIFO DMA
 *          functions to indicate the transaction has completed.
 *
 * @param   len         The length of data actually read/written
 * @param   result      See \ref MXC_Error_Codes for the list of error codes.
 */
typedef void (*mxc_i2c_dma_complete_cb_t)(int len, int result);

/**
 * @brief   The information required to perform a complete I2C transaction as
 *          the bus master.
 *
 * The information required to perform a complete I2C transaction as the bus
 * master. This structure is used by the MXC_I2C_MasterTransaction() and
 * MXC_I2C_MasterTransactionAsync() functions.
 */
struct _i2c_req_t {
    mxc_i2c_regs_t *i2c; ///< Pointer to I2C registers (selects the
    ///< I2C block used.)
    unsigned int addr; ///< The 7-bit or 10-bit address of the slave.
    unsigned char *tx_buf; ///< The buffer containing the bytes to write.
    unsigned int tx_len; ///< The number of bytes to write. On return
    ///< from the function, this will be set to
    ///< the number of bytes actually transmitted.
    unsigned char *rx_buf; ///< The buffer to read the data into.
    unsigned int rx_len; ///< The number of bytes to read.  On return
    ///< from the function, this will be set to
    ///< the number of bytes actually received.
    int restart; ///< Controls whether the transaction is
    ///< terminated with a stop or repeated start
    ///< condition.  Use 0 for a stop, non-zero
    ///< for repeated start.
    mxc_i2c_complete_cb_t callback; ///< The callback used to indicate the
    ///< transaction is complete or an error has
    ///< occurred. This field may be set to NULL
    ///< if no indication is necessary. This
    ///< field is only used by the
    ///< MXC_I2C_MasterTransactionAsync() function.
    ///< MXC_I2C_MasterTransaction() ignores the
    ///< callback field.
};

/**
 * @brief   The list of events reported by the MXC_I2C_SlaveTransaction() and
 *          MXC_I2C_SlaveTransactionAsync() functions.
 *
 * The list of events reported by the MXC_I2C_SlaveTransaction() and
 * MXC_I2C_SlaveTransactionAsync() functions.  It is up to the calling
 * application to handle these events.
 */
typedef enum {
    MXC_I2C_EVT_MASTER_WR, ///< A slave address match occurred with the master
    ///< requesting a write to the slave.
    MXC_I2C_EVT_MASTER_RD, ///< A slave address match occurred with the master
    ///< requesting a read from the slave.
    MXC_I2C_EVT_RX_THRESH, ///< The receive FIFO contains more bytes than its
    ///< threshold level.
    MXC_I2C_EVT_TX_THRESH, ///< The transmit FIFO contains fewer bytes than its
    ///< threshold level.
    MXC_I2C_EVT_TRANS_COMP, ///< The transaction has ended.
    MXC_I2C_EVT_UNDERFLOW, ///< The master has attempted a read when the
    ///< transmit FIFO was empty.
    MXC_I2C_EVT_OVERFLOW, ///< The master has written data when the receive
    ///< FIFO was already full.
} mxc_i2c_slave_event_t;

/**
 * @brief   The callback routine used by the MXC_I2C_SlaveTransaction() and
 *          MXC_I2C_SlaveTransactionAsync functions to handle the various I2C
 *          slave events.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 * @param   event       The event that occurred to trigger this callback.
 * @param   data        This field is used to pass Success/Fail for the
 *                      MXC_I2C_EVT_TRANS_COMP event.
 *
 * @return  The return value is only used in the case of an MXC_I2C_EVT_RX_THRESH
 *          event. In this case, the return specifies if the last byte
 *          received should be acknowledged or not. Return 0 to acknowledge,
 *          non-zero to not acknowledge.  The return value is ignored for all
 *          other event types.
 */
typedef int (*mxc_i2c_slave_handler_t)(mxc_i2c_regs_t *i2c, mxc_i2c_slave_event_t event,
                                       void *data);

/***** Function Prototypes *****/

/* ************************************************************************* */
/* Control/Configuration functions                                           */
/* ************************************************************************* */

/**
 * @brief   Initialize and enable I2C peripheral.
 * @note    This function sets the I2C Speed to 100kHz,  if another speed is
 *          desired use the MXC_I2C_SetFrequency() function to set it.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 * @param   masterMode  Whether to put the device in master or slave mode. Use
 *                      non-zero
 *                      for master mode, and zero for slave mode.
 * @param   slaveAddr   7-bit or 10-bit address to use when in slave mode.
 *                      This parameter is ignored when masterMode is non-zero.
 *
 * @return  Success/Fail, see \ref MXC_Error_Codes for a list of return codes.
 */
int MXC_I2C_Init(mxc_i2c_regs_t *i2c, int masterMode, unsigned int slaveAddr);

/**
 * @brief   Initialize and enable I2C peripheral.
 * @note    Set idx to 0, multiple I2C instances acting as slaves is not yet
 *          supported.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 * @param   slaveAddr   7-bit or 10-bit address to use when in slave mode.
 *                      This parameter is ignored when masterMode is non-zero.
 * @param   idx         Index of the I2C slave instance.
 *
 * @return  Success/Fail, see \ref MXC_Error_Codes for a list of return codes.
 */
int MXC_I2C_SetSlaveAddr(mxc_i2c_regs_t *i2c, unsigned int slaveAddr, int idx);

/**
 * @brief   Disable and shutdown I2C peripheral.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 *
 * @return  Success/Fail, see \ref MXC_Error_Codes for a list of return codes.
 */
int MXC_I2C_Shutdown(mxc_i2c_regs_t *i2c);

/**
 * @brief   Reset the I2C peripheral.
 * @note    The peripheral will need to be initialized with MXC_I2C_Init() before use
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 *
 * @return  Success/Fail, see \ref MXC_Error_Codes for a list of return codes.
 */
int MXC_I2C_Reset(mxc_i2c_regs_t *i2c);

/**
 * @brief   Set the frequency of the I2C interface.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 * @param   hz          The desired frequency in Hertz.
 *
 * @return  Negative if error, otherwise actual speed set. See \ref
 *          MXC_Error_Codes for the list of error return codes.
 */
int MXC_I2C_SetFrequency(mxc_i2c_regs_t *i2c, unsigned int hz);

/**
 * @brief   Get the frequency of the I2C interface.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 *
 * @return  The I2C bus frequency in Hertz
 */
unsigned int MXC_I2C_GetFrequency(mxc_i2c_regs_t *i2c);

/**
 * @brief   Checks if the given I2C bus can be placed in sleep more.
 *
 * This functions checks to see if there are any on-going I2C transactions in
 * progress. If there are transactions in progress, the application should
 * wait until the I2C bus is free before entering a low-power state.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 *
 * @return  #E_NO_ERROR if ready, and non-zero if busy or error. See \ref
 *          MXC_Error_Codes for the list of error return codes.
 */
int MXC_I2C_ReadyForSleep(mxc_i2c_regs_t *i2c);

/**
 * @brief   Enables or disables clock stretching by the slave.
 *
 * Enables or disables clock stretching by the slave. This function has no
 * affect when operating as the master.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 * @param   enable      Enables clock stretching if non-zero, disables if zero.
 *
 * @return  Success/Fail, see \ref MXC_Error_Codes for a list of return codes.
 */
int MXC_I2C_SetClockStretching(mxc_i2c_regs_t *i2c, int enable);

/**
 * @brief   Determines if clock stretching has been enabled.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 *
 * @return  Zero if clock stretching is disabled, non-zero otherwise
 */
int MXC_I2C_GetClockStretching(mxc_i2c_regs_t *i2c);

/* ************************************************************************* */
/* Low-level functions                                                       */
/* ************************************************************************* */

/**
 * @brief   Generate a start (or repeated start) condition on the I2C bus.
 *
 * Generate a start (or repeated start) condition on the I2C bus. This
 * function may opt to delay the actual generation of the start condition
 * until data is actually transferred.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 *
 * @return  Success/Fail, see \ref MXC_Error_Codes for a list of return codes.
 */
int MXC_I2C_Start(mxc_i2c_regs_t *i2c);

/**
 * @brief   Generate a stop condition on the I2C bus.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 *
 * @return  Success/Fail, see \ref MXC_Error_Codes for a list of return codes.
 */
int MXC_I2C_Stop(mxc_i2c_regs_t *i2c);

/**
 * @brief   Write a single byte to the I2C bus.
 *
 * Write a single byte to the I2C bus. This function assumes the I2C bus is
 * already in the proper state (i.e. a start condition has already been
 * generated and the bus is in the write phase of an I2C transaction). If any
 * bytes are pending in the FIFO (i.e. in the case of clock stretching), this
 * function will return E_OVERFLOW.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 * @param   byte        The byte to transmit.
 *
 * @return  0 if byte is acknowledged, 1 if not acknowledged, negative if
 *          error. See \ref MXC_Error_Codes for the list of error return codes.
 */
int MXC_I2C_WriteByte(mxc_i2c_regs_t *i2c, unsigned char byte);

/**
 * @brief   Read a single byte from the I2C bus.
 *
 * Read a single byte from the I2C bus. This function assumes the I2C bus is
 * already in the proper state (i.e. a start condition has already been
 * generated and the bus is in the read phase of an I2C transaction). If the FIFO
 * is empty, this function will return E_UNDERFLOW.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 * @param   byte        Pointer to the byte to read into.
 * @param   ack         Whether or not to acknowledge the byte once received.
 *
 * @return  Success/Fail, see \ref MXC_Error_Codes for a list of return codes.
 */
int MXC_I2C_ReadByte(mxc_i2c_regs_t *i2c, unsigned char *byte, int ack);

/**
 * @brief   Read a single byte from the I2C bus.
 *
 * Read a single byte from the I2C bus. After the byte is received, the
 * provided callback will be used to determine if the byte should be
 * acknowledged or not before continuing with the rest of the transaction.
 * This function assumes the I2C bus is already in the proper state (i.e. a
 * start condition has already been generated and the bus is in the read
 * phase of an I2C transaction). This function must be called with clock
 * stretching enabled.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 * @param   byte        Pointer to the byte to read into.
 * @param   getAck      A function to be called to determine whether or not
 *                      to acknowledge the byte once received.  A non-zero
 *                      return value will acknowledge the byte.  If this
 *                      parameter is set to NULL or its return value is 0,
 *                      the byte received will not be acknowledged (i.e., it
 *                      will be NACKed).
 *
 * @return  Success/Fail, see \ref MXC_Error_Codes for a list of return codes.
 */
int MXC_I2C_ReadByteInteractive(mxc_i2c_regs_t *i2c, unsigned char *byte, mxc_i2c_getAck_t getAck);

/**
 * @brief   Write multiple bytes to the I2C bus.
 *
 * Write multiple bytes to the I2C bus.  This function assumes the I2C bus is
 * already in the proper state (i.e. a start condition has already been
 * generated and the bus is in the write phase of an I2C transaction).
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 * @param   bytes       The buffer containing the bytes to transmit.
 * @param   len         The number of bytes to write. On return from the
 *                      function, this will be set to the number of bytes
 *                      actually transmitted.
 *
 * @return  0 if all bytes are acknowledged, 1 if any byte transmitted is not
 *          acknowledged, negative if error. See \ref MXC_Error_Codes for the
 *          list of error return codes.
 */
int MXC_I2C_Write(mxc_i2c_regs_t *i2c, unsigned char *bytes, unsigned int *len);

/**
 * @brief   Read multiple bytes from the I2C bus.
 *
 * Read multiple byte from the I2C bus.  This function assumes the I2C bus is
 * already in the proper state (i.e. a start condition has already been
 * generated and the bus is in the read phase of an I2C transaction).
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 * @param   bytes       The buffer to read the data into.
 * @param   len         The number of bytes to read. On return from the
 *                      function, this will be set to the number of bytes
 *                      actually received.
 * @param   ack         Whether or not to acknowledge the last byte once it is
 *                      received.  All previous bytes will be acknowledged.
 *
 * @return  Success/Fail, see \ref MXC_Error_Codes for a list of return codes.
 */
int MXC_I2C_Read(mxc_i2c_regs_t *i2c, unsigned char *bytes, unsigned int *len, int ack);

/**
 * @brief   Unloads bytes from the receive FIFO.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 * @param   bytes       The buffer to read the data into.
 * @param   len         The number of bytes to read.
 *
 * @return  The number of bytes actually read.
 */
int MXC_I2C_ReadRXFIFO(mxc_i2c_regs_t *i2c, volatile unsigned char *bytes, unsigned int len);

/**
 * @brief   Unloads bytes from the receive FIFO using DMA for longer reads.
 *
 * @note    The operation is not complete until the callback has been called
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 * @param   bytes       The buffer to read the data into.
 * @param   len         The number of bytes to read.
 * @param   callback    The function to call when the read is complete
 *
 * @return  See \ref MXC_Error_Codes for a list of return values.
 */
int MXC_I2C_ReadRXFIFODMA(mxc_i2c_regs_t *i2c, unsigned char *bytes, unsigned int len,
                          mxc_i2c_dma_complete_cb_t callback);

/**
 * @brief   Get the number of bytes currently available in the receive FIFO.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 *
 * @return  The number of bytes available.
 */
int MXC_I2C_GetRXFIFOAvailable(mxc_i2c_regs_t *i2c);

/**
 * @brief   Loads bytes into the transmit FIFO.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 * @param   bytes       The buffer containing the bytes to write
 * @param   len         The number of bytes to write.
 *
 * @return  The number of bytes actually written.
 */
int MXC_I2C_WriteTXFIFO(mxc_i2c_regs_t *i2c, volatile unsigned char *bytes, unsigned int len);

/**
 * @brief   Loads bytes into the transmit FIFO using DMA for longer writes.
 *
 * @note    The operation is not complete until the callback has been called
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 * @param   bytes       The buffer containing the bytes to write
 * @param   len         The number of bytes to write.
 * @param   callback    The function to call when the read is complete
 *
 * @return  See \ref MXC_Error_Codes for a list of return values
 */
int MXC_I2C_WriteTXFIFODMA(mxc_i2c_regs_t *i2c, unsigned char *bytes, unsigned int len,
                           mxc_i2c_dma_complete_cb_t callback);

/**
 * @brief   Get the amount of free space available in the transmit FIFO.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 *
 * @return  The number of bytes available.
 */
int MXC_I2C_GetTXFIFOAvailable(mxc_i2c_regs_t *i2c);

/**
 * @brief   Removes and discards all bytes currently in the receive FIFO.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 */
void MXC_I2C_ClearRXFIFO(mxc_i2c_regs_t *i2c);

/**
 * @brief   Removes and discards all bytes currently in the transmit FIFO.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 */
void MXC_I2C_ClearTXFIFO(mxc_i2c_regs_t *i2c);

/**
 * @brief   Get the presently set interrupt flags.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 * @param   flags0      Pointer to store flags currently set in interrupt register intfl0.
 * @param   flags1      Pointer to store flags currently set in interrupt register intfl1.
 *
 * @return  See \ref MXC_Error_Codes for a list of return values
 */
int MXC_I2C_GetFlags(mxc_i2c_regs_t *i2c, unsigned int *flags0, unsigned int *flags1);

/**
 * @brief   Clears the Interrupt Flags.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 * @param   flags0      Flags to be cleared in interrupt register intfl0.
 * @param   flags1      Flags to be cleared in interrupt register intfl1.
 */
void MXC_I2C_ClearFlags(mxc_i2c_regs_t *i2c, unsigned int flags0, unsigned int flags1);

/**
 * @brief   Enable Interrupts.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 * @param   flags0      Interrupts to be enabled in int->en0
 * @param   flags1      Interrupts to be enabled in int->en1
 */
void MXC_I2C_EnableInt(mxc_i2c_regs_t *i2c, unsigned int flags0, unsigned int flags1);

/**
 * @brief   Disable Interrupts.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 * @param   flags0      Interrupts to be disabled in int->en0
 * @param   flags1      Interrupts to be disabled in int->en1
 */
void MXC_I2C_DisableInt(mxc_i2c_regs_t *i2c, unsigned int flags0, unsigned int flags1);

/**
 * @brief   Enables the slave preload mode
 *
 * Use this mode to preload the slave TX FIFO with data that can be sent when
 * the slave is addressed for a read operation without software intervention.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 */
void MXC_I2C_EnablePreload(mxc_i2c_regs_t *i2c);

/**
 * @brief   Disable the slave preload mode
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 */
void MXC_I2C_DisablePreload(mxc_i2c_regs_t *i2c);

/**
 * @brief   Enables the slave to respond to the general call address
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 */
void MXC_I2C_EnableGeneralCall(mxc_i2c_regs_t *i2c);

/**
 * @brief   Prevents the slave from responding to the general call address
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 */
void MXC_I2C_DisableGeneralCall(mxc_i2c_regs_t *i2c);

/**
 * @brief   Set the I2C Timeout
 *
 * The I2C timeout determines the amount of time the master will wait while the
 * slave is stretching the clock, and the amount of time the slave will stretch
 * the clock while waiting for software to unload the fifo.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 * @param   timeout     Timeout in uS
 *
 * @return  Success/Fail, see \ref MXC_Error_Codes for a list of return codes.
 */
void MXC_I2C_SetTimeout(mxc_i2c_regs_t *i2c, unsigned int timeout);

/**
 * @brief   Get the current I2C timeout
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 *
 * @return  The current timeout in uS
 */
unsigned int MXC_I2C_GetTimeout(mxc_i2c_regs_t *i2c);

/**
 * @brief   Attempts to recover the I2C bus, ensuring the I2C lines are idle.
 *
 * Attempts to recover and reset an I2C bus by sending I2C clocks. During
 * each clock cycle, the SDA line is cycled to determine if the master has
 * control of the line. The following steps are performed to create one SCL
 * clock cycle:
 *   1. Drive SCL low
 *   2. Verify SCL is low
 *   3. Drive SDA low
 *   4. Verify SDA is low
 *   5. Release SDA allowing it to return high
 *   6. Verify SDA is high
 *   7. Release SCL allowing it to return high.
 *   8. Verify SCL is high
 * If any of the steps fail, the bus is considered to still be busy and the
 * sequence is repeated up to the requested number of times. If all steps
 * succeed, a final stop condition is generated on the I2C bus.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 * @param   retries     Number of times to attempt the clock cycle sequence.
 *
 * @return  Success/Fail, see \ref MXC_Error_Codes for a list of return codes.
 */
int MXC_I2C_Recover(mxc_i2c_regs_t *i2c, unsigned int retries);

/* ************************************************************************* */
/* Transaction level functions                                               */
/* ************************************************************************* */

/**
 * @brief   Performs a blocking I2C Master transaction.
 *
 * Performs a blocking I2C transaction.  These actions will be performed:
 *   1. If necessary, generate a start condition on the bus.
 *   2. Send the slave address with the low bit set to 0 (indicating a write).
 *   3. Transmit req->tx_len bytes of req->tx_buff.
 *   4. Generate a repeated start condition on the bus.
 *   5. Send the slave address with the low bit set to 1 (indicating a read).
 *   6. Receive req->rx_len bytes into req->rx_buf, acknowledging each byte.
 *   7. Generate a stop (or repeated start) condition on the bus.
 *   Steps 3-6 will be skipped if req->tx_len and req->rx_len are both 0.
 *   Steps 2-4 will be skipped if req->tx_len equals 0.
 *   Steps 4-6 will be skipped if req->rx_len equals 0.
 *
 * @param   req         Pointer to details of the transaction
 *
 * @return  0 if all bytes are acknowledged, 1 if any byte transmitted is not
 *          acknowledged, negative if error. See \ref MXC_Error_Codes for the
 *          list of error return codes.
 */
int MXC_I2C_MasterTransaction(mxc_i2c_req_t *req);

/**
 * @brief   Performs a non-blocking I2C Master transaction.
 *
 * Performs a non-blocking I2C transaction.  These actions will be performed:
 *   1. If necessary, generate a start condition on the bus.
 *   2. Send the slave address with the low bit set to 0 (indicating a write).
 *   3. Transmit req->tx_len bytes of req->tx_buff.
 *   4. Generate a repeated start condition on the bus.
 *   5. Send the slave address with the low bit set to 1 (indicating a read).
 *   6. Receive req->rx_len bytes into req->rx_buf, acknowledging each byte.
 *   7. Generate a stop (or repeated start) condition on the bus.
 *   8. Execute req->callback to indicate the transaction is complete.
 *   Steps 3-6 will be skipped if tx_len and rx_len are both 0.
 *   Steps 2-4 will be skipped if tx_len equals 0.
 *   Steps 4-6 will be skipped if rx_len equals 0.
 *
 * @note    MXC_I2C_AsyncHandler() must be called periodically for this function
 *          to operate properly. Ideally from the I2C ISR.
 *
 * @param   req         Pointer to details of the transaction.  The memory
 *                      used by this parameter must remain available until
 *                      the callback is executed.
 *
 * @return  Success/Fail, see \ref MXC_Error_Codes for a list of return codes.
 */
int MXC_I2C_MasterTransactionAsync(mxc_i2c_req_t *req);

/**
 * @brief   Performs a non-blocking I2C Master transaction using DMA for reduced time
 *          in the ISR.
 *
 * Performs a non-blocking I2C transaction.  These actions will be performed:
 *   1. If necessary, generate a start condition on the bus.
 *   2. Send the slave address with the low bit set to 0 (indicating a write).
 *   3. Transmit req->tx_len bytes of req->tx_buff.
 *   4. Generate a repeated start condition on the bus.
 *   5. Send the slave address with the low bit set to 1 (indicating a read).
 *   6. Receive req->rx_len bytes into req->rx_buf, acknowledging each byte.
 *   7. Generate a stop (or repeated start) condition on the bus.
 *   8. Execute req->callback to indicate the transaction is complete.
 *   Steps 3-6 will be skipped if tx_len and rx_len are both 0.
 *   Steps 2-4 will be skipped if tx_len equals 0.
 *   Steps 4-6 will be skipped if rx_len equals 0.
 *
 * @note    MXC_I2C_AsyncHandler() must be called periodically for this function
 *          to operate properly. Ideally from the I2C ISR.
 *
 * @param   req         Pointer to details of the transaction.  The memory
 *                      used by this parameter must remain available until
 *                      the callback is executed.
 *
 * @return  Success/Fail, see \ref MXC_Error_Codes for a list of return codes.
 */
int MXC_I2C_MasterTransactionDMA(mxc_i2c_req_t *req);

/**
 * @brief   Performs a blocking I2C Slave transaction.
 *
 * Performs a blocking I2C transaction. This function will block until a
 * complete transaction with this slave has been performed. A transaction
 * begins with the master addressing the slave and ends with a repeated start
 * condition, a stop condition, or a bus error. The provided callback
 * function will be called for these events:
 *      - A slave address match occurs with the master requesting a write to
 *        the slave.
 *      - A slave address match occurs with the master requesting a read from
 *        the slave.
 *      - The receive FIFO crosses the set threshold (see
 *        MXC_I2C_SetRXThreshold()). The callback code should unload the receive
 *        FIFO (see MXC_I2C_ReadFIFO()) to allow the master to send more data.
 *        The return value of the callback function will determine if the
 *        last byte received should be acknowledged or not. Return 0 to
 *        acknowledge, non-zero to not acknowledge.
 *      - The transmit FIFO crosses the set threshold (see
 *        MXC_I2C_SetTXThreshold()). If the master is expected to read more
 *        data from this slave, the callback code should add data to the
 *        transmit FIFO (see MXC_I2C_WriteFIFO()).
 *      - The transaction ends.  If the master was writing to the slave, the
 *        receive FIFO may still contain valid data that needs to be
 *        retreived (see MXC_I2C_ReadFIFO()).
 *      - The transmit FIFO underflows because the master requests data when
 *        the transmit FIFO is empty.
 *      - The receive FIFO overflows because the master writes data while the
 *        receive FIFO was full.
 *
 * If clock stretching is disabled, careful attention must be paid to the timing
 * of the callback to avoid losing data on write or unintentionally nacking a read.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 * @param   callback    The function to be called when an I2C event occurs.
 *
 * @return  Success/Fail, see \ref MXC_Error_Codes for a list of return codes.
 */
int MXC_I2C_SlaveTransaction(mxc_i2c_regs_t *i2c, mxc_i2c_slave_handler_t callback);

/**
 * @brief   Performs a non-blocking I2C Slave transaction.
 *
 * Performs a non-blocking I2C transaction. This request will remain active
 * until a complete transaction with this slave has been performed.  A
 * transaction begins with the master  begins with the master addressing the
 * slave and ends with a repeated start condition, a stop condition, or a bus
 * error. The provided callback function will be called for these events:
 *      - A slave address match occurs with the master requesting a write to
 *        the slave.
 *      - A slave address match occurs with the master requesting a read from
 *        the slave.
 *      - The receive FIFO crosses the set threshold (see
 *        MXC_I2C_SetRXThreshold()). The callback code should unload the receive
 *        FIFO (see MXC_I2C_ReadFIFO()) to allow the master to send more data.
 *        The return value of the callback function will determine if the
 *        last byte received should be acknowledged or not. Return 0 to
 *        acknowledge, non-zero to not acknowledge.
 *      - The transmit FIFO crosses the set threshold (see
 *        MXC_I2C_SetTXThreshold()). If the master is expected to read more
 *        data from this slave, the callback code should add data to the
 *        transmit FIFO (see MXC_I2C_WriteFIFO()).
 *      - The transaction ends.  If the master was writing to the slave, the
 *        receive FIFO may still contain valid data that needs to be
 *        retreived (see MXC_I2C_ReadFIFO()).
 *      - The transmit FIFO underflows because the master requests data when
 *        the transmit FIFO is empty.
 *      - The receive FIFO overflows because the master writes data while the
 *        receive FIFO was full.
 *
 * If clock stretching is disabled, careful attention must be paid to the timing
 * of the callback to avoid losing data on write or unintentionally nacking a read.
 *
 * @note    MXC_I2C_AsyncHandler() must be called peridocally for this function
 *          to operate properly.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 * @param   callback    The function to be called when an I2C event occurs.
 *
 * @return  Success/Fail, see \ref MXC_Error_Codes for a list of return codes.
 */
int MXC_I2C_SlaveTransactionAsync(mxc_i2c_regs_t *i2c, mxc_i2c_slave_handler_t callback);

/**
 * @brief   Set the receive threshold level.
 *
 * When operating as a master, the function sets the receive threshold level
 * for when the master should unload the receive FIFO. Smaller values may
 * consume more CPU cycles, but decrease the chances of the master delaying
 * the generation of I2C bus clocks because it has no room in the FIFO to
 * receive data. Larger values may consume fewer CPU cycles, but risk delays
 * of the I2C clock. When operating as a slave, this function sets the number
 * of bytes the slave transaction  functions should receive before issuing a
 * call to their callback function. Smaller values may consume more CPU
 * cycles, but reduce the risk of missing data from the master due to the
 * recieve FIFO being full. Larger values may reduce the number of CPU
 * cycles, but may cause bytes sent from the master to be missed.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 * @param   numBytes    The threshold level to set. This value must be
 *                      between 0 and 8 inclusive.
 *
 * @return  Success/Fail, see \ref MXC_Error_Codes for a list of return codes.
 */
int MXC_I2C_SetRXThreshold(mxc_i2c_regs_t *i2c, unsigned int numBytes);

/**
 * @brief   Get the current receive threshold level.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 *
 * @return  The receive threshold value (in bytes).
 */
unsigned int MXC_I2C_GetRXThreshold(mxc_i2c_regs_t *i2c);

/**
 * @brief   Set the transmit threshold level.
 *
 * When operating as a master, the function sets the transmit threshold level
 * for when the master should add additional bytes to the transmit FIFO.
 * Larger values may consume more CPU cycles, but decrease the chances of the
 * master delaying the generation of I2C bus clocks because it has no data in
 * the FIFO to transmit. Smaller values may consume fewer CPU cycles, but
 * risk delays of the I2C clock. When operating as a slave, this function
 * sets the number of bytes the slave transaction functions should transmit
 * before issuing a call to their callback function. Larger values may
 * consume more CPU cycles, but reduce the risk of not having data ready when
 * the master requests it.  Smaller values may reduce the number of CPU
 * cycles, but may cause the master to read from an empty FIFO.  (The master
 * will read 0xFF in this case.)
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 * @param   numBytes    The threshold level to set.  This value must be
 *                      between 0 and 8 inclusive.
 *
 * @return  Success/Fail, see \ref MXC_Error_Codes for a list of return codes.
 */
int MXC_I2C_SetTXThreshold(mxc_i2c_regs_t *i2c, unsigned int numBytes);

/**
 * @brief   Get the current transmit threshold level.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 *
 * @return  The transmit threshold value (in bytes).
 */
unsigned int MXC_I2C_GetTXThreshold(mxc_i2c_regs_t *i2c);

/**
 * @brief   Abort any asynchronous requests in progress.
 *
 * Abort any asynchronous requests in progress. Any callbacks associated with
 * the active transaction will be executed to indicate when the transaction
 * has been terminated.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 */
void MXC_I2C_AbortAsync(mxc_i2c_regs_t *i2c);

/**
 * @brief   The processing function for asynchronous transactions.
 *
 * When using the asynchronous functions, the application must call this
 * function periodically. This can be done from within the I2C interrupt
 * handler or periodically by the application if I2C interrupts are disabled.
 *
 * @param   i2c         Pointer to I2C registers (selects the I2C block used.)
 */
void MXC_I2C_AsyncHandler(mxc_i2c_regs_t *i2c);

/**
 * @brief   The processing function for DMA transactions.
 *
 * When using the DMA functions, the application must call this
 * function periodically. This can be done from within the DMA Interrupt Handler.
 *
 * @param   ch          DMA channel
 * @param   error       Error status
 */
void MXC_I2C_DMACallback(int ch, int error);

/**@} end of group i2c */

#ifdef __cplusplus
}
#endif

#endif // LIBRARIES_PERIPHDRIVERS_INCLUDE_MAX32670_I2C_H_