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"
43 #include <cfg/macros.h> // MIN()
44 #include <cfg/debug.h>
45 #include <cfg/module.h> // MOD_CHECK()
52 #include <cpu/byteorder.h> // cpu_to_be16()
54 #include <string.h> // memset()
59 #define EEPROM_ID 0xA0
62 * This macros form the correct slave address for EEPROMs
64 #define EEPROM_ADDR(x) (EEPROM_ID | (((uint8_t)((x) & 0x07)) << 1))
68 * Array used to describe EEPROM memory devices currently supported.
70 static const EepromInfo mem_info[] =
74 .has_dev_addr = false,
80 .has_dev_addr = false,
103 /* Add other memories here */
106 STATIC_ASSERT(countof(mem_info) == EEPROM_CNT);
109 * Check that the contents of an EEPROM range
110 * match with a provided data buffer.
112 * \return true on success.
113 * \note Seek position of \a fd will not change.
115 bool eeprom_verify(Eeprom *fd, const void *buf, size_t count)
117 uint8_t verify_buf[16];
120 /* Save seek position */
121 kfile_off_t prev_seek = fd->fd.seek_pos;
123 while (count && result)
125 /* Split read in smaller pieces */
126 size_t size = MIN(count, sizeof verify_buf);
128 /* Read back buffer */
129 if (eeprom_read(&fd->fd, verify_buf, size))
131 if (memcmp(buf, verify_buf, size) != 0)
133 TRACEMSG("Data mismatch!");
139 TRACEMSG("Read error!");
143 /* Update count and addr for next operation */
145 buf = ((const char *)buf) + size;
148 /* Restore previous seek position */
149 fd->fd.seek_pos = prev_seek;
154 * Erase specified part of eeprom, writing 0xFF.
156 * \a addr starting address
157 * \a count length of block to erase
158 * \note Seek position is unchanged.
159 * \return true if ok, false otherwise.
161 bool eeprom_erase(Eeprom *fd, e2addr_t addr, e2_size_t count)
163 e2blk_size_t blk_size = mem_info[fd->type].blk_size;
164 uint8_t buf[blk_size];
165 kfile_off_t prev_off = fd->fd.seek_pos;
169 memset(buf, 0xFF, blk_size);
172 kfile_seek(&fd->fd, addr, KSM_SEEK_SET);
175 * Optimization: this first write id used to realign
176 * current address to block boundaries.
180 size = MIN(count, (e2_size_t)(blk_size - (addr & (blk_size - 1))));
181 if (kfile_write(&fd->fd, buf, size) != size)
183 fd->fd.seek_pos = prev_off;
191 /* Long operation, reset watchdog */
194 size = MIN(count, (e2_size_t)sizeof buf);
195 if (kfile_write(&fd->fd, buf, size) != size)
203 fd->fd.seek_pos = prev_off;
209 * Initialize EEPROM module.
210 * \a fd is the Kfile context.
211 * \a type is the eeprom device we want to initialize (\see EepromType)
212 * \a addr is the i2c devide address (usually pins A0, A1, A2).
213 * \a verify is true if you want that every write operation will be verified.
215 void eeprom_init(Eeprom *fd, EepromType type, e2dev_addr_t addr, bool verify)
218 ASSERT(type < EEPROM_CNT);
220 memset(fd, 0, sizeof(*fd));
221 DB(fd->fd._type = KFT_EEPROM);
225 fd->fd.size = mem_info[fd->type].e2_size;
227 // Setup eeprom programming functions.
228 fd->fd.read = eeprom_read;
230 fd->fd.write = eeprom_writeVerify;
232 fd->fd.write = eeprom_writeRaw;
233 fd->fd.close = kfile_genericClose;
235 fd->fd.seek = kfile_genericSeek;
239 static size_t eeprom_writeDirect(KBlock *blk, block_idx_t idx, const void *buf, size_t offset, size_t size)
241 Eeprom *fd = EEPROM_CAST_KBLOCK(blk);
242 e2dev_addr_t dev_addr;
245 uint32_t abs_addr = blk->blk_size * idx + offset;
247 STATIC_ASSERT(countof(addr_buf) <= sizeof(e2addr_t));
250 /* clamp size to memory limit (otherwise may roll back) */
251 ASSERT(idx <= blk->blk_cnt);
252 size = MIN(size, blk->blk_size - offset);
254 if (mem_info[fd->type].has_dev_addr)
261 dev_addr = (e2dev_addr_t)((abs_addr >> 8) & 0x07);
265 if (mem_info[fd->type].has_dev_addr)
267 addr_buf[0] = (abs_addr >> 8) & 0xFF;
268 addr_buf[1] = (abs_addr & 0xFF);
272 dev_addr = (e2dev_addr_t)((abs_addr >> 8) & 0x07);
273 addr_buf[0] = (abs_addr & 0xFF);
276 i2c_start_w(fd->i2c, EEPROM_ADDR(dev_addr), addr_len + size, I2C_STOP);
277 i2c_write(fd->i2c, addr_buf, addr_len);
278 i2c_write(fd->i2c, buf, size);
280 if (i2c_error(fd->i2c))
287 static size_t eeprom_readDirect(struct KBlock *_blk, block_idx_t idx, void *_buf, size_t offset, size_t size)
289 Eeprom *blk = EEPROM_CAST_KBLOCK(_blk);
293 uint8_t *buf = (uint8_t *)_buf;
294 uint32_t abs_addr = mem_info[blk->type].blk_size * idx + offset;
296 STATIC_ASSERT(countof(addr_buf) <= sizeof(e2addr_t));
298 /* clamp size to memory limit (otherwise may roll back) */
299 ASSERT(idx <= blk->blk.blk_cnt);
300 size = MIN(size, blk->blk.blk_size - offset);
302 e2dev_addr_t dev_addr;
303 if (mem_info[blk->type].has_dev_addr)
305 dev_addr = blk->addr;
307 addr_buf[0] = (abs_addr >> 8) & 0xFF;
308 addr_buf[1] = (abs_addr & 0xFF);
312 dev_addr = (e2dev_addr_t)((abs_addr >> 8) & 0x07);
314 addr_buf[0] = (abs_addr & 0xFF);
318 i2c_start_w(blk->i2c, EEPROM_ADDR(dev_addr), addr_len, I2C_NOSTOP);
319 i2c_write(blk->i2c, addr_buf, addr_len);
321 i2c_start_r(blk->i2c, EEPROM_ADDR(dev_addr), size, I2C_STOP);
322 i2c_read(blk->i2c, buf, size);
324 if (i2c_error(blk->i2c))
332 static int kblockEeprom_dummy(UNUSED_ARG(struct KBlock *,b))
338 static const KBlockVTable eeprom_unbuffered_vt =
340 .readDirect = eeprom_readDirect,
341 .writeDirect = eeprom_writeDirect,
343 .error = kblockEeprom_dummy,
344 .clearerr = (kblock_clearerr_t)kblockEeprom_dummy,
348 * Initialize EEPROM module.
349 * \param b is the Kblock context.
350 * \param type is the eeprom device we want to initialize (\see EepromType)
351 * \param i2c context for i2c channel
352 * \param addr is the i2c devide address (usually pins A0, A1, A2).
354 void eeprom_init_5(Eeprom *blk, I2c *i2c, EepromType type, e2dev_addr_t addr, bool verify)
356 ASSERT(type < EEPROM_CNT);
358 memset(blk, 0, sizeof(*blk));
359 DB(blk->blk.priv.type = KBT_EEPROM);
365 blk->blk.blk_size = mem_info[type].blk_size;
366 blk->blk.blk_cnt = mem_info[type].e2_size / mem_info[type].blk_size;
367 blk->blk.priv.flags |= KB_PARTIAL_WRITE;
368 blk->blk.priv.vt = &eeprom_unbuffered_vt;