]>
Commit | Line | Data |
---|---|---|
62219a28 WD |
1 | /* |
2 | * (C) Copyright 2000 | |
3 | * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it | |
4 | * | |
5 | * (C) Copyright 2000 Sysgo Real-Time Solutions, GmbH <www.elinos.com> | |
6 | * Marius Groeger <mgroeger@sysgo.de> | |
7 | * | |
1a459660 | 8 | * SPDX-License-Identifier: GPL-2.0+ |
62219a28 WD |
9 | * |
10 | * Back ported to the 8xx platform (from the 8260 platform) by | |
11 | * Murray.Jensen@cmst.csiro.au, 27-Jan-01. | |
12 | */ | |
13 | ||
14 | #include <common.h> | |
24b852a7 | 15 | #include <console.h> |
62219a28 WD |
16 | |
17 | #ifdef CONFIG_HARD_I2C | |
18 | ||
19 | #include <commproc.h> | |
20 | #include <i2c.h> | |
62219a28 | 21 | |
d87080b7 WD |
22 | DECLARE_GLOBAL_DATA_PTR; |
23 | ||
62219a28 WD |
24 | /* tx/rx timeout (we need the i2c early, so we don't use get_timer()) */ |
25 | #define TOUT_LOOP 1000000 | |
26 | ||
27 | #define NUM_RX_BDS 4 | |
28 | #define NUM_TX_BDS 4 | |
29 | #define MAX_TX_SPACE 256 | |
30 | #define I2C_RXTX_LEN 128 /* maximum tx/rx buffer length */ | |
31 | ||
09e68ffa WD |
32 | typedef struct I2C_BD { |
33 | unsigned short status; | |
34 | unsigned short length; | |
35 | unsigned char *addr; | |
62219a28 | 36 | } I2C_BD; |
09e68ffa WD |
37 | |
38 | #define BD_I2C_TX_START 0x0400 /* special status for i2c: Start condition */ | |
62219a28 WD |
39 | |
40 | #define BD_I2C_TX_CL 0x0001 /* collision error */ | |
41 | #define BD_I2C_TX_UN 0x0002 /* underflow error */ | |
42 | #define BD_I2C_TX_NAK 0x0004 /* no acknowledge error */ | |
43 | #define BD_I2C_TX_ERR (BD_I2C_TX_NAK|BD_I2C_TX_UN|BD_I2C_TX_CL) | |
44 | ||
45 | #define BD_I2C_RX_ERR BD_SC_OV | |
46 | ||
09e68ffa | 47 | typedef void (*i2c_ecb_t) (int, int); /* error callback function */ |
62219a28 WD |
48 | |
49 | /* This structure keeps track of the bd and buffer space usage. */ | |
50 | typedef struct i2c_state { | |
09e68ffa WD |
51 | int rx_idx; /* index to next free Rx BD */ |
52 | int tx_idx; /* index to next free Tx BD */ | |
53 | void *rxbd; /* pointer to next free Rx BD */ | |
54 | void *txbd; /* pointer to next free Tx BD */ | |
55 | int tx_space; /* number of Tx bytes left */ | |
56 | unsigned char *tx_buf; /* pointer to free Tx area */ | |
57 | i2c_ecb_t err_cb; /* error callback function */ | |
62219a28 WD |
58 | } i2c_state_t; |
59 | ||
60 | ||
61 | /* flags for i2c_send() and i2c_receive() */ | |
09e68ffa WD |
62 | #define I2CF_ENABLE_SECONDARY 0x01 /* secondary_address is valid */ |
63 | #define I2CF_START_COND 0x02 /* tx: generate start condition */ | |
64 | #define I2CF_STOP_COND 0x04 /* tx: generate stop condition */ | |
62219a28 WD |
65 | |
66 | /* return codes */ | |
09e68ffa WD |
67 | #define I2CERR_NO_BUFFERS 0x01 /* no more BDs or buffer space */ |
68 | #define I2CERR_MSG_TOO_LONG 0x02 /* tried to send/receive to much data */ | |
69 | #define I2CERR_TIMEOUT 0x03 /* timeout in i2c_doio() */ | |
70 | #define I2CERR_QUEUE_EMPTY 0x04 /* i2c_doio called without send/receive */ | |
62219a28 WD |
71 | |
72 | /* error callback flags */ | |
09e68ffa WD |
73 | #define I2CECB_RX_ERR 0x10 /* this is a receive error */ |
74 | #define I2CECB_RX_ERR_OV 0x02 /* receive overrun error */ | |
75 | #define I2CECB_RX_MASK 0x0f /* mask for error bits */ | |
76 | #define I2CECB_TX_ERR 0x20 /* this is a transmit error */ | |
77 | #define I2CECB_TX_CL 0x01 /* transmit collision error */ | |
78 | #define I2CECB_TX_UN 0x02 /* transmit underflow error */ | |
79 | #define I2CECB_TX_NAK 0x04 /* transmit no ack error */ | |
80 | #define I2CECB_TX_MASK 0x0f /* mask for error bits */ | |
81 | #define I2CECB_TIMEOUT 0x40 /* this is a timeout error */ | |
62219a28 | 82 | |
62219a28 WD |
83 | /* |
84 | * Returns the best value of I2BRG to meet desired clock speed of I2C with | |
85 | * input parameters (clock speed, filter, and predivider value). | |
86 | * It returns computer speed value and the difference between it and desired | |
87 | * speed. | |
88 | */ | |
89 | static inline int | |
90 | i2c_roundrate(int hz, int speed, int filter, int modval, | |
09e68ffa | 91 | int *brgval, int *totspeed) |
62219a28 | 92 | { |
09e68ffa | 93 | int moddiv = 1 << (5 - (modval & 3)), brgdiv, div; |
62219a28 | 94 | |
937943d3 WD |
95 | debug("\t[I2C] trying hz=%d, speed=%d, filter=%d, modval=%d\n", |
96 | hz, speed, filter, modval); | |
62219a28 | 97 | |
09e68ffa WD |
98 | div = moddiv * speed; |
99 | brgdiv = (hz + div - 1) / div; | |
62219a28 | 100 | |
937943d3 | 101 | debug("\t\tmoddiv=%d, brgdiv=%d\n", moddiv, brgdiv); |
62219a28 | 102 | |
09e68ffa | 103 | *brgval = ((brgdiv + 1) / 2) - 3 - (2 * filter); |
62219a28 | 104 | |
09e68ffa | 105 | if ((*brgval < 0) || (*brgval > 255)) { |
937943d3 | 106 | debug("\t\trejected brgval=%d\n", *brgval); |
09e68ffa WD |
107 | return -1; |
108 | } | |
62219a28 | 109 | |
09e68ffa WD |
110 | brgdiv = 2 * (*brgval + 3 + (2 * filter)); |
111 | div = moddiv * brgdiv; | |
112 | *totspeed = hz / div; | |
62219a28 | 113 | |
937943d3 | 114 | debug("\t\taccepted brgval=%d, totspeed=%d\n", *brgval, *totspeed); |
62219a28 | 115 | |
09e68ffa | 116 | return 0; |
62219a28 WD |
117 | } |
118 | ||
119 | /* | |
120 | * Sets the I2C clock predivider and divider to meet required clock speed. | |
121 | */ | |
09e68ffa | 122 | static int i2c_setrate(int hz, int speed) |
62219a28 | 123 | { |
09e68ffa | 124 | immap_t *immap = (immap_t *) CONFIG_SYS_IMMR; |
62219a28 | 125 | volatile i2c8xx_t *i2c = (i2c8xx_t *) & immap->im_i2c; |
09e68ffa WD |
126 | int brgval, |
127 | modval, /* 0-3 */ | |
128 | bestspeed_diff = speed, | |
129 | bestspeed_brgval = 0, | |
130 | bestspeed_modval = 0, | |
131 | bestspeed_filter = 0, | |
132 | totspeed, | |
133 | filter = 0; /* Use this fixed value */ | |
62219a28 WD |
134 | |
135 | for (modval = 0; modval < 4; modval++) { | |
09e68ffa WD |
136 | if (i2c_roundrate |
137 | (hz, speed, filter, modval, &brgval, &totspeed) == 0) { | |
62219a28 WD |
138 | int diff = speed - totspeed; |
139 | ||
140 | if ((diff >= 0) && (diff < bestspeed_diff)) { | |
141 | bestspeed_diff = diff; | |
142 | bestspeed_modval = modval; | |
143 | bestspeed_brgval = brgval; | |
144 | bestspeed_filter = filter; | |
145 | } | |
146 | } | |
147 | } | |
148 | ||
937943d3 WD |
149 | debug("[I2C] Best is:\n"); |
150 | debug("[I2C] CPU=%dhz RATE=%d F=%d I2MOD=%08x I2BRG=%08x DIFF=%dhz\n", | |
62219a28 WD |
151 | hz, |
152 | speed, | |
153 | bestspeed_filter, | |
154 | bestspeed_modval, | |
155 | bestspeed_brgval, | |
937943d3 | 156 | bestspeed_diff); |
62219a28 | 157 | |
09e68ffa WD |
158 | i2c->i2c_i2mod |= |
159 | ((bestspeed_modval & 3) << 1) | (bestspeed_filter << 3); | |
62219a28 WD |
160 | i2c->i2c_i2brg = bestspeed_brgval & 0xff; |
161 | ||
937943d3 WD |
162 | debug("[I2C] i2mod=%08x i2brg=%08x\n", |
163 | i2c->i2c_i2mod, | |
164 | i2c->i2c_i2brg); | |
62219a28 WD |
165 | |
166 | return 1; | |
167 | } | |
168 | ||
09e68ffa | 169 | void i2c_init(int speed, int slaveaddr) |
62219a28 | 170 | { |
09e68ffa | 171 | volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR; |
62219a28 | 172 | volatile cpm8xx_t *cp = (cpm8xx_t *)&immap->im_cpm; |
09e68ffa | 173 | volatile i2c8xx_t *i2c = (i2c8xx_t *)&immap->im_i2c; |
62219a28 WD |
174 | volatile iic_t *iip = (iic_t *)&cp->cp_dparam[PROFF_IIC]; |
175 | ulong rbase, tbase; | |
176 | volatile I2C_BD *rxbd, *txbd; | |
177 | uint dpaddr; | |
178 | ||
6d0f6bcf | 179 | #ifdef CONFIG_SYS_I2C_INIT_BOARD |
47cd00fa WD |
180 | /* call board specific i2c bus reset routine before accessing the */ |
181 | /* environment, which might be in a chip on that bus. For details */ | |
182 | /* about this problem see doc/I2C_Edge_Conditions. */ | |
183 | i2c_init_board(); | |
184 | #endif | |
185 | ||
6d0f6bcf | 186 | #ifdef CONFIG_SYS_I2C_UCODE_PATCH |
62219a28 WD |
187 | iip = (iic_t *)&cp->cp_dpmem[iip->iic_rpbase]; |
188 | #else | |
189 | /* Disable relocation */ | |
190 | iip->iic_rpbase = 0; | |
191 | #endif | |
192 | ||
62219a28 | 193 | dpaddr = CPM_I2C_BASE; |
62219a28 WD |
194 | |
195 | /* | |
196 | * initialise data in dual port ram: | |
197 | * | |
198 | * dpaddr->rbase -> rx BD (NUM_RX_BDS * sizeof(I2C_BD) bytes) | |
199 | * tbase -> tx BD (NUM_TX_BDS * sizeof(I2C_BD) bytes) | |
200 | * tx buffer (MAX_TX_SPACE bytes) | |
201 | */ | |
202 | ||
203 | rbase = dpaddr; | |
204 | tbase = rbase + NUM_RX_BDS * sizeof(I2C_BD); | |
205 | ||
206 | /* Initialize Port B I2C pins. */ | |
207 | cp->cp_pbpar |= 0x00000030; | |
208 | cp->cp_pbdir |= 0x00000030; | |
209 | cp->cp_pbodr |= 0x00000030; | |
210 | ||
211 | /* Disable interrupts */ | |
212 | i2c->i2c_i2mod = 0x00; | |
213 | i2c->i2c_i2cmr = 0x00; | |
214 | i2c->i2c_i2cer = 0xff; | |
215 | i2c->i2c_i2add = slaveaddr; | |
216 | ||
217 | /* | |
218 | * Set the I2C BRG Clock division factor from desired i2c rate | |
219 | * and current CPU rate (we assume sccr dfbgr field is 0; | |
220 | * divide BRGCLK by 1) | |
221 | */ | |
937943d3 | 222 | debug("[I2C] Setting rate...\n"); |
09e68ffa | 223 | i2c_setrate(gd->cpu_clk, CONFIG_SYS_I2C_SPEED); |
62219a28 WD |
224 | |
225 | /* Set I2C controller in master mode */ | |
226 | i2c->i2c_i2com = 0x01; | |
227 | ||
228 | /* Set SDMA bus arbitration level to 5 (SDCR) */ | |
09e68ffa | 229 | immap->im_siu_conf.sc_sdcr = 0x0001; |
62219a28 WD |
230 | |
231 | /* Initialize Tx/Rx parameters */ | |
232 | iip->iic_rbase = rbase; | |
233 | iip->iic_tbase = tbase; | |
09e68ffa WD |
234 | rxbd = (I2C_BD *) ((unsigned char *) &cp->cp_dpmem[iip->iic_rbase]); |
235 | txbd = (I2C_BD *) ((unsigned char *) &cp->cp_dpmem[iip->iic_tbase]); | |
62219a28 | 236 | |
937943d3 WD |
237 | debug("[I2C] rbase = %04x\n", iip->iic_rbase); |
238 | debug("[I2C] tbase = %04x\n", iip->iic_tbase); | |
239 | debug("[I2C] rxbd = %08x\n", (int)rxbd); | |
240 | debug("[I2C] txbd = %08x\n", (int)txbd); | |
62219a28 WD |
241 | |
242 | /* Set big endian byte order */ | |
243 | iip->iic_tfcr = 0x10; | |
244 | iip->iic_rfcr = 0x10; | |
245 | ||
246 | /* Set maximum receive size. */ | |
247 | iip->iic_mrblr = I2C_RXTX_LEN; | |
248 | ||
6d0f6bcf | 249 | #ifdef CONFIG_SYS_I2C_UCODE_PATCH |
62219a28 WD |
250 | /* |
251 | * Initialize required parameters if using microcode patch. | |
252 | */ | |
09e68ffa WD |
253 | iip->iic_rbptr = iip->iic_rbase; |
254 | iip->iic_tbptr = iip->iic_tbase; | |
62219a28 WD |
255 | iip->iic_rstate = 0; |
256 | iip->iic_tstate = 0; | |
257 | #else | |
258 | cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_INIT_TRX) | CPM_CR_FLG; | |
259 | do { | |
09e68ffa | 260 | __asm__ __volatile__("eieio"); |
62219a28 WD |
261 | } while (cp->cp_cpcr & CPM_CR_FLG); |
262 | #endif | |
263 | ||
264 | /* Clear events and interrupts */ | |
265 | i2c->i2c_i2cer = 0xff; | |
266 | i2c->i2c_i2cmr = 0x00; | |
267 | } | |
268 | ||
09e68ffa | 269 | static void i2c_newio(i2c_state_t *state) |
62219a28 | 270 | { |
09e68ffa | 271 | volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR; |
62219a28 WD |
272 | volatile cpm8xx_t *cp = (cpm8xx_t *)&immap->im_cpm; |
273 | volatile iic_t *iip = (iic_t *)&cp->cp_dparam[PROFF_IIC]; | |
274 | ||
937943d3 | 275 | debug("[I2C] i2c_newio\n"); |
62219a28 | 276 | |
6d0f6bcf | 277 | #ifdef CONFIG_SYS_I2C_UCODE_PATCH |
62219a28 WD |
278 | iip = (iic_t *)&cp->cp_dpmem[iip->iic_rpbase]; |
279 | #endif | |
280 | state->rx_idx = 0; | |
281 | state->tx_idx = 0; | |
09e68ffa WD |
282 | state->rxbd = (void *)&cp->cp_dpmem[iip->iic_rbase]; |
283 | state->txbd = (void *)&cp->cp_dpmem[iip->iic_tbase]; | |
62219a28 | 284 | state->tx_space = MAX_TX_SPACE; |
09e68ffa | 285 | state->tx_buf = (uchar *)state->txbd + NUM_TX_BDS * sizeof(I2C_BD); |
62219a28 WD |
286 | state->err_cb = NULL; |
287 | ||
937943d3 WD |
288 | debug("[I2C] rxbd = %08x\n", (int)state->rxbd); |
289 | debug("[I2C] txbd = %08x\n", (int)state->txbd); | |
290 | debug("[I2C] tx_buf = %08x\n", (int)state->tx_buf); | |
62219a28 WD |
291 | |
292 | /* clear the buffer memory */ | |
293 | memset((char *)state->tx_buf, 0, MAX_TX_SPACE); | |
294 | } | |
295 | ||
296 | static int | |
297 | i2c_send(i2c_state_t *state, | |
298 | unsigned char address, | |
299 | unsigned char secondary_address, | |
09e68ffa | 300 | unsigned int flags, unsigned short size, unsigned char *dataout) |
62219a28 WD |
301 | { |
302 | volatile I2C_BD *txbd; | |
09e68ffa | 303 | int i, j; |
62219a28 | 304 | |
937943d3 WD |
305 | debug("[I2C] i2c_send add=%02d sec=%02d flag=%02d size=%d\n", |
306 | address, secondary_address, flags, size); | |
62219a28 WD |
307 | |
308 | /* trying to send message larger than BD */ | |
309 | if (size > I2C_RXTX_LEN) | |
09e68ffa | 310 | return I2CERR_MSG_TOO_LONG; |
62219a28 WD |
311 | |
312 | /* no more free bds */ | |
313 | if (state->tx_idx >= NUM_TX_BDS || state->tx_space < (2 + size)) | |
09e68ffa | 314 | return I2CERR_NO_BUFFERS; |
62219a28 | 315 | |
09e68ffa | 316 | txbd = (I2C_BD *) state->txbd; |
62219a28 WD |
317 | txbd->addr = state->tx_buf; |
318 | ||
937943d3 | 319 | debug("[I2C] txbd = %08x\n", (int)txbd); |
62219a28 WD |
320 | |
321 | if (flags & I2CF_START_COND) { | |
937943d3 | 322 | debug("[I2C] Formatting addresses...\n"); |
62219a28 | 323 | if (flags & I2CF_ENABLE_SECONDARY) { |
09e68ffa WD |
324 | /* Length of msg + dest addr */ |
325 | txbd->length = size + 2; | |
326 | ||
62219a28 WD |
327 | txbd->addr[0] = address << 1; |
328 | txbd->addr[1] = secondary_address; | |
329 | i = 2; | |
330 | } else { | |
09e68ffa WD |
331 | /* Length of msg + dest addr */ |
332 | txbd->length = size + 1; | |
333 | /* Write dest addr to BD */ | |
334 | txbd->addr[0] = address << 1; | |
62219a28 WD |
335 | i = 1; |
336 | } | |
337 | } else { | |
09e68ffa | 338 | txbd->length = size; /* Length of message */ |
62219a28 WD |
339 | i = 0; |
340 | } | |
341 | ||
342 | /* set up txbd */ | |
343 | txbd->status = BD_SC_READY; | |
344 | if (flags & I2CF_START_COND) | |
09e68ffa | 345 | txbd->status |= BD_I2C_TX_START; |
62219a28 | 346 | if (flags & I2CF_STOP_COND) |
09e68ffa | 347 | txbd->status |= BD_SC_LAST | BD_SC_WRAP; |
62219a28 WD |
348 | |
349 | /* Copy data to send into buffer */ | |
937943d3 | 350 | debug("[I2C] copy data...\n"); |
62219a28 | 351 | for(j = 0; j < size; i++, j++) |
09e68ffa | 352 | txbd->addr[i] = dataout[j]; |
62219a28 | 353 | |
937943d3 | 354 | debug("[I2C] txbd: length=0x%04x status=0x%04x addr[0]=0x%02x addr[1]=0x%02x\n", |
09e68ffa WD |
355 | txbd->length, |
356 | txbd->status, | |
357 | txbd->addr[0], | |
937943d3 | 358 | txbd->addr[1]); |
62219a28 WD |
359 | |
360 | /* advance state */ | |
361 | state->tx_buf += txbd->length; | |
362 | state->tx_space -= txbd->length; | |
363 | state->tx_idx++; | |
09e68ffa | 364 | state->txbd = (void *) (txbd + 1); |
62219a28 WD |
365 | |
366 | return 0; | |
367 | } | |
368 | ||
369 | static int | |
370 | i2c_receive(i2c_state_t *state, | |
371 | unsigned char address, | |
372 | unsigned char secondary_address, | |
373 | unsigned int flags, | |
09e68ffa | 374 | unsigned short size_to_expect, unsigned char *datain) |
62219a28 WD |
375 | { |
376 | volatile I2C_BD *rxbd, *txbd; | |
377 | ||
937943d3 WD |
378 | debug("[I2C] i2c_receive %02d %02d %02d\n", |
379 | address, secondary_address, flags); | |
62219a28 WD |
380 | |
381 | /* Expected to receive too much */ | |
382 | if (size_to_expect > I2C_RXTX_LEN) | |
09e68ffa | 383 | return I2CERR_MSG_TOO_LONG; |
62219a28 WD |
384 | |
385 | /* no more free bds */ | |
386 | if (state->tx_idx >= NUM_TX_BDS || state->rx_idx >= NUM_RX_BDS | |
09e68ffa WD |
387 | || state->tx_space < 2) |
388 | return I2CERR_NO_BUFFERS; | |
62219a28 | 389 | |
09e68ffa WD |
390 | rxbd = (I2C_BD *) state->rxbd; |
391 | txbd = (I2C_BD *) state->txbd; | |
62219a28 | 392 | |
937943d3 WD |
393 | debug("[I2C] rxbd = %08x\n", (int)rxbd); |
394 | debug("[I2C] txbd = %08x\n", (int)txbd); | |
62219a28 WD |
395 | |
396 | txbd->addr = state->tx_buf; | |
397 | ||
398 | /* set up TXBD for destination address */ | |
399 | if (flags & I2CF_ENABLE_SECONDARY) { | |
400 | txbd->length = 2; | |
09e68ffa WD |
401 | txbd->addr[0] = address << 1; /* Write data */ |
402 | txbd->addr[1] = secondary_address; /* Internal address */ | |
62219a28 WD |
403 | txbd->status = BD_SC_READY; |
404 | } else { | |
405 | txbd->length = 1 + size_to_expect; | |
406 | txbd->addr[0] = (address << 1) | 0x01; | |
407 | txbd->status = BD_SC_READY; | |
408 | memset(&txbd->addr[1], 0, txbd->length); | |
409 | } | |
410 | ||
411 | /* set up rxbd for reception */ | |
412 | rxbd->status = BD_SC_EMPTY; | |
413 | rxbd->length = size_to_expect; | |
414 | rxbd->addr = datain; | |
415 | ||
416 | txbd->status |= BD_I2C_TX_START; | |
417 | if (flags & I2CF_STOP_COND) { | |
418 | txbd->status |= BD_SC_LAST | BD_SC_WRAP; | |
419 | rxbd->status |= BD_SC_WRAP; | |
420 | } | |
421 | ||
937943d3 | 422 | debug("[I2C] txbd: length=0x%04x status=0x%04x addr[0]=0x%02x addr[1]=0x%02x\n", |
09e68ffa WD |
423 | txbd->length, |
424 | txbd->status, | |
425 | txbd->addr[0], | |
937943d3 WD |
426 | txbd->addr[1]); |
427 | debug("[I2C] rxbd: length=0x%04x status=0x%04x addr[0]=0x%02x addr[1]=0x%02x\n", | |
09e68ffa WD |
428 | rxbd->length, |
429 | rxbd->status, | |
430 | rxbd->addr[0], | |
937943d3 | 431 | rxbd->addr[1]); |
62219a28 WD |
432 | |
433 | /* advance state */ | |
434 | state->tx_buf += txbd->length; | |
435 | state->tx_space -= txbd->length; | |
436 | state->tx_idx++; | |
09e68ffa | 437 | state->txbd = (void *) (txbd + 1); |
62219a28 | 438 | state->rx_idx++; |
09e68ffa | 439 | state->rxbd = (void *) (rxbd + 1); |
62219a28 WD |
440 | |
441 | return 0; | |
442 | } | |
443 | ||
444 | ||
445 | static int i2c_doio(i2c_state_t *state) | |
446 | { | |
09e68ffa | 447 | volatile immap_t *immap = (immap_t *)CONFIG_SYS_IMMR; |
62219a28 | 448 | volatile cpm8xx_t *cp = (cpm8xx_t *)&immap->im_cpm; |
09e68ffa | 449 | volatile i2c8xx_t *i2c = (i2c8xx_t *)&immap->im_i2c; |
62219a28 WD |
450 | volatile iic_t *iip = (iic_t *)&cp->cp_dparam[PROFF_IIC]; |
451 | volatile I2C_BD *txbd, *rxbd; | |
452 | volatile int j = 0; | |
453 | ||
937943d3 | 454 | debug("[I2C] i2c_doio\n"); |
62219a28 | 455 | |
6d0f6bcf | 456 | #ifdef CONFIG_SYS_I2C_UCODE_PATCH |
62219a28 WD |
457 | iip = (iic_t *)&cp->cp_dpmem[iip->iic_rpbase]; |
458 | #endif | |
459 | ||
460 | if (state->tx_idx <= 0 && state->rx_idx <= 0) { | |
937943d3 | 461 | debug("[I2C] No I/O is queued\n"); |
62219a28 WD |
462 | return I2CERR_QUEUE_EMPTY; |
463 | } | |
464 | ||
465 | iip->iic_rbptr = iip->iic_rbase; | |
466 | iip->iic_tbptr = iip->iic_tbase; | |
467 | ||
468 | /* Enable I2C */ | |
937943d3 | 469 | debug("[I2C] Enabling I2C...\n"); |
62219a28 WD |
470 | i2c->i2c_i2mod |= 0x01; |
471 | ||
472 | /* Begin transmission */ | |
473 | i2c->i2c_i2com |= 0x80; | |
474 | ||
475 | /* Loop until transmit & receive completed */ | |
476 | ||
477 | if (state->tx_idx > 0) { | |
478 | txbd = ((I2C_BD*)state->txbd) - 1; | |
937943d3 WD |
479 | |
480 | debug("[I2C] Transmitting...(txbd=0x%08lx)\n", | |
481 | (ulong)txbd); | |
482 | ||
09e68ffa WD |
483 | while ((txbd->status & BD_SC_READY) && (j++ < TOUT_LOOP)) { |
484 | if (ctrlc()) | |
62219a28 | 485 | return (-1); |
09e68ffa WD |
486 | |
487 | __asm__ __volatile__("eieio"); | |
62219a28 WD |
488 | } |
489 | } | |
490 | ||
491 | if ((state->rx_idx > 0) && (j < TOUT_LOOP)) { | |
492 | rxbd = ((I2C_BD*)state->rxbd) - 1; | |
937943d3 WD |
493 | |
494 | debug("[I2C] Receiving...(rxbd=0x%08lx)\n", | |
495 | (ulong)rxbd); | |
496 | ||
09e68ffa WD |
497 | while ((rxbd->status & BD_SC_EMPTY) && (j++ < TOUT_LOOP)) { |
498 | if (ctrlc()) | |
62219a28 | 499 | return (-1); |
09e68ffa WD |
500 | |
501 | __asm__ __volatile__("eieio"); | |
62219a28 WD |
502 | } |
503 | } | |
504 | ||
505 | /* Turn off I2C */ | |
506 | i2c->i2c_i2mod &= ~0x01; | |
507 | ||
508 | if (state->err_cb != NULL) { | |
509 | int n, i, b; | |
510 | ||
511 | /* | |
512 | * if we have an error callback function, look at the | |
513 | * error bits in the bd status and pass them back | |
514 | */ | |
515 | ||
516 | if ((n = state->tx_idx) > 0) { | |
517 | for (i = 0; i < n; i++) { | |
09e68ffa | 518 | txbd = ((I2C_BD *) state->txbd) - (n - i); |
62219a28 | 519 | if ((b = txbd->status & BD_I2C_TX_ERR) != 0) |
09e68ffa WD |
520 | (*state->err_cb) (I2CECB_TX_ERR | b, |
521 | i); | |
62219a28 WD |
522 | } |
523 | } | |
524 | ||
525 | if ((n = state->rx_idx) > 0) { | |
526 | for (i = 0; i < n; i++) { | |
09e68ffa | 527 | rxbd = ((I2C_BD *) state->rxbd) - (n - i); |
62219a28 | 528 | if ((b = rxbd->status & BD_I2C_RX_ERR) != 0) |
09e68ffa WD |
529 | (*state->err_cb) (I2CECB_RX_ERR | b, |
530 | i); | |
62219a28 WD |
531 | } |
532 | } | |
533 | ||
534 | if (j >= TOUT_LOOP) | |
09e68ffa | 535 | (*state->err_cb) (I2CECB_TIMEOUT, 0); |
62219a28 WD |
536 | } |
537 | ||
538 | return (j >= TOUT_LOOP) ? I2CERR_TIMEOUT : 0; | |
539 | } | |
540 | ||
541 | static int had_tx_nak; | |
542 | ||
09e68ffa | 543 | static void i2c_test_callback(int flags, int xnum) |
62219a28 WD |
544 | { |
545 | if ((flags & I2CECB_TX_ERR) && (flags & I2CECB_TX_NAK)) | |
546 | had_tx_nak = 1; | |
547 | } | |
548 | ||
549 | int i2c_probe(uchar chip) | |
550 | { | |
551 | i2c_state_t state; | |
53677ef1 | 552 | int rc; |
62219a28 WD |
553 | uchar buf[1]; |
554 | ||
6d0f6bcf | 555 | i2c_init(CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE); |
62219a28 WD |
556 | |
557 | i2c_newio(&state); | |
558 | ||
559 | state.err_cb = i2c_test_callback; | |
560 | had_tx_nak = 0; | |
561 | ||
09e68ffa WD |
562 | rc = i2c_receive(&state, chip, 0, I2CF_START_COND | I2CF_STOP_COND, 1, |
563 | buf); | |
62219a28 WD |
564 | |
565 | if (rc != 0) | |
566 | return (rc); | |
567 | ||
568 | rc = i2c_doio(&state); | |
569 | ||
570 | if ((rc != 0) && (rc != I2CERR_TIMEOUT)) | |
571 | return (rc); | |
572 | ||
573 | return (had_tx_nak); | |
574 | } | |
575 | ||
576 | int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len) | |
577 | { | |
62219a28 WD |
578 | i2c_state_t state; |
579 | uchar xaddr[4]; | |
580 | int rc; | |
581 | ||
62219a28 WD |
582 | xaddr[0] = (addr >> 24) & 0xFF; |
583 | xaddr[1] = (addr >> 16) & 0xFF; | |
09e68ffa WD |
584 | xaddr[2] = (addr >> 8) & 0xFF; |
585 | xaddr[3] = addr & 0xFF; | |
62219a28 | 586 | |
6d0f6bcf | 587 | #ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW |
62219a28 WD |
588 | /* |
589 | * EEPROM chips that implement "address overflow" are ones like | |
590 | * Catalyst 24WC04/08/16 which has 9/10/11 bits of address and the | |
591 | * extra bits end up in the "chip address" bit slots. This makes | |
592 | * a 24WC08 (1Kbyte) chip look like four 256 byte chips. | |
593 | * | |
594 | * Note that we consider the length of the address field to still | |
595 | * be one byte because the extra address bits are hidden in the | |
596 | * chip address. | |
597 | */ | |
09e68ffa | 598 | chip |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW); |
62219a28 WD |
599 | #endif |
600 | ||
601 | i2c_newio(&state); | |
602 | ||
09e68ffa WD |
603 | rc = i2c_send(&state, chip, 0, I2CF_START_COND, alen, |
604 | &xaddr[4 - alen]); | |
62219a28 | 605 | if (rc != 0) { |
e3e454cd | 606 | printf("i2c_read: i2c_send failed (%d)\n", rc); |
62219a28 WD |
607 | return 1; |
608 | } | |
609 | ||
610 | rc = i2c_receive(&state, chip, 0, I2CF_STOP_COND, len, buffer); | |
611 | if (rc != 0) { | |
e3e454cd | 612 | printf("i2c_read: i2c_receive failed (%d)\n", rc); |
62219a28 WD |
613 | return 1; |
614 | } | |
615 | ||
616 | rc = i2c_doio(&state); | |
617 | if (rc != 0) { | |
e3e454cd | 618 | printf("i2c_read: i2c_doio failed (%d)\n", rc); |
62219a28 WD |
619 | return 1; |
620 | } | |
621 | return 0; | |
622 | } | |
623 | ||
624 | int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len) | |
625 | { | |
62219a28 WD |
626 | i2c_state_t state; |
627 | uchar xaddr[4]; | |
628 | int rc; | |
629 | ||
630 | xaddr[0] = (addr >> 24) & 0xFF; | |
631 | xaddr[1] = (addr >> 16) & 0xFF; | |
09e68ffa WD |
632 | xaddr[2] = (addr >> 8) & 0xFF; |
633 | xaddr[3] = addr & 0xFF; | |
62219a28 | 634 | |
6d0f6bcf | 635 | #ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW |
62219a28 WD |
636 | /* |
637 | * EEPROM chips that implement "address overflow" are ones like | |
638 | * Catalyst 24WC04/08/16 which has 9/10/11 bits of address and the | |
639 | * extra bits end up in the "chip address" bit slots. This makes | |
640 | * a 24WC08 (1Kbyte) chip look like four 256 byte chips. | |
641 | * | |
642 | * Note that we consider the length of the address field to still | |
643 | * be one byte because the extra address bits are hidden in the | |
644 | * chip address. | |
645 | */ | |
09e68ffa | 646 | chip |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW); |
62219a28 WD |
647 | #endif |
648 | ||
649 | i2c_newio(&state); | |
650 | ||
09e68ffa WD |
651 | rc = i2c_send(&state, chip, 0, I2CF_START_COND, alen, |
652 | &xaddr[4 - alen]); | |
62219a28 | 653 | if (rc != 0) { |
e3e454cd | 654 | printf("i2c_write: first i2c_send failed (%d)\n", rc); |
62219a28 WD |
655 | return 1; |
656 | } | |
657 | ||
658 | rc = i2c_send(&state, 0, 0, I2CF_STOP_COND, len, buffer); | |
659 | if (rc != 0) { | |
e3e454cd | 660 | printf("i2c_write: second i2c_send failed (%d)\n", rc); |
62219a28 WD |
661 | return 1; |
662 | } | |
663 | ||
664 | rc = i2c_doio(&state); | |
665 | if (rc != 0) { | |
e3e454cd | 666 | printf("i2c_write: i2c_doio failed (%d)\n", rc); |
62219a28 WD |
667 | return 1; |
668 | } | |
669 | return 0; | |
670 | } | |
671 | ||
09e68ffa | 672 | #endif /* CONFIG_HARD_I2C */ |