int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) { int err, retval = 0; int i; if (!(obj->stop_pending) && (obj->i2c->trans & MXC_F_I2CM_TRANS_TX_IN_PROGRESS)) { return 0; } // clear all interrupts obj->i2c->intfl = 0x3FF; // write the address to the fifo if ((err = write_tx_fifo(obj, (MXC_S_I2CM_TRANS_TAG_START | address))) != 0) { // start + addr (write) i2c_reset(obj); return err; } obj->start_pending = 0; // start the transaction obj->i2c->trans |= MXC_F_I2CM_TRANS_TX_START; // load as much of the cmd into the FIFO as possible for (i = 0; i < length; i++) { if ((err = write_tx_fifo(obj, (MXC_S_I2CM_TRANS_TAG_TXDATA_ACK | data[i]))) != 0) { // cmd (expect ACK) retval = (retval ? retval : err); break; } } if (stop) { obj->stop_pending = 0; if ((err = write_tx_fifo(obj, MXC_S_I2CM_TRANS_TAG_STOP)) != 0) { // stop condition retval = (retval ? retval : err); } if ((err = wait_tx_in_progress(obj)) != 0) { retval = (retval ? retval : err); } } else { obj->stop_pending = 1; int timeout = MXC_I2CM_TX_TIMEOUT; // Wait for TX fifo to be empty while (!(obj->i2c->intfl & MXC_F_I2CM_INTFL_TX_FIFO_EMPTY) && timeout--); } if (retval == 0) { return length; } i2c_reset(obj); return retval; }
int i2c_byte_read(i2c_t *obj, int last) { uint16_t fifo_value; int err; // clear all interrupts obj->i2c->intfl = 0x3FF; if (last) { fifo_value = MXC_S_I2CM_TRANS_TAG_RXDATA_NACK; } else { fifo_value = MXC_S_I2CM_TRANS_TAG_RXDATA_COUNT; } if ((err = write_tx_fifo(obj, fifo_value)) != 0) { return err; } obj->i2c->trans |= MXC_F_I2CM_TRANS_TX_START; int timeout = MXC_I2CM_RX_TIMEOUT; while (!(obj->i2c->intfl & MXC_F_I2CM_INTFL_RX_FIFO_NOT_EMPTY) && (!(obj->i2c->bb & MXC_F_I2CM_BB_RX_FIFO_CNT))) { if ((--timeout < 0) || !(obj->i2c->trans & MXC_F_I2CM_TRANS_TX_IN_PROGRESS)) { break; } } if (obj->i2c->intfl & MXC_F_I2CM_INTFL_RX_FIFO_NOT_EMPTY) { obj->i2c->intfl = MXC_F_I2CM_INTFL_RX_FIFO_NOT_EMPTY; return *obj->rxfifo; } return -1; }
int i2c_stop(i2c_t *obj) { obj->start_pending = 0; write_tx_fifo(obj, MXC_S_I2CM_TRANS_TAG_STOP); return wait_tx_in_progress(obj); }
int i2c_byte_write(i2c_t *obj, int data) { int err; // clear all interrupts obj->i2c->intfl = 0x3FF; if (obj->start_pending) { obj->start_pending = 0; data = (data & 0xFF) | MXC_S_I2CM_TRANS_TAG_START; } else { data = (data & 0xFF) | MXC_S_I2CM_TRANS_TAG_TXDATA_ACK; } if ((err = write_tx_fifo(obj, data)) != 0) { return err; } obj->i2c->trans |= MXC_F_I2CM_TRANS_TX_START; // Wait for the FIFO to be empty while (!(obj->i2c->intfl & MXC_F_I2CM_INTFL_TX_FIFO_EMPTY)); if (obj->i2c->intfl & MXC_F_I2CM_INTFL_TX_NACKED) { i2c_reset(obj); return 0; } if (obj->i2c->intfl & (MXC_F_I2CM_INTFL_TX_TIMEOUT | MXC_F_I2CM_INTFL_TX_LOST_ARBITR)) { i2c_reset(obj); return 2; } return 1; }
int i2c_byte_write(i2c_t *obj, int data) { int err; // clear all interrupts obj->i2c->intfl = 0x3FF; if (obj->start_pending) { obj->start_pending = 0; data = (data & 0xFF) | MXC_S_I2CM_TRANS_TAG_START; } else { data = (data & 0xFF) | MXC_S_I2CM_TRANS_TAG_TXDATA_ACK; } if ((err = write_tx_fifo(obj, data)) != 0) { return err; } obj->i2c->trans |= MXC_F_I2CM_TRANS_TX_START; return 0; }
int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) { int err, retval = 0; int i = length; int timeout; if (!(obj->stop_pending) && (obj->i2c->trans & MXC_F_I2CM_TRANS_TX_IN_PROGRESS)) { return 0; } // clear all interrupts obj->i2c->intfl = 0x3FF; // start + addr (read) if ((retval = write_tx_fifo(obj, (MXC_S_I2CM_TRANS_TAG_START | address | I2C_SLAVE_ADDR_READ_BIT))) != 0) { goto read_done; } obj->start_pending = 0; while (i > 256) { if ((retval = write_tx_fifo(obj, (MXC_S_I2CM_TRANS_TAG_RXDATA_COUNT | 255))) != 0) { goto read_done; } i -= 256; } if (i > 1) { if ((retval = write_tx_fifo(obj, (MXC_S_I2CM_TRANS_TAG_RXDATA_COUNT | (i - 2)))) != 0) { goto read_done; } } // start the transaction obj->i2c->trans |= MXC_F_I2CM_TRANS_TX_START; if ((retval = write_tx_fifo(obj, MXC_S_I2CM_TRANS_TAG_RXDATA_NACK)) != 0) { // NACK last data byte goto read_done; } if (stop) { if ((retval = write_tx_fifo(obj, MXC_S_I2CM_TRANS_TAG_STOP)) != 0) { // stop condition goto read_done; } } timeout = MXC_I2CM_RX_TIMEOUT; i = 0; while (i < length) { while (!(obj->i2c->intfl & MXC_F_I2CM_INTFL_RX_FIFO_NOT_EMPTY) && (!(obj->i2c->bb & MXC_F_I2CM_BB_RX_FIFO_CNT))) { if ((--timeout < 0) || !(obj->i2c->trans & MXC_F_I2CM_TRANS_TX_IN_PROGRESS)) { retval = -3; goto read_done; } } timeout = MXC_I2CM_RX_TIMEOUT; obj->i2c->intfl = MXC_F_I2CM_INTFL_RX_FIFO_NOT_EMPTY; uint16_t temp = *obj->rxfifo; if (temp & MXC_S_I2CM_RSTLS_TAG_EMPTY) { continue; } data[i++] = (uint8_t) temp; } read_done: if (stop) { obj->stop_pending = 0; if ((err = wait_tx_in_progress(obj)) != 0) { retval = (retval ? retval : err); } } else { obj->stop_pending = 1; } if (retval == 0) { return length; } return retval; }