altos/telefireone-v1.0: Track ao_led_init API change
[fw/altos] / src / drivers / ao_25lc1024.c
1 /*
2  * Copyright © 2009 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #include "ao.h"
20 #include "ao_25lc1024.h"
21
22 #define EE_BLOCK_SIZE   ((uint16_t) (256))
23 #define EE_BLOCK_SHIFT  8
24 #define EE_DEVICE_SIZE  ((uint32_t) 128 * (uint32_t) 1024)
25
26 /* Total bytes of available storage */
27 uint32_t        ao_storage_total;
28
29 /* Block size - device is erased in these units. At least 256 bytes */
30 uint32_t        ao_storage_block;
31
32 /* Byte offset of config block. Will be ao_storage_block bytes long */
33 uint32_t        ao_storage_config;
34
35 /* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */
36 uint16_t        ao_storage_unit;
37
38 /*
39  * Using SPI on USART 0, with P1_2 as the chip select
40  */
41
42 #define EE_CS_PORT      P1
43 #define EE_CS           P1_2
44 #define EE_CS_PIN       2
45
46 static uint8_t ao_ee_mutex;
47
48 #define ao_ee_delay() do { \
49         _asm nop _endasm; \
50         _asm nop _endasm; \
51         _asm nop _endasm; \
52 } while(0)
53
54 #define ao_ee_cs_low()  ao_spi_get_bit(EE_CS_PORT, EE_CS_PIN, EE_CS, AO_EE_SPI_BUS, AO_SPI_SPEED_FAST)
55
56 #define ao_ee_cs_high() ao_spi_put_bit(EE_CS_PORT, EE_CS_PIN, EE_CS, AO_EE_SPI_BUS)
57
58 struct ao_ee_instruction {
59         uint8_t instruction;
60         uint8_t address[3];
61 } ao_ee_instruction;
62
63 static void
64 ao_ee_write_enable(void)
65 {
66         ao_ee_cs_low();
67         ao_ee_instruction.instruction = EE_WREN;
68         ao_spi_send(&ao_ee_instruction, 1, AO_EE_SPI_BUS);
69         ao_ee_cs_high();
70 }
71
72 static uint8_t
73 ao_ee_rdsr(void)
74 {
75         ao_ee_cs_low();
76         ao_ee_instruction.instruction = EE_RDSR;
77         ao_spi_send(&ao_ee_instruction, 1, AO_EE_SPI_BUS);
78         ao_spi_recv(&ao_ee_instruction, 1, AO_EE_SPI_BUS);
79         ao_ee_cs_high();
80         return ao_ee_instruction.instruction;
81 }
82
83 static void
84 ao_ee_wrsr(uint8_t status)
85 {
86         ao_ee_cs_low();
87         ao_ee_instruction.instruction = EE_WRSR;
88         ao_ee_instruction.address[0] = status;
89         ao_spi_send(&ao_ee_instruction, 2, AO_EE_SPI_BUS);
90         ao_ee_cs_high();
91 }
92
93 #define EE_BLOCK_NONE   0xffff
94
95 static uint8_t ao_ee_data[EE_BLOCK_SIZE];
96 static uint16_t ao_ee_block = EE_BLOCK_NONE;
97 static uint8_t  ao_ee_block_dirty;
98
99 /* Write the current block to the EEPROM */
100 static void
101 ao_ee_write_block(void)
102 {
103         uint8_t status;
104
105         status = ao_ee_rdsr();
106         if (status & (EE_STATUS_BP0|EE_STATUS_BP1|EE_STATUS_WPEN)) {
107                 status &= ~(EE_STATUS_BP0|EE_STATUS_BP1|EE_STATUS_WPEN);
108                 ao_ee_wrsr(status);
109         }
110         ao_ee_write_enable();
111         ao_ee_cs_low();
112         ao_ee_instruction.instruction = EE_WRITE;
113         ao_ee_instruction.address[0] = ao_ee_block >> 8;
114         ao_ee_instruction.address[1] = ao_ee_block;
115         ao_ee_instruction.address[2] = 0;
116         ao_spi_send(&ao_ee_instruction, 4, AO_EE_SPI_BUS);
117         ao_spi_send(ao_ee_data, EE_BLOCK_SIZE, AO_EE_SPI_BUS);
118         ao_ee_cs_high();
119         for (;;) {
120                 uint8_t status = ao_ee_rdsr();
121                 if ((status & EE_STATUS_WIP) == 0)
122                         break;
123         }
124 }
125
126 /* Read the current block from the EEPROM */
127 static void
128 ao_ee_read_block(void)
129 {
130         ao_ee_cs_low();
131         ao_ee_instruction.instruction = EE_READ;
132         ao_ee_instruction.address[0] = ao_ee_block >> 8;
133         ao_ee_instruction.address[1] = ao_ee_block;
134         ao_ee_instruction.address[2] = 0;
135         ao_spi_send(&ao_ee_instruction, 4, AO_EE_SPI_BUS);
136         ao_spi_recv(ao_ee_data, EE_BLOCK_SIZE, AO_EE_SPI_BUS);
137         ao_ee_cs_high();
138 }
139
140 static void
141 ao_ee_flush_internal(void)
142 {
143         if (ao_ee_block_dirty) {
144                 ao_ee_write_block();
145                 ao_ee_block_dirty = 0;
146         }
147 }
148
149 static void
150 ao_ee_fill(uint16_t block)
151 {
152         if (block != ao_ee_block) {
153                 ao_ee_flush_internal();
154                 ao_ee_block = block;
155                 ao_ee_read_block();
156         }
157 }
158
159 uint8_t
160 ao_storage_device_write(uint32_t pos, void *buf, uint16_t len) 
161 {
162         uint16_t block = (uint16_t) (pos >> EE_BLOCK_SHIFT);
163
164         /* Transfer the data */
165         ao_mutex_get(&ao_ee_mutex); {
166                 if (len != EE_BLOCK_SIZE)
167                         ao_ee_fill(block);
168                 else {
169                         ao_ee_flush_internal();
170                         ao_ee_block = block;
171                 }
172                 ao_xmemcpy(ao_ee_data + (uint16_t) (pos & 0xff), buf, len);
173                 ao_ee_block_dirty = 1;
174         } ao_mutex_put(&ao_ee_mutex);
175         return 1;
176 }
177
178 uint8_t
179 ao_storage_device_read(uint32_t pos, void *buf, uint16_t len) 
180 {
181         uint16_t block = (uint16_t) (pos >> EE_BLOCK_SHIFT);
182
183         /* Transfer the data */
184         ao_mutex_get(&ao_ee_mutex); {
185                 ao_ee_fill(block);
186                 ao_xmemcpy(buf, ao_ee_data + (uint16_t) (pos & 0xff), len);
187         } ao_mutex_put(&ao_ee_mutex);
188         return 1;
189 }
190
191 void
192 ao_storage_flush(void) 
193 {
194         ao_mutex_get(&ao_ee_mutex); {
195                 ao_ee_flush_internal();
196         } ao_mutex_put(&ao_ee_mutex);
197 }
198
199 uint8_t
200 ao_storage_erase(uint32_t pos) 
201 {
202         ao_mutex_get(&ao_ee_mutex); {
203                 ao_ee_flush_internal();
204                 ao_ee_block = (uint16_t) (pos >> EE_BLOCK_SHIFT);
205                 ao_xmemset(ao_ee_data, 0xff, EE_BLOCK_SIZE);
206                 ao_ee_block_dirty = 1;
207         } ao_mutex_put(&ao_ee_mutex);
208         return 1;
209 }
210
211 static void
212 ee_store(void) 
213 {
214 }
215
216 void
217 ao_storage_setup(void)
218 {
219         if (ao_storage_total == 0) {
220                 ao_storage_total = EE_DEVICE_SIZE;
221                 ao_storage_block = EE_BLOCK_SIZE;
222                 ao_storage_config = EE_DEVICE_SIZE - EE_BLOCK_SIZE;
223                 ao_storage_unit = EE_BLOCK_SIZE;
224         }
225 }
226
227 void
228 ao_storage_device_info(void) 
229 {
230 }
231
232 /*
233  * To initialize the chip, set up the CS line and
234  * the SPI interface
235  */
236 void
237 ao_storage_device_init(void)
238 {
239         /* set up CS */
240         ao_enable_output(EE_CS_PORT, EE_CS_PIN, EE_CS, 1);
241 }