]>
Commit | Line | Data |
---|---|---|
7a8e9bed WD |
1 | /* Three-wire (MicroWire) serial eeprom driver (for 93C46 and compatibles) */ |
2 | ||
3 | #include <common.h> | |
4 | #include <ssi.h> | |
5 | ||
6 | ||
7 | #ifdef CONFIG_MW_EEPROM | |
8 | ||
9 | /* | |
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 | ||
21 | static int addrlen; | |
22 | ||
23 | static 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 | ||
32 | static int mw_eeprom_size(int dev) | |
33 | { | |
34 | int x; | |
35 | u16 res; | |
8bde7f77 | 36 | |
7a8e9bed WD |
37 | mw_eeprom_select(dev); |
38 | ssi_tx_byte(EEP_OPC_READ); | |
8bde7f77 | 39 | |
7a8e9bed WD |
40 | 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); | |
8bde7f77 | 49 | |
7a8e9bed WD |
50 | return x; |
51 | } | |
52 | ||
53 | int 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); | |
8bde7f77 | 60 | |
7a8e9bed WD |
61 | return 0; |
62 | } | |
63 | ||
64 | int mw_eeprom_erase_disable(int dev) | |
8bde7f77 | 65 | { |
7a8e9bed WD |
66 | 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); | |
8bde7f77 | 71 | |
7a8e9bed WD |
72 | return 0; |
73 | } | |
74 | ||
75 | ||
76 | u32 mw_eeprom_read_word(int dev, int addr) | |
77 | { | |
78 | u16 rcv; | |
79 | u16 res; | |
80 | int bits; | |
8bde7f77 | 81 | |
7a8e9bed WD |
82 | 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; | |
8bde7f77 | 87 | |
7a8e9bed WD |
88 | 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 | } | |
8bde7f77 | 97 | |
7a8e9bed | 98 | ssi_chip_select(0); |
8bde7f77 | 99 | |
7a8e9bed WD |
100 | return res; |
101 | } | |
102 | ||
103 | int mw_eeprom_write_word(int dev, int addr, u16 data) | |
104 | { | |
105 | u8 byte1=0; | |
106 | u8 byte2=0; | |
8bde7f77 | 107 | |
7a8e9bed WD |
108 | mw_eeprom_erase_enable(dev); |
109 | mw_eeprom_select(dev); | |
8bde7f77 | 110 | |
7a8e9bed WD |
111 | 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; | |
8bde7f77 | 139 | |
7a8e9bed | 140 | } |
8bde7f77 | 141 | |
7a8e9bed WD |
142 | ssi_tx_byte(byte1); |
143 | ssi_tx_byte(byte2); | |
8bde7f77 | 144 | ssi_tx_byte(data >> 8); |
7a8e9bed | 145 | ssi_tx_byte(data & 0xff); |
8bde7f77 | 146 | ssi_chip_select(0); |
7a8e9bed WD |
147 | udelay(10000); /* Worst case */ |
148 | mw_eeprom_erase_disable(dev); | |
149 | ||
150 | return 0; | |
151 | } | |
152 | ||
153 | ||
154 | int mw_eeprom_write(int dev, int addr, u8 *buffer, int len) | |
155 | { | |
156 | int done; | |
8bde7f77 | 157 | |
7a8e9bed WD |
158 | done = 0; |
159 | if (addr & 1) { | |
160 | u16 temp = mw_eeprom_read_word(dev, addr >> 1); | |
161 | temp &= 0xff00; | |
162 | temp |= buffer[0]; | |
8bde7f77 | 163 | |
7a8e9bed WD |
164 | mw_eeprom_write_word(dev, addr >> 1, temp); |
165 | len--; | |
166 | addr++; | |
167 | buffer++; | |
168 | done++; | |
169 | } | |
8bde7f77 | 170 | |
7a8e9bed WD |
171 | 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; | |
8bde7f77 | 183 | |
7a8e9bed WD |
184 | mw_eeprom_write_word(dev, addr >> 1, temp); |
185 | len--; | |
186 | addr++; | |
187 | buffer++; | |
188 | done++; | |
189 | } | |
190 | ||
191 | return done; | |
192 | } | |
193 | ||
194 | ||
7a8e9bed WD |
195 | int mw_eeprom_read(int dev, int addr, u8 *buffer, int len) |
196 | { | |
197 | int done; | |
8bde7f77 | 198 | |
7a8e9bed WD |
199 | done = 0; |
200 | if (addr & 1) { | |
201 | u16 temp = mw_eeprom_read_word(dev, addr >> 1); | |
202 | buffer[0]= temp & 0xff; | |
8bde7f77 | 203 | |
7a8e9bed WD |
204 | len--; |
205 | addr++; | |
206 | buffer++; | |
207 | done++; | |
208 | } | |
8bde7f77 | 209 | |
7a8e9bed WD |
210 | 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; | |
8bde7f77 | 221 | |
7a8e9bed WD |
222 | len--; |
223 | addr++; | |
224 | buffer++; | |
225 | done++; | |
226 | } | |
227 | ||
228 | return done; | |
229 | } | |
230 | ||
231 | int mw_eeprom_probe(int dev) | |
232 | { | |
233 | addrlen = mw_eeprom_size(dev); | |
8bde7f77 | 234 | |
7a8e9bed WD |
235 | if (addrlen < 6 || addrlen > 10) { |
236 | return -1; | |
237 | } | |
238 | return 0; | |
239 | } | |
240 | ||
241 | #endif |