]>
Commit | Line | Data |
---|---|---|
3a473b2a WD |
1 | /* |
2 | * (C) Copyright 2000 | |
3 | * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
4 | * | |
1a459660 | 5 | * SPDX-License-Identifier: GPL-2.0+ |
3a473b2a WD |
6 | * |
7 | * Hacked for the DB64360 board by Ingo.Assmus@keymile.com | |
8 | * extra improvments by Brain Waite | |
9 | */ | |
10 | #include <common.h> | |
11 | #include <mpc8xx.h> | |
12 | #include <malloc.h> | |
a056b1ce | 13 | #include <i2c.h> |
3a473b2a WD |
14 | #include "../include/mv_gen_reg.h" |
15 | #include "../include/core.h" | |
16 | ||
17 | #define MAX_I2C_RETRYS 10 | |
18 | #define I2C_DELAY 1000 /* Should be at least the # of MHz of Tclk */ | |
19 | #undef DEBUG_I2C | |
20 | /*#define DEBUG_I2C*/ | |
21 | ||
22 | #ifdef DEBUG_I2C | |
23 | #define DP(x) x | |
24 | #else | |
25 | #define DP(x) | |
26 | #endif | |
27 | ||
28 | /* Assuming that there is only one master on the bus (us) */ | |
29 | ||
a056b1ce | 30 | void i2c_init (int speed, int slaveaddr) |
3a473b2a WD |
31 | { |
32 | unsigned int n, m, freq, margin, power; | |
33 | unsigned int actualN = 0, actualM = 0; | |
34 | unsigned int control, status; | |
35 | unsigned int minMargin = 0xffffffff; | |
6d0f6bcf | 36 | unsigned int tclk = CONFIG_SYS_TCLK; |
3a473b2a WD |
37 | unsigned int i2cFreq = speed; /* 100000 max. Fast mode not supported */ |
38 | ||
39 | DP (puts ("i2c_init\n")); | |
40 | /* gtI2cMasterInit */ | |
41 | for (n = 0; n < 8; n++) { | |
42 | for (m = 0; m < 16; m++) { | |
43 | power = 2 << n; /* power = 2^(n+1) */ | |
44 | freq = tclk / (10 * (m + 1) * power); | |
45 | if (i2cFreq > freq) | |
46 | margin = i2cFreq - freq; | |
47 | else | |
48 | margin = freq - i2cFreq; | |
49 | if (margin < minMargin) { | |
50 | minMargin = margin; | |
51 | actualN = n; | |
52 | actualM = m; | |
53 | } | |
54 | } | |
55 | } | |
56 | ||
57 | DP (puts ("setup i2c bus\n")); | |
58 | ||
59 | /* Setup bus */ | |
60 | /* gtI2cReset */ | |
61 | GT_REG_WRITE (I2C_SOFT_RESET, 0); | |
62 | ||
63 | DP (puts ("udelay...\n")); | |
64 | ||
65 | udelay (I2C_DELAY); | |
66 | ||
67 | DP (puts ("set baudrate\n")); | |
68 | ||
69 | GT_REG_WRITE (I2C_STATUS_BAUDE_RATE, (actualM << 3) | actualN); | |
70 | GT_REG_WRITE (I2C_CONTROL, (0x1 << 2) | (0x1 << 6)); | |
71 | ||
72 | udelay (I2C_DELAY * 10); | |
73 | ||
74 | DP (puts ("read control, baudrate\n")); | |
75 | ||
76 | GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); | |
77 | GT_REG_READ (I2C_CONTROL, &control); | |
78 | } | |
79 | ||
80 | static uchar i2c_start (void) | |
81 | { /* DB64360 checked -> ok */ | |
82 | unsigned int control, status; | |
83 | int count = 0; | |
84 | ||
85 | DP (puts ("i2c_start\n")); | |
86 | ||
87 | /* Set the start bit */ | |
88 | ||
89 | /* gtI2cGenerateStartBit() */ | |
90 | ||
91 | GT_REG_READ (I2C_CONTROL, &control); | |
92 | control |= (0x1 << 5); /* generate the I2C_START_BIT */ | |
93 | GT_REG_WRITE (I2C_CONTROL, control); | |
94 | ||
95 | GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); | |
96 | ||
97 | count = 0; | |
98 | while ((status & 0xff) != 0x08) { | |
99 | udelay (I2C_DELAY); | |
100 | if (count > 20) { | |
101 | GT_REG_WRITE (I2C_CONTROL, (0x1 << 4)); /*stop */ | |
102 | return (status); | |
103 | } | |
104 | GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); | |
105 | count++; | |
106 | } | |
107 | ||
108 | return (0); | |
109 | } | |
110 | ||
111 | static uchar i2c_select_device (uchar dev_addr, uchar read, int ten_bit) | |
112 | { | |
113 | unsigned int status, data, bits = 7; | |
114 | int count = 0; | |
115 | ||
116 | DP (puts ("i2c_select_device\n")); | |
117 | ||
118 | /* Output slave address */ | |
119 | ||
120 | if (ten_bit) { | |
121 | bits = 10; | |
122 | } | |
123 | ||
124 | data = (dev_addr << 1); | |
125 | /* set the read bit */ | |
126 | data |= read; | |
127 | GT_REG_WRITE (I2C_DATA, data); | |
128 | /* assert the address */ | |
129 | RESET_REG_BITS (I2C_CONTROL, BIT3); | |
130 | ||
131 | udelay (I2C_DELAY); | |
132 | ||
133 | GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); | |
134 | count = 0; | |
135 | while (((status & 0xff) != 0x40) && ((status & 0xff) != 0x18)) { | |
136 | udelay (I2C_DELAY); | |
137 | if (count > 20) { | |
138 | GT_REG_WRITE (I2C_CONTROL, (0x1 << 4)); /*stop */ | |
139 | return (status); | |
140 | } | |
141 | GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); | |
142 | count++; | |
143 | } | |
144 | ||
145 | if (bits == 10) { | |
146 | printf ("10 bit I2C addressing not yet implemented\n"); | |
147 | return (0xff); | |
148 | } | |
149 | ||
150 | return (0); | |
151 | } | |
152 | ||
153 | static uchar i2c_get_data (uchar * return_data, int len) | |
154 | { | |
155 | ||
77ddac94 | 156 | unsigned int data, status = 0; |
3a473b2a WD |
157 | int count = 0; |
158 | ||
159 | DP (puts ("i2c_get_data\n")); | |
160 | ||
161 | while (len) { | |
162 | ||
163 | /* Get and return the data */ | |
164 | ||
165 | RESET_REG_BITS (I2C_CONTROL, (0x1 << 3)); | |
166 | ||
167 | udelay (I2C_DELAY * 5); | |
168 | ||
169 | GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); | |
170 | count++; | |
171 | while ((status & 0xff) != 0x50) { | |
172 | udelay (I2C_DELAY); | |
173 | if (count > 2) { | |
174 | GT_REG_WRITE (I2C_CONTROL, (0x1 << 4)); /*stop */ | |
175 | return 0; | |
176 | } | |
177 | GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); | |
178 | count++; | |
179 | } | |
180 | GT_REG_READ (I2C_DATA, &data); | |
181 | len--; | |
182 | *return_data = (uchar) data; | |
183 | return_data++; | |
184 | } | |
185 | RESET_REG_BITS (I2C_CONTROL, BIT2 | BIT3); | |
186 | while ((status & 0xff) != 0x58) { | |
187 | udelay (I2C_DELAY); | |
188 | if (count > 200) { | |
189 | GT_REG_WRITE (I2C_CONTROL, (0x1 << 4)); /*stop */ | |
190 | return (status); | |
191 | } | |
192 | GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); | |
193 | count++; | |
194 | } | |
195 | GT_REG_WRITE (I2C_CONTROL, (0x1 << 4)); /* stop */ | |
196 | ||
197 | return (0); | |
198 | } | |
199 | ||
200 | static uchar i2c_write_data (unsigned int *data, int len) | |
201 | { | |
202 | unsigned int status; | |
203 | int count = 0; | |
204 | unsigned int temp; | |
205 | unsigned int *temp_ptr = data; | |
206 | ||
207 | DP (puts ("i2c_write_data\n")); | |
208 | ||
209 | while (len) { | |
210 | temp = (unsigned int) (*temp_ptr); | |
211 | GT_REG_WRITE (I2C_DATA, temp); | |
212 | RESET_REG_BITS (I2C_CONTROL, (0x1 << 3)); | |
213 | ||
214 | udelay (I2C_DELAY); | |
215 | ||
216 | GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); | |
217 | count++; | |
218 | while ((status & 0xff) != 0x28) { | |
219 | udelay (I2C_DELAY); | |
220 | if (count > 20) { | |
221 | GT_REG_WRITE (I2C_CONTROL, (0x1 << 4)); /*stop */ | |
222 | return (status); | |
223 | } | |
224 | GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); | |
225 | count++; | |
226 | } | |
227 | len--; | |
228 | temp_ptr++; | |
229 | } | |
230 | /* 11-14-2002 Paul Marchese */ | |
231 | /* Can't have the write issuing a stop command */ | |
232 | /* it's wrong to have a stop bit in read stream or write stream */ | |
233 | /* since we don't know if it's really the end of the command */ | |
234 | /* or whether we have just send the device address + offset */ | |
235 | /* we will push issuing the stop command off to the original */ | |
236 | /* calling function */ | |
237 | /* set the interrupt bit in the control register */ | |
238 | GT_REG_WRITE (I2C_CONTROL, (0x1 << 3)); | |
239 | udelay (I2C_DELAY * 10); | |
240 | return (0); | |
241 | } | |
242 | ||
243 | /* 11-14-2002 Paul Marchese */ | |
244 | /* created this function to get the i2c_write() */ | |
245 | /* function working properly. */ | |
246 | /* function to write bytes out on the i2c bus */ | |
247 | /* this is identical to the function i2c_write_data() */ | |
248 | /* except that it requires a buffer that is an */ | |
249 | /* unsigned character array. You can't use */ | |
250 | /* i2c_write_data() to send an array of unsigned characters */ | |
251 | /* since the byte of interest ends up on the wrong end of the bus */ | |
252 | /* aah, the joys of big endian versus little endian! */ | |
253 | /* */ | |
254 | /* returns 0 = success */ | |
255 | /* anything other than zero is failure */ | |
256 | static uchar i2c_write_byte (unsigned char *data, int len) | |
257 | { | |
258 | unsigned int status; | |
259 | int count = 0; | |
260 | unsigned int temp; | |
261 | unsigned char *temp_ptr = data; | |
262 | ||
263 | DP (puts ("i2c_write_byte\n")); | |
264 | ||
265 | while (len) { | |
266 | /* Set and assert the data */ | |
267 | temp = *temp_ptr; | |
268 | GT_REG_WRITE (I2C_DATA, temp); | |
269 | RESET_REG_BITS (I2C_CONTROL, (0x1 << 3)); | |
270 | ||
271 | udelay (I2C_DELAY); | |
272 | ||
273 | GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); | |
274 | count++; | |
275 | while ((status & 0xff) != 0x28) { | |
276 | udelay (I2C_DELAY); | |
277 | if (count > 20) { | |
278 | GT_REG_WRITE (I2C_CONTROL, (0x1 << 4)); /*stop */ | |
279 | return (status); | |
280 | } | |
281 | GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status); | |
282 | count++; | |
283 | } | |
284 | len--; | |
285 | temp_ptr++; | |
286 | } | |
287 | /* Can't have the write issuing a stop command */ | |
288 | /* it's wrong to have a stop bit in read stream or write stream */ | |
289 | /* since we don't know if it's really the end of the command */ | |
290 | /* or whether we have just send the device address + offset */ | |
291 | /* we will push issuing the stop command off to the original */ | |
292 | /* calling function */ | |
293 | /* GT_REG_WRITE(I2C_CONTROL, (0x1 << 3) | (0x1 << 4)); | |
294 | GT_REG_WRITE(I2C_CONTROL, (0x1 << 4)); */ | |
295 | /* set the interrupt bit in the control register */ | |
296 | GT_REG_WRITE (I2C_CONTROL, (0x1 << 3)); | |
297 | udelay (I2C_DELAY * 10); | |
298 | ||
299 | return (0); | |
300 | } | |
301 | ||
302 | static uchar | |
303 | i2c_set_dev_offset (uchar dev_addr, unsigned int offset, int ten_bit, | |
304 | int alen) | |
305 | { | |
306 | uchar status; | |
307 | unsigned int table[2]; | |
308 | ||
309 | /* initialize the table of address offset bytes */ | |
310 | /* utilized for 2 byte address offsets */ | |
311 | /* NOTE: the order is high byte first! */ | |
312 | table[1] = offset & 0xff; /* low byte */ | |
313 | table[0] = offset / 0x100; /* high byte */ | |
314 | ||
315 | DP (puts ("i2c_set_dev_offset\n")); | |
316 | ||
317 | status = i2c_select_device (dev_addr, 0, ten_bit); | |
318 | if (status) { | |
319 | #ifdef DEBUG_I2C | |
320 | printf ("Failed to select device setting offset: 0x%02x\n", | |
321 | status); | |
322 | #endif | |
323 | return status; | |
324 | } | |
325 | /* check the address offset length */ | |
326 | if (alen == 0) | |
327 | /* no address offset */ | |
328 | return (0); | |
329 | else if (alen == 1) { | |
330 | /* 1 byte address offset */ | |
331 | status = i2c_write_data (&offset, 1); | |
332 | if (status) { | |
333 | #ifdef DEBUG_I2C | |
334 | printf ("Failed to write data: 0x%02x\n", status); | |
335 | #endif | |
336 | return status; | |
337 | } | |
338 | } else if (alen == 2) { | |
339 | /* 2 bytes address offset */ | |
340 | status = i2c_write_data (table, 2); | |
341 | if (status) { | |
342 | #ifdef DEBUG_I2C | |
343 | printf ("Failed to write data: 0x%02x\n", status); | |
344 | #endif | |
345 | return status; | |
346 | } | |
347 | } else { | |
348 | /* address offset unknown or not supported */ | |
349 | printf ("Address length offset %d is not supported\n", alen); | |
350 | return 1; | |
351 | } | |
352 | return 0; /* sucessful completion */ | |
353 | } | |
354 | ||
a056b1ce | 355 | int |
3a473b2a WD |
356 | i2c_read (uchar dev_addr, unsigned int offset, int alen, uchar * data, |
357 | int len) | |
358 | { | |
359 | uchar status = 0; | |
6d0f6bcf | 360 | unsigned int i2cFreq = CONFIG_SYS_I2C_SPEED; |
3a473b2a WD |
361 | |
362 | DP (puts ("i2c_read\n")); | |
363 | ||
a056b1ce PT |
364 | /* set the i2c frequency */ |
365 | i2c_init (i2cFreq, CONFIG_SYS_I2C_SLAVE); | |
3a473b2a WD |
366 | |
367 | status = i2c_start (); | |
368 | ||
369 | if (status) { | |
370 | #ifdef DEBUG_I2C | |
371 | printf ("Transaction start failed: 0x%02x\n", status); | |
372 | #endif | |
373 | return status; | |
374 | } | |
375 | ||
376 | status = i2c_set_dev_offset (dev_addr, offset, 0, alen); /* send the slave address + offset */ | |
377 | if (status) { | |
378 | #ifdef DEBUG_I2C | |
379 | printf ("Failed to set slave address & offset: 0x%02x\n", | |
380 | status); | |
381 | #endif | |
382 | return status; | |
383 | } | |
384 | ||
a056b1ce PT |
385 | /* set the i2c frequency again */ |
386 | i2c_init (i2cFreq, CONFIG_SYS_I2C_SLAVE); | |
3a473b2a WD |
387 | |
388 | status = i2c_start (); | |
389 | if (status) { | |
390 | #ifdef DEBUG_I2C | |
391 | printf ("Transaction restart failed: 0x%02x\n", status); | |
392 | #endif | |
393 | return status; | |
394 | } | |
395 | ||
396 | status = i2c_select_device (dev_addr, 1, 0); /* send the slave address */ | |
397 | if (status) { | |
398 | #ifdef DEBUG_I2C | |
399 | printf ("Address not acknowledged: 0x%02x\n", status); | |
400 | #endif | |
401 | return status; | |
402 | } | |
403 | ||
404 | status = i2c_get_data (data, len); | |
405 | if (status) { | |
406 | #ifdef DEBUG_I2C | |
16263087 | 407 | printf ("Data not received: 0x%02x\n", status); |
3a473b2a WD |
408 | #endif |
409 | return status; | |
410 | } | |
411 | ||
412 | return 0; | |
413 | } | |
414 | ||
415 | /* 11-14-2002 Paul Marchese */ | |
416 | /* Function to set the I2C stop bit */ | |
417 | void i2c_stop (void) | |
418 | { | |
419 | GT_REG_WRITE (I2C_CONTROL, (0x1 << 4)); | |
420 | } | |
421 | ||
422 | /* 11-14-2002 Paul Marchese */ | |
423 | /* I2C write function */ | |
424 | /* dev_addr = device address */ | |
425 | /* offset = address offset */ | |
426 | /* alen = length in bytes of the address offset */ | |
427 | /* data = pointer to buffer to read data into */ | |
428 | /* len = # of bytes to read */ | |
429 | /* */ | |
430 | /* returns 0 = succesful */ | |
431 | /* anything but zero is failure */ | |
a056b1ce | 432 | int |
3a473b2a WD |
433 | i2c_write (uchar dev_addr, unsigned int offset, int alen, uchar * data, |
434 | int len) | |
435 | { | |
436 | uchar status = 0; | |
6d0f6bcf | 437 | unsigned int i2cFreq = CONFIG_SYS_I2C_SPEED; |
3a473b2a WD |
438 | |
439 | DP (puts ("i2c_write\n")); | |
440 | ||
a056b1ce PT |
441 | /* set the i2c frequency */ |
442 | i2c_init (i2cFreq, CONFIG_SYS_I2C_SLAVE); | |
3a473b2a WD |
443 | |
444 | status = i2c_start (); /* send a start bit */ | |
445 | ||
446 | if (status) { | |
447 | #ifdef DEBUG_I2C | |
448 | printf ("Transaction start failed: 0x%02x\n", status); | |
449 | #endif | |
450 | return status; | |
451 | } | |
452 | ||
453 | status = i2c_set_dev_offset (dev_addr, offset, 0, alen); /* send the slave address + offset */ | |
454 | if (status) { | |
455 | #ifdef DEBUG_I2C | |
456 | printf ("Failed to set slave address & offset: 0x%02x\n", | |
457 | status); | |
458 | #endif | |
459 | return status; | |
460 | } | |
461 | ||
462 | ||
463 | status = i2c_write_byte (data, len); /* write the data */ | |
464 | if (status) { | |
465 | #ifdef DEBUG_I2C | |
466 | printf ("Data not written: 0x%02x\n", status); | |
467 | #endif | |
468 | return status; | |
469 | } | |
470 | /* issue a stop bit */ | |
471 | i2c_stop (); | |
472 | return 0; | |
473 | } | |
474 | ||
475 | /* 11-14-2002 Paul Marchese */ | |
476 | /* function to determine if an I2C device is present */ | |
477 | /* chip = device address of chip to check for */ | |
478 | /* */ | |
479 | /* returns 0 = sucessful, the device exists */ | |
480 | /* anything other than zero is failure, no device */ | |
481 | int i2c_probe (uchar chip) | |
482 | { | |
483 | ||
484 | /* We are just looking for an <ACK> back. */ | |
485 | /* To see if the device/chip is there */ | |
486 | ||
487 | #ifdef DEBUG_I2C | |
488 | unsigned int i2c_status; | |
489 | #endif | |
490 | uchar status = 0; | |
6d0f6bcf | 491 | unsigned int i2cFreq = CONFIG_SYS_I2C_SPEED; |
3a473b2a WD |
492 | |
493 | DP (puts ("i2c_probe\n")); | |
494 | ||
a056b1ce PT |
495 | /* set the i2c frequency */ |
496 | i2c_init (i2cFreq, CONFIG_SYS_I2C_SLAVE); | |
3a473b2a WD |
497 | |
498 | status = i2c_start (); /* send a start bit */ | |
499 | ||
500 | if (status) { | |
501 | #ifdef DEBUG_I2C | |
502 | printf ("Transaction start failed: 0x%02x\n", status); | |
503 | #endif | |
504 | return (int) status; | |
505 | } | |
506 | ||
507 | status = i2c_set_dev_offset (chip, 0, 0, 0); /* send the slave address + no offset */ | |
508 | if (status) { | |
509 | #ifdef DEBUG_I2C | |
510 | printf ("Failed to set slave address: 0x%02x\n", status); | |
511 | #endif | |
512 | return (int) status; | |
513 | } | |
514 | #ifdef DEBUG_I2C | |
515 | GT_REG_READ (I2C_STATUS_BAUDE_RATE, &i2c_status); | |
516 | printf ("address %#x returned %#x\n", chip, i2c_status); | |
517 | #endif | |
518 | /* issue a stop bit */ | |
519 | i2c_stop (); | |
520 | return 0; /* successful completion */ | |
521 | } |