Fix type warning.
[bertos.git] / bertos / drv / flash25.c
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
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.
10  *
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.
15  *
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
19  *
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.
28  *
29  * Copyright 2007 Develer S.r.l. (http://www.develer.com/)
30  *
31  * -->
32  *
33  *  \brief Function library for serial Flash memory.
34  *
35  * Module provide a kfile interface, that ensure an abstraction
36  * from comunication channel and give a standard interface.
37  * Typicaly this kind of memory use an SPI bus, but you should
38  * use another comunication channel you have defined.
39  *
40  * \version $Id$
41  * \author Daniele Basile <asterix@develer.com>
42  */
43
44 /*
45  * We use a spi bus, thus include hardware specific definition.
46  * If you use another channel you must redefine this macros.
47  */
48 #include "hw/hw_spi.h"
49
50 #include <cfg/macros.h>
51 #include <cfg/debug.h>
52
53 #include <drv/timer.h>
54 #include <drv/flash25.h>
55
56 #include <kern/kfile.h>
57
58 #if CONFIG_KERNEL
59 #include <kern/proc.h>
60 #endif
61
62 #warning FIXME:This file was change, but is untest!
63
64 /**
65  * Wait until flash memory is ready.
66  */
67 static void flash25_waitReady(KFileFlash25 *fd)
68 {
69         uint8_t stat;
70
71         while (1)
72         {
73                 CS_ENABLE();
74
75                 kfile_putc(FLASH25_RDSR, fd->channel);
76                 stat = kfile_getc(fd->channel);
77
78                 CS_DISABLE();
79
80                 if (!(stat & RDY_BIT))
81                         break;
82                 #if CONFIG_KERNEL
83                 else
84                         proc_switch();
85                 #endif
86         }
87 }
88
89 /**
90  * Send a single command to serial flash memory.
91  */
92 static void flash25_sendCmd(KFileFlash25 *fd, Flash25Opcode cmd)
93 {
94         CS_ENABLE();
95
96         kfile_putc(cmd, fd->channel);
97
98         CS_DISABLE();
99 }
100
101 /**
102  * flash25 init function.
103  * This function init a comunication channel and
104  * try to read manufacturer id of serial memory,
105  * then check if is equal to selected type.
106  */
107 static bool flash25_pin_init(KFileFlash25 *fd)
108 {
109         uint8_t device_id;
110         uint8_t manufacturer;
111
112         SPI_HW_INIT();
113
114         CS_ENABLE();
115         /*
116          * Send read id productor opcode on
117          * comunication channel
118          * TODO:controllare se ha senso
119          */
120         kfile_putc(FLASH25_RDID, fd->channel);
121
122         manufacturer = kfile_getc(fd->channel);
123         device_id = kfile_getc(fd->channel);
124
125         CS_DISABLE();
126
127         if((FLASH25_MANUFACTURER_ID == manufacturer) &&
128                 (FLASH25_DEVICE_ID == device_id))
129                 return true;
130         else
131                 return false;
132 }
133
134 /**
135  * Reopen a serial memory interface.
136  *
137  * For serial memory this function reinit only
138  * the size and seek_pos in kfile stucture.
139  * Return a kfile pointer, after assert check.
140  */
141 static KFile * flash25_reopen(struct KFile *_fd)
142 {
143         KFileFlash25 *fd = KFILEFLASH25(_fd);
144
145         fd->fd.seek_pos = 0;
146         fd->fd.size = FLASH25_MEM_SIZE;
147
148         kprintf("flash25 file opened\n");
149         return &fd->fd;
150 }
151
152 /**
153  * Close a serial memory interface.
154  *
155  * For serial memory this funtion do nothing,
156  * and return always 0.
157  */
158 static int flash25_close(UNUSED_ARG(struct KFile *,fd))
159 {
160         kprintf("flash25 file closed\n");
161         return 0;
162 }
163
164 /**
165  * Read \a _buf lenght \a size byte from serial flash memmory.
166  *
167  * For read in serial flash memory we
168  * enble cs pin and send one byte of read opcode,
169  * and then 3 byte of address of memory cell we
170  * want to read. After the last byte of address we
171  * can read data from so pin.
172  *
173  * \return the number of bytes read.
174  */
175 static size_t flash25_read(struct KFile *_fd, void *buf, size_t size)
176 {
177         uint8_t *data = (uint8_t *)buf;
178
179         KFileFlash25 *fd = KFILEFLASH25(_fd);
180
181         ASSERT(fd->fd.seek_pos + (kfile_size_t)size <= fd->fd.size);
182         size = MIN((kfile_size_t)size, fd->fd.size - fd->fd.seek_pos);
183
184         //kprintf("Reading at addr[%lu], size[%d]\n", fd->seek_pos, size);
185         CS_ENABLE();
186
187         kfile_putc(FLASH25_READ, fd->channel);
188
189
190         /*
191          * Address that we want to read.
192          */
193         kfile_putc((fd->fd.seek_pos >> 16) & 0xFF, fd->channel);
194         kfile_putc((fd->fd.seek_pos >> 8) & 0xFF, fd->channel);
195         kfile_putc(fd->fd.seek_pos & 0xFF, fd->channel);
196
197         kfile_read(fd->channel, data, size);
198
199         CS_DISABLE();
200
201         fd->fd.seek_pos += size;
202
203         return size;
204 }
205
206 /**
207  * Write \a _buf in serial flash memory
208  *
209  * Before to write data into flash we must enable
210  * memory writing. To do this we send a WRE command opcode.
211  * After this command the flash is ready to be write, and so
212  * we send a PROGRAM opcode followed to 3 byte of
213  * address memory, at the end of last address byte
214  * we can send the data.
215  * When we finish to send all data, we disable cs
216  * and flash write received data bytes on its memory.
217  *
218  * \note: WARNING: you could write only on erased memory section!
219  * Each write time you could write max a memory page size,
220  * because if you write more than memory page size the
221  * address roll over to first byte of page.
222  *
223  * \return the number of bytes write.
224  */
225 static size_t flash25_write(struct KFile *_fd, const void *_buf, size_t size)
226 {
227         flash25Offset_t offset;
228         flash25Size_t total_write = 0;
229         flash25Size_t wr_len;
230         const uint8_t *data = (const uint8_t *) _buf;
231
232         KFileFlash25 *fd = KFILEFLASH25(_fd);
233
234         ASSERT(fd->fd.seek_pos + (kfile_size_t)size <= fd->fd.size);
235
236         size = MIN((kfile_size_t)size, fd->fd.size - fd->fd.seek_pos);
237
238         while (size)
239         {
240                 offset = fd->fd.seek_pos % (flash25Size_t)FLASH25_PAGE_SIZE;
241                 wr_len = MIN((flash25Size_t)size, FLASH25_PAGE_SIZE - (flash25Size_t)offset);
242
243                 kprintf("[seek_pos-<%lu>, offset-<%d>]\n", fd->fd.seek_pos, offset);
244
245                 /*
246                  * We check serial flash memory state, and wait until ready-flag
247                  * is high.
248                  */
249                 flash25_waitReady(fd);
250
251                 /*
252                  * Start write cycle.
253                  * We could write only data not more long than one
254                  * page size.
255                  *
256                  * To write on serial flash memory we must first
257                  * enable write with a WREN opcode command, before
258                  * the PROGRAM opcode.
259                  *
260                  * \note: the same byte cannot be reprogrammed without
261                  * erasing the whole sector first.
262                  */
263                 flash25_sendCmd(fd, FLASH25_WREN);
264
265                 CS_ENABLE();
266                 kfile_putc(FLASH25_PROGRAM, fd->channel);
267
268                 /*
269                  * Address that we want to write.
270                  */
271                 kfile_putc((fd->fd.seek_pos >> 16) & 0xFF, fd->channel);
272                 kfile_putc((fd->fd.seek_pos >> 8) & 0xFF, fd->channel);
273                 kfile_putc(fd->fd.seek_pos & 0xFF, fd->channel);
274
275                 kfile_write(fd->channel, data, wr_len);
276
277                 CS_DISABLE();
278
279                 data += wr_len;
280                 fd->fd.seek_pos += wr_len;
281                 size -= wr_len;
282                 total_write += wr_len;
283         }
284
285         kprintf("written %u bytes\n", total_write);
286         return total_write;
287 }
288
289 /**
290  * Sector erase function.
291  *
292  * Erase a select \p sector of serial flash memory.
293  *
294  * \note A sector size is FLASH25_SECTOR_SIZE.
295  * This operation could take a while.
296  */
297 void flash25_sectorErase(KFileFlash25 *fd, Flash25Sector sector)
298 {
299
300         /*
301          * Erase a sector could take a while,
302          * for debug we measure that time
303          * see datasheet to compare this time.
304          */
305         DB(ticks_t start_time = timer_clock());
306
307         CS_ENABLE();
308
309         /*
310          * To erase a sector of serial flash memory we must first
311          * enable write with a WREN opcode command, before
312          * the SECTOR_ERASE opcode. Sector is automatically
313          * determinate if any address within the sector
314          * is selected.
315          */
316         kfile_putc(FLASH25_WREN, fd->channel);
317         kfile_putc(FLASH25_SECTORE_ERASE,fd-> channel);
318
319         /*
320          * Address inside the sector that we want to
321          * erase.
322          */
323         kfile_putc(sector, fd->channel);
324
325         CS_DISABLE();
326
327         /*
328          * We check serial flash memory state, and wait until ready-flag
329          * is hight.
330          */
331         flash25_waitReady(fd);
332
333         DB(kprintf("Erased sector [%d] in %d ms\n", sector, ticks_to_ms(timer_clock() - start_time)));
334
335 }
336
337 /**
338  * Chip erase function.
339  *
340  * Erase all sector of serial flash memory.
341  *
342  * \note This operation could take a while.
343  */
344 void flash25_chipErase(KFileFlash25 *fd)
345 {
346         /*
347          * Erase all chip could take a while,
348          * for debug we measure that time
349          * see datasheet to compare this time.
350          */
351         DB(ticks_t start_time = timer_clock());
352
353         /*
354          * To erase serial flash memory we must first
355          * enable write with a WREN opcode command, before
356          * the CHIP_ERASE opcode.
357          */
358         flash25_sendCmd(fd, FLASH25_WREN);
359         flash25_sendCmd(fd, FLASH25_CHIP_ERASE);
360
361         /*
362          * We check serial flash memory state, and wait until ready-flag
363          * is high.
364          */
365         flash25_waitReady(fd);
366
367         DB(kprintf("Erased all memory in %d ms\n", ticks_to_ms(timer_clock() - start_time)));
368
369 }
370
371 /**
372  * Init data flash memory interface.
373  */
374 void flash25_init(KFileFlash25 *fd, KFile *ch)
375 {
376
377         ASSERT(fd);
378         ASSERT(ch);
379
380          //Set kfile struct type as a generic kfile structure.
381         DB(fd->fd._type = KFT_FLASH25);
382
383         // Set up data flash programming functions.
384         fd->fd.reopen = flash25_reopen;
385         fd->fd.close = flash25_close;
386         fd->fd.read = flash25_read;
387         fd->fd.write = flash25_write;
388         fd->fd.seek = kfile_genericSeek;
389
390         /*
391          * Init a local channel structure and flash kfile interface.
392          */
393         fd->channel = ch;
394         flash25_reopen(&fd->fd);
395
396         /*
397          * Init data flash memory and micro pin.
398          */
399         if (!flash25_pin_init(fd))
400                 ASSERT(0);
401 }
402
403