]>
Commit | Line | Data |
---|---|---|
771e05be SR |
1 | /* |
2 | * (C) Copyright 2000 | |
3 | * Wolfgang Denk, DENX Software Engineering, wd@denx.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 | * Hacked for the DB64360 board by Ingo.Assmus@keymile.com | |
24 | * extra improvments by Brain Waite | |
25 | * for cpci750 by reinhard.arlt@esd-electronics.com | |
26 | */ | |
27 | #include <common.h> | |
28 | #include <mpc8xx.h> | |
29 | #include <malloc.h> | |
30 | #include "../../Marvell/include/mv_gen_reg.h" | |
31 | #include "../../Marvell/include/core.h" | |
32 | ||
33 | #define I2C_DELAY 100 | |
34 | #undef DEBUG_I2C | |
35 | ||
36 | #ifdef DEBUG_I2C | |
37 | #define DP(x) x | |
38 | #else | |
39 | #define DP(x) | |
40 | #endif | |
41 | ||
42 | /* Assuming that there is only one master on the bus (us) */ | |
43 | ||
44 | static void i2c_init (int speed, int slaveaddr) | |
45 | { | |
46 | unsigned int n, m, freq, margin, power; | |
47 | unsigned int actualN = 0, actualM = 0; | |
48 | unsigned int minMargin = 0xffffffff; | |
6d0f6bcf | 49 | unsigned int tclk = CONFIG_SYS_TCLK; |
771e05be SR |
50 | unsigned int i2cFreq = speed; /* 100000 max. Fast mode not supported */ |
51 | ||
52 | DP (puts ("i2c_init\n")); | |
53 | /* gtI2cMasterInit */ | |
54 | for (n = 0; n < 8; n++) { | |
55 | for (m = 0; m < 16; m++) { | |
56 | power = 2 << n; /* power = 2^(n+1) */ | |
57 | freq = tclk / (10 * (m + 1) * power); | |
58 | if (i2cFreq > freq) | |
59 | margin = i2cFreq - freq; | |
60 | else | |
61 | margin = freq - i2cFreq; | |
62 | if (margin < minMargin) { | |
63 | minMargin = margin; | |
64 | actualN = n; | |
65 | actualM = m; | |
66 | } | |
67 | } | |
68 | } | |
69 | ||
70 | DP (puts ("setup i2c bus\n")); | |
71 | ||
72 | /* Setup bus */ | |
73 | /* gtI2cReset */ | |
74 | GT_REG_WRITE (I2C_SOFT_RESET, 0); | |
efe2a4d5 | 75 | asm(" sync"); |
771e05be | 76 | GT_REG_WRITE (I2C_CONTROL, 0); |
efe2a4d5 | 77 | asm(" sync"); |
771e05be SR |
78 | |
79 | DP (puts ("set baudrate\n")); | |
80 | ||
81 | GT_REG_WRITE (I2C_STATUS_BAUDE_RATE, (actualM << 3) | actualN); | |
efe2a4d5 | 82 | asm(" sync"); |
771e05be SR |
83 | |
84 | DP (puts ("udelay...\n")); | |
85 | ||
86 | udelay (I2C_DELAY); | |
87 | ||
88 | GT_REG_WRITE (I2C_CONTROL, (0x1 << 2) | (0x1 << 6)); | |
efe2a4d5 | 89 | asm(" sync"); |
771e05be SR |
90 | } |
91 | ||
92 | ||
93 | static uchar i2c_select_device (uchar dev_addr, uchar read, int ten_bit) | |
94 | { | |
95 | unsigned int status, data, bits = 7; | |
efe2a4d5 | 96 | unsigned int control; |
771e05be SR |
97 | int count = 0; |
98 | ||
99 | DP (puts ("i2c_select_device\n")); | |
100 | ||
101 | /* Output slave address */ | |
102 | ||
103 | if (ten_bit) { | |
104 | bits = 10; | |
105 | } | |
106 | ||
107 | GT_REG_READ (I2C_CONTROL, &control); | |
108 | control |= (0x1 << 2); | |
109 | GT_REG_WRITE (I2C_CONTROL, control); | |
efe2a4d5 | 110 | asm(" sync"); |
771e05be SR |
111 | |
112 | GT_REG_READ (I2C_CONTROL, &control); | |
113 | control |= (0x1 << 5); /* generate the I2C_START_BIT */ | |
114 | GT_REG_WRITE (I2C_CONTROL, control); | |
efe2a4d5 | 115 | asm(" sync"); |
771e05be | 116 | RESET_REG_BITS (I2C_CONTROL, (0x01 << 3)); |
efe2a4d5 | 117 | asm(" sync"); |
771e05be SR |
118 | |
119 | GT_REG_READ (I2C_CONTROL, &status); | |
120 | while ((status & 0x08) != 0x08) { | |
efe2a4d5 WD |
121 | GT_REG_READ (I2C_CONTROL, &status); |
122 | } | |
771e05be SR |
123 | |
124 | ||
125 | count = 0; | |
126 | ||
127 | GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); | |
128 | while (((status & 0xff) != 0x08) && ((status & 0xff) != 0x10)){ | |
129 | if (count > 200) { | |
130 | #ifdef DEBUG_I2C | |
efe2a4d5 | 131 | printf ("Failed to set startbit: 0x%02x\n", status); |
771e05be SR |
132 | #endif |
133 | GT_REG_WRITE (I2C_CONTROL, (0x1 << 4)); /*stop */ | |
134 | asm(" sync"); | |
135 | return (status); | |
136 | } | |
137 | GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); | |
138 | count++; | |
139 | } | |
140 | ||
141 | DP (puts ("i2c_select_device:write addr byte\n")); | |
142 | ||
143 | /* assert the address */ | |
144 | ||
145 | data = (dev_addr << 1); | |
146 | /* set the read bit */ | |
147 | data |= read; | |
148 | GT_REG_WRITE (I2C_DATA, data); | |
efe2a4d5 | 149 | asm(" sync"); |
771e05be | 150 | RESET_REG_BITS (I2C_CONTROL, BIT3); |
efe2a4d5 | 151 | asm(" sync"); |
771e05be SR |
152 | |
153 | GT_REG_READ (I2C_CONTROL, &status); | |
154 | while ((status & 0x08) != 0x08) { | |
efe2a4d5 WD |
155 | GT_REG_READ (I2C_CONTROL, &status); |
156 | } | |
771e05be SR |
157 | |
158 | GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); | |
159 | count = 0; | |
160 | while (((status & 0xff) != 0x40) && ((status & 0xff) != 0x18)) { | |
161 | if (count > 200) { | |
162 | #ifdef DEBUG_I2C | |
efe2a4d5 | 163 | printf ("Failed to write address: 0x%02x\n", status); |
771e05be SR |
164 | #endif |
165 | GT_REG_WRITE (I2C_CONTROL, (0x1 << 4)); /*stop */ | |
166 | return (status); | |
167 | } | |
168 | GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); | |
169 | asm(" sync"); | |
170 | count++; | |
171 | } | |
172 | ||
173 | if (bits == 10) { | |
174 | printf ("10 bit I2C addressing not yet implemented\n"); | |
175 | return (0xff); | |
176 | } | |
177 | ||
178 | return (0); | |
179 | } | |
180 | ||
181 | static uchar i2c_get_data (uchar * return_data, int len) | |
182 | { | |
183 | ||
184 | unsigned int data, status; | |
185 | int count = 0; | |
186 | ||
187 | DP (puts ("i2c_get_data\n")); | |
188 | ||
189 | while (len) { | |
190 | ||
191 | RESET_REG_BITS (I2C_CONTROL, BIT3); | |
192 | asm(" sync"); | |
193 | ||
194 | /* Get and return the data */ | |
195 | ||
196 | GT_REG_READ (I2C_CONTROL, &status); | |
197 | while ((status & 0x08) != 0x08) { | |
efe2a4d5 WD |
198 | GT_REG_READ (I2C_CONTROL, &status); |
199 | } | |
771e05be SR |
200 | |
201 | GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); | |
202 | count++; | |
203 | while ((status & 0xff) != 0x50) { | |
204 | if (count > 20) { | |
205 | #ifdef DEBUG_I2C | |
efe2a4d5 | 206 | printf ("Failed to get data len status: 0x%02x\n", status); |
771e05be SR |
207 | #endif |
208 | GT_REG_WRITE (I2C_CONTROL, (0x1 << 4)); /*stop */ | |
209 | asm(" sync"); | |
210 | return 0; | |
211 | } | |
212 | GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); | |
213 | count++; | |
214 | } | |
215 | GT_REG_READ (I2C_DATA, &data); | |
216 | len--; | |
217 | *return_data = (uchar) data; | |
218 | return_data++; | |
219 | ||
220 | } | |
221 | RESET_REG_BITS (I2C_CONTROL, BIT2 | BIT3); | |
efe2a4d5 | 222 | asm(" sync"); |
771e05be SR |
223 | count = 0; |
224 | ||
225 | GT_REG_READ (I2C_CONTROL, &status); | |
226 | while ((status & 0x08) != 0x08) { | |
efe2a4d5 WD |
227 | GT_REG_READ (I2C_CONTROL, &status); |
228 | } | |
771e05be SR |
229 | |
230 | while ((status & 0xff) != 0x58) { | |
231 | if (count > 2000) { | |
232 | GT_REG_WRITE (I2C_CONTROL, (0x1 << 4)); /*stop */ | |
233 | return (status); | |
234 | } | |
235 | GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); | |
236 | count++; | |
237 | } | |
238 | GT_REG_WRITE (I2C_CONTROL, (0x1 << 4)); /* stop */ | |
efe2a4d5 | 239 | asm(" sync"); |
771e05be | 240 | RESET_REG_BITS (I2C_CONTROL, (0x1 << 3)); |
efe2a4d5 | 241 | asm(" sync"); |
771e05be SR |
242 | |
243 | return (0); | |
244 | } | |
245 | ||
246 | ||
247 | static uchar i2c_write_data (unsigned int *data, int len) | |
248 | { | |
249 | unsigned int status; | |
250 | int count; | |
251 | unsigned int temp; | |
252 | unsigned int *temp_ptr = data; | |
253 | ||
254 | DP (puts ("i2c_write_data\n")); | |
255 | ||
256 | while (len) { | |
efe2a4d5 | 257 | count = 0; |
771e05be SR |
258 | temp = (unsigned int) (*temp_ptr); |
259 | GT_REG_WRITE (I2C_DATA, temp); | |
260 | asm(" sync"); | |
261 | RESET_REG_BITS (I2C_CONTROL, (0x1 << 3)); | |
262 | asm(" sync"); | |
263 | ||
264 | GT_REG_READ (I2C_CONTROL, &status); | |
265 | while ((status & 0x08) != 0x08) { | |
266 | GT_REG_READ (I2C_CONTROL, &status); | |
efe2a4d5 | 267 | } |
771e05be SR |
268 | |
269 | GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); | |
270 | count++; | |
271 | while ((status & 0xff) != 0x28) { | |
272 | if (count > 200) { | |
273 | GT_REG_WRITE (I2C_CONTROL, (0x1 << 4)); /*stop */ | |
274 | asm(" sync"); | |
275 | return (status); | |
276 | } | |
277 | GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); | |
278 | count++; | |
279 | } | |
280 | len--; | |
281 | temp_ptr++; | |
282 | } | |
283 | return (0); | |
284 | } | |
285 | ||
286 | ||
287 | static uchar i2c_write_byte (unsigned char *data, int len) | |
288 | { | |
289 | unsigned int status; | |
290 | int count; | |
291 | unsigned int temp; | |
292 | unsigned char *temp_ptr = data; | |
293 | ||
294 | DP (puts ("i2c_write_byte\n")); | |
295 | ||
296 | while (len) { | |
efe2a4d5 | 297 | count = 0; |
771e05be SR |
298 | /* Set and assert the data */ |
299 | temp = *temp_ptr; | |
300 | GT_REG_WRITE (I2C_DATA, temp); | |
301 | asm(" sync"); | |
302 | RESET_REG_BITS (I2C_CONTROL, (0x1 << 3)); | |
303 | asm(" sync"); | |
304 | ||
305 | ||
306 | GT_REG_READ (I2C_CONTROL, &status); | |
307 | while ((status & 0x08) != 0x08) { | |
308 | GT_REG_READ (I2C_CONTROL, &status); | |
efe2a4d5 | 309 | } |
771e05be SR |
310 | |
311 | GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); | |
312 | count++; | |
313 | while ((status & 0xff) != 0x28) { | |
314 | if (count > 200) { | |
315 | GT_REG_WRITE (I2C_CONTROL, (0x1 << 4)); /*stop */ | |
316 | asm(" sync"); | |
317 | return (status); | |
318 | } | |
319 | GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); | |
320 | count++; | |
321 | } | |
322 | len--; | |
323 | temp_ptr++; | |
324 | } | |
325 | return (0); | |
326 | } | |
327 | ||
328 | static uchar | |
329 | i2c_set_dev_offset (uchar dev_addr, unsigned int offset, int ten_bit, | |
330 | int alen) | |
331 | { | |
332 | uchar status; | |
333 | unsigned int table[2]; | |
334 | ||
335 | table[1] = (offset ) & 0x0ff; /* low byte */ | |
336 | table[0] = (offset >> 8) & 0x0ff; /* high byte */ | |
337 | ||
338 | DP (puts ("i2c_set_dev_offset\n")); | |
339 | ||
340 | status = i2c_select_device (dev_addr, 0, ten_bit); | |
341 | if (status) { | |
342 | #ifdef DEBUG_I2C | |
343 | 22 printf ("Failed to select device setting offset: 0x%02x\n", | |
344 | status); | |
345 | #endif | |
346 | return status; | |
347 | } | |
348 | /* check the address offset length */ | |
349 | if (alen == 0) | |
350 | /* no address offset */ | |
351 | return (0); | |
352 | else if (alen == 1) { | |
353 | /* 1 byte address offset */ | |
354 | status = i2c_write_data (&offset, 1); | |
355 | if (status) { | |
356 | #ifdef DEBUG_I2C | |
357 | printf ("Failed to write data: 0x%02x\n", status); | |
358 | #endif | |
359 | return status; | |
360 | } | |
361 | } else if (alen == 2) { | |
362 | /* 2 bytes address offset */ | |
363 | status = i2c_write_data (table, 2); | |
364 | if (status) { | |
365 | #ifdef DEBUG_I2C | |
366 | printf ("Failed to write data: 0x%02x\n", status); | |
367 | #endif | |
368 | return status; | |
369 | } | |
370 | } else { | |
371 | /* address offset unknown or not supported */ | |
372 | printf ("Address length offset %d is not supported\n", alen); | |
373 | return 1; | |
374 | } | |
375 | return 0; /* sucessful completion */ | |
376 | } | |
377 | ||
378 | uchar | |
379 | i2c_read (uchar dev_addr, unsigned int offset, int alen, uchar * data, | |
380 | int len) | |
381 | { | |
382 | uchar status = 0; | |
6d0f6bcf | 383 | unsigned int i2cFreq = CONFIG_SYS_I2C_SPEED; |
771e05be SR |
384 | |
385 | DP (puts ("i2c_read\n")); | |
386 | ||
387 | i2c_init (i2cFreq, 0); /* set the i2c frequency */ | |
388 | ||
389 | status = i2c_set_dev_offset (dev_addr, offset, 0, alen); /* send the slave address + offset */ | |
390 | if (status) { | |
391 | #ifdef DEBUG_I2C | |
392 | printf ("Failed to set slave address & offset: 0x%02x\n", | |
393 | status); | |
394 | #endif | |
395 | return status; | |
396 | } | |
397 | ||
398 | status = i2c_select_device (dev_addr, 1, 0); | |
399 | if (status) { | |
400 | #ifdef DEBUG_I2C | |
401 | printf ("Failed to select device for data read: 0x%02x\n", | |
402 | status); | |
403 | #endif | |
404 | return status; | |
405 | } | |
406 | ||
407 | status = i2c_get_data (data, len); | |
408 | if (status) { | |
409 | #ifdef DEBUG_I2C | |
410 | printf ("Data not read: 0x%02x\n", status); | |
411 | #endif | |
412 | return status; | |
413 | } | |
414 | ||
415 | return 0; | |
416 | } | |
417 | ||
418 | ||
419 | void i2c_stop (void) | |
420 | { | |
421 | GT_REG_WRITE (I2C_CONTROL, (0x1 << 4)); | |
efe2a4d5 | 422 | asm(" sync"); |
771e05be SR |
423 | } |
424 | ||
425 | ||
426 | uchar | |
427 | i2c_write (uchar dev_addr, unsigned int offset, int alen, uchar * data, | |
428 | int len) | |
429 | { | |
430 | uchar status = 0; | |
6d0f6bcf | 431 | unsigned int i2cFreq = CONFIG_SYS_I2C_SPEED; |
771e05be SR |
432 | |
433 | DP (puts ("i2c_write\n")); | |
434 | ||
435 | i2c_init (i2cFreq, 0); /* set the i2c frequency */ | |
436 | ||
437 | status = i2c_set_dev_offset (dev_addr, offset, 0, alen); /* send the slave address + offset */ | |
438 | if (status) { | |
439 | #ifdef DEBUG_I2C | |
440 | printf ("Failed to set slave address & offset: 0x%02x\n", | |
441 | status); | |
442 | #endif | |
443 | return status; | |
efe2a4d5 | 444 | } |
771e05be SR |
445 | |
446 | ||
447 | status = i2c_write_byte (data, len); /* write the data */ | |
448 | if (status) { | |
449 | #ifdef DEBUG_I2C | |
450 | printf ("Data not written: 0x%02x\n", status); | |
451 | #endif | |
452 | return status; | |
efe2a4d5 | 453 | } |
771e05be SR |
454 | /* issue a stop bit */ |
455 | i2c_stop (); | |
456 | return 0; | |
457 | } | |
458 | ||
459 | ||
460 | int i2c_probe (uchar chip) | |
461 | { | |
462 | ||
463 | #ifdef DEBUG_I2C | |
464 | unsigned int i2c_status; | |
465 | #endif | |
466 | uchar status = 0; | |
6d0f6bcf | 467 | unsigned int i2cFreq = CONFIG_SYS_I2C_SPEED; |
771e05be SR |
468 | |
469 | DP (puts ("i2c_probe\n")); | |
470 | ||
471 | i2c_init (i2cFreq, 0); /* set the i2c frequency */ | |
472 | ||
473 | status = i2c_set_dev_offset (chip, 0, 0, 0); /* send the slave address + no offset */ | |
474 | if (status) { | |
475 | #ifdef DEBUG_I2C | |
476 | printf ("Failed to set slave address: 0x%02x\n", status); | |
477 | #endif | |
478 | return (int) status; | |
479 | } | |
480 | #ifdef DEBUG_I2C | |
481 | GT_REG_READ (I2C_STATUS_BAUDE_RATE, &i2c_status); | |
482 | printf ("address %#x returned %#x\n", chip, i2c_status); | |
483 | #endif | |
484 | /* issue a stop bit */ | |
485 | i2c_stop (); | |
486 | return 0; /* successful completion */ | |
487 | } |