| /* |
| * (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 |
| */ |
| |
| #include <common.h> |
| #include "srom.h" |
| |
| /*----------------------------------------------------------------------------*/ |
| /* |
| * START sequence |
| * _ _________ |
| * SCLK _> \____ |
| * _ ____ |
| * SDIO _> \_________ |
| * : : : |
| */ |
| static void eepStart (void) |
| { |
| out8(I2C_BUS_DAT, 0x60); /* SCLK = high SDIO = high */ |
| out8(I2C_BUS_DIR, 0x60); /* set output direction for SCLK/SDIO */ |
| udelay(10); |
| out8(I2C_BUS_DAT, 0x40); /* SCLK = high SDIO = low */ |
| udelay(10); |
| out8(I2C_BUS_DAT, 0x00); /* SCLK = low SDIO = low */ |
| udelay(10); |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /* |
| * STOP sequence |
| * _______ |
| * SCLK _____/ |
| * _ ___ |
| * SDIO _>_______/ |
| * : : : |
| */ |
| static void eepStop (void) |
| { |
| out8(I2C_BUS_DAT, 0x00); /* SCLK = low SDIO = low */ |
| out8(I2C_BUS_DIR, 0x60); /* set output direction for SCLK/SDIO */ |
| udelay(10); |
| out8(I2C_BUS_DAT, 0x40); /* SCLK = high SDIO = low */ |
| udelay(10); |
| out8(I2C_BUS_DAT, 0x60); /* SCLK = high SDIO = high */ |
| udelay(10); |
| out8(I2C_BUS_DIR, 0x00); /* reset to input direction */ |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /* |
| * Read one byte from EEPROM |
| * ___ ___ ___ ___ ___ ___ ___ ___ |
| * SCLK ___/ \___/ \___/ \___/ \___/ \___/ \___/ \___/ \ |
| * _________________________________________________________________ |
| * SDIO > ^ ^ ^ ^ ^ ^ ^ ^ |
| * : : : : : : : : : : : : : : : : : |
| */ |
| static unsigned char eepReadByte (void) |
| { |
| register unsigned char buf = 0x00; |
| register int i; |
| |
| out8(I2C_BUS_DIR, 0x40); |
| |
| for (i = 0; i < 8; i++) |
| { |
| out8(I2C_BUS_DAT, 0x00); /* SCLK = low SDIO = high */ |
| udelay(10); |
| out8(I2C_BUS_DAT, 0x40); /* SCLK = high SDIO = high */ |
| udelay(15); |
| buf <<= 1; |
| buf = (in8(I2C_BUS_DAT) & 0x20) ? (buf | 0x01) : (buf & 0xFE); |
| out8(I2C_BUS_DAT, 0x00); /* SCLK = low SDIO = high */ |
| udelay(10); |
| } |
| return(buf); |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /* |
| * Write one byte to EEPROM |
| * ___ ___ ___ ___ ___ ___ ___ ___ |
| * SCLK __/ \___/ \___/ \___/ \___/ \___/ \___/ \___/ \__ |
| * _______ _______ _______ _______ _______ _______ _______ ________ |
| * SDIO X_______X_______X_______X_______X_______X_______X_______X________ |
| * : 7 : 6 : 5 : 4 : 3 : 2 : 1 : 0 |
| */ |
| static void eepWriteByte (register unsigned char buf) |
| { |
| register int i; |
| |
| (buf & 0x80) ? out8(I2C_BUS_DAT, 0x20) : out8(I2C_BUS_DAT, 0x00); /* SCLK = low SDIO = data */ |
| out8(I2C_BUS_DIR, 0x60); |
| |
| for (i = 7; i >= 0; i--) |
| { |
| (buf & 0x80) ? out8(I2C_BUS_DAT, 0x20) : out8(I2C_BUS_DAT, 0x00); /* SCLK=low SDIO=data */ |
| udelay(10); |
| (buf & 0x80) ? out8(I2C_BUS_DAT, 0x60) : out8(I2C_BUS_DAT, 0x40); /* SCLK=high SDIO=data */ |
| udelay(15); |
| (buf & 0x80) ? out8(I2C_BUS_DAT, 0x20) : out8(I2C_BUS_DAT, 0x00); /* SCLK=low SDIO=data */ |
| udelay(10); |
| buf <<= 1; |
| } |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /* |
| * Read data acknowledge of EEPROM |
| * _______ |
| * SCLK ____/ \___ |
| * _______________ |
| * SDIO > |
| * : : ^ : |
| */ |
| static int eepReadAck (void) |
| { |
| int retval; |
| |
| out8(I2C_BUS_DIR, 0x40); |
| out8(I2C_BUS_DAT, 0x00); /* SCLK = low SDIO = high */ |
| udelay(10); |
| out8(I2C_BUS_DAT, 0x40); /* SCLK = high SDIO = high */ |
| udelay(10); |
| retval = (in8(I2C_BUS_DAT) & 0x20) ? ERROR : 0; |
| udelay(10); |
| out8(I2C_BUS_DAT, 0x00); /* SCLK = low SDIO = high */ |
| udelay(10); |
| |
| return(retval); |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /* |
| * Write data acknowledge to EEPROM |
| * _______ |
| * SCLK ____/ \___ |
| * |
| * SDIO >_______________ |
| * : : : |
| */ |
| static void eepWriteAck (unsigned char ack) |
| { |
| ack ? out8(I2C_BUS_DAT, 0x20) : out8(I2C_BUS_DAT, 0x00); /* SCLK = low SDIO = ack */ |
| out8(I2C_BUS_DIR, 0x60); |
| udelay(10); |
| ack ? out8(I2C_BUS_DAT, 0x60) : out8(I2C_BUS_DAT, 0x40); /* SCLK = high SDIO = ack */ |
| udelay(15); |
| ack ? out8(I2C_BUS_DAT, 0x20) : out8(I2C_BUS_DAT, 0x00); /* SCLK = low SDIO = ack */ |
| udelay(10); |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /* |
| * Read bytes from EEPROM |
| */ |
| int el_srom_load (addr, buf, cnt, device, block) |
| unsigned char addr; |
| unsigned char *buf; |
| int cnt; |
| unsigned char device; |
| unsigned char block; |
| { |
| register int i; |
| |
| for (i=0;i<cnt;i++) |
| { |
| eepStart(); |
| eepWriteByte(0xA0 | device | block); |
| if (eepReadAck() == ERROR) |
| { |
| eepStop(); |
| return(ERROR); |
| } |
| eepWriteByte(addr++); |
| if (eepReadAck() == ERROR) |
| { |
| eepStop(); |
| return(ERROR); |
| } |
| eepStart(); |
| |
| eepWriteByte(0xA1 | device | block); |
| if (eepReadAck() == ERROR) |
| { |
| eepStop(); |
| return(ERROR); |
| } |
| |
| *buf++ = eepReadByte(); |
| eepWriteAck(1); |
| eepStop(); |
| |
| if ((addr == 0) && (i != (cnt-1))) /* is it the same block ? */ |
| { |
| if (block == FIRST_BLOCK) |
| block = SECOND_BLOCK; |
| else |
| return(ERROR); |
| } |
| } |
| return(cnt); |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /* |
| * |
| * Write bytes to EEPROM |
| * |
| */ |
| int el_srom_store (addr, buf, cnt, device, block) |
| unsigned char addr, *buf, device, block; |
| int cnt; |
| { |
| register int i, retVal; |
| |
| for (i=0;i<cnt;i++) |
| { |
| retVal = ERROR; |
| do |
| { |
| eepStart(); |
| eepWriteByte(0xA0 | device | block); |
| if ((retVal = eepReadAck()) == ERROR) |
| eepStop(); |
| } while (retVal == ERROR); |
| |
| eepWriteByte(addr++); |
| if (eepReadAck() == ERROR) return(ERROR); |
| |
| if ((addr == 0) && (i != (cnt-1))) /* is it the same block ? */ |
| { |
| if (block == FIRST_BLOCK) |
| block = SECOND_BLOCK; |
| else |
| return(ERROR); |
| } |
| |
| eepWriteByte(*buf++); |
| if (eepReadAck() == ERROR) |
| return(ERROR); |
| |
| eepStop(); |
| } |
| return(cnt); |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /* |
| * 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); |
| } |
| |
| /*----------------------------------------------------------------------------*/ |