Subversion Repositories shark

Rev

Blame | Last modification | View Log | RSS feed

/* credit winbond-840.c
 */

#include <asm/io.h>
struct eeprom_ops {
        void    (*set_cs)(void *ee);
        void    (*clear_cs)(void *ee);
};

#define EEPOL_EEDI      0x01
#define EEPOL_EEDO      0x02
#define EEPOL_EECLK     0x04
#define EEPOL_EESEL     0x08

struct eeprom {
        void *dev;
        struct eeprom_ops *ops;

        long            addr;

        unsigned        ee_addr_bits;

        unsigned        eesel;
        unsigned        eeclk;
        unsigned        eedo;
        unsigned        eedi;
        unsigned        polarity;
        unsigned        ee_state;

        spinlock_t      *lock;
        u32             *cache;
};


u8   eeprom_readb(struct eeprom *ee, unsigned address);
void eeprom_read(struct eeprom *ee, unsigned address, u8 *bytes,
                unsigned count);
void eeprom_writeb(struct eeprom *ee, unsigned address, u8 data);
void eeprom_write(struct eeprom *ee, unsigned address, u8 *bytes,
                unsigned count);

/* The EEPROM commands include the alway-set leading bit. */
enum EEPROM_Cmds {
        EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6),
};

void setup_ee_mem_bitbanger(struct eeprom *ee, long memaddr, int eesel_bit, int eeclk_bit, int eedo_bit, int eedi_bit, unsigned polarity)
{
        ee->addr = memaddr;
        ee->eesel = 1 << eesel_bit;
        ee->eeclk = 1 << eeclk_bit;
        ee->eedo = 1 << eedo_bit;
        ee->eedi = 1 << eedi_bit;

        ee->polarity = polarity;

        *ee->cache = readl(ee->addr);
}

/* foo. put this in a .c file */
static inline void eeprom_update(struct eeprom *ee, u32 mask, int pol)
{
        unsigned long flags;
        u32 data;

        spin_lock_irqsave(ee->lock, flags);
        data = *ee->cache;

        data &= ~mask;
        if (pol)
                data |= mask;

        *ee->cache = data;
//printk("update: %08x\n", data);
        writel(data, ee->addr);
        spin_unlock_irqrestore(ee->lock, flags);
}

void eeprom_clk_lo(struct eeprom *ee)
{
        int pol = !!(ee->polarity & EEPOL_EECLK);

        eeprom_update(ee, ee->eeclk, pol);
        udelay(2);
}

void eeprom_clk_hi(struct eeprom *ee)
{
        int pol = !!(ee->polarity & EEPOL_EECLK);

        eeprom_update(ee, ee->eeclk, !pol);
        udelay(2);
}

void eeprom_send_addr(struct eeprom *ee, unsigned address)
{
        int pol = !!(ee->polarity & EEPOL_EEDI);
        unsigned i;
        address |= 6 << 6;

        /* Shift the read command bits out. */
        for (i=0; i<11; i++) {
                eeprom_update(ee, ee->eedi, ((address >> 10) & 1) ^ pol);
                address <<= 1;
                eeprom_clk_hi(ee);
                eeprom_clk_lo(ee);
        }
        eeprom_update(ee, ee->eedi, pol);
}

u16   eeprom_readw(struct eeprom *ee, unsigned address)
{
        unsigned i;
        u16     res = 0;

        eeprom_clk_lo(ee);
        eeprom_update(ee, ee->eesel, 1 ^ !!(ee->polarity & EEPOL_EESEL));
        eeprom_send_addr(ee, address);

        for (i=0; i<16; i++) {
                u32 data;
                eeprom_clk_hi(ee);
                res <<= 1;
                data = readl(ee->addr);
//printk("eeprom_readw: %08x\n", data);
                res |= !!(data & ee->eedo) ^ !!(ee->polarity & EEPOL_EEDO);
                eeprom_clk_lo(ee);
        }
        eeprom_update(ee, ee->eesel, 0 ^ !!(ee->polarity & EEPOL_EESEL));

        return res;
}


void eeprom_writeb(struct eeprom *ee, unsigned address, u8 data)
{
}