blob: 30a51fa0517ea7ba64d630173838ccca8ad1b3e7 [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>
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
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;
36
37 mw_eeprom_select(dev);
38 ssi_tx_byte(EEP_OPC_READ);
39
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);
49
50 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);
60
61 return 0;
62}
63
64int mw_eeprom_erase_disable(int dev)
65{
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);
71
72 return 0;
73}
74
75
76u32 mw_eeprom_read_word(int dev, int addr)
77{
78 u16 rcv;
79 u16 res;
80 int bits;
81
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;
87
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 }
97
98 ssi_chip_select(0);
99
100 return res;
101}
102
103int mw_eeprom_write_word(int dev, int addr, u16 data)
104{
105 u8 byte1=0;
106 u8 byte2=0;
107
108 mw_eeprom_erase_enable(dev);
109 mw_eeprom_select(dev);
110
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;
139
140 }
141
142 ssi_tx_byte(byte1);
143 ssi_tx_byte(byte2);
144 ssi_tx_byte(data >> 8);
145 ssi_tx_byte(data & 0xff);
146 ssi_chip_select(0);
147 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;
157
158 done = 0;
159 if (addr & 1) {
160 u16 temp = mw_eeprom_read_word(dev, addr >> 1);
161 temp &= 0xff00;
162 temp |= buffer[0];
163
164 mw_eeprom_write_word(dev, addr >> 1, temp);
165 len--;
166 addr++;
167 buffer++;
168 done++;
169 }
170
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;
183
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
195
196int mw_eeprom_read(int dev, int addr, u8 *buffer, int len)
197{
198 int done;
199
200 done = 0;
201 if (addr & 1) {
202 u16 temp = mw_eeprom_read_word(dev, addr >> 1);
203 buffer[0]= temp & 0xff;
204
205 len--;
206 addr++;
207 buffer++;
208 done++;
209 }
210
211 while (len <= 2) {
212 *(u16*)buffer = mw_eeprom_read_word(dev, addr >> 1);
213 len-=2;
214 addr+=2;
215 buffer+=2;
216 done+=2;
217 }
218
219 if (len) {
220 u16 temp = mw_eeprom_read_word(dev, addr >> 1);
221 buffer[0] = temp >> 8;
222
223 len--;
224 addr++;
225 buffer++;
226 done++;
227 }
228
229 return done;
230}
231
232int mw_eeprom_probe(int dev)
233{
234 addrlen = mw_eeprom_size(dev);
235
236 if (addrlen < 6 || addrlen > 10) {
237 return -1;
238 }
239 return 0;
240}
241
242#endif