1 /*! \page License
2  * Copyright (C) 2009, H&D Wireless AB All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright notice,
8  * this list of conditions and the following disclaimer.
9  *
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * 3. The name of H&D Wireless AB may not be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY H&D WIRELESS AB ``AS IS'' AND ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND
20  * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT,
21  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 #include <string.h>
29 
30 #include "compiler.h"
31 #include "preprocessor.h"
32 #include "board.h"
33 #include "power_clocks_lib.h"
34 #include "gpio.h"
35 #include "spi.h"
36 #include "conf_at45dbx.h"
37 #include "at45dbx.h"
38 #include <board_init.h>
39 #include <nvram.h>
40 
41 
42 static struct nvram {
43         uint8_t read;
44         void *data;
45         uint32_t len;
46         uint16_t off;
47 } PRIV;
48 
nvram_init(void)49 int nvram_init(void)
50 {
51         spi_options_t spiOptions = {
52                 .reg          = AT45DBX_SPI_FIRST_NPCS,
53                 .baudrate     = AT45DBX_SPI_MASTER_SPEED,
54                 .bits         = AT45DBX_SPI_BITS,
55                 .spck_delay   = 0,
56                 .trans_delay  = 0,
57                 .stay_act     = 1,
58                 .spi_mode     = 0,
59                 .modfdis      = 1
60         };
61 
62         at45dbx_init(spiOptions, FPBA_HZ);
63         return 0;
64 }
65 
66 
67 /**
68  * Invoked by at45dbx driver
69  *
70  */
at45dbx_read_multiple_sector_callback(const void * psector)71 void at45dbx_read_multiple_sector_callback(const void *psector)
72 {
73         struct nvram *priv = &PRIV;
74         const uint8_t *buf = psector;
75 
76         if (!priv->read)
77                 return;
78 
79         memcpy(priv->data, buf + priv->off, priv->len);
80 }
81 
82 
83 /**
84  * Invoked by at45dbx driver
85  *
86  */
at45dbx_write_multiple_sector_callback(void * psector)87 void at45dbx_write_multiple_sector_callback(void *psector)
88 {
89         struct nvram *priv = &PRIV;
90         uint8_t *buf = psector;
91         memcpy(buf + priv->off, priv->data, priv->len);
92 }
93 
94 
95 /**
96  * Write/read any number bytes into any offset of nor flash by taking care
97  * of cases where the length is not aligned to the sector size or where
98  * the addr is not aligned to the sector offsets.
99  *
100  */
nvram_rw(uint32_t addr,void * data,uint16_t len,int write)101 static int nvram_rw(uint32_t addr, void *data, uint16_t len, int write)
102 {
103         struct nvram *priv = &PRIV;
104         priv->read = write ? 0 : 1;
105 
106         while (len) {
107                 uint32_t sector = addr / AT45DBX_SECTOR_SIZE;
108                 priv->data = data;
109                 priv->off = addr % AT45DBX_SECTOR_SIZE;
110                 priv->len = AT45DBX_SECTOR_SIZE;
111 
112                 if (len < AT45DBX_SECTOR_SIZE)
113                         priv->len = len;
114 
115                 if (priv->len > AT45DBX_SECTOR_SIZE - priv->off)
116                         priv->len = AT45DBX_SECTOR_SIZE - priv->off;
117 
118                 at45dbx_read_open(sector);
119                 at45dbx_read_multiple_sector(1);
120                 at45dbx_read_close();
121 
122                 if (write) {
123                         at45dbx_write_open(sector);
124                         at45dbx_write_multiple_sector(1);
125                         at45dbx_write_close();
126                 }
127 
128                 data += priv->len;
129                 len -= priv->len;
130                 addr += priv->len;
131         }
132 
133         return 0;
134 }
135 
136 /**
137  * Write any number bytes into any offset of nor flash.
138  *
139  */
nvram_write(uint32_t addr,const void * data,uint32_t len)140 int nvram_write(uint32_t addr, const void *data, uint32_t len)
141 {
142         return nvram_rw(addr, (void *) data, len, 1);
143 }
144 
145 
146 /**
147  * Read any number bytes into any offset of nor flash.
148  *
149  */
nvram_read(uint32_t addr,void * data,uint32_t len)150 int nvram_read(uint32_t addr, void *data, uint32_t len)
151 {
152         return nvram_rw(addr, data, len, 0);
153 }
154