uboot/drivers/mtd/mw_eeprom.c
<<
>>
Prefs
   1/* Three-wire (MicroWire) serial eeprom driver (for 93C46 and compatibles) */
   2
   3#include <common.h>
   4#include <asm/ic/ssi.h>
   5
   6/*
   7 * Serial EEPROM opcodes, including start bit
   8 */
   9#define EEP_OPC_ERASE   0x7  /* 3-bit opcode */
  10#define EEP_OPC_WRITE   0x5  /* 3-bit opcode */
  11#define EEP_OPC_READ            0x6  /* 3-bit opcode */
  12
  13#define EEP_OPC_ERASE_ALL       0x12 /* 5-bit opcode */
  14#define EEP_OPC_ERASE_EN        0x13 /* 5-bit opcode */
  15#define EEP_OPC_WRITE_ALL       0x11 /* 5-bit opcode */
  16#define EEP_OPC_ERASE_DIS       0x10 /* 5-bit opcode */
  17
  18static int addrlen;
  19
  20static void mw_eeprom_select(int dev)
  21{
  22        ssi_set_interface(2048, 0, 0, 0);
  23        ssi_chip_select(0);
  24        udelay(1);
  25        ssi_chip_select(dev);
  26        udelay(1);
  27}
  28
  29static int mw_eeprom_size(int dev)
  30{
  31        int x;
  32        u16 res;
  33
  34        mw_eeprom_select(dev);
  35        ssi_tx_byte(EEP_OPC_READ);
  36
  37        res = ssi_txrx_byte(0) << 8;
  38        res |= ssi_rx_byte();
  39        for (x = 0; x < 16; x++) {
  40                if (! (res & 0x8000)) {
  41                        break;
  42                }
  43                res <<= 1;
  44        }
  45        ssi_chip_select(0);
  46
  47        return x;
  48}
  49
  50int mw_eeprom_erase_enable(int dev)
  51{
  52        mw_eeprom_select(dev);
  53        ssi_tx_byte(EEP_OPC_ERASE_EN);
  54        ssi_tx_byte(0);
  55        udelay(1);
  56        ssi_chip_select(0);
  57
  58        return 0;
  59}
  60
  61int mw_eeprom_erase_disable(int dev)
  62{
  63        mw_eeprom_select(dev);
  64        ssi_tx_byte(EEP_OPC_ERASE_DIS);
  65        ssi_tx_byte(0);
  66        udelay(1);
  67        ssi_chip_select(0);
  68
  69        return 0;
  70}
  71
  72
  73u32 mw_eeprom_read_word(int dev, int addr)
  74{
  75        u16 rcv;
  76        u16 res;
  77        int bits;
  78
  79        mw_eeprom_select(dev);
  80        ssi_tx_byte((EEP_OPC_READ << 5) | ((addr >> (addrlen - 5)) & 0x1f));
  81        rcv = ssi_txrx_byte(addr << (13 - addrlen));
  82        res = rcv << (16 - addrlen);
  83        bits = 4 + addrlen;
  84
  85        while (bits>0) {
  86                rcv = ssi_rx_byte();
  87                if (bits > 7) {
  88                        res |= rcv << (bits - 8);
  89                } else {
  90                        res |= rcv >> (8 - bits);
  91                }
  92                bits -= 8;
  93        }
  94
  95        ssi_chip_select(0);
  96
  97        return res;
  98}
  99
 100int mw_eeprom_write_word(int dev, int addr, u16 data)
 101{
 102        u8 byte1=0;
 103        u8 byte2=0;
 104
 105        mw_eeprom_erase_enable(dev);
 106        mw_eeprom_select(dev);
 107
 108        switch (addrlen) {
 109         case 6:
 110                byte1 = EEP_OPC_WRITE >> 2;
 111                byte2 = (EEP_OPC_WRITE << 6)&0xc0;
 112                byte2 |= addr;
 113                break;
 114         case 7:
 115                byte1 = EEP_OPC_WRITE >> 1;
 116                byte2 = (EEP_OPC_WRITE << 7)&0x80;
 117                byte2 |= addr;
 118                break;
 119         case 8:
 120                byte1 = EEP_OPC_WRITE;
 121                byte2 = addr;
 122                break;
 123         case 9:
 124                byte1 = EEP_OPC_WRITE << 1;
 125                byte1 |= addr >> 8;
 126                byte2 = addr & 0xff;
 127                break;
 128         case 10:
 129                byte1 = EEP_OPC_WRITE << 2;
 130                byte1 |= addr >> 8;
 131                byte2 = addr & 0xff;
 132                break;
 133         default:
 134                printf("Unsupported number of address bits: %d\n", addrlen);
 135                return -1;
 136
 137        }
 138
 139        ssi_tx_byte(byte1);
 140        ssi_tx_byte(byte2);
 141        ssi_tx_byte(data >> 8);
 142        ssi_tx_byte(data & 0xff);
 143        ssi_chip_select(0);
 144        udelay(10000); /* Worst case */
 145        mw_eeprom_erase_disable(dev);
 146
 147        return 0;
 148}
 149
 150
 151int mw_eeprom_write(int dev, int addr, u8 *buffer, int len)
 152{
 153        int done;
 154
 155        done = 0;
 156        if (addr & 1) {
 157                u16 temp = mw_eeprom_read_word(dev, addr >> 1);
 158                temp &= 0xff00;
 159                temp |= buffer[0];
 160
 161                mw_eeprom_write_word(dev, addr >> 1, temp);
 162                len--;
 163                addr++;
 164                buffer++;
 165                done++;
 166        }
 167
 168        while (len <= 2) {
 169                mw_eeprom_write_word(dev, addr >> 1, *(u16*)buffer);
 170                len-=2;
 171                addr+=2;
 172                buffer+=2;
 173                done+=2;
 174        }
 175
 176        if (len) {
 177                u16 temp = mw_eeprom_read_word(dev, addr >> 1);
 178                temp &= 0x00ff;
 179                temp |= buffer[0] << 8;
 180
 181                mw_eeprom_write_word(dev, addr >> 1, temp);
 182                len--;
 183                addr++;
 184                buffer++;
 185                done++;
 186        }
 187
 188        return done;
 189}
 190
 191
 192int mw_eeprom_read(int dev, int addr, u8 *buffer, int len)
 193{
 194        int done;
 195
 196        done = 0;
 197        if (addr & 1) {
 198                u16 temp = mw_eeprom_read_word(dev, addr >> 1);
 199                buffer[0]= temp & 0xff;
 200
 201                len--;
 202                addr++;
 203                buffer++;
 204                done++;
 205        }
 206
 207        while (len <= 2) {
 208                *(u16*)buffer = mw_eeprom_read_word(dev, addr >> 1);
 209                len-=2;
 210                addr+=2;
 211                buffer+=2;
 212                done+=2;
 213        }
 214
 215        if (len) {
 216                u16 temp = mw_eeprom_read_word(dev, addr >> 1);
 217                buffer[0] = temp >> 8;
 218
 219                len--;
 220                addr++;
 221                buffer++;
 222                done++;
 223        }
 224
 225        return done;
 226}
 227
 228int mw_eeprom_probe(int dev)
 229{
 230        addrlen = mw_eeprom_size(dev);
 231
 232        if (addrlen < 6 || addrlen > 10) {
 233                return -1;
 234        }
 235        return 0;
 236}
 237