Newer
Older
mbed-os / targets / TARGET_Maxim / TARGET_MAX32660 / Libraries / PeriphDrivers / Source / I2C / i2c_reva.c
@Sadik.Ozer Sadik.Ozer on 30 Sep 2021 41 KB Add MAX32660EVSYS
/* ****************************************************************************
 * Copyright (C) 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.
 *
 *************************************************************************** */

#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
#include "mxc_device.h"
#include "mxc_assert.h"
#include "mxc_lock.h"
#include "mxc_sys.h"
#include "mxc_delay.h"
#include "i2c_regs.h"
#include "mxc_i2c.h"
#include "i2c_reva.h"
#include "dma.h"

/* **** Variable Declaration **** */
typedef struct {
    mxc_i2c_reva_req_t *req;
    int master;             // 1 for Master, 0 for slave
    int channelTx;          // DMA channel for TX transaction
    int channelRx;          // DMA channel for RX transaction
    int writeDone;          // Write done flag
    int readDone;           // Flag done flag
} mxc_i2c_reva_req_state_t;

static mxc_i2c_reva_req_state_t states[MXC_I2C_INSTANCES];

void*           AsyncRequests[MXC_I2C_INSTANCES];
unsigned int    AsyncWritten[MXC_I2C_INSTANCES];
unsigned int    AsyncRead[MXC_I2C_INSTANCES];

/* **** Function Prototypes **** */
void MXC_I2C_RevA_AsyncCallback (mxc_i2c_reva_regs_t* i2c, int retVal);
void MXC_I2C_RevA_AsyncStop (mxc_i2c_reva_regs_t* i2c);
void MXC_I2C_RevA_AbortAsync (mxc_i2c_reva_regs_t* i2c);
void MXC_I2C_RevA_MasterAsyncHandler (int i2cNum);
int MXC_I2C_RevA_DMAHandler (mxc_i2c_reva_req_t* req);
unsigned int MXC_I2C_RevA_SlaveAsyncHandler (mxc_i2c_reva_regs_t* i2c, mxc_i2c_reva_slave_handler_t callback, unsigned int interruptEnables, int* retVal);

/* ************************************************************************* */
/* Control/Configuration functions                                           */
/* ************************************************************************* */
int MXC_I2C_RevA_Init (mxc_i2c_reva_regs_t* i2c, int masterMode, unsigned int slaveAddr)
{   
    int err;

     if(i2c == NULL) {
        return E_NULL_PTR;
    }

    if ((err = MXC_I2C_Recover ((mxc_i2c_regs_t*) i2c, 16)) != E_NO_ERROR) {
        return err;
    }
    
    i2c->ctrl |= MXC_F_I2C_REVA_CTRL_EN;

    MXC_I2C_ClearRXFIFO ((mxc_i2c_regs_t*) i2c);
    MXC_I2C_ClearTXFIFO ((mxc_i2c_regs_t*) i2c);
    // Set the thresholds here and allow the user to change them as needed
    MXC_I2C_SetTXThreshold ((mxc_i2c_regs_t*) i2c, 2);    // set TX threshold to 2 bytes
    MXC_I2C_SetRXThreshold ((mxc_i2c_regs_t*) i2c, 6);    // set RX threshold to 6 bytes
    
    if (!masterMode) {
    	MXC_I2C_SetSlaveAddr((mxc_i2c_regs_t*) i2c, slaveAddr, 0);
        states[MXC_I2C_GET_IDX ((mxc_i2c_regs_t*) i2c)].master = 0;
    }
    else {
        i2c->ctrl |= MXC_F_I2C_REVA_CTRL_MST_MODE;
        states[MXC_I2C_GET_IDX ((mxc_i2c_regs_t*) i2c)].master = 1;
    }

    return E_NO_ERROR;
}

int MXC_I2C_RevA_SetSlaveAddr (mxc_i2c_reva_regs_t* i2c, unsigned int slaveAddr, int idx)
{
    if (i2c == NULL) {
        return E_NULL_PTR;
    }
    
    if (idx != 0) {
        // Multiple slaves are not supported yet
        return E_NOT_SUPPORTED;
    }
    
    if (slaveAddr > MXC_F_I2C_REVA_SLAVE_ADDR) {
        // Only support addresses up to 10 bits
        return E_BAD_PARAM;
    }
    
    i2c->slave = 0;
    
    if (slaveAddr > MXC_I2C_REVA_MAX_ADDR_WIDTH) {
        // Set for 10bit addressing mode
        i2c->slave = MXC_F_I2C_REVA_SLAVE_EXT_ADDR_EN;
    }
    
    i2c->slave |= slaveAddr;
    
    return E_NO_ERROR;
}

int MXC_I2C_RevA_Shutdown (mxc_i2c_reva_regs_t* i2c)
{
    return E_NOT_SUPPORTED;
}

int MXC_I2C_RevA_SetFrequency (mxc_i2c_reva_regs_t* i2c, unsigned int hz)
{
    unsigned int ticksTotal, hiClks, lowClks;
    
    if (i2c == NULL) {
        return E_NULL_PTR;
    }

    if (hz > MXC_I2C_REVA_FASTPLUS_SPEED) {
        // We're going to enable high speed
        int hsLowClks, hsHiClks;
        
        // Calculate the period of SCL and set up 33% duty cycle
        ticksTotal = PeripheralClock / hz;
        hsLowClks = (ticksTotal * 2) / 3 - 1;
        hsHiClks = ticksTotal / 3 - 1;
        
        // For rounding errors, adjust by 1 clock tick
        if (ticksTotal % 1) {
            hsHiClks++;
        }
        
        // If we're too slow for high speed, bail out
        if ((hsHiClks > 0xF) || (hsLowClks > 0xF)) {
            return E_BAD_PARAM;
        }
        
        hz = MXC_I2C_REVA_FAST_SPEED; // High speed preambles will be sent at 400kHz
    }
    
    // Calculate the period of SCL, 50% duty cycle
    ticksTotal = PeripheralClock / hz;
    hiClks = (ticksTotal >> 1) - 1;
    lowClks = (ticksTotal >> 1) - 1;
    
    // Adjust for rounding errors
    if (ticksTotal % 1) {
        hiClks++;
    }
    
    // Check for maximum/minimum supported speeds
    if ( (hiClks > MXC_F_I2C_REVA_CLKHI_HI) || (lowClks == 0)) {
        return E_BAD_PARAM;
    }
    
    i2c->clklo = lowClks & MXC_F_I2C_REVA_CLKLO_LO;
    i2c->clkhi = hiClks & MXC_F_I2C_REVA_CLKHI_HI;
    
    // Return the actual speed set, since it won't be exactly what's requested
    return MXC_I2C_GetFrequency ((mxc_i2c_regs_t*) i2c);
}

unsigned int MXC_I2C_RevA_GetFrequency (mxc_i2c_reva_regs_t* i2c)
{
    unsigned int sclCycles = 0;
    
    // Calculate the speed based on what we've written into registers
    sclCycles = (i2c->clklo & MXC_F_I2C_REVA_CLKLO_LO) + (i2c->clkhi & MXC_F_I2C_REVA_CLKHI_HI);
    
    return PeripheralClock / sclCycles;
}

