/*
 * (C) Copyright 2001
 * Stefan Roese, esd gmbh germany, stefan.roese@esd-electronics.com
 *
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 *
 */

#include <ppcboot.h>
#include <command.h>


#define EEPROM_CAP              0x50000358
#define EEPROM_DATA             0x5000035c


unsigned int eepromReadLong(int offs)
{
  unsigned int value;
  volatile unsigned short ret;
  int count;

  *(unsigned short *)EEPROM_CAP = offs;

  count = 0;

  for (;;)
    {
      count++;
      ret = *(unsigned short *)EEPROM_CAP;

      if ((ret & 0x8000) != 0)
        break;
    }

  value = *(unsigned long *)EEPROM_DATA;

  return value;
}


unsigned char eepromReadByte(int offs)
{
  unsigned int valueLong;
  unsigned char *ptr;

  valueLong = eepromReadLong(offs & ~3);
  ptr = (unsigned char *)&valueLong;

  return ptr[offs & 3];
}


void eepromWriteLong(int offs, unsigned int value)
{
  volatile unsigned short ret;
  int count;

  count = 0;

  *(unsigned long *)EEPROM_DATA = value;
  *(unsigned short *)EEPROM_CAP = 0x8000 + offs;

  for (;;)
    {
      count++;
      ret = *(unsigned short *)EEPROM_CAP;

      if ((ret & 0x8000) == 0)
        break;
    }
}


void eepromWriteByte(int offs, unsigned char valueByte)
{
  unsigned int valueLong;
  unsigned char *ptr;

  valueLong = eepromReadLong(offs & ~3);
  ptr = (unsigned char *)&valueLong;

  ptr[offs & 3] = valueByte;

  eepromWriteLong(offs & ~3, valueLong);
}


void i2c_read (uchar *addr, int alen, uchar *buffer, int len)
{
  int i;
  int len2, ptr;

  //  printf("\naddr=%x alen=%x buffer=%x len=%x", addr[0], addr[1], *(short *)addr, alen, buffer, len); // test-only

  ptr = *(short *)addr;

  /*
   * Read till lword boundary
   */
  len2 = 4 - (*(short *)addr & 0x0003);
  for (i=0; i<len2; i++)
    {
      *buffer++ = eepromReadByte(ptr++);
    }

  /*
   * Read all lwords
   */
  len2 = (len - len2) >> 2;
  for (i=0; i<len2; i++)
    {
      *(unsigned int *)buffer = eepromReadLong(ptr);
      buffer += 4;
      ptr += 4;
    }

  /*
   * Read last bytes
   */
  len2 = (*(short *)addr + len) & 0x0003;
  for (i=0; i<len2; i++)
    {
      *buffer++ = eepromReadByte(ptr++);
    }
}

void i2c_write (uchar *addr, int alen, uchar *buffer, int len)
{
  int i;
  int len2, ptr;

  //  printf("\naddr=%x alen=%x buffer=%x len=%x", addr[0], addr[1], *(short *)addr, alen, buffer, len); // test-only

  ptr = *(short *)addr;

  /*
   * Write till lword boundary
   */
  len2 = 4 - (*(short *)addr & 0x0003);
  for (i=0; i<len2; i++)
    {
      eepromWriteByte(ptr++, *buffer++);
    }

  /*
   * Write all lwords
   */
  len2 = (len - len2) >> 2;
  for (i=0; i<len2; i++)
    {
      eepromWriteLong(ptr, *(unsigned int *)buffer);
      buffer += 4;
      ptr += 4;
    }

  /*
   * Write last bytes
   */
  len2 = (*(short *)addr + len) & 0x0003;
  for (i=0; i<len2; i++)
    {
      eepromWriteByte(ptr++, *buffer++);
    }
}
