]>
Commit | Line | Data |
---|---|---|
8ed96046 WD |
1 | /* |
2 | * Basic I2C functions | |
3 | * | |
4 | * Copyright (c) 2004 Texas Instruments | |
5 | * | |
6 | * This package is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the license found in the file | |
8 | * named COPYING that should have accompanied this file. | |
9 | * | |
10 | * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
11 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
12 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
13 | * | |
14 | * Author: Jian Zhang jzhang@ti.com, Texas Instruments | |
15 | * | |
16 | * Copyright (c) 2003 Wolfgang Denk, wd@denx.de | |
17 | * Rewritten to fit into the current U-Boot framework | |
18 | * | |
19 | * Adapted for OMAP2420 I2C, r-woodruff2@ti.com | |
20 | * | |
21 | */ | |
22 | ||
23 | #include <common.h> | |
289f932c | 24 | |
8ed96046 WD |
25 | #include <asm/arch/i2c.h> |
26 | #include <asm/io.h> | |
27 | ||
938717ce SS |
28 | #include "omap24xx_i2c.h" |
29 | ||
73e8747f | 30 | #define I2C_TIMEOUT 1000 |
d708395d | 31 | |
8ed96046 WD |
32 | static void wait_for_bb (void); |
33 | static u16 wait_for_pin (void); | |
49a7581c | 34 | static void flush_fifo(void); |
8ed96046 | 35 | |
1d2e96de DB |
36 | static struct i2c *i2c_base = (struct i2c *)I2C_DEFAULT_BASE; |
37 | ||
38 | static unsigned int bus_initialized[I2C_BUS_MAX]; | |
39 | static unsigned int current_bus; | |
40 | ||
8ed96046 WD |
41 | void i2c_init (int speed, int slaveadd) |
42 | { | |
1724fe9a | 43 | DECLARE_GLOBAL_DATA_PTR; |
7f79dfb4 TR |
44 | int psc, fsscll, fssclh; |
45 | int hsscll = 0, hssclh = 0; | |
46 | u32 scll, sclh; | |
d708395d | 47 | int timeout = I2C_TIMEOUT; |
7f79dfb4 TR |
48 | |
49 | /* Only handle standard, fast and high speeds */ | |
50 | if ((speed != OMAP_I2C_STANDARD) && | |
51 | (speed != OMAP_I2C_FAST_MODE) && | |
52 | (speed != OMAP_I2C_HIGH_SPEED)) { | |
53 | printf("Error : I2C unsupported speed %d\n", speed); | |
54 | return; | |
55 | } | |
56 | ||
57 | psc = I2C_IP_CLK / I2C_INTERNAL_SAMPLING_CLK; | |
58 | psc -= 1; | |
59 | if (psc < I2C_PSC_MIN) { | |
60 | printf("Error : I2C unsupported prescalar %d\n", psc); | |
61 | return; | |
62 | } | |
63 | ||
64 | if (speed == OMAP_I2C_HIGH_SPEED) { | |
65 | /* High speed */ | |
66 | ||
67 | /* For first phase of HS mode */ | |
68 | fsscll = fssclh = I2C_INTERNAL_SAMPLING_CLK / | |
69 | (2 * OMAP_I2C_FAST_MODE); | |
70 | ||
71 | fsscll -= I2C_HIGHSPEED_PHASE_ONE_SCLL_TRIM; | |
72 | fssclh -= I2C_HIGHSPEED_PHASE_ONE_SCLH_TRIM; | |
73 | if (((fsscll < 0) || (fssclh < 0)) || | |
74 | ((fsscll > 255) || (fssclh > 255))) { | |
75 | printf("Error : I2C initializing first phase clock\n"); | |
76 | return; | |
77 | } | |
78 | ||
79 | /* For second phase of HS mode */ | |
80 | hsscll = hssclh = I2C_INTERNAL_SAMPLING_CLK / (2 * speed); | |
81 | ||
82 | hsscll -= I2C_HIGHSPEED_PHASE_TWO_SCLL_TRIM; | |
83 | hssclh -= I2C_HIGHSPEED_PHASE_TWO_SCLH_TRIM; | |
84 | if (((fsscll < 0) || (fssclh < 0)) || | |
85 | ((fsscll > 255) || (fssclh > 255))) { | |
86 | printf("Error : I2C initializing second phase clock\n"); | |
87 | return; | |
88 | } | |
89 | ||
90 | scll = (unsigned int)hsscll << 8 | (unsigned int)fsscll; | |
91 | sclh = (unsigned int)hssclh << 8 | (unsigned int)fssclh; | |
92 | ||
93 | } else { | |
94 | /* Standard and fast speed */ | |
95 | fsscll = fssclh = I2C_INTERNAL_SAMPLING_CLK / (2 * speed); | |
96 | ||
97 | fsscll -= I2C_FASTSPEED_SCLL_TRIM; | |
98 | fssclh -= I2C_FASTSPEED_SCLH_TRIM; | |
99 | if (((fsscll < 0) || (fssclh < 0)) || | |
100 | ((fsscll > 255) || (fssclh > 255))) { | |
101 | printf("Error : I2C initializing clock\n"); | |
102 | return; | |
103 | } | |
104 | ||
105 | scll = (unsigned int)fsscll; | |
106 | sclh = (unsigned int)fssclh; | |
107 | } | |
8ed96046 | 108 | |
1d2e96de DB |
109 | if (readw (&i2c_base->con) & I2C_CON_EN) { |
110 | writew (0, &i2c_base->con); | |
8ed96046 WD |
111 | udelay (50000); |
112 | } | |
113 | ||
d708395d SS |
114 | writew(0x2, &i2c_base->sysc); /* for ES2 after soft reset */ |
115 | udelay(1000); | |
116 | ||
117 | writew(I2C_CON_EN, &i2c_base->con); | |
118 | while (!(readw(&i2c_base->syss) & I2C_SYSS_RDONE) && timeout--) { | |
119 | if (timeout <= 0) { | |
120 | printf("ERROR: Timeout in soft-reset\n"); | |
121 | return; | |
122 | } | |
123 | udelay(1000); | |
124 | } | |
125 | ||
126 | writew(0, &i2c_base->con); | |
1d2e96de DB |
127 | writew(psc, &i2c_base->psc); |
128 | writew(scll, &i2c_base->scll); | |
129 | writew(sclh, &i2c_base->sclh); | |
7f79dfb4 | 130 | |
8ed96046 | 131 | /* own address */ |
1d2e96de DB |
132 | writew (slaveadd, &i2c_base->oa); |
133 | writew (I2C_CON_EN, &i2c_base->con); | |
49a7581c | 134 | |
8ed96046 | 135 | /* have to enable intrrupts or OMAP i2c module doesn't work */ |
e23c7c95 | 136 | writew (I2C_IE_XRDY_IE | I2C_IE_RRDY_IE | I2C_IE_ARDY_IE | |
1d2e96de | 137 | I2C_IE_NACK_IE | I2C_IE_AL_IE, &i2c_base->ie); |
8ed96046 | 138 | udelay (1000); |
49a7581c | 139 | flush_fifo(); |
1d2e96de DB |
140 | writew (0xFFFF, &i2c_base->stat); |
141 | writew (0, &i2c_base->cnt); | |
142 | ||
1724fe9a HS |
143 | if (gd->flags & GD_FLG_RELOC) |
144 | bus_initialized[current_bus] = 1; | |
8ed96046 WD |
145 | } |
146 | ||
147 | static int i2c_read_byte (u8 devaddr, u8 regoffset, u8 * value) | |
148 | { | |
149 | int i2c_error = 0; | |
150 | u16 status; | |
151 | ||
152 | /* wait until bus not busy */ | |
153 | wait_for_bb (); | |
154 | ||
155 | /* one byte only */ | |
1d2e96de | 156 | writew (1, &i2c_base->cnt); |
8ed96046 | 157 | /* set slave address */ |
1d2e96de | 158 | writew (devaddr, &i2c_base->sa); |
8ed96046 | 159 | /* no stop bit needed here */ |
1d2e96de | 160 | writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX, &i2c_base->con); |
8ed96046 | 161 | |
da0cc665 SS |
162 | /* send register offset */ |
163 | while (1) { | |
164 | status = wait_for_pin(); | |
165 | if (status == 0 || status & I2C_STAT_NACK) { | |
8ed96046 | 166 | i2c_error = 1; |
da0cc665 SS |
167 | goto read_exit; |
168 | } | |
169 | if (status & I2C_STAT_XRDY) { | |
170 | /* Important: have to use byte access */ | |
171 | writeb(regoffset, &i2c_base->data); | |
172 | writew(I2C_STAT_XRDY, &i2c_base->stat); | |
173 | } | |
174 | if (status & I2C_STAT_ARDY) { | |
175 | writew(I2C_STAT_ARDY, &i2c_base->stat); | |
176 | break; | |
8ed96046 | 177 | } |
8ed96046 WD |
178 | } |
179 | ||
da0cc665 SS |
180 | /* set slave address */ |
181 | writew(devaddr, &i2c_base->sa); | |
182 | /* read one byte from slave */ | |
183 | writew(1, &i2c_base->cnt); | |
184 | /* need stop bit here */ | |
185 | writew(I2C_CON_EN | I2C_CON_MST | | |
186 | I2C_CON_STT | I2C_CON_STP, | |
187 | &i2c_base->con); | |
188 | ||
189 | /* receive data */ | |
190 | while (1) { | |
191 | status = wait_for_pin(); | |
192 | if (status == 0 || status & I2C_STAT_NACK) { | |
193 | i2c_error = 1; | |
194 | goto read_exit; | |
8ed96046 | 195 | } |
8ed96046 | 196 | if (status & I2C_STAT_RRDY) { |
938717ce SS |
197 | #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ |
198 | defined(CONFIG_OMAP44XX) | |
da0cc665 | 199 | *value = readb(&i2c_base->data); |
7d264c1e | 200 | #else |
da0cc665 | 201 | *value = readw(&i2c_base->data); |
7d264c1e | 202 | #endif |
da0cc665 | 203 | writew(I2C_STAT_RRDY, &i2c_base->stat); |
8ed96046 | 204 | } |
da0cc665 SS |
205 | if (status & I2C_STAT_ARDY) { |
206 | writew(I2C_STAT_ARDY, &i2c_base->stat); | |
207 | break; | |
8ed96046 WD |
208 | } |
209 | } | |
da0cc665 SS |
210 | |
211 | read_exit: | |
8ed96046 | 212 | flush_fifo(); |
1d2e96de DB |
213 | writew (0xFFFF, &i2c_base->stat); |
214 | writew (0, &i2c_base->cnt); | |
8ed96046 WD |
215 | return i2c_error; |
216 | } | |
217 | ||
218 | static int i2c_write_byte (u8 devaddr, u8 regoffset, u8 value) | |
219 | { | |
220 | int i2c_error = 0; | |
d480c467 | 221 | u16 status; |
8ed96046 WD |
222 | |
223 | /* wait until bus not busy */ | |
224 | wait_for_bb (); | |
225 | ||
226 | /* two bytes */ | |
1d2e96de | 227 | writew (2, &i2c_base->cnt); |
8ed96046 | 228 | /* set slave address */ |
1d2e96de | 229 | writew (devaddr, &i2c_base->sa); |
8ed96046 | 230 | /* stop bit needed here */ |
e23c7c95 | 231 | writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX | |
1d2e96de | 232 | I2C_CON_STP, &i2c_base->con); |
8ed96046 | 233 | |
d480c467 SS |
234 | while (1) { |
235 | status = wait_for_pin(); | |
236 | if (status == 0 || status & I2C_STAT_NACK) { | |
7d264c1e | 237 | i2c_error = 1; |
d480c467 | 238 | goto write_exit; |
7d264c1e | 239 | } |
d480c467 SS |
240 | if (status & I2C_STAT_XRDY) { |
241 | #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ | |
242 | defined(CONFIG_OMAP44XX) | |
243 | /* send register offset */ | |
244 | writeb(regoffset, &i2c_base->data); | |
245 | writew(I2C_STAT_XRDY, &i2c_base->stat); | |
246 | ||
247 | while (1) { | |
248 | status = wait_for_pin(); | |
249 | if (status == 0 || status & I2C_STAT_NACK) { | |
250 | i2c_error = 1; | |
251 | goto write_exit; | |
252 | } | |
253 | if (status & I2C_STAT_XRDY) { | |
254 | /* send data */ | |
255 | writeb(value, &i2c_base->data); | |
256 | writew(I2C_STAT_XRDY, &i2c_base->stat); | |
257 | } | |
258 | if (status & I2C_STAT_ARDY) { | |
259 | writew(I2C_STAT_ARDY, &i2c_base->stat); | |
260 | break; | |
261 | } | |
262 | } | |
263 | break; | |
7d264c1e | 264 | #else |
d480c467 SS |
265 | /* send out two bytes */ |
266 | writew((value << 8) + regoffset, &i2c_base->data); | |
267 | writew(I2C_STAT_XRDY, &i2c_base->stat); | |
7d264c1e | 268 | #endif |
8ed96046 | 269 | } |
d480c467 SS |
270 | if (status & I2C_STAT_ARDY) { |
271 | writew(I2C_STAT_ARDY, &i2c_base->stat); | |
272 | break; | |
273 | } | |
8ed96046 WD |
274 | } |
275 | ||
d480c467 | 276 | wait_for_bb(); |
49a7581c | 277 | |
d480c467 SS |
278 | status = readw(&i2c_base->stat); |
279 | if (status & I2C_STAT_NACK) | |
280 | i2c_error = 1; | |
281 | ||
282 | write_exit: | |
8ed96046 | 283 | flush_fifo(); |
1d2e96de DB |
284 | writew (0xFFFF, &i2c_base->stat); |
285 | writew (0, &i2c_base->cnt); | |
8ed96046 WD |
286 | return i2c_error; |
287 | } | |
288 | ||
49a7581c | 289 | static void flush_fifo(void) |
8ed96046 | 290 | { u16 stat; |
082acfd4 WD |
291 | |
292 | /* note: if you try and read data when its not there or ready | |
293 | * you get a bus error | |
294 | */ | |
8ed96046 | 295 | while(1){ |
1d2e96de | 296 | stat = readw(&i2c_base->stat); |
8ed96046 | 297 | if(stat == I2C_STAT_RRDY){ |
938717ce SS |
298 | #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ |
299 | defined(CONFIG_OMAP44XX) | |
1d2e96de | 300 | readb(&i2c_base->data); |
7d264c1e | 301 | #else |
1d2e96de | 302 | readw(&i2c_base->data); |
7d264c1e | 303 | #endif |
1d2e96de | 304 | writew(I2C_STAT_RRDY,&i2c_base->stat); |
8ed96046 WD |
305 | udelay(1000); |
306 | }else | |
307 | break; | |
308 | } | |
309 | } | |
310 | ||
311 | int i2c_probe (uchar chip) | |
312 | { | |
fbad3555 | 313 | u16 status; |
8ed96046 WD |
314 | int res = 1; /* default = fail */ |
315 | ||
1d2e96de | 316 | if (chip == readw (&i2c_base->oa)) { |
8ed96046 WD |
317 | return res; |
318 | } | |
319 | ||
320 | /* wait until bus not busy */ | |
321 | wait_for_bb (); | |
322 | ||
323 | /* try to read one byte */ | |
1d2e96de | 324 | writew (1, &i2c_base->cnt); |
8ed96046 | 325 | /* set slave address */ |
1d2e96de | 326 | writew (chip, &i2c_base->sa); |
8ed96046 | 327 | /* stop bit needed here */ |
1d2e96de | 328 | writew (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP, &i2c_base->con); |
8ed96046 | 329 | |
fbad3555 SS |
330 | while (1) { |
331 | status = wait_for_pin(); | |
4df66894 | 332 | if (status == 0 || status & I2C_STAT_AL) { |
fbad3555 SS |
333 | res = 1; |
334 | goto probe_exit; | |
335 | } | |
336 | if (status & I2C_STAT_NACK) { | |
337 | res = 1; | |
338 | writew(0xff, &i2c_base->stat); | |
339 | writew (readw (&i2c_base->con) | I2C_CON_STP, &i2c_base->con); | |
340 | wait_for_bb (); | |
341 | break; | |
342 | } | |
343 | if (status & I2C_STAT_ARDY) { | |
344 | writew(I2C_STAT_ARDY, &i2c_base->stat); | |
345 | break; | |
346 | } | |
347 | if (status & I2C_STAT_RRDY) { | |
348 | res = 0; | |
349 | #if defined(CONFIG_OMAP243X) || defined(CONFIG_OMAP34XX) || \ | |
350 | defined(CONFIG_OMAP44XX) | |
351 | readb(&i2c_base->data); | |
352 | #else | |
353 | readw(&i2c_base->data); | |
354 | #endif | |
355 | writew(I2C_STAT_RRDY, &i2c_base->stat); | |
356 | } | |
8ed96046 | 357 | } |
fbad3555 SS |
358 | |
359 | probe_exit: | |
8ed96046 | 360 | flush_fifo(); |
1d2e96de DB |
361 | writew (0, &i2c_base->cnt); /* don't allow any more data in...we don't want it.*/ |
362 | writew(0xFFFF, &i2c_base->stat); | |
8ed96046 WD |
363 | return res; |
364 | } | |
365 | ||
366 | int i2c_read (uchar chip, uint addr, int alen, uchar * buffer, int len) | |
367 | { | |
368 | int i; | |
369 | ||
370 | if (alen > 1) { | |
371 | printf ("I2C read: addr len %d not supported\n", alen); | |
372 | return 1; | |
373 | } | |
374 | ||
375 | if (addr + len > 256) { | |
376 | printf ("I2C read: address out of range\n"); | |
377 | return 1; | |
378 | } | |
379 | ||
380 | for (i = 0; i < len; i++) { | |
381 | if (i2c_read_byte (chip, addr + i, &buffer[i])) { | |
382 | printf ("I2C read: I/O error\n"); | |
6d0f6bcf | 383 | i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); |
8ed96046 WD |
384 | return 1; |
385 | } | |
386 | } | |
387 | ||
388 | return 0; | |
389 | } | |
390 | ||
391 | int i2c_write (uchar chip, uint addr, int alen, uchar * buffer, int len) | |
392 | { | |
393 | int i; | |
394 | ||
395 | if (alen > 1) { | |
396 | printf ("I2C read: addr len %d not supported\n", alen); | |
397 | return 1; | |
398 | } | |
399 | ||
400 | if (addr + len > 256) { | |
401 | printf ("I2C read: address out of range\n"); | |
402 | return 1; | |
403 | } | |
404 | ||
405 | for (i = 0; i < len; i++) { | |
406 | if (i2c_write_byte (chip, addr + i, buffer[i])) { | |
407 | printf ("I2C read: I/O error\n"); | |
6d0f6bcf | 408 | i2c_init (CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); |
8ed96046 WD |
409 | return 1; |
410 | } | |
411 | } | |
412 | ||
413 | return 0; | |
414 | } | |
415 | ||
416 | static void wait_for_bb (void) | |
417 | { | |
73e8747f | 418 | int timeout = I2C_TIMEOUT; |
8ed96046 WD |
419 | u16 stat; |
420 | ||
1d2e96de DB |
421 | writew(0xFFFF, &i2c_base->stat); /* clear current interruts...*/ |
422 | while ((stat = readw (&i2c_base->stat) & I2C_STAT_BB) && timeout--) { | |
423 | writew (stat, &i2c_base->stat); | |
73e8747f | 424 | udelay(1000); |
8ed96046 WD |
425 | } |
426 | ||
427 | if (timeout <= 0) { | |
428 | printf ("timed out in wait_for_bb: I2C_STAT=%x\n", | |
1d2e96de | 429 | readw (&i2c_base->stat)); |
8ed96046 | 430 | } |
1d2e96de | 431 | writew(0xFFFF, &i2c_base->stat); /* clear delayed stuff*/ |
8ed96046 WD |
432 | } |
433 | ||
434 | static u16 wait_for_pin (void) | |
435 | { | |
436 | u16 status; | |
73e8747f | 437 | int timeout = I2C_TIMEOUT; |
8ed96046 WD |
438 | |
439 | do { | |
440 | udelay (1000); | |
1d2e96de | 441 | status = readw (&i2c_base->stat); |
8ed96046 WD |
442 | } while ( !(status & |
443 | (I2C_STAT_ROVR | I2C_STAT_XUDF | I2C_STAT_XRDY | | |
444 | I2C_STAT_RRDY | I2C_STAT_ARDY | I2C_STAT_NACK | | |
445 | I2C_STAT_AL)) && timeout--); | |
446 | ||
447 | if (timeout <= 0) { | |
448 | printf ("timed out in wait_for_pin: I2C_STAT=%x\n", | |
1d2e96de | 449 | readw (&i2c_base->stat)); |
73e8747f SS |
450 | writew(0xFFFF, &i2c_base->stat); |
451 | status = 0; | |
452 | } | |
453 | ||
8ed96046 WD |
454 | return status; |
455 | } | |
1d2e96de DB |
456 | |
457 | int i2c_set_bus_num(unsigned int bus) | |
458 | { | |
459 | if ((bus < 0) || (bus >= I2C_BUS_MAX)) { | |
460 | printf("Bad bus: %d\n", bus); | |
461 | return -1; | |
462 | } | |
463 | ||
464 | #if I2C_BUS_MAX==3 | |
465 | if (bus == 2) | |
466 | i2c_base = (struct i2c *)I2C_BASE3; | |
467 | else | |
468 | #endif | |
469 | if (bus == 1) | |
470 | i2c_base = (struct i2c *)I2C_BASE2; | |
471 | else | |
472 | i2c_base = (struct i2c *)I2C_BASE1; | |
473 | ||
474 | current_bus = bus; | |
475 | ||
476 | if(!bus_initialized[current_bus]) | |
477 | i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); | |
478 | ||
479 | return 0; | |
480 | } | |
938717ce SS |
481 | |
482 | int i2c_get_bus_num(void) | |
483 | { | |
484 | return (int) current_bus; | |
485 | } |