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: releng/10.2/sys/boot/arm/at91/bootspi/ee.c 238463 2012-07-15 05:35:14Z imp $ 22 *****************************************************************************/ 23 24#include "at91rm9200_lowlevel.h" 25#include "at91rm9200.h" 26#include "lib.h" 27#include "ee.h" 28 29/******************************* GLOBALS *************************************/ 30 31 32/*********************** PRIVATE FUNCTIONS/DATA ******************************/ 33 34 35/* Use a macro to calculate the TWI clock generator value to save code space. */ 36#define AT91C_TWSI_CLOCK 100000 37#define TWSI_EEPROM_ADDRESS 0x40 38 39#define TWI_CLK_BASE_DIV ((AT91C_MASTER_CLOCK/(4*AT91C_TWSI_CLOCK)) - 2) 40#define SET_TWI_CLOCK ((0x00010000) | (TWI_CLK_BASE_DIV) | (TWI_CLK_BASE_DIV << 8)) 41 42 43/*************************** GLOBAL FUNCTIONS ********************************/ 44 45 46/* 47 * .KB_C_FN_DEFINITION_START 48 * void InitEEPROM(void) 49 * This global function initializes the EEPROM interface (TWI). Intended 50 * to be called a single time. 51 * .KB_C_FN_DEFINITION_END 52 */ 53void 54EEInit(void) 55{ 56 57 AT91PS_TWI twiPtr = (AT91PS_TWI)AT91C_BASE_TWI; 58 59 AT91PS_PIO pPio = (AT91PS_PIO)AT91C_BASE_PIOA; 60 AT91PS_PMC pPMC = (AT91PS_PMC)AT91C_BASE_PMC; 61 62 pPio->PIO_ASR = AT91C_PIO_PA25 | AT91C_PIO_PA26; 63 pPio->PIO_PDR = AT91C_PIO_PA25 | AT91C_PIO_PA26; 64 65 pPio->PIO_MDDR = ~AT91C_PIO_PA25; 66 pPio->PIO_MDER = AT91C_PIO_PA25; 67 68 pPMC->PMC_PCER = 1u << AT91C_ID_TWI; 69 70 twiPtr->TWI_IDR = 0xffffffffu; 71 twiPtr->TWI_CR = AT91C_TWI_SWRST; 72 twiPtr->TWI_CR = AT91C_TWI_MSEN | AT91C_TWI_SVDIS; 73 74 twiPtr->TWI_CWGR = SET_TWI_CLOCK; 75} 76 77static inline unsigned 78iicaddr(unsigned ee_off) 79{ 80 return (TWSI_EEPROM_ADDRESS | ((ee_off >> 8) & 0x7)); 81} 82 83 84/* 85 * .KB_C_FN_DEFINITION_START 86 * void ReadEEPROM(unsigned ee_addr, char *data_addr, unsigned size) 87 * This global function reads data from the eeprom at ee_addr storing data 88 * to data_addr for size bytes. Assume the TWI has been initialized. 89 * This function does not utilize the page read mode to simplify the code. 90 * .KB_C_FN_DEFINITION_END 91 */ 92void 93EERead(unsigned ee_off, char *data_addr, unsigned size) 94{ 95 const AT91PS_TWI twiPtr = AT91C_BASE_TWI; 96 unsigned int status; 97 98 if ((ee_off & ~0xff) != ((ee_off + size) & ~0xff)) { 99 printf("Crosses page boundary: 0x%x 0x%x\n", ee_off, size); 100 return; 101 } 102 103 status = twiPtr->TWI_SR; 104 status = twiPtr->TWI_RHR; 105 twiPtr->TWI_MMR = (iicaddr(ee_off) << 16) | AT91C_TWI_IADRSZ_1_BYTE | 106 AT91C_TWI_MREAD; 107 twiPtr->TWI_IADR = ee_off & 0xff; 108 twiPtr->TWI_CR = AT91C_TWI_START; 109 while (size-- > 1) { 110 while (!(twiPtr->TWI_SR & AT91C_TWI_RXRDY)) 111 continue; 112 *(data_addr++) = twiPtr->TWI_RHR; 113 } 114 twiPtr->TWI_CR = AT91C_TWI_STOP; 115 status = twiPtr->TWI_SR; 116 while (!(twiPtr->TWI_SR & AT91C_TWI_TXCOMP)) 117 continue; 118 *data_addr = twiPtr->TWI_RHR; 119} 120 121 122/* 123 * .KB_C_FN_DEFINITION_START 124 * void WriteEEPROM(unsigned ee_off, char *data_addr, unsigned size) 125 * This global function writes data to the eeprom at ee_off using data 126 * from data_addr for size bytes. Assume the TWI has been initialized. 127 * This function does not utilize the page write mode as the write time is 128 * much greater than the time required to access the device for byte-write 129 * functionality. This allows the function to be much simpler. 130 * .KB_C_FN_DEFINITION_END 131 */ 132void 133EEWrite(unsigned ee_off, const char *data_addr, unsigned size) 134{ 135 const AT91PS_TWI twiPtr = AT91C_BASE_TWI; 136 unsigned status; 137 char test_data; 138 139 while (size--) { 140 // Set the TWI Master Mode Register 141 twiPtr->TWI_MMR = (iicaddr(ee_off) << 16) | 142 AT91C_TWI_IADRSZ_1_BYTE; 143 twiPtr->TWI_IADR = ee_off++; 144 status = twiPtr->TWI_SR; 145 146 // Load one data byte 147 twiPtr->TWI_THR = *(data_addr++); 148 twiPtr->TWI_CR = AT91C_TWI_START; 149 while (!(twiPtr->TWI_SR & AT91C_TWI_TXRDY)) 150 continue; 151 twiPtr->TWI_CR = AT91C_TWI_STOP; 152 status = twiPtr->TWI_SR; 153 while (!(twiPtr->TWI_SR & AT91C_TWI_TXCOMP)) 154 continue; 155 156 // wait for write operation to complete, it is done once 157 // we can read it back... 158 EERead(ee_off, &test_data, 1); 159 } 160} 161