summaryrefslogtreecommitdiff
path: root/board/eltec/elppc/mpc107_i2c.c
diff options
context:
space:
mode:
Diffstat (limited to 'board/eltec/elppc/mpc107_i2c.c')
-rwxr-xr-xboard/eltec/elppc/mpc107_i2c.c320
1 files changed, 320 insertions, 0 deletions
diff --git a/board/eltec/elppc/mpc107_i2c.c b/board/eltec/elppc/mpc107_i2c.c
new file mode 100755
index 0000000..ae6642e
--- /dev/null
+++ b/board/eltec/elppc/mpc107_i2c.c
@@ -0,0 +1,320 @@
+/*
+ * (C) Copyright 2002 ELTEC Elektronik AG
+ * Frank Gottschling <fgottschling@eltec.de>
+ *
+ * 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
+ */
+
+/* includes */
+#include <common.h>
+#include "srom.h"
+
+/* locals */
+static unsigned long mpc107_eumb_addr = 0;
+
+/*----------------------------------------------------------------------------*/
+
+/*
+ * calculate checksum for ELTEC revision srom
+ */
+unsigned long el_srom_checksum (ptr, size)
+register unsigned char *ptr;
+unsigned long size;
+{
+ u_long f, accu = 0;
+ u_int i;
+ u_char byte;
+
+ for (; size; size--)
+ {
+ byte = *ptr++;
+ for (i = 8; i; i--)
+ {
+ f = ((byte & 1) ^ (accu & 1)) ? 0x84083001 : 0;
+ accu >>= 1; accu ^= f;
+ byte >>= 1;
+ }
+ }
+ return(accu);
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int mpc107_i2c_wait ( unsigned long timeout )
+{
+ unsigned long x;
+
+ while (((x = in32r(MPC107_I2CSR)) & 0x82) != 0x82)
+ {
+ if (!timeout--)
+ return -1;
+ }
+
+ if (x & 0x10)
+ {
+ return -1;
+ }
+ out32r(MPC107_I2CSR, 0);
+
+ return 0;
+}
+
+/*----------------------------------------------------------------------------*/
+
+static int mpc107_i2c_wait_idle ( unsigned long timeout )
+{
+ while (in32r(MPC107_I2CSR) & 0x20)
+ {
+ if (!timeout--)
+ return -1;
+ }
+ return 0;
+}
+
+
+/*----------------------------------------------------------------------------*/
+
+int mpc107_i2c_read_byte (
+ unsigned char device,
+ unsigned char block,
+ unsigned char offset )
+{
+ unsigned long timeout = MPC107_I2C_TIMEOUT;
+ int data;
+
+ if (!mpc107_eumb_addr)
+ return -6;
+
+ mpc107_i2c_wait_idle (timeout);
+
+ /* Start with MEN */
+ out32r(MPC107_I2CCR, 0x80);
+
+ /* Start as master */
+ out32r(MPC107_I2CCR, 0xB0);
+ out32r(MPC107_I2CDR, (0xA0 | device | block));
+
+ if (mpc107_i2c_wait(timeout) < 0)
+ {
+ printf("mpc107_i2c_read Error 1\n");
+ return -2;
+ }
+
+ if (in32r(MPC107_I2CSR)&0x1)
+ {
+ /* Generate STOP condition; device busy or not existing */
+ out32r(MPC107_I2CCR, 0x80);
+ return -1;
+ }
+
+ /* Data address */
+ out32r(MPC107_I2CDR, offset);
+
+ if (mpc107_i2c_wait(timeout) < 0)
+ {
+ printf("mpc107_i2c_read Error 2\n");
+ return -3;
+ }
+
+ /* Switch to read - restart */
+ out32r(MPC107_I2CCR, 0xB4);
+ out32r(MPC107_I2CDR, (0xA1 | device | block));
+
+ if (mpc107_i2c_wait(timeout) < 0)
+ {
+ printf("mpc107_i2c_read Error 3\n");
+ return -4;
+ }
+
+ out32r(MPC107_I2CCR, 0xA8); /* no ACK */
+ in32r(MPC107_I2CDR);
+
+ if (mpc107_i2c_wait(timeout) < 0)
+ {
+ printf("mpc107_i2c_read Error 4\n");
+ return -5;
+ }
+ /* Generate STOP condition */
+ out32r(MPC107_I2CCR, 0x88);
+
+ /* read */
+ data = in32r(MPC107_I2CDR);
+
+ return (data);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int mpc107_i2c_write_byte (
+ unsigned char device,
+ unsigned char block,
+ unsigned char offset,
+ unsigned char val )
+{
+
+ unsigned long timeout = MPC107_I2C_TIMEOUT;
+
+ if (!mpc107_eumb_addr)
+ return -6;
+
+ mpc107_i2c_wait_idle(timeout);
+
+ /* Start with MEN */
+ out32r(MPC107_I2CCR, 0x80);
+
+ /* Start as master */
+ out32r(MPC107_I2CCR, 0xB0);
+ out32r(MPC107_I2CDR, (0xA0 | device | block));
+
+ if (mpc107_i2c_wait(timeout) < 0)
+ {
+ printf("mpc107_i2c_write Error 1\n");
+ return -1;
+ }
+
+ /* Data address */
+ out32r(MPC107_I2CDR, offset);
+
+ if (mpc107_i2c_wait(timeout) < 0)
+ {
+ printf("mpc107_i2c_write Error 2\n");
+ return -1;
+ }
+
+ /* Write */
+ out32r(MPC107_I2CDR, val);
+ if (mpc107_i2c_wait(timeout) < 0)
+ {
+ printf("mpc107_i2c_write Error 3\n");
+ return -1;
+ }
+
+ /* Generate Stop Condition */
+ out32r(MPC107_I2CCR, 0x80);
+
+ /* Return ACK or no ACK */
+ return (in32r(MPC107_I2CSR) & 0x01);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int mpc107_srom_load (
+ unsigned char addr,
+ unsigned char *pBuf,
+ int cnt,
+ unsigned char device,
+ unsigned char block )
+{
+ register int i;
+ int val;
+ int timeout;
+
+ for (i = 0; i < cnt; i++)
+ {
+ timeout=100;
+ do
+ {
+ val = mpc107_i2c_read_byte (device, block, addr);
+ if (val < -1)
+ {
+ printf("i2c_read_error %d at dev %x block %x addr %x\n",
+ val, device, block, addr);
+ return -1;
+ }
+ else if (timeout==0)
+ {
+ printf ("i2c_read_error: timeout at dev %x block %x addr %x\n",
+ device, block, addr);
+ return -1;
+ }
+ timeout--;
+ } while (val == -1); /* if no ack: try again! */
+
+ *pBuf++ = (unsigned char)val;
+ addr++;
+
+ if ((addr == 0) && (i != cnt-1)) /* is it the same block ? */
+ {
+ if (block == FIRST_BLOCK)
+ block = SECOND_BLOCK;
+ else
+ {
+ printf ("ic2_read_error: read beyond 2. block !\n");
+ return -1;
+ }
+ }
+ }
+ udelay(100000);
+ return (cnt);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int mpc107_srom_store (
+ unsigned char addr,
+ unsigned char *pBuf,
+ int cnt,
+ unsigned char device,
+ unsigned char block )
+{
+ register int i;
+
+ for (i = 0; i < cnt; i++)
+ {
+ while (mpc107_i2c_write_byte (device,block,addr,*pBuf) == 1);
+ addr++;
+ pBuf++;
+
+ if ((addr == 0) && (i != cnt-1)) /* is it the same block ? */
+ {
+ if (block == FIRST_BLOCK)
+ block = SECOND_BLOCK;
+ else
+ {
+ printf ("ic2_write_error: write beyond 2. block !\n");
+ return -1;
+ }
+ }
+ }
+ udelay(100000);
+ return(cnt);
+}
+
+/*----------------------------------------------------------------------------*/
+
+int mpc107_i2c_init ( unsigned long eumb_addr, unsigned long divider )
+{
+ unsigned long x;
+
+ if (eumb_addr)
+ mpc107_eumb_addr = eumb_addr;
+ else
+ return -1;
+
+ /* Set I2C clock */
+ x = in32r(MPC107_I2CFDR) & 0xffffff00;
+ out32r(MPC107_I2CFDR, (x | divider));
+
+ /* Clear arbitration */
+ out32r(MPC107_I2CSR, 0);
+
+ return mpc107_eumb_addr;
+}
+
+/*----------------------------------------------------------------------------*/