blob: 73f8066e0d286c751a4fc477f9febded05196d7c [file] [log] [blame]
wdenkc6097192002-11-03 00:24:07 +00001/*
2 * (C) Copyright 2002 ELTEC Elektronik AG
3 * Frank Gottschling <fgottschling@eltec.de>
4 *
5 * See file CREDITS for list of people who contributed to this
6 * project.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 */
23
24#include <common.h>
25#include "srom.h"
26
27/*----------------------------------------------------------------------------*/
28/*
29 * START sequence
30 * _ _________
31 * SCLK _> \____
32 * _ ____
33 * SDIO _> \_________
34 * : : :
35 */
36static void eepStart (void)
37{
38 out8(I2C_BUS_DAT, 0x60); /* SCLK = high SDIO = high */
39 out8(I2C_BUS_DIR, 0x60); /* set output direction for SCLK/SDIO */
40 udelay(10);
41 out8(I2C_BUS_DAT, 0x40); /* SCLK = high SDIO = low */
42 udelay(10);
43 out8(I2C_BUS_DAT, 0x00); /* SCLK = low SDIO = low */
44 udelay(10);
45}
46
47/*----------------------------------------------------------------------------*/
48/*
49 * STOP sequence
50 * _______
51 * SCLK _____/
52 * _ ___
53 * SDIO _>_______/
54 * : : :
55 */
56static void eepStop (void)
57{
58 out8(I2C_BUS_DAT, 0x00); /* SCLK = low SDIO = low */
59 out8(I2C_BUS_DIR, 0x60); /* set output direction for SCLK/SDIO */
60 udelay(10);
61 out8(I2C_BUS_DAT, 0x40); /* SCLK = high SDIO = low */
62 udelay(10);
63 out8(I2C_BUS_DAT, 0x60); /* SCLK = high SDIO = high */
64 udelay(10);
65 out8(I2C_BUS_DIR, 0x00); /* reset to input direction */
66}
67
68/*----------------------------------------------------------------------------*/
69/*
70 * Read one byte from EEPROM
71 * ___ ___ ___ ___ ___ ___ ___ ___
72 * SCLK ___/ \___/ \___/ \___/ \___/ \___/ \___/ \___/ \
73 * _________________________________________________________________
74 * SDIO > ^ ^ ^ ^ ^ ^ ^ ^
75 * : : : : : : : : : : : : : : : : :
76 */
77static unsigned char eepReadByte (void)
78{
79 register unsigned char buf = 0x00;
80 register int i;
81
82 out8(I2C_BUS_DIR, 0x40);
83
84 for (i = 0; i < 8; i++)
85 {
wdenk57b2d802003-06-27 21:31:46 +000086 out8(I2C_BUS_DAT, 0x00); /* SCLK = low SDIO = high */
87 udelay(10);
88 out8(I2C_BUS_DAT, 0x40); /* SCLK = high SDIO = high */
89 udelay(15);
90 buf <<= 1;
91 buf = (in8(I2C_BUS_DAT) & 0x20) ? (buf | 0x01) : (buf & 0xFE);
92 out8(I2C_BUS_DAT, 0x00); /* SCLK = low SDIO = high */
93 udelay(10);
wdenkc6097192002-11-03 00:24:07 +000094 }
95 return(buf);
96}
97
98/*----------------------------------------------------------------------------*/
99/*
100 * Write one byte to EEPROM
101 * ___ ___ ___ ___ ___ ___ ___ ___
102 * SCLK __/ \___/ \___/ \___/ \___/ \___/ \___/ \___/ \__
103 * _______ _______ _______ _______ _______ _______ _______ ________
104 * SDIO X_______X_______X_______X_______X_______X_______X_______X________
105 * : 7 : 6 : 5 : 4 : 3 : 2 : 1 : 0
106 */
107static void eepWriteByte (register unsigned char buf)
108{
109 register int i;
110
111 (buf & 0x80) ? out8(I2C_BUS_DAT, 0x20) : out8(I2C_BUS_DAT, 0x00); /* SCLK = low SDIO = data */
112 out8(I2C_BUS_DIR, 0x60);
113
114 for (i = 7; i >= 0; i--)
115 {
wdenk57b2d802003-06-27 21:31:46 +0000116 (buf & 0x80) ? out8(I2C_BUS_DAT, 0x20) : out8(I2C_BUS_DAT, 0x00); /* SCLK=low SDIO=data */
117 udelay(10);
118 (buf & 0x80) ? out8(I2C_BUS_DAT, 0x60) : out8(I2C_BUS_DAT, 0x40); /* SCLK=high SDIO=data */
119 udelay(15);
120 (buf & 0x80) ? out8(I2C_BUS_DAT, 0x20) : out8(I2C_BUS_DAT, 0x00); /* SCLK=low SDIO=data */
121 udelay(10);
122 buf <<= 1;
wdenkc6097192002-11-03 00:24:07 +0000123 }
124}
125
126/*----------------------------------------------------------------------------*/
127/*
128 * Read data acknowledge of EEPROM
129 * _______
130 * SCLK ____/ \___
131 * _______________
132 * SDIO >
133 * : : ^ :
134 */
135static int eepReadAck (void)
136{
137 int retval;
138
139 out8(I2C_BUS_DIR, 0x40);
140 out8(I2C_BUS_DAT, 0x00); /* SCLK = low SDIO = high */
141 udelay(10);
142 out8(I2C_BUS_DAT, 0x40); /* SCLK = high SDIO = high */
143 udelay(10);
144 retval = (in8(I2C_BUS_DAT) & 0x20) ? ERROR : 0;
145 udelay(10);
146 out8(I2C_BUS_DAT, 0x00); /* SCLK = low SDIO = high */
147 udelay(10);
148
149 return(retval);
150}
151
152/*----------------------------------------------------------------------------*/
153/*
154 * Write data acknowledge to EEPROM
155 * _______
156 * SCLK ____/ \___
157 *
158 * SDIO >_______________
159 * : : :
160 */
161static void eepWriteAck (unsigned char ack)
162{
163 ack ? out8(I2C_BUS_DAT, 0x20) : out8(I2C_BUS_DAT, 0x00); /* SCLK = low SDIO = ack */
164 out8(I2C_BUS_DIR, 0x60);
165 udelay(10);
166 ack ? out8(I2C_BUS_DAT, 0x60) : out8(I2C_BUS_DAT, 0x40); /* SCLK = high SDIO = ack */
167 udelay(15);
168 ack ? out8(I2C_BUS_DAT, 0x20) : out8(I2C_BUS_DAT, 0x00); /* SCLK = low SDIO = ack */
169 udelay(10);
170}
171
172/*----------------------------------------------------------------------------*/
173/*
174 * Read bytes from EEPROM
175 */
176int el_srom_load (addr, buf, cnt, device, block)
177unsigned char addr;
178unsigned char *buf;
179int cnt;
180unsigned char device;
181unsigned char block;
182{
183 register int i;
184
185 for (i=0;i<cnt;i++)
186 {
wdenk57b2d802003-06-27 21:31:46 +0000187 eepStart();
188 eepWriteByte(0xA0 | device | block);
189 if (eepReadAck() == ERROR)
190 {
191 eepStop();
192 return(ERROR);
193 }
194 eepWriteByte(addr++);
195 if (eepReadAck() == ERROR)
196 {
197 eepStop();
198 return(ERROR);
199 }
200 eepStart();
wdenkc6097192002-11-03 00:24:07 +0000201
wdenk57b2d802003-06-27 21:31:46 +0000202 eepWriteByte(0xA1 | device | block);
203 if (eepReadAck() == ERROR)
204 {
205 eepStop();
206 return(ERROR);
207 }
wdenkc6097192002-11-03 00:24:07 +0000208
wdenk57b2d802003-06-27 21:31:46 +0000209 *buf++ = eepReadByte();
210 eepWriteAck(1);
211 eepStop();
wdenkc6097192002-11-03 00:24:07 +0000212
wdenk57b2d802003-06-27 21:31:46 +0000213 if ((addr == 0) && (i != (cnt-1))) /* is it the same block ? */
214 {
215 if (block == FIRST_BLOCK)
216 block = SECOND_BLOCK;
217 else
218 return(ERROR);
219 }
wdenkc6097192002-11-03 00:24:07 +0000220 }
221 return(cnt);
222}
223
224/*----------------------------------------------------------------------------*/
225/*
226 *
227 * Write bytes to EEPROM
228 *
229 */
230int el_srom_store (addr, buf, cnt, device, block)
231unsigned char addr, *buf, device, block;
232int cnt;
233{
234 register int i, retVal;
235
236 for (i=0;i<cnt;i++)
237 {
wdenk57b2d802003-06-27 21:31:46 +0000238 retVal = ERROR;
239 do
240 {
241 eepStart();
242 eepWriteByte(0xA0 | device | block);
243 if ((retVal = eepReadAck()) == ERROR)
244 eepStop();
245 } while (retVal == ERROR);
wdenkc6097192002-11-03 00:24:07 +0000246
wdenk57b2d802003-06-27 21:31:46 +0000247 eepWriteByte(addr++);
248 if (eepReadAck() == ERROR) return(ERROR);
wdenkc6097192002-11-03 00:24:07 +0000249
wdenk57b2d802003-06-27 21:31:46 +0000250 if ((addr == 0) && (i != (cnt-1))) /* is it the same block ? */
251 {
252 if (block == FIRST_BLOCK)
253 block = SECOND_BLOCK;
254 else
255 return(ERROR);
256 }
wdenkc6097192002-11-03 00:24:07 +0000257
wdenk57b2d802003-06-27 21:31:46 +0000258 eepWriteByte(*buf++);
259 if (eepReadAck() == ERROR)
260 return(ERROR);
wdenkc6097192002-11-03 00:24:07 +0000261
wdenk57b2d802003-06-27 21:31:46 +0000262 eepStop();
wdenkc6097192002-11-03 00:24:07 +0000263 }
264 return(cnt);
265}
266
267/*----------------------------------------------------------------------------*/
268/*
269 * calculate checksum for ELTEC revision srom
270 */
271unsigned long el_srom_checksum (ptr, size)
272register unsigned char *ptr;
273unsigned long size;
274{
275 u_long f, accu = 0;
276 u_int i;
277 u_char byte;
278
279 for (; size; size--)
280 {
wdenk57b2d802003-06-27 21:31:46 +0000281 byte = *ptr++;
282 for (i = 8; i; i--)
283 {
284 f = ((byte & 1) ^ (accu & 1)) ? 0x84083001 : 0;
285 accu >>= 1; accu ^= f;
286 byte >>= 1;
287 }
wdenkc6097192002-11-03 00:24:07 +0000288 }
289 return(accu);
290}
291
292/*----------------------------------------------------------------------------*/