Refactor eeprom for kblock interface, for now disable the old api.
[bertos.git] / bertos / drv / eeprom.c
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2003, 2004, 2005, 2010 Develer S.r.l. (http://www.develer.com/)
30  *
31  * -->
32  *
33  * \brief Driver for the 24xx16 and 24xx256 I2C EEPROMS (implementation)
34  *
35  * \author Stefano Fedrigo <aleph@develer.com>
36  * \author Bernie Innocenti <bernie@codewiz.org>
37  */
38
39 #include "eeprom.h"
40
41 #include "cfg/cfg_i2c.h"
42
43 #include <cfg/macros.h>  // MIN()
44 #include <cfg/debug.h>
45 #include <cfg/module.h>  // MOD_CHECK()
46
47 #include <cpu/attr.h>
48 #include <drv/i2c.h>
49
50 #include <drv/wdt.h>
51
52 #include <cpu/byteorder.h> // cpu_to_be16()
53
54 #include <string.h>  // memset()
55
56 /**
57  * EEPROM ID code
58  */
59 #define EEPROM_ID  0xA0
60
61 /**
62  * This macros form the correct slave address for EEPROMs
63  */
64 #define EEPROM_ADDR(x) (EEPROM_ID | (((uint8_t)((x) & 0x07)) << 1))
65
66
67 /**
68  * Array used to describe EEPROM memory devices currently supported.
69  */
70 static const EepromInfo mem_info[] =
71 {
72         {
73                 /* 24XX08 */
74                 .has_dev_addr = false,
75                 .blk_size = 0x10,
76                 .e2_size = 0x400,
77         },
78         {
79                 /* 24XX16 */
80                 .has_dev_addr = false,
81                 .blk_size = 0x10,
82                 .e2_size = 0x800,
83         },
84         {
85                 /* 24XX256 */
86                 .has_dev_addr = true,
87                 .blk_size = 0x40,
88                 .e2_size = 0x8000,
89         },
90         {
91                 /* 24XX512 */
92                 .has_dev_addr = true,
93                 .blk_size = 0x80,
94                 .e2_size = 0x10000,
95         },
96         {
97                 /* 24XX1024 */
98                 .has_dev_addr = true,
99                 .blk_size = 0x100,
100                 .e2_size = 0x20000,
101         },
102
103         /* Add other memories here */
104 };
105
106 STATIC_ASSERT(countof(mem_info) == EEPROM_CNT);
107
108 #if 0//!CONFIG_I2C_DISABLE_OLD_API
109 /**
110  * Copy \a size bytes from buffer \a buf to
111  * eeprom.
112  */
113 static size_t eeprom_writeRaw(struct KFile *_fd, const void *buf, size_t size)
114 {
115         Eeprom *fd = EEPROM_CAST(_fd);
116         e2dev_addr_t dev_addr;
117         uint8_t addr_buf[2];
118         uint8_t addr_len;
119         size_t wr_len = 0;
120
121         e2blk_size_t blk_size = mem_info[fd->type].blk_size;
122
123         STATIC_ASSERT(countof(addr_buf) <= sizeof(e2addr_t));
124
125         /* clamp size to memory limit (otherwise may roll back) */
126         ASSERT(_fd->seek_pos + (kfile_off_t)size <= (kfile_off_t)_fd->size);
127         size = MIN((kfile_off_t)size, _fd->size - _fd->seek_pos);
128
129         if (mem_info[fd->type].has_dev_addr)
130         {
131                 dev_addr = fd->addr;
132                 addr_len = 2;
133         }
134         else
135         {
136                 dev_addr = (e2dev_addr_t)((fd->fd.seek_pos >> 8) & 0x07);
137                 addr_len = 1;
138         }
139
140         while (size)
141         {
142                 /*
143                  * Split write in multiple sequential mode operations that
144                  * don't cross page boundaries.
145                  */
146                 size_t count = MIN(size, (size_t)(blk_size - (fd->fd.seek_pos & (blk_size - 1))));
147
148                 if (mem_info[fd->type].has_dev_addr)
149                 {
150                         addr_buf[0] = (fd->fd.seek_pos >> 8) & 0xFF;
151                         addr_buf[1] = (fd->fd.seek_pos & 0xFF);
152                 }
153                 else
154                 {
155                         dev_addr = (e2dev_addr_t)((fd->fd.seek_pos >> 8) & 0x07);
156                         addr_buf[0] = (fd->fd.seek_pos & 0xFF);
157                 }
158
159
160                 if (!(i2c_start_w(EEPROM_ADDR(dev_addr))
161                         && i2c_send(addr_buf, addr_len)
162                         && i2c_send(buf, count)))
163                 {
164                         i2c_stop();
165                         return wr_len;
166                 }
167
168                 i2c_stop();
169
170                 /* Update count and addr for next operation */
171                 size -= count;
172                 fd->fd.seek_pos += count;
173                 buf = ((const char *)buf) + count;
174                 wr_len += count;
175         }
176
177         return wr_len;
178 }
179
180 /**
181  * Copy \a size bytes from buffer \a _buf to
182  * eeprom.
183  * \note Writes are verified and if buffer content
184  *       is not matching we retry 5 times max.
185  */
186 static size_t eeprom_writeVerify(struct KFile *_fd, const void *_buf, size_t size)
187 {
188         Eeprom *fd = EEPROM_CAST(_fd);
189         int retries = 5;
190         size_t wr_len = 0;
191
192         while (retries--)
193         {
194                 wr_len = eeprom_writeRaw(_fd, _buf, size);
195                 /* rewind to verify what we have just written */
196                 kfile_seek(_fd, -(kfile_off_t)wr_len, KSM_SEEK_CUR);
197                 if (wr_len == size
198                  && eeprom_verify(fd, _buf, wr_len))
199                 {
200                         /* Forward to go after what we have written*/
201                         kfile_seek(_fd, wr_len, KSM_SEEK_CUR);
202                         return wr_len;
203                 }
204         }
205         return wr_len;
206 }
207
208
209 /**
210  * Copy \a size bytes
211  * from eeprom to RAM to buffer \a _buf.
212  *
213  * \return the number of bytes read.
214  */
215 static size_t eeprom_read(struct KFile *_fd, void *_buf, size_t size)
216 {
217         Eeprom *fd = EEPROM_CAST(_fd);
218         uint8_t addr_buf[2];
219         uint8_t addr_len;
220         size_t rd_len = 0;
221         uint8_t *buf = (uint8_t *)_buf;
222
223         STATIC_ASSERT(countof(addr_buf) <= sizeof(e2addr_t));
224
225         /* clamp size to memory limit (otherwise may roll back) */
226         ASSERT(_fd->seek_pos + (kfile_off_t)size <= (kfile_off_t)_fd->size);
227         size = MIN((kfile_off_t)size, _fd->size - _fd->seek_pos);
228
229         e2dev_addr_t dev_addr;
230         if (mem_info[fd->type].has_dev_addr)
231         {
232                 dev_addr = fd->addr;
233                 addr_len = 2;
234                 addr_buf[0] = (fd->fd.seek_pos >> 8) & 0xFF;
235                 addr_buf[1] = (fd->fd.seek_pos & 0xFF);
236         }
237         else
238         {
239                 dev_addr = (e2dev_addr_t)((fd->fd.seek_pos >> 8) & 0x07);
240                 addr_len = 1;
241                 addr_buf[0] = (fd->fd.seek_pos & 0xFF);
242         }
243
244
245         if (!(i2c_start_w(EEPROM_ADDR(dev_addr))
246            && i2c_send(addr_buf, addr_len)
247            && i2c_start_r(EEPROM_ADDR(dev_addr))))
248         {
249                 i2c_stop();
250                 return 0;
251         }
252
253
254         if (i2c_recv(buf, size))
255         {
256                 fd->fd.seek_pos += size;
257                 rd_len += size;
258         }
259
260         i2c_stop();
261         return rd_len;
262 }
263
264 /**
265  * Check that the contents of an EEPROM range
266  * match with a provided data buffer.
267  *
268  * \return true on success.
269  * \note Seek position of \a fd will not change.
270  */
271 bool eeprom_verify(Eeprom *fd, const void *buf, size_t count)
272 {
273         uint8_t verify_buf[16];
274         bool result = true;
275
276         /* Save seek position */
277         kfile_off_t prev_seek = fd->fd.seek_pos;
278
279         while (count && result)
280         {
281                 /* Split read in smaller pieces */
282                 size_t size = MIN(count, sizeof verify_buf);
283
284                 /* Read back buffer */
285                 if (eeprom_read(&fd->fd, verify_buf, size))
286                 {
287                         if (memcmp(buf, verify_buf, size) != 0)
288                         {
289                                 TRACEMSG("Data mismatch!");
290                                 result = false;
291                         }
292                 }
293                 else
294                 {
295                         TRACEMSG("Read error!");
296                         result = false;
297                 }
298
299                 /* Update count and addr for next operation */
300                 count -= size;
301                 buf = ((const char *)buf) + size;
302         }
303
304         /* Restore previous seek position */
305         fd->fd.seek_pos = prev_seek;
306         return result;
307 }
308
309 /**
310  * Erase specified part of eeprom, writing 0xFF.
311  *
312  * \a addr   starting address
313  * \a count  length of block to erase
314  * \note Seek position is unchanged.
315  * \return true if ok, false otherwise.
316  */
317 bool eeprom_erase(Eeprom *fd, e2addr_t addr, e2_size_t count)
318 {
319         e2blk_size_t blk_size = mem_info[fd->type].blk_size;
320         uint8_t buf[blk_size];
321         kfile_off_t prev_off = fd->fd.seek_pos;
322         bool res = true;
323         size_t size;
324
325         memset(buf, 0xFF, blk_size);
326
327
328         kfile_seek(&fd->fd, addr, KSM_SEEK_SET);
329
330         /*
331          * Optimization: this first write id used to realign
332          * current address to block boundaries.
333          */
334
335         wdt_reset();
336         size = MIN(count, (e2_size_t)(blk_size - (addr & (blk_size - 1))));
337         if (kfile_write(&fd->fd, buf, size) != size)
338         {
339                 fd->fd.seek_pos = prev_off;
340                 return false;
341         }
342         count -= size;
343
344         /* Clear all */
345         while (count)
346         {
347                 /* Long operation, reset watchdog */
348                 wdt_reset();
349
350                 size = MIN(count, (e2_size_t)sizeof buf);
351                 if (kfile_write(&fd->fd, buf, size) != size)
352                 {
353                         res = false;
354                         break;
355                 }
356
357                 count -= size;
358         }
359         fd->fd.seek_pos = prev_off;
360         return res;
361 }
362
363
364 /**
365  * Initialize EEPROM module.
366  * \a fd is the Kfile context.
367  * \a type is the eeprom device we want to initialize (\see EepromType)
368  * \a addr is the i2c devide address (usually pins A0, A1, A2).
369  * \a verify is true if you want that every write operation will be verified.
370  */
371 void eeprom_init(Eeprom *fd, EepromType type, e2dev_addr_t addr, bool verify)
372 {
373         MOD_CHECK(i2c);
374         ASSERT(type < EEPROM_CNT);
375
376         memset(fd, 0, sizeof(*fd));
377         DB(fd->fd._type = KFT_EEPROM);
378
379         fd->type = type;
380         fd->addr = addr;
381         fd->fd.size = mem_info[fd->type].e2_size;
382
383         // Setup eeprom programming functions.
384         fd->fd.read = eeprom_read;
385         if (verify)
386                 fd->fd.write = eeprom_writeVerify;
387         else
388                 fd->fd.write = eeprom_writeRaw;
389         fd->fd.close = kfile_genericClose;
390
391         fd->fd.seek = kfile_genericSeek;
392 }
393
394 #endif /* !CONFIG_I2C_DISABLE_OLD_API */
395
396 static size_t eeprom_writeDirect(KBlock *b, block_idx_t idx, const void *buf, size_t offset, size_t size)
397 {
398         Eeprom *fd = EEPROM_CAST(b);
399         e2dev_addr_t dev_addr;
400         uint8_t addr_buf[2];
401         uint8_t addr_len;
402         uint32_t abs_addr = b->blk_size * idx + offset;
403
404         STATIC_ASSERT(countof(addr_buf) <= sizeof(e2addr_t));
405
406
407         /* clamp size to memory limit (otherwise may roll back) */
408         ASSERT(idx <= b->blk_cnt);
409         size = MIN(size, b->blk_size - offset);
410
411         if (mem_info[fd->type].has_dev_addr)
412         {
413                 dev_addr = fd->addr;
414                 addr_len = 2;
415         }
416         else
417         {
418                 dev_addr = (e2dev_addr_t)((abs_addr >> 8) & 0x07);
419                 addr_len = 1;
420         }
421
422         if (mem_info[fd->type].has_dev_addr)
423         {
424                 addr_buf[0] = (abs_addr >> 8) & 0xFF;
425                 addr_buf[1] = (abs_addr & 0xFF);
426         }
427         else
428         {
429                 dev_addr = (e2dev_addr_t)((abs_addr >> 8) & 0x07);
430                 addr_buf[0] = (abs_addr & 0xFF);
431         }
432
433         i2c_start_w(fd->i2c, EEPROM_ADDR(dev_addr),  addr_len + size, I2C_STOP);
434         i2c_write(fd->i2c, addr_buf, addr_len);
435         i2c_write(fd->i2c, buf, size);
436
437         if (i2c_error(fd->i2c))
438                 return 0;
439
440         return size;
441 }
442
443
444 static size_t eeprom_readDirect(struct KBlock *b, block_idx_t idx, void *_buf, size_t offset, size_t size)
445 {
446         Eeprom *fd = EEPROM_CAST(b);
447         uint8_t addr_buf[2];
448         uint8_t addr_len;
449         size_t rd_len = 0;
450         uint8_t *buf = (uint8_t *)_buf;
451         uint32_t abs_addr = mem_info[fd->type].blk_size * idx + offset;
452
453         STATIC_ASSERT(countof(addr_buf) <= sizeof(e2addr_t));
454
455         /* clamp size to memory limit (otherwise may roll back) */
456         ASSERT(idx <= b->blk_cnt);
457         size = MIN(size, b->blk_size - offset);
458
459         e2dev_addr_t dev_addr;
460         if (mem_info[fd->type].has_dev_addr)
461         {
462                 dev_addr = fd->addr;
463                 addr_len = 2;
464                 addr_buf[0] = (abs_addr >> 8) & 0xFF;
465                 addr_buf[1] = (abs_addr & 0xFF);
466         }
467         else
468         {
469                 dev_addr = (e2dev_addr_t)((abs_addr >> 8) & 0x07);
470                 addr_len = 1;
471                 addr_buf[0] = (abs_addr & 0xFF);
472         }
473
474
475         i2c_start_w(fd->i2c, EEPROM_ADDR(dev_addr),  addr_len, I2C_NOSTOP);
476         i2c_write(fd->i2c, addr_buf, addr_len);
477
478         i2c_start_r(fd->i2c, EEPROM_ADDR(dev_addr), size, I2C_STOP);
479         i2c_read(fd->i2c, buf, size);
480
481         if (i2c_error(fd->i2c))
482                    return rd_len;
483
484         rd_len += size;
485
486         return rd_len;
487 }
488
489 static int kblockEeprom_dummy(UNUSED_ARG(struct KBlock *,b))
490 {
491         return 0;
492 }
493
494
495 static const KBlockVTable eeprom_unbuffered_vt =
496 {
497         .readDirect = eeprom_readDirect,
498         .writeDirect = eeprom_writeDirect,
499
500         .error = kblockEeprom_dummy,
501         .clearerr = (kblock_clearerr_t)kblockEeprom_dummy,
502 };
503
504 /**
505  * Initialize EEPROM module.
506  * \param b is the Kblock context.
507  * \param type is the eeprom device we want to initialize (\see EepromType)
508  * \param i2c context for i2c channel
509  * \param addr is the i2c devide address (usually pins A0, A1, A2).
510  */
511 void eeprom_init(Eeprom *b, I2c *i2c, EepromType type, e2dev_addr_t addr)
512 {
513         ASSERT(type < EEPROM_CNT);
514
515         memset(b, 0, sizeof(*b));
516         DB(b->b.priv.type = KBT_EEPROM);
517
518         b->type = type;
519         b->addr = addr;
520         b->i2c = i2c;
521
522         b->b.blk_size = mem_info[type].blk_size;
523         b->b.blk_cnt = mem_info[type].e2_size / mem_info[type].blk_size;
524         b->b.priv.flags |= KB_PARTIAL_WRITE;
525         b->b.priv.vt = &eeprom_unbuffered_vt;
526 }
527
528