00001
00041 #include "eeprom.h"
00042
00043 #warning TODO:Test and complete this module for arm platform.
00044 #if !CPU_ARM
00045
00046 #include <cfg/macros.h>
00047 #include <cfg/debug.h>
00048 #include <cfg/module.h>
00049
00050 #include <cpu/attr.h>
00051 #include <drv/i2c.h>
00052
00053 #include <drv/wdt.h>
00054
00055 #include <cpu/byteorder.h>
00056
00057 #include <string.h>
00058
00062 #define EEPROM_ID 0xA0
00063
00067 #define EEPROM_ADDR(x) (EEPROM_ID | (((uint8_t)((x) & 0x07)) << 1))
00068
00069
00073 static const EepromInfo mem_info[] =
00074 {
00075 {
00076
00077 .has_dev_addr = false,
00078 .blk_size = 0x10,
00079 .e2_size = 0x800,
00080 },
00081 {
00082
00083 .has_dev_addr = true,
00084 .blk_size = 0x40,
00085 .e2_size = 0x8000,
00086 },
00087 {
00088
00089 .has_dev_addr = true,
00090 .blk_size = 0x80,
00091 .e2_size = 0x10000,
00092 },
00093
00094 };
00095
00096 STATIC_ASSERT(countof(mem_info) == EEPROM_CNT);
00097
00098
00103 static size_t eeprom_writeRaw(struct KFile *_fd, const void *buf, size_t size)
00104 {
00105 Eeprom *fd = EEPROM_CAST(_fd);
00106 e2dev_addr_t dev_addr;
00107 uint8_t addr_buf[2];
00108 uint8_t addr_len;
00109 size_t wr_len = 0;
00110
00111 e2blk_size_t blk_size = mem_info[fd->type].blk_size;
00112
00113 STATIC_ASSERT(countof(addr_buf) <= sizeof(e2addr_t));
00114
00115
00116 ASSERT(_fd->seek_pos + size <= (kfile_off_t)_fd->size);
00117 size = MIN((kfile_off_t)size, _fd->size - _fd->seek_pos);
00118
00119 if (mem_info[fd->type].has_dev_addr)
00120 {
00121 dev_addr = fd->addr;
00122 addr_len = 2;
00123 }
00124 else
00125 {
00126 dev_addr = (e2dev_addr_t)((fd->fd.seek_pos >> 8) & 0x07);
00127 addr_len = 1;
00128 }
00129
00130 while (size)
00131 {
00132
00133
00134
00135
00136 size_t count = MIN(size, (size_t)(blk_size - (fd->fd.seek_pos & (blk_size - 1))));
00137
00138 if (mem_info[fd->type].has_dev_addr)
00139 {
00140 addr_buf[0] = (fd->fd.seek_pos >> 8) & 0xFF;
00141 addr_buf[1] = (fd->fd.seek_pos & 0xFF);
00142 }
00143 else
00144 {
00145 dev_addr = (e2dev_addr_t)((fd->fd.seek_pos >> 8) & 0x07);
00146 addr_buf[0] = (fd->fd.seek_pos & 0xFF);
00147 }
00148
00149
00150 if (!(i2c_start_w(EEPROM_ADDR(dev_addr))
00151 && i2c_send(addr_buf, addr_len)
00152 && i2c_send(buf, count)))
00153 {
00154 i2c_stop();
00155 return wr_len;
00156 }
00157
00158 i2c_stop();
00159
00160
00161 size -= count;
00162 fd->fd.seek_pos += count;
00163 buf = ((const char *)buf) + count;
00164 wr_len += count;
00165 }
00166
00167 return wr_len;
00168 }
00169
00176 static size_t eeprom_writeVerify(struct KFile *_fd, const void *_buf, size_t size)
00177 {
00178 Eeprom *fd = EEPROM_CAST(_fd);
00179 int retries = 5;
00180 size_t wr_len;
00181
00182 while (retries--)
00183 {
00184 wr_len = eeprom_writeRaw(_fd, _buf, size);
00185
00186 kfile_seek(_fd, -(kfile_off_t)wr_len, KSM_SEEK_CUR);
00187 if (wr_len == size
00188 && eeprom_verify(fd, _buf, wr_len))
00189 {
00190
00191 kfile_seek(_fd, wr_len, KSM_SEEK_CUR);
00192 return wr_len;
00193 }
00194 }
00195 return wr_len;
00196 }
00197
00198
00205 static size_t eeprom_read(struct KFile *_fd, void *_buf, size_t size)
00206 {
00207 Eeprom *fd = EEPROM_CAST(_fd);
00208 uint8_t addr_buf[2];
00209 uint8_t addr_len;
00210 size_t rd_len = 0;
00211 uint8_t *buf = (uint8_t *)_buf;
00212
00213 STATIC_ASSERT(countof(addr_buf) <= sizeof(e2addr_t));
00214
00215
00216 ASSERT(_fd->seek_pos + size <= (kfile_off_t)_fd->size);
00217 size = MIN((kfile_off_t)size, _fd->size - _fd->seek_pos);
00218
00219 e2dev_addr_t dev_addr;
00220 if (mem_info[fd->type].has_dev_addr)
00221 {
00222 dev_addr = fd->addr;
00223 addr_len = 2;
00224 addr_buf[0] = (fd->fd.seek_pos >> 8) & 0xFF;
00225 addr_buf[1] = (fd->fd.seek_pos & 0xFF);
00226 }
00227 else
00228 {
00229 dev_addr = (e2dev_addr_t)((fd->fd.seek_pos >> 8) & 0x07);
00230 addr_len = 1;
00231 addr_buf[0] = (fd->fd.seek_pos & 0xFF);
00232 }
00233
00234
00235 if (!(i2c_start_w(EEPROM_ADDR(dev_addr))
00236 && i2c_send(addr_buf, addr_len)
00237 && i2c_start_r(EEPROM_ADDR(dev_addr))))
00238 {
00239 i2c_stop();
00240 return 0;
00241 }
00242
00243 while (size--)
00244 {
00245
00246
00247
00248
00249 int c = i2c_get(size);
00250
00251 if (c == EOF)
00252 break;
00253
00254 *buf++ = c;
00255 fd->fd.seek_pos++;
00256 rd_len++;
00257 }
00258
00259 return rd_len;
00260 }
00261
00269 bool eeprom_verify(Eeprom *fd, const void *buf, size_t count)
00270 {
00271 uint8_t verify_buf[16];
00272 bool result = true;
00273
00274
00275 kfile_off_t prev_seek = fd->fd.seek_pos;
00276
00277 while (count && result)
00278 {
00279
00280 size_t size = MIN(count, sizeof verify_buf);
00281
00282
00283 if (eeprom_read(&fd->fd, verify_buf, size))
00284 {
00285 if (memcmp(buf, verify_buf, size) != 0)
00286 {
00287 TRACEMSG("Data mismatch!");
00288 result = false;
00289 }
00290 }
00291 else
00292 {
00293 TRACEMSG("Read error!");
00294 result = false;
00295 }
00296
00297
00298 count -= size;
00299 buf = ((const char *)buf) + size;
00300 }
00301
00302
00303 fd->fd.seek_pos = prev_seek;
00304 return result;
00305 }
00306
00315 bool eeprom_erase(Eeprom *fd, e2addr_t addr, e2_size_t count)
00316 {
00317 e2blk_size_t blk_size = mem_info[fd->type].blk_size;
00318 uint8_t buf[blk_size];
00319 kfile_off_t prev_off = fd->fd.seek_pos;
00320 bool res = true;
00321 size_t size;
00322
00323 memset(buf, 0xFF, blk_size);
00324
00325
00326 kfile_seek(&fd->fd, addr, KSM_SEEK_SET);
00327
00328
00329
00330
00331
00332
00333 wdt_reset();
00334 size = MIN(count, (e2_size_t)(blk_size - (addr & (blk_size - 1))));
00335 if (kfile_write(&fd->fd, buf, size) != size)
00336 {
00337 fd->fd.seek_pos = prev_off;
00338 return false;
00339 }
00340 count -= size;
00341
00342
00343 while (count)
00344 {
00345
00346 wdt_reset();
00347
00348 size = MIN(count, (e2_size_t)sizeof buf);
00349 if (kfile_write(&fd->fd, buf, size) != size)
00350 {
00351 res = false;
00352 break;
00353 }
00354
00355 count -= size;
00356 }
00357 fd->fd.seek_pos = prev_off;
00358 return res;
00359 }
00360
00361
00369 void eeprom_init(Eeprom *fd, EepromType type, e2dev_addr_t addr, bool verify)
00370 {
00371 MOD_CHECK(i2c);
00372 ASSERT(type < EEPROM_CNT);
00373
00374 memset(fd, 0, sizeof(*fd));
00375 DB(fd->fd._type = KFT_EEPROM);
00376
00377 fd->type = type;
00378 fd->addr = addr;
00379 fd->fd.size = mem_info[fd->type].e2_size;
00380
00381
00382 fd->fd.read = eeprom_read;
00383 if (verify)
00384 fd->fd.write = eeprom_writeVerify;
00385 else
00386 fd->fd.write = eeprom_writeRaw;
00387 fd->fd.close = kfile_genericClose;
00388
00389 fd->fd.seek = kfile_genericSeek;
00390 }
00391
00392 #endif