int MXC_I2C_RevA_ReadyForSleep (mxc_i2c_reva_regs_t* i2c)
{
    if (MXC_I2C_GET_IDX ((mxc_i2c_regs_t*) i2c) < 0) {
        return E_BAD_PARAM;
    }
    
    if (AsyncRequests[MXC_I2C_GET_IDX ((mxc_i2c_regs_t*) i2c)] != NULL) {
        return E_BUSY;
    }
    
    return E_NO_ERROR;
}

int MXC_I2C_RevA_SetClockStretching (mxc_i2c_reva_regs_t* i2c, int enable)
{
    if (i2c == NULL) {
        return E_NULL_PTR;
    }
    
    if (enable) {
        i2c->ctrl &= ~MXC_F_I2C_REVA_CTRL_CLKSTR_DIS;
    }
    else {
        i2c->ctrl |= MXC_F_I2C_REVA_CTRL_CLKSTR_DIS;
    }
    
    return E_NO_ERROR;
}

int MXC_I2C_RevA_GetClockStretching (mxc_i2c_reva_regs_t* i2c)
{
    if (i2c == NULL) {
        return E_NULL_PTR;
    }

    return ! ( (i2c->ctrl & MXC_F_I2C_REVA_CTRL_CLKSTR_DIS) >> MXC_F_I2C_REVA_CTRL_CLKSTR_DIS_POS);
}

/* ************************************************************************* */
/* Low-level functions                                                       */
/* ************************************************************************* */
int MXC_I2C_RevA_Start (mxc_i2c_reva_regs_t* i2c)
{
    if (i2c == NULL) {
        return E_NULL_PTR;
    }
    
    // If we have an incomplete transfer, we need to do a restart
    if (i2c->mstctrl & MXC_F_I2C_REVA_MSTCTRL_START) {
        i2c->mstctrl |= MXC_F_I2C_REVA_MSTCTRL_RESTART;
    }
    else {
        i2c->mstctrl |= MXC_F_I2C_REVA_MSTCTRL_START; // No check for start generation
    }
    
    return E_NO_ERROR;
}

int MXC_I2C_RevA_Stop (mxc_i2c_reva_regs_t* i2c)
{
    if (i2c == NULL) {
        return E_NULL_PTR;
    }

    i2c->mstctrl |= MXC_F_I2C_REVA_MSTCTRL_STOP;
    
    while (i2c->mstctrl & MXC_F_I2C_REVA_MSTCTRL_STOP);
    
    return E_NO_ERROR;
}

int MXC_I2C_RevA_WriteByte (mxc_i2c_reva_regs_t* i2c, unsigned char byte)
{
    if (i2c == NULL) {
        return E_NULL_PTR;
    }
    
    if (!(i2c->status & MXC_F_I2C_REVA_STATUS_TX_EM)) {
        return E_OVERFLOW;
    }
    
    // I'm depending on an interrupt flag here
    // This might cause issues with the transaction level functions to come
    MXC_I2C_ClearFlags ((mxc_i2c_regs_t*) i2c, MXC_I2C_REVA_INTFL0_MASK, MXC_I2C_REVA_INTFL1_MASK);
    i2c->fifo = byte;
    
    while (! (i2c->status & MXC_F_I2C_REVA_STATUS_TX_EM));
    
    return i2c->intfl0 & MXC_F_I2C_REVA_INTFL0_DATA_ERR;
}

int MXC_I2C_RevA_ReadByte (mxc_i2c_reva_regs_t* i2c, unsigned char* byte, int ack)
{
    if ((i2c == NULL) || (byte == NULL)) {
        return E_NULL_PTR;
    }

    if (! (i2c->status & MXC_F_I2C_REVA_STATUS_RX_EM)) {
        return E_UNDERFLOW;
    }
    
    *byte = (uint8_t) (i2c->fifo & MXC_F_I2C_REVA_FIFO_DATA);

    if(ack) {
        i2c->ctrl &= ~MXC_F_I2C_REVA_CTRL_IRXM_ACK;
    } else {
        i2c->ctrl |= MXC_F_I2C_REVA_CTRL_IRXM_ACK;
    }

    return E_NO_ERROR;
}

int MXC_I2C_RevA_ReadByteInteractive (mxc_i2c_reva_regs_t* i2c, unsigned char* byte, mxc_i2c_reva_getAck_t getAck)
{
    if ((i2c == NULL) || (byte == NULL)) {
        return E_NULL_PTR;
    }

    if (! (i2c->status & MXC_F_I2C_REVA_STATUS_RX_EM)) {
        return E_UNDERFLOW;
    }
    
    *byte = (uint8_t) (i2c->fifo & MXC_F_I2C_REVA_FIFO_DATA);
    
    if (getAck == NULL) {
        i2c->ctrl &= ~MXC_F_I2C_REVA_CTRL_IRXM_ACK_POS;
    }
    else {
        i2c->ctrl |= (!!getAck ((mxc_i2c_reva_regs_t*) i2c, *byte)) << MXC_F_I2C_REVA_CTRL_IRXM_ACK_POS;
    }
    
    return E_NO_ERROR;
}

int MXC_I2C_RevA_Write (mxc_i2c_reva_regs_t* i2c, unsigned char* bytes, unsigned int* len)
{
    int notAcked = 0;
    unsigned written = 0;
    
    if (i2c == NULL) {
        return E_NULL_PTR;
    }
    
    if ((bytes == NULL) || (len == NULL)) {
        return E_NULL_PTR;
    }
    
    for (; written < *len; written++) {
        int retVal = MXC_I2C_WriteByte ((mxc_i2c_regs_t*) i2c, bytes[written]);
        
        if (retVal >= 0) {
            notAcked += retVal;
        }
        else {
            *len = written;
            return retVal;
        }
    }
    
    *len = written;
    notAcked = (notAcked > 0) ? 1 : 0;
    return notAcked;
}

int MXC_I2C_RevA_Read (mxc_i2c_reva_regs_t* i2c, unsigned char* bytes, unsigned int* len, int ack)
{
    unsigned read = 0;
    
    if (i2c == NULL) {
        return E_NULL_PTR;
    }
    
    if ((bytes == NULL) || (len == NULL)) {
        return E_NULL_PTR;
    }

    for (; read < *len-1; read++) {
        int retVal = MXC_I2C_ReadByte ((mxc_i2c_regs_t*) i2c, & (bytes[read]), 1);
        
        if (retVal != E_NO_ERROR) {
            *len = read;
            return retVal;
        }
    }
    
    read++;
    *len = read;
    return MXC_I2C_ReadByte ((mxc_i2c_regs_t*) i2c, & (bytes[read]), ack);
}

int MXC_I2C_RevA_ReadRXFIFO (mxc_i2c_reva_regs_t* i2c, volatile unsigned char* bytes, unsigned int len)
{
    unsigned read = 0;
    
    if ((i2c == NULL) || (bytes == NULL)) {
        return E_NULL_PTR;
    }
    
    while ( (len > read) && (! (i2c->status & MXC_F_I2C_REVA_STATUS_RX_EM))) {
        bytes[read++] = i2c->fifo;
    }
    
    return read;
}

