00001
00039 #include "eeprom.h"
00040
00041 #include <cfg/macros.h>
00042 #include <cfg/debug.h>
00043 #include <cfg/module.h>
00044
00045 #include <cpu/attr.h>
00046 #include <drv/i2c.h>
00047
00048 #include <drv/wdt.h>
00049
00050 #include <cpu/byteorder.h>
00051
00052 #include <string.h>
00053
00057 #define EEPROM_ID 0xA0
00058
00062 #define EEPROM_ADDR(x) (EEPROM_ID | (((uint8_t)((x) & 0x07)) << 1))
00063
00064
00068 static const EepromInfo mem_info[] =
00069 {
00070 {
00071
00072 .has_dev_addr = false,
00073 .blk_size = 0x10,
00074 .e2_size = 0x400,
00075 },
00076 {
00077
00078 .has_dev_addr = false,
00079 .blk_size = 0x10,
00080 .e2_size = 0x800,
00081 },
00082 {
00083
00084 .has_dev_addr = true,
00085 .blk_size = 0x40,
00086 .e2_size = 0x8000,
00087 },
00088 {
00089
00090 .has_dev_addr = true,
00091 .blk_size = 0x80,
00092 .e2_size = 0x10000,
00093 },
00094 {
00095
00096 .has_dev_addr = true,
00097 .blk_size = 0x100,
00098 .e2_size = 0x20000,
00099 },
00100
00101
00102 };
00103
00104 STATIC_ASSERT(countof(mem_info) == EEPROM_CNT);
00105
00106
00111 static size_t eeprom_writeRaw(struct KFile *_fd, const void *buf, size_t size)
00112 {
00113 Eeprom *fd = EEPROM_CAST(_fd);
00114 e2dev_addr_t dev_addr;
00115 uint8_t addr_buf[2];
00116 uint8_t addr_len;
00117 size_t wr_len = 0;
00118
00119 e2blk_size_t blk_size = mem_info[fd->type].blk_size;
00120
00121 STATIC_ASSERT(countof(addr_buf) <= sizeof(e2addr_t));
00122
00123
00124 ASSERT(_fd->seek_pos + (kfile_off_t)size <= (kfile_off_t)_fd->size);
00125 size = MIN((kfile_off_t)size, _fd->size - _fd->seek_pos);
00126
00127 if (mem_info[fd->type].has_dev_addr)
00128 {
00129 dev_addr = fd->addr;
00130 addr_len = 2;
00131 }
00132 else
00133 {
00134 dev_addr = (e2dev_addr_t)((fd->fd.seek_pos >> 8) & 0x07);
00135 addr_len = 1;
00136 }
00137
00138 while (size)
00139 {
00140
00141
00142
00143
00144 size_t count = MIN(size, (size_t)(blk_size - (fd->fd.seek_pos & (blk_size - 1))));
00145
00146 if (mem_info[fd->type].has_dev_addr)
00147 {
00148 addr_buf[0] = (fd->fd.seek_pos >> 8) & 0xFF;
00149 addr_buf[1] = (fd->fd.seek_pos & 0xFF);
00150 }
00151 else
00152 {
00153 dev_addr = (e2dev_addr_t)((fd->fd.seek_pos >> 8) & 0x07);
00154 addr_buf[0] = (fd->fd.seek_pos & 0xFF);
00155 }
00156
00157
00158 if (!(i2c_start_w(EEPROM_ADDR(dev_addr))
00159 && i2c_send(addr_buf, addr_len)
00160 && i2c_send(buf, count)))
00161 {
00162 i2c_stop();
00163 return wr_len;
00164 }
00165
00166 i2c_stop();
00167
00168
00169 size -= count;
00170 fd->fd.seek_pos += count;
00171 buf = ((const char *)buf) + count;
00172 wr_len += count;
00173 }
00174
00175 return wr_len;
00176 }
00177
00184 static size_t eeprom_writeVerify(struct KFile *_fd, const void *_buf, size_t size)
00185 {
00186 Eeprom *fd = EEPROM_CAST(_fd);
00187 int retries = 5;
00188 size_t wr_len = 0;
00189
00190 while (retries--)
00191 {
00192 wr_len = eeprom_writeRaw(_fd, _buf, size);
00193
00194 kfile_seek(_fd, -(kfile_off_t)wr_len, KSM_SEEK_CUR);
00195 if (wr_len == size
00196 && eeprom_verify(fd, _buf, wr_len))
00197 {
00198
00199 kfile_seek(_fd, wr_len, KSM_SEEK_CUR);
00200 return wr_len;
00201 }
00202 }
00203 return wr_len;
00204 }
00205
00206
00213 static size_t eeprom_read(struct KFile *_fd, void *_buf, size_t size)
00214 {
00215 Eeprom *fd = EEPROM_CAST(_fd);
00216 uint8_t addr_buf[2];
00217 uint8_t addr_len;
00218 size_t rd_len = 0;
00219 uint8_t *buf = (uint8_t *)_buf;
00220
00221 STATIC_ASSERT(countof(addr_buf) <= sizeof(e2addr_t));
00222
00223
00224 ASSERT(_fd->seek_pos + (kfile_off_t)size <= (kfile_off_t)_fd->size);
00225 size = MIN((kfile_off_t)size, _fd->size - _fd->seek_pos);
00226
00227 e2dev_addr_t dev_addr;
00228 if (mem_info[fd->type].has_dev_addr)
00229 {
00230 dev_addr = fd->addr;
00231 addr_len = 2;
00232 addr_buf[0] = (fd->fd.seek_pos >> 8) & 0xFF;
00233 addr_buf[1] = (fd->fd.seek_pos & 0xFF);
00234 }
00235 else
00236 {
00237 dev_addr = (e2dev_addr_t)((fd->fd.seek_pos >> 8) & 0x07);
00238 addr_len = 1;
00239 addr_buf[0] = (fd->fd.seek_pos & 0xFF);
00240 }
00241
00242
00243 if (!(i2c_start_w(EEPROM_ADDR(dev_addr))
00244 && i2c_send(addr_buf, addr_len)
00245 && i2c_start_r(EEPROM_ADDR(dev_addr))))
00246 {
00247 i2c_stop();
00248 return 0;
00249 }
00250
00251 while (size--)
00252 {
00253
00254
00255
00256
00257 int c = i2c_get(size);
00258
00259 if (c == EOF)
00260 break;
00261
00262 *buf++ = c;
00263 fd->fd.seek_pos++;
00264 rd_len++;
00265 }
00266
00267 i2c_stop();
00268 return rd_len;
00269 }
00270
00278 bool eeprom_verify(Eeprom *fd, const void *buf, size_t count)
00279 {
00280 uint8_t verify_buf[16];
00281 bool result = true;
00282
00283
00284 kfile_off_t prev_seek = fd->fd.seek_pos;
00285
00286 while (count && result)
00287 {
00288
00289 size_t size = MIN(count, sizeof verify_buf);
00290
00291
00292 if (eeprom_read(&fd->fd, verify_buf, size))
00293 {
00294 if (memcmp(buf, verify_buf, size) != 0)
00295 {
00296 TRACEMSG("Data mismatch!");
00297 result = false;
00298 }
00299 }
00300 else
00301 {
00302 TRACEMSG("Read error!");
00303 result = false;
00304 }
00305
00306
00307 count -= size;
00308 buf = ((const char *)buf) + size;
00309 }
00310
00311
00312 fd->fd.seek_pos = prev_seek;
00313 return result;
00314 }
00315
00324 bool eeprom_erase(Eeprom *fd, e2addr_t addr, e2_size_t count)
00325 {
00326 e2blk_size_t blk_size = mem_info[fd->type].blk_size;
00327 uint8_t buf[blk_size];
00328 kfile_off_t prev_off = fd->fd.seek_pos;
00329 bool res = true;
00330 size_t size;
00331
00332 memset(buf, 0xFF, blk_size);
00333
00334
00335 kfile_seek(&fd->fd, addr, KSM_SEEK_SET);
00336
00337
00338
00339
00340
00341
00342 wdt_reset();
00343 size = MIN(count, (e2_size_t)(blk_size - (addr & (blk_size - 1))));
00344 if (kfile_write(&fd->fd, buf, size) != size)
00345 {
00346 fd->fd.seek_pos = prev_off;
00347 return false;
00348 }
00349 count -= size;
00350
00351
00352 while (count)
00353 {
00354
00355 wdt_reset();
00356
00357 size = MIN(count, (e2_size_t)sizeof buf);
00358 if (kfile_write(&fd->fd, buf, size) != size)
00359 {
00360 res = false;
00361 break;
00362 }
00363
00364 count -= size;
00365 }
00366 fd->fd.seek_pos = prev_off;
00367 return res;
00368 }
00369
00370
00378 void eeprom_init(Eeprom *fd, EepromType type, e2dev_addr_t addr, bool verify)
00379 {
00380 MOD_CHECK(i2c);
00381 ASSERT(type < EEPROM_CNT);
00382
00383 memset(fd, 0, sizeof(*fd));
00384 DB(fd->fd._type = KFT_EEPROM);
00385
00386 fd->type = type;
00387 fd->addr = addr;
00388 fd->fd.size = mem_info[fd->type].e2_size;
00389
00390
00391 fd->fd.read = eeprom_read;
00392 if (verify)
00393 fd->fd.write = eeprom_writeVerify;
00394 else
00395 fd->fd.write = eeprom_writeRaw;
00396 fd->fd.close = kfile_genericClose;
00397
00398 fd->fd.seek = kfile_genericSeek;
00399 }