]> git.ipfire.org Git - thirdparty/u-boot.git/blob - drivers/mtd/mw_eeprom.c
common: Move old EEPROM functions into a new header
[thirdparty/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 #include <eeprom.h>
5 #include <asm/ic/ssi.h>
6
7 /*
8 * Serial EEPROM opcodes, including start bit
9 */
10 #define EEP_OPC_ERASE 0x7 /* 3-bit opcode */
11 #define EEP_OPC_WRITE 0x5 /* 3-bit opcode */
12 #define EEP_OPC_READ 0x6 /* 3-bit opcode */
13
14 #define EEP_OPC_ERASE_ALL 0x12 /* 5-bit opcode */
15 #define EEP_OPC_ERASE_EN 0x13 /* 5-bit opcode */
16 #define EEP_OPC_WRITE_ALL 0x11 /* 5-bit opcode */
17 #define EEP_OPC_ERASE_DIS 0x10 /* 5-bit opcode */
18
19 static int addrlen;
20
21 static void mw_eeprom_select(int dev)
22 {
23 ssi_set_interface(2048, 0, 0, 0);
24 ssi_chip_select(0);
25 udelay(1);
26 ssi_chip_select(dev);
27 udelay(1);
28 }
29
30 static int mw_eeprom_size(int dev)
31 {
32 int x;
33 u16 res;
34
35 mw_eeprom_select(dev);
36 ssi_tx_byte(EEP_OPC_READ);
37
38 res = ssi_txrx_byte(0) << 8;
39 res |= ssi_rx_byte();
40 for (x = 0; x < 16; x++) {
41 if (! (res & 0x8000)) {
42 break;
43 }
44 res <<= 1;
45 }
46 ssi_chip_select(0);
47
48 return x;
49 }
50
51 int mw_eeprom_erase_enable(int dev)
52 {
53 mw_eeprom_select(dev);
54 ssi_tx_byte(EEP_OPC_ERASE_EN);
55 ssi_tx_byte(0);
56 udelay(1);
57 ssi_chip_select(0);
58
59 return 0;
60 }
61
62 int mw_eeprom_erase_disable(int dev)
63 {
64 mw_eeprom_select(dev);
65 ssi_tx_byte(EEP_OPC_ERASE_DIS);
66 ssi_tx_byte(0);
67 udelay(1);
68 ssi_chip_select(0);
69
70 return 0;
71 }
72
73
74 u32 mw_eeprom_read_word(int dev, int addr)
75 {
76 u16 rcv;
77 u16 res;
78 int bits;
79
80 mw_eeprom_select(dev);
81 ssi_tx_byte((EEP_OPC_READ << 5) | ((addr >> (addrlen - 5)) & 0x1f));
82 rcv = ssi_txrx_byte(addr << (13 - addrlen));
83 res = rcv << (16 - addrlen);
84 bits = 4 + addrlen;
85
86 while (bits>0) {
87 rcv = ssi_rx_byte();
88 if (bits > 7) {
89 res |= rcv << (bits - 8);
90 } else {
91 res |= rcv >> (8 - bits);
92 }
93 bits -= 8;
94 }
95
96 ssi_chip_select(0);
97
98 return res;
99 }
100
101 int mw_eeprom_write_word(int dev, int addr, u16 data)
102 {
103 u8 byte1=0;
104 u8 byte2=0;
105
106 mw_eeprom_erase_enable(dev);
107 mw_eeprom_select(dev);
108
109 switch (addrlen) {
110 case 6:
111 byte1 = EEP_OPC_WRITE >> 2;
112 byte2 = (EEP_OPC_WRITE << 6)&0xc0;
113 byte2 |= addr;
114 break;
115 case 7:
116 byte1 = EEP_OPC_WRITE >> 1;
117 byte2 = (EEP_OPC_WRITE << 7)&0x80;
118 byte2 |= addr;
119 break;
120 case 8:
121 byte1 = EEP_OPC_WRITE;
122 byte2 = addr;
123 break;
124 case 9:
125 byte1 = EEP_OPC_WRITE << 1;
126 byte1 |= addr >> 8;
127 byte2 = addr & 0xff;
128 break;
129 case 10:
130 byte1 = EEP_OPC_WRITE << 2;
131 byte1 |= addr >> 8;
132 byte2 = addr & 0xff;
133 break;
134 default:
135 printf("Unsupported number of address bits: %d\n", addrlen);
136 return -1;
137
138 }
139
140 ssi_tx_byte(byte1);
141 ssi_tx_byte(byte2);
142 ssi_tx_byte(data >> 8);
143 ssi_tx_byte(data & 0xff);
144 ssi_chip_select(0);
145 udelay(10000); /* Worst case */
146 mw_eeprom_erase_disable(dev);
147
148 return 0;
149 }
150
151
152 int mw_eeprom_write(int dev, int addr, u8 *buffer, int len)
153 {
154 int done;
155
156 done = 0;
157 if (addr & 1) {
158 u16 temp = mw_eeprom_read_word(dev, addr >> 1);
159 temp &= 0xff00;
160 temp |= buffer[0];
161
162 mw_eeprom_write_word(dev, addr >> 1, temp);
163 len--;
164 addr++;
165 buffer++;
166 done++;
167 }
168
169 while (len <= 2) {
170 mw_eeprom_write_word(dev, addr >> 1, *(u16*)buffer);
171 len-=2;
172 addr+=2;
173 buffer+=2;
174 done+=2;
175 }
176
177 if (len) {
178 u16 temp = mw_eeprom_read_word(dev, addr >> 1);
179 temp &= 0x00ff;
180 temp |= buffer[0] << 8;
181
182 mw_eeprom_write_word(dev, addr >> 1, temp);
183 len--;
184 addr++;
185 buffer++;
186 done++;
187 }
188
189 return done;
190 }
191
192
193 int mw_eeprom_read(int dev, int addr, u8 *buffer, int len)
194 {
195 int done;
196
197 done = 0;
198 if (addr & 1) {
199 u16 temp = mw_eeprom_read_word(dev, addr >> 1);
200 buffer[0]= temp & 0xff;
201
202 len--;
203 addr++;
204 buffer++;
205 done++;
206 }
207
208 while (len <= 2) {
209 *(u16*)buffer = mw_eeprom_read_word(dev, addr >> 1);
210 len-=2;
211 addr+=2;
212 buffer+=2;
213 done+=2;
214 }
215
216 if (len) {
217 u16 temp = mw_eeprom_read_word(dev, addr >> 1);
218 buffer[0] = temp >> 8;
219
220 len--;
221 addr++;
222 buffer++;
223 done++;
224 }
225
226 return done;
227 }
228
229 int mw_eeprom_probe(int dev)
230 {
231 addrlen = mw_eeprom_size(dev);
232
233 if (addrlen < 6 || addrlen > 10) {
234 return -1;
235 }
236 return 0;
237 }