]> git.ipfire.org Git - people/ms/u-boot.git/blob - drivers/mtd/mw_eeprom.c
Merge git://www.denx.de/git/u-boot
[people/ms/u-boot.git] / drivers / mtd / mw_eeprom.c
1 /* Three-wire (MicroWire) serial eeprom driver (for 93C46 and compatibles) */
2
3 #include <common.h>
4
5 #ifdef CONFIG_MW_EEPROM
6
7 #include <ssi.h>
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;
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
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);
60
61 return 0;
62 }
63
64 int 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
76 u32 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
103 int 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
154 int 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 int mw_eeprom_read(int dev, int addr, u8 *buffer, int len)
196 {
197 int done;
198
199 done = 0;
200 if (addr & 1) {
201 u16 temp = mw_eeprom_read_word(dev, addr >> 1);
202 buffer[0]= temp & 0xff;
203
204 len--;
205 addr++;
206 buffer++;
207 done++;
208 }
209
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;
221
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);
234
235 if (addrlen < 6 || addrlen > 10) {
236 return -1;
237 }
238 return 0;
239 }
240
241 #endif