159829cc1SJean-Christophe PLAGNIOL-VILLARD /* Three-wire (MicroWire) serial eeprom driver (for 93C46 and compatibles) */ 259829cc1SJean-Christophe PLAGNIOL-VILLARD 359829cc1SJean-Christophe PLAGNIOL-VILLARD #include <common.h> 4*3ef96dedSGraeme Russ #include <asm/ic/ssi.h> 559829cc1SJean-Christophe PLAGNIOL-VILLARD 659829cc1SJean-Christophe PLAGNIOL-VILLARD /* 759829cc1SJean-Christophe PLAGNIOL-VILLARD * Serial EEPROM opcodes, including start bit 859829cc1SJean-Christophe PLAGNIOL-VILLARD */ 959829cc1SJean-Christophe PLAGNIOL-VILLARD #define EEP_OPC_ERASE 0x7 /* 3-bit opcode */ 1059829cc1SJean-Christophe PLAGNIOL-VILLARD #define EEP_OPC_WRITE 0x5 /* 3-bit opcode */ 1159829cc1SJean-Christophe PLAGNIOL-VILLARD #define EEP_OPC_READ 0x6 /* 3-bit opcode */ 1259829cc1SJean-Christophe PLAGNIOL-VILLARD 1359829cc1SJean-Christophe PLAGNIOL-VILLARD #define EEP_OPC_ERASE_ALL 0x12 /* 5-bit opcode */ 1459829cc1SJean-Christophe PLAGNIOL-VILLARD #define EEP_OPC_ERASE_EN 0x13 /* 5-bit opcode */ 1559829cc1SJean-Christophe PLAGNIOL-VILLARD #define EEP_OPC_WRITE_ALL 0x11 /* 5-bit opcode */ 1659829cc1SJean-Christophe PLAGNIOL-VILLARD #define EEP_OPC_ERASE_DIS 0x10 /* 5-bit opcode */ 1759829cc1SJean-Christophe PLAGNIOL-VILLARD 1859829cc1SJean-Christophe PLAGNIOL-VILLARD static int addrlen; 1959829cc1SJean-Christophe PLAGNIOL-VILLARD 2059829cc1SJean-Christophe PLAGNIOL-VILLARD static void mw_eeprom_select(int dev) 2159829cc1SJean-Christophe PLAGNIOL-VILLARD { 2259829cc1SJean-Christophe PLAGNIOL-VILLARD ssi_set_interface(2048, 0, 0, 0); 2359829cc1SJean-Christophe PLAGNIOL-VILLARD ssi_chip_select(0); 2459829cc1SJean-Christophe PLAGNIOL-VILLARD udelay(1); 2559829cc1SJean-Christophe PLAGNIOL-VILLARD ssi_chip_select(dev); 2659829cc1SJean-Christophe PLAGNIOL-VILLARD udelay(1); 2759829cc1SJean-Christophe PLAGNIOL-VILLARD } 2859829cc1SJean-Christophe PLAGNIOL-VILLARD 2959829cc1SJean-Christophe PLAGNIOL-VILLARD static int mw_eeprom_size(int dev) 3059829cc1SJean-Christophe PLAGNIOL-VILLARD { 3159829cc1SJean-Christophe PLAGNIOL-VILLARD int x; 3259829cc1SJean-Christophe PLAGNIOL-VILLARD u16 res; 3359829cc1SJean-Christophe PLAGNIOL-VILLARD 3459829cc1SJean-Christophe PLAGNIOL-VILLARD mw_eeprom_select(dev); 3559829cc1SJean-Christophe PLAGNIOL-VILLARD ssi_tx_byte(EEP_OPC_READ); 3659829cc1SJean-Christophe PLAGNIOL-VILLARD 3759829cc1SJean-Christophe PLAGNIOL-VILLARD res = ssi_txrx_byte(0) << 8; 3859829cc1SJean-Christophe PLAGNIOL-VILLARD res |= ssi_rx_byte(); 3959829cc1SJean-Christophe PLAGNIOL-VILLARD for (x = 0; x < 16; x++) { 4059829cc1SJean-Christophe PLAGNIOL-VILLARD if (! (res & 0x8000)) { 4159829cc1SJean-Christophe PLAGNIOL-VILLARD break; 4259829cc1SJean-Christophe PLAGNIOL-VILLARD } 4359829cc1SJean-Christophe PLAGNIOL-VILLARD res <<= 1; 4459829cc1SJean-Christophe PLAGNIOL-VILLARD } 4559829cc1SJean-Christophe PLAGNIOL-VILLARD ssi_chip_select(0); 4659829cc1SJean-Christophe PLAGNIOL-VILLARD 4759829cc1SJean-Christophe PLAGNIOL-VILLARD return x; 4859829cc1SJean-Christophe PLAGNIOL-VILLARD } 4959829cc1SJean-Christophe PLAGNIOL-VILLARD 5059829cc1SJean-Christophe PLAGNIOL-VILLARD int mw_eeprom_erase_enable(int dev) 5159829cc1SJean-Christophe PLAGNIOL-VILLARD { 5259829cc1SJean-Christophe PLAGNIOL-VILLARD mw_eeprom_select(dev); 5359829cc1SJean-Christophe PLAGNIOL-VILLARD ssi_tx_byte(EEP_OPC_ERASE_EN); 5459829cc1SJean-Christophe PLAGNIOL-VILLARD ssi_tx_byte(0); 5559829cc1SJean-Christophe PLAGNIOL-VILLARD udelay(1); 5659829cc1SJean-Christophe PLAGNIOL-VILLARD ssi_chip_select(0); 5759829cc1SJean-Christophe PLAGNIOL-VILLARD 5859829cc1SJean-Christophe PLAGNIOL-VILLARD return 0; 5959829cc1SJean-Christophe PLAGNIOL-VILLARD } 6059829cc1SJean-Christophe PLAGNIOL-VILLARD 6159829cc1SJean-Christophe PLAGNIOL-VILLARD int mw_eeprom_erase_disable(int dev) 6259829cc1SJean-Christophe PLAGNIOL-VILLARD { 6359829cc1SJean-Christophe PLAGNIOL-VILLARD mw_eeprom_select(dev); 6459829cc1SJean-Christophe PLAGNIOL-VILLARD ssi_tx_byte(EEP_OPC_ERASE_DIS); 6559829cc1SJean-Christophe PLAGNIOL-VILLARD ssi_tx_byte(0); 6659829cc1SJean-Christophe PLAGNIOL-VILLARD udelay(1); 6759829cc1SJean-Christophe PLAGNIOL-VILLARD ssi_chip_select(0); 6859829cc1SJean-Christophe PLAGNIOL-VILLARD 6959829cc1SJean-Christophe PLAGNIOL-VILLARD return 0; 7059829cc1SJean-Christophe PLAGNIOL-VILLARD } 7159829cc1SJean-Christophe PLAGNIOL-VILLARD 7259829cc1SJean-Christophe PLAGNIOL-VILLARD 7359829cc1SJean-Christophe PLAGNIOL-VILLARD u32 mw_eeprom_read_word(int dev, int addr) 7459829cc1SJean-Christophe PLAGNIOL-VILLARD { 7559829cc1SJean-Christophe PLAGNIOL-VILLARD u16 rcv; 7659829cc1SJean-Christophe PLAGNIOL-VILLARD u16 res; 7759829cc1SJean-Christophe PLAGNIOL-VILLARD int bits; 7859829cc1SJean-Christophe PLAGNIOL-VILLARD 7959829cc1SJean-Christophe PLAGNIOL-VILLARD mw_eeprom_select(dev); 8059829cc1SJean-Christophe PLAGNIOL-VILLARD ssi_tx_byte((EEP_OPC_READ << 5) | ((addr >> (addrlen - 5)) & 0x1f)); 8159829cc1SJean-Christophe PLAGNIOL-VILLARD rcv = ssi_txrx_byte(addr << (13 - addrlen)); 8259829cc1SJean-Christophe PLAGNIOL-VILLARD res = rcv << (16 - addrlen); 8359829cc1SJean-Christophe PLAGNIOL-VILLARD bits = 4 + addrlen; 8459829cc1SJean-Christophe PLAGNIOL-VILLARD 8559829cc1SJean-Christophe PLAGNIOL-VILLARD while (bits>0) { 8659829cc1SJean-Christophe PLAGNIOL-VILLARD rcv = ssi_rx_byte(); 8759829cc1SJean-Christophe PLAGNIOL-VILLARD if (bits > 7) { 8859829cc1SJean-Christophe PLAGNIOL-VILLARD res |= rcv << (bits - 8); 8959829cc1SJean-Christophe PLAGNIOL-VILLARD } else { 9059829cc1SJean-Christophe PLAGNIOL-VILLARD res |= rcv >> (8 - bits); 9159829cc1SJean-Christophe PLAGNIOL-VILLARD } 9259829cc1SJean-Christophe PLAGNIOL-VILLARD bits -= 8; 9359829cc1SJean-Christophe PLAGNIOL-VILLARD } 9459829cc1SJean-Christophe PLAGNIOL-VILLARD 9559829cc1SJean-Christophe PLAGNIOL-VILLARD ssi_chip_select(0); 9659829cc1SJean-Christophe PLAGNIOL-VILLARD 9759829cc1SJean-Christophe PLAGNIOL-VILLARD return res; 9859829cc1SJean-Christophe PLAGNIOL-VILLARD } 9959829cc1SJean-Christophe PLAGNIOL-VILLARD 10059829cc1SJean-Christophe PLAGNIOL-VILLARD int mw_eeprom_write_word(int dev, int addr, u16 data) 10159829cc1SJean-Christophe PLAGNIOL-VILLARD { 10259829cc1SJean-Christophe PLAGNIOL-VILLARD u8 byte1=0; 10359829cc1SJean-Christophe PLAGNIOL-VILLARD u8 byte2=0; 10459829cc1SJean-Christophe PLAGNIOL-VILLARD 10559829cc1SJean-Christophe PLAGNIOL-VILLARD mw_eeprom_erase_enable(dev); 10659829cc1SJean-Christophe PLAGNIOL-VILLARD mw_eeprom_select(dev); 10759829cc1SJean-Christophe PLAGNIOL-VILLARD 10859829cc1SJean-Christophe PLAGNIOL-VILLARD switch (addrlen) { 10959829cc1SJean-Christophe PLAGNIOL-VILLARD case 6: 11059829cc1SJean-Christophe PLAGNIOL-VILLARD byte1 = EEP_OPC_WRITE >> 2; 11159829cc1SJean-Christophe PLAGNIOL-VILLARD byte2 = (EEP_OPC_WRITE << 6)&0xc0; 11259829cc1SJean-Christophe PLAGNIOL-VILLARD byte2 |= addr; 11359829cc1SJean-Christophe PLAGNIOL-VILLARD break; 11459829cc1SJean-Christophe PLAGNIOL-VILLARD case 7: 11559829cc1SJean-Christophe PLAGNIOL-VILLARD byte1 = EEP_OPC_WRITE >> 1; 11659829cc1SJean-Christophe PLAGNIOL-VILLARD byte2 = (EEP_OPC_WRITE << 7)&0x80; 11759829cc1SJean-Christophe PLAGNIOL-VILLARD byte2 |= addr; 11859829cc1SJean-Christophe PLAGNIOL-VILLARD break; 11959829cc1SJean-Christophe PLAGNIOL-VILLARD case 8: 12059829cc1SJean-Christophe PLAGNIOL-VILLARD byte1 = EEP_OPC_WRITE; 12159829cc1SJean-Christophe PLAGNIOL-VILLARD byte2 = addr; 12259829cc1SJean-Christophe PLAGNIOL-VILLARD break; 12359829cc1SJean-Christophe PLAGNIOL-VILLARD case 9: 12459829cc1SJean-Christophe PLAGNIOL-VILLARD byte1 = EEP_OPC_WRITE << 1; 12559829cc1SJean-Christophe PLAGNIOL-VILLARD byte1 |= addr >> 8; 12659829cc1SJean-Christophe PLAGNIOL-VILLARD byte2 = addr & 0xff; 12759829cc1SJean-Christophe PLAGNIOL-VILLARD break; 12859829cc1SJean-Christophe PLAGNIOL-VILLARD case 10: 12959829cc1SJean-Christophe PLAGNIOL-VILLARD byte1 = EEP_OPC_WRITE << 2; 13059829cc1SJean-Christophe PLAGNIOL-VILLARD byte1 |= addr >> 8; 13159829cc1SJean-Christophe PLAGNIOL-VILLARD byte2 = addr & 0xff; 13259829cc1SJean-Christophe PLAGNIOL-VILLARD break; 13359829cc1SJean-Christophe PLAGNIOL-VILLARD default: 13459829cc1SJean-Christophe PLAGNIOL-VILLARD printf("Unsupported number of address bits: %d\n", addrlen); 13559829cc1SJean-Christophe PLAGNIOL-VILLARD return -1; 13659829cc1SJean-Christophe PLAGNIOL-VILLARD 13759829cc1SJean-Christophe PLAGNIOL-VILLARD } 13859829cc1SJean-Christophe PLAGNIOL-VILLARD 13959829cc1SJean-Christophe PLAGNIOL-VILLARD ssi_tx_byte(byte1); 14059829cc1SJean-Christophe PLAGNIOL-VILLARD ssi_tx_byte(byte2); 14159829cc1SJean-Christophe PLAGNIOL-VILLARD ssi_tx_byte(data >> 8); 14259829cc1SJean-Christophe PLAGNIOL-VILLARD ssi_tx_byte(data & 0xff); 14359829cc1SJean-Christophe PLAGNIOL-VILLARD ssi_chip_select(0); 14459829cc1SJean-Christophe PLAGNIOL-VILLARD udelay(10000); /* Worst case */ 14559829cc1SJean-Christophe PLAGNIOL-VILLARD mw_eeprom_erase_disable(dev); 14659829cc1SJean-Christophe PLAGNIOL-VILLARD 14759829cc1SJean-Christophe PLAGNIOL-VILLARD return 0; 14859829cc1SJean-Christophe PLAGNIOL-VILLARD } 14959829cc1SJean-Christophe PLAGNIOL-VILLARD 15059829cc1SJean-Christophe PLAGNIOL-VILLARD 15159829cc1SJean-Christophe PLAGNIOL-VILLARD int mw_eeprom_write(int dev, int addr, u8 *buffer, int len) 15259829cc1SJean-Christophe PLAGNIOL-VILLARD { 15359829cc1SJean-Christophe PLAGNIOL-VILLARD int done; 15459829cc1SJean-Christophe PLAGNIOL-VILLARD 15559829cc1SJean-Christophe PLAGNIOL-VILLARD done = 0; 15659829cc1SJean-Christophe PLAGNIOL-VILLARD if (addr & 1) { 15759829cc1SJean-Christophe PLAGNIOL-VILLARD u16 temp = mw_eeprom_read_word(dev, addr >> 1); 15859829cc1SJean-Christophe PLAGNIOL-VILLARD temp &= 0xff00; 15959829cc1SJean-Christophe PLAGNIOL-VILLARD temp |= buffer[0]; 16059829cc1SJean-Christophe PLAGNIOL-VILLARD 16159829cc1SJean-Christophe PLAGNIOL-VILLARD mw_eeprom_write_word(dev, addr >> 1, temp); 16259829cc1SJean-Christophe PLAGNIOL-VILLARD len--; 16359829cc1SJean-Christophe PLAGNIOL-VILLARD addr++; 16459829cc1SJean-Christophe PLAGNIOL-VILLARD buffer++; 16559829cc1SJean-Christophe PLAGNIOL-VILLARD done++; 16659829cc1SJean-Christophe PLAGNIOL-VILLARD } 16759829cc1SJean-Christophe PLAGNIOL-VILLARD 16859829cc1SJean-Christophe PLAGNIOL-VILLARD while (len <= 2) { 16959829cc1SJean-Christophe PLAGNIOL-VILLARD mw_eeprom_write_word(dev, addr >> 1, *(u16*)buffer); 17059829cc1SJean-Christophe PLAGNIOL-VILLARD len-=2; 17159829cc1SJean-Christophe PLAGNIOL-VILLARD addr+=2; 17259829cc1SJean-Christophe PLAGNIOL-VILLARD buffer+=2; 17359829cc1SJean-Christophe PLAGNIOL-VILLARD done+=2; 17459829cc1SJean-Christophe PLAGNIOL-VILLARD } 17559829cc1SJean-Christophe PLAGNIOL-VILLARD 17659829cc1SJean-Christophe PLAGNIOL-VILLARD if (len) { 17759829cc1SJean-Christophe PLAGNIOL-VILLARD u16 temp = mw_eeprom_read_word(dev, addr >> 1); 17859829cc1SJean-Christophe PLAGNIOL-VILLARD temp &= 0x00ff; 17959829cc1SJean-Christophe PLAGNIOL-VILLARD temp |= buffer[0] << 8; 18059829cc1SJean-Christophe PLAGNIOL-VILLARD 18159829cc1SJean-Christophe PLAGNIOL-VILLARD mw_eeprom_write_word(dev, addr >> 1, temp); 18259829cc1SJean-Christophe PLAGNIOL-VILLARD len--; 18359829cc1SJean-Christophe PLAGNIOL-VILLARD addr++; 18459829cc1SJean-Christophe PLAGNIOL-VILLARD buffer++; 18559829cc1SJean-Christophe PLAGNIOL-VILLARD done++; 18659829cc1SJean-Christophe PLAGNIOL-VILLARD } 18759829cc1SJean-Christophe PLAGNIOL-VILLARD 18859829cc1SJean-Christophe PLAGNIOL-VILLARD return done; 18959829cc1SJean-Christophe PLAGNIOL-VILLARD } 19059829cc1SJean-Christophe PLAGNIOL-VILLARD 19159829cc1SJean-Christophe PLAGNIOL-VILLARD 19259829cc1SJean-Christophe PLAGNIOL-VILLARD int mw_eeprom_read(int dev, int addr, u8 *buffer, int len) 19359829cc1SJean-Christophe PLAGNIOL-VILLARD { 19459829cc1SJean-Christophe PLAGNIOL-VILLARD int done; 19559829cc1SJean-Christophe PLAGNIOL-VILLARD 19659829cc1SJean-Christophe PLAGNIOL-VILLARD done = 0; 19759829cc1SJean-Christophe PLAGNIOL-VILLARD if (addr & 1) { 19859829cc1SJean-Christophe PLAGNIOL-VILLARD u16 temp = mw_eeprom_read_word(dev, addr >> 1); 19959829cc1SJean-Christophe PLAGNIOL-VILLARD buffer[0]= temp & 0xff; 20059829cc1SJean-Christophe PLAGNIOL-VILLARD 20159829cc1SJean-Christophe PLAGNIOL-VILLARD len--; 20259829cc1SJean-Christophe PLAGNIOL-VILLARD addr++; 20359829cc1SJean-Christophe PLAGNIOL-VILLARD buffer++; 20459829cc1SJean-Christophe PLAGNIOL-VILLARD done++; 20559829cc1SJean-Christophe PLAGNIOL-VILLARD } 20659829cc1SJean-Christophe PLAGNIOL-VILLARD 20759829cc1SJean-Christophe PLAGNIOL-VILLARD while (len <= 2) { 20859829cc1SJean-Christophe PLAGNIOL-VILLARD *(u16*)buffer = mw_eeprom_read_word(dev, addr >> 1); 20959829cc1SJean-Christophe PLAGNIOL-VILLARD len-=2; 21059829cc1SJean-Christophe PLAGNIOL-VILLARD addr+=2; 21159829cc1SJean-Christophe PLAGNIOL-VILLARD buffer+=2; 21259829cc1SJean-Christophe PLAGNIOL-VILLARD done+=2; 21359829cc1SJean-Christophe PLAGNIOL-VILLARD } 21459829cc1SJean-Christophe PLAGNIOL-VILLARD 21559829cc1SJean-Christophe PLAGNIOL-VILLARD if (len) { 21659829cc1SJean-Christophe PLAGNIOL-VILLARD u16 temp = mw_eeprom_read_word(dev, addr >> 1); 21759829cc1SJean-Christophe PLAGNIOL-VILLARD buffer[0] = temp >> 8; 21859829cc1SJean-Christophe PLAGNIOL-VILLARD 21959829cc1SJean-Christophe PLAGNIOL-VILLARD len--; 22059829cc1SJean-Christophe PLAGNIOL-VILLARD addr++; 22159829cc1SJean-Christophe PLAGNIOL-VILLARD buffer++; 22259829cc1SJean-Christophe PLAGNIOL-VILLARD done++; 22359829cc1SJean-Christophe PLAGNIOL-VILLARD } 22459829cc1SJean-Christophe PLAGNIOL-VILLARD 22559829cc1SJean-Christophe PLAGNIOL-VILLARD return done; 22659829cc1SJean-Christophe PLAGNIOL-VILLARD } 22759829cc1SJean-Christophe PLAGNIOL-VILLARD 22859829cc1SJean-Christophe PLAGNIOL-VILLARD int mw_eeprom_probe(int dev) 22959829cc1SJean-Christophe PLAGNIOL-VILLARD { 23059829cc1SJean-Christophe PLAGNIOL-VILLARD addrlen = mw_eeprom_size(dev); 23159829cc1SJean-Christophe PLAGNIOL-VILLARD 23259829cc1SJean-Christophe PLAGNIOL-VILLARD if (addrlen < 6 || addrlen > 10) { 23359829cc1SJean-Christophe PLAGNIOL-VILLARD return -1; 23459829cc1SJean-Christophe PLAGNIOL-VILLARD } 23559829cc1SJean-Christophe PLAGNIOL-VILLARD return 0; 23659829cc1SJean-Christophe PLAGNIOL-VILLARD } 237