test

Committer:
elijahsj
Date:
Mon Nov 09 00:33:19 2020 -0500
Revision:
2:4364577b5ad8
Parent:
1:8a094db1347f
copied mbed library

Who changed what in which revision?

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