/* * I2C read called by cmd_i2c when doing 'i2c read' and by cmd_eeprom.c * Begin write, send address byte(s), begin read, receive data bytes, end. */ int i2c_read(u8 dev, uint addr, int alen, u8 *data, int length) { u32 status; u32 i = 0; u8 *cur_data = data; /* Check the hardware can handle the requested bytes */ if ((length < 0) || (length > ZYNQ_I2C_TRANSFERT_SIZE_MAX)) return -EINVAL; /* Write the register address */ setbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_CLR_FIFO | ZYNQ_I2C_CONTROL_HOLD); /* * Temporarily disable restart (by clearing hold) * It doesn't seem to work. */ clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_RW | ZYNQ_I2C_CONTROL_HOLD); writel(0xFF, &zynq_i2c->interrupt_status); while (alen--) writel(addr >> (8*alen), &zynq_i2c->data); writel(dev, &zynq_i2c->address); /* Wait for the address to be sent */ if (!zynq_i2c_wait(ZYNQ_I2C_INTERRUPT_COMP)) { /* Release the bus */ clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD); return -ETIMEDOUT; } debug("Device acked address\n"); setbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_CLR_FIFO | ZYNQ_I2C_CONTROL_RW); /* Start reading data */ writel(dev, &zynq_i2c->address); writel(length, &zynq_i2c->transfer_size); /* Wait for data */ do { status = zynq_i2c_wait(ZYNQ_I2C_INTERRUPT_COMP | ZYNQ_I2C_INTERRUPT_DATA); if (!status) { /* Release the bus */ clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD); return -ETIMEDOUT; } debug("Read %d bytes\n", length - readl(&zynq_i2c->transfer_size)); for (; i < length - readl(&zynq_i2c->transfer_size); i++) *(cur_data++) = readl(&zynq_i2c->data); } while (readl(&zynq_i2c->transfer_size) != 0); /* All done... release the bus */ clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD); #ifdef DEBUG zynq_i2c_debug_status(); #endif return 0; }
/* * I2C write called by cmd_i2c when doing 'i2c write' and by cmd_eeprom.c * Begin write, send address byte(s), send data bytes, end. */ static int zynq_i2c_write(struct i2c_adapter *adap, u8 dev, uint addr, int alen, u8 *data, int length) { u8 *cur_data = data; struct zynq_i2c_registers *zynq_i2c = i2c_select(adap); /* Write the register address */ setbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_CLR_FIFO | ZYNQ_I2C_CONTROL_HOLD); clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_RW); writel(0xFF, &zynq_i2c->interrupt_status); writel(dev, &zynq_i2c->address); if (alen) { while (alen--) writel(addr >> (8 * alen), &zynq_i2c->data); /* Start the tranfer */ if (!zynq_i2c_wait(zynq_i2c, ZYNQ_I2C_INTERRUPT_COMP)) { /* Release the bus */ clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD); return -ETIMEDOUT; } debug("Device acked address\n"); } while (length--) { writel(*(cur_data++), &zynq_i2c->data); if (readl(&zynq_i2c->transfer_size) == ZYNQ_I2C_FIFO_DEPTH) { if (!zynq_i2c_wait(zynq_i2c, ZYNQ_I2C_INTERRUPT_COMP)) { /* Release the bus */ clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD); return -ETIMEDOUT; } } } /* All done... release the bus */ clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD); /* Wait for the address and data to be sent */ if (!zynq_i2c_wait(zynq_i2c, ZYNQ_I2C_INTERRUPT_COMP)) return -ETIMEDOUT; return 0; }
/* * I2C probe called by cmd_i2c when doing 'i2c probe'. * Begin read, nak data byte, end. */ int i2c_probe(u8 dev) { /* Attempt to read a byte */ setbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_CLR_FIFO | ZYNQ_I2C_CONTROL_RW); clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD); writel(0xFF, &zynq_i2c->interrupt_status); writel(dev, &zynq_i2c->address); writel(1, &zynq_i2c->transfer_size); return (zynq_i2c_wait(ZYNQ_I2C_INTERRUPT_COMP | ZYNQ_I2C_INTERRUPT_NACK) & ZYNQ_I2C_INTERRUPT_COMP) ? 0 : -ETIMEDOUT; }
/* * I2C probe called by cmd_i2c when doing 'i2c probe'. * Begin read, nak data byte, end. */ static int zynq_i2c_probe(struct i2c_adapter *adap, u8 dev) { struct zynq_i2c_registers *zynq_i2c = i2c_select(adap); /* Attempt to read a byte */ setbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_CLR_FIFO | ZYNQ_I2C_CONTROL_RW); clrbits_le32(&zynq_i2c->control, ZYNQ_I2C_CONTROL_HOLD); writel(0xFF, &zynq_i2c->interrupt_status); writel(dev, &zynq_i2c->address); writel(1, &zynq_i2c->transfer_size); return (zynq_i2c_wait(zynq_i2c, ZYNQ_I2C_INTERRUPT_COMP | ZYNQ_I2C_INTERRUPT_NACK) & ZYNQ_I2C_INTERRUPT_COMP) ? 0 : -ETIMEDOUT; }