int MXC_I2C_RevA_ReadRXFIFODMA (mxc_i2c_reva_regs_t* i2c, unsigned char* bytes, unsigned int len, \
                                mxc_i2c_reva_dma_complete_cb_t callback, mxc_dma_config_t config, mxc_dma_regs_t* dma)
{
    uint8_t i2cNum;
    uint8_t channel;
    mxc_dma_srcdst_t srcdst;
    
    if ((i2c == NULL) || (bytes == NULL)) {
        return E_NULL_PTR;
    }

    i2cNum = MXC_I2C_GET_IDX ((mxc_i2c_regs_t*) i2c);
    
  #if TARGET_NUM == 32665
    channel = MXC_DMA_AcquireChannel(dma);
  #else
    channel = MXC_DMA_AcquireChannel();
  #endif
    
    config.ch = channel;
    
    config.srcwd = MXC_DMA_WIDTH_BYTE;
    config.dstwd = MXC_DMA_WIDTH_BYTE;
    
    config.srcinc_en = 0;
    config.dstinc_en = 1;
    
    srcdst.ch = channel;
    srcdst.dest = bytes;
    srcdst.len = len;
    
    states[i2cNum].channelRx = channel;
    MXC_DMA_ConfigChannel(config, srcdst);
    
    if (states[i2cNum].master) {
        MXC_DMA_SetCallback(channel, MXC_I2C_RevA_DMACallback);
    }
    
    else {
        MXC_DMA_SetCallback(channel, NULL);
    }
    
    MXC_DMA_EnableInt (channel);
    MXC_DMA_Start (channel);
    //MXC_DMA->ch[channel].cfg |= MXC_F_DMA_CFG_CTZIEN;
    MXC_DMA_SetChannelInterruptEn(channel, 0, 1);
    i2c->dma |= MXC_F_I2C_REVA_DMA_RX_EN;
    
    return E_NO_ERROR;
}

int MXC_I2C_RevA_GetRXFIFOAvailable (mxc_i2c_reva_regs_t* i2c)
{  
    if(i2c == NULL) {
        return E_NULL_PTR;
    }
        
    return (i2c->rxctrl1 & MXC_F_I2C_REVA_RXCTRL1_LVL) >> MXC_F_I2C_REVA_RXCTRL1_LVL_POS;
}

int MXC_I2C_RevA_WriteTXFIFO (mxc_i2c_reva_regs_t* i2c, volatile unsigned char* bytes, unsigned int len)
{
    unsigned written = 0;
    
    if ((i2c == NULL) || (bytes == NULL)) {
        return E_NULL_PTR;
    }

    while ( (len > written) && (! (i2c->status & MXC_F_I2C_REVA_STATUS_TX_FULL))) {
        i2c->fifo = bytes[written++];
    }
    
    return written;
}

int MXC_I2C_RevA_WriteTXFIFODMA (mxc_i2c_reva_regs_t* i2c, unsigned char* bytes, unsigned int len, \
                                    mxc_i2c_reva_dma_complete_cb_t callback, mxc_dma_config_t config, mxc_dma_regs_t* dma)
{
    uint8_t i2cNum;
    uint8_t channel;
    mxc_dma_srcdst_t srcdst;
    
    if ((i2c == NULL) || (bytes == NULL)) {
        return E_NULL_PTR;
    }

    i2cNum = MXC_I2C_GET_IDX ((mxc_i2c_regs_t*)i2c);
    
    i2c->mstctrl |= MXC_F_I2C_REVA_MSTCTRL_START;
    
  #if TARGET_NUM == 32665
    channel = MXC_DMA_AcquireChannel(dma);
  #else
    channel = MXC_DMA_AcquireChannel();
  #endif
    
    config.ch = channel;
    
    config.srcwd = MXC_DMA_WIDTH_BYTE;
    config.dstwd = MXC_DMA_WIDTH_BYTE;
    
    config.srcinc_en = 1;
    config.dstinc_en = 0;
    
    srcdst.ch = channel;
    srcdst.source = bytes;
    srcdst.len = len;
    
    states[i2cNum].channelTx = channel;
    MXC_DMA_ConfigChannel(config, srcdst);
    
    if (states[i2cNum].master) {
        MXC_DMA_SetCallback(channel, MXC_I2C_RevA_DMACallback);
    }
    else {
        MXC_DMA_SetCallback(channel, NULL);
    }
    
    MXC_DMA_EnableInt (channel);
    MXC_DMA_Start (channel);
    // MXC_DMA->ch[channel].cfg |= MXC_F_DMA_CFG_CTZIEN;
    MXC_DMA_SetChannelInterruptEn(channel, 0, 1);
    i2c->dma |= MXC_F_I2C_REVA_DMA_TX_EN;
    
    return E_NO_ERROR;
}

int MXC_I2C_RevA_GetTXFIFOAvailable (mxc_i2c_reva_regs_t* i2c)
{
    if (i2c == NULL) {
        return E_NULL_PTR;
    }
    
    int txFIFOlen = (i2c->fifolen & MXC_F_I2C_REVA_FIFOLEN_TX_DEPTH) >> MXC_F_I2C_REVA_FIFOLEN_TX_DEPTH_POS;
    return txFIFOlen - ( (i2c->txctrl1 & MXC_F_I2C_REVA_TXCTRL1_LVL) >> MXC_F_I2C_REVA_TXCTRL1_LVL_POS);
}

void MXC_I2C_RevA_ClearRXFIFO (mxc_i2c_reva_regs_t* i2c)
{
    i2c->rxctrl0 |= MXC_F_I2C_REVA_RXCTRL0_FLUSH;
    
    while (i2c->rxctrl0 & MXC_F_I2C_REVA_RXCTRL0_FLUSH);
}

void MXC_I2C_RevA_ClearTXFIFO (mxc_i2c_reva_regs_t* i2c)
{ 
    i2c->txctrl0 |= MXC_F_I2C_REVA_TXCTRL0_FLUSH;
    
    while (i2c->txctrl0 & MXC_F_I2C_REVA_TXCTRL0_FLUSH);
}

int MXC_I2C_RevA_GetFlags (mxc_i2c_reva_regs_t* i2c, unsigned int *flags0, unsigned int *flags1)
{
    if (i2c == NULL) {
        return E_NULL_PTR;
    }
    
    if ((flags0 == NULL) || (flags1 == NULL)) {
        return E_BAD_PARAM;
    }
    
    *flags0 = i2c->intfl0;
    *flags1 = i2c->intfl1;
    
    return E_NO_ERROR;
}

void MXC_I2C_RevA_ClearFlags (mxc_i2c_reva_regs_t* i2c, unsigned int flags0, unsigned int flags1)
{
    i2c->intfl0 = flags0;
    i2c->intfl1 = flags1;
}

void MXC_I2C_RevA_EnableInt (mxc_i2c_reva_regs_t* i2c, unsigned int flags0, unsigned int flags1)
{
    i2c->inten0 |= flags0;
    i2c->inten1 |= flags1;
}

void MXC_I2C_RevA_DisableInt (mxc_i2c_reva_regs_t* i2c, unsigned int flags0, unsigned int flags1)
{
    i2c->inten0 &= ~flags0;
    i2c->inten1 &= ~flags1;
}

