source: rtems/c/src/lib/libbsp/arm/beagle/misc/i2c.c @ 1c0663b

4.115
Last change on this file since 1c0663b was d4edbdbc, checked in by Sebastian Huber <sebastian.huber@…>, on Mar 20, 2015 at 1:09:26 PM

Replace www.rtems.com with www.rtems.org

  • Property mode set to 100644
File size: 10.3 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup arm_beagle
5 *
6 * @brief I2C support implementation.
7 */
8
9/*
10 * Copyright (c) 2012 Claas Ziemke. All rights reserved.
11 *
12 *  Claas Ziemke
13 *  Kernerstrasse 11
14 *  70182 Stuttgart
15 *  Germany
16 *  <claas.ziemke@gmx.net>
17 *
18 * The license and distribution terms for this file may be
19 * found in the file LICENSE in this distribution or at
20 * http://www.rtems.org/license/LICENSE.
21 */
22
23#include <rtems.h>
24
25#include <bsp.h>
26#include <bsp/i2c.h>
27
28static struct i2c *i2c_base = (struct i2c *)I2C_DEFAULT_BASE;
29
30static unsigned short wait_for_pin( void ) {
31
32  unsigned short status;
33  int timeout = I2C_TIMEOUT;
34
35  do {
36    udelay( 1000 );
37    status = readw( &i2c_base->stat );
38  } while( !( status &
39        ( I2C_STAT_ROVR | I2C_STAT_XUDF | I2C_STAT_XRDY |
40        I2C_STAT_RRDY | I2C_STAT_ARDY | I2C_STAT_NACK |
41        I2C_STAT_AL ) ) && timeout-- );
42
43  if( timeout <= 0 ) {
44    printk( "timed out in wait_for_pin: I2C_STAT = %x\n",
45      readw( &i2c_base->stat ) );
46    writew( 0xFFFF, &i2c_base->stat );  /* clear current interrupts...*/
47    status = 0;
48  }
49
50  return status;
51}
52
53static void wait_for_bb( void ) {
54
55  int timeout = I2C_TIMEOUT;
56  unsigned short status;
57
58  writew( 0xFFFF, &i2c_base->stat );  /* clear current interrupts...*/
59  while( ( status = readw( &i2c_base->stat ) & I2C_STAT_BB ) && timeout-- ) {
60    writew( status, &i2c_base->stat );
61    udelay( 1000 );
62  }
63
64  if( timeout <= 0 ) {
65    printk( "timed out in wait_for_bb: I2C_STAT = %x\n",
66      readw( &i2c_base->stat ) );
67  }
68  writew( 0xFFFF, &i2c_base->stat );   /* clear delayed stuff*/
69}
70
71static void flush_fifo( void ) {
72
73  unsigned short status;
74
75  /* note: if you try and read data when its not there or ready
76   * you get a bus error
77   */
78  while( 1 ) {
79    status = readw( &i2c_base->stat );
80    if( status == I2C_STAT_RRDY ) {
81      readw( &i2c_base->data );
82      writew( I2C_STAT_RRDY, &i2c_base->stat );
83      udelay( 1000 );
84    } else {
85      break;
86    }
87  }
88}
89
90void i2c_init( int speed, int slaveadd ) {
91
92  int psc, fsscll, fssclh;
93  int hsscll = 0, hssclh = 0;
94  unsigned int scll, sclh;
95  int timeout = I2C_TIMEOUT;
96
97  // Only handle standard, fast and high speeds
98  if( ( speed != OMAP_I2C_STANDARD   ) &&
99      ( speed != OMAP_I2C_FAST_MODE  ) &&
100      ( speed != OMAP_I2C_HIGH_SPEED ) ) {
101    printk( "Error : I2C unsupported speed %d\n", speed );
102    return;
103  }
104
105  psc = I2C_IP_CLK / I2C_INTERNAL_SAMPLING_CLK;
106  psc -= 1;
107  if( psc < I2C_PSC_MIN ) {
108    printk( "Error : I2C unsupported prescalar %d\n", psc );
109    return;
110  }
111
112  if( speed == OMAP_I2C_HIGH_SPEED ) {
113    // High speed
114
115    // For first phase of HS mode
116    fsscll = fssclh = I2C_INTERNAL_SAMPLING_CLK / ( 2 * OMAP_I2C_FAST_MODE );
117
118    fsscll -= I2C_HIGHSPEED_PHASE_ONE_SCLL_TRIM;
119    fssclh -= I2C_HIGHSPEED_PHASE_ONE_SCLH_TRIM;
120    if( ( ( fsscll < 0 ) || ( fssclh < 0 ) ) || ( ( fsscll > 255 ) ||
121      ( fssclh > 255 ) ) ) {
122      printk( "Error : I2C initializing first phase clock\n" );
123      return;
124    }
125
126    // For second phase of HS mode
127    hsscll = hssclh = I2C_INTERNAL_SAMPLING_CLK / ( 2 * speed );
128
129    hsscll -= I2C_HIGHSPEED_PHASE_TWO_SCLL_TRIM;
130    hssclh -= I2C_HIGHSPEED_PHASE_TWO_SCLH_TRIM;
131    if( ( ( fsscll < 0 ) || ( fssclh < 0 ) ) || ( ( fsscll > 255 ) ||
132      ( fssclh > 255 ) ) ) {
133      printk( "Error : I2C initializing second phase clock\n" );
134      return;
135    }
136
137    scll = ( unsigned int ) hsscll << 8 | ( unsigned int ) fsscll;
138    sclh = ( unsigned int ) hssclh << 8 | ( unsigned int ) fssclh;
139
140  } else {
141    // Standard and fast speed
142    fsscll = fssclh = I2C_INTERNAL_SAMPLING_CLK / ( 2 * speed );
143
144    fsscll -= I2C_FASTSPEED_SCLL_TRIM;
145    fssclh -= I2C_FASTSPEED_SCLH_TRIM;
146    if( ( ( fsscll < 0 ) || ( fssclh < 0 ) ) || ( ( fsscll > 255 ) ||
147      ( fssclh > 255 ) ) ) {
148      printk( "Error : I2C initializing clock\n" );
149      return;
150    }
151
152    scll = ( unsigned int ) fsscll;
153    sclh = ( unsigned int ) fssclh;
154  }
155
156  if( readw( &i2c_base->con ) & I2C_CON_EN ) {
157    writew( 0, &i2c_base->con );
158    udelay( 50000  );
159  }
160
161  writew( 0x2, &i2c_base->sysc ); /* for ES2 after soft reset */
162  udelay( 1000 );
163
164  writew( I2C_CON_EN, &i2c_base->con );
165  while( !( readw( &i2c_base->syss ) & I2C_SYSS_RDONE ) && timeout-- ) {
166    if (timeout <= 0) {
167      printk( "ERROR: Timeout in soft-reset\n" );
168      return;
169    }
170    udelay( 1000 );
171  }
172
173  writew( 0, &i2c_base->con );
174  writew( psc, &i2c_base->psc );
175  writew( scll, &i2c_base->scll );
176  writew( sclh, &i2c_base->sclh );
177
178  /* own address */
179  writew( slaveadd, &i2c_base->oa );
180  writew( I2C_CON_EN, &i2c_base->con );
181
182  /* have to enable intrrupts or OMAP i2c module doesn't work */
183  writew( I2C_IE_XRDY_IE | I2C_IE_RRDY_IE | I2C_IE_ARDY_IE | I2C_IE_NACK_IE |
184          I2C_IE_AL_IE, &i2c_base->ie );
185  udelay( 1000 );
186  flush_fifo();
187  writew( 0xFFFF, &i2c_base->stat );
188  writew( 0, &i2c_base->cnt );
189
190  //if( gd->flags & GD_FLG_RELOC ) bus_initialized[ current_bus ] = 1;
191}
192
193static int i2c_read_byte(
194  unsigned char devaddr,
195  unsigned char regoffset,
196  unsigned char *value
197)
198{
199  int i2c_error = 0;
200  unsigned short status;
201
202  /* wait until bus not busy */
203  wait_for_bb();
204
205  /* one byte only */
206  writew(1, &i2c_base->cnt);
207  /* set slave address */
208  writew(devaddr, &i2c_base->sa);
209  /* no stop bit needed here */
210  writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT |
211        I2C_CON_TRX, &i2c_base->con);
212
213  /* send register offset */
214  while (1) {
215    status = wait_for_pin();
216    if (status == 0 || status & I2C_STAT_NACK) {
217      i2c_error = 1;
218      goto read_exit;
219    }
220    if (status & I2C_STAT_XRDY) {
221      /* Important: have to use byte access */
222      writeb(regoffset, &i2c_base->data);
223      writew(I2C_STAT_XRDY, &i2c_base->stat);
224    }
225    if (status & I2C_STAT_ARDY) {
226      writew(I2C_STAT_ARDY, &i2c_base->stat);
227      break;
228    }
229  }
230
231  /* set slave address */
232  writew(devaddr, &i2c_base->sa);
233  /* read one byte from slave */
234  writew(1, &i2c_base->cnt);
235  /* need stop bit here */
236  writew(I2C_CON_EN | I2C_CON_MST |
237    I2C_CON_STT | I2C_CON_STP,
238    &i2c_base->con);
239
240  /* receive data */
241  while (1) {
242    status = wait_for_pin();
243    if (status == 0 || status & I2C_STAT_NACK) {
244      i2c_error = 1;
245      goto read_exit;
246    }
247    if (status & I2C_STAT_RRDY) {
248      *value = readw(&i2c_base->data);
249      writew(I2C_STAT_RRDY, &i2c_base->stat);
250    }
251    if (status & I2C_STAT_ARDY) {
252      writew(I2C_STAT_ARDY, &i2c_base->stat);
253      break;
254    }
255  }
256
257read_exit:
258  flush_fifo();
259  writew(0xFFFF, &i2c_base->stat);
260  writew(0, &i2c_base->cnt);
261  return i2c_error;
262}
263
264int i2c_write(
265  unsigned char chip,
266  unsigned int addr,
267  int alen,
268  unsigned char *buffer,
269  int len
270)
271{
272  int i;
273  unsigned short status;
274  int i2c_error = 0;
275
276  if (alen > 1) {
277    printk("I2C write: addr len %d not supported\n", alen);
278    return 1;
279  }
280
281  if (addr + len > 256) {
282    printk("I2C write: address 0x%x + 0x%x out of range\n",
283        addr, len);
284    return 1;
285  }
286
287  /* wait until bus not busy */
288  wait_for_bb();
289
290  /* start address phase - will write regoffset + len bytes data */
291  writew(alen + len, &i2c_base->cnt);
292  /* set slave address */
293  writew(chip, &i2c_base->sa);
294  /* stop bit needed here */
295  writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX |
296    I2C_CON_STP, &i2c_base->con);
297
298  /* Send address byte */
299  status = wait_for_pin();
300
301  if (status == 0 || status & I2C_STAT_NACK) {
302    i2c_error = 1;
303    printk("error waiting for i2c address ACK (status=0x%x)\n",
304          status);
305    goto write_exit;
306  }
307
308  if (status & I2C_STAT_XRDY) {
309    writeb(addr & 0xFF, &i2c_base->data);
310    writew(I2C_STAT_XRDY, &i2c_base->stat);
311  } else {
312    i2c_error = 1;
313    printk("i2c bus not ready for transmit (status=0x%x)\n",
314          status);
315    goto write_exit;
316  }
317
318  /* address phase is over, now write data */
319  for (i = 0; i < len; i++) {
320    status = wait_for_pin();
321
322    if (status == 0 || status & I2C_STAT_NACK) {
323      i2c_error = 1;
324      printk("i2c error waiting for data ACK (status=0x%x)\n",
325          status);
326      goto write_exit;
327    }
328
329    if (status & I2C_STAT_XRDY) {
330      writeb(buffer[i], &i2c_base->data);
331      writew(I2C_STAT_XRDY, &i2c_base->stat);
332    } else {
333      i2c_error = 1;
334      printk("i2c bus not ready for Tx (i=%d)\n", i);
335      goto write_exit;
336    }
337  }
338
339write_exit:
340  flush_fifo();
341  writew(0xFFFF, &i2c_base->stat);
342  return i2c_error;
343}
344
345int i2c_read(
346  unsigned char chip,
347  uint addr,
348  int alen,
349  unsigned char *buffer,
350  int len
351)
352{
353  int i;
354
355  if (alen > 1) {
356    printk("I2C read: addr len %d not supported\n", alen);
357    return 1;
358  }
359
360  if (addr + len > 256) {
361    printk("I2C read: address out of range\n");
362    return 1;
363  }
364
365  for (i = 0; i < len; i++) {
366    if (i2c_read_byte(chip, addr + i, &buffer[i])) {
367      printk("I2C read: I/O error\n");
368      i2c_init( CONFIG_SYS_I2C_SPEED, CONFIG_SYS_I2C_SLAVE );
369      return 1;
370    }
371  }
372
373  return 0;
374}
375
376/* Write (fill) memory
377 *
378 * Syntax:
379 *  i2c mw {i2c_chip} {addr}{.0, .1, .2} {data} [{count}]
380 */
381static int imw ( unsigned char  chip, unsigned long addr, unsigned char byte )
382{
383
384  unsigned int  alen;
385  int count;
386
387  alen = 1;
388  count = 1;
389
390  while (count-- > 0) {
391    if (i2c_write(chip, addr++, alen, &byte, 1) != 0)
392      printk("Error writing the chip.\n");
393    /*
394     * Wait for the write to complete.  The write can take
395     * up to 10mSec (we allow a little more time).
396     */
397  }
398
399  return (0);
400}
401
402/*
403 * Syntax:
404 *  i2c md {i2c_chip} {addr}{.0, .1, .2} {len}
405 */
406static int imd( unsigned char chip, unsigned int addr, unsigned int length )
407{
408  int j, nbytes, linebytes;
409
410  unsigned int alen = 0;
411  if (alen > 3) return 0;
412
413  /*
414   * Print the lines.
415   *
416   * We buffer all read data, so we can make sure data is read only
417   * once.
418   */
419  nbytes = length;
420  do {
421    unsigned char linebuf[DISP_LINE_LEN];
422    unsigned char *cp;
423
424    linebytes = (nbytes > DISP_LINE_LEN) ? DISP_LINE_LEN : nbytes;
425
426    if (i2c_read(chip, addr, alen, linebuf, linebytes) != 0)
427      printk ("Error reading the chip.\n");
428    else {
429      printk("%04x:", addr);
430      cp = linebuf;
431      for (j=0; j<linebytes; j++) {
432        printk(" %02x", *cp++);
433        addr++;
434      }
435      printk ("    ");
436      cp = linebuf;
437      for (j=0; j<linebytes; j++) {
438        if ((*cp < 0x20) || (*cp > 0x7e))
439          printk (".");
440        else
441          printk("%c", *cp);
442        cp++;
443      }
444      printk ("\n");
445    }
446    nbytes -= linebytes;
447  } while (nbytes > 0);
448
449  return 0;
450}
Note: See TracBrowser for help on using the repository browser.