mbed library sources. Supersedes mbed-src.

Fork of mbed-dev by Umar Naeem

Committer:
<>
Date:
Thu Feb 02 17:01:33 2017 +0000
Revision:
157:ff67d9f36b67
This updates the lib to the mbed lib v135

Who changed what in which revision?

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