int MXC_I2C_RevA_Recover (mxc_i2c_reva_regs_t* i2c, unsigned int retries)
{
    int err;
    unsigned int i;
    
    if(i2c == NULL) {
        return E_NULL_PTR;
    }

    err = E_COMM_ERR;

    i2c->ctrl |= MXC_F_I2C_REVA_CTRL_EN;
    int swBit = i2c->ctrl & MXC_F_I2C_REVA_CTRL_BB_MODE;

    if(i2c == NULL) {
        return E_NULL_PTR;
    }

    i2c->ctrl |= MXC_F_I2C_REVA_CTRL_BB_MODE;
    
    // Follow the procedure detailed in the header file
    // Delay 10uS between each step to give the line/slaves time to react
    for (i = 0; i < retries; i++) {
        MXC_Delay (10);
        i2c->ctrl &= ~MXC_F_I2C_REVA_CTRL_SCL_OUT;
        
        MXC_Delay(10);
        
        if (i2c->ctrl & MXC_F_I2C_REVA_CTRL_SCL) {
            i2c->ctrl |= MXC_F_I2C_REVA_CTRL_SCL_OUT | MXC_F_I2C_REVA_CTRL_SDA_OUT;
            continue; // Give up and try again
        }
        
        MXC_Delay (10);
        i2c->ctrl &= ~MXC_F_I2C_REVA_CTRL_SDA_OUT;
        
        MXC_Delay(10);
        
        if (i2c->ctrl & MXC_F_I2C_REVA_CTRL_SDA) {
            i2c->ctrl |= MXC_F_I2C_REVA_CTRL_SCL_OUT | MXC_F_I2C_REVA_CTRL_SDA_OUT;
            continue; // Give up and try again
        }
        
        MXC_Delay (10);
        i2c->ctrl |= MXC_F_I2C_REVA_CTRL_SDA_OUT;
        
        MXC_Delay(10);
        
        if (! (i2c->ctrl & MXC_F_I2C_REVA_CTRL_SDA)) {
            i2c->ctrl |= MXC_F_I2C_REVA_CTRL_SCL_OUT | MXC_F_I2C_REVA_CTRL_SDA_OUT;
            continue; // Give up and try again
        }
        
        MXC_Delay (10);
        i2c->ctrl |= MXC_F_I2C_REVA_CTRL_SCL_OUT;
        
        MXC_Delay(10);
        
        if (i2c->ctrl & MXC_F_I2C_REVA_CTRL_SCL) {
            err = E_NO_ERROR; // We have control
            break;
        }
    }
    
    if (swBit == 0) {
        i2c->ctrl &= ~MXC_F_I2C_REVA_CTRL_BB_MODE;
    }

    i2c->ctrl &= ~MXC_F_I2C_REVA_CTRL_EN;
    
    return err;
}

void MXC_I2C_RevA_EnablePreload(mxc_i2c_reva_regs_t* i2c)
{
    i2c->txctrl0 |= MXC_F_I2C_REVA_TXCTRL0_PRELOAD_MODE;
}

void MXC_I2C_RevA_DisablePreload(mxc_i2c_reva_regs_t* i2c)
{
    i2c->txctrl0 &= ~MXC_F_I2C_REVA_TXCTRL0_PRELOAD_MODE;
}

void MXC_I2C_RevA_EnableGeneralCall (mxc_i2c_reva_regs_t* i2c)
{
    i2c->txctrl0 &= ~MXC_F_I2C_REVA_TXCTRL0_GC_ADDR_FLUSH_DIS;
}

void MXC_I2C_RevA_DisableGeneralCall (mxc_i2c_reva_regs_t* i2c)
{
    i2c->txctrl0 |= MXC_F_I2C_REVA_TXCTRL0_GC_ADDR_FLUSH_DIS;
}

void MXC_I2C_RevA_SetTimeout (mxc_i2c_reva_regs_t* i2c, unsigned int timeout)
{
    i2c->timeout |= (timeout & 0xFFFF);
}

unsigned int MXC_I2C_RevA_GetTimeout (mxc_i2c_reva_regs_t* i2c)
{
    return (i2c->timeout & 0xFFFF);
}

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

int MXC_I2C_RevA_MasterTransaction (mxc_i2c_reva_req_t* req)
{
    mxc_i2c_reva_regs_t* i2c = req->i2c; // Save off pointer for faster access
    unsigned int written = 0;
    unsigned int read = 0;
    
    if (req->addr > MXC_I2C_REVA_MAX_ADDR_WIDTH) {
        return E_NOT_SUPPORTED;
    }
    
    if (MXC_I2C_GET_IDX ((mxc_i2c_regs_t*) i2c) < 0) {
        return E_BAD_PARAM;
    }
    
    if (!(i2c->ctrl & MXC_F_I2C_REVA_CTRL_MST_MODE)) {
        return E_BAD_STATE;
    }
    
    // if(!read | write)
    //  Start
    //  send addr w/ write bit
    // if(Write)
    //  send tx_len data
    //  return if error (or NACK)
    // if(Read)
    //  if(Write)
    //   send restart
    //  else
    //   send start
    //  send addr w/ read bit
    //  read rx_len bytes acking all
    // stop or restart
    // return good or error
    
    MXC_I2C_ClearFlags ((mxc_i2c_regs_t*) i2c, MXC_I2C_REVA_INTFL0_MASK, MXC_I2C_REVA_INTFL1_MASK); // Clear all I2C Interrupts
    MXC_I2C_ClearTXFIFO ((mxc_i2c_regs_t*) i2c);
    MXC_I2C_ClearRXFIFO ((mxc_i2c_regs_t*) i2c);
    i2c->inten0 = 0;
    i2c->inten1 = 0;
    
    if ((req->rx_len == 0) || (req->tx_len != 0)) {
        // Load the slave address with write bit set
        i2c->fifo = (req->addr << 1) & ~0x1;
        i2c->mstctrl |= MXC_F_I2C_REVA_MSTCTRL_START;
    }
    
    while (req->tx_len > written) {
        if (i2c->intfl0 & MXC_F_I2C_REVA_INTFL0_TX_THD) {
            written += MXC_I2C_WriteTXFIFO ((mxc_i2c_regs_t*) i2c, &req->tx_buf[written], req->tx_len - written);
            i2c->intfl0 = MXC_F_I2C_REVA_INTFL0_TX_THD;
        }
        
        if (i2c->intfl0 & MXC_I2C_REVA_ERROR) {
            req->tx_len = written;
            MXC_I2C_Stop ((mxc_i2c_regs_t*) i2c);
            return E_COMM_ERR;
        }
    }
    
    MXC_I2C_ClearFlags ((mxc_i2c_regs_t*) i2c, MXC_F_I2C_REVA_INTFL0_DONE | MXC_F_I2C_REVA_INTFL0_RX_THD, 0);
    
    if (req->rx_len != 0) {
        if (req->rx_len > MXC_I2C_REVA_MAX_FIFO_TRANSACTION) {
            i2c->rxctrl1 = 0;
        }
        else {
            i2c->rxctrl1 = req->rx_len; // 0 for 256, otherwise number of bytes to read
        }
        
        MXC_I2C_Start ((mxc_i2c_regs_t*) i2c); // Start or Restart as needed
        
        while (i2c->mstctrl & MXC_F_I2C_REVA_MSTCTRL_RESTART);
        
        i2c->fifo = (req->addr << 1) | 0x1;     // Load slave address with read bit.
    }
    
    while (req->rx_len > read) {
        if (i2c->intfl0 & (MXC_F_I2C_REVA_INTFL0_RX_THD | MXC_F_I2C_REVA_INTFL0_DONE)) {
            read += MXC_I2C_ReadRXFIFO ((mxc_i2c_regs_t*) i2c, &req->rx_buf[read], req->rx_len - read);
            i2c->intfl0 = MXC_F_I2C_REVA_INTFL0_RX_THD;
        }
        
        if (i2c->intfl0 & MXC_I2C_REVA_ERROR) {
            req->rx_len = read;
            MXC_I2C_Stop ((mxc_i2c_regs_t*) i2c);
            return E_COMM_ERR;
        }
        
        if ( (i2c->intfl0 & MXC_F_I2C_REVA_INTFL0_DONE) && (req->rx_len < read)) {
            if ( (req->rx_len-read) > MXC_I2C_REVA_MAX_FIFO_TRANSACTION) {
                i2c->rxctrl1 = 0;
            }
            else {
                i2c->rxctrl1 = (req->rx_len - read); // 0 for 256, otherwise number of bytes to read
            }
            
            i2c->mstctrl |= MXC_F_I2C_REVA_MSTCTRL_RESTART;
            i2c->intfl0 = MXC_F_I2C_REVA_INTFL0_DONE;
            i2c->fifo = (req->addr << 1) | 0x1;     // Load slave address with read bit.
        }
    }
    
    if (req->restart) {
        i2c->mstctrl |= MXC_F_I2C_REVA_MSTCTRL_RESTART;
    }
    else {
        i2c->mstctrl |= MXC_F_I2C_REVA_MSTCTRL_STOP;
    }
    
    while (!(i2c->intfl0 & MXC_F_I2C_REVA_INTFL0_STOP)); // Wait for Transaction to finish
    while (!(i2c->intfl0 & MXC_F_I2C_REVA_INTFL0_DONE)); // Wait for Transaction to finish
    
    i2c->intfl0 = MXC_F_I2C_REVA_INTFL0_DONE | MXC_F_I2C_REVA_INTFL0_STOP;
    
    if (i2c->intfl0 & MXC_I2C_REVA_ERROR) {
        return E_COMM_ERR;
    }
    
    return E_NO_ERROR;
}

