initial commit
[freebsd-arm:freebsd-arm.git] / boot / arm / at91 / libat91 / eeprom.c
1 /******************************************************************************
2  *
3  * Filename: eeprom.c
4  *
5  * Instantiation of eeprom routines
6  *
7  * Revision information:
8  *
9  * 28AUG2004    kb_admin        initial creation - adapted from Atmel sources
10  * 12JAN2005    kb_admin        fixed clock generation, write polling, init
11  *
12  * BEGIN_KBDD_BLOCK
13  * No warranty, expressed or implied, is included with this software.  It is
14  * provided "AS IS" and no warranty of any kind including statutory or aspects
15  * relating to merchantability or fitness for any purpose is provided.  All
16  * intellectual property rights of others is maintained with the respective
17  * owners.  This software is not copyrighted and is intended for reference
18  * only.
19  * END_BLOCK
20  *
21  * $FreeBSD$
22  *****************************************************************************/
23
24 #include "at91rm9200_lowlevel.h"
25 #include "at91rm9200.h"
26 #include "lib.h"
27
28 /******************************* GLOBALS *************************************/
29
30
31 /*********************** PRIVATE FUNCTIONS/DATA ******************************/
32
33
34 /* Use a macro to calculate the TWI clock generator value to save code space. */
35 #define AT91C_TWSI_CLOCK        100000
36 #define TWSI_EEPROM_ADDRESS     0x50
37
38 #define TWI_CLK_BASE_DIV        ((AT91C_MASTER_CLOCK/(4*AT91C_TWSI_CLOCK)) - 2)
39 #define SET_TWI_CLOCK   ((0x00010000) | (TWI_CLK_BASE_DIV) | (TWI_CLK_BASE_DIV << 8))
40
41
42 /*************************** GLOBAL FUNCTIONS ********************************/
43
44
45 /*
46  * .KB_C_FN_DEFINITION_START
47  * void InitEEPROM(void)
48  *  This global function initializes the EEPROM interface (TWI).  Intended
49  * to be called a single time.
50  * .KB_C_FN_DEFINITION_END
51  */
52 void
53 InitEEPROM(void)
54 {
55
56         AT91PS_TWI twiPtr = (AT91PS_TWI)AT91C_BASE_TWI;
57
58         AT91PS_PIO pPio = (AT91PS_PIO)AT91C_BASE_PIOA;
59         AT91PS_PMC pPMC = (AT91PS_PMC)AT91C_BASE_PMC;
60
61         pPio->PIO_ASR = AT91C_PA25_TWD | AT91C_PA26_TWCK;
62         pPio->PIO_PDR = AT91C_PA25_TWD | AT91C_PA26_TWCK;
63
64         pPio->PIO_MDDR = ~AT91C_PA25_TWD;
65         pPio->PIO_MDER = AT91C_PA25_TWD;
66
67         pPMC->PMC_PCER = 1u << AT91C_ID_TWI;
68
69         twiPtr->TWI_IDR = 0xffffffffu;
70         twiPtr->TWI_CR = AT91C_TWI_SWRST;
71         twiPtr->TWI_CR = AT91C_TWI_MSEN | AT91C_TWI_SVDIS;
72
73         twiPtr->TWI_CWGR = SET_TWI_CLOCK;
74 }
75
76
77 /*
78  * .KB_C_FN_DEFINITION_START
79  * void ReadEEPROM(unsigned ee_addr, char *data_addr, unsigned size)
80  *  This global function reads data from the eeprom at ee_addr storing data
81  * to data_addr for size bytes.  Assume the TWI has been initialized.
82  * This function does not utilize the page read mode to simplify the code.
83  * .KB_C_FN_DEFINITION_END
84  */
85 int
86 ReadEEPROM(unsigned ee_off, unsigned char *data_addr, unsigned size)
87 {
88         const AT91PS_TWI        twiPtr = AT91C_BASE_TWI;
89         unsigned int status;
90         unsigned int count;
91
92         status = twiPtr->TWI_SR;
93         status = twiPtr->TWI_RHR;
94
95         // Set the TWI Master Mode Register
96         twiPtr->TWI_MMR = (TWSI_EEPROM_ADDRESS << 16) |
97             AT91C_TWI_IADRSZ_2_BYTE | AT91C_TWI_MREAD;
98
99         // Set TWI Internal Address Register
100         twiPtr->TWI_IADR = ee_off;
101
102         // Start transfer
103         twiPtr->TWI_CR = AT91C_TWI_START;
104
105         status = twiPtr->TWI_SR;
106
107         while (size-- > 1){
108                 // Wait RHR Holding register is full
109                 count = 1000000;
110                 while (!(twiPtr->TWI_SR & AT91C_TWI_RXRDY) && --count > 0)
111                         continue;
112                 if (count <= 0)
113                         return -1;
114
115                 // Read byte
116                 *(data_addr++) = twiPtr->TWI_RHR;
117         }
118
119         twiPtr->TWI_CR = AT91C_TWI_STOP;
120
121         status = twiPtr->TWI_SR;
122
123         // Wait transfer is finished
124         while (!(twiPtr->TWI_SR & AT91C_TWI_TXCOMP))
125                 continue;
126
127         // Read last byte
128         *data_addr = twiPtr->TWI_RHR;
129         return 0;
130 }
131
132
133 /*
134  * .KB_C_FN_DEFINITION_START
135  * void WriteEEPROM(unsigned ee_off, char *data_addr, unsigned size)
136  *  This global function writes data to the eeprom at ee_off using data
137  * from data_addr for size bytes.  Assume the TWI has been initialized.
138  * This function does not utilize the page write mode as the write time is
139  * much greater than the time required to access the device for byte-write
140  * functionality.  This allows the function to be much simpler.
141  * .KB_C_FN_DEFINITION_END
142  */
143 void
144 WriteEEPROM(unsigned ee_off, char *data_addr, unsigned size)
145 {
146         const AT91PS_TWI        twiPtr = AT91C_BASE_TWI;
147         unsigned                status;
148         unsigned char           test_data;
149
150         while (size--) {
151                 if (!(ee_off & 0x3f))
152                         putchar('.');
153
154                 // Set the TWI Master Mode Register
155                 twiPtr->TWI_MMR = ((TWSI_EEPROM_ADDRESS << 16) |
156                     AT91C_TWI_IADRSZ_2_BYTE) & ~AT91C_TWI_MREAD;
157
158                 // Set TWI Internal Address Register
159                 twiPtr->TWI_IADR = ee_off++;
160
161                 status = twiPtr->TWI_SR;
162
163                 twiPtr->TWI_THR = *(data_addr++);
164
165                 twiPtr->TWI_CR = AT91C_TWI_START;
166
167                 // Wait transfer is finished
168                 while (!(twiPtr->TWI_SR & AT91C_TWI_TXRDY))
169                         continue;
170
171                 twiPtr->TWI_CR = AT91C_TWI_STOP;
172
173                 status = twiPtr->TWI_SR;
174
175                 // Wait transfer is finished
176                 while (!(twiPtr->TWI_SR & AT91C_TWI_TXCOMP))
177                         continue;
178
179                 // wait for write operation to complete
180                 ReadEEPROM(ee_off, &test_data, 1);
181         }
182
183         putchar('\r');
184         putchar('\n');
185 }