]> git.donarmstrong.com Git - qmk_firmware.git/blob - tmk_core/common/chibios/eeprom.c
Generate API docs from source code comments (#2491)
[qmk_firmware.git] / tmk_core / common / chibios / eeprom.c
1 #include "ch.h"
2 #include "hal.h"
3
4 #include "eeconfig.h"
5
6 /*************************************/
7 /*          Hardware backend         */
8 /*                                   */
9 /*    Code from PJRC/Teensyduino     */
10 /*************************************/
11
12 /* Teensyduino Core Library
13  * http://www.pjrc.com/teensy/
14  * Copyright (c) 2013 PJRC.COM, LLC.
15  *
16  * Permission is hereby granted, free of charge, to any person obtaining
17  * a copy of this software and associated documentation files (the
18  * "Software"), to deal in the Software without restriction, including
19  * without limitation the rights to use, copy, modify, merge, publish,
20  * distribute, sublicense, and/or sell copies of the Software, and to
21  * permit persons to whom the Software is furnished to do so, subject to
22  * the following conditions:
23  *
24  * 1. The above copyright notice and this permission notice shall be 
25  * included in all copies or substantial portions of the Software.
26  *
27  * 2. If the Software is incorporated into a build system that allows 
28  * selection among a list of target devices, then similar target
29  * devices manufactured by PJRC.COM must be included in the list of
30  * target devices and selectable in the same manner.
31  *
32  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
33  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
34  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
35  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
36  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
37  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
38  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39  * SOFTWARE.
40  */
41
42
43 #if defined(K20x) /* chip selection */
44 /* Teensy 3.0, 3.1, 3.2; mchck; infinity keyboard */
45
46 // The EEPROM is really RAM with a hardware-based backup system to
47 // flash memory.  Selecting a smaller size EEPROM allows more wear
48 // leveling, for higher write endurance.  If you edit this file,
49 // set this to the smallest size your application can use.  Also,
50 // due to Freescale's implementation, writing 16 or 32 bit words
51 // (aligned to 2 or 4 byte boundaries) has twice the endurance
52 // compared to writing 8 bit bytes.
53 //
54 #define EEPROM_SIZE 32
55
56 // Writing unaligned 16 or 32 bit data is handled automatically when
57 // this is defined, but at a cost of extra code size.  Without this,
58 // any unaligned write will cause a hard fault exception!  If you're
59 // absolutely sure all 16 and 32 bit writes will be aligned, you can
60 // remove the extra unnecessary code.
61 //
62 #define HANDLE_UNALIGNED_WRITES
63
64 // Minimum EEPROM Endurance
65 // ------------------------
66 #if (EEPROM_SIZE == 2048)       // 35000 writes/byte or 70000 writes/word
67   #define EEESIZE 0x33
68 #elif (EEPROM_SIZE == 1024)     // 75000 writes/byte or 150000 writes/word
69   #define EEESIZE 0x34
70 #elif (EEPROM_SIZE == 512)      // 155000 writes/byte or 310000 writes/word
71   #define EEESIZE 0x35
72 #elif (EEPROM_SIZE == 256)      // 315000 writes/byte or 630000 writes/word
73   #define EEESIZE 0x36
74 #elif (EEPROM_SIZE == 128)      // 635000 writes/byte or 1270000 writes/word
75   #define EEESIZE 0x37
76 #elif (EEPROM_SIZE == 64)       // 1275000 writes/byte or 2550000 writes/word
77   #define EEESIZE 0x38
78 #elif (EEPROM_SIZE == 32)       // 2555000 writes/byte or 5110000 writes/word
79   #define EEESIZE 0x39
80 #endif
81
82 /** \brief eeprom initialization
83  *
84  * FIXME: needs doc
85  */
86 void eeprom_initialize(void)
87 {
88         uint32_t count=0;
89         uint16_t do_flash_cmd[] = {
90                 0xf06f, 0x037f, 0x7003, 0x7803,
91                 0xf013, 0x0f80, 0xd0fb, 0x4770};
92         uint8_t status;
93
94         if (FTFL->FCNFG & FTFL_FCNFG_RAMRDY) {
95                 // FlexRAM is configured as traditional RAM
96                 // We need to reconfigure for EEPROM usage
97                 FTFL->FCCOB0 = 0x80; // PGMPART = Program Partition Command
98                 FTFL->FCCOB4 = EEESIZE; // EEPROM Size
99                 FTFL->FCCOB5 = 0x03; // 0K for Dataflash, 32K for EEPROM backup
100                 __disable_irq();
101                 // do_flash_cmd() must execute from RAM.  Luckily the C syntax is simple...
102                 (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFL->FSTAT));
103                 __enable_irq();
104                 status = FTFL->FSTAT;
105                 if (status & (FTFL_FSTAT_RDCOLERR|FTFL_FSTAT_ACCERR|FTFL_FSTAT_FPVIOL)) {
106                         FTFL->FSTAT = (status & (FTFL_FSTAT_RDCOLERR|FTFL_FSTAT_ACCERR|FTFL_FSTAT_FPVIOL));
107                         return; // error
108                 }
109         }
110         // wait for eeprom to become ready (is this really necessary?)
111         while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) {
112                 if (++count > 20000) break;
113         }
114 }
115
116 #define FlexRAM ((uint8_t *)0x14000000)
117
118 /** \brief eeprom read byte
119  *
120  * FIXME: needs doc
121  */
122 uint8_t eeprom_read_byte(const uint8_t *addr)
123 {
124         uint32_t offset = (uint32_t)addr;
125         if (offset >= EEPROM_SIZE) return 0;
126         if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
127         return FlexRAM[offset];
128 }
129
130 /** \brief eeprom read word
131  *
132  * FIXME: needs doc
133  */
134 uint16_t eeprom_read_word(const uint16_t *addr)
135 {
136         uint32_t offset = (uint32_t)addr;
137         if (offset >= EEPROM_SIZE-1) return 0;
138         if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
139         return *(uint16_t *)(&FlexRAM[offset]);
140 }
141
142 /** \brief eeprom read dword
143  *
144  * FIXME: needs doc
145  */
146 uint32_t eeprom_read_dword(const uint32_t *addr)
147 {
148         uint32_t offset = (uint32_t)addr;
149         if (offset >= EEPROM_SIZE-3) return 0;
150         if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
151         return *(uint32_t *)(&FlexRAM[offset]);
152 }
153
154 /** \brief eeprom read block
155  *
156  * FIXME: needs doc
157  */
158 void eeprom_read_block(void *buf, const void *addr, uint32_t len)
159 {
160         uint32_t offset = (uint32_t)addr;
161         uint8_t *dest = (uint8_t *)buf;
162         uint32_t end = offset + len;
163         
164         if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
165         if (end > EEPROM_SIZE) end = EEPROM_SIZE;
166         while (offset < end) {
167                 *dest++ = FlexRAM[offset++];
168         }
169 }
170
171 /** \brief eeprom is ready
172  *
173  * FIXME: needs doc
174  */
175 int eeprom_is_ready(void)
176 {
177         return (FTFL->FCNFG & FTFL_FCNFG_EEERDY) ? 1 : 0;
178 }
179
180 /** \brief flexram wait
181  *
182  * FIXME: needs doc
183  */
184 static void flexram_wait(void)
185 {
186         while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) {
187                 // TODO: timeout
188         }
189 }
190
191 /** \brief eeprom_write_byte
192  *
193  * FIXME: needs doc
194  */
195 void eeprom_write_byte(uint8_t *addr, uint8_t value)
196 {
197         uint32_t offset = (uint32_t)addr;
198
199         if (offset >= EEPROM_SIZE) return;
200         if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
201         if (FlexRAM[offset] != value) {
202                 FlexRAM[offset] = value;
203                 flexram_wait();
204         }
205 }
206
207 /** \brief eeprom write word
208  *
209  * FIXME: needs doc
210  */
211 void eeprom_write_word(uint16_t *addr, uint16_t value)
212 {
213         uint32_t offset = (uint32_t)addr;
214
215         if (offset >= EEPROM_SIZE-1) return;
216         if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
217 #ifdef HANDLE_UNALIGNED_WRITES
218         if ((offset & 1) == 0) {
219 #endif
220                 if (*(uint16_t *)(&FlexRAM[offset]) != value) {
221                         *(uint16_t *)(&FlexRAM[offset]) = value;
222                         flexram_wait();
223                 }
224 #ifdef HANDLE_UNALIGNED_WRITES
225         } else {
226                 if (FlexRAM[offset] != value) {
227                         FlexRAM[offset] = value;
228                         flexram_wait();
229                 }
230                 if (FlexRAM[offset + 1] != (value >> 8)) {
231                         FlexRAM[offset + 1] = value >> 8;
232                         flexram_wait();
233                 }
234         }
235 #endif
236 }
237
238 /** \brief eeprom write dword
239  *
240  * FIXME: needs doc
241  */
242 void eeprom_write_dword(uint32_t *addr, uint32_t value)
243 {
244         uint32_t offset = (uint32_t)addr;
245
246         if (offset >= EEPROM_SIZE-3) return;
247         if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
248 #ifdef HANDLE_UNALIGNED_WRITES
249         switch (offset & 3) {
250         case 0:
251 #endif
252                 if (*(uint32_t *)(&FlexRAM[offset]) != value) {
253                         *(uint32_t *)(&FlexRAM[offset]) = value;
254                         flexram_wait();
255                 }
256                 return;
257 #ifdef HANDLE_UNALIGNED_WRITES
258         case 2:
259                 if (*(uint16_t *)(&FlexRAM[offset]) != value) {
260                         *(uint16_t *)(&FlexRAM[offset]) = value;
261                         flexram_wait();
262                 }
263                 if (*(uint16_t *)(&FlexRAM[offset + 2]) != (value >> 16)) {
264                         *(uint16_t *)(&FlexRAM[offset + 2]) = value >> 16;
265                         flexram_wait();
266                 }
267                 return;
268         default:
269                 if (FlexRAM[offset] != value) {
270                         FlexRAM[offset] = value;
271                         flexram_wait();
272                 }
273                 if (*(uint16_t *)(&FlexRAM[offset + 1]) != (value >> 8)) {
274                         *(uint16_t *)(&FlexRAM[offset + 1]) = value >> 8;
275                         flexram_wait();
276                 }
277                 if (FlexRAM[offset + 3] != (value >> 24)) {
278                         FlexRAM[offset + 3] = value >> 24;
279                         flexram_wait();
280                 }
281         }
282 #endif
283 }
284
285 /** \brief eeprom write block
286  *
287  * FIXME: needs doc
288  */
289 void eeprom_write_block(const void *buf, void *addr, uint32_t len)
290 {
291         uint32_t offset = (uint32_t)addr;
292         const uint8_t *src = (const uint8_t *)buf;
293
294         if (offset >= EEPROM_SIZE) return;
295         if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
296         if (len >= EEPROM_SIZE) len = EEPROM_SIZE;
297         if (offset + len >= EEPROM_SIZE) len = EEPROM_SIZE - offset;
298         while (len > 0) {
299                 uint32_t lsb = offset & 3;
300                 if (lsb == 0 && len >= 4) {
301                         // write aligned 32 bits
302                         uint32_t val32;
303                         val32 = *src++;
304                         val32 |= (*src++ << 8);
305                         val32 |= (*src++ << 16);
306                         val32 |= (*src++ << 24);
307                         if (*(uint32_t *)(&FlexRAM[offset]) != val32) {
308                                 *(uint32_t *)(&FlexRAM[offset]) = val32;
309                                 flexram_wait();
310                         }
311                         offset += 4;
312                         len -= 4;
313                 } else if ((lsb == 0 || lsb == 2) && len >= 2) {
314                         // write aligned 16 bits
315                         uint16_t val16;
316                         val16 = *src++;
317                         val16 |= (*src++ << 8);
318                         if (*(uint16_t *)(&FlexRAM[offset]) != val16) {
319                                 *(uint16_t *)(&FlexRAM[offset]) = val16;
320                                 flexram_wait();
321                         }
322                         offset += 2;
323                         len -= 2;
324                 } else {
325                         // write 8 bits
326                         uint8_t val8 = *src++;
327                         if (FlexRAM[offset] != val8) {
328                                 FlexRAM[offset] = val8;
329                                 flexram_wait();
330                         }
331                         offset++;
332                         len--;
333                 }
334         }
335 }
336
337 /*
338 void do_flash_cmd(volatile uint8_t *fstat)
339 {
340         *fstat = 0x80;
341         while ((*fstat & 0x80) == 0) ; // wait
342 }
343 00000000 <do_flash_cmd>:
344    0:   f06f 037f       mvn.w   r3, #127        ; 0x7f
345    4:   7003            strb    r3, [r0, #0]
346    6:   7803            ldrb    r3, [r0, #0]
347    8:   f013 0f80       tst.w   r3, #128        ; 0x80
348    c:   d0fb            beq.n   6 <do_flash_cmd+0x6>
349    e:   4770            bx      lr
350 */
351
352 #elif defined(KL2x) /* chip selection */
353 /* Teensy LC (emulated) */
354
355 #define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))
356
357 extern uint32_t __eeprom_workarea_start__;
358 extern uint32_t __eeprom_workarea_end__;
359
360 #define EEPROM_SIZE 128
361
362 static uint32_t flashend = 0;
363
364 void eeprom_initialize(void)
365 {
366         const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__);
367
368         do {
369                 if (*p++ == 0xFFFF) {
370                         flashend = (uint32_t)(p - 2);
371                         return;
372                 }
373         } while (p < (uint16_t *)SYMVAL(__eeprom_workarea_end__));
374         flashend = (uint32_t)((uint16_t *)SYMVAL(__eeprom_workarea_end__) - 1);
375 }
376
377 uint8_t eeprom_read_byte(const uint8_t *addr)
378 {
379         uint32_t offset = (uint32_t)addr;
380         const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__);
381         const uint16_t *end = (const uint16_t *)((uint32_t)flashend);
382         uint16_t val;
383         uint8_t data=0xFF;
384
385         if (!end) {
386                 eeprom_initialize();
387                 end = (const uint16_t *)((uint32_t)flashend);
388         }
389         if (offset < EEPROM_SIZE) {
390                 while (p <= end) {
391                         val = *p++;
392                         if ((val & 255) == offset) data = val >> 8;
393                 }
394         }
395         return data;
396 }
397
398 static void flash_write(const uint16_t *code, uint32_t addr, uint32_t data)
399 {
400         // with great power comes great responsibility....
401         uint32_t stat;
402         *(uint32_t *)&(FTFA->FCCOB3) = 0x06000000 | (addr & 0x00FFFFFC);
403         *(uint32_t *)&(FTFA->FCCOB7) = data;
404         __disable_irq();
405         (*((void (*)(volatile uint8_t *))((uint32_t)code | 1)))(&(FTFA->FSTAT));
406         __enable_irq();
407         stat = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR|FTFA_FSTAT_ACCERR|FTFA_FSTAT_FPVIOL);
408         if (stat) {
409                 FTFA->FSTAT = stat;
410         }
411         MCM->PLACR |= MCM_PLACR_CFCC;
412 }
413
414 void eeprom_write_byte(uint8_t *addr, uint8_t data)
415 {
416         uint32_t offset = (uint32_t)addr;
417         const uint16_t *p, *end = (const uint16_t *)((uint32_t)flashend);
418         uint32_t i, val, flashaddr;
419         uint16_t do_flash_cmd[] = {
420                 0x2380, 0x7003, 0x7803, 0xb25b, 0x2b00, 0xdafb, 0x4770};
421         uint8_t buf[EEPROM_SIZE];
422
423         if (offset >= EEPROM_SIZE) return;
424         if (!end) {
425                 eeprom_initialize();
426                 end = (const uint16_t *)((uint32_t)flashend);
427         }
428         if (++end < (uint16_t *)SYMVAL(__eeprom_workarea_end__)) {
429                 val = (data << 8) | offset;
430                 flashaddr = (uint32_t)end;
431                 flashend = flashaddr;
432                 if ((flashaddr & 2) == 0) {
433                         val |= 0xFFFF0000;
434                 } else {
435                         val <<= 16;
436                         val |= 0x0000FFFF;
437                 }
438                 flash_write(do_flash_cmd, flashaddr, val);
439         } else {
440                 for (i=0; i < EEPROM_SIZE; i++) {
441                         buf[i] = 0xFF;
442                 }
443                 val = 0;
444                 for (p = (uint16_t *)SYMVAL(__eeprom_workarea_start__); p < (uint16_t *)SYMVAL(__eeprom_workarea_end__); p++) {
445                         val = *p;
446                         if ((val & 255) < EEPROM_SIZE) {
447                                 buf[val & 255] = val >> 8;
448                         }
449                 }
450                 buf[offset] = data;
451                 for (flashaddr=(uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__); flashaddr < (uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_end__); flashaddr += 1024) {
452                         *(uint32_t *)&(FTFA->FCCOB3) = 0x09000000 | flashaddr;
453                         __disable_irq();
454                         (*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFA->FSTAT));
455                         __enable_irq();
456                         val = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR|FTFA_FSTAT_ACCERR|FTFA_FSTAT_FPVIOL);;
457                         if (val) FTFA->FSTAT = val;
458                         MCM->PLACR |= MCM_PLACR_CFCC;
459                 }
460                 flashaddr=(uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__);
461                 for (i=0; i < EEPROM_SIZE; i++) {
462                         if (buf[i] == 0xFF) continue;
463                         if ((flashaddr & 2) == 0) {
464                                 val = (buf[i] << 8) | i;
465                         } else {
466                                 val = val | (buf[i] << 24) | (i << 16);
467                                 flash_write(do_flash_cmd, flashaddr, val);
468                         }
469                         flashaddr += 2;
470                 }
471                 flashend = flashaddr;
472                 if ((flashaddr & 2)) {
473                         val |= 0xFFFF0000;
474                         flash_write(do_flash_cmd, flashaddr, val);
475                 }
476         }
477 }
478
479 /*
480 void do_flash_cmd(volatile uint8_t *fstat)
481 {
482         *fstat = 0x80;
483         while ((*fstat & 0x80) == 0) ; // wait
484 }
485 00000000 <do_flash_cmd>:
486    0:   2380            movs    r3, #128        ; 0x80
487    2:   7003            strb    r3, [r0, #0]
488    4:   7803            ldrb    r3, [r0, #0]
489    6:   b25b            sxtb    r3, r3
490    8:   2b00            cmp     r3, #0
491    a:   dafb            bge.n   4 <do_flash_cmd+0x4>
492    c:   4770            bx      lr
493 */
494
495
496 uint16_t eeprom_read_word(const uint16_t *addr)
497 {
498         const uint8_t *p = (const uint8_t *)addr;
499         return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8);
500 }
501
502 uint32_t eeprom_read_dword(const uint32_t *addr)
503 {
504         const uint8_t *p = (const uint8_t *)addr;
505         return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8)
506                 | (eeprom_read_byte(p+2) << 16) | (eeprom_read_byte(p+3) << 24);
507 }
508
509 void eeprom_read_block(void *buf, const void *addr, uint32_t len)
510 {
511         const uint8_t *p = (const uint8_t *)addr;
512         uint8_t *dest = (uint8_t *)buf;
513         while (len--) {
514                 *dest++ = eeprom_read_byte(p++);
515         }
516 }
517
518 int eeprom_is_ready(void)
519 {
520         return 1;
521 }
522
523 void eeprom_write_word(uint16_t *addr, uint16_t value)
524 {
525         uint8_t *p = (uint8_t *)addr;
526         eeprom_write_byte(p++, value);
527         eeprom_write_byte(p, value >> 8);
528 }
529
530 void eeprom_write_dword(uint32_t *addr, uint32_t value)
531 {
532         uint8_t *p = (uint8_t *)addr;
533         eeprom_write_byte(p++, value);
534         eeprom_write_byte(p++, value >> 8);
535         eeprom_write_byte(p++, value >> 16);
536         eeprom_write_byte(p, value >> 24);
537 }
538
539 void eeprom_write_block(const void *buf, void *addr, uint32_t len)
540 {
541         uint8_t *p = (uint8_t *)addr;
542         const uint8_t *src = (const uint8_t *)buf;
543         while (len--) {
544                 eeprom_write_byte(p++, *src++);
545         }
546 }
547
548 #else
549 // No EEPROM supported, so emulate it
550
551 #define EEPROM_SIZE 32
552 static uint8_t buffer[EEPROM_SIZE];
553
554 uint8_t eeprom_read_byte(const uint8_t *addr) {
555         uint32_t offset = (uint32_t)addr;
556         return buffer[offset];
557 }
558
559 void eeprom_write_byte(uint8_t *addr, uint8_t value) {
560         uint32_t offset = (uint32_t)addr;
561         buffer[offset] = value;
562 }
563
564 uint16_t eeprom_read_word(const uint16_t *addr) {
565         const uint8_t *p = (const uint8_t *)addr;
566         return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8);
567 }
568
569 uint32_t eeprom_read_dword(const uint32_t *addr) {
570         const uint8_t *p = (const uint8_t *)addr;
571         return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8)
572                 | (eeprom_read_byte(p+2) << 16) | (eeprom_read_byte(p+3) << 24);
573 }
574
575 void eeprom_read_block(void *buf, const void *addr, uint32_t len) {
576         const uint8_t *p = (const uint8_t *)addr;
577         uint8_t *dest = (uint8_t *)buf;
578         while (len--) {
579                 *dest++ = eeprom_read_byte(p++);
580         }
581 }
582
583 void eeprom_write_word(uint16_t *addr, uint16_t value) {
584         uint8_t *p = (uint8_t *)addr;
585         eeprom_write_byte(p++, value);
586         eeprom_write_byte(p, value >> 8);
587 }
588
589 void eeprom_write_dword(uint32_t *addr, uint32_t value) {
590         uint8_t *p = (uint8_t *)addr;
591         eeprom_write_byte(p++, value);
592         eeprom_write_byte(p++, value >> 8);
593         eeprom_write_byte(p++, value >> 16);
594         eeprom_write_byte(p, value >> 24);
595 }
596
597 void eeprom_write_block(const void *buf, void *addr, uint32_t len) {
598         uint8_t *p = (uint8_t *)addr;
599         const uint8_t *src = (const uint8_t *)buf;
600         while (len--) {
601                 eeprom_write_byte(p++, *src++);
602         }
603 }
604
605 #endif /* chip selection */
606 // The update functions just calls write for now, but could probably be optimized
607
608 void eeprom_update_byte(uint8_t *addr, uint8_t value) {
609         eeprom_write_byte(addr, value);
610 }
611
612 void eeprom_update_word(uint16_t *addr, uint16_t value) {
613         uint8_t *p = (uint8_t *)addr;
614         eeprom_write_byte(p++, value);
615         eeprom_write_byte(p, value >> 8);
616 }
617
618 void eeprom_update_dword(uint32_t *addr, uint32_t value) {
619         uint8_t *p = (uint8_t *)addr;
620         eeprom_write_byte(p++, value);
621         eeprom_write_byte(p++, value >> 8);
622         eeprom_write_byte(p++, value >> 16);
623         eeprom_write_byte(p, value >> 24);
624 }
625
626 void eeprom_update_block(const void *buf, void *addr, uint32_t len) {
627         uint8_t *p = (uint8_t *)addr;
628         const uint8_t *src = (const uint8_t *)buf;
629         while (len--) {
630                 eeprom_write_byte(p++, *src++);
631         }
632 }