1157873Simp/******************************************************************************
2157873Simp *
3157873Simp * Filename: eeprom.c
4157873Simp *
5157873Simp * Instantiation of eeprom routines
6157873Simp *
7157873Simp * Revision information:
8157873Simp *
9157873Simp * 28AUG2004	kb_admin	initial creation - adapted from Atmel sources
10157873Simp * 12JAN2005	kb_admin	fixed clock generation, write polling, init
11157873Simp *
12157873Simp * BEGIN_KBDD_BLOCK
13157873Simp * No warranty, expressed or implied, is included with this software.  It is
14157873Simp * provided "AS IS" and no warranty of any kind including statutory or aspects
15157873Simp * relating to merchantability or fitness for any purpose is provided.  All
16157873Simp * intellectual property rights of others is maintained with the respective
17157873Simp * owners.  This software is not copyrighted and is intended for reference
18157873Simp * only.
19157873Simp * END_BLOCK
20157873Simp *
21157873Simp * $FreeBSD$
22157873Simp *****************************************************************************/
23157873Simp
24157873Simp#include "at91rm9200_lowlevel.h"
25157873Simp#include "at91rm9200.h"
26157873Simp#include "lib.h"
27157873Simp
28157873Simp/******************************* GLOBALS *************************************/
29157873Simp
30157873Simp
31157873Simp/*********************** PRIVATE FUNCTIONS/DATA ******************************/
32157873Simp
33157873Simp
34157873Simp/* Use a macro to calculate the TWI clock generator value to save code space. */
35157873Simp#define AT91C_TWSI_CLOCK	100000
36157873Simp#define TWSI_EEPROM_ADDRESS	0x50
37157873Simp
38157873Simp#define TWI_CLK_BASE_DIV	((AT91C_MASTER_CLOCK/(4*AT91C_TWSI_CLOCK)) - 2)
39157873Simp#define SET_TWI_CLOCK	((0x00010000) | (TWI_CLK_BASE_DIV) | (TWI_CLK_BASE_DIV << 8))
40157873Simp
41157873Simp
42157873Simp/*************************** GLOBAL FUNCTIONS ********************************/
43157873Simp
44157873Simp
45157873Simp/*
46157873Simp * .KB_C_FN_DEFINITION_START
47157873Simp * void InitEEPROM(void)
48157873Simp *  This global function initializes the EEPROM interface (TWI).  Intended
49157873Simp * to be called a single time.
50157873Simp * .KB_C_FN_DEFINITION_END
51157873Simp */
52157873Simpvoid
53157873SimpInitEEPROM(void)
54157873Simp{
55157873Simp
56157873Simp	AT91PS_TWI twiPtr = (AT91PS_TWI)AT91C_BASE_TWI;
57157873Simp
58157873Simp	AT91PS_PIO pPio = (AT91PS_PIO)AT91C_BASE_PIOA;
59157873Simp	AT91PS_PMC pPMC = (AT91PS_PMC)AT91C_BASE_PMC;
60157873Simp
61238463Simp	pPio->PIO_ASR = AT91C_PIO_PA25 | AT91C_PIO_PA26;
62238463Simp	pPio->PIO_PDR = AT91C_PIO_PA25 | AT91C_PIO_PA26;
63157873Simp
64238463Simp	pPio->PIO_MDDR = ~AT91C_PIO_PA25;
65238463Simp	pPio->PIO_MDER = AT91C_PIO_PA25;
66157873Simp
67157873Simp	pPMC->PMC_PCER = 1u << AT91C_ID_TWI;
68157873Simp
69157873Simp	twiPtr->TWI_IDR = 0xffffffffu;
70157873Simp	twiPtr->TWI_CR = AT91C_TWI_SWRST;
71157873Simp	twiPtr->TWI_CR = AT91C_TWI_MSEN | AT91C_TWI_SVDIS;
72157873Simp
73157873Simp	twiPtr->TWI_CWGR = SET_TWI_CLOCK;
74157873Simp}
75157873Simp
76157873Simp
77157873Simp/*
78157873Simp * .KB_C_FN_DEFINITION_START
79157873Simp * void ReadEEPROM(unsigned ee_addr, char *data_addr, unsigned size)
80157873Simp *  This global function reads data from the eeprom at ee_addr storing data
81157873Simp * to data_addr for size bytes.  Assume the TWI has been initialized.
82157873Simp * This function does not utilize the page read mode to simplify the code.
83157873Simp * .KB_C_FN_DEFINITION_END
84157873Simp */
85165399Simpint
86172991ScognetReadEEPROM(unsigned ee_off, unsigned char *data_addr, unsigned size)
87157873Simp{
88157873Simp	const AT91PS_TWI 	twiPtr = AT91C_BASE_TWI;
89157873Simp	unsigned int status;
90165399Simp	unsigned int count;
91157873Simp
92157873Simp	status = twiPtr->TWI_SR;
93157873Simp	status = twiPtr->TWI_RHR;
94157873Simp
95157873Simp	// Set the TWI Master Mode Register
96157873Simp	twiPtr->TWI_MMR = (TWSI_EEPROM_ADDRESS << 16) |
97157873Simp	    AT91C_TWI_IADRSZ_2_BYTE | AT91C_TWI_MREAD;
98157873Simp
99157873Simp	// Set TWI Internal Address Register
100161193Simp	twiPtr->TWI_IADR = ee_off;
101157873Simp
102157873Simp	// Start transfer
103157873Simp	twiPtr->TWI_CR = AT91C_TWI_START;
104157873Simp
105157873Simp	status = twiPtr->TWI_SR;
106157873Simp
107157873Simp	while (size-- > 1){
108157873Simp		// Wait RHR Holding register is full
109165399Simp		count = 1000000;
110165399Simp		while (!(twiPtr->TWI_SR & AT91C_TWI_RXRDY) && --count > 0)
111157873Simp			continue;
112165399Simp		if (count <= 0)
113165399Simp			return -1;
114157873Simp
115157873Simp		// Read byte
116157873Simp		*(data_addr++) = twiPtr->TWI_RHR;
117157873Simp	}
118157873Simp
119157873Simp	twiPtr->TWI_CR = AT91C_TWI_STOP;
120157873Simp
121157873Simp	status = twiPtr->TWI_SR;
122157873Simp
123157873Simp	// Wait transfer is finished
124157873Simp	while (!(twiPtr->TWI_SR & AT91C_TWI_TXCOMP))
125157873Simp		continue;
126157873Simp
127157873Simp	// Read last byte
128157873Simp	*data_addr = twiPtr->TWI_RHR;
129165399Simp	return 0;
130157873Simp}
131157873Simp
132157873Simp
133157873Simp/*
134157873Simp * .KB_C_FN_DEFINITION_START
135161193Simp * void WriteEEPROM(unsigned ee_off, char *data_addr, unsigned size)
136161193Simp *  This global function writes data to the eeprom at ee_off using data
137157873Simp * from data_addr for size bytes.  Assume the TWI has been initialized.
138157873Simp * This function does not utilize the page write mode as the write time is
139157873Simp * much greater than the time required to access the device for byte-write
140157873Simp * functionality.  This allows the function to be much simpler.
141157873Simp * .KB_C_FN_DEFINITION_END
142157873Simp */
143157873Simpvoid
144161193SimpWriteEEPROM(unsigned ee_off, char *data_addr, unsigned size)
145157873Simp{
146157873Simp	const AT91PS_TWI 	twiPtr = AT91C_BASE_TWI;
147157873Simp	unsigned		status;
148172991Scognet	unsigned char		test_data;
149157873Simp
150157873Simp	while (size--) {
151161193Simp		if (!(ee_off & 0x3f))
152157873Simp			putchar('.');
153157873Simp
154157873Simp		// Set the TWI Master Mode Register
155157873Simp		twiPtr->TWI_MMR = ((TWSI_EEPROM_ADDRESS << 16) |
156157873Simp		    AT91C_TWI_IADRSZ_2_BYTE) & ~AT91C_TWI_MREAD;
157157873Simp
158157873Simp		// Set TWI Internal Address Register
159161193Simp		twiPtr->TWI_IADR = ee_off++;
160157873Simp
161157873Simp		status = twiPtr->TWI_SR;
162157873Simp
163157873Simp		twiPtr->TWI_THR = *(data_addr++);
164157873Simp
165157873Simp		twiPtr->TWI_CR = AT91C_TWI_START;
166157873Simp
167157873Simp		// Wait transfer is finished
168157873Simp		while (!(twiPtr->TWI_SR & AT91C_TWI_TXRDY))
169157873Simp			continue;
170157873Simp
171157873Simp		twiPtr->TWI_CR = AT91C_TWI_STOP;
172157873Simp
173157873Simp		status = twiPtr->TWI_SR;
174157873Simp
175157873Simp		// Wait transfer is finished
176157873Simp		while (!(twiPtr->TWI_SR & AT91C_TWI_TXCOMP))
177157873Simp			continue;
178157873Simp
179157873Simp		// wait for write operation to complete
180161193Simp		ReadEEPROM(ee_off, &test_data, 1);
181157873Simp	}
182157873Simp
183157873Simp	putchar('\r');
184157873Simp	putchar('\n');
185157873Simp}
186