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