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 ******************************************************************************/