]>
Commit | Line | Data |
---|---|---|
7a8e9bed WD |
1 | /* Three-wire (MicroWire) serial eeprom driver (for 93C46 and compatibles) */ |
2 | ||
3 | #include <common.h> | |
3ef96ded | 4 | #include <asm/ic/ssi.h> |
58b74b05 | 5 | |
7a8e9bed WD |
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; | |
8bde7f77 | 33 | |
7a8e9bed WD |
34 | mw_eeprom_select(dev); |
35 | ssi_tx_byte(EEP_OPC_READ); | |
8bde7f77 | 36 | |
7a8e9bed WD |
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); | |
8bde7f77 | 46 | |
7a8e9bed WD |
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); | |
8bde7f77 | 57 | |
7a8e9bed WD |
58 | return 0; |
59 | } | |
60 | ||
61 | int mw_eeprom_erase_disable(int dev) | |
8bde7f77 | 62 | { |
7a8e9bed WD |
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); | |
8bde7f77 | 68 | |
7a8e9bed WD |
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; | |
8bde7f77 | 78 | |
7a8e9bed WD |
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; | |
8bde7f77 | 84 | |
7a8e9bed WD |
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 | } | |
8bde7f77 | 94 | |
7a8e9bed | 95 | ssi_chip_select(0); |
8bde7f77 | 96 | |
7a8e9bed WD |
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; | |
8bde7f77 | 104 | |
7a8e9bed WD |
105 | mw_eeprom_erase_enable(dev); |
106 | mw_eeprom_select(dev); | |
8bde7f77 | 107 | |
7a8e9bed WD |
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; | |
8bde7f77 | 136 | |
7a8e9bed | 137 | } |
8bde7f77 | 138 | |
7a8e9bed WD |
139 | ssi_tx_byte(byte1); |
140 | ssi_tx_byte(byte2); | |
8bde7f77 | 141 | ssi_tx_byte(data >> 8); |
7a8e9bed | 142 | ssi_tx_byte(data & 0xff); |
8bde7f77 | 143 | ssi_chip_select(0); |
7a8e9bed WD |
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; | |
8bde7f77 | 154 | |
7a8e9bed WD |
155 | done = 0; |
156 | if (addr & 1) { | |
157 | u16 temp = mw_eeprom_read_word(dev, addr >> 1); | |
158 | temp &= 0xff00; | |
159 | temp |= buffer[0]; | |
8bde7f77 | 160 | |
7a8e9bed WD |
161 | mw_eeprom_write_word(dev, addr >> 1, temp); |
162 | len--; | |
163 | addr++; | |
164 | buffer++; | |
165 | done++; | |
166 | } | |
8bde7f77 | 167 | |
7a8e9bed WD |
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; | |
8bde7f77 | 180 | |
7a8e9bed WD |
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 | ||
7a8e9bed WD |
192 | int mw_eeprom_read(int dev, int addr, u8 *buffer, int len) |
193 | { | |
194 | int done; | |
8bde7f77 | 195 | |
7a8e9bed WD |
196 | done = 0; |
197 | if (addr & 1) { | |
198 | u16 temp = mw_eeprom_read_word(dev, addr >> 1); | |
199 | buffer[0]= temp & 0xff; | |
8bde7f77 | 200 | |
7a8e9bed WD |
201 | len--; |
202 | addr++; | |
203 | buffer++; | |
204 | done++; | |
205 | } | |
8bde7f77 | 206 | |
7a8e9bed WD |
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; | |
8bde7f77 | 218 | |
7a8e9bed WD |
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); | |
8bde7f77 | 231 | |
7a8e9bed WD |
232 | if (addrlen < 6 || addrlen > 10) { |
233 | return -1; | |
234 | } | |
235 | return 0; | |
236 | } |