2 * Copyright (c) 2013 - 2014, Freescale Semiconductor, Inc.
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
8 * o Redistributions of source code must retain the above copyright notice, this list
9 * of conditions and the following disclaimer.
11 * o Redistributions in binary form must reproduce the above copyright notice, this
12 * list of conditions and the following disclaimer in the documentation and/or
13 * other materials provided with the distribution.
15 * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from this
17 * software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include "fsl_i2c_hal.h"
32 #include "fsl_misc_utilities.h" /* For ARRAY_SIZE*/
34 /*******************************************************************************
36 ******************************************************************************/
39 * @brief An entry in the I2C divider table.
41 * This struct pairs the value of the I2C_F.ICR bitfield with the resulting
42 * clock divider value.
44 typedef struct I2CDividerTableEntry {
45 uint8_t icr; /*!< F register ICR value.*/
46 uint16_t sclDivider; /*!< SCL clock divider.*/
47 } i2c_divider_table_entry_t;
49 /*******************************************************************************
51 ******************************************************************************/
54 * @brief I2C divider values.
56 * This table is taken from the I2C Divider and Hold values section of the
57 * reference manual. In the original table there are, in some cases, multiple
58 * entries with the same divider but different hold values. This table
59 * includes only one entry for every divider, selecting the lowest hold value.
61 const i2c_divider_table_entry_t kI2CDividerTable[] = {
115 /*******************************************************************************
117 ******************************************************************************/
118 /*FUNCTION**********************************************************************
120 * Function Name : I2C_HAL_Init
121 * Description : Initialize I2C peripheral to reset state.
123 *END**************************************************************************/
124 void I2C_HAL_Init(uint32_t baseAddr)
127 HW_I2C_A1_WR(baseAddr, 0u);
128 HW_I2C_F_WR(baseAddr, 0u);
129 HW_I2C_C1_WR(baseAddr, 0u);
130 HW_I2C_S_WR(baseAddr, 0u);
131 HW_I2C_D_WR(baseAddr, 0u);
132 HW_I2C_C2_WR(baseAddr, 0u);
133 HW_I2C_FLT_WR(baseAddr, 0u);
134 HW_I2C_RA_WR(baseAddr, 0u);
136 #if FSL_FEATURE_I2C_HAS_SMBUS
137 HW_I2C_SMB_WR(baseAddr, 0u);
138 HW_I2C_A2_WR(baseAddr, 0xc2u);
139 HW_I2C_SLTH_WR(baseAddr, 0u);
140 HW_I2C_SLTL_WR(baseAddr, 0u);
141 #endif /* FSL_FEATURE_I2C_HAS_SMBUS*/
144 /*FUNCTION**********************************************************************
146 * Function Name : I2C_HAL_SetBaudRate
147 * Description : Sets the I2C bus frequency for master transactions.
149 *END**************************************************************************/
150 i2c_status_t I2C_HAL_SetBaudRate(uint32_t baseAddr, uint32_t sourceClockInHz, uint32_t kbps,
151 uint32_t * absoluteError_Hz)
153 uint32_t mult, i, multiplier;
154 uint32_t hz = kbps * 1000u;
155 uint32_t bestError = 0xffffffffu;
156 uint32_t bestMult = 0u;
157 uint32_t bestIcr = 0u;
159 /* Check if the requested frequency is greater than the max supported baud.*/
160 if ((kbps * 1000U) > (sourceClockInHz / (1U * 20U)))
162 return kStatus_I2C_OutOfRange;
165 /* Search for the settings with the lowest error.
166 * mult is the MULT field of the I2C_F register, and ranges from 0-2. It selects the
167 * multiplier factor for the divider. */
168 for (mult = 0u; (mult <= 2u) && (bestError != 0); ++mult)
170 multiplier = 1u << mult;
172 /* Scan table to find best match.*/
173 for (i = 0u; i < ARRAY_SIZE(kI2CDividerTable); ++i)
175 uint32_t computedRate = sourceClockInHz / (multiplier * kI2CDividerTable[i].sclDivider);
176 uint32_t absError = hz > computedRate ? hz - computedRate : computedRate - hz;
178 if (absError < bestError)
181 bestIcr = kI2CDividerTable[i].icr;
182 bestError = absError;
184 /* If the error is 0, then we can stop searching
185 * because we won't find a better match.*/
194 /* Set the resulting error.*/
195 if (absoluteError_Hz)
197 *absoluteError_Hz = bestError;
200 /* Set frequency register based on best settings.*/
201 HW_I2C_F_WR(baseAddr, BF_I2C_F_MULT(bestMult) | BF_I2C_F_ICR(bestIcr));
203 return kStatus_I2C_Success;
206 /*FUNCTION**********************************************************************
208 * Function Name : I2C_HAL_SendStart
209 * Description : Send a START or Repeated START signal on the I2C bus.
210 * This function is used to initiate a new master mode transfer by sending the
211 * START signal. It is also used to send a Repeated START signal when a transfer
212 * is already in progress.
214 *END**************************************************************************/
215 void I2C_HAL_SendStart(uint32_t baseAddr)
217 /* Check if we're in a master mode transfer.*/
218 if (BR_I2C_C1_MST(baseAddr))
220 #if FSL_FEATURE_I2C_HAS_ERRATA_6070
221 /* Errata 6070: Repeat start cannot be generated if the I2Cx_F[MULT] field is set to a
223 * The workaround is to either always keep MULT set to 0, or to temporarily set it to
224 * 0 while performing the repeated start and then restore it.*/
225 uint32_t savedMult = 0;
226 if (BR_I2C_F_MULT(baseAddr) != 0)
228 savedMult = BR_I2C_F_MULT(baseAddr);
229 BW_I2C_F_MULT(baseAddr, 0U);
231 #endif /* FSL_FEATURE_I2C_HAS_ERRATA_6070*/
233 /* We are already in a transfer, so send a repeated start.*/
234 BW_I2C_C1_RSTA(baseAddr, 1U);
236 #if FSL_FEATURE_I2C_HAS_ERRATA_6070
239 BW_I2C_F_MULT(baseAddr, savedMult);
241 #endif /* FSL_FEATURE_I2C_HAS_ERRATA_6070*/
245 /* Initiate a transfer by sending the start signal.*/
246 HW_I2C_C1_SET(baseAddr, BM_I2C_C1_MST | BM_I2C_C1_TX);
250 /*FUNCTION**********************************************************************
252 * Function Name : I2C_HAL_SetAddress7bit
253 * Description : Sets the primary 7-bit slave address.
255 *END**************************************************************************/
256 void I2C_HAL_SetAddress7bit(uint32_t baseAddr, uint8_t address)
258 /* Set 7-bit slave address.*/
259 HW_I2C_A1_WR(baseAddr, address << 1U);
261 /* Disable the address extension option, selecting 7-bit mode.*/
262 BW_I2C_C2_ADEXT(baseAddr, 0U);
265 /*FUNCTION**********************************************************************
267 * Function Name : I2C_HAL_SetAddress10bit
268 * Description : Sets the primary slave address and enables 10-bit address mode.
270 *END**************************************************************************/
271 void I2C_HAL_SetAddress10bit(uint32_t baseAddr, uint16_t address)
276 /* Set bottom 7 bits of slave address.*/
277 temp = address & 0x7FU;
278 HW_I2C_A1_WR(baseAddr, temp << 1U);
280 /* Enable 10-bit address extension.*/
281 BW_I2C_C2_ADEXT(baseAddr, 1U);
283 /* Set top 3 bits of slave address.*/
284 BW_I2C_C2_AD(baseAddr, (address & 0x0380U) >> 7U);
287 /*******************************************************************************
289 ******************************************************************************/