int MXC_I2C_RevA_MasterTransactionAsync (mxc_i2c_reva_req_t* req)
{
    int i2cNum = MXC_I2C_GET_IDX ((mxc_i2c_regs_t*)(req->i2c));
    mxc_i2c_reva_regs_t* i2c = req->i2c;
    
    if (i2cNum < 0) {
        return E_BAD_PARAM;
    }
    
    if (!(i2c->ctrl & MXC_F_I2C_REVA_CTRL_MST_MODE)) {
        return E_BAD_STATE;
    }
    
    if (AsyncRequests[i2cNum] == NULL) {
        if (req->addr > MXC_I2C_REVA_MAX_ADDR_WIDTH) {
            return E_NOT_SUPPORTED;
        }
        
        AsyncRequests[i2cNum] = (void*) req;
        AsyncWritten[i2cNum] = 0;
        AsyncRead[i2cNum] = 0;
        MXC_I2C_ClearFlags ((mxc_i2c_regs_t*) i2c, MXC_I2C_REVA_INTFL0_MASK, MXC_I2C_REVA_INTFL1_MASK); // Clear all I2C Interrupts
        MXC_I2C_ClearTXFIFO ((mxc_i2c_regs_t*) i2c);
        MXC_I2C_ClearRXFIFO ((mxc_i2c_regs_t*) i2c);
        
        if ((req->rx_len == 0) || (req->tx_len != 0)) {
            i2c->fifo = (req->addr << 1) & ~0x1;    // Load the slave address with write bit set
            i2c->mstctrl |= MXC_F_I2C_REVA_MSTCTRL_START;
        }
        
        i2c->inten0 = MXC_I2C_REVA_ERROR | MXC_F_I2C_REVA_INTEN0_TX_THD;
        return E_NO_ERROR;
    }
    else {
        return E_BUSY;
    }
}

int MXC_I2C_RevA_MasterTransactionDMA (mxc_i2c_reva_req_t* req, mxc_dma_regs_t* dma)
{
    int i2cNum;
    
    mxc_i2c_reva_regs_t* i2c = req->i2c; // Save off pointer for faster access
    i2cNum = MXC_I2C_GET_IDX ((mxc_i2c_regs_t*) i2c);

    if (req->addr > MXC_I2C_REVA_MAX_ADDR_WIDTH) {
        return E_NOT_SUPPORTED;
    }
    
    if (i2cNum < 0) {
        return E_BAD_PARAM;
    }
    
    if (!(i2c->ctrl & MXC_F_I2C_REVA_CTRL_MST_MODE)) {
        return E_BAD_STATE;
    }
    
    if (req->rx_len > MXC_I2C_REVA_MAX_FIFO_TRANSACTION) {
        return E_BAD_PARAM;
    }
    
    MXC_I2C_ClearFlags ((mxc_i2c_regs_t*) i2c, MXC_I2C_REVA_INTFL0_MASK, MXC_I2C_REVA_INTFL1_MASK); // Clear all I2C Interrupts
    MXC_I2C_ClearTXFIFO ((mxc_i2c_regs_t*) i2c);
    MXC_I2C_ClearRXFIFO ((mxc_i2c_regs_t*) i2c);
    
    MXC_I2C_SetTXThreshold ((mxc_i2c_regs_t*) i2c, 2);
    MXC_I2C_SetRXThreshold ((mxc_i2c_regs_t*) i2c, 1);
    
    states[i2cNum].req = req;
    
    states[i2cNum].channelTx = 0xFF;
    states[i2cNum].channelRx = 0xFF;
    
  #if TARGET_NUM == 32665
    MXC_DMA_Init(dma);
  #else
    MXC_DMA_Init();
  #endif
    
    //tx
    if ((req->tx_buf != NULL) && !(states[i2cNum].writeDone)) {
        i2c->fifo = ((req->addr) << 1) & ~0x1;    // Load the slave address with write bit set
        
      #if TARGET_NUM == 32665
        MXC_I2C_WriteTXFIFODMA ((mxc_i2c_regs_t*) i2c, req->tx_buf, req->tx_len, NULL, dma);
      #else
        MXC_I2C_WriteTXFIFODMA ((mxc_i2c_regs_t*) i2c, req->tx_buf, req->tx_len, NULL);
      #endif
    }
    else {
        states[i2cNum].writeDone = 1;
    }
    
    if (req->rx_buf != NULL) {
        while(states[i2cNum].writeDone != 1);			//Ensure DMA transmit has finished before attempting to receive

        if ( (states[i2cNum].writeDone) && (!states[i2cNum].readDone)) {
            if (req->rx_len > MXC_I2C_REVA_MAX_FIFO_TRANSACTION) {
                i2c->rxctrl1 = 0;
            }
            else {
                i2c->rxctrl1 = req->rx_len; // 0 for 256, otherwise number of bytes to read
            }

            MXC_I2C_Start ((mxc_i2c_regs_t*) i2c); // Start or Restart as needed
            
            while (i2c->mstctrl & MXC_F_I2C_REVA_MSTCTRL_RESTART);
            
            i2c->fifo = ((req->addr) << 1) | 0x1;    // Load the slave address with write bit set

          #if TARGET_NUM == 32665
            MXC_I2C_ReadRXFIFODMA ((mxc_i2c_regs_t*) i2c, req->rx_buf, req->rx_len, NULL, dma);
          #else
            MXC_I2C_ReadRXFIFODMA ((mxc_i2c_regs_t*) i2c, req->rx_buf, req->rx_len, NULL);
          #endif
        }
    }
    else {
        states[i2cNum].readDone = 1;
    }
    
    return E_NO_ERROR;
}

