blob: bad0dac05d479f000aff9484a7f5ee61c26a5136 [file] [log] [blame]
stroesec096c842004-12-16 18:21:17 +00001/*
2 * (C) Copyright 2000
3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02005 * SPDX-License-Identifier: GPL-2.0+
stroesec096c842004-12-16 18:21:17 +00006 *
7 * Hacked for the DB64360 board by Ingo.Assmus@keymile.com
8 * extra improvments by Brain Waite
9 * for cpci750 by reinhard.arlt@esd-electronics.com
10 */
11#include <common.h>
12#include <mpc8xx.h>
13#include <malloc.h>
Peter Tyserdc2da6c2009-04-24 15:34:06 -050014#include <i2c.h>
stroesec096c842004-12-16 18:21:17 +000015#include "../../Marvell/include/mv_gen_reg.h"
16#include "../../Marvell/include/core.h"
17
18#define I2C_DELAY 100
19#undef DEBUG_I2C
20
21#ifdef DEBUG_I2C
22#define DP(x) x
23#else
24#define DP(x)
25#endif
26
27/* Assuming that there is only one master on the bus (us) */
28
Peter Tyserdc2da6c2009-04-24 15:34:06 -050029void i2c_init (int speed, int slaveaddr)
stroesec096c842004-12-16 18:21:17 +000030{
31 unsigned int n, m, freq, margin, power;
32 unsigned int actualN = 0, actualM = 0;
33 unsigned int minMargin = 0xffffffff;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +020034 unsigned int tclk = CONFIG_SYS_TCLK;
stroesec096c842004-12-16 18:21:17 +000035 unsigned int i2cFreq = speed; /* 100000 max. Fast mode not supported */
36
37 DP (puts ("i2c_init\n"));
38/* gtI2cMasterInit */
39 for (n = 0; n < 8; n++) {
40 for (m = 0; m < 16; m++) {
41 power = 2 << n; /* power = 2^(n+1) */
42 freq = tclk / (10 * (m + 1) * power);
43 if (i2cFreq > freq)
44 margin = i2cFreq - freq;
45 else
46 margin = freq - i2cFreq;
47 if (margin < minMargin) {
48 minMargin = margin;
49 actualN = n;
50 actualM = m;
51 }
52 }
53 }
54
55 DP (puts ("setup i2c bus\n"));
56
57 /* Setup bus */
58 /* gtI2cReset */
59 GT_REG_WRITE (I2C_SOFT_RESET, 0);
wdenk07d7e6b2004-12-16 21:44:03 +000060 asm(" sync");
stroesec096c842004-12-16 18:21:17 +000061 GT_REG_WRITE (I2C_CONTROL, 0);
wdenk07d7e6b2004-12-16 21:44:03 +000062 asm(" sync");
stroesec096c842004-12-16 18:21:17 +000063
64 DP (puts ("set baudrate\n"));
65
66 GT_REG_WRITE (I2C_STATUS_BAUDE_RATE, (actualM << 3) | actualN);
wdenk07d7e6b2004-12-16 21:44:03 +000067 asm(" sync");
stroesec096c842004-12-16 18:21:17 +000068
69 DP (puts ("udelay...\n"));
70
71 udelay (I2C_DELAY);
72
73 GT_REG_WRITE (I2C_CONTROL, (0x1 << 2) | (0x1 << 6));
wdenk07d7e6b2004-12-16 21:44:03 +000074 asm(" sync");
stroesec096c842004-12-16 18:21:17 +000075}
76
77
78static uchar i2c_select_device (uchar dev_addr, uchar read, int ten_bit)
79{
80 unsigned int status, data, bits = 7;
wdenk07d7e6b2004-12-16 21:44:03 +000081 unsigned int control;
stroesec096c842004-12-16 18:21:17 +000082 int count = 0;
83
84 DP (puts ("i2c_select_device\n"));
85
86 /* Output slave address */
87
88 if (ten_bit) {
89 bits = 10;
90 }
91
92 GT_REG_READ (I2C_CONTROL, &control);
93 control |= (0x1 << 2);
94 GT_REG_WRITE (I2C_CONTROL, control);
wdenk07d7e6b2004-12-16 21:44:03 +000095 asm(" sync");
stroesec096c842004-12-16 18:21:17 +000096
97 GT_REG_READ (I2C_CONTROL, &control);
98 control |= (0x1 << 5); /* generate the I2C_START_BIT */
99 GT_REG_WRITE (I2C_CONTROL, control);
wdenk07d7e6b2004-12-16 21:44:03 +0000100 asm(" sync");
stroesec096c842004-12-16 18:21:17 +0000101 RESET_REG_BITS (I2C_CONTROL, (0x01 << 3));
wdenk07d7e6b2004-12-16 21:44:03 +0000102 asm(" sync");
stroesec096c842004-12-16 18:21:17 +0000103
104 GT_REG_READ (I2C_CONTROL, &status);
105 while ((status & 0x08) != 0x08) {
wdenk07d7e6b2004-12-16 21:44:03 +0000106 GT_REG_READ (I2C_CONTROL, &status);
107 }
stroesec096c842004-12-16 18:21:17 +0000108
109
110 count = 0;
111
112 GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status);
113 while (((status & 0xff) != 0x08) && ((status & 0xff) != 0x10)){
114 if (count > 200) {
115#ifdef DEBUG_I2C
wdenk07d7e6b2004-12-16 21:44:03 +0000116 printf ("Failed to set startbit: 0x%02x\n", status);
stroesec096c842004-12-16 18:21:17 +0000117#endif
118 GT_REG_WRITE (I2C_CONTROL, (0x1 << 4)); /*stop */
119 asm(" sync");
120 return (status);
121 }
122 GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status);
123 count++;
124 }
125
126 DP (puts ("i2c_select_device:write addr byte\n"));
127
128 /* assert the address */
129
130 data = (dev_addr << 1);
131 /* set the read bit */
132 data |= read;
133 GT_REG_WRITE (I2C_DATA, data);
wdenk07d7e6b2004-12-16 21:44:03 +0000134 asm(" sync");
stroesec096c842004-12-16 18:21:17 +0000135 RESET_REG_BITS (I2C_CONTROL, BIT3);
wdenk07d7e6b2004-12-16 21:44:03 +0000136 asm(" sync");
stroesec096c842004-12-16 18:21:17 +0000137
138 GT_REG_READ (I2C_CONTROL, &status);
139 while ((status & 0x08) != 0x08) {
wdenk07d7e6b2004-12-16 21:44:03 +0000140 GT_REG_READ (I2C_CONTROL, &status);
141 }
stroesec096c842004-12-16 18:21:17 +0000142
143 GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status);
144 count = 0;
145 while (((status & 0xff) != 0x40) && ((status & 0xff) != 0x18)) {
146 if (count > 200) {
147#ifdef DEBUG_I2C
wdenk07d7e6b2004-12-16 21:44:03 +0000148 printf ("Failed to write address: 0x%02x\n", status);
stroesec096c842004-12-16 18:21:17 +0000149#endif
150 GT_REG_WRITE (I2C_CONTROL, (0x1 << 4)); /*stop */
151 return (status);
152 }
153 GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status);
154 asm(" sync");
155 count++;
156 }
157
158 if (bits == 10) {
159 printf ("10 bit I2C addressing not yet implemented\n");
160 return (0xff);
161 }
162
163 return (0);
164}
165
166static uchar i2c_get_data (uchar * return_data, int len)
167{
168
169 unsigned int data, status;
170 int count = 0;
171
172 DP (puts ("i2c_get_data\n"));
173
174 while (len) {
175
176 RESET_REG_BITS (I2C_CONTROL, BIT3);
177 asm(" sync");
178
179 /* Get and return the data */
180
181 GT_REG_READ (I2C_CONTROL, &status);
182 while ((status & 0x08) != 0x08) {
wdenk07d7e6b2004-12-16 21:44:03 +0000183 GT_REG_READ (I2C_CONTROL, &status);
184 }
stroesec096c842004-12-16 18:21:17 +0000185
186 GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status);
187 count++;
188 while ((status & 0xff) != 0x50) {
189 if (count > 20) {
190#ifdef DEBUG_I2C
wdenk07d7e6b2004-12-16 21:44:03 +0000191 printf ("Failed to get data len status: 0x%02x\n", status);
stroesec096c842004-12-16 18:21:17 +0000192#endif
193 GT_REG_WRITE (I2C_CONTROL, (0x1 << 4)); /*stop */
194 asm(" sync");
195 return 0;
196 }
197 GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status);
198 count++;
199 }
200 GT_REG_READ (I2C_DATA, &data);
201 len--;
202 *return_data = (uchar) data;
203 return_data++;
204
205 }
206 RESET_REG_BITS (I2C_CONTROL, BIT2 | BIT3);
wdenk07d7e6b2004-12-16 21:44:03 +0000207 asm(" sync");
stroesec096c842004-12-16 18:21:17 +0000208 count = 0;
209
210 GT_REG_READ (I2C_CONTROL, &status);
211 while ((status & 0x08) != 0x08) {
wdenk07d7e6b2004-12-16 21:44:03 +0000212 GT_REG_READ (I2C_CONTROL, &status);
213 }
stroesec096c842004-12-16 18:21:17 +0000214
215 while ((status & 0xff) != 0x58) {
216 if (count > 2000) {
217 GT_REG_WRITE (I2C_CONTROL, (0x1 << 4)); /*stop */
218 return (status);
219 }
220 GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status);
221 count++;
222 }
223 GT_REG_WRITE (I2C_CONTROL, (0x1 << 4)); /* stop */
wdenk07d7e6b2004-12-16 21:44:03 +0000224 asm(" sync");
stroesec096c842004-12-16 18:21:17 +0000225 RESET_REG_BITS (I2C_CONTROL, (0x1 << 3));
wdenk07d7e6b2004-12-16 21:44:03 +0000226 asm(" sync");
stroesec096c842004-12-16 18:21:17 +0000227
228 return (0);
229}
230
231
232static uchar i2c_write_data (unsigned int *data, int len)
233{
234 unsigned int status;
235 int count;
236 unsigned int temp;
237 unsigned int *temp_ptr = data;
238
239 DP (puts ("i2c_write_data\n"));
240
241 while (len) {
wdenk07d7e6b2004-12-16 21:44:03 +0000242 count = 0;
stroesec096c842004-12-16 18:21:17 +0000243 temp = (unsigned int) (*temp_ptr);
244 GT_REG_WRITE (I2C_DATA, temp);
245 asm(" sync");
246 RESET_REG_BITS (I2C_CONTROL, (0x1 << 3));
247 asm(" sync");
248
249 GT_REG_READ (I2C_CONTROL, &status);
250 while ((status & 0x08) != 0x08) {
251 GT_REG_READ (I2C_CONTROL, &status);
wdenk07d7e6b2004-12-16 21:44:03 +0000252 }
stroesec096c842004-12-16 18:21:17 +0000253
254 GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status);
255 count++;
256 while ((status & 0xff) != 0x28) {
257 if (count > 200) {
258 GT_REG_WRITE (I2C_CONTROL, (0x1 << 4)); /*stop */
259 asm(" sync");
260 return (status);
261 }
262 GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status);
263 count++;
264 }
265 len--;
266 temp_ptr++;
267 }
268 return (0);
269}
270
271
272static uchar i2c_write_byte (unsigned char *data, int len)
273{
274 unsigned int status;
275 int count;
276 unsigned int temp;
277 unsigned char *temp_ptr = data;
278
279 DP (puts ("i2c_write_byte\n"));
280
281 while (len) {
wdenk07d7e6b2004-12-16 21:44:03 +0000282 count = 0;
stroesec096c842004-12-16 18:21:17 +0000283 /* Set and assert the data */
284 temp = *temp_ptr;
285 GT_REG_WRITE (I2C_DATA, temp);
286 asm(" sync");
287 RESET_REG_BITS (I2C_CONTROL, (0x1 << 3));
288 asm(" sync");
289
290
291 GT_REG_READ (I2C_CONTROL, &status);
292 while ((status & 0x08) != 0x08) {
293 GT_REG_READ (I2C_CONTROL, &status);
wdenk07d7e6b2004-12-16 21:44:03 +0000294 }
stroesec096c842004-12-16 18:21:17 +0000295
296 GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status);
297 count++;
298 while ((status & 0xff) != 0x28) {
299 if (count > 200) {
300 GT_REG_WRITE (I2C_CONTROL, (0x1 << 4)); /*stop */
301 asm(" sync");
302 return (status);
303 }
304 GT_REG_READ (I2C_STATUS_BAUDE_RATE, &status);
305 count++;
306 }
307 len--;
308 temp_ptr++;
309 }
310 return (0);
311}
312
313static uchar
314i2c_set_dev_offset (uchar dev_addr, unsigned int offset, int ten_bit,
315 int alen)
316{
317 uchar status;
318 unsigned int table[2];
319
320 table[1] = (offset ) & 0x0ff; /* low byte */
321 table[0] = (offset >> 8) & 0x0ff; /* high byte */
322
323 DP (puts ("i2c_set_dev_offset\n"));
324
325 status = i2c_select_device (dev_addr, 0, ten_bit);
326 if (status) {
327#ifdef DEBUG_I2C
32822 printf ("Failed to select device setting offset: 0x%02x\n",
329 status);
330#endif
331 return status;
332 }
333/* check the address offset length */
334 if (alen == 0)
335 /* no address offset */
336 return (0);
337 else if (alen == 1) {
338 /* 1 byte address offset */
339 status = i2c_write_data (&offset, 1);
340 if (status) {
341#ifdef DEBUG_I2C
342 printf ("Failed to write data: 0x%02x\n", status);
343#endif
344 return status;
345 }
346 } else if (alen == 2) {
347 /* 2 bytes address offset */
348 status = i2c_write_data (table, 2);
349 if (status) {
350#ifdef DEBUG_I2C
351 printf ("Failed to write data: 0x%02x\n", status);
352#endif
353 return status;
354 }
355 } else {
356 /* address offset unknown or not supported */
357 printf ("Address length offset %d is not supported\n", alen);
358 return 1;
359 }
360 return 0; /* sucessful completion */
361}
362
Peter Tyserdc2da6c2009-04-24 15:34:06 -0500363int
stroesec096c842004-12-16 18:21:17 +0000364i2c_read (uchar dev_addr, unsigned int offset, int alen, uchar * data,
365 int len)
366{
367 uchar status = 0;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200368 unsigned int i2cFreq = CONFIG_SYS_I2C_SPEED;
stroesec096c842004-12-16 18:21:17 +0000369
370 DP (puts ("i2c_read\n"));
371
Peter Tyserdc2da6c2009-04-24 15:34:06 -0500372 /* set the i2c frequency */
373 i2c_init (i2cFreq, CONFIG_SYS_I2C_SLAVE);
stroesec096c842004-12-16 18:21:17 +0000374
375 status = i2c_set_dev_offset (dev_addr, offset, 0, alen); /* send the slave address + offset */
376 if (status) {
377#ifdef DEBUG_I2C
378 printf ("Failed to set slave address & offset: 0x%02x\n",
379 status);
380#endif
381 return status;
382 }
383
384 status = i2c_select_device (dev_addr, 1, 0);
385 if (status) {
386#ifdef DEBUG_I2C
387 printf ("Failed to select device for data read: 0x%02x\n",
388 status);
389#endif
390 return status;
391 }
392
393 status = i2c_get_data (data, len);
394 if (status) {
395#ifdef DEBUG_I2C
396 printf ("Data not read: 0x%02x\n", status);
397#endif
398 return status;
399 }
400
401 return 0;
402}
403
404
405void i2c_stop (void)
406{
407 GT_REG_WRITE (I2C_CONTROL, (0x1 << 4));
wdenk07d7e6b2004-12-16 21:44:03 +0000408 asm(" sync");
stroesec096c842004-12-16 18:21:17 +0000409}
410
411
Peter Tyserdc2da6c2009-04-24 15:34:06 -0500412int
stroesec096c842004-12-16 18:21:17 +0000413i2c_write (uchar dev_addr, unsigned int offset, int alen, uchar * data,
414 int len)
415{
416 uchar status = 0;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200417 unsigned int i2cFreq = CONFIG_SYS_I2C_SPEED;
stroesec096c842004-12-16 18:21:17 +0000418
419 DP (puts ("i2c_write\n"));
420
Peter Tyserdc2da6c2009-04-24 15:34:06 -0500421 /* set the i2c frequency */
422 i2c_init (i2cFreq, CONFIG_SYS_I2C_SLAVE);
stroesec096c842004-12-16 18:21:17 +0000423
424 status = i2c_set_dev_offset (dev_addr, offset, 0, alen); /* send the slave address + offset */
425 if (status) {
426#ifdef DEBUG_I2C
427 printf ("Failed to set slave address & offset: 0x%02x\n",
428 status);
429#endif
430 return status;
wdenk07d7e6b2004-12-16 21:44:03 +0000431 }
stroesec096c842004-12-16 18:21:17 +0000432
433
434 status = i2c_write_byte (data, len); /* write the data */
435 if (status) {
436#ifdef DEBUG_I2C
437 printf ("Data not written: 0x%02x\n", status);
438#endif
439 return status;
wdenk07d7e6b2004-12-16 21:44:03 +0000440 }
stroesec096c842004-12-16 18:21:17 +0000441 /* issue a stop bit */
442 i2c_stop ();
443 return 0;
444}
445
446
447int i2c_probe (uchar chip)
448{
449
450#ifdef DEBUG_I2C
451 unsigned int i2c_status;
452#endif
453 uchar status = 0;
Jean-Christophe PLAGNIOL-VILLARD03836942008-10-16 15:01:15 +0200454 unsigned int i2cFreq = CONFIG_SYS_I2C_SPEED;
stroesec096c842004-12-16 18:21:17 +0000455
456 DP (puts ("i2c_probe\n"));
457
Peter Tyserdc2da6c2009-04-24 15:34:06 -0500458 /* set the i2c frequency */
459 i2c_init (i2cFreq, CONFIG_SYS_I2C_SLAVE);
stroesec096c842004-12-16 18:21:17 +0000460
461 status = i2c_set_dev_offset (chip, 0, 0, 0); /* send the slave address + no offset */
462 if (status) {
463#ifdef DEBUG_I2C
464 printf ("Failed to set slave address: 0x%02x\n", status);
465#endif
466 return (int) status;
467 }
468#ifdef DEBUG_I2C
469 GT_REG_READ (I2C_STATUS_BAUDE_RATE, &i2c_status);
470 printf ("address %#x returned %#x\n", chip, i2c_status);
471#endif
472 /* issue a stop bit */
473 i2c_stop ();
474 return 0; /* successful completion */
475}