blob: 2b3348810d2dea50dd14a425219fd176bd846b2c [file] [log] [blame]
wdenk7a8e9bed2003-05-31 18:35:21 +00001/* Three-wire (MicroWire) serial eeprom driver (for 93C46 and compatibles) */
2
3#include <common.h>
wdenk7a8e9bed2003-05-31 18:35:21 +00004
5#ifdef CONFIG_MW_EEPROM
6
Jean-Christophe PLAGNIOL-VILLARD58b74b02007-10-19 00:09:05 +02007#include <ssi.h>
8
wdenk7a8e9bed2003-05-31 18:35:21 +00009/*
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
21static int addrlen;
22
23static 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
32static int mw_eeprom_size(int dev)
33{
34 int x;
35 u16 res;
wdenk8bde7f72003-06-27 21:31:46 +000036
wdenk7a8e9bed2003-05-31 18:35:21 +000037 mw_eeprom_select(dev);
38 ssi_tx_byte(EEP_OPC_READ);
wdenk8bde7f72003-06-27 21:31:46 +000039
wdenk7a8e9bed2003-05-31 18:35:21 +000040 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);
wdenk8bde7f72003-06-27 21:31:46 +000049
wdenk7a8e9bed2003-05-31 18:35:21 +000050 return x;
51}
52
53int 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);
wdenk8bde7f72003-06-27 21:31:46 +000060
wdenk7a8e9bed2003-05-31 18:35:21 +000061 return 0;
62}
63
64int mw_eeprom_erase_disable(int dev)
wdenk8bde7f72003-06-27 21:31:46 +000065{
wdenk7a8e9bed2003-05-31 18:35:21 +000066 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);
wdenk8bde7f72003-06-27 21:31:46 +000071
wdenk7a8e9bed2003-05-31 18:35:21 +000072 return 0;
73}
74
75
76u32 mw_eeprom_read_word(int dev, int addr)
77{
78 u16 rcv;
79 u16 res;
80 int bits;
wdenk8bde7f72003-06-27 21:31:46 +000081
wdenk7a8e9bed2003-05-31 18:35:21 +000082 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;
wdenk8bde7f72003-06-27 21:31:46 +000087
wdenk7a8e9bed2003-05-31 18:35:21 +000088 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 }
wdenk8bde7f72003-06-27 21:31:46 +000097
wdenk7a8e9bed2003-05-31 18:35:21 +000098 ssi_chip_select(0);
wdenk8bde7f72003-06-27 21:31:46 +000099
wdenk7a8e9bed2003-05-31 18:35:21 +0000100 return res;
101}
102
103int mw_eeprom_write_word(int dev, int addr, u16 data)
104{
105 u8 byte1=0;
106 u8 byte2=0;
wdenk8bde7f72003-06-27 21:31:46 +0000107
wdenk7a8e9bed2003-05-31 18:35:21 +0000108 mw_eeprom_erase_enable(dev);
109 mw_eeprom_select(dev);
wdenk8bde7f72003-06-27 21:31:46 +0000110
wdenk7a8e9bed2003-05-31 18:35:21 +0000111 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;
wdenk8bde7f72003-06-27 21:31:46 +0000139
wdenk7a8e9bed2003-05-31 18:35:21 +0000140 }
wdenk8bde7f72003-06-27 21:31:46 +0000141
wdenk7a8e9bed2003-05-31 18:35:21 +0000142 ssi_tx_byte(byte1);
143 ssi_tx_byte(byte2);
wdenk8bde7f72003-06-27 21:31:46 +0000144 ssi_tx_byte(data >> 8);
wdenk7a8e9bed2003-05-31 18:35:21 +0000145 ssi_tx_byte(data & 0xff);
wdenk8bde7f72003-06-27 21:31:46 +0000146 ssi_chip_select(0);
wdenk7a8e9bed2003-05-31 18:35:21 +0000147 udelay(10000); /* Worst case */
148 mw_eeprom_erase_disable(dev);
149
150 return 0;
151}
152
153
154int mw_eeprom_write(int dev, int addr, u8 *buffer, int len)
155{
156 int done;
wdenk8bde7f72003-06-27 21:31:46 +0000157
wdenk7a8e9bed2003-05-31 18:35:21 +0000158 done = 0;
159 if (addr & 1) {
160 u16 temp = mw_eeprom_read_word(dev, addr >> 1);
161 temp &= 0xff00;
162 temp |= buffer[0];
wdenk8bde7f72003-06-27 21:31:46 +0000163
wdenk7a8e9bed2003-05-31 18:35:21 +0000164 mw_eeprom_write_word(dev, addr >> 1, temp);
165 len--;
166 addr++;
167 buffer++;
168 done++;
169 }
wdenk8bde7f72003-06-27 21:31:46 +0000170
wdenk7a8e9bed2003-05-31 18:35:21 +0000171 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;
wdenk8bde7f72003-06-27 21:31:46 +0000183
wdenk7a8e9bed2003-05-31 18:35:21 +0000184 mw_eeprom_write_word(dev, addr >> 1, temp);
185 len--;
186 addr++;
187 buffer++;
188 done++;
189 }
190
191 return done;
192}
193
194
wdenk7a8e9bed2003-05-31 18:35:21 +0000195int mw_eeprom_read(int dev, int addr, u8 *buffer, int len)
196{
197 int done;
wdenk8bde7f72003-06-27 21:31:46 +0000198
wdenk7a8e9bed2003-05-31 18:35:21 +0000199 done = 0;
200 if (addr & 1) {
201 u16 temp = mw_eeprom_read_word(dev, addr >> 1);
202 buffer[0]= temp & 0xff;
wdenk8bde7f72003-06-27 21:31:46 +0000203
wdenk7a8e9bed2003-05-31 18:35:21 +0000204 len--;
205 addr++;
206 buffer++;
207 done++;
208 }
wdenk8bde7f72003-06-27 21:31:46 +0000209
wdenk7a8e9bed2003-05-31 18:35:21 +0000210 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;
wdenk8bde7f72003-06-27 21:31:46 +0000221
wdenk7a8e9bed2003-05-31 18:35:21 +0000222 len--;
223 addr++;
224 buffer++;
225 done++;
226 }
227
228 return done;
229}
230
231int mw_eeprom_probe(int dev)
232{
233 addrlen = mw_eeprom_size(dev);
wdenk8bde7f72003-06-27 21:31:46 +0000234
wdenk7a8e9bed2003-05-31 18:35:21 +0000235 if (addrlen < 6 || addrlen > 10) {
236 return -1;
237 }
238 return 0;
239}
240
241#endif