eeprom.c revision 161193
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: head/sys/boot/arm/at91/libat91/eeprom.c 161193 2006-08-10 18:03:50Z imp $
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 */
52void
53InitEEPROM(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 */
85void
86ReadEEPROM(unsigned ee_off, char *data_addr, unsigned size)
87{
88	const AT91PS_TWI 	twiPtr = AT91C_BASE_TWI;
89	unsigned int status;
90
91	status = twiPtr->TWI_SR;
92	status = twiPtr->TWI_RHR;
93
94	// Set the TWI Master Mode Register
95	twiPtr->TWI_MMR = (TWSI_EEPROM_ADDRESS << 16) |
96	    AT91C_TWI_IADRSZ_2_BYTE | AT91C_TWI_MREAD;
97
98	// Set TWI Internal Address Register
99	twiPtr->TWI_IADR = ee_off;
100
101	// Start transfer
102	twiPtr->TWI_CR = AT91C_TWI_START;
103
104	status = twiPtr->TWI_SR;
105
106	while (size-- > 1){
107
108		// Wait RHR Holding register is full
109		while (!(twiPtr->TWI_SR & AT91C_TWI_RXRDY))
110			continue;
111
112		// Read byte
113		*(data_addr++) = twiPtr->TWI_RHR;
114	}
115
116	twiPtr->TWI_CR = AT91C_TWI_STOP;
117
118	status = twiPtr->TWI_SR;
119
120	// Wait transfer is finished
121	while (!(twiPtr->TWI_SR & AT91C_TWI_TXCOMP))
122		continue;
123
124	// Read last byte
125	*data_addr = twiPtr->TWI_RHR;
126}
127
128
129/*
130 * .KB_C_FN_DEFINITION_START
131 * void WriteEEPROM(unsigned ee_off, char *data_addr, unsigned size)
132 *  This global function writes data to the eeprom at ee_off using data
133 * from data_addr for size bytes.  Assume the TWI has been initialized.
134 * This function does not utilize the page write mode as the write time is
135 * much greater than the time required to access the device for byte-write
136 * functionality.  This allows the function to be much simpler.
137 * .KB_C_FN_DEFINITION_END
138 */
139void
140WriteEEPROM(unsigned ee_off, char *data_addr, unsigned size)
141{
142	const AT91PS_TWI 	twiPtr = AT91C_BASE_TWI;
143	unsigned		status;
144	char			test_data;
145
146	while (size--) {
147		if (!(ee_off & 0x3f))
148			putchar('.');
149
150		// Set the TWI Master Mode Register
151		twiPtr->TWI_MMR = ((TWSI_EEPROM_ADDRESS << 16) |
152		    AT91C_TWI_IADRSZ_2_BYTE) & ~AT91C_TWI_MREAD;
153
154		// Set TWI Internal Address Register
155		twiPtr->TWI_IADR = ee_off++;
156
157		status = twiPtr->TWI_SR;
158
159		twiPtr->TWI_THR = *(data_addr++);
160
161		twiPtr->TWI_CR = AT91C_TWI_START;
162
163		// Wait transfer is finished
164		while (!(twiPtr->TWI_SR & AT91C_TWI_TXRDY))
165			continue;
166
167		twiPtr->TWI_CR = AT91C_TWI_STOP;
168
169		status = twiPtr->TWI_SR;
170
171		// Wait transfer is finished
172		while (!(twiPtr->TWI_SR & AT91C_TWI_TXCOMP))
173			continue;
174
175		// wait for write operation to complete
176		ReadEEPROM(ee_off, &test_data, 1);
177	}
178
179	putchar('\r');
180	putchar('\n');
181}
182