]> git.donarmstrong.com Git - qmk_firmware.git/blob - tmk_core/tool/mbed/mbed-sdk/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KPSDK_MCUS/TARGET_KPSDK_CODE/hal/i2c/fsl_i2c_hal.c
Merge commit '1fe4406f374291ab2e86e95a97341fd9c475fcb8'
[qmk_firmware.git] / tmk_core / tool / mbed / mbed-sdk / libraries / mbed / targets / hal / TARGET_Freescale / TARGET_KPSDK_MCUS / TARGET_KPSDK_CODE / hal / i2c / fsl_i2c_hal.c
1 /*
2  * Copyright (c) 2013 - 2014, Freescale Semiconductor, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * o Redistributions of source code must retain the above copyright notice, this list
9  *   of conditions and the following disclaimer.
10  *
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.
14  *
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.
18  *
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.
29  */
30
31 #include "fsl_i2c_hal.h"
32 #include "fsl_misc_utilities.h" /* For ARRAY_SIZE*/
33
34 /*******************************************************************************
35  * Definitions
36  ******************************************************************************/
37
38 /*!
39  * @brief An entry in the I2C divider table.
40  *
41  * This struct pairs the value of the I2C_F.ICR bitfield with the resulting
42  * clock divider value.
43  */
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;
48
49 /*******************************************************************************
50  * Variables
51  ******************************************************************************/
52
53 /*!
54  * @brief I2C divider values.
55  *
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.
60  */
61 const i2c_divider_table_entry_t kI2CDividerTable[] = {
62         /* ICR  Divider*/
63         { 0x00, 20 },
64         { 0x01, 22 },
65         { 0x02, 24 },
66         { 0x03, 26 },
67         { 0x04, 28 },
68         { 0x05, 30 },
69         { 0x09, 32 },
70         { 0x06, 34 },
71         { 0x0a, 36 },
72         { 0x07, 40 },
73         { 0x0c, 44 },
74         { 0x0d, 48 },
75         { 0x0e, 56 },
76         { 0x12, 64 },
77         { 0x0f, 68 },
78         { 0x13, 72 },
79         { 0x14, 80 },
80         { 0x15, 88 },
81         { 0x19, 96 },
82         { 0x16, 104 },
83         { 0x1a, 112 },
84         { 0x17, 128 },
85         { 0x1c, 144 },
86         { 0x1d, 160 },
87         { 0x1e, 192 },
88         { 0x22, 224 },
89         { 0x1f, 240 },
90         { 0x23, 256 },
91         { 0x24, 288 },
92         { 0x25, 320 },
93         { 0x26, 384 },
94         { 0x2a, 448 },
95         { 0x27, 480 },
96         { 0x2b, 512 },
97         { 0x2c, 576 },
98         { 0x2d, 640 },
99         { 0x2e, 768 },
100         { 0x32, 896 },
101         { 0x2f, 960 },
102         { 0x33, 1024 },
103         { 0x34, 1152 },
104         { 0x35, 1280 },
105         { 0x36, 1536 },
106         { 0x3a, 1792 },
107         { 0x37, 1920 },
108         { 0x3b, 2048 },
109         { 0x3c, 2304 },
110         { 0x3d, 2560 },
111         { 0x3e, 3072 },
112         { 0x3f, 3840 }
113     };
114
115 /*******************************************************************************
116  * Code
117  ******************************************************************************/
118 /*FUNCTION**********************************************************************
119  *
120  * Function Name : I2C_HAL_Init
121  * Description   : Initialize I2C peripheral to reset state.
122  *
123  *END**************************************************************************/
124 void I2C_HAL_Init(uint32_t baseAddr)
125 {
126     
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);
135     
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*/
142 }
143
144 /*FUNCTION**********************************************************************
145  *
146  * Function Name : I2C_HAL_SetBaudRate
147  * Description   : Sets the I2C bus frequency for master transactions.
148  *
149  *END**************************************************************************/
150 i2c_status_t I2C_HAL_SetBaudRate(uint32_t baseAddr, uint32_t sourceClockInHz, uint32_t kbps,
151                                   uint32_t * absoluteError_Hz)
152 {
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;
158        
159     /* Check if the requested frequency is greater than the max supported baud.*/
160     if ((kbps * 1000U) > (sourceClockInHz / (1U * 20U)))
161     {
162         return kStatus_I2C_OutOfRange;
163     }
164     
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)
169     {
170         multiplier = 1u << mult;
171         
172         /* Scan table to find best match.*/
173         for (i = 0u; i < ARRAY_SIZE(kI2CDividerTable); ++i)
174         {
175             uint32_t computedRate = sourceClockInHz / (multiplier * kI2CDividerTable[i].sclDivider);
176             uint32_t absError = hz > computedRate ? hz - computedRate : computedRate - hz;
177             
178             if (absError < bestError)
179             {
180                 bestMult = mult;
181                 bestIcr = kI2CDividerTable[i].icr;
182                 bestError = absError;
183                 
184                 /* If the error is 0, then we can stop searching
185                  * because we won't find a better match.*/
186                 if (absError == 0)
187                 {
188                     break;
189                 }
190             }
191         }
192     }
193
194     /* Set the resulting error.*/
195     if (absoluteError_Hz)
196     {
197         *absoluteError_Hz = bestError;
198     }
199     
200     /* Set frequency register based on best settings.*/
201     HW_I2C_F_WR(baseAddr, BF_I2C_F_MULT(bestMult) | BF_I2C_F_ICR(bestIcr));
202     
203     return kStatus_I2C_Success;
204 }
205
206 /*FUNCTION**********************************************************************
207  *
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.
213  *
214  *END**************************************************************************/
215 void I2C_HAL_SendStart(uint32_t baseAddr)
216 {
217     /* Check if we're in a master mode transfer.*/
218     if (BR_I2C_C1_MST(baseAddr))
219     {
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
222          * non- zero value.
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)
227         {
228             savedMult = BR_I2C_F_MULT(baseAddr);
229             BW_I2C_F_MULT(baseAddr, 0U);
230         }
231 #endif /* FSL_FEATURE_I2C_HAS_ERRATA_6070*/
232
233         /* We are already in a transfer, so send a repeated start.*/
234         BW_I2C_C1_RSTA(baseAddr, 1U);
235
236 #if FSL_FEATURE_I2C_HAS_ERRATA_6070
237         if (savedMult)
238         {
239             BW_I2C_F_MULT(baseAddr, savedMult);
240         }
241 #endif /* FSL_FEATURE_I2C_HAS_ERRATA_6070*/
242     }
243     else
244     {
245         /* Initiate a transfer by sending the start signal.*/
246         HW_I2C_C1_SET(baseAddr, BM_I2C_C1_MST | BM_I2C_C1_TX);
247     }
248 }
249
250 /*FUNCTION**********************************************************************
251  *
252  * Function Name : I2C_HAL_SetAddress7bit
253  * Description   : Sets the primary 7-bit slave address.
254  *
255  *END**************************************************************************/
256 void I2C_HAL_SetAddress7bit(uint32_t baseAddr, uint8_t address)
257 {
258     /* Set 7-bit slave address.*/
259     HW_I2C_A1_WR(baseAddr, address << 1U);
260     
261     /* Disable the address extension option, selecting 7-bit mode.*/
262     BW_I2C_C2_ADEXT(baseAddr, 0U);
263 }
264
265 /*FUNCTION**********************************************************************
266  *
267  * Function Name : I2C_HAL_SetAddress10bit
268  * Description   : Sets the primary slave address and enables 10-bit address mode.
269  *
270  *END**************************************************************************/
271 void I2C_HAL_SetAddress10bit(uint32_t baseAddr, uint16_t address)
272 {
273     
274     uint8_t temp;
275
276     /* Set bottom 7 bits of slave address.*/
277     temp = address & 0x7FU;
278     HW_I2C_A1_WR(baseAddr, temp << 1U);
279     
280     /* Enable 10-bit address extension.*/
281     BW_I2C_C2_ADEXT(baseAddr, 1U);
282     
283     /* Set top 3 bits of slave address.*/
284     BW_I2C_C2_AD(baseAddr, (address & 0x0380U) >> 7U);
285 }
286
287 /*******************************************************************************
288  * EOF
289  ******************************************************************************/
290
291