diff options
Diffstat (limited to 'firmware/drivers/eeprom_24cxx.c')
-rw-r--r-- | firmware/drivers/eeprom_24cxx.c | 381 |
1 files changed, 381 insertions, 0 deletions
diff --git a/firmware/drivers/eeprom_24cxx.c b/firmware/drivers/eeprom_24cxx.c new file mode 100644 index 0000000000..4f7362ec82 --- /dev/null +++ b/firmware/drivers/eeprom_24cxx.c | |||
@@ -0,0 +1,381 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2006 by Miika Pekkarinen | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | #include "lcd.h" | ||
20 | #include "cpu.h" | ||
21 | #include "system.h" | ||
22 | #include "kernel.h" | ||
23 | #include "thread.h" | ||
24 | #include "debug.h" | ||
25 | #include "logf.h" | ||
26 | #include "sprintf.h" | ||
27 | #include "string.h" | ||
28 | |||
29 | #include "eeprom_24cxx.h" | ||
30 | |||
31 | /** | ||
32 | * I2C-functions are copied and ported from fmradio.c. | ||
33 | */ | ||
34 | |||
35 | #define SW_I2C_WRITE 0 | ||
36 | #define SW_I2C_READ 1 | ||
37 | |||
38 | /* cute little functions, atomic read-modify-write */ | ||
39 | |||
40 | /* SCL is GPIO, 12 */ | ||
41 | #define SCL_LO and_l(~0x00001000, &GPIO_OUT) // and_b(~0x10, &PBDRL) | ||
42 | #define SCL_HI or_l( 0x00001000, &GPIO_OUT) // or_b( 0x10, &PBDRL) | ||
43 | #define SCL_INPUT and_l(~0x00001000, &GPIO_ENABLE) // and_b(~0x10, &PBIORL) | ||
44 | #define SCL_OUTPUT or_l( 0x00001000, &GPIO_ENABLE) // or_b( 0x10, &PBIORL) | ||
45 | #define SCL ( 0x00001000 & GPIO_READ) // (PBDR & 0x0010) | ||
46 | |||
47 | /* SDA is GPIO1, 13 */ | ||
48 | #define SDA_LO and_l(~0x00002000, &GPIO1_OUT) // and_b(~0x02, &PBDRL) | ||
49 | #define SDA_HI or_l( 0x00002000, &GPIO1_OUT) // or_b( 0x02, &PBDRL) | ||
50 | #define SDA_INPUT and_l(~0x00002000, &GPIO1_ENABLE) // and_b(~0x02, &PBIORL) | ||
51 | #define SDA_OUTPUT or_l( 0x00002000, &GPIO1_ENABLE) // or_b( 0x02, &PBIORL) | ||
52 | #define SDA ( 0x00002000 & GPIO1_READ) // (PBDR & 0x0002) | ||
53 | |||
54 | /* delay loop to achieve 400kHz at 120MHz CPU frequency */ | ||
55 | #define DELAY do { int _x; for(_x=0;_x<22;_x++);} while(0) | ||
56 | |||
57 | static void sw_i2c_init(void) | ||
58 | { | ||
59 | logf("sw_i2c_init"); | ||
60 | or_l(0x00001000, &GPIO_FUNCTION); | ||
61 | or_l(0x00002000, &GPIO1_FUNCTION); | ||
62 | SDA_HI; | ||
63 | SCL_HI; | ||
64 | SDA_OUTPUT; | ||
65 | SCL_OUTPUT; | ||
66 | } | ||
67 | |||
68 | static void sw_i2c_start(void) | ||
69 | { | ||
70 | SCL_LO; | ||
71 | SCL_OUTPUT; | ||
72 | DELAY; | ||
73 | SDA_HI; | ||
74 | SDA_OUTPUT; | ||
75 | DELAY; | ||
76 | SCL_HI; | ||
77 | DELAY; | ||
78 | SDA_LO; | ||
79 | DELAY; | ||
80 | SCL_LO; | ||
81 | } | ||
82 | |||
83 | static void sw_i2c_stop(void) | ||
84 | { | ||
85 | // SCL_LO; | ||
86 | // DELAY; | ||
87 | // SDA_LO; | ||
88 | // DELAY; | ||
89 | SCL_HI; | ||
90 | DELAY; | ||
91 | SDA_HI; | ||
92 | DELAY; | ||
93 | } | ||
94 | |||
95 | |||
96 | static void sw_i2c_ack(void) | ||
97 | { | ||
98 | SCL_LO; | ||
99 | SDA_LO; | ||
100 | DELAY; | ||
101 | |||
102 | SCL_HI; | ||
103 | DELAY; | ||
104 | } | ||
105 | |||
106 | static int sw_i2c_getack(void) | ||
107 | { | ||
108 | int ret = 1; | ||
109 | int count = 10; | ||
110 | |||
111 | SCL_LO; | ||
112 | SDA_INPUT; /* And set to input */ | ||
113 | DELAY; | ||
114 | SCL_HI; | ||
115 | DELAY; | ||
116 | |||
117 | while (SDA && count--) | ||
118 | DELAY; | ||
119 | |||
120 | if (SDA) | ||
121 | /* ack failed */ | ||
122 | ret = 0; | ||
123 | |||
124 | SCL_LO; | ||
125 | SCL_OUTPUT; | ||
126 | DELAY; | ||
127 | SDA_LO; | ||
128 | SDA_OUTPUT; | ||
129 | |||
130 | return ret; | ||
131 | } | ||
132 | |||
133 | static void sw_i2c_outb(unsigned char byte) | ||
134 | { | ||
135 | int i; | ||
136 | |||
137 | /* clock out each bit, MSB first */ | ||
138 | for ( i=0x80; i; i>>=1 ) { | ||
139 | SCL_LO; | ||
140 | DELAY; | ||
141 | if ( i & byte ) | ||
142 | SDA_HI; | ||
143 | else | ||
144 | SDA_LO; | ||
145 | DELAY; | ||
146 | SCL_HI; | ||
147 | DELAY; | ||
148 | } | ||
149 | |||
150 | // SDA_LO; | ||
151 | } | ||
152 | |||
153 | static unsigned char sw_i2c_inb(void) | ||
154 | { | ||
155 | int i; | ||
156 | unsigned char byte = 0; | ||
157 | |||
158 | SDA_INPUT; /* And set to input */ | ||
159 | |||
160 | /* clock in each bit, MSB first */ | ||
161 | for ( i=0x80; i; i>>=1 ) | ||
162 | { | ||
163 | SCL_HI; | ||
164 | DELAY; | ||
165 | if ( SDA ) | ||
166 | byte |= i; | ||
167 | SCL_LO; | ||
168 | DELAY; | ||
169 | } | ||
170 | |||
171 | SDA_OUTPUT; | ||
172 | |||
173 | sw_i2c_ack(); | ||
174 | |||
175 | return byte; | ||
176 | } | ||
177 | |||
178 | int sw_i2c_write(int location, const unsigned char* buf, int count) | ||
179 | { | ||
180 | int i; | ||
181 | |||
182 | sw_i2c_start(); | ||
183 | sw_i2c_outb((EEPROM_ADDR & 0xfe) | SW_I2C_WRITE); | ||
184 | if (!sw_i2c_getack()) | ||
185 | { | ||
186 | sw_i2c_stop(); | ||
187 | return -1; | ||
188 | } | ||
189 | |||
190 | sw_i2c_outb(location); | ||
191 | if (!sw_i2c_getack()) | ||
192 | { | ||
193 | sw_i2c_stop(); | ||
194 | return -2; | ||
195 | } | ||
196 | |||
197 | for (i=0; i<count; i++) | ||
198 | { | ||
199 | sw_i2c_outb(buf[i]); | ||
200 | if (!sw_i2c_getack()) | ||
201 | { | ||
202 | sw_i2c_stop(); | ||
203 | return -3; | ||
204 | } | ||
205 | } | ||
206 | |||
207 | sw_i2c_stop(); | ||
208 | |||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | int sw_i2c_write_byte(int location, unsigned char byte) | ||
213 | { | ||
214 | sw_i2c_start(); | ||
215 | sw_i2c_outb((EEPROM_ADDR & 0xfe) | SW_I2C_WRITE); | ||
216 | if (!sw_i2c_getack()) | ||
217 | { | ||
218 | sw_i2c_stop(); | ||
219 | return -1; | ||
220 | } | ||
221 | |||
222 | sw_i2c_outb(location); | ||
223 | if (!sw_i2c_getack()) | ||
224 | { | ||
225 | sw_i2c_stop(); | ||
226 | return -2; | ||
227 | } | ||
228 | |||
229 | sw_i2c_outb(byte); | ||
230 | if (!sw_i2c_getack()) | ||
231 | { | ||
232 | sw_i2c_stop(); | ||
233 | return -3; | ||
234 | } | ||
235 | |||
236 | sw_i2c_stop(); | ||
237 | |||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | int sw_i2c_read(unsigned char location, unsigned char* byte) | ||
242 | { | ||
243 | sw_i2c_start(); | ||
244 | sw_i2c_outb((EEPROM_ADDR & 0xfe) | SW_I2C_WRITE); | ||
245 | if (!sw_i2c_getack()) | ||
246 | { | ||
247 | sw_i2c_stop(); | ||
248 | return -1; | ||
249 | } | ||
250 | |||
251 | sw_i2c_outb(location); | ||
252 | if (!sw_i2c_getack()) | ||
253 | { | ||
254 | sw_i2c_stop(); | ||
255 | return -2; | ||
256 | } | ||
257 | |||
258 | sw_i2c_start(); | ||
259 | sw_i2c_outb((EEPROM_ADDR & 0xfe) | SW_I2C_READ); | ||
260 | if (!sw_i2c_getack()) | ||
261 | { | ||
262 | sw_i2c_stop(); | ||
263 | return -3; | ||
264 | } | ||
265 | |||
266 | *byte = sw_i2c_inb(); | ||
267 | sw_i2c_stop(); | ||
268 | |||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | void eeprom_24cxx_init(void) | ||
273 | { | ||
274 | sw_i2c_init(); | ||
275 | } | ||
276 | |||
277 | bool eeprom_24cxx_read_byte(unsigned int address, char *c) | ||
278 | { | ||
279 | int ret; | ||
280 | char byte; | ||
281 | int count = 10; | ||
282 | |||
283 | if (address >= EEPROM_SIZE) | ||
284 | { | ||
285 | logf("EEPROM address: %d", address); | ||
286 | return false; | ||
287 | } | ||
288 | |||
289 | *c = 0; | ||
290 | do { | ||
291 | ret = sw_i2c_read(address, &byte); | ||
292 | if (ret < 0) | ||
293 | { | ||
294 | logf("EEPROM Fail: %d/%d", ret, address); | ||
295 | } | ||
296 | } while (ret < 0 && count--) ; | ||
297 | |||
298 | if (ret < 0) | ||
299 | { | ||
300 | logf("EEPROM RFail: %d/%d", ret, address); | ||
301 | return false; | ||
302 | } | ||
303 | |||
304 | *c = byte; | ||
305 | return true; | ||
306 | } | ||
307 | |||
308 | bool eeprom_24cxx_write_byte(unsigned int address, char c) | ||
309 | { | ||
310 | int ret; | ||
311 | int count = 10; | ||
312 | |||
313 | if (address >= EEPROM_SIZE) | ||
314 | { | ||
315 | logf("EEPROM address: %d", address); | ||
316 | return false; | ||
317 | } | ||
318 | |||
319 | do { | ||
320 | ret = sw_i2c_write_byte(address, c); | ||
321 | if (ret < 0) | ||
322 | { | ||
323 | logf("EEPROM Fail: %d/%d", ret, address); | ||
324 | } | ||
325 | } while (ret < 0 && count--) ; | ||
326 | |||
327 | if (ret < 0) | ||
328 | { | ||
329 | logf("EEPROM WFail: %d/%d", ret, address); | ||
330 | return false; | ||
331 | } | ||
332 | |||
333 | return true; | ||
334 | } | ||
335 | |||
336 | bool eeprom_24cxx_read(unsigned char address, void *dest, int length) | ||
337 | { | ||
338 | char *buf = (char *)dest; | ||
339 | int i; | ||
340 | |||
341 | for (i = 0; i < length; i++) | ||
342 | { | ||
343 | if (!eeprom_24cxx_read_byte(address+i, &buf[i])) | ||
344 | return false; | ||
345 | } | ||
346 | |||
347 | return true; | ||
348 | } | ||
349 | |||
350 | bool eeprom_24cxx_write(unsigned char address, const void *src, int length) | ||
351 | { | ||
352 | const char *buf = (const char *)src; | ||
353 | int count = 10; | ||
354 | int i, ok; | ||
355 | |||
356 | while (count-- > 0) | ||
357 | { | ||
358 | for (i = 0; i < length; i++) | ||
359 | eeprom_24cxx_write_byte(address+i, buf[i]); | ||
360 | |||
361 | ok = true; | ||
362 | for (i = 0; i < length; i++) | ||
363 | { | ||
364 | char byte; | ||
365 | |||
366 | eeprom_24cxx_read_byte(address+i, &byte); | ||
367 | if (byte != buf[i]) | ||
368 | { | ||
369 | logf("Verify failed: %d/%d", address+i, count); | ||
370 | ok = false; | ||
371 | break; | ||
372 | } | ||
373 | } | ||
374 | |||
375 | if (ok) | ||
376 | return true; | ||
377 | } | ||
378 | |||
379 | return false; | ||
380 | } | ||
381 | |||