1 /* Three-wire (MicroWire) serial eeprom driver (for 93C46 and compatibles) */ 2 3 #include <common.h> 4 5 #ifdef CONFIG_MW_EEPROM 6 7 #include <ssi.h> 8 9 /* 10 * Serial EEPROM opcodes, including start bit 11 */ 12 #define EEP_OPC_ERASE 0x7 /* 3-bit opcode */ 13 #define EEP_OPC_WRITE 0x5 /* 3-bit opcode */ 14 #define EEP_OPC_READ 0x6 /* 3-bit opcode */ 15 16 #define EEP_OPC_ERASE_ALL 0x12 /* 5-bit opcode */ 17 #define EEP_OPC_ERASE_EN 0x13 /* 5-bit opcode */ 18 #define EEP_OPC_WRITE_ALL 0x11 /* 5-bit opcode */ 19 #define EEP_OPC_ERASE_DIS 0x10 /* 5-bit opcode */ 20 21 static int addrlen; 22 23 static void mw_eeprom_select(int dev) 24 { 25 ssi_set_interface(2048, 0, 0, 0); 26 ssi_chip_select(0); 27 udelay(1); 28 ssi_chip_select(dev); 29 udelay(1); 30 } 31 32 static int mw_eeprom_size(int dev) 33 { 34 int x; 35 u16 res; 36 37 mw_eeprom_select(dev); 38 ssi_tx_byte(EEP_OPC_READ); 39 40 res = ssi_txrx_byte(0) << 8; 41 res |= ssi_rx_byte(); 42 for (x = 0; x < 16; x++) { 43 if (! (res & 0x8000)) { 44 break; 45 } 46 res <<= 1; 47 } 48 ssi_chip_select(0); 49 50 return x; 51 } 52 53 int mw_eeprom_erase_enable(int dev) 54 { 55 mw_eeprom_select(dev); 56 ssi_tx_byte(EEP_OPC_ERASE_EN); 57 ssi_tx_byte(0); 58 udelay(1); 59 ssi_chip_select(0); 60 61 return 0; 62 } 63 64 int mw_eeprom_erase_disable(int dev) 65 { 66 mw_eeprom_select(dev); 67 ssi_tx_byte(EEP_OPC_ERASE_DIS); 68 ssi_tx_byte(0); 69 udelay(1); 70 ssi_chip_select(0); 71 72 return 0; 73 } 74 75 76 u32 mw_eeprom_read_word(int dev, int addr) 77 { 78 u16 rcv; 79 u16 res; 80 int bits; 81 82 mw_eeprom_select(dev); 83 ssi_tx_byte((EEP_OPC_READ << 5) | ((addr >> (addrlen - 5)) & 0x1f)); 84 rcv = ssi_txrx_byte(addr << (13 - addrlen)); 85 res = rcv << (16 - addrlen); 86 bits = 4 + addrlen; 87 88 while (bits>0) { 89 rcv = ssi_rx_byte(); 90 if (bits > 7) { 91 res |= rcv << (bits - 8); 92 } else { 93 res |= rcv >> (8 - bits); 94 } 95 bits -= 8; 96 } 97 98 ssi_chip_select(0); 99 100 return res; 101 } 102 103 int mw_eeprom_write_word(int dev, int addr, u16 data) 104 { 105 u8 byte1=0; 106 u8 byte2=0; 107 108 mw_eeprom_erase_enable(dev); 109 mw_eeprom_select(dev); 110 111 switch (addrlen) { 112 case 6: 113 byte1 = EEP_OPC_WRITE >> 2; 114 byte2 = (EEP_OPC_WRITE << 6)&0xc0; 115 byte2 |= addr; 116 break; 117 case 7: 118 byte1 = EEP_OPC_WRITE >> 1; 119 byte2 = (EEP_OPC_WRITE << 7)&0x80; 120 byte2 |= addr; 121 break; 122 case 8: 123 byte1 = EEP_OPC_WRITE; 124 byte2 = addr; 125 break; 126 case 9: 127 byte1 = EEP_OPC_WRITE << 1; 128 byte1 |= addr >> 8; 129 byte2 = addr & 0xff; 130 break; 131 case 10: 132 byte1 = EEP_OPC_WRITE << 2; 133 byte1 |= addr >> 8; 134 byte2 = addr & 0xff; 135 break; 136 default: 137 printf("Unsupported number of address bits: %d\n", addrlen); 138 return -1; 139 140 } 141 142 ssi_tx_byte(byte1); 143 ssi_tx_byte(byte2); 144 ssi_tx_byte(data >> 8); 145 ssi_tx_byte(data & 0xff); 146 ssi_chip_select(0); 147 udelay(10000); /* Worst case */ 148 mw_eeprom_erase_disable(dev); 149 150 return 0; 151 } 152 153 154 int mw_eeprom_write(int dev, int addr, u8 *buffer, int len) 155 { 156 int done; 157 158 done = 0; 159 if (addr & 1) { 160 u16 temp = mw_eeprom_read_word(dev, addr >> 1); 161 temp &= 0xff00; 162 temp |= buffer[0]; 163 164 mw_eeprom_write_word(dev, addr >> 1, temp); 165 len--; 166 addr++; 167 buffer++; 168 done++; 169 } 170 171 while (len <= 2) { 172 mw_eeprom_write_word(dev, addr >> 1, *(u16*)buffer); 173 len-=2; 174 addr+=2; 175 buffer+=2; 176 done+=2; 177 } 178 179 if (len) { 180 u16 temp = mw_eeprom_read_word(dev, addr >> 1); 181 temp &= 0x00ff; 182 temp |= buffer[0] << 8; 183 184 mw_eeprom_write_word(dev, addr >> 1, temp); 185 len--; 186 addr++; 187 buffer++; 188 done++; 189 } 190 191 return done; 192 } 193 194 195 int mw_eeprom_read(int dev, int addr, u8 *buffer, int len) 196 { 197 int done; 198 199 done = 0; 200 if (addr & 1) { 201 u16 temp = mw_eeprom_read_word(dev, addr >> 1); 202 buffer[0]= temp & 0xff; 203 204 len--; 205 addr++; 206 buffer++; 207 done++; 208 } 209 210 while (len <= 2) { 211 *(u16*)buffer = mw_eeprom_read_word(dev, addr >> 1); 212 len-=2; 213 addr+=2; 214 buffer+=2; 215 done+=2; 216 } 217 218 if (len) { 219 u16 temp = mw_eeprom_read_word(dev, addr >> 1); 220 buffer[0] = temp >> 8; 221 222 len--; 223 addr++; 224 buffer++; 225 done++; 226 } 227 228 return done; 229 } 230 231 int mw_eeprom_probe(int dev) 232 { 233 addrlen = mw_eeprom_size(dev); 234 235 if (addrlen < 6 || addrlen > 10) { 236 return -1; 237 } 238 return 0; 239 } 240 241 #endif 242