void MXC_I2C_RevA_DMACallback(int ch, int error)
{
    mxc_i2c_reva_req_t *temp_req;
    
    for (int i = 0; i < MXC_I2C_INSTANCES; i ++) {
        if (states[i].channelTx == ch) {
            //save the request
            temp_req = states[i].req;
            states[i].writeDone = 1;
            
            if (states[i].readDone) {
                if (temp_req->restart) {
                    (temp_req->i2c)->mstctrl |= MXC_F_I2C_REVA_MSTCTRL_RESTART;
                }
                else {
                    (temp_req->i2c)->mstctrl |= MXC_F_I2C_REVA_MSTCTRL_STOP;
                }
            
                MXC_DMA_ReleaseChannel(states[i].channelRx);
                MXC_DMA_ReleaseChannel(states[i].channelTx);
                
                // Callback if not NULL
                if (temp_req->callback != NULL) {
                    temp_req->callback(temp_req, E_NO_ERROR);
                }
            }
        }
        
        else if (states[i].channelRx == ch) {
            //save the request
            states[i].readDone = 1;
            temp_req = states[i].req;
            
            if (states[i].writeDone) {
                if (temp_req->restart) {
                    (temp_req->i2c)->mstctrl |= MXC_F_I2C_REVA_MSTCTRL_RESTART;
                }
                else {
                    (temp_req->i2c)->mstctrl |= MXC_F_I2C_REVA_MSTCTRL_STOP;
                }
                
                MXC_DMA_ReleaseChannel(states[i].channelRx);
                MXC_DMA_ReleaseChannel(states[i].channelTx);
                
                // Callback if not NULL
                if (temp_req->callback != NULL) {
                    temp_req->callback(temp_req, E_NO_ERROR);
                }                
            }
        }
    }
}

int MXC_I2C_RevA_SlaveTransaction (mxc_i2c_reva_regs_t* i2c, mxc_i2c_reva_slave_handler_t callback, uint32_t interruptCheck)
{
    unsigned int interruptEnables = interruptCheck;
    int retVal = E_NO_ERROR;
    
    if (MXC_I2C_GET_IDX ((mxc_i2c_regs_t*) i2c) < 0) {
        return E_BAD_PARAM;
    }
    
    if (i2c->ctrl & MXC_F_I2C_REVA_CTRL_MST_MODE) {
        return E_BAD_STATE;
    }
    
    MXC_I2C_ClearFlags ((mxc_i2c_regs_t*) i2c, MXC_I2C_REVA_INTFL0_MASK, MXC_I2C_REVA_INTFL1_MASK); // Clear all I2C Interrupts
    MXC_I2C_ClearTXFIFO ((mxc_i2c_regs_t*) i2c);
    MXC_I2C_ClearRXFIFO ((mxc_i2c_regs_t*) i2c);
    
    // Callback called on
    // Slave Address Match (distinguish read/write)
    // RX Threshold
    // TX Threshold
    // Done
    // TX Underflow
    // RX Overflow
    //
    // Event Codes
    // I2C_EVT_MASTER_WR
    // I2C_EVT_MASTER_RD
    // I2C_EVT_RX_THRESH
    // I2C_EVT_TX_THRESH
    // I2C_EVT_TRANS_COMP
    // I2C_EVT_UNDERFLOW
    // I2C_EVT_OVERFLOW
    
    while (interruptEnables > 0) {
        interruptEnables = MXC_I2C_RevA_SlaveAsyncHandler(i2c, callback, interruptEnables, &retVal);
    }
    
    return retVal;
}

int MXC_I2C_RevA_SlaveTransactionAsync (mxc_i2c_reva_regs_t* i2c, mxc_i2c_reva_slave_handler_t callback, uint32_t interruptCheck)
{
    int i2cnum = MXC_I2C_GET_IDX((mxc_i2c_regs_t*) i2c);
    
    if (i2cnum < 0) {
        return E_BAD_PARAM;
    }
    
    if (i2c->ctrl & MXC_F_I2C_REVA_CTRL_MST_MODE) {
        return E_BAD_STATE;
    }
    
    if (AsyncRequests[i2cnum] != NULL) {
        return E_BUSY;
    }
    
    MXC_I2C_ClearFlags ((mxc_i2c_regs_t*) i2c, MXC_I2C_REVA_INTFL0_MASK, MXC_I2C_REVA_INTFL1_MASK); // Clear all I2C Interrupts
    MXC_I2C_ClearTXFIFO ((mxc_i2c_regs_t*) i2c);
    MXC_I2C_ClearRXFIFO ((mxc_i2c_regs_t*) i2c);
    MXC_I2C_SetTXThreshold ((mxc_i2c_regs_t*) i2c, 1);    // set TX threshold to 2 bytes
    MXC_I2C_SetRXThreshold ((mxc_i2c_regs_t*) i2c, 1);    // set RX threshold to 6 bytes
    AsyncRequests[i2cnum] = (void *) callback;
    
    i2c->inten0 = interruptCheck;
    
    return E_NO_ERROR;
}

int MXC_I2C_RevA_SetRXThreshold (mxc_i2c_reva_regs_t* i2c, unsigned int numBytes)
{
    unsigned int rxFIFOlen = (i2c->fifolen & MXC_F_I2C_REVA_FIFOLEN_RX_DEPTH) >> MXC_F_I2C_REVA_FIFOLEN_RX_DEPTH_POS;
    
    if (numBytes > rxFIFOlen) {
        return E_BAD_PARAM;
    }
    
    i2c->rxctrl0 = (i2c->rxctrl0 & ~MXC_F_I2C_REVA_RXCTRL0_THD_LVL) | (numBytes << MXC_F_I2C_REVA_RXCTRL0_THD_LVL_POS);
    return E_NO_ERROR;
}

unsigned int MXC_I2C_RevA_GetRXThreshold (mxc_i2c_reva_regs_t* i2c)
{
    return (i2c->rxctrl0 & MXC_F_I2C_REVA_RXCTRL0_THD_LVL) >> MXC_F_I2C_REVA_RXCTRL0_THD_LVL_POS;
}

int MXC_I2C_RevA_SetTXThreshold (mxc_i2c_reva_regs_t* i2c, unsigned int numBytes)
{
    unsigned int txFIFOlen = (i2c->fifolen & MXC_F_I2C_REVA_FIFOLEN_TX_DEPTH) >> MXC_F_I2C_REVA_FIFOLEN_TX_DEPTH_POS;
    
    if (numBytes > txFIFOlen) {
        return E_BAD_PARAM;
    }
    
    i2c->txctrl0 = (i2c->txctrl0 & ~MXC_F_I2C_REVA_TXCTRL0_THD_LVL) | (numBytes << MXC_F_I2C_REVA_TXCTRL0_THD_LVL_POS);
    return E_NO_ERROR;
}

unsigned int MXC_I2C_RevA_GetTXThreshold (mxc_i2c_reva_regs_t* i2c)
{
    return (i2c->txctrl0 & MXC_F_I2C_REVA_TXCTRL0_THD_LVL) >> MXC_F_I2C_REVA_TXCTRL0_THD_LVL_POS;
}

