Skip to content
Snippets Groups Projects
acenic.c 85.4 KiB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
	u32 local;

	udelay(ACE_SHORT_DELAY);
	local = readl(&regs->LocalCtrl);
	local &= ~EEPROM_DATA_OUT;
	local |= EEPROM_WRITE_ENABLE;
	writel(local, &regs->LocalCtrl);
	readl(&regs->LocalCtrl);
	mb();

	for (i = 0; i < 8; i++, magic <<= 1) {
		udelay(ACE_SHORT_DELAY);
		if (magic & 0x80)
Linus Torvalds's avatar
Linus Torvalds committed
			local |= EEPROM_DATA_OUT;
		else
			local &= ~EEPROM_DATA_OUT;
		writel(local, &regs->LocalCtrl);
		readl(&regs->LocalCtrl);
		mb();

		udelay(ACE_SHORT_DELAY);
		local |= EEPROM_CLK_OUT;
		writel(local, &regs->LocalCtrl);
		readl(&regs->LocalCtrl);
		mb();
		udelay(ACE_SHORT_DELAY);
		local &= ~(EEPROM_CLK_OUT | EEPROM_DATA_OUT);
		writel(local, &regs->LocalCtrl);
		readl(&regs->LocalCtrl);
		mb();
	}
}


static int __devinit eeprom_check_ack(struct ace_regs __iomem *regs)
{
	int state;
	u32 local;

	local = readl(&regs->LocalCtrl);
	local &= ~EEPROM_WRITE_ENABLE;
	writel(local, &regs->LocalCtrl);
	readl(&regs->LocalCtrl);
	mb();
	udelay(ACE_LONG_DELAY);
	local |= EEPROM_CLK_OUT;
	writel(local, &regs->LocalCtrl);
	readl(&regs->LocalCtrl);
	mb();
	udelay(ACE_SHORT_DELAY);
	/* sample data in middle of high clk */
	state = (readl(&regs->LocalCtrl) & EEPROM_DATA_IN) != 0;
	udelay(ACE_SHORT_DELAY);
	mb();
	writel(readl(&regs->LocalCtrl) & ~EEPROM_CLK_OUT, &regs->LocalCtrl);
	readl(&regs->LocalCtrl);
	mb();

	return state;
}


static void __devinit eeprom_stop(struct ace_regs __iomem *regs)
{
	u32 local;

	udelay(ACE_SHORT_DELAY);
	local = readl(&regs->LocalCtrl);
	local |= EEPROM_WRITE_ENABLE;
	writel(local, &regs->LocalCtrl);
	readl(&regs->LocalCtrl);
	mb();
	udelay(ACE_SHORT_DELAY);
	local &= ~EEPROM_DATA_OUT;
	writel(local, &regs->LocalCtrl);
	readl(&regs->LocalCtrl);
	mb();
	udelay(ACE_SHORT_DELAY);
	local |= EEPROM_CLK_OUT;
	writel(local, &regs->LocalCtrl);
	readl(&regs->LocalCtrl);
	mb();
	udelay(ACE_SHORT_DELAY);
	local |= EEPROM_DATA_OUT;
	writel(local, &regs->LocalCtrl);
	readl(&regs->LocalCtrl);
	mb();
	udelay(ACE_LONG_DELAY);
	local &= ~EEPROM_CLK_OUT;
	writel(local, &regs->LocalCtrl);
	mb();
}


/*
 * Read a whole byte from the EEPROM.
 */
static int __devinit read_eeprom_byte(struct net_device *dev,
				   unsigned long offset)
{
	struct ace_private *ap = netdev_priv(dev);
	struct ace_regs __iomem *regs = ap->regs;
	unsigned long flags;
	u32 local;
	int result = 0;
	short i;

	/*
	 * Don't take interrupts on this CPU will bit banging
	 * the %#%#@$ I2C device
	 */
	local_irq_save(flags);

	eeprom_start(regs);

	eeprom_prep(regs, EEPROM_WRITE_SELECT);
	if (eeprom_check_ack(regs)) {
		local_irq_restore(flags);
		printk(KERN_ERR "%s: Unable to sync eeprom\n", ap->name);
		result = -EIO;
		goto eeprom_read_error;
	}

	eeprom_prep(regs, (offset >> 8) & 0xff);
	if (eeprom_check_ack(regs)) {
		local_irq_restore(flags);
		printk(KERN_ERR "%s: Unable to set address byte 0\n",
		       ap->name);
		result = -EIO;
		goto eeprom_read_error;
	}

	eeprom_prep(regs, offset & 0xff);
	if (eeprom_check_ack(regs)) {
		local_irq_restore(flags);
		printk(KERN_ERR "%s: Unable to set address byte 1\n",
		       ap->name);
		result = -EIO;
		goto eeprom_read_error;
	}

	eeprom_start(regs);
	eeprom_prep(regs, EEPROM_READ_SELECT);
	if (eeprom_check_ack(regs)) {
		local_irq_restore(flags);
		printk(KERN_ERR "%s: Unable to set READ_SELECT\n",
		       ap->name);
		result = -EIO;
		goto eeprom_read_error;
	}

	for (i = 0; i < 8; i++) {
		local = readl(&regs->LocalCtrl);
		local &= ~EEPROM_WRITE_ENABLE;
		writel(local, &regs->LocalCtrl);
		readl(&regs->LocalCtrl);
		udelay(ACE_LONG_DELAY);
		mb();
		local |= EEPROM_CLK_OUT;
		writel(local, &regs->LocalCtrl);
		readl(&regs->LocalCtrl);
		mb();
		udelay(ACE_SHORT_DELAY);
		/* sample data mid high clk */
		result = (result << 1) |
			((readl(&regs->LocalCtrl) & EEPROM_DATA_IN) != 0);
		udelay(ACE_SHORT_DELAY);
		mb();
		local = readl(&regs->LocalCtrl);
		local &= ~EEPROM_CLK_OUT;
		writel(local, &regs->LocalCtrl);
		readl(&regs->LocalCtrl);
		udelay(ACE_SHORT_DELAY);
		mb();
		if (i == 7) {
			local |= EEPROM_WRITE_ENABLE;
			writel(local, &regs->LocalCtrl);
			readl(&regs->LocalCtrl);
			mb();
			udelay(ACE_SHORT_DELAY);
		}
	}

	local |= EEPROM_DATA_OUT;
	writel(local, &regs->LocalCtrl);
	readl(&regs->LocalCtrl);
	mb();
	udelay(ACE_SHORT_DELAY);
	writel(readl(&regs->LocalCtrl) | EEPROM_CLK_OUT, &regs->LocalCtrl);
	readl(&regs->LocalCtrl);
	udelay(ACE_LONG_DELAY);
	writel(readl(&regs->LocalCtrl) & ~EEPROM_CLK_OUT, &regs->LocalCtrl);
	readl(&regs->LocalCtrl);
	mb();
	udelay(ACE_SHORT_DELAY);
	eeprom_stop(regs);

	local_irq_restore(flags);
 out:
	return result;

 eeprom_read_error:
	printk(KERN_ERR "%s: Unable to read eeprom byte 0x%02lx\n",
	       ap->name, offset);
	goto out;
}