diff options
Diffstat (limited to 'drivers/mw_eeprom.c')
| -rw-r--r-- | drivers/mw_eeprom.c | 242 | 
1 files changed, 242 insertions, 0 deletions
| diff --git a/drivers/mw_eeprom.c b/drivers/mw_eeprom.c new file mode 100644 index 000000000..30a51fa05 --- /dev/null +++ b/drivers/mw_eeprom.c @@ -0,0 +1,242 @@ +/* Three-wire (MicroWire) serial eeprom driver (for 93C46 and compatibles) */ + +#include <common.h> +#include <ssi.h> + + +#ifdef CONFIG_MW_EEPROM + +/* + * Serial EEPROM opcodes, including start bit + */ +#define EEP_OPC_ERASE	0x7  /* 3-bit opcode */ +#define EEP_OPC_WRITE	0x5  /* 3-bit opcode */ +#define EEP_OPC_READ	        0x6  /* 3-bit opcode */ + +#define EEP_OPC_ERASE_ALL	0x12 /* 5-bit opcode */ +#define EEP_OPC_ERASE_EN	0x13 /* 5-bit opcode */ +#define EEP_OPC_WRITE_ALL	0x11 /* 5-bit opcode */ +#define EEP_OPC_ERASE_DIS	0x10 /* 5-bit opcode */ + +static int addrlen; + +static void mw_eeprom_select(int dev) +{ +	ssi_set_interface(2048, 0, 0, 0); +	ssi_chip_select(0); +	udelay(1); +	ssi_chip_select(dev); +	udelay(1); +} + +static int mw_eeprom_size(int dev) +{ +	int x; +	u16 res; +		 +	mw_eeprom_select(dev); +	ssi_tx_byte(EEP_OPC_READ); +	 +	res = ssi_txrx_byte(0) << 8; +	res |= ssi_rx_byte(); +	for (x = 0; x < 16; x++) { +		if (! (res & 0x8000)) { +			break; +		} +		res <<= 1; +	} +	ssi_chip_select(0); +	 +	return x; +} + +int mw_eeprom_erase_enable(int dev) +{ +	mw_eeprom_select(dev); +	ssi_tx_byte(EEP_OPC_ERASE_EN); +	ssi_tx_byte(0); +	udelay(1); +	ssi_chip_select(0); +		 +	return 0; +} + +int mw_eeprom_erase_disable(int dev) +{	 +	mw_eeprom_select(dev); +	ssi_tx_byte(EEP_OPC_ERASE_DIS); +	ssi_tx_byte(0); +	udelay(1); +	ssi_chip_select(0); +		 +	return 0; +} + + +u32 mw_eeprom_read_word(int dev, int addr) +{ +	u16 rcv; +	u16 res; +	int bits; +	 +	mw_eeprom_select(dev); +	ssi_tx_byte((EEP_OPC_READ << 5) | ((addr >> (addrlen - 5)) & 0x1f)); +	rcv = ssi_txrx_byte(addr << (13 - addrlen)); +	res = rcv << (16 - addrlen); +	bits = 4 + addrlen; +	 +	while (bits>0) { +		rcv = ssi_rx_byte(); +		if (bits > 7) { +			res |= rcv << (bits - 8); +		} else { +			res |= rcv >> (8 - bits); +		} +		bits -= 8; +	} +	 +	ssi_chip_select(0); +	 +	return res; +} + +int mw_eeprom_write_word(int dev, int addr, u16 data) +{ +	u8 byte1=0; +	u8 byte2=0; +	 +	mw_eeprom_erase_enable(dev); +	mw_eeprom_select(dev); +	 +	switch (addrlen) { +	 case 6: +		byte1 = EEP_OPC_WRITE >> 2; +		byte2 = (EEP_OPC_WRITE << 6)&0xc0; +		byte2 |= addr; +		break; +	 case 7: +		byte1 = EEP_OPC_WRITE >> 1; +		byte2 = (EEP_OPC_WRITE << 7)&0x80; +		byte2 |= addr; +		break; +	 case 8: +		byte1 = EEP_OPC_WRITE; +		byte2 = addr; +		break; +	 case 9: +		byte1 = EEP_OPC_WRITE << 1; +		byte1 |= addr >> 8; +		byte2 = addr & 0xff; +		break; +	 case 10: +		byte1 = EEP_OPC_WRITE << 2; +		byte1 |= addr >> 8; +		byte2 = addr & 0xff; +		break; +	 default: +		printf("Unsupported number of address bits: %d\n", addrlen); +		return -1; +		 +	} +	 +	ssi_tx_byte(byte1); +	ssi_tx_byte(byte2); +	ssi_tx_byte(data >> 8);	 +	ssi_tx_byte(data & 0xff); +	ssi_chip_select(0);	 +	udelay(10000); /* Worst case */ +	mw_eeprom_erase_disable(dev); + +	return 0; +} + + +int mw_eeprom_write(int dev, int addr, u8 *buffer, int len) +{ +	int done; +	 +	done = 0; +	if (addr & 1) { +		u16 temp = mw_eeprom_read_word(dev, addr >> 1); +		temp &= 0xff00; +		temp |= buffer[0]; +		 +		mw_eeprom_write_word(dev, addr >> 1, temp); +		len--; +		addr++; +		buffer++; +		done++; +	} +	 +	while (len <= 2) { +		mw_eeprom_write_word(dev, addr >> 1, *(u16*)buffer); +		len-=2; +		addr+=2; +		buffer+=2; +		done+=2; +	} + +	if (len) { +		u16 temp = mw_eeprom_read_word(dev, addr >> 1); +		temp &= 0x00ff; +		temp |= buffer[0] << 8; +		 +		mw_eeprom_write_word(dev, addr >> 1, temp); +		len--; +		addr++; +		buffer++; +		done++; +	} + +	return done; +} + + + +int mw_eeprom_read(int dev, int addr, u8 *buffer, int len) +{ +	int done; +	 +	done = 0; +	if (addr & 1) { +		u16 temp = mw_eeprom_read_word(dev, addr >> 1); +		buffer[0]= temp & 0xff; +		 +		len--; +		addr++; +		buffer++; +		done++; +	} +	 +	while (len <= 2) { +		*(u16*)buffer = mw_eeprom_read_word(dev, addr >> 1); +		len-=2; +		addr+=2; +		buffer+=2; +		done+=2; +	} + +	if (len) { +		u16 temp = mw_eeprom_read_word(dev, addr >> 1); +		buffer[0] = temp >> 8; +		 +		len--; +		addr++; +		buffer++; +		done++; +	} + +	return done; +} + +int mw_eeprom_probe(int dev) +{ +	addrlen = mw_eeprom_size(dev); +	 +	if (addrlen < 6 || addrlen > 10) { +		return -1; +	} +	return 0; +} + +#endif |