void MXC_I2C_RevA_AsyncCallback (mxc_i2c_reva_regs_t* i2c, int retVal)
{
    // Don't need to check for return value as this function is not accessible to user
    // i2c is already cheked for NULL from where this function is being called
    mxc_i2c_reva_req_t* req = (mxc_i2c_reva_req_t*) AsyncRequests[MXC_I2C_GET_IDX ((mxc_i2c_regs_t*) i2c)];
    
    if (req->callback != NULL) {
        req->callback(req, retVal);
    }
}

void MXC_I2C_RevA_AsyncStop (mxc_i2c_reva_regs_t* i2c)
{
    i2c->inten0 = 0;
    i2c->inten1 = 0;
    
    // Don't need to check for return value as this function is not accessible to user
    // i2c is already cheked for NULL from where this function is being called
    AsyncRequests[MXC_I2C_GET_IDX ((mxc_i2c_regs_t*) i2c)] = NULL;
}

void MXC_I2C_RevA_AbortAsync (mxc_i2c_reva_regs_t* i2c)
{
    // Don't need to check for return value as this function is not accessible to user
    // i2c is already cheked for NULL from where this function is being called
    MXC_I2C_RevA_AsyncCallback(i2c, E_ABORT);
    MXC_I2C_RevA_AsyncStop(i2c);
}

void MXC_I2C_RevA_MasterAsyncHandler(int i2cNum)
{
    unsigned int written = AsyncWritten[i2cNum];
    unsigned int read = AsyncRead[i2cNum];
    mxc_i2c_reva_regs_t* i2c = (mxc_i2c_reva_regs_t*) MXC_I2C_GET_BASE (i2cNum);
    mxc_i2c_reva_req_t* req = (mxc_i2c_reva_req_t*) AsyncRequests[i2cNum];
    
    if (req->tx_len > written) {
        if (i2c->intfl0 & MXC_F_I2C_REVA_INTFL0_TX_THD) {
            written += MXC_I2C_WriteTXFIFO ((mxc_i2c_regs_t*) i2c, &req->tx_buf[written], req->tx_len - written);
            i2c->intfl0 = MXC_F_I2C_REVA_INTFL0_TX_THD;
        }
        
        if (i2c->intfl0 & MXC_I2C_REVA_ERROR) {
            req->tx_len = written;
            MXC_I2C_Stop ((mxc_i2c_regs_t*) i2c);
            MXC_I2C_RevA_AsyncCallback (i2c, E_COMM_ERR);
            MXC_I2C_RevA_AsyncStop (i2c);
        }
    }
    
    if (req->rx_len > read) {
        if (i2c->intfl0 & (MXC_F_I2C_REVA_INTFL0_RX_THD | MXC_F_I2C_REVA_INTFL0_DONE)) {
            read += MXC_I2C_ReadRXFIFO ((mxc_i2c_regs_t*) i2c, &req->rx_buf[read], req->rx_len - read);
            i2c->intfl0 = MXC_F_I2C_REVA_INTFL0_RX_THD;
        }
        
        if (i2c->intfl0 & MXC_I2C_REVA_ERROR) {
            req->rx_len = read;
            MXC_I2C_Stop ((mxc_i2c_regs_t*) i2c);
            MXC_I2C_RevA_AsyncCallback (i2c, E_COMM_ERR);
            MXC_I2C_RevA_AsyncStop (i2c);
        }
        
        if ( (i2c->intfl0 & MXC_F_I2C_REVA_INTFL0_DONE) && (req->rx_len < read)) {
            if ( (req->rx_len-read) > MXC_I2C_REVA_MAX_FIFO_TRANSACTION) {
                i2c->rxctrl1 = 0;
            }
            else {
                i2c->rxctrl1 = (req->rx_len - read); // 0 for 256, otherwise number of bytes to read
            }
            
            i2c->mstctrl |= MXC_F_I2C_REVA_MSTCTRL_RESTART;
            i2c->intfl0 = MXC_F_I2C_REVA_INTFL0_DONE;
            i2c->fifo = (req->addr << 1) | 0x1;         // Load slave address with read bit.
        }
    }
    
    if ( (req->tx_len == written) && (read == 0)) {
        i2c->inten0 &= ~MXC_F_I2C_REVA_INTEN0_TX_THD;
        i2c->inten0 |= MXC_F_I2C_REVA_INTEN0_RX_THD | MXC_F_I2C_REVA_INTEN0_DONE;
        
        if ( (req->rx_len) > MXC_I2C_REVA_MAX_FIFO_TRANSACTION) {
            i2c->rxctrl1 = 0;
        }
        else {
            i2c->rxctrl1 = (req->rx_len); // 0 for 256, otherwise number of bytes to read
        }
        
        MXC_I2C_Start ((mxc_i2c_regs_t*) i2c); // Start or Restart as needed
        
        i2c->fifo = (req->addr << 1) | 0x1;     // Load slave address with read bit.
    }
    
    if ( (req->tx_len == written) && (req->rx_len == read)) {
        i2c->inten0 &= ~ (MXC_F_I2C_REVA_INTEN0_RX_THD | MXC_F_I2C_REVA_INTEN0_DONE);
        
        if (req->restart) {
            i2c->mstctrl |= MXC_F_I2C_REVA_MSTCTRL_RESTART;
        }
        else {
            i2c->mstctrl |= MXC_F_I2C_REVA_MSTCTRL_STOP;
        }
        
        if (i2c->intfl0 & MXC_I2C_REVA_ERROR) {
            MXC_I2C_RevA_AsyncCallback (i2c, E_COMM_ERR);
        }
        else {
            MXC_I2C_RevA_AsyncCallback(i2c, E_NO_ERROR);
        }
        
        MXC_I2C_RevA_AsyncStop(i2c);
    }
    
    AsyncWritten[i2cNum] = written;
    AsyncRead[i2cNum] = read;
}

