1 /*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016-2019 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8 #include "fsl_eeprom.h"
9
10 /*******************************************************************************
11 * Definitions
12 ******************************************************************************/
13
14 /* Component ID definition, used by tools. */
15 #ifndef FSL_COMPONENT_ID
16 #define FSL_COMPONENT_ID "platform.drivers.eeprom"
17 #endif
18
19 /*******************************************************************************
20 * Prototypes
21 ******************************************************************************/
22
23 /*!
24 * @brief Get the EEPROM instance from peripheral base address.
25 *
26 * @param base EEPROM peripheral base address.
27 * @return EEPROM instance.
28 */
29 static uint32_t EEPROM_GetInstance(EEPROM_Type *base);
30
31 /*******************************************************************************
32 * Variables
33 ******************************************************************************/
34
35 /* Array of EEPROM peripheral base address. */
36 static EEPROM_Type *const s_eepromBases[] = EEPROM_BASE_PTRS;
37
38 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
39 /* Array of EEPROM clock name. */
40 static const clock_ip_name_t s_eepromClock[] = EEPROM_CLOCKS;
41 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
42
43 /*******************************************************************************
44 * Code
45 ******************************************************************************/
EEPROM_GetInstance(EEPROM_Type * base)46 static uint32_t EEPROM_GetInstance(EEPROM_Type *base)
47 {
48 uint32_t instance;
49
50 /* Find the instance index from base address mappings. */
51 for (instance = 0; instance < ARRAY_SIZE(s_eepromBases); instance++)
52 {
53 if (s_eepromBases[instance] == base)
54 {
55 break;
56 }
57 }
58
59 assert(instance < ARRAY_SIZE(s_eepromBases));
60
61 return instance;
62 }
63
64 /*!
65 * brief Get EEPROM default configure settings.
66 *
67 * param config EEPROM config structure pointer.
68 */
EEPROM_GetDefaultConfig(eeprom_config_t * config)69 void EEPROM_GetDefaultConfig(eeprom_config_t *config)
70 {
71 /* Initializes the configure structure to zero. */
72 (void)memset(config, 0, sizeof(*config));
73
74 config->autoProgram = kEEPROM_AutoProgramWriteWord;
75 config->writeWaitPhase1 = 0x5U;
76 config->writeWaitPhase2 = 0x9U;
77 config->writeWaitPhase3 = 0x3U;
78 config->readWaitPhase1 = 0xFU;
79 config->readWaitPhase2 = 0x8U;
80 config->lockTimingParam = false;
81 }
82
EEPROM_Flush(EEPROM_Type * base)83 static void EEPROM_Flush(EEPROM_Type *base)
84 {
85 /* Write all prepared words */
86 EEPROM_ClearInterruptFlag(base, (uint32_t)kEEPROM_ProgramFinishInterruptEnable);
87 base->CMD = FSL_FEATURE_EEPROM_PROGRAM_CMD;
88
89 /* Waiting for operation finished */
90 while ((EEPROM_GetInterruptStatus(base) & (uint32_t)kEEPROM_ProgramFinishInterruptEnable) == 0UL)
91 {
92 }
93 }
94
95 /*!
96 * brief Initializes the EEPROM with the user configuration structure.
97 *
98 * This function configures the EEPROM module with the user-defined configuration. This function also sets the
99 * internal clock frequency to about 155kHz according to the source clock frequency.
100 *
101 * param base EEPROM peripheral base address.
102 * param config The pointer to the configuration structure.
103 * param sourceClock_Hz EEPROM source clock frequency in Hz.
104 */
EEPROM_Init(EEPROM_Type * base,const eeprom_config_t * config,uint32_t sourceClock_Hz)105 void EEPROM_Init(EEPROM_Type *base, const eeprom_config_t *config, uint32_t sourceClock_Hz)
106 {
107 assert(config != NULL);
108
109 uint32_t clockDiv = 0;
110
111 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
112 /* Enable the SAI clock */
113 CLOCK_EnableClock(s_eepromClock[EEPROM_GetInstance(base)]);
114 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
115
116 #if !(defined(FSL_FEATURE_EEPROM_HAS_NO_RESET) && FSL_FEATURE_EEPROM_HAS_NO_RESET)
117 /* Reset the EEPROM module */
118 RESET_PeripheralReset(kEEPROM_RST_SHIFT_RSTn);
119 #endif /* FSL_FEATURE_EEPROM_HAS_NO_RESET */
120
121 #if (defined(FSL_SDK_ENABLE_DRIVER_POWER_CONTROL) && (FSL_SDK_ENABLE_DRIVER_POWER_CONTROL))
122 POWER_DisablePD(kPDRUNCFG_PD_EEPROM);
123
124 /* Delay larger than 100us. */
125 uint32_t count = SystemCoreClock / 1000;
126 while (count--)
127 {
128 __NOP();
129 }
130 #endif /* FSL_SDK_ENABLE_DRIVER_POWER_CONTROL */
131
132 /* Set the clock divider */
133 clockDiv = sourceClock_Hz / (uint32_t)FSL_FEATURE_EEPROM_INTERNAL_FREQ;
134 if ((sourceClock_Hz % (uint32_t)FSL_FEATURE_EEPROM_INTERNAL_FREQ) >
135 ((uint32_t)FSL_FEATURE_EEPROM_INTERNAL_FREQ / 2UL))
136 {
137 clockDiv += 1UL;
138 }
139
140 if (sourceClock_Hz / clockDiv > (uint32_t)FSL_FEATURE_EEPROM_INTERNAL_FREQ)
141 {
142 clockDiv += 1UL;
143 }
144
145 base->CLKDIV = clockDiv - 1UL;
146
147 /* Set the auto program feature */
148 EEPROM_SetAutoProgram(base, config->autoProgram);
149
150 /* Set time delay parameter */
151 base->RWSTATE =
152 EEPROM_RWSTATE_RPHASE1(config->readWaitPhase1 - 1UL) | EEPROM_RWSTATE_RPHASE2(config->readWaitPhase2 - 1UL);
153 base->WSTATE = EEPROM_WSTATE_PHASE1(config->writeWaitPhase1 - 1UL) |
154 EEPROM_WSTATE_PHASE2(config->writeWaitPhase2 - 1UL) |
155 EEPROM_WSTATE_PHASE3(config->writeWaitPhase3 - 1UL);
156 base->WSTATE |= EEPROM_WSTATE_LCK_PARWEP(config->lockTimingParam);
157
158 /* Clear the remaining write operation */
159 base->CMD = FSL_FEATURE_EEPROM_PROGRAM_CMD;
160 while ((EEPROM_GetInterruptStatus(base) & (uint32_t)kEEPROM_ProgramFinishInterruptEnable) == 0UL)
161 {
162 }
163 }
164
165 /*!
166 * brief Deinitializes the EEPROM regions.
167 *
168 * param base EEPROM peripheral base address.
169 */
EEPROM_Deinit(EEPROM_Type * base)170 void EEPROM_Deinit(EEPROM_Type *base)
171 {
172 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
173 /* Enable the SAI clock */
174 CLOCK_DisableClock(s_eepromClock[EEPROM_GetInstance(base)]);
175 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
176 }
177
178 /*!
179 * brief Write a word data in address of EEPROM.
180 *
181 * Users can write a page or at least a word data into EEPROM address.
182 *
183 * param base EEPROM peripheral base address.
184 * param offset Offset from the begining address of EEPROM. This value shall be 4-byte aligned.
185 * param data Data need be write.
186 */
EEPROM_WriteWord(EEPROM_Type * base,uint32_t offset,uint32_t data)187 status_t EEPROM_WriteWord(EEPROM_Type *base, uint32_t offset, uint32_t data)
188 {
189 uint32_t *addr = NULL;
190 status_t status = kStatus_Success;
191
192 if ((offset % 4UL != 0UL) || (offset > (uint32_t)FSL_FEATURE_EEPROM_SIZE))
193 {
194 status = kStatus_InvalidArgument;
195 }
196 else
197 {
198 /* Set auto program settings */
199 if (base->AUTOPROG != (uint32_t)kEEPROM_AutoProgramDisable)
200 {
201 EEPROM_SetAutoProgram(base, kEEPROM_AutoProgramWriteWord);
202 }
203
204 EEPROM_ClearInterruptFlag(base, (uint32_t)kEEPROM_ProgramFinishInterruptEnable);
205
206 /* Compute the page */
207 addr = (uint32_t *)((uint32_t)FSL_FEATURE_EEPROM_BASE_ADDRESS + offset);
208 *addr = data;
209
210 /* Check if manual program erase is needed. */
211 if (base->AUTOPROG != (uint32_t)kEEPROM_AutoProgramWriteWord)
212 {
213 base->CMD = FSL_FEATURE_EEPROM_PROGRAM_CMD;
214 }
215
216 /* Waiting for operation to finish */
217 while ((EEPROM_GetInterruptStatus(base) & (uint32_t)kEEPROM_ProgramFinishInterruptEnable) == 0UL)
218 {
219 }
220 }
221
222 return status;
223 }
224
225 /*!
226 * brief Write data from a user allocated buffer in address of EEPROM.
227 *
228 * Users can write any bytes data into EEPROM address by wBuf.
229 *
230 * param base EEPROM peripheral base address.
231 * param offset Offset from the begining address of EEPROM.
232 * param wBuf Data need be write.
233 * param size Number of bytes to write.
234 */
EEPROM_Write(EEPROM_Type * base,uint32_t offset,void * wBuf,uint32_t size)235 void EEPROM_Write(EEPROM_Type *base, uint32_t offset, void *wBuf, uint32_t size)
236 {
237 uint8_t *src;
238 bool unalignedStart;
239 uint32_t memUnit = 0;
240 uint32_t alignSize = 0;
241
242 #if (defined(FSL_FEATURE_EEPROM_TWOBYTES_ALIGNED) && FSL_FEATURE_EEPROM_TWOBYTES_ALIGNED)
243 uint16_t *dst;
244 alignSize = 2;
245 memUnit = FSL_FEATURE_EEPROM_ROW_SIZE;
246 #else
247 uint32_t i = 0;
248 uint32_t *dst;
249 uint32_t data32_Align = 0;
250 uint32_t unalignedSize = 0;
251 alignSize = 4;
252 memUnit = FSL_FEATURE_EEPROM_SIZE / FSL_FEATURE_EEPROM_PAGE_COUNT;
253 #endif /* FSL_FEATURE_EEPROM_TWOBYTES_ALIGNED */
254
255 /* Offset and size must be positive */
256 assert(size > 0UL);
257 /* All bytes must be written to a valid EEPROM address */
258 assert((offset + size) <= (uint32_t)FSL_FEATURE_EEPROM_SIZE);
259
260 src = wBuf;
261
262 #if (defined(FSL_FEATURE_EEPROM_TWOBYTES_ALIGNED) && FSL_FEATURE_EEPROM_TWOBYTES_ALIGNED)
263 dst = &((uint16_t *)FSL_FEATURE_EEPROM_BASE_ADDRESS)[offset / alignSize];
264 unalignedStart = (offset % alignSize != 0UL);
265 #else
266 dst = &((uint32_t *)FSL_FEATURE_EEPROM_BASE_ADDRESS)[offset / alignSize];
267 unalignedStart = (offset % alignSize) != 0UL;
268 unalignedSize = alignSize - (offset % alignSize);
269 #endif /* FSL_FEATURE_EEPROM_TWOBYTES_ALIGNED */
270
271 while (size > 0UL)
272 {
273 /* If first byte is to be copied to non aligned EEPROM byte */
274 if (unalignedStart)
275 {
276 /* The first byte from the buffer is not 16-bits aligned.
277 * Read the LSB from EEPROM to complete it.
278 */
279 #if (defined(FSL_FEATURE_EEPROM_TWOBYTES_ALIGNED) && FSL_FEATURE_EEPROM_TWOBYTES_ALIGNED)
280 *dst = (uint16_t)(((uint16_t)src[0] << 8UL) | (*dst & 0x00ffUL));
281 #else
282 /* The first byte from the buffer is not 32-bits aligned.
283 * Read the rest of data after position offset and realign them.
284 */
285 for (i = 0; i < unalignedSize; i++)
286 {
287 data32_Align |= (uint32_t)((uint32_t)src[i] << (8UL * ((alignSize - unalignedSize) + i)));
288 }
289 *dst = (*dst & (0xffffffffUL >> (8UL * unalignedSize))) | data32_Align;
290 #endif /* FSL_FEATURE_EEPROM_TWOBYTES_ALIGNED */
291 src += (alignSize - (offset % alignSize)); /* Operate src to let wBuf pointer offset correct*/
292 size -= (alignSize - (offset % alignSize));
293 unalignedStart = false;
294 }
295 else if (size >= alignSize)
296 {
297 #if (defined(FSL_FEATURE_EEPROM_TWOBYTES_ALIGNED) && FSL_FEATURE_EEPROM_TWOBYTES_ALIGNED)
298 /* Combine two bytes from the buffer to a 16-bits word */
299 *dst = (uint16_t)(((uint16_t)src[1] << 8UL) | (uint16_t)src[0]);
300 #else
301 /* Combine four bytes from the buffer to a 32-bits word */
302 *dst = (uint32_t)(((uint32_t)src[3] << 24UL) | ((uint32_t)src[2] << 16UL) | ((uint32_t)src[1] << 8UL) |
303 src[0]);
304 #endif /* FSL_FEATURE_EEPROM_TWOBYTES_ALIGNED */
305 src += alignSize; /* Normal operate src to offset wBuf pointer by 4 bytes*/
306 size -= alignSize;
307 }
308 else
309 {
310 /* The last several bytes from the buffer is not 32-bit aligned.
311 * Read the rest of bytes of non 32-bit aligned data
312 * and realign them by 32-bit aligned */
313 #if (defined(FSL_FEATURE_EEPROM_TWOBYTES_ALIGNED) && FSL_FEATURE_EEPROM_TWOBYTES_ALIGNED)
314 *dst = (uint16_t)((*dst & 0xff00UL) | src[0]);
315 #else
316 data32_Align = 0; /* Clear data32_Align */
317 for (i = 0; i < (size % alignSize); i++)
318 {
319 data32_Align |= (uint32_t)((uint32_t)src[i] << (8UL * i));
320 }
321 *dst = (*dst & (0xffffffffUL << (8UL * (size % alignSize)))) | data32_Align;
322 #endif /* FSL_FEATURE_EEPROM_TWOBYTES_ALIGNED */
323 size -= (size % alignSize);
324 }
325
326 dst++; /* EEPROM mempory pointer go ahead */
327
328 /* When memory unit size reached, have to flush. */
329 if ((((uint32_t)dst % memUnit) == 0UL) && (size > 0UL))
330 {
331 EEPROM_Flush(base);
332 }
333 }
334
335 /* Normal need to flush after write data into eeprom */
336 EEPROM_Flush(base);
337 }
338 #if !(defined(FSL_FEATURE_EEPROM_PAGE_COUNT) && FSL_FEATURE_EEPROM_PAGE_COUNT)
EEPROM_WriteRow(EEPROM_Type * base,uint32_t rowNum,uint32_t * data)339 status_t EEPROM_WriteRow(EEPROM_Type *base, uint32_t rowNum, uint32_t *data)
340 {
341 uint32_t i = 0;
342 uint32_t *addr = NULL;
343 status_t status = kStatus_Success;
344
345 if ((rowNum > FSL_FEATURE_EEPROM_ROW_COUNT) || (!data))
346 {
347 status = kStatus_InvalidArgument;
348 }
349 else
350 {
351 /* Set auto program settings */
352 if (base->AUTOPROG != (uint32_t)kEEPROM_AutoProgramDisable)
353 {
354 EEPROM_SetAutoProgram(base, kEEPROM_AutoProgramLastWord);
355 }
356
357 EEPROM_ClearInterruptFlag(base, (uint32_t)kEEPROM_ProgramFinishInterruptEnable);
358
359 addr = (uint32_t *)((uint32_t)FSL_FEATURE_EEPROM_BASE_ADDRESS +
360 rowNum * ((uint32_t)FSL_FEATURE_EEPROM_SIZE / (uint32_t)FSL_FEATURE_EEPROM_ROW_COUNT));
361 for (i = 0; i < ((uint32_t)FSL_FEATURE_EEPROM_SIZE / (uint32_t)FSL_FEATURE_EEPROM_ROW_COUNT) / 4UL; i++)
362 {
363 addr[i] = data[i];
364 }
365
366 if (base->AUTOPROG == kEEPROM_AutoProgramDisable)
367 {
368 base->CMD = FSL_FEATURE_EEPROM_PROGRAM_CMD;
369 }
370
371 /* Waiting for operation to finish */
372 while ((EEPROM_GetInterruptStatus(base) & (uint32_t)kEEPROM_ProgramFinishInterruptEnable) == 0UL)
373 {
374 }
375 }
376
377 return status;
378 }
379 #else
380 /*!
381 * brief Write a page data into EEPROM.
382 *
383 * Users can write a page or at least a word data into EEPROM address.
384 *
385 * param base EEPROM peripheral base address.
386 * param pageNum Page number to be written.
387 * param data Data need be write. This array data size shall equals to the page size.
388 */
EEPROM_WritePage(EEPROM_Type * base,uint32_t pageNum,uint32_t * data)389 status_t EEPROM_WritePage(EEPROM_Type *base, uint32_t pageNum, uint32_t *data)
390 {
391 uint32_t i = 0;
392 uint32_t *addr = NULL;
393 status_t status = kStatus_Success;
394
395 if ((pageNum > (uint32_t)FSL_FEATURE_EEPROM_PAGE_COUNT) || (data == NULL))
396 {
397 status = kStatus_InvalidArgument;
398 }
399 else
400 {
401 /* Set auto program settings */
402 if (base->AUTOPROG != (uint32_t)kEEPROM_AutoProgramDisable)
403 {
404 EEPROM_SetAutoProgram(base, kEEPROM_AutoProgramLastWord);
405 }
406
407 EEPROM_ClearInterruptFlag(base, (uint32_t)kEEPROM_ProgramFinishInterruptEnable);
408
409 addr = (uint32_t *)((uint32_t)FSL_FEATURE_EEPROM_BASE_ADDRESS +
410 pageNum * ((uint32_t)FSL_FEATURE_EEPROM_SIZE / (uint32_t)FSL_FEATURE_EEPROM_PAGE_COUNT));
411 for (i = 0; i < ((uint32_t)FSL_FEATURE_EEPROM_SIZE / (uint32_t)FSL_FEATURE_EEPROM_PAGE_COUNT) / 4UL; i++)
412 {
413 addr[i] = data[i];
414 }
415
416 if (base->AUTOPROG == (uint32_t)kEEPROM_AutoProgramDisable)
417 {
418 base->CMD = FSL_FEATURE_EEPROM_PROGRAM_CMD;
419 }
420
421 /* Waiting for operation to finish */
422 while ((EEPROM_GetInterruptStatus(base) & (uint32_t)kEEPROM_ProgramFinishInterruptEnable) == 0UL)
423 {
424 }
425 }
426
427 return status;
428 }
429 #endif /* FSL_FEATURE_EEPROM_PAGE_COUNT */
430