source: SVN/rincon/u-boot/cpu/arm920t/s3c24x0/i2c.c @ 55

Last change on this file since 55 was 55, checked in by Tim Harvey, 22 months ago

rincon: added latest u-boot source

restored form server backup

Signed-off-by: Tim Harvey <tharvey@…>

File size: 10.3 KB
Line 
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
42#define I2C_WRITE       0
43#define I2C_READ        1
44
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 */
50
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 */
58
59#define I2C_TIMEOUT 1                   /* 1 second */
60
61
62static int GetI2CSDA(void)
63{
64        S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
65
66#ifdef CONFIG_S3C2410
67        return (gpio->GPEDAT & 0x8000) >> 15;
68#endif
69#ifdef CONFIG_S3C2400
70        return (gpio->PGDAT & 0x0020) >> 5;
71#endif
72}
73
74#if 0
75static void SetI2CSDA(int x)
76{
77        rGPEDAT = (rGPEDAT & ~0x8000) | (x&1) << 15;
78}
79#endif
80
81static void SetI2CSCL(int x)
82{
83        S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
84
85#ifdef CONFIG_S3C2410
86        gpio->GPEDAT = (gpio->GPEDAT & ~0x4000) | (x&1) << 14;
87#endif
88#ifdef CONFIG_S3C2400
89        gpio->PGDAT = (gpio->PGDAT & ~0x0040) | (x&1) << 6;
90#endif
91}
92
93
94static int WaitForXfer (void)
95{
96        S3C24X0_I2C *const i2c = S3C24X0_GetBase_I2C ();
97        int i, status;
98
99        i = I2C_TIMEOUT * 10000;
100        status = i2c->IICCON;
101        while ((i > 0) && !(status & I2CCON_IRPND)) {
102                udelay (100);
103                status = i2c->IICCON;
104                i--;
105        }
106
107        return (status & I2CCON_IRPND) ? I2C_OK : I2C_NOK_TOUT;
108}
109
110static int IsACK (void)
111{
112        S3C24X0_I2C *const i2c = S3C24X0_GetBase_I2C ();
113
114        return (!(i2c->IICSTAT & I2CSTAT_NACK));
115}
116
117static void ReadWriteByte (void)
118{
119        S3C24X0_I2C *const i2c = S3C24X0_GetBase_I2C ();
120
121        i2c->IICCON &= ~I2CCON_IRPND;
122}
123
124void i2c_init (int speed, int slaveadd)
125{
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;
130
131        /* wait for some time to give previous transfer a chance to finish */
132
133        i = I2C_TIMEOUT * 1000;
134        status = i2c->IICSTAT;
135        while ((i > 0) && (status & I2CSTAT_BSY)) {
136                udelay (1000);
137                status = i2c->IICSTAT;
138                i--;
139        }
140
141        if ((status & I2CSTAT_BSY) || GetI2CSDA () == 0) {
142#ifdef CONFIG_S3C2410
143                ulong old_gpecon = gpio->GPECON;
144#endif
145#ifdef CONFIG_S3C2400
146                ulong old_gpecon = gpio->PGCON;
147#endif
148                /* bus still busy probably by (most) previously interrupted transfer */
149
150#ifdef CONFIG_S3C2410
151                /* set I2CSDA and I2CSCL (GPE15, GPE14) to GPIO */
152                gpio->GPECON = (gpio->GPECON & ~0xF0000000) | 0x10000000;
153#endif
154#ifdef CONFIG_S3C2400
155                /* set I2CSDA and I2CSCL (PG5, PG6) to GPIO */
156                gpio->PGCON = (gpio->PGCON & ~0x00003c00) | 0x00001000;
157#endif
158
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);
172
173                /* restore pin functions */
174#ifdef CONFIG_S3C2410
175                gpio->GPECON = old_gpecon;
176#endif
177#ifdef CONFIG_S3C2400
178                gpio->PGCON = old_gpecon;
179#endif
180        }
181
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;
187
188        div = 0;
189        while ((freq / pres / (div + 1)) > speed)
190                div++;
191
192        /* set prescaler, divisor according to freq, also set
193         * ACKGEN, IRQ */
194        i2c->IICCON = (div & 0x0F) | 0xA0 | ((pres == 512) ? 0x40 : 0);
195
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;
201
202}
203
204/*
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 */
211static
212int 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)
217{
218        S3C24X0_I2C *const i2c = S3C24X0_GetBase_I2C ();
219        int i, status, result;
220
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        }
226
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        }
235
236        if (status & I2CSTAT_BSY)
237                return I2C_NOK_TOUT;
238
239        i2c->IICCON |= 0x80;
240        result = I2C_OK;
241
242        switch (cmd_type) {
243        case I2C_WRITE:
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                        }
273                }
274
275                if (result == I2C_OK)
276                        result = WaitForXfer ();
277
278                /* send STOP */
279                i2c->IICSTAT = I2C_MODE_MR | I2C_TXRX_ENA;
280                ReadWriteByte ();
281                break;
282
283        case I2C_READ:
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                        }
318
319                } else {
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                        }
340                }
341
342                /* send STOP */
343                i2c->IICSTAT = I2C_MODE_MR | I2C_TXRX_ENA;
344                ReadWriteByte ();
345                break;
346
347        default:
348                printf ("i2c_transfer: bad call\n");
349                result = I2C_NOK;
350                break;
351        }
352
353        return (result);
354}
355
356int i2c_probe (uchar chip)
357{
358        uchar buf[1];
359
360        buf[0] = 0;
361
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);
368}
369
370int i2c_read (uchar chip, uint addr, int alen, uchar * buffer, int len)
371{
372        uchar xaddr[4];
373        int ret;
374
375        if (alen > 4) {
376                printf ("I2C read: addr len %d not supported\n", alen);
377                return 1;
378        }
379
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        }
386
387#ifdef CFG_I2C_EEPROM_ADDR_OVERFLOW
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)
400                chip |= ((addr >> (alen * 8)) & CFG_I2C_EEPROM_ADDR_OVERFLOW);
401#endif
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;
409}
410
411int i2c_write (uchar chip, uint addr, int alen, uchar * buffer, int len)
412{
413        uchar xaddr[4];
414
415        if (alen > 4) {
416                printf ("I2C write: addr len %d not supported\n", alen);
417                return 1;
418        }
419
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        }
426#ifdef CFG_I2C_EEPROM_ADDR_OVERFLOW
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)
439                chip |= ((addr >> (alen * 8)) & CFG_I2C_EEPROM_ADDR_OVERFLOW);
440#endif
441        return (i2c_transfer
442                (I2C_WRITE, chip << 1, &xaddr[4 - alen], alen, buffer,
443                 len) != 0);
444}
445#endif  /* CONFIG_HARD_I2C */
446
447#endif /* CONFIG_DRIVER_S3C24X0_I2C */
Note: See TracBrowser for help on using the repository browser.