]>
Commit | Line | Data |
---|---|---|
1cb8e980 WD |
1 | /* |
2 | * (C) Copyright 2002 | |
3 | * David Mueller, ELSOFT AG, d.mueller@elsoft.ch | |
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 | ||
24 | /* This code should work for both the S3C2400 and the S3C2410 | |
25 | * as they seem to have the same I2C controller inside. | |
26 | * The different address mapping is handled by the s3c24xx.h files below. | |
27 | */ | |
28 | ||
29 | #include <common.h> | |
30 | ||
31 | #ifdef CONFIG_DRIVER_S3C24X0_I2C | |
32 | ||
33 | #if defined(CONFIG_S3C2400) | |
34 | #include <s3c2400.h> | |
35 | #elif defined(CONFIG_S3C2410) | |
36 | #include <s3c2410.h> | |
37 | #endif | |
38 | #include <i2c.h> | |
39 | ||
40 | #ifdef CONFIG_HARD_I2C | |
41 | ||
48b42616 WD |
42 | #define I2C_WRITE 0 |
43 | #define I2C_READ 1 | |
1cb8e980 | 44 | |
48b42616 WD |
45 | #define I2C_OK 0 |
46 | #define I2C_NOK 1 | |
47 | #define I2C_NACK 2 | |
48 | #define I2C_NOK_LA 3 /* Lost arbitration */ | |
49 | #define I2C_NOK_TOUT 4 /* time out */ | |
1cb8e980 | 50 | |
48b42616 WD |
51 | #define I2CSTAT_BSY 0x20 /* Busy bit */ |
52 | #define I2CSTAT_NACK 0x01 /* Nack bit */ | |
53 | #define I2CCON_IRPND 0x10 /* Interrupt pending bit */ | |
54 | #define I2C_MODE_MT 0xC0 /* Master Transmit Mode */ | |
55 | #define I2C_MODE_MR 0x80 /* Master Receive Mode */ | |
56 | #define I2C_START_STOP 0x20 /* START / STOP */ | |
57 | #define I2C_TXRX_ENA 0x10 /* I2C Tx/Rx enable */ | |
1cb8e980 | 58 | |
b56ddc63 | 59 | #define I2C_TIMEOUT 1 /* 1 second */ |
1cb8e980 WD |
60 | |
61 | ||
48b42616 | 62 | static int GetI2CSDA(void) |
1cb8e980 | 63 | { |
48b42616 WD |
64 | S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); |
65 | ||
6dff5529 | 66 | #ifdef CONFIG_S3C2410 |
48b42616 | 67 | return (gpio->GPEDAT & 0x8000) >> 15; |
6dff5529 WD |
68 | #endif |
69 | #ifdef CONFIG_S3C2400 | |
70 | return (gpio->PGDAT & 0x0020) >> 5; | |
71 | #endif | |
1cb8e980 WD |
72 | } |
73 | ||
06d01dbe | 74 | #if 0 |
48b42616 | 75 | static void SetI2CSDA(int x) |
1cb8e980 WD |
76 | { |
77 | rGPEDAT = (rGPEDAT & ~0x8000) | (x&1) << 15; | |
78 | } | |
06d01dbe | 79 | #endif |
1cb8e980 | 80 | |
48b42616 | 81 | static void SetI2CSCL(int x) |
1cb8e980 | 82 | { |
48b42616 WD |
83 | S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO(); |
84 | ||
6dff5529 | 85 | #ifdef CONFIG_S3C2410 |
48b42616 | 86 | gpio->GPEDAT = (gpio->GPEDAT & ~0x4000) | (x&1) << 14; |
6dff5529 WD |
87 | #endif |
88 | #ifdef CONFIG_S3C2400 | |
89 | gpio->PGDAT = (gpio->PGDAT & ~0x0040) | (x&1) << 6; | |
90 | #endif | |
1cb8e980 WD |
91 | } |
92 | ||
93 | ||
fc3e2165 | 94 | static int WaitForXfer (void) |
1cb8e980 | 95 | { |
fc3e2165 WD |
96 | S3C24X0_I2C *const i2c = S3C24X0_GetBase_I2C (); |
97 | int i, status; | |
1cb8e980 | 98 | |
fc3e2165 | 99 | i = I2C_TIMEOUT * 10000; |
48b42616 | 100 | status = i2c->IICCON; |
fc3e2165 WD |
101 | while ((i > 0) && !(status & I2CCON_IRPND)) { |
102 | udelay (100); | |
103 | status = i2c->IICCON; | |
104 | i--; | |
105 | } | |
1cb8e980 | 106 | |
fc3e2165 | 107 | return (status & I2CCON_IRPND) ? I2C_OK : I2C_NOK_TOUT; |
1cb8e980 WD |
108 | } |
109 | ||
fc3e2165 | 110 | static int IsACK (void) |
1cb8e980 | 111 | { |
fc3e2165 | 112 | S3C24X0_I2C *const i2c = S3C24X0_GetBase_I2C (); |
48b42616 | 113 | |
fc3e2165 | 114 | return (!(i2c->IICSTAT & I2CSTAT_NACK)); |
1cb8e980 WD |
115 | } |
116 | ||
fc3e2165 | 117 | static void ReadWriteByte (void) |
1cb8e980 | 118 | { |
fc3e2165 | 119 | S3C24X0_I2C *const i2c = S3C24X0_GetBase_I2C (); |
48b42616 | 120 | |
fc3e2165 | 121 | i2c->IICCON &= ~I2CCON_IRPND; |
1cb8e980 WD |
122 | } |
123 | ||
124 | void i2c_init (int speed, int slaveadd) | |
125 | { | |
fc3e2165 WD |
126 | S3C24X0_I2C *const i2c = S3C24X0_GetBase_I2C (); |
127 | S3C24X0_GPIO *const gpio = S3C24X0_GetBase_GPIO (); | |
128 | ulong freq, pres = 16, div; | |
129 | int i, status; | |
1cb8e980 | 130 | |
fc3e2165 | 131 | /* wait for some time to give previous transfer a chance to finish */ |
1cb8e980 | 132 | |
fc3e2165 | 133 | i = I2C_TIMEOUT * 1000; |
48b42616 | 134 | status = i2c->IICSTAT; |
fc3e2165 WD |
135 | while ((i > 0) && (status & I2CSTAT_BSY)) { |
136 | udelay (1000); | |
137 | status = i2c->IICSTAT; | |
138 | i--; | |
139 | } | |
1cb8e980 | 140 | |
fc3e2165 | 141 | if ((status & I2CSTAT_BSY) || GetI2CSDA () == 0) { |
6dff5529 | 142 | #ifdef CONFIG_S3C2410 |
fc3e2165 | 143 | ulong old_gpecon = gpio->GPECON; |
6dff5529 WD |
144 | #endif |
145 | #ifdef CONFIG_S3C2400 | |
fc3e2165 | 146 | ulong old_gpecon = gpio->PGCON; |
6dff5529 | 147 | #endif |
fc3e2165 | 148 | /* bus still busy probably by (most) previously interrupted transfer */ |
1cb8e980 | 149 | |
6dff5529 | 150 | #ifdef CONFIG_S3C2410 |
fc3e2165 WD |
151 | /* set I2CSDA and I2CSCL (GPE15, GPE14) to GPIO */ |
152 | gpio->GPECON = (gpio->GPECON & ~0xF0000000) | 0x10000000; | |
6dff5529 WD |
153 | #endif |
154 | #ifdef CONFIG_S3C2400 | |
fc3e2165 | 155 | /* set I2CSDA and I2CSCL (PG5, PG6) to GPIO */ |
30a43cc2 | 156 | gpio->PGCON = (gpio->PGCON & ~0x00003c00) | 0x00001000; |
6dff5529 | 157 | #endif |
1cb8e980 | 158 | |
fc3e2165 WD |
159 | /* toggle I2CSCL until bus idle */ |
160 | SetI2CSCL (0); | |
161 | udelay (1000); | |
162 | i = 10; | |
163 | while ((i > 0) && (GetI2CSDA () != 1)) { | |
164 | SetI2CSCL (1); | |
165 | udelay (1000); | |
166 | SetI2CSCL (0); | |
167 | udelay (1000); | |
168 | i--; | |
169 | } | |
170 | SetI2CSCL (1); | |
171 | udelay (1000); | |
1cb8e980 | 172 | |
fc3e2165 | 173 | /* restore pin functions */ |
6dff5529 | 174 | #ifdef CONFIG_S3C2410 |
fc3e2165 | 175 | gpio->GPECON = old_gpecon; |
6dff5529 WD |
176 | #endif |
177 | #ifdef CONFIG_S3C2400 | |
fc3e2165 | 178 | gpio->PGCON = old_gpecon; |
6dff5529 | 179 | #endif |
fc3e2165 | 180 | } |
1cb8e980 | 181 | |
fc3e2165 WD |
182 | /* calculate prescaler and divisor values */ |
183 | freq = get_PCLK (); | |
184 | if ((freq / pres / (16 + 1)) > speed) | |
185 | /* set prescaler to 512 */ | |
186 | pres = 512; | |
1cb8e980 | 187 | |
fc3e2165 WD |
188 | div = 0; |
189 | while ((freq / pres / (div + 1)) > speed) | |
190 | div++; | |
1cb8e980 | 191 | |
fc3e2165 WD |
192 | /* set prescaler, divisor according to freq, also set |
193 | * ACKGEN, IRQ */ | |
194 | i2c->IICCON = (div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0); | |
1cb8e980 | 195 | |
fc3e2165 WD |
196 | /* init to SLAVE REVEIVE and set slaveaddr */ |
197 | i2c->IICSTAT = 0; | |
198 | i2c->IICADD = slaveadd; | |
199 | /* program Master Transmit (and implicit STOP) */ | |
200 | i2c->IICSTAT = I2C_MODE_MT | I2C_TXRX_ENA; | |
1cb8e980 WD |
201 | |
202 | } | |
203 | ||
204 | /* | |
fc3e2165 WD |
205 | * cmd_type is 0 for write, 1 for read. |
206 | * | |
207 | * addr_len can take any value from 0-255, it is only limited | |
208 | * by the char, we could make it larger if needed. If it is | |
209 | * 0 we skip the address write cycle. | |
210 | */ | |
1cb8e980 | 211 | static |
fc3e2165 WD |
212 | int i2c_transfer (unsigned char cmd_type, |
213 | unsigned char chip, | |
214 | unsigned char addr[], | |
215 | unsigned char addr_len, | |
216 | unsigned char data[], unsigned short data_len) | |
1cb8e980 | 217 | { |
fc3e2165 WD |
218 | S3C24X0_I2C *const i2c = S3C24X0_GetBase_I2C (); |
219 | int i, status, result; | |
1cb8e980 | 220 | |
fc3e2165 WD |
221 | if (data == 0 || data_len == 0) { |
222 | /*Don't support data transfer of no length or to address 0 */ | |
223 | printf ("i2c_transfer: bad call\n"); | |
224 | return I2C_NOK; | |
225 | } | |
1cb8e980 | 226 | |
fc3e2165 WD |
227 | /* Check I2C bus idle */ |
228 | i = I2C_TIMEOUT * 1000; | |
229 | status = i2c->IICSTAT; | |
230 | while ((i > 0) && (status & I2CSTAT_BSY)) { | |
231 | udelay (1000); | |
232 | status = i2c->IICSTAT; | |
233 | i--; | |
234 | } | |
1cb8e980 | 235 | |
fc3e2165 WD |
236 | if (status & I2CSTAT_BSY) |
237 | return I2C_NOK_TOUT; | |
1cb8e980 | 238 | |
fc3e2165 WD |
239 | i2c->IICCON |= 0x80; |
240 | result = I2C_OK; | |
1cb8e980 | 241 | |
fc3e2165 | 242 | switch (cmd_type) { |
48b42616 | 243 | case I2C_WRITE: |
fc3e2165 WD |
244 | if (addr && addr_len) { |
245 | i2c->IICDS = chip; | |
246 | /* send START */ | |
247 | i2c->IICSTAT = I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP; | |
248 | i = 0; | |
249 | while ((i < addr_len) && (result == I2C_OK)) { | |
250 | result = WaitForXfer (); | |
251 | i2c->IICDS = addr[i]; | |
252 | ReadWriteByte (); | |
253 | i++; | |
254 | } | |
255 | i = 0; | |
256 | while ((i < data_len) && (result == I2C_OK)) { | |
257 | result = WaitForXfer (); | |
258 | i2c->IICDS = data[i]; | |
259 | ReadWriteByte (); | |
260 | i++; | |
261 | } | |
262 | } else { | |
263 | i2c->IICDS = chip; | |
264 | /* send START */ | |
265 | i2c->IICSTAT = I2C_MODE_MT | I2C_TXRX_ENA | I2C_START_STOP; | |
266 | i = 0; | |
267 | while ((i < data_len) && (result = I2C_OK)) { | |
268 | result = WaitForXfer (); | |
269 | i2c->IICDS = data[i]; | |
270 | ReadWriteByte (); | |
271 | i++; | |
272 | } | |
1cb8e980 | 273 | } |
1cb8e980 | 274 | |
fc3e2165 WD |
275 | if (result == I2C_OK) |
276 | result = WaitForXfer (); | |
1cb8e980 | 277 | |
fc3e2165 WD |
278 | /* send STOP */ |
279 | i2c->IICSTAT = I2C_MODE_MR | I2C_TXRX_ENA; | |
280 | ReadWriteByte (); | |
281 | break; | |
1cb8e980 | 282 | |
48b42616 | 283 | case I2C_READ: |
fc3e2165 WD |
284 | if (addr && addr_len) { |
285 | i2c->IICSTAT = I2C_MODE_MT | I2C_TXRX_ENA; | |
286 | i2c->IICDS = chip; | |
287 | /* send START */ | |
288 | i2c->IICSTAT |= I2C_START_STOP; | |
289 | result = WaitForXfer (); | |
290 | if (IsACK ()) { | |
291 | i = 0; | |
292 | while ((i < addr_len) && (result == I2C_OK)) { | |
293 | i2c->IICDS = addr[i]; | |
294 | ReadWriteByte (); | |
295 | result = WaitForXfer (); | |
296 | i++; | |
297 | } | |
298 | ||
299 | i2c->IICDS = chip; | |
300 | /* resend START */ | |
301 | i2c->IICSTAT = I2C_MODE_MR | I2C_TXRX_ENA | | |
302 | I2C_START_STOP; | |
303 | ReadWriteByte (); | |
304 | result = WaitForXfer (); | |
305 | i = 0; | |
306 | while ((i < data_len) && (result == I2C_OK)) { | |
307 | /* disable ACK for final READ */ | |
308 | if (i == data_len - 1) | |
309 | i2c->IICCON &= ~0x80; | |
310 | ReadWriteByte (); | |
311 | result = WaitForXfer (); | |
312 | data[i] = i2c->IICDS; | |
313 | i++; | |
314 | } | |
315 | } else { | |
316 | result = I2C_NACK; | |
317 | } | |
1cb8e980 | 318 | |
1cb8e980 | 319 | } else { |
fc3e2165 WD |
320 | i2c->IICSTAT = I2C_MODE_MR | I2C_TXRX_ENA; |
321 | i2c->IICDS = chip; | |
322 | /* send START */ | |
323 | i2c->IICSTAT |= I2C_START_STOP; | |
324 | result = WaitForXfer (); | |
325 | ||
326 | if (IsACK ()) { | |
327 | i = 0; | |
328 | while ((i < data_len) && (result == I2C_OK)) { | |
329 | /* disable ACK for final READ */ | |
330 | if (i == data_len - 1) | |
331 | i2c->IICCON &= ~0x80; | |
332 | ReadWriteByte (); | |
333 | result = WaitForXfer (); | |
334 | data[i] = i2c->IICDS; | |
335 | i++; | |
336 | } | |
337 | } else { | |
338 | result = I2C_NACK; | |
339 | } | |
1cb8e980 | 340 | } |
1cb8e980 | 341 | |
fc3e2165 WD |
342 | /* send STOP */ |
343 | i2c->IICSTAT = I2C_MODE_MR | I2C_TXRX_ENA; | |
344 | ReadWriteByte (); | |
345 | break; | |
1cb8e980 WD |
346 | |
347 | default: | |
fc3e2165 WD |
348 | printf ("i2c_transfer: bad call\n"); |
349 | result = I2C_NOK; | |
350 | break; | |
351 | } | |
1cb8e980 | 352 | |
fc3e2165 | 353 | return (result); |
1cb8e980 WD |
354 | } |
355 | ||
356 | int i2c_probe (uchar chip) | |
357 | { | |
fc3e2165 | 358 | uchar buf[1]; |
1cb8e980 | 359 | |
fc3e2165 | 360 | buf[0] = 0; |
1cb8e980 | 361 | |
fc3e2165 WD |
362 | /* |
363 | * What is needed is to send the chip address and verify that the | |
364 | * address was <ACK>ed (i.e. there was a chip at that address which | |
365 | * drove the data line low). | |
366 | */ | |
367 | return (i2c_transfer (I2C_READ, chip << 1, 0, 0, buf, 1) != I2C_OK); | |
1cb8e980 WD |
368 | } |
369 | ||
370 | int i2c_read (uchar chip, uint addr, int alen, uchar * buffer, int len) | |
371 | { | |
fc3e2165 WD |
372 | uchar xaddr[4]; |
373 | int ret; | |
1cb8e980 | 374 | |
fc3e2165 WD |
375 | if (alen > 4) { |
376 | printf ("I2C read: addr len %d not supported\n", alen); | |
377 | return 1; | |
378 | } | |
1cb8e980 | 379 | |
fc3e2165 WD |
380 | if (alen > 0) { |
381 | xaddr[0] = (addr >> 24) & 0xFF; | |
382 | xaddr[1] = (addr >> 16) & 0xFF; | |
383 | xaddr[2] = (addr >> 8) & 0xFF; | |
384 | xaddr[3] = addr & 0xFF; | |
385 | } | |
1cb8e980 | 386 | |
6d0f6bcf | 387 | #ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW |
fc3e2165 WD |
388 | /* |
389 | * EEPROM chips that implement "address overflow" are ones | |
390 | * like Catalyst 24WC04/08/16 which has 9/10/11 bits of | |
391 | * address and the extra bits end up in the "chip address" | |
392 | * bit slots. This makes a 24WC08 (1Kbyte) chip look like | |
393 | * four 256 byte chips. | |
394 | * | |
395 | * Note that we consider the length of the address field to | |
396 | * still be one byte because the extra address bits are | |
397 | * hidden in the chip address. | |
398 | */ | |
399 | if (alen > 0) | |
6d0f6bcf | 400 | chip |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW); |
1cb8e980 | 401 | #endif |
fc3e2165 WD |
402 | if ((ret = |
403 | i2c_transfer (I2C_READ, chip << 1, &xaddr[4 - alen], alen, | |
404 | buffer, len)) != 0) { | |
405 | printf ("I2c read: failed %d\n", ret); | |
406 | return 1; | |
407 | } | |
408 | return 0; | |
1cb8e980 WD |
409 | } |
410 | ||
411 | int i2c_write (uchar chip, uint addr, int alen, uchar * buffer, int len) | |
412 | { | |
fc3e2165 | 413 | uchar xaddr[4]; |
1cb8e980 | 414 | |
fc3e2165 WD |
415 | if (alen > 4) { |
416 | printf ("I2C write: addr len %d not supported\n", alen); | |
417 | return 1; | |
418 | } | |
1cb8e980 | 419 | |
fc3e2165 WD |
420 | if (alen > 0) { |
421 | xaddr[0] = (addr >> 24) & 0xFF; | |
422 | xaddr[1] = (addr >> 16) & 0xFF; | |
423 | xaddr[2] = (addr >> 8) & 0xFF; | |
424 | xaddr[3] = addr & 0xFF; | |
425 | } | |
6d0f6bcf | 426 | #ifdef CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW |
fc3e2165 WD |
427 | /* |
428 | * EEPROM chips that implement "address overflow" are ones | |
429 | * like Catalyst 24WC04/08/16 which has 9/10/11 bits of | |
430 | * address and the extra bits end up in the "chip address" | |
431 | * bit slots. This makes a 24WC08 (1Kbyte) chip look like | |
432 | * four 256 byte chips. | |
433 | * | |
434 | * Note that we consider the length of the address field to | |
435 | * still be one byte because the extra address bits are | |
436 | * hidden in the chip address. | |
437 | */ | |
438 | if (alen > 0) | |
6d0f6bcf | 439 | chip |= ((addr >> (alen * 8)) & CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW); |
1cb8e980 | 440 | #endif |
fc3e2165 WD |
441 | return (i2c_transfer |
442 | (I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer, | |
443 | len) != 0); | |
1cb8e980 | 444 | } |
1cb8e980 WD |
445 | #endif /* CONFIG_HARD_I2C */ |
446 | ||
447 | #endif /* CONFIG_DRIVER_S3C24X0_I2C */ |