Logo Search packages:      
Sourcecode: linux version File versions  Download package

iic.c

/* Minimal support functions to read configuration from IIC EEPROMS
 * on MPC8xx boards.  Originally written for RPGC RPX-Lite.
 * Dan Malek (dmalek@jlc.net).
 */
#include <linux/types.h>
#include <asm/uaccess.h>
#include <asm/mpc8xx.h>
#include <asm/commproc.h>


/* IIC functions.
 * These are just the basic master read/write operations so we can
 * examine serial EEPROM.
 */
void  iic_read(uint devaddr, u_char *buf, uint offset, uint count);

static      int   iic_init_done;

static void
iic_init(void)
{
      volatile iic_t *iip;
      volatile i2c8xx_t *i2c;
      volatile cpm8xx_t *cp;
      volatile immap_t  *immap;
      uint  dpaddr;

      immap = (immap_t *)IMAP_ADDR;
      cp = (cpm8xx_t *)&(immap->im_cpm);

      /* Reset the CPM.  This is necessary on the 860 processors
       * that may have started the SCC1 ethernet without relocating
       * the IIC.
       * This also stops the Ethernet in case we were loaded by a
       * BOOTP rom monitor.
       */
      cp->cp_cpcr = (CPM_CR_RST | CPM_CR_FLG);

      /* Wait for it.
      */
      while (cp->cp_cpcr & (CPM_CR_RST | CPM_CR_FLG));

      /* Remove any microcode patches.  We will install our own
       * later.
       */
      cp->cp_cpmcr1 = 0;
      cp->cp_cpmcr2 = 0;
      cp->cp_cpmcr3 = 0;
      cp->cp_cpmcr4 = 0;
      cp->cp_rccr = 0;

      iip = (iic_t *)&cp->cp_dparam[PROFF_IIC];
      i2c = (i2c8xx_t *)&(immap->im_i2c);

      /* Initialize Port B IIC pins.
      */
      cp->cp_pbpar |= 0x00000030;
      cp->cp_pbdir |= 0x00000030;
      cp->cp_pbodr |= 0x00000030;

      /* Initialize the parameter ram.
      */

      /* Allocate space for a two transmit and one receive buffer
       * descriptor in the DP ram.
       * For now, this address seems OK, but it may have to
       * change with newer versions of the firmware.
       */
      dpaddr = 0x0840;

      /* Set up the IIC parameters in the parameter ram.
      */
      iip->iic_tbase = dpaddr;
      iip->iic_rbase = dpaddr + (2 * sizeof(cbd_t));

      iip->iic_tfcr = SMC_EB;
      iip->iic_rfcr = SMC_EB;

      /* This should really be done by the reader/writer.
      */
      iip->iic_mrblr = 128;

      /* Initialize Tx/Rx parameters.
      */
      cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_I2C, CPM_CR_INIT_TRX) | CPM_CR_FLG;
      while (cp->cp_cpcr & CPM_CR_FLG);

      /* Select an arbitrary address.  Just make sure it is unique.
      */
      i2c->i2c_i2add = 0x34;

      /* Make clock run maximum slow.
      */
      i2c->i2c_i2brg = 7;

      /* Disable interrupts.
      */
      i2c->i2c_i2cmr = 0;
      i2c->i2c_i2cer = 0xff;

      /* Enable SDMA.
      */
      immap->im_siu_conf.sc_sdcr = 1;

      iic_init_done = 1;
}

/* Read from IIC.
 * Caller provides device address, memory buffer, and byte count.
 */
static      u_char      iitemp[32];

void
iic_read(uint devaddr, u_char *buf, uint offset, uint count)
{
      volatile iic_t          *iip;
      volatile i2c8xx_t *i2c;
      volatile cbd_t          *tbdf, *rbdf;
      volatile cpm8xx_t *cp;
      volatile immap_t  *immap;
      u_char                  *tb;
      uint              temp;

      /* If the interface has not been initialized, do that now.
      */
      if (!iic_init_done)
            iic_init();

      immap = (immap_t *)IMAP_ADDR;
      cp = (cpm8xx_t *)&(immap->im_cpm);

      iip = (iic_t *)&cp->cp_dparam[PROFF_IIC];
      i2c = (i2c8xx_t *)&(immap->im_i2c);

      tbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_tbase];
      rbdf = (cbd_t *)&cp->cp_dpmem[iip->iic_rbase];

      /* Send a "dummy write" operation.  This is a write request with
       * only the offset sent, followed by another start condition.
       * This will ensure we start reading from the first location
       * of the EEPROM.
       */
      tb = iitemp;
      tb = (u_char *)(((uint)tb + 15) & ~15);
      tbdf->cbd_bufaddr = (int)tb;
      *tb = devaddr & 0xfe;   /* Device address */
      *(tb+1) = offset;       /* Offset */
      tbdf->cbd_datlen = 2;         /* Length */
      tbdf->cbd_sc =
            BD_SC_READY | BD_SC_LAST | BD_SC_WRAP | BD_IIC_START;

      i2c->i2c_i2mod = 1;     /* Enable */
      i2c->i2c_i2cer = 0xff;
      i2c->i2c_i2com = 0x81;  /* Start master */

      /* Wait for IIC transfer.
      */
#if 0
      while ((i2c->i2c_i2cer & 3) == 0);

      if (tbdf->cbd_sc & BD_SC_READY)
            printf("IIC ra complete but tbuf ready\n");
#else
      temp = 10000000;
      while ((tbdf->cbd_sc & BD_SC_READY) && (temp != 0))
            temp--;
#if 0
      /* We can't do this...there is no serial port yet!
      */
      if (temp == 0) {
            printf("Timeout reading EEPROM\n");
            return;
      }
#endif
#endif
      
      /* Chip errata, clear enable.
      */
      i2c->i2c_i2mod = 0;

      /* To read, we need an empty buffer of the proper length.
       * All that is used is the first byte for address, the remainder
       * is just used for timing (and doesn't really have to exist).
       */
      tbdf->cbd_bufaddr = (int)tb;
      *tb = devaddr | 1;      /* Device address */
      rbdf->cbd_bufaddr = (uint)buf;            /* Desination buffer */
      tbdf->cbd_datlen = rbdf->cbd_datlen = count + 1;      /* Length */
      tbdf->cbd_sc = BD_SC_READY | BD_SC_LAST | BD_SC_WRAP | BD_IIC_START;
      rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP;

      /* Chip bug, set enable here.
      */
      i2c->i2c_i2mod = 1;     /* Enable */
      i2c->i2c_i2cer = 0xff;
      i2c->i2c_i2com = 0x81;  /* Start master */

      /* Wait for IIC transfer.
      */
#if 0
      while ((i2c->i2c_i2cer & 1) == 0);

      if (rbdf->cbd_sc & BD_SC_EMPTY)
            printf("IIC read complete but rbuf empty\n");
#else
      temp = 10000000;
      while ((tbdf->cbd_sc & BD_SC_READY) && (temp != 0))
            temp--;
#endif
      
      /* Chip errata, clear enable.
      */
      i2c->i2c_i2mod = 0;
}

Generated by  Doxygen 1.6.0   Back to index