1163598Simp/******************************************************************************
2163598Simp *
3163598Simp * Filename: eeprom.c
4163598Simp *
5163598Simp * Instantiation of eeprom routines
6163598Simp *
7163598Simp * Revision information:
8163598Simp *
9163598Simp * 28AUG2004	kb_admin	initial creation - adapted from Atmel sources
10163598Simp * 12JAN2005	kb_admin	fixed clock generation, write polling, init
11163598Simp *
12163598Simp * BEGIN_KBDD_BLOCK
13163598Simp * No warranty, expressed or implied, is included with this software.  It is
14163598Simp * provided "AS IS" and no warranty of any kind including statutory or aspects
15163598Simp * relating to merchantability or fitness for any purpose is provided.  All
16163598Simp * intellectual property rights of others is maintained with the respective
17163598Simp * owners.  This software is not copyrighted and is intended for reference
18163598Simp * only.
19163598Simp * END_BLOCK
20163598Simp *
21163598Simp * $FreeBSD$
22163598Simp *****************************************************************************/
23163598Simp
24163598Simp#include "at91rm9200_lowlevel.h"
25163598Simp#include "at91rm9200.h"
26163598Simp#include "lib.h"
27163598Simp#include "ee.h"
28163598Simp
29163598Simp/******************************* GLOBALS *************************************/
30163598Simp
31163598Simp
32163598Simp/*********************** PRIVATE FUNCTIONS/DATA ******************************/
33163598Simp
34163598Simp
35163598Simp/* Use a macro to calculate the TWI clock generator value to save code space. */
36163598Simp#define AT91C_TWSI_CLOCK	100000
37163598Simp#define TWSI_EEPROM_ADDRESS	0x40
38163598Simp
39163598Simp#define TWI_CLK_BASE_DIV	((AT91C_MASTER_CLOCK/(4*AT91C_TWSI_CLOCK)) - 2)
40163598Simp#define SET_TWI_CLOCK	((0x00010000) | (TWI_CLK_BASE_DIV) | (TWI_CLK_BASE_DIV << 8))
41163598Simp
42163598Simp
43163598Simp/*************************** GLOBAL FUNCTIONS ********************************/
44163598Simp
45163598Simp
46163598Simp/*
47163598Simp * .KB_C_FN_DEFINITION_START
48163598Simp * void InitEEPROM(void)
49163598Simp *  This global function initializes the EEPROM interface (TWI).  Intended
50163598Simp * to be called a single time.
51163598Simp * .KB_C_FN_DEFINITION_END
52163598Simp */
53163598Simpvoid
54163598SimpEEInit(void)
55163598Simp{
56163598Simp
57163598Simp	AT91PS_TWI twiPtr = (AT91PS_TWI)AT91C_BASE_TWI;
58163598Simp
59163598Simp	AT91PS_PIO pPio = (AT91PS_PIO)AT91C_BASE_PIOA;
60163598Simp	AT91PS_PMC pPMC = (AT91PS_PMC)AT91C_BASE_PMC;
61163598Simp
62163598Simp	pPio->PIO_ASR = AT91C_PA25_TWD | AT91C_PA26_TWCK;
63163598Simp	pPio->PIO_PDR = AT91C_PA25_TWD | AT91C_PA26_TWCK;
64163598Simp
65163598Simp	pPio->PIO_MDDR = ~AT91C_PA25_TWD;
66163598Simp	pPio->PIO_MDER = AT91C_PA25_TWD;
67163598Simp
68163598Simp	pPMC->PMC_PCER = 1u << AT91C_ID_TWI;
69163598Simp
70163598Simp	twiPtr->TWI_IDR = 0xffffffffu;
71163598Simp	twiPtr->TWI_CR = AT91C_TWI_SWRST;
72163598Simp	twiPtr->TWI_CR = AT91C_TWI_MSEN | AT91C_TWI_SVDIS;
73163598Simp
74163598Simp	twiPtr->TWI_CWGR = SET_TWI_CLOCK;
75163598Simp}
76163598Simp
77163598Simpstatic inline unsigned
78163598Simpiicaddr(unsigned ee_off)
79163598Simp{
80163598Simp    return (TWSI_EEPROM_ADDRESS | ((ee_off >> 8) & 0x7));
81163598Simp}
82163598Simp
83163598Simp
84163598Simp/*
85163598Simp * .KB_C_FN_DEFINITION_START
86163598Simp * void ReadEEPROM(unsigned ee_addr, char *data_addr, unsigned size)
87163598Simp *  This global function reads data from the eeprom at ee_addr storing data
88163598Simp * to data_addr for size bytes.  Assume the TWI has been initialized.
89163598Simp * This function does not utilize the page read mode to simplify the code.
90163598Simp * .KB_C_FN_DEFINITION_END
91163598Simp */
92163598Simpvoid
93163598SimpEERead(unsigned ee_off, char *data_addr, unsigned size)
94163598Simp{
95163598Simp	const AT91PS_TWI 	twiPtr = AT91C_BASE_TWI;
96163598Simp	unsigned int status;
97163598Simp
98163598Simp	if ((ee_off & ~0xff) != ((ee_off + size) & ~0xff)) {
99163598Simp		printf("Crosses page boundary: 0x%x 0x%x\n", ee_off, size);
100163598Simp		return;
101163598Simp	}
102163598Simp
103163598Simp	status = twiPtr->TWI_SR;
104163598Simp	status = twiPtr->TWI_RHR;
105163598Simp	twiPtr->TWI_MMR = (iicaddr(ee_off) << 16) | AT91C_TWI_IADRSZ_1_BYTE |
106163598Simp	    AT91C_TWI_MREAD;
107163598Simp	twiPtr->TWI_IADR = ee_off & 0xff;
108163598Simp	twiPtr->TWI_CR = AT91C_TWI_START;
109163598Simp	while (size-- > 1) {
110163598Simp		while (!(twiPtr->TWI_SR & AT91C_TWI_RXRDY))
111163598Simp			continue;
112163598Simp		*(data_addr++) = twiPtr->TWI_RHR;
113163598Simp	}
114163598Simp	twiPtr->TWI_CR = AT91C_TWI_STOP;
115163598Simp	status = twiPtr->TWI_SR;
116163598Simp	while (!(twiPtr->TWI_SR & AT91C_TWI_TXCOMP))
117163598Simp		continue;
118163598Simp	*data_addr = twiPtr->TWI_RHR;
119163598Simp}
120163598Simp
121163598Simp
122163598Simp/*
123163598Simp * .KB_C_FN_DEFINITION_START
124163598Simp * void WriteEEPROM(unsigned ee_off, char *data_addr, unsigned size)
125163598Simp *  This global function writes data to the eeprom at ee_off using data
126163598Simp * from data_addr for size bytes.  Assume the TWI has been initialized.
127163598Simp * This function does not utilize the page write mode as the write time is
128163598Simp * much greater than the time required to access the device for byte-write
129163598Simp * functionality.  This allows the function to be much simpler.
130163598Simp * .KB_C_FN_DEFINITION_END
131163598Simp */
132163598Simpvoid
133163598SimpEEWrite(unsigned ee_off, const char *data_addr, unsigned size)
134163598Simp{
135163598Simp	const AT91PS_TWI 	twiPtr = AT91C_BASE_TWI;
136163598Simp	unsigned		status;
137163598Simp	char			test_data;
138163598Simp
139163598Simp	while (size--) {
140163598Simp		// Set the TWI Master Mode Register
141163598Simp		twiPtr->TWI_MMR = (iicaddr(ee_off) << 16) |
142163598Simp		    AT91C_TWI_IADRSZ_1_BYTE;
143163598Simp		twiPtr->TWI_IADR = ee_off++;
144163598Simp		status = twiPtr->TWI_SR;
145163598Simp
146163598Simp		// Load one data byte
147163598Simp		twiPtr->TWI_THR = *(data_addr++);
148163598Simp		twiPtr->TWI_CR = AT91C_TWI_START;
149163598Simp		while (!(twiPtr->TWI_SR & AT91C_TWI_TXRDY))
150163598Simp			continue;
151163598Simp		twiPtr->TWI_CR = AT91C_TWI_STOP;
152163598Simp		status = twiPtr->TWI_SR;
153163598Simp		while (!(twiPtr->TWI_SR & AT91C_TWI_TXCOMP))
154163598Simp			continue;
155163598Simp
156163598Simp		// wait for write operation to complete, it is done once
157163598Simp		// we can read it back...
158163598Simp		EERead(ee_off, &test_data, 1);
159163598Simp	}
160163598Simp}
161