00001
00039 #include "eeprom.h"
00040
00041 #include "cfg/cfg_i2c.h"
00042 #include "cfg/cfg_eeprom.h"
00043
00044
00045 #define LOG_LEVEL EEPROM_LOG_LEVEL
00046 #define LOG_FORMAT EEPROM_LOG_FORMAT
00047 #include <cfg/log.h>
00048 #include <cfg/debug.h>
00049 #include <cfg/macros.h>
00050
00051 #include <cpu/attr.h>
00052
00053 #include <drv/i2c.h>
00054
00055 #include <string.h>
00056
00060 #define EEPROM_ID 0xA0
00061
00065 #define EEPROM_ADDR(x) (EEPROM_ID | (((uint8_t)((x) & 0x07)) << 1))
00066
00067
00071 static const EepromInfo mem_info[] =
00072 {
00073 {
00074
00075 .has_dev_addr = false,
00076 .blk_size = 0x10,
00077 .e2_size = 0x400,
00078 },
00079 {
00080
00081 .has_dev_addr = false,
00082 .blk_size = 0x10,
00083 .e2_size = 0x800,
00084 },
00085 {
00086
00087 .has_dev_addr = true,
00088 .blk_size = 0x40,
00089 .e2_size = 0x8000,
00090 },
00091 {
00092
00093 .has_dev_addr = true,
00094 .blk_size = 0x80,
00095 .e2_size = 0x10000,
00096 },
00097 {
00098
00099 .has_dev_addr = true,
00100 .blk_size = 0x100,
00101 .e2_size = 0x20000,
00102 },
00103
00104
00105 };
00106
00107 STATIC_ASSERT(countof(mem_info) == EEPROM_CNT);
00108
00109 #define CHUNCK_SIZE 16
00110
00117 bool eeprom_erase(Eeprom *eep, e2addr_t addr, e2_size_t size)
00118 {
00119 uint8_t tmp[CHUNCK_SIZE] = { [0 ... (CHUNCK_SIZE - 1)] = 0xFF };
00120
00121 while (size)
00122 {
00123 block_idx_t idx = addr / eep->blk.blk_size;
00124 size_t offset = addr % eep->blk.blk_size;
00125 size_t count = MIN(size, (e2_size_t)CHUNCK_SIZE);
00126 size_t ret_len = eep->blk.priv.vt->writeDirect((KBlock *)eep, idx, tmp, offset, count);
00127 size -= ret_len;
00128 addr += ret_len;
00129
00130 if (ret_len != count)
00131 return false;
00132 }
00133 return true;
00134 }
00135
00143 bool eeprom_verify(Eeprom *eep, e2addr_t addr, const void *buf, size_t size)
00144 {
00145 uint8_t verify_buf[CHUNCK_SIZE];
00146 while (size)
00147 {
00148 block_idx_t idx = addr / eep->blk.blk_size;
00149 size_t offset = addr % eep->blk.blk_size;
00150 size_t count = MIN(size, (size_t)CHUNCK_SIZE);
00151
00152 size_t ret_len = eep->blk.priv.vt->readDirect((KBlock *)eep, idx, verify_buf, offset, count);
00153
00154 if (ret_len != count)
00155 {
00156 LOG_ERR("Verify read fail.\n");
00157 return false;
00158 }
00159
00160 if (memcmp(buf, verify_buf, ret_len) != 0)
00161 {
00162 LOG_ERR("Data mismatch!\n");
00163 return false;
00164 }
00165
00166 size -= ret_len;
00167 addr += ret_len;
00168 buf = ((const char *)buf) + ret_len;
00169 }
00170 return true;
00171 }
00172
00173
00174 static size_t eeprom_write(KBlock *blk, block_idx_t idx, const void *buf, size_t offset, size_t size)
00175 {
00176 Eeprom *eep = EEPROM_CAST_KBLOCK(blk);
00177 e2dev_addr_t dev_addr;
00178 uint8_t addr_buf[2];
00179 uint8_t addr_len;
00180 uint32_t abs_addr = blk->blk_size * idx + offset;
00181
00182 STATIC_ASSERT(countof(addr_buf) <= sizeof(e2addr_t));
00183
00184
00185 ASSERT(idx < blk->priv.blk_start + blk->blk_cnt);
00186 size = MIN(size, blk->blk_size - offset);
00187
00188 if (mem_info[eep->type].has_dev_addr)
00189 {
00190 dev_addr = eep->addr;
00191 addr_len = 2;
00192 }
00193 else
00194 {
00195 dev_addr = (e2dev_addr_t)((abs_addr >> 8) & 0x07);
00196 addr_len = 1;
00197 }
00198
00199 if (mem_info[eep->type].has_dev_addr)
00200 {
00201 addr_buf[0] = (abs_addr >> 8) & 0xFF;
00202 addr_buf[1] = (abs_addr & 0xFF);
00203 }
00204 else
00205 {
00206 dev_addr = (e2dev_addr_t)((abs_addr >> 8) & 0x07);
00207 addr_buf[0] = (abs_addr & 0xFF);
00208 }
00209
00210 i2c_start_w(eep->i2c, EEPROM_ADDR(dev_addr), addr_len + size, I2C_STOP);
00211 i2c_write(eep->i2c, addr_buf, addr_len);
00212 i2c_write(eep->i2c, buf, size);
00213
00214 if (i2c_error(eep->i2c))
00215 return 0;
00216
00217 return size;
00218 }
00219
00220 static size_t eeprom_readDirect(struct KBlock *_blk, block_idx_t idx, void *_buf, size_t offset, size_t size)
00221 {
00222 Eeprom *blk = EEPROM_CAST_KBLOCK(_blk);
00223 uint8_t addr_buf[2];
00224 uint8_t addr_len;
00225 size_t rd_len = 0;
00226 uint8_t *buf = (uint8_t *)_buf;
00227 uint32_t abs_addr = mem_info[blk->type].blk_size * idx + offset;
00228
00229 STATIC_ASSERT(countof(addr_buf) <= sizeof(e2addr_t));
00230
00231
00232 ASSERT(idx < blk->blk.priv.blk_start + blk->blk.blk_cnt);
00233 size = MIN(size, blk->blk.blk_size - offset);
00234
00235 e2dev_addr_t dev_addr;
00236 if (mem_info[blk->type].has_dev_addr)
00237 {
00238 dev_addr = blk->addr;
00239 addr_len = 2;
00240 addr_buf[0] = (abs_addr >> 8) & 0xFF;
00241 addr_buf[1] = (abs_addr & 0xFF);
00242 }
00243 else
00244 {
00245 dev_addr = (e2dev_addr_t)((abs_addr >> 8) & 0x07);
00246 addr_len = 1;
00247 addr_buf[0] = (abs_addr & 0xFF);
00248 }
00249
00250
00251 i2c_start_w(blk->i2c, EEPROM_ADDR(dev_addr), addr_len, I2C_NOSTOP);
00252 i2c_write(blk->i2c, addr_buf, addr_len);
00253
00254 i2c_start_r(blk->i2c, EEPROM_ADDR(dev_addr), size, I2C_STOP);
00255 i2c_read(blk->i2c, buf, size);
00256
00257 if (i2c_error(blk->i2c))
00258 return rd_len;
00259
00260 rd_len += size;
00261
00262 return rd_len;
00263 }
00264
00265 static size_t eeprom_writeDirect(KBlock *blk, block_idx_t idx, const void *buf, size_t offset, size_t size)
00266 {
00267 Eeprom *eep = EEPROM_CAST_KBLOCK(blk);
00268 if (!eep->verify)
00269 return eeprom_write(blk, idx, buf, offset, size);
00270 else
00271 {
00272 int retries = 5;
00273 while (retries--)
00274 {
00275 uint8_t verify_buf[CHUNCK_SIZE];
00276 size_t wr_len = 0;
00277 size_t len = 0;
00278 while (size)
00279 {
00280
00281 size_t count = MIN(size, (size_t)CHUNCK_SIZE);
00282 if ((wr_len = eeprom_write(blk, idx, buf, offset, count)) != 0)
00283 {
00284 if (eeprom_readDirect(blk, idx, verify_buf, offset, count) != wr_len)
00285 {
00286 LOG_ERR("Verify read fail.\n");
00287 return 0;
00288 }
00289 else if (memcmp(buf, verify_buf, wr_len) != 0)
00290 {
00291 LOG_ERR("Data mismatch!\n");
00292 continue;
00293 }
00294 }
00295 else
00296 {
00297 LOG_ERR("Write fail.\n");
00298 return 0;
00299 }
00300 size -= wr_len;
00301 len += wr_len;
00302 buf = ((const char *)buf) + wr_len;
00303 }
00304 return len;
00305 }
00306 }
00307
00308 return 0;
00309 }
00310
00311 static int kblockEeprom_dummy(UNUSED_ARG(struct KBlock *,b))
00312 {
00313 return 0;
00314 }
00315
00316
00317 static const KBlockVTable eeprom_unbuffered_vt =
00318 {
00319 .readDirect = eeprom_readDirect,
00320 .writeDirect = eeprom_writeDirect,
00321
00322 .error = kblockEeprom_dummy,
00323 .clearerr = (kblock_clearerr_t)kblockEeprom_dummy,
00324 };
00325
00334 void eeprom_init_5(Eeprom *eep, I2c *i2c, EepromType type, e2dev_addr_t addr, bool verify)
00335 {
00336 ASSERT(type < EEPROM_CNT);
00337
00338 memset(eep, 0, sizeof(*eep));
00339 DB(eep->blk.priv.type = KBT_EEPROM);
00340
00341 eep->type = type;
00342 eep->addr = addr;
00343 eep->i2c = i2c;
00344 eep->verify = verify;
00345
00346 eep->blk.blk_size = mem_info[type].blk_size;
00347 eep->blk.blk_cnt = mem_info[type].e2_size / mem_info[type].blk_size;
00348 eep->blk.priv.flags |= KB_PARTIAL_WRITE;
00349 eep->blk.priv.vt = &eeprom_unbuffered_vt;
00350 }
00351
00352