xref: /titanic_52/usr/src/boot/sys/boot/arm/at91/libat91/eeprom.c (revision 4a5d661a82b942b6538acd26209d959ce98b593a)
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_PIO_PA25 | AT91C_PIO_PA26;
62 	pPio->PIO_PDR = AT91C_PIO_PA25 | AT91C_PIO_PA26;
63 
64 	pPio->PIO_MDDR = ~AT91C_PIO_PA25;
65 	pPio->PIO_MDER = AT91C_PIO_PA25;
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 }
186