4 * This file is part of BeRTOS.
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.
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.
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
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.
29 * Copyright 2003, 2004, 2005, 2010 Develer S.r.l. (http://www.develer.com/)
33 * \brief Driver for the 24xx16 and 24xx256 I2C EEPROMS (implementation)
35 * \author Stefano Fedrigo <aleph@develer.com>
36 * \author Bernie Innocenti <bernie@codewiz.org>
41 #include "cfg/cfg_i2c.h"
42 #include "cfg/cfg_eeprom.h"
44 /* Define logging setting (for cfg/log.h module). */
45 #define LOG_LEVEL EEPROM_LOG_LEVEL
46 #define LOG_FORMAT EEPROM_LOG_FORMAT
48 #include <cfg/debug.h>
49 #include <cfg/macros.h> // MIN()
55 #include <string.h> // memset()
60 #define EEPROM_ID 0xA0
63 * This macros form the correct slave address for EEPROMs
65 #define EEPROM_ADDR(x) (EEPROM_ID | (((uint8_t)((x) & 0x07)) << 1))
69 * Array used to describe EEPROM memory devices currently supported.
71 static const EepromInfo mem_info[] =
75 .has_dev_addr = false,
81 .has_dev_addr = false,
105 .has_dev_addr = true,
111 .has_dev_addr = true,
117 .has_dev_addr = true,
122 /* Add other memories here */
125 STATIC_ASSERT(countof(mem_info) == EEPROM_CNT);
127 #define CHUNCK_SIZE 16
131 * \param eep is the Kblock context.
132 * \param addr eeprom address where start to erase
133 * \param size number of byte to erase
135 bool eeprom_erase(Eeprom *eep, e2addr_t addr, e2_size_t size)
137 uint8_t tmp[CHUNCK_SIZE] = { [0 ... (CHUNCK_SIZE - 1)] = 0xFF };
141 block_idx_t idx = addr / eep->blk.blk_size;
142 size_t offset = addr % eep->blk.blk_size;
143 size_t count = MIN(size, (e2_size_t)CHUNCK_SIZE);
144 size_t ret_len = eep->blk.priv.vt->writeDirect((KBlock *)eep, idx, tmp, offset, count);
148 if (ret_len != count)
156 * \param eep is the Kblock context.
157 * \param addr eeprom address where start to verify.
158 * \param buf buffer of data to compare with eeprom data read.
159 * \param size number of byte to verify.
161 bool eeprom_verify(Eeprom *eep, e2addr_t addr, const void *buf, size_t size)
163 uint8_t verify_buf[CHUNCK_SIZE];
166 block_idx_t idx = addr / eep->blk.blk_size;
167 size_t offset = addr % eep->blk.blk_size;
168 size_t count = MIN(size, (size_t)CHUNCK_SIZE);
170 size_t ret_len = eep->blk.priv.vt->readDirect((KBlock *)eep, idx, verify_buf, offset, count);
172 if (ret_len != count)
174 LOG_ERR("Verify read fail.\n");
178 if (memcmp(buf, verify_buf, ret_len) != 0)
180 LOG_ERR("Data mismatch!\n");
186 buf = ((const char *)buf) + ret_len;
192 static size_t eeprom_write(KBlock *blk, block_idx_t idx, const void *buf, size_t offset, size_t size)
194 Eeprom *eep = EEPROM_CAST_KBLOCK(blk);
195 e2dev_addr_t dev_addr;
198 uint32_t abs_addr = blk->blk_size * idx + offset;
200 STATIC_ASSERT(countof(addr_buf) <= sizeof(e2addr_t));
202 /* clamp size to memory limit (otherwise may roll back) */
203 ASSERT(idx < blk->priv.blk_start + blk->blk_cnt);
204 size = MIN(size, blk->blk_size - offset);
206 if (mem_info[eep->type].has_dev_addr)
208 dev_addr = eep->addr;
213 dev_addr = (e2dev_addr_t)((abs_addr >> 8) & 0x07);
217 if (mem_info[eep->type].has_dev_addr)
219 addr_buf[0] = (abs_addr >> 8) & 0xFF;
220 addr_buf[1] = (abs_addr & 0xFF);
224 dev_addr = (e2dev_addr_t)((abs_addr >> 8) & 0x07);
225 addr_buf[0] = (abs_addr & 0xFF);
228 i2c_start_w(eep->i2c, EEPROM_ADDR(dev_addr), addr_len + size, I2C_STOP);
229 i2c_write(eep->i2c, addr_buf, addr_len);
230 i2c_write(eep->i2c, buf, size);
232 if (i2c_error(eep->i2c))
238 static size_t eeprom_readDirect(struct KBlock *_blk, block_idx_t idx, void *_buf, size_t offset, size_t size)
240 Eeprom *blk = EEPROM_CAST_KBLOCK(_blk);
244 uint8_t *buf = (uint8_t *)_buf;
245 uint32_t abs_addr = mem_info[blk->type].blk_size * idx + offset;
247 STATIC_ASSERT(countof(addr_buf) <= sizeof(e2addr_t));
249 /* clamp size to memory limit (otherwise may roll back) */
250 ASSERT(idx < blk->blk.priv.blk_start + blk->blk.blk_cnt);
251 size = MIN(size, blk->blk.blk_size - offset);
253 e2dev_addr_t dev_addr;
254 if (mem_info[blk->type].has_dev_addr)
256 dev_addr = blk->addr;
258 addr_buf[0] = (abs_addr >> 8) & 0xFF;
259 addr_buf[1] = (abs_addr & 0xFF);
263 dev_addr = (e2dev_addr_t)((abs_addr >> 8) & 0x07);
265 addr_buf[0] = (abs_addr & 0xFF);
269 i2c_start_w(blk->i2c, EEPROM_ADDR(dev_addr), addr_len, I2C_NOSTOP);
270 i2c_write(blk->i2c, addr_buf, addr_len);
272 i2c_start_r(blk->i2c, EEPROM_ADDR(dev_addr), size, I2C_STOP);
273 i2c_read(blk->i2c, buf, size);
275 if (i2c_error(blk->i2c))
283 static size_t eeprom_writeDirect(KBlock *blk, block_idx_t idx, const void *buf, size_t offset, size_t size)
285 Eeprom *eep = EEPROM_CAST_KBLOCK(blk);
287 return eeprom_write(blk, idx, buf, offset, size);
293 uint8_t verify_buf[CHUNCK_SIZE];
298 /* Split read in smaller pieces */
299 size_t count = MIN(size, (size_t)CHUNCK_SIZE);
300 if ((wr_len = eeprom_write(blk, idx, buf, offset, count)) != 0)
302 if (eeprom_readDirect(blk, idx, verify_buf, offset, count) != wr_len)
304 LOG_ERR("Verify read fail.\n");
307 else if (memcmp(buf, verify_buf, wr_len) != 0)
309 LOG_ERR("Data mismatch!\n");
315 LOG_ERR("Write fail.\n");
320 buf = ((const char *)buf) + wr_len;
329 static int kblockEeprom_dummy(UNUSED_ARG(struct KBlock *,b))
335 static const KBlockVTable eeprom_unbuffered_vt =
337 .readDirect = eeprom_readDirect,
338 .writeDirect = eeprom_writeDirect,
340 .error = kblockEeprom_dummy,
341 .clearerr = (kblock_clearerr_t)kblockEeprom_dummy,
345 * Initialize EEPROM module.
346 * \param eep is the Kblock context.
347 * \param type is the eeprom device we want to initialize (\see EepromType)
348 * \param i2c context for i2c channel
349 * \param addr is the i2c devide address (usually pins A0, A1, A2).
350 * \param verify enable the write check.
352 void eeprom_init_5(Eeprom *eep, I2c *i2c, EepromType type, e2dev_addr_t addr, bool verify)
354 ASSERT(type < EEPROM_CNT);
356 memset(eep, 0, sizeof(*eep));
357 DB(eep->blk.priv.type = KBT_EEPROM);
362 eep->verify = verify;
364 eep->blk.blk_size = mem_info[type].blk_size;
365 eep->blk.blk_cnt = mem_info[type].e2_size / mem_info[type].blk_size;
366 eep->blk.priv.flags |= KB_PARTIAL_WRITE;
367 eep->blk.priv.vt = &eeprom_unbuffered_vt;