137 lines
2.8 KiB
C
137 lines
2.8 KiB
C
|
/* 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;
|
||
|
|
||
|
void __iomem * 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, void __iomem *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)
|
||
|
{
|
||
|
}
|