ON Semiconductor / mbed-os

Dependents:   mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510

Committer:
group-onsemi
Date:
Wed Jan 25 20:34:15 2017 +0000
Revision:
0:098463de4c5d
Initial commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
group-onsemi 0:098463de4c5d 1 /*******************************************************************************
group-onsemi 0:098463de4c5d 2 * Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved.
group-onsemi 0:098463de4c5d 3 *
group-onsemi 0:098463de4c5d 4 * Permission is hereby granted, free of charge, to any person obtaining a
group-onsemi 0:098463de4c5d 5 * copy of this software and associated documentation files (the "Software"),
group-onsemi 0:098463de4c5d 6 * to deal in the Software without restriction, including without limitation
group-onsemi 0:098463de4c5d 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
group-onsemi 0:098463de4c5d 8 * and/or sell copies of the Software, and to permit persons to whom the
group-onsemi 0:098463de4c5d 9 * Software is furnished to do so, subject to the following conditions:
group-onsemi 0:098463de4c5d 10 *
group-onsemi 0:098463de4c5d 11 * The above copyright notice and this permission notice shall be included
group-onsemi 0:098463de4c5d 12 * in all copies or substantial portions of the Software.
group-onsemi 0:098463de4c5d 13 *
group-onsemi 0:098463de4c5d 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
group-onsemi 0:098463de4c5d 15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
group-onsemi 0:098463de4c5d 16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
group-onsemi 0:098463de4c5d 17 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
group-onsemi 0:098463de4c5d 18 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
group-onsemi 0:098463de4c5d 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
group-onsemi 0:098463de4c5d 20 * OTHER DEALINGS IN THE SOFTWARE.
group-onsemi 0:098463de4c5d 21 *
group-onsemi 0:098463de4c5d 22 * Except as contained in this notice, the name of Maxim Integrated
group-onsemi 0:098463de4c5d 23 * Products, Inc. shall not be used except as stated in the Maxim Integrated
group-onsemi 0:098463de4c5d 24 * Products, Inc. Branding Policy.
group-onsemi 0:098463de4c5d 25 *
group-onsemi 0:098463de4c5d 26 * The mere transfer of this software does not imply any licenses
group-onsemi 0:098463de4c5d 27 * of trade secrets, proprietary technology, copyrights, patents,
group-onsemi 0:098463de4c5d 28 * trademarks, maskwork rights, or any other form of intellectual
group-onsemi 0:098463de4c5d 29 * property whatsoever. Maxim Integrated Products, Inc. retains all
group-onsemi 0:098463de4c5d 30 * ownership rights.
group-onsemi 0:098463de4c5d 31 *
group-onsemi 0:098463de4c5d 32 * $Date: 2016-06-01 08:51:23 -0500 (Wed, 01 Jun 2016) $
group-onsemi 0:098463de4c5d 33 * $Revision: 23131 $
group-onsemi 0:098463de4c5d 34 *
group-onsemi 0:098463de4c5d 35 ******************************************************************************/
group-onsemi 0:098463de4c5d 36
group-onsemi 0:098463de4c5d 37 /**
group-onsemi 0:098463de4c5d 38 * @file i2cm.c
group-onsemi 0:098463de4c5d 39 * @brief I2C Master driver source.
group-onsemi 0:098463de4c5d 40 */
group-onsemi 0:098463de4c5d 41
group-onsemi 0:098463de4c5d 42 /***** Includes *****/
group-onsemi 0:098463de4c5d 43 #include <string.h>
group-onsemi 0:098463de4c5d 44 #include <math.h>
group-onsemi 0:098463de4c5d 45 #include "mxc_assert.h"
group-onsemi 0:098463de4c5d 46 #include "mxc_lock.h"
group-onsemi 0:098463de4c5d 47 #include "mxc_errors.h"
group-onsemi 0:098463de4c5d 48 #include "mxc_sys.h"
group-onsemi 0:098463de4c5d 49 #include "i2cm.h"
group-onsemi 0:098463de4c5d 50
group-onsemi 0:098463de4c5d 51 /***** Definitions *****/
group-onsemi 0:098463de4c5d 52
group-onsemi 0:098463de4c5d 53 #ifndef MXC_I2CM_TX_TIMEOUT
group-onsemi 0:098463de4c5d 54 #define MXC_I2CM_TX_TIMEOUT 0x5000
group-onsemi 0:098463de4c5d 55 #endif
group-onsemi 0:098463de4c5d 56
group-onsemi 0:098463de4c5d 57 #ifndef MXC_I2CM_RX_TIMEOUT
group-onsemi 0:098463de4c5d 58 #define MXC_I2CM_RX_TIMEOUT 0x5000
group-onsemi 0:098463de4c5d 59 #endif
group-onsemi 0:098463de4c5d 60
group-onsemi 0:098463de4c5d 61 #define I2CM_READ_BIT 0x0001
group-onsemi 0:098463de4c5d 62 #define I2CM_FIFO_DEPTH_3Q ((3 * MXC_I2CM_FIFO_DEPTH) / 4)
group-onsemi 0:098463de4c5d 63 #define I2CM_FIFO_DEPTH_2Q (MXC_I2CM_FIFO_DEPTH / 2)
group-onsemi 0:098463de4c5d 64
group-onsemi 0:098463de4c5d 65 /***** Globals *****/
group-onsemi 0:098463de4c5d 66
group-onsemi 0:098463de4c5d 67 // Saves the state of the non-blocking requests
group-onsemi 0:098463de4c5d 68 typedef enum {
group-onsemi 0:098463de4c5d 69 I2CM_STATE_READING = 0,
group-onsemi 0:098463de4c5d 70 I2CM_STATE_WRITING = 1
group-onsemi 0:098463de4c5d 71 } i2cm_state_t;
group-onsemi 0:098463de4c5d 72
group-onsemi 0:098463de4c5d 73 typedef struct {
group-onsemi 0:098463de4c5d 74 i2cm_req_t *req;
group-onsemi 0:098463de4c5d 75 i2cm_state_t state;
group-onsemi 0:098463de4c5d 76 } i2cm_req_state_t;
group-onsemi 0:098463de4c5d 77 static i2cm_req_state_t states[MXC_CFG_I2CM_INSTANCES];
group-onsemi 0:098463de4c5d 78
group-onsemi 0:098463de4c5d 79 /***** Functions *****/
group-onsemi 0:098463de4c5d 80
group-onsemi 0:098463de4c5d 81 //static void I2CM_Recover(mxc_i2cm_regs_t *i2cm);
group-onsemi 0:098463de4c5d 82 //static int I2CM_WriteTxFifo(mxc_i2cm_regs_t *regs, mxc_i2cm_fifo_regs_t *fifo, const uint16_t data);
group-onsemi 0:098463de4c5d 83 //static int I2CM_TxInProgress(mxc_i2cm_regs_t *i2cm);
group-onsemi 0:098463de4c5d 84 static void I2CM_FreeCallback(int i2cm_num, int error);
group-onsemi 0:098463de4c5d 85 //static int I2CM_Tx(mxc_i2cm_regs_t *i2cm, mxc_i2cm_fifo_regs_t *fifo, uint8_t addr,
group-onsemi 0:098463de4c5d 86 // const uint8_t *data, uint32_t len, uint8_t stop);
group-onsemi 0:098463de4c5d 87
group-onsemi 0:098463de4c5d 88 //static int I2CM_Rx(mxc_i2cm_regs_t *i2cm, mxc_i2cm_fifo_regs_t *fifo, uint8_t addr,
group-onsemi 0:098463de4c5d 89 // uint8_t *data, uint32_t len);
group-onsemi 0:098463de4c5d 90
group-onsemi 0:098463de4c5d 91 static int I2CM_CmdHandler(mxc_i2cm_regs_t *i2cm, mxc_i2cm_fifo_regs_t *fifo, i2cm_req_t *req);
group-onsemi 0:098463de4c5d 92 static int I2CM_ReadHandler(mxc_i2cm_regs_t *i2cm, i2cm_req_t *req, int i2cm_num);
group-onsemi 0:098463de4c5d 93 static int I2CM_WriteHandler(mxc_i2cm_regs_t *i2cm, i2cm_req_t *req, int i2cm_num);
group-onsemi 0:098463de4c5d 94
group-onsemi 0:098463de4c5d 95 /******************************************************************************/
group-onsemi 0:098463de4c5d 96 int I2CM_Init(mxc_i2cm_regs_t *i2cm, const sys_cfg_i2cm_t *sys_cfg, i2cm_speed_t speed)
group-onsemi 0:098463de4c5d 97 {
group-onsemi 0:098463de4c5d 98 int err;
group-onsemi 0:098463de4c5d 99
group-onsemi 0:098463de4c5d 100 // Check the base pointer
group-onsemi 0:098463de4c5d 101 MXC_ASSERT(MXC_I2CM_GET_IDX(i2cm) >= 0);
group-onsemi 0:098463de4c5d 102
group-onsemi 0:098463de4c5d 103 // Set system level configurations
group-onsemi 0:098463de4c5d 104 if ((err = SYS_I2CM_Init(i2cm, sys_cfg)) != E_NO_ERROR) {
group-onsemi 0:098463de4c5d 105 return err;
group-onsemi 0:098463de4c5d 106 }
group-onsemi 0:098463de4c5d 107
group-onsemi 0:098463de4c5d 108 I2CM_SetFrequency(i2cm,speed);
group-onsemi 0:098463de4c5d 109
group-onsemi 0:098463de4c5d 110 // Reset module
group-onsemi 0:098463de4c5d 111 i2cm->ctrl = MXC_F_I2CM_CTRL_MSTR_RESET_EN;
group-onsemi 0:098463de4c5d 112 i2cm->ctrl = 0;
group-onsemi 0:098463de4c5d 113
group-onsemi 0:098463de4c5d 114 // Set timeout to 255 ms and turn on the auto-stop option
group-onsemi 0:098463de4c5d 115 i2cm->timeout = (MXC_F_I2CM_TIMEOUT_TX_TIMEOUT | MXC_F_I2CM_TIMEOUT_AUTO_STOP_EN);
group-onsemi 0:098463de4c5d 116
group-onsemi 0:098463de4c5d 117 // Enable tx_fifo and rx_fifo
group-onsemi 0:098463de4c5d 118 i2cm->ctrl |= (MXC_F_I2CM_CTRL_TX_FIFO_EN | MXC_F_I2CM_CTRL_RX_FIFO_EN);
group-onsemi 0:098463de4c5d 119
group-onsemi 0:098463de4c5d 120 return E_NO_ERROR;
group-onsemi 0:098463de4c5d 121 }
group-onsemi 0:098463de4c5d 122
group-onsemi 0:098463de4c5d 123 /******************************************************************************/
group-onsemi 0:098463de4c5d 124 int I2CM_Shutdown(mxc_i2cm_regs_t *i2cm)
group-onsemi 0:098463de4c5d 125 {
group-onsemi 0:098463de4c5d 126 int i2cm_num, err;
group-onsemi 0:098463de4c5d 127
group-onsemi 0:098463de4c5d 128 // Check the base pointer
group-onsemi 0:098463de4c5d 129 i2cm_num = MXC_I2CM_GET_IDX(i2cm);
group-onsemi 0:098463de4c5d 130 MXC_ASSERT(i2cm_num >= 0);
group-onsemi 0:098463de4c5d 131
group-onsemi 0:098463de4c5d 132 // Disable and clear interrupts
group-onsemi 0:098463de4c5d 133 i2cm->inten = 0;
group-onsemi 0:098463de4c5d 134 i2cm->intfl = i2cm->intfl;
group-onsemi 0:098463de4c5d 135
group-onsemi 0:098463de4c5d 136 // Call all of the pending callbacks for this I2CM
group-onsemi 0:098463de4c5d 137 if(states[i2cm_num].req != NULL) {
group-onsemi 0:098463de4c5d 138 I2CM_Recover(i2cm);
group-onsemi 0:098463de4c5d 139 I2CM_FreeCallback(i2cm_num, E_SHUTDOWN);
group-onsemi 0:098463de4c5d 140 }
group-onsemi 0:098463de4c5d 141
group-onsemi 0:098463de4c5d 142 // Clears system level configurations
group-onsemi 0:098463de4c5d 143 if ((err = SYS_I2CM_Shutdown(i2cm)) != E_NO_ERROR) {
group-onsemi 0:098463de4c5d 144 return err;
group-onsemi 0:098463de4c5d 145 }
group-onsemi 0:098463de4c5d 146
group-onsemi 0:098463de4c5d 147 return E_NO_ERROR;
group-onsemi 0:098463de4c5d 148 }
group-onsemi 0:098463de4c5d 149
group-onsemi 0:098463de4c5d 150
group-onsemi 0:098463de4c5d 151 /******************************************************************************/
group-onsemi 0:098463de4c5d 152 int I2CM_Read(mxc_i2cm_regs_t *i2cm, uint8_t addr, const uint8_t *cmd_data,
group-onsemi 0:098463de4c5d 153 uint32_t cmd_len, uint8_t* data, uint32_t len)
group-onsemi 0:098463de4c5d 154 {
group-onsemi 0:098463de4c5d 155 int i2cm_num;
group-onsemi 0:098463de4c5d 156 int error = E_NO_ERROR;
group-onsemi 0:098463de4c5d 157 int retval = E_NO_ERROR;
group-onsemi 0:098463de4c5d 158 mxc_i2cm_fifo_regs_t *fifo;
group-onsemi 0:098463de4c5d 159
group-onsemi 0:098463de4c5d 160 if(data == NULL) {
group-onsemi 0:098463de4c5d 161 return E_NULL_PTR;
group-onsemi 0:098463de4c5d 162 }
group-onsemi 0:098463de4c5d 163
group-onsemi 0:098463de4c5d 164 // Make sure the I2CM has been initialized
group-onsemi 0:098463de4c5d 165 if(i2cm->ctrl == 0) {
group-onsemi 0:098463de4c5d 166 return E_UNINITIALIZED;
group-onsemi 0:098463de4c5d 167 }
group-onsemi 0:098463de4c5d 168
group-onsemi 0:098463de4c5d 169 if(!(len > 0)) {
group-onsemi 0:098463de4c5d 170 return E_NO_ERROR;
group-onsemi 0:098463de4c5d 171 }
group-onsemi 0:098463de4c5d 172
group-onsemi 0:098463de4c5d 173 // Lock this I2CM
group-onsemi 0:098463de4c5d 174 i2cm_num = MXC_I2CM_GET_IDX(i2cm);
group-onsemi 0:098463de4c5d 175 while(mxc_get_lock((uint32_t*)&states[i2cm_num].req,1) != E_NO_ERROR) {}
group-onsemi 0:098463de4c5d 176
group-onsemi 0:098463de4c5d 177 // Get the FIFO pointer for this I2CM
group-onsemi 0:098463de4c5d 178 fifo = MXC_I2CM_GET_FIFO(i2cm_num);
group-onsemi 0:098463de4c5d 179
group-onsemi 0:098463de4c5d 180 // Disable and clear the interrupts
group-onsemi 0:098463de4c5d 181 i2cm->inten = 0;
group-onsemi 0:098463de4c5d 182 i2cm->intfl = i2cm->intfl;
group-onsemi 0:098463de4c5d 183
group-onsemi 0:098463de4c5d 184 // Transmit the command if there is command data and length
group-onsemi 0:098463de4c5d 185 if((cmd_data != NULL) && (cmd_len > 0)) {
group-onsemi 0:098463de4c5d 186 retval = I2CM_Tx(i2cm, fifo, addr, cmd_data, cmd_len, 0);
group-onsemi 0:098463de4c5d 187 }
group-onsemi 0:098463de4c5d 188
group-onsemi 0:098463de4c5d 189 // Read data from the slave if we don't have any errors
group-onsemi 0:098463de4c5d 190 if(retval == E_NO_ERROR) {
group-onsemi 0:098463de4c5d 191 retval = I2CM_Rx(i2cm, fifo, addr, data, len);
group-onsemi 0:098463de4c5d 192 }
group-onsemi 0:098463de4c5d 193
group-onsemi 0:098463de4c5d 194 // Wait for the transaction to complete
group-onsemi 0:098463de4c5d 195 if((error = I2CM_TxInProgress(i2cm)) != E_NO_ERROR) {
group-onsemi 0:098463de4c5d 196 retval = error;
group-onsemi 0:098463de4c5d 197 }
group-onsemi 0:098463de4c5d 198
group-onsemi 0:098463de4c5d 199 // Unlock this I2CM
group-onsemi 0:098463de4c5d 200 mxc_free_lock((uint32_t*)&states[i2cm_num].req);
group-onsemi 0:098463de4c5d 201
group-onsemi 0:098463de4c5d 202 if(retval != E_NO_ERROR) {
group-onsemi 0:098463de4c5d 203 return retval;
group-onsemi 0:098463de4c5d 204 }
group-onsemi 0:098463de4c5d 205
group-onsemi 0:098463de4c5d 206 return len;
group-onsemi 0:098463de4c5d 207 }
group-onsemi 0:098463de4c5d 208
group-onsemi 0:098463de4c5d 209 /******************************************************************************/
group-onsemi 0:098463de4c5d 210 int I2CM_Write(mxc_i2cm_regs_t *i2cm, uint8_t addr, const uint8_t *cmd_data,
group-onsemi 0:098463de4c5d 211 uint32_t cmd_len, uint8_t* data, uint32_t len)
group-onsemi 0:098463de4c5d 212 {
group-onsemi 0:098463de4c5d 213 int i2cm_num;
group-onsemi 0:098463de4c5d 214 int error = E_NO_ERROR;
group-onsemi 0:098463de4c5d 215 int retval = E_NO_ERROR;
group-onsemi 0:098463de4c5d 216 mxc_i2cm_fifo_regs_t *fifo;
group-onsemi 0:098463de4c5d 217
group-onsemi 0:098463de4c5d 218 if(data == NULL) {
group-onsemi 0:098463de4c5d 219 return E_NULL_PTR;
group-onsemi 0:098463de4c5d 220 }
group-onsemi 0:098463de4c5d 221
group-onsemi 0:098463de4c5d 222 // Make sure the I2CM has been initialized
group-onsemi 0:098463de4c5d 223 if(i2cm->ctrl == 0) {
group-onsemi 0:098463de4c5d 224 return E_UNINITIALIZED;
group-onsemi 0:098463de4c5d 225 }
group-onsemi 0:098463de4c5d 226
group-onsemi 0:098463de4c5d 227 if(!(len > 0)) {
group-onsemi 0:098463de4c5d 228 return E_NO_ERROR;
group-onsemi 0:098463de4c5d 229 }
group-onsemi 0:098463de4c5d 230
group-onsemi 0:098463de4c5d 231 // Lock this I2CM
group-onsemi 0:098463de4c5d 232 i2cm_num = MXC_I2CM_GET_IDX(i2cm);
group-onsemi 0:098463de4c5d 233 while(mxc_get_lock((uint32_t*)&states[i2cm_num].req,1) != E_NO_ERROR) {}
group-onsemi 0:098463de4c5d 234
group-onsemi 0:098463de4c5d 235 // Get the FIFO pointer for this I2CM
group-onsemi 0:098463de4c5d 236 fifo = MXC_I2CM_GET_FIFO(i2cm_num);
group-onsemi 0:098463de4c5d 237
group-onsemi 0:098463de4c5d 238 // Disable and clear the interrupts
group-onsemi 0:098463de4c5d 239 i2cm->inten = 0;
group-onsemi 0:098463de4c5d 240 i2cm->intfl = i2cm->intfl;
group-onsemi 0:098463de4c5d 241
group-onsemi 0:098463de4c5d 242 // Transmit the command if there is command data and length, don't send stop bit
group-onsemi 0:098463de4c5d 243 if((cmd_data != NULL) && (cmd_len > 0)) {
group-onsemi 0:098463de4c5d 244 retval = I2CM_Tx(i2cm, fifo, addr, cmd_data, cmd_len, 0);
group-onsemi 0:098463de4c5d 245 }
group-onsemi 0:098463de4c5d 246
group-onsemi 0:098463de4c5d 247 // Write data to the slave, send the stop bit
group-onsemi 0:098463de4c5d 248 if(retval == E_NO_ERROR) {
group-onsemi 0:098463de4c5d 249 retval = I2CM_Tx(i2cm, fifo, addr, data, len, 1);
group-onsemi 0:098463de4c5d 250 }
group-onsemi 0:098463de4c5d 251
group-onsemi 0:098463de4c5d 252 // Wait for the transaction to complete
group-onsemi 0:098463de4c5d 253 if((error = I2CM_TxInProgress(i2cm)) != E_NO_ERROR) {
group-onsemi 0:098463de4c5d 254 retval = error;
group-onsemi 0:098463de4c5d 255 }
group-onsemi 0:098463de4c5d 256
group-onsemi 0:098463de4c5d 257 // Unlock this I2CM
group-onsemi 0:098463de4c5d 258 mxc_free_lock((uint32_t*)&states[i2cm_num].req);
group-onsemi 0:098463de4c5d 259
group-onsemi 0:098463de4c5d 260 if(retval != E_NO_ERROR) {
group-onsemi 0:098463de4c5d 261 return retval;
group-onsemi 0:098463de4c5d 262 }
group-onsemi 0:098463de4c5d 263
group-onsemi 0:098463de4c5d 264 return len;
group-onsemi 0:098463de4c5d 265 }
group-onsemi 0:098463de4c5d 266
group-onsemi 0:098463de4c5d 267 /******************************************************************************/
group-onsemi 0:098463de4c5d 268 int I2CM_ReadAsync(mxc_i2cm_regs_t *i2cm, i2cm_req_t *req)
group-onsemi 0:098463de4c5d 269 {
group-onsemi 0:098463de4c5d 270 int i2cm_num, error;
group-onsemi 0:098463de4c5d 271
group-onsemi 0:098463de4c5d 272 if(req->data == NULL) {
group-onsemi 0:098463de4c5d 273 return E_NULL_PTR;
group-onsemi 0:098463de4c5d 274 }
group-onsemi 0:098463de4c5d 275
group-onsemi 0:098463de4c5d 276 // Make sure the I2CM has been initialized
group-onsemi 0:098463de4c5d 277 if(i2cm->ctrl == 0) {
group-onsemi 0:098463de4c5d 278 return E_UNINITIALIZED;
group-onsemi 0:098463de4c5d 279 }
group-onsemi 0:098463de4c5d 280
group-onsemi 0:098463de4c5d 281 if(!(req->data_len > 0)) {
group-onsemi 0:098463de4c5d 282 return E_NO_ERROR;
group-onsemi 0:098463de4c5d 283 }
group-onsemi 0:098463de4c5d 284
group-onsemi 0:098463de4c5d 285 i2cm_num = MXC_I2CM_GET_IDX(i2cm);
group-onsemi 0:098463de4c5d 286
group-onsemi 0:098463de4c5d 287 // Attempt to register this request
group-onsemi 0:098463de4c5d 288 if(mxc_get_lock((uint32_t*)&states[i2cm_num].req, (uint32_t)req) != E_NO_ERROR) {
group-onsemi 0:098463de4c5d 289 return E_BUSY;
group-onsemi 0:098463de4c5d 290 }
group-onsemi 0:098463de4c5d 291
group-onsemi 0:098463de4c5d 292 states[i2cm_num].state = I2CM_STATE_READING;
group-onsemi 0:098463de4c5d 293
group-onsemi 0:098463de4c5d 294 // Clear the number of bytes counter
group-onsemi 0:098463de4c5d 295 req->cmd_num = 0;
group-onsemi 0:098463de4c5d 296 req->data_num = 0;
group-onsemi 0:098463de4c5d 297
group-onsemi 0:098463de4c5d 298 // Disable and clear the interrupts
group-onsemi 0:098463de4c5d 299 i2cm->inten = 0;
group-onsemi 0:098463de4c5d 300 i2cm->intfl = i2cm->intfl;
group-onsemi 0:098463de4c5d 301
group-onsemi 0:098463de4c5d 302 // Start the read
group-onsemi 0:098463de4c5d 303 if((error = I2CM_ReadHandler(i2cm, req, i2cm_num)) != E_NO_ERROR) {
group-onsemi 0:098463de4c5d 304 I2CM_Recover(i2cm);
group-onsemi 0:098463de4c5d 305 I2CM_FreeCallback(i2cm_num, error);
group-onsemi 0:098463de4c5d 306 return error;
group-onsemi 0:098463de4c5d 307 }
group-onsemi 0:098463de4c5d 308
group-onsemi 0:098463de4c5d 309 return E_NO_ERROR;
group-onsemi 0:098463de4c5d 310 }
group-onsemi 0:098463de4c5d 311
group-onsemi 0:098463de4c5d 312 /******************************************************************************/
group-onsemi 0:098463de4c5d 313 int I2CM_WriteAsync(mxc_i2cm_regs_t *i2cm, i2cm_req_t *req)
group-onsemi 0:098463de4c5d 314 {
group-onsemi 0:098463de4c5d 315 int i2cm_num, error;
group-onsemi 0:098463de4c5d 316
group-onsemi 0:098463de4c5d 317 if(req->data == NULL) {
group-onsemi 0:098463de4c5d 318 return E_NULL_PTR;
group-onsemi 0:098463de4c5d 319 }
group-onsemi 0:098463de4c5d 320
group-onsemi 0:098463de4c5d 321 // Make sure the I2CM has been initialized
group-onsemi 0:098463de4c5d 322 if(i2cm->ctrl == 0) {
group-onsemi 0:098463de4c5d 323 return E_UNINITIALIZED;
group-onsemi 0:098463de4c5d 324 }
group-onsemi 0:098463de4c5d 325
group-onsemi 0:098463de4c5d 326 if(!(req->data_len > 0)) {
group-onsemi 0:098463de4c5d 327 return E_NO_ERROR;
group-onsemi 0:098463de4c5d 328 }
group-onsemi 0:098463de4c5d 329
group-onsemi 0:098463de4c5d 330 i2cm_num = MXC_I2CM_GET_IDX(i2cm);
group-onsemi 0:098463de4c5d 331
group-onsemi 0:098463de4c5d 332 // Attempt to register this request
group-onsemi 0:098463de4c5d 333 if(mxc_get_lock((uint32_t*)&states[i2cm_num].req, (uint32_t)req) != E_NO_ERROR) {
group-onsemi 0:098463de4c5d 334 return E_BUSY;
group-onsemi 0:098463de4c5d 335 }
group-onsemi 0:098463de4c5d 336
group-onsemi 0:098463de4c5d 337 states[i2cm_num].state = I2CM_STATE_WRITING;
group-onsemi 0:098463de4c5d 338
group-onsemi 0:098463de4c5d 339 // Clear the number of bytes counter
group-onsemi 0:098463de4c5d 340 req->cmd_num = 0;
group-onsemi 0:098463de4c5d 341 req->data_num = 0;
group-onsemi 0:098463de4c5d 342
group-onsemi 0:098463de4c5d 343 // Disable and clear the interrupts
group-onsemi 0:098463de4c5d 344 i2cm->inten = 0;
group-onsemi 0:098463de4c5d 345 i2cm->intfl = i2cm->intfl;
group-onsemi 0:098463de4c5d 346
group-onsemi 0:098463de4c5d 347 // Start the Write
group-onsemi 0:098463de4c5d 348 if((error = I2CM_WriteHandler(i2cm, req, i2cm_num)) != E_NO_ERROR) {
group-onsemi 0:098463de4c5d 349 I2CM_Recover(i2cm);
group-onsemi 0:098463de4c5d 350 I2CM_FreeCallback(i2cm_num, error);
group-onsemi 0:098463de4c5d 351 return error;
group-onsemi 0:098463de4c5d 352 }
group-onsemi 0:098463de4c5d 353
group-onsemi 0:098463de4c5d 354 return E_NO_ERROR;
group-onsemi 0:098463de4c5d 355 }
group-onsemi 0:098463de4c5d 356
group-onsemi 0:098463de4c5d 357 /******************************************************************************/
group-onsemi 0:098463de4c5d 358 int I2CM_AbortAsync(i2cm_req_t *req)
group-onsemi 0:098463de4c5d 359 {
group-onsemi 0:098463de4c5d 360 int i2cm_num;
group-onsemi 0:098463de4c5d 361 mxc_i2cm_regs_t *i2cm;
group-onsemi 0:098463de4c5d 362
group-onsemi 0:098463de4c5d 363 // Find the request, set to NULL
group-onsemi 0:098463de4c5d 364 for(i2cm_num = 0; i2cm_num < MXC_CFG_I2CM_INSTANCES; i2cm_num++) {
group-onsemi 0:098463de4c5d 365 if(req == states[i2cm_num].req) {
group-onsemi 0:098463de4c5d 366
group-onsemi 0:098463de4c5d 367 i2cm = MXC_I2CM_GET_I2CM(i2cm_num);
group-onsemi 0:098463de4c5d 368 I2CM_Recover(i2cm);
group-onsemi 0:098463de4c5d 369 I2CM_FreeCallback(i2cm_num, E_ABORT);
group-onsemi 0:098463de4c5d 370
group-onsemi 0:098463de4c5d 371 return E_NO_ERROR;
group-onsemi 0:098463de4c5d 372 }
group-onsemi 0:098463de4c5d 373 }
group-onsemi 0:098463de4c5d 374
group-onsemi 0:098463de4c5d 375 return E_BAD_PARAM;
group-onsemi 0:098463de4c5d 376 }
group-onsemi 0:098463de4c5d 377
group-onsemi 0:098463de4c5d 378 /******************************************************************************/
group-onsemi 0:098463de4c5d 379 void I2CM_Handler(mxc_i2cm_regs_t *i2cm)
group-onsemi 0:098463de4c5d 380 {
group-onsemi 0:098463de4c5d 381 uint32_t intfl;
group-onsemi 0:098463de4c5d 382 int i2cm_num, error;
group-onsemi 0:098463de4c5d 383
group-onsemi 0:098463de4c5d 384 // Save and clear the interrupts
group-onsemi 0:098463de4c5d 385 intfl = i2cm->intfl;
group-onsemi 0:098463de4c5d 386 i2cm->intfl = intfl;
group-onsemi 0:098463de4c5d 387
group-onsemi 0:098463de4c5d 388 // Mask the disabled interrupts
group-onsemi 0:098463de4c5d 389 intfl &= i2cm->inten;
group-onsemi 0:098463de4c5d 390
group-onsemi 0:098463de4c5d 391 i2cm_num = MXC_I2CM_GET_IDX(i2cm);
group-onsemi 0:098463de4c5d 392
group-onsemi 0:098463de4c5d 393 // Check for errors
group-onsemi 0:098463de4c5d 394 if ((intfl & MXC_F_I2CM_INTFL_TX_NACKED) || (intfl & MXC_F_I2CM_INTFL_TX_LOST_ARBITR)) {
group-onsemi 0:098463de4c5d 395 I2CM_Recover(i2cm);
group-onsemi 0:098463de4c5d 396 I2CM_FreeCallback(i2cm_num, E_COMM_ERR);
group-onsemi 0:098463de4c5d 397 return;
group-onsemi 0:098463de4c5d 398 }
group-onsemi 0:098463de4c5d 399
group-onsemi 0:098463de4c5d 400 if(intfl & MXC_F_I2CM_INTFL_TX_TIMEOUT) {
group-onsemi 0:098463de4c5d 401 I2CM_Recover(i2cm);
group-onsemi 0:098463de4c5d 402 I2CM_FreeCallback(i2cm_num, E_TIME_OUT);
group-onsemi 0:098463de4c5d 403 return;
group-onsemi 0:098463de4c5d 404 }
group-onsemi 0:098463de4c5d 405
group-onsemi 0:098463de4c5d 406 // Read or write
group-onsemi 0:098463de4c5d 407 if(states[i2cm_num].state == I2CM_STATE_READING) {
group-onsemi 0:098463de4c5d 408 if((error = I2CM_ReadHandler(i2cm, states[i2cm_num].req, i2cm_num)) != E_NO_ERROR) {
group-onsemi 0:098463de4c5d 409 I2CM_Recover(i2cm);
group-onsemi 0:098463de4c5d 410 I2CM_FreeCallback(i2cm_num, error);
group-onsemi 0:098463de4c5d 411 return;
group-onsemi 0:098463de4c5d 412 }
group-onsemi 0:098463de4c5d 413
group-onsemi 0:098463de4c5d 414 } else if(states[i2cm_num].state == I2CM_STATE_WRITING) {
group-onsemi 0:098463de4c5d 415 if((error = I2CM_WriteHandler(i2cm, states[i2cm_num].req, i2cm_num)) != E_NO_ERROR) {
group-onsemi 0:098463de4c5d 416 I2CM_Recover(i2cm);
group-onsemi 0:098463de4c5d 417 I2CM_FreeCallback(i2cm_num, error);
group-onsemi 0:098463de4c5d 418 return;
group-onsemi 0:098463de4c5d 419 }
group-onsemi 0:098463de4c5d 420 }
group-onsemi 0:098463de4c5d 421
group-onsemi 0:098463de4c5d 422 // Done with the transaction
group-onsemi 0:098463de4c5d 423 if(intfl & MXC_F_I2CM_INTFL_TX_DONE) {
group-onsemi 0:098463de4c5d 424 I2CM_Recover(i2cm);
group-onsemi 0:098463de4c5d 425 I2CM_FreeCallback(i2cm_num, E_NO_ERROR);
group-onsemi 0:098463de4c5d 426 }
group-onsemi 0:098463de4c5d 427
group-onsemi 0:098463de4c5d 428 }
group-onsemi 0:098463de4c5d 429
group-onsemi 0:098463de4c5d 430 /******************************************************************************/
group-onsemi 0:098463de4c5d 431 int I2CM_Busy(mxc_i2cm_regs_t *i2cm)
group-onsemi 0:098463de4c5d 432 {
group-onsemi 0:098463de4c5d 433 // Check to see if there are any ongoing transactions
group-onsemi 0:098463de4c5d 434 if((states[MXC_I2CM_GET_IDX(i2cm)].req == NULL) &&
group-onsemi 0:098463de4c5d 435 !(i2cm->trans & MXC_F_I2CM_TRANS_TX_IN_PROGRESS)) {
group-onsemi 0:098463de4c5d 436
group-onsemi 0:098463de4c5d 437 return E_NO_ERROR;
group-onsemi 0:098463de4c5d 438 }
group-onsemi 0:098463de4c5d 439
group-onsemi 0:098463de4c5d 440 return E_BUSY;
group-onsemi 0:098463de4c5d 441 }
group-onsemi 0:098463de4c5d 442
group-onsemi 0:098463de4c5d 443 /******************************************************************************/
group-onsemi 0:098463de4c5d 444 int I2CM_PrepForSleep(mxc_i2cm_regs_t *i2cm)
group-onsemi 0:098463de4c5d 445 {
group-onsemi 0:098463de4c5d 446 if(I2CM_Busy(i2cm) != E_NO_ERROR) {
group-onsemi 0:098463de4c5d 447 return E_BUSY;
group-onsemi 0:098463de4c5d 448 }
group-onsemi 0:098463de4c5d 449
group-onsemi 0:098463de4c5d 450 // Disable interrupts
group-onsemi 0:098463de4c5d 451 i2cm->inten = 0;
group-onsemi 0:098463de4c5d 452 return E_NO_ERROR;
group-onsemi 0:098463de4c5d 453 }
group-onsemi 0:098463de4c5d 454
group-onsemi 0:098463de4c5d 455 /******************************************************************************/
group-onsemi 0:098463de4c5d 456 int I2CM_BusCheck(mxc_i2cm_regs_t *i2cm)
group-onsemi 0:098463de4c5d 457 {
group-onsemi 0:098463de4c5d 458 // If SCL is low, we don't have the bus
group-onsemi 0:098463de4c5d 459 if(!(i2cm->bb & MXC_F_I2CM_BB_BB_SCL_IN_VAL)) {
group-onsemi 0:098463de4c5d 460 return E_BUSY;
group-onsemi 0:098463de4c5d 461 }
group-onsemi 0:098463de4c5d 462
group-onsemi 0:098463de4c5d 463 // If SDA is low, we don't have the bus
group-onsemi 0:098463de4c5d 464 if(!(i2cm->bb & MXC_F_I2CM_BB_BB_SDA_IN_VAL)) {
group-onsemi 0:098463de4c5d 465 return E_BUSY;
group-onsemi 0:098463de4c5d 466 }
group-onsemi 0:098463de4c5d 467
group-onsemi 0:098463de4c5d 468 return E_NO_ERROR;
group-onsemi 0:098463de4c5d 469 }
group-onsemi 0:098463de4c5d 470
group-onsemi 0:098463de4c5d 471 /******************************************************************************/
group-onsemi 0:098463de4c5d 472 static void I2CM_FreeCallback(int i2cm_num, int error)
group-onsemi 0:098463de4c5d 473 {
group-onsemi 0:098463de4c5d 474 // Save the request
group-onsemi 0:098463de4c5d 475 i2cm_req_t *temp_req = states[i2cm_num].req;
group-onsemi 0:098463de4c5d 476
group-onsemi 0:098463de4c5d 477 // Unlock this UART to write
group-onsemi 0:098463de4c5d 478 mxc_free_lock((uint32_t*)&states[i2cm_num].req);
group-onsemi 0:098463de4c5d 479
group-onsemi 0:098463de4c5d 480 // Callback if not NULL
group-onsemi 0:098463de4c5d 481 if(temp_req->callback != NULL) {
group-onsemi 0:098463de4c5d 482 temp_req->callback(temp_req, error);
group-onsemi 0:098463de4c5d 483 }
group-onsemi 0:098463de4c5d 484 }
group-onsemi 0:098463de4c5d 485
group-onsemi 0:098463de4c5d 486 /******************************************************************************/
group-onsemi 0:098463de4c5d 487 void I2CM_Recover(mxc_i2cm_regs_t *i2cm)
group-onsemi 0:098463de4c5d 488 {
group-onsemi 0:098463de4c5d 489 // Disable and clear interrupts
group-onsemi 0:098463de4c5d 490 i2cm->inten = 0;
group-onsemi 0:098463de4c5d 491 i2cm->intfl = i2cm->intfl;
group-onsemi 0:098463de4c5d 492 i2cm->ctrl = MXC_F_I2CM_CTRL_MSTR_RESET_EN;
group-onsemi 0:098463de4c5d 493 i2cm->ctrl = MXC_F_I2CM_CTRL_TX_FIFO_EN | MXC_F_I2CM_CTRL_RX_FIFO_EN;
group-onsemi 0:098463de4c5d 494 }
group-onsemi 0:098463de4c5d 495
group-onsemi 0:098463de4c5d 496 /******************************************************************************/
group-onsemi 0:098463de4c5d 497 int I2CM_WriteTxFifo(mxc_i2cm_regs_t *i2cm, mxc_i2cm_fifo_regs_t *fifo, const uint16_t data)
group-onsemi 0:098463de4c5d 498 {
group-onsemi 0:098463de4c5d 499 int32_t timeout = MXC_I2CM_TX_TIMEOUT;
group-onsemi 0:098463de4c5d 500
group-onsemi 0:098463de4c5d 501 // Read the TX FIFO to determine if it's full
group-onsemi 0:098463de4c5d 502 do {
group-onsemi 0:098463de4c5d 503
group-onsemi 0:098463de4c5d 504 // Wait for the TX FIFO to have room and check for errors
group-onsemi 0:098463de4c5d 505 if (i2cm->intfl & (MXC_F_I2CM_INTFL_TX_NACKED |
group-onsemi 0:098463de4c5d 506 MXC_F_I2CM_INTFL_TX_LOST_ARBITR)) {
group-onsemi 0:098463de4c5d 507
group-onsemi 0:098463de4c5d 508 return E_COMM_ERR;
group-onsemi 0:098463de4c5d 509 }
group-onsemi 0:098463de4c5d 510
group-onsemi 0:098463de4c5d 511 if((i2cm->intfl & MXC_F_I2CM_INTFL_TX_TIMEOUT) || !timeout--) {
group-onsemi 0:098463de4c5d 512 return E_TIME_OUT;
group-onsemi 0:098463de4c5d 513 }
group-onsemi 0:098463de4c5d 514
group-onsemi 0:098463de4c5d 515 } while (fifo->tx);
group-onsemi 0:098463de4c5d 516
group-onsemi 0:098463de4c5d 517 fifo->tx = data;
group-onsemi 0:098463de4c5d 518
group-onsemi 0:098463de4c5d 519 return E_NO_ERROR;
group-onsemi 0:098463de4c5d 520 }
group-onsemi 0:098463de4c5d 521
group-onsemi 0:098463de4c5d 522 /******************************************************************************/
group-onsemi 0:098463de4c5d 523 int I2CM_TxInProgress(mxc_i2cm_regs_t *i2cm)
group-onsemi 0:098463de4c5d 524 {
group-onsemi 0:098463de4c5d 525 int32_t timeout = MXC_I2CM_TX_TIMEOUT;
group-onsemi 0:098463de4c5d 526
group-onsemi 0:098463de4c5d 527 while ((i2cm->trans & MXC_F_I2CM_TRANS_TX_IN_PROGRESS) && --timeout);
group-onsemi 0:098463de4c5d 528
group-onsemi 0:098463de4c5d 529 if (i2cm->intfl & (MXC_F_I2CM_INTFL_TX_NACKED |
group-onsemi 0:098463de4c5d 530 MXC_F_I2CM_INTFL_TX_LOST_ARBITR)) {
group-onsemi 0:098463de4c5d 531
group-onsemi 0:098463de4c5d 532 I2CM_Recover(i2cm);
group-onsemi 0:098463de4c5d 533 return E_COMM_ERR;
group-onsemi 0:098463de4c5d 534 }
group-onsemi 0:098463de4c5d 535
group-onsemi 0:098463de4c5d 536 if((i2cm->intfl & MXC_F_I2CM_INTFL_TX_TIMEOUT) && !timeout--) {
group-onsemi 0:098463de4c5d 537 I2CM_Recover(i2cm);
group-onsemi 0:098463de4c5d 538 return E_TIME_OUT;
group-onsemi 0:098463de4c5d 539 }
group-onsemi 0:098463de4c5d 540
group-onsemi 0:098463de4c5d 541 return E_NO_ERROR;
group-onsemi 0:098463de4c5d 542 }
group-onsemi 0:098463de4c5d 543
group-onsemi 0:098463de4c5d 544 /******************************************************************************/
group-onsemi 0:098463de4c5d 545 int I2CM_Tx(mxc_i2cm_regs_t *i2cm, mxc_i2cm_fifo_regs_t *fifo, uint8_t addr,
group-onsemi 0:098463de4c5d 546 const uint8_t *data, uint32_t len, uint8_t stop)
group-onsemi 0:098463de4c5d 547 {
group-onsemi 0:098463de4c5d 548 uint32_t i;
group-onsemi 0:098463de4c5d 549 int error;
group-onsemi 0:098463de4c5d 550
group-onsemi 0:098463de4c5d 551 // Write the address to the TXFIFO
group-onsemi 0:098463de4c5d 552 if((error = I2CM_WriteTxFifo(i2cm, fifo, (MXC_S_I2CM_TRANS_TAG_START | (addr << 1)))) != E_NO_ERROR) {
group-onsemi 0:098463de4c5d 553 return error;
group-onsemi 0:098463de4c5d 554 }
group-onsemi 0:098463de4c5d 555
group-onsemi 0:098463de4c5d 556 // Start the transaction if it is not currently ongoing
group-onsemi 0:098463de4c5d 557 if (!(i2cm->trans & MXC_F_I2CM_TRANS_TX_IN_PROGRESS)) {
group-onsemi 0:098463de4c5d 558 i2cm->trans |= MXC_F_I2CM_TRANS_TX_START;
group-onsemi 0:098463de4c5d 559 }
group-onsemi 0:098463de4c5d 560
group-onsemi 0:098463de4c5d 561 // Fill the FIFO
group-onsemi 0:098463de4c5d 562 for (i = 0; i < len; i++) {
group-onsemi 0:098463de4c5d 563 if((error = I2CM_WriteTxFifo(i2cm, fifo, (MXC_S_I2CM_TRANS_TAG_TXDATA_ACK | data[i]))) != E_NO_ERROR) {
group-onsemi 0:098463de4c5d 564 return error;
group-onsemi 0:098463de4c5d 565 }
group-onsemi 0:098463de4c5d 566 }
group-onsemi 0:098463de4c5d 567
group-onsemi 0:098463de4c5d 568 // Send the stop condition
group-onsemi 0:098463de4c5d 569 if(stop) {
group-onsemi 0:098463de4c5d 570 if ((error = I2CM_WriteTxFifo(i2cm, fifo, MXC_S_I2CM_TRANS_TAG_STOP)) != E_NO_ERROR) {
group-onsemi 0:098463de4c5d 571 return error;
group-onsemi 0:098463de4c5d 572 }
group-onsemi 0:098463de4c5d 573 }
group-onsemi 0:098463de4c5d 574
group-onsemi 0:098463de4c5d 575 return E_NO_ERROR;
group-onsemi 0:098463de4c5d 576 }
group-onsemi 0:098463de4c5d 577
group-onsemi 0:098463de4c5d 578 /******************************************************************************/
group-onsemi 0:098463de4c5d 579 int I2CM_Rx(mxc_i2cm_regs_t *i2cm, mxc_i2cm_fifo_regs_t *fifo, uint8_t addr,
group-onsemi 0:098463de4c5d 580 uint8_t *data, uint32_t len)
group-onsemi 0:098463de4c5d 581 {
group-onsemi 0:098463de4c5d 582 uint32_t i = len;
group-onsemi 0:098463de4c5d 583 int32_t timeout;
group-onsemi 0:098463de4c5d 584 uint16_t temp;
group-onsemi 0:098463de4c5d 585 int error;
group-onsemi 0:098463de4c5d 586
group-onsemi 0:098463de4c5d 587 // Write the address to the TXFIFO
group-onsemi 0:098463de4c5d 588 if((error = I2CM_WriteTxFifo(i2cm, fifo, (MXC_S_I2CM_TRANS_TAG_START |
group-onsemi 0:098463de4c5d 589 (addr << 1) | I2CM_READ_BIT))) != E_NO_ERROR) {
group-onsemi 0:098463de4c5d 590
group-onsemi 0:098463de4c5d 591 return error;
group-onsemi 0:098463de4c5d 592 }
group-onsemi 0:098463de4c5d 593
group-onsemi 0:098463de4c5d 594 // Write to the TXFIFO the number of bytes we want to read
group-onsemi 0:098463de4c5d 595 while(i > 256) {
group-onsemi 0:098463de4c5d 596 if((error = I2CM_WriteTxFifo(i2cm, fifo, (MXC_S_I2CM_TRANS_TAG_RXDATA_COUNT | 255))) != E_NO_ERROR) {
group-onsemi 0:098463de4c5d 597 return error;
group-onsemi 0:098463de4c5d 598 }
group-onsemi 0:098463de4c5d 599
group-onsemi 0:098463de4c5d 600 i -= 256;
group-onsemi 0:098463de4c5d 601 }
group-onsemi 0:098463de4c5d 602
group-onsemi 0:098463de4c5d 603 if(i > 1) {
group-onsemi 0:098463de4c5d 604 if((error = I2CM_WriteTxFifo(i2cm, fifo, (MXC_S_I2CM_TRANS_TAG_RXDATA_COUNT | (i-2)))) != E_NO_ERROR) {
group-onsemi 0:098463de4c5d 605 return error;
group-onsemi 0:098463de4c5d 606 }
group-onsemi 0:098463de4c5d 607 }
group-onsemi 0:098463de4c5d 608
group-onsemi 0:098463de4c5d 609 // Start the transaction if it is not currently ongoing
group-onsemi 0:098463de4c5d 610 if (!(i2cm->trans & MXC_F_I2CM_TRANS_TX_IN_PROGRESS)) {
group-onsemi 0:098463de4c5d 611 i2cm->trans |= MXC_F_I2CM_TRANS_TX_START;
group-onsemi 0:098463de4c5d 612 }
group-onsemi 0:098463de4c5d 613
group-onsemi 0:098463de4c5d 614
group-onsemi 0:098463de4c5d 615 // NACK the last read byte
group-onsemi 0:098463de4c5d 616 if((error = I2CM_WriteTxFifo(i2cm, fifo, (MXC_S_I2CM_TRANS_TAG_RXDATA_NACK))) != E_NO_ERROR) {
group-onsemi 0:098463de4c5d 617 return error;
group-onsemi 0:098463de4c5d 618 }
group-onsemi 0:098463de4c5d 619
group-onsemi 0:098463de4c5d 620 // Send the stop condition
group-onsemi 0:098463de4c5d 621 if ((error = I2CM_WriteTxFifo(i2cm, fifo, MXC_S_I2CM_TRANS_TAG_STOP)) != E_NO_ERROR) {
group-onsemi 0:098463de4c5d 622 return error;
group-onsemi 0:098463de4c5d 623 }
group-onsemi 0:098463de4c5d 624
group-onsemi 0:098463de4c5d 625 // Get the data from the RX FIFO
group-onsemi 0:098463de4c5d 626 i = 0;
group-onsemi 0:098463de4c5d 627 while (i < len) {
group-onsemi 0:098463de4c5d 628
group-onsemi 0:098463de4c5d 629 // Wait for there to be data in the RX FIFO
group-onsemi 0:098463de4c5d 630 timeout = MXC_I2CM_RX_TIMEOUT;
group-onsemi 0:098463de4c5d 631 while (!(i2cm->intfl & MXC_F_I2CM_INTFL_RX_FIFO_NOT_EMPTY) &&
group-onsemi 0:098463de4c5d 632 ((i2cm->bb & MXC_F_I2CM_BB_RX_FIFO_CNT) == 0)) {
group-onsemi 0:098463de4c5d 633
group-onsemi 0:098463de4c5d 634 if((timeout-- < 0) || (i2cm->trans & MXC_F_I2CM_TRANS_TX_TIMEOUT)) {
group-onsemi 0:098463de4c5d 635 return E_TIME_OUT;
group-onsemi 0:098463de4c5d 636 }
group-onsemi 0:098463de4c5d 637
group-onsemi 0:098463de4c5d 638 if (i2cm->trans & (MXC_F_I2CM_TRANS_TX_LOST_ARBITR | MXC_F_I2CM_TRANS_TX_NACKED)) {
group-onsemi 0:098463de4c5d 639 return E_COMM_ERR;
group-onsemi 0:098463de4c5d 640 }
group-onsemi 0:098463de4c5d 641 }
group-onsemi 0:098463de4c5d 642 i2cm->intfl = MXC_F_I2CM_INTFL_RX_FIFO_NOT_EMPTY;
group-onsemi 0:098463de4c5d 643
group-onsemi 0:098463de4c5d 644 // Save the data from the RX FIFO
group-onsemi 0:098463de4c5d 645 temp = fifo->rx;
group-onsemi 0:098463de4c5d 646 if (temp & MXC_S_I2CM_RSTLS_TAG_EMPTY) {
group-onsemi 0:098463de4c5d 647 continue;
group-onsemi 0:098463de4c5d 648 }
group-onsemi 0:098463de4c5d 649 data[i++] = (uint8_t)temp;
group-onsemi 0:098463de4c5d 650 }
group-onsemi 0:098463de4c5d 651
group-onsemi 0:098463de4c5d 652 return E_NO_ERROR;
group-onsemi 0:098463de4c5d 653 }
group-onsemi 0:098463de4c5d 654
group-onsemi 0:098463de4c5d 655 /******************************************************************************/
group-onsemi 0:098463de4c5d 656 static int I2CM_CmdHandler(mxc_i2cm_regs_t *i2cm, mxc_i2cm_fifo_regs_t *fifo, i2cm_req_t *req)
group-onsemi 0:098463de4c5d 657 {
group-onsemi 0:098463de4c5d 658 int error;
group-onsemi 0:098463de4c5d 659
group-onsemi 0:098463de4c5d 660 // Start of the command
group-onsemi 0:098463de4c5d 661 if(req->cmd_num == 0) {
group-onsemi 0:098463de4c5d 662
group-onsemi 0:098463de4c5d 663 // Write the address to the TXFIFO
group-onsemi 0:098463de4c5d 664 if((error = I2CM_WriteTxFifo(i2cm, fifo, (MXC_S_I2CM_TRANS_TAG_START | (req->addr << 1)))) != E_NO_ERROR) {
group-onsemi 0:098463de4c5d 665 return error;
group-onsemi 0:098463de4c5d 666 }
group-onsemi 0:098463de4c5d 667
group-onsemi 0:098463de4c5d 668 // Start the transaction if it is not currently ongoing
group-onsemi 0:098463de4c5d 669 if (!(i2cm->trans & MXC_F_I2CM_TRANS_TX_IN_PROGRESS)) {
group-onsemi 0:098463de4c5d 670 i2cm->trans |= MXC_F_I2CM_TRANS_TX_START;
group-onsemi 0:098463de4c5d 671 }
group-onsemi 0:098463de4c5d 672 }
group-onsemi 0:098463de4c5d 673
group-onsemi 0:098463de4c5d 674 // Write to the FIFO until it is full or we run out of command bytes
group-onsemi 0:098463de4c5d 675 while((req->cmd_num < req->cmd_len) && (!fifo->tx)) {
group-onsemi 0:098463de4c5d 676 fifo->tx = MXC_S_I2CM_TRANS_TAG_TXDATA_ACK | req->cmd_data[req->cmd_num++];
group-onsemi 0:098463de4c5d 677 }
group-onsemi 0:098463de4c5d 678
group-onsemi 0:098463de4c5d 679 return E_NO_ERROR;
group-onsemi 0:098463de4c5d 680 }
group-onsemi 0:098463de4c5d 681
group-onsemi 0:098463de4c5d 682 /******************************************************************************/
group-onsemi 0:098463de4c5d 683 static int I2CM_ReadHandler(mxc_i2cm_regs_t *i2cm, i2cm_req_t *req, int i2cm_num)
group-onsemi 0:098463de4c5d 684 {
group-onsemi 0:098463de4c5d 685 int error, cmd_remain, data_remain;
group-onsemi 0:098463de4c5d 686 uint16_t data;
group-onsemi 0:098463de4c5d 687 uint32_t temp_len, inten;
group-onsemi 0:098463de4c5d 688 mxc_i2cm_fifo_regs_t *fifo;
group-onsemi 0:098463de4c5d 689
group-onsemi 0:098463de4c5d 690 // Get the FIFO pointer for this I2CM
group-onsemi 0:098463de4c5d 691 fifo = MXC_I2CM_GET_FIFO(i2cm_num);
group-onsemi 0:098463de4c5d 692
group-onsemi 0:098463de4c5d 693 cmd_remain = req->cmd_len - req->cmd_num;
group-onsemi 0:098463de4c5d 694 data_remain = req->data_len - req->data_num;
group-onsemi 0:098463de4c5d 695
group-onsemi 0:098463de4c5d 696 // Process the command portion
group-onsemi 0:098463de4c5d 697 if((cmd_remain) && (req->cmd_data != NULL)) {
group-onsemi 0:098463de4c5d 698 if((error = I2CM_CmdHandler(i2cm, fifo, req)) != E_NO_ERROR) {
group-onsemi 0:098463de4c5d 699 return error;
group-onsemi 0:098463de4c5d 700 }
group-onsemi 0:098463de4c5d 701
group-onsemi 0:098463de4c5d 702 cmd_remain = req->cmd_len - req->cmd_num;
group-onsemi 0:098463de4c5d 703 }
group-onsemi 0:098463de4c5d 704
group-onsemi 0:098463de4c5d 705 // Process the data portion
group-onsemi 0:098463de4c5d 706 if((cmd_remain == 0) && (data_remain)) {
group-onsemi 0:098463de4c5d 707
group-onsemi 0:098463de4c5d 708 // Save the data from the RXFIFO
group-onsemi 0:098463de4c5d 709 data = fifo->rx;
group-onsemi 0:098463de4c5d 710 while((req->data_num < req->data_len) && !(data & MXC_S_I2CM_RSTLS_TAG_EMPTY)) {
group-onsemi 0:098463de4c5d 711 req->data[req->data_num++] = data;
group-onsemi 0:098463de4c5d 712 data = fifo->rx;
group-onsemi 0:098463de4c5d 713 }
group-onsemi 0:098463de4c5d 714
group-onsemi 0:098463de4c5d 715 // Start of the data portion
group-onsemi 0:098463de4c5d 716 if(req->data_num == 0) {
group-onsemi 0:098463de4c5d 717
group-onsemi 0:098463de4c5d 718 temp_len = req->data_len;
group-onsemi 0:098463de4c5d 719
group-onsemi 0:098463de4c5d 720 // Write the address to the TXFIFO
group-onsemi 0:098463de4c5d 721 if((error = I2CM_WriteTxFifo(i2cm, fifo, (MXC_S_I2CM_TRANS_TAG_START |
group-onsemi 0:098463de4c5d 722 (req->addr << 1) | I2CM_READ_BIT))) != E_NO_ERROR) {
group-onsemi 0:098463de4c5d 723
group-onsemi 0:098463de4c5d 724 return error;
group-onsemi 0:098463de4c5d 725 }
group-onsemi 0:098463de4c5d 726
group-onsemi 0:098463de4c5d 727 // Write to the TXFIFO the number of bytes we want to read
group-onsemi 0:098463de4c5d 728 while(temp_len > 256) {
group-onsemi 0:098463de4c5d 729 if((error = I2CM_WriteTxFifo(i2cm, fifo, (MXC_S_I2CM_TRANS_TAG_RXDATA_COUNT | 255))) != E_NO_ERROR) {
group-onsemi 0:098463de4c5d 730 return error;
group-onsemi 0:098463de4c5d 731 }
group-onsemi 0:098463de4c5d 732
group-onsemi 0:098463de4c5d 733 temp_len -= 256;
group-onsemi 0:098463de4c5d 734 }
group-onsemi 0:098463de4c5d 735
group-onsemi 0:098463de4c5d 736 if(temp_len > 1) {
group-onsemi 0:098463de4c5d 737 if((error = I2CM_WriteTxFifo(i2cm, fifo, (MXC_S_I2CM_TRANS_TAG_RXDATA_COUNT | (temp_len-2)))) != E_NO_ERROR) {
group-onsemi 0:098463de4c5d 738 return error;
group-onsemi 0:098463de4c5d 739 }
group-onsemi 0:098463de4c5d 740 }
group-onsemi 0:098463de4c5d 741
group-onsemi 0:098463de4c5d 742 // Start the transaction if it is not currently ongoing
group-onsemi 0:098463de4c5d 743 if (!(i2cm->trans & MXC_F_I2CM_TRANS_TX_IN_PROGRESS)) {
group-onsemi 0:098463de4c5d 744 i2cm->trans |= MXC_F_I2CM_TRANS_TX_START;
group-onsemi 0:098463de4c5d 745 }
group-onsemi 0:098463de4c5d 746
group-onsemi 0:098463de4c5d 747 // NACK the last read byte
group-onsemi 0:098463de4c5d 748 if((error = I2CM_WriteTxFifo(i2cm, fifo, (MXC_S_I2CM_TRANS_TAG_RXDATA_NACK))) != E_NO_ERROR) {
group-onsemi 0:098463de4c5d 749 return error;
group-onsemi 0:098463de4c5d 750 }
group-onsemi 0:098463de4c5d 751
group-onsemi 0:098463de4c5d 752 // Send the stop condition
group-onsemi 0:098463de4c5d 753 if ((error = I2CM_WriteTxFifo(i2cm, fifo, MXC_S_I2CM_TRANS_TAG_STOP)) != E_NO_ERROR) {
group-onsemi 0:098463de4c5d 754 return error;
group-onsemi 0:098463de4c5d 755 }
group-onsemi 0:098463de4c5d 756 }
group-onsemi 0:098463de4c5d 757 }
group-onsemi 0:098463de4c5d 758
group-onsemi 0:098463de4c5d 759 // Enable the required interrupts
group-onsemi 0:098463de4c5d 760 inten = MXC_F_I2CM_INTEN_TX_DONE | MXC_F_I2CM_INTEN_TX_NACKED |
group-onsemi 0:098463de4c5d 761 MXC_F_I2CM_INTEN_TX_LOST_ARBITR | MXC_F_I2CM_INTEN_TX_TIMEOUT;
group-onsemi 0:098463de4c5d 762
group-onsemi 0:098463de4c5d 763 if (cmd_remain) {
group-onsemi 0:098463de4c5d 764 inten |= (MXC_F_I2CM_INTEN_TX_FIFO_EMPTY | MXC_F_I2CM_INTEN_TX_FIFO_3Q_EMPTY);
group-onsemi 0:098463de4c5d 765 }
group-onsemi 0:098463de4c5d 766
group-onsemi 0:098463de4c5d 767 data_remain = req->data_len - req->data_num;
group-onsemi 0:098463de4c5d 768 if (data_remain > I2CM_FIFO_DEPTH_3Q) {
group-onsemi 0:098463de4c5d 769 inten |= MXC_F_I2CM_INTEN_RX_FIFO_3Q_FULL;
group-onsemi 0:098463de4c5d 770
group-onsemi 0:098463de4c5d 771 } else if (data_remain > I2CM_FIFO_DEPTH_2Q) {
group-onsemi 0:098463de4c5d 772 inten |= MXC_F_I2CM_INTEN_RX_FIFO_2Q_FULL;
group-onsemi 0:098463de4c5d 773
group-onsemi 0:098463de4c5d 774 } else if (data_remain > 0) {
group-onsemi 0:098463de4c5d 775 inten |= MXC_F_I2CM_INTEN_RX_FIFO_NOT_EMPTY;
group-onsemi 0:098463de4c5d 776 }
group-onsemi 0:098463de4c5d 777
group-onsemi 0:098463de4c5d 778 i2cm->inten = inten;
group-onsemi 0:098463de4c5d 779
group-onsemi 0:098463de4c5d 780 return E_NO_ERROR;
group-onsemi 0:098463de4c5d 781 }
group-onsemi 0:098463de4c5d 782
group-onsemi 0:098463de4c5d 783 /******************************************************************************/
group-onsemi 0:098463de4c5d 784 static int I2CM_WriteHandler(mxc_i2cm_regs_t *i2cm, i2cm_req_t *req, int i2cm_num)
group-onsemi 0:098463de4c5d 785 {
group-onsemi 0:098463de4c5d 786 int error, cmd_remain, data_remain;
group-onsemi 0:098463de4c5d 787 uint32_t inten;
group-onsemi 0:098463de4c5d 788 mxc_i2cm_fifo_regs_t *fifo;
group-onsemi 0:098463de4c5d 789
group-onsemi 0:098463de4c5d 790 // Get the FIFO pointer for this I2CM
group-onsemi 0:098463de4c5d 791 fifo = MXC_I2CM_GET_FIFO(i2cm_num);
group-onsemi 0:098463de4c5d 792
group-onsemi 0:098463de4c5d 793 cmd_remain = req->cmd_len - req->cmd_num;
group-onsemi 0:098463de4c5d 794 data_remain = req->data_len - req->data_num;
group-onsemi 0:098463de4c5d 795
group-onsemi 0:098463de4c5d 796 // Process the command portion
group-onsemi 0:098463de4c5d 797 if((cmd_remain) && (req->cmd_data != NULL)) {
group-onsemi 0:098463de4c5d 798 if((error = I2CM_CmdHandler(i2cm, fifo, req)) != E_NO_ERROR) {
group-onsemi 0:098463de4c5d 799 return error;
group-onsemi 0:098463de4c5d 800 }
group-onsemi 0:098463de4c5d 801
group-onsemi 0:098463de4c5d 802 cmd_remain = req->cmd_len - req->cmd_num;
group-onsemi 0:098463de4c5d 803 }
group-onsemi 0:098463de4c5d 804
group-onsemi 0:098463de4c5d 805 // Process the data portion
group-onsemi 0:098463de4c5d 806 if((cmd_remain == 0) && (data_remain)) {
group-onsemi 0:098463de4c5d 807
group-onsemi 0:098463de4c5d 808 // Start of the data portion
group-onsemi 0:098463de4c5d 809 if(req->data_num == 0) {
group-onsemi 0:098463de4c5d 810
group-onsemi 0:098463de4c5d 811 // Write the address to the TXFIFO
group-onsemi 0:098463de4c5d 812 if((error = I2CM_WriteTxFifo(i2cm, fifo, (MXC_S_I2CM_TRANS_TAG_START |
group-onsemi 0:098463de4c5d 813 (req->addr << 1)))) != E_NO_ERROR) {
group-onsemi 0:098463de4c5d 814
group-onsemi 0:098463de4c5d 815 return error;
group-onsemi 0:098463de4c5d 816 }
group-onsemi 0:098463de4c5d 817
group-onsemi 0:098463de4c5d 818 // Start the transaction if it is not currently ongoing
group-onsemi 0:098463de4c5d 819 if (!(i2cm->trans & MXC_F_I2CM_TRANS_TX_IN_PROGRESS)) {
group-onsemi 0:098463de4c5d 820 i2cm->trans |= MXC_F_I2CM_TRANS_TX_START;
group-onsemi 0:098463de4c5d 821 }
group-onsemi 0:098463de4c5d 822 }
group-onsemi 0:098463de4c5d 823
group-onsemi 0:098463de4c5d 824 // Write bytes to the FIFO until it's full or we run out of bytes
group-onsemi 0:098463de4c5d 825 while(req->data_num < req->data_len) {
group-onsemi 0:098463de4c5d 826 fifo->tx = MXC_S_I2CM_TRANS_TAG_TXDATA_ACK | req->data[req->data_num++];
group-onsemi 0:098463de4c5d 827 }
group-onsemi 0:098463de4c5d 828
group-onsemi 0:098463de4c5d 829 // Send the stop condition
group-onsemi 0:098463de4c5d 830 if ((error = I2CM_WriteTxFifo(i2cm, fifo, MXC_S_I2CM_TRANS_TAG_STOP)) != E_NO_ERROR) {
group-onsemi 0:098463de4c5d 831 return error;
group-onsemi 0:098463de4c5d 832 }
group-onsemi 0:098463de4c5d 833 }
group-onsemi 0:098463de4c5d 834
group-onsemi 0:098463de4c5d 835 // Enable the required interrupts
group-onsemi 0:098463de4c5d 836 data_remain = req->data_len - req->data_num;
group-onsemi 0:098463de4c5d 837 inten = MXC_F_I2CM_INTEN_TX_DONE | MXC_F_I2CM_INTEN_TX_NACKED |
group-onsemi 0:098463de4c5d 838 MXC_F_I2CM_INTEN_TX_LOST_ARBITR | MXC_F_I2CM_INTEN_TX_TIMEOUT;
group-onsemi 0:098463de4c5d 839
group-onsemi 0:098463de4c5d 840 if(data_remain || cmd_remain) {
group-onsemi 0:098463de4c5d 841 inten |= (MXC_F_I2CM_INTEN_TX_FIFO_EMPTY | MXC_F_I2CM_INTEN_TX_FIFO_3Q_EMPTY);
group-onsemi 0:098463de4c5d 842 }
group-onsemi 0:098463de4c5d 843 i2cm->inten = inten;
group-onsemi 0:098463de4c5d 844
group-onsemi 0:098463de4c5d 845 return E_NO_ERROR;
group-onsemi 0:098463de4c5d 846 }
group-onsemi 0:098463de4c5d 847
group-onsemi 0:098463de4c5d 848 int I2CM_SetFrequency(mxc_i2cm_regs_t *i2cm, int speed)
group-onsemi 0:098463de4c5d 849 {
group-onsemi 0:098463de4c5d 850 // Speed converted into Khz
group-onsemi 0:098463de4c5d 851 float i2cSpeed = speed / 1000.0f;
group-onsemi 0:098463de4c5d 852 //get clk speed into MHz
group-onsemi 0:098463de4c5d 853 int sClk = SYS_I2CM_GetFreq(i2cm) / 1000000;
group-onsemi 0:098463de4c5d 854 // duty cycle of .67
group-onsemi 0:098463de4c5d 855 float dc = 2.0f / 3.0f;
group-onsemi 0:098463de4c5d 856 //Hold Time
group-onsemi 0:098463de4c5d 857 float hold = (100.0f / i2cSpeed);
group-onsemi 0:098463de4c5d 858 int riseTime;
group-onsemi 0:098463de4c5d 859 //max rise time based on speed according to the I2C specs
group-onsemi 0:098463de4c5d 860 if (i2cSpeed <= 100) {
group-onsemi 0:098463de4c5d 861 riseTime = 1000;
group-onsemi 0:098463de4c5d 862 } else if (i2cSpeed <= 400) {
group-onsemi 0:098463de4c5d 863 riseTime = 300;
group-onsemi 0:098463de4c5d 864 } else if (i2cSpeed <= 1000) {
group-onsemi 0:098463de4c5d 865 riseTime = 120;
group-onsemi 0:098463de4c5d 866 } else {
group-onsemi 0:098463de4c5d 867 return E_NOT_SUPPORTED;
group-onsemi 0:098463de4c5d 868 }
group-onsemi 0:098463de4c5d 869 // Clock cycles to delay
group-onsemi 0:098463de4c5d 870 int latency = 4;
group-onsemi 0:098463de4c5d 871 int filtDev, sclHi, sclLow;
group-onsemi 0:098463de4c5d 872 filtDev = (hold * sClk) / 2;
group-onsemi 0:098463de4c5d 873 sclHi = (((dc * sClk * 1000.0f / i2cSpeed) - (((2.5f * filtDev) + (riseTime / 1000.0f * sClk) + latency) * (1.0f + dc))) / (1.0f + dc));
group-onsemi 0:098463de4c5d 874 sclLow = ((sClk * 1000.0f / i2cSpeed) - (2.5f * filtDev) - (riseTime / 1000.0f * sClk) - latency - sclHi);
group-onsemi 0:098463de4c5d 875
group-onsemi 0:098463de4c5d 876 i2cm->fs_clk_div = ((filtDev << MXC_F_I2CM_FS_CLK_DIV_FS_FILTER_CLK_DIV_POS) |
group-onsemi 0:098463de4c5d 877 (sclHi << MXC_F_I2CM_FS_CLK_DIV_FS_SCL_HI_CNT_POS) |
group-onsemi 0:098463de4c5d 878 (sclLow << MXC_F_I2CM_FS_CLK_DIV_FS_SCL_LO_CNT_POS));
group-onsemi 0:098463de4c5d 879 return E_NO_ERROR;
group-onsemi 0:098463de4c5d 880 }