unsigned int MXC_I2C_RevA_SlaveAsyncHandler (mxc_i2c_reva_regs_t* i2c, mxc_i2c_reva_slave_handler_t callback, unsigned int interruptEnables, int* retVal)
{
    uint32_t tFlags = i2c->intfl0;
    *retVal = E_NO_ERROR;
    
    uint32_t readFlag = i2c->ctrl & MXC_F_I2C_REVA_CTRL_READ;
    // Callback called on
    // Slave Address Match (distinguish read/write)
    // RX Threshold
    // TX Threshold
    // Done
    // TX Underflow
    // RX Overflow
    //
    // Event Codes
    // I2C_EVT_MASTER_WR
    // I2C_EVT_MASTER_RD
    // I2C_EVT_RX_THRESH
    // I2C_EVT_TX_THRESH
    // I2C_EVT_TRANS_COMP
    // I2C_EVT_UNDERFLOW
    // I2C_EVT_OVERFLOW
    if (!(interruptEnables & (MXC_F_I2C_REVA_INTFL0_RD_ADDR_MATCH | MXC_F_I2C_REVA_INTFL0_WR_ADDR_MATCH| MXC_F_I2C_REVA_INTFL0_ADDR_MATCH))) {
        // The STOPERR/STARTERR interrupt that's enabled here could fire before we are addressed
        // (fires anytime a stop/start is detected out of sequence).
        if (tFlags & MXC_I2C_REVA_ERROR) {
            *retVal = E_COMM_ERR;
            callback (i2c, MXC_I2C_REVA_EVT_TRANS_COMP, retVal);
            MXC_I2C_ClearFlags ((mxc_i2c_regs_t*) i2c, MXC_I2C_REVA_INTFL0_MASK, MXC_I2C_REVA_INTFL1_MASK); // Clear all I2C Interrupts
            MXC_I2C_ClearTXFIFO ((mxc_i2c_regs_t*) i2c);
            MXC_I2C_ClearRXFIFO ((mxc_i2c_regs_t*) i2c);
            interruptEnables = 0;
            AsyncRequests[MXC_I2C_GET_IDX ((mxc_i2c_regs_t*) i2c)] = NULL;
        }
        
        if (interruptEnables & (MXC_F_I2C_REVA_INTFL0_RX_THD | MXC_F_I2C_REVA_INTFL1_RX_OV)) {
            if (tFlags & MXC_F_I2C_REVA_INTFL0_RX_THD) {
                callback (i2c, MXC_I2C_REVA_EVT_RX_THRESH, NULL);
                i2c->intfl0 = MXC_F_I2C_REVA_INTFL0_RX_THD;
            }
            
            if (i2c->intfl1 & MXC_F_I2C_REVA_INTFL1_RX_OV) {
                callback (i2c, MXC_I2C_REVA_EVT_OVERFLOW, NULL);
                i2c->intfl1 = MXC_F_I2C_REVA_INTFL1_RX_OV;
            }
        }
        
        if (interruptEnables & (MXC_F_I2C_REVA_INTFL0_TX_THD | MXC_F_I2C_REVA_INTFL1_TX_UN | MXC_F_I2C_REVA_INTFL0_TX_LOCKOUT)) {
            if (tFlags & MXC_F_I2C_REVA_INTFL0_TX_THD) {
                callback (i2c, MXC_I2C_REVA_EVT_TX_THRESH, NULL);
                i2c->intfl0 = MXC_F_I2C_REVA_INTFL0_TX_THD;
            }
            
            if (i2c->intfl1 & MXC_F_I2C_REVA_INTFL1_TX_UN) {
                callback (i2c, MXC_I2C_REVA_EVT_UNDERFLOW, NULL);
                i2c->intfl1 = MXC_F_I2C_REVA_INTFL1_TX_UN;
            }
            
            if (tFlags & MXC_F_I2C_REVA_INTFL0_TX_LOCKOUT) {
                *retVal = E_NO_ERROR;
                callback (i2c, MXC_I2C_REVA_EVT_TRANS_COMP, retVal);
                i2c->intfl0 = MXC_F_I2C_REVA_INTFL0_TX_LOCKOUT;
                interruptEnables = 0;
                AsyncRequests[MXC_I2C_GET_IDX ((mxc_i2c_regs_t*) i2c)] = NULL;
            }
        }
        
        if (tFlags & MXC_F_I2C_REVA_INTFL0_STOP) {
            *retVal = E_NO_ERROR;
            callback (i2c, MXC_I2C_REVA_EVT_TRANS_COMP, retVal);
            i2c->intfl0 = MXC_F_I2C_REVA_INTFL0_STOP;
            interruptEnables = 0;
            AsyncRequests[MXC_I2C_GET_IDX ((mxc_i2c_regs_t*) i2c)] = NULL;
        }
    }

    if (tFlags & MXC_F_I2C_REVA_INTFL0_RD_ADDR_MATCH) {
        callback (i2c, MXC_I2C_REVA_EVT_MASTER_WR, NULL);
        i2c->intfl0 = MXC_F_I2C_REVA_INTFL0_RD_ADDR_MATCH;
        i2c->intfl0 = MXC_F_I2C_REVA_INTFL0_ADDR_MATCH;
        interruptEnables = MXC_F_I2C_REVA_INTFL0_RX_THD | MXC_F_I2C_REVA_INTFL1_RX_OV | MXC_I2C_REVA_ERROR;
    }
    
    if (tFlags & MXC_F_I2C_REVA_INTFL0_WR_ADDR_MATCH) {
        callback (i2c, MXC_I2C_REVA_EVT_MASTER_RD, NULL);
        i2c->intfl0 = MXC_F_I2C_REVA_INTFL0_WR_ADDR_MATCH;
        i2c->intfl0 = MXC_F_I2C_REVA_INTFL0_ADDR_MATCH;
        interruptEnables = MXC_F_I2C_REVA_INTFL0_TX_THD | MXC_F_I2C_REVA_INTFL1_TX_UN | MXC_F_I2C_REVA_INTFL0_TX_LOCKOUT | MXC_I2C_REVA_ERROR;
    }

    if (tFlags & MXC_F_I2C_REVA_INTFL0_ADDR_MATCH){
        if (readFlag & MXC_F_I2C_REVA_CTRL_READ) {
            callback (i2c, MXC_I2C_REVA_EVT_MASTER_RD, NULL);
            i2c->intfl0 = MXC_F_I2C_REVA_INTFL0_ADDR_MATCH;
            i2c->intfl0 = MXC_F_I2C_REVA_INTFL0_ADDR_MATCH;
            interruptEnables = MXC_F_I2C_REVA_INTFL0_TX_THD | MXC_F_I2C_REVA_INTFL1_TX_UN | MXC_F_I2C_REVA_INTFL0_TX_LOCKOUT | MXC_I2C_REVA_ERROR;
        }
        else {
            callback (i2c, MXC_I2C_REVA_EVT_MASTER_WR, NULL);
            i2c->intfl0 = MXC_F_I2C_REVA_INTFL0_ADDR_MATCH;
            i2c->intfl0 = MXC_F_I2C_REVA_INTFL0_ADDR_MATCH;
            interruptEnables = MXC_F_I2C_REVA_INTFL0_RX_THD | MXC_F_I2C_REVA_INTFL1_RX_OV | MXC_I2C_REVA_ERROR;            
        }
    } else if (tFlags & MXC_I2C_REVA_ERROR) {
        *retVal = E_COMM_ERR;
        callback (i2c, MXC_I2C_REVA_EVT_TRANS_COMP, retVal);
        MXC_I2C_RevA_ClearFlags(i2c, MXC_I2C_REVA_INTFL0_MASK, MXC_I2C_REVA_INTFL1_MASK);   // clear all i2c interrupts
        MXC_I2C_RevA_ClearTXFIFO(i2c);
        MXC_I2C_RevA_ClearRXFIFO(i2c);
        interruptEnables = 0;
        AsyncRequests[MXC_I2C_GET_IDX ((mxc_i2c_regs_t*) i2c)] = NULL;    
    }
    
    return interruptEnables;
}

void MXC_I2C_RevA_AsyncHandler (mxc_i2c_reva_regs_t* i2c, uint32_t interruptCheck)
{
    int i2cNum = MXC_I2C_GET_IDX ((mxc_i2c_regs_t*) i2c);
    int slaveRetVal;
    
    if (i2cNum < 0) {
        return;
    }
    
    if (i2c->ctrl & MXC_F_I2C_REVA_CTRL_MST_MODE) {
        MXC_I2C_RevA_MasterAsyncHandler (i2cNum);
    }
    else {
        mxc_i2c_reva_slave_handler_t callback = (mxc_i2c_reva_slave_handler_t) AsyncRequests[i2cNum];
        i2c->inten0 = MXC_I2C_RevA_SlaveAsyncHandler (i2c, callback, i2c->inten0, &slaveRetVal);
    }
}