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