+ if (addr + len > (1 << 16)) {
+ puts("I2C read: address out of range\n");
+ return 1;
+ }
+
+ /* Wait until bus not busy */
+ if (wait_for_bb(adap))
+ return 1;
+
+ /* Zero, one or two bytes reg address (offset) */
+ writew(alen, &i2c_base->cnt);
+ /* Set slave address */
+ writew(chip, &i2c_base->sa);
+
+ if (alen) {
+ /* Must write reg offset first */
+#ifdef CONFIG_I2C_REPEATED_START
+ /* No stop bit, use Repeated Start (Sr) */
+ writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT |
+ I2C_CON_TRX, &i2c_base->con);
+#else
+ /* Stop - Start (P-S) */
+ writew(I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP |
+ I2C_CON_TRX, &i2c_base->con);
+#endif
+ /* Send register offset */
+ while (1) {
+ status = wait_for_event(adap);
+ /* Try to identify bus that is not padconf'd for I2C */
+ if (status == I2C_STAT_XRDY) {
+ i2c_error = 2;
+ printf("i2c_read (addr phase): pads on bus %d probably not configured (status=0x%x)\n",
+ adap->hwadapnr, status);
+ goto rd_exit;
+ }
+ if (status == 0 || status & I2C_STAT_NACK) {
+ i2c_error = 1;
+ printf("i2c_read: error waiting for addr ACK (status=0x%x)\n",
+ status);
+ goto rd_exit;
+ }
+ if (alen) {
+ if (status & I2C_STAT_XRDY) {
+ alen--;
+ /* Do we have to use byte access? */
+ writeb((addr >> (8 * alen)) & 0xff,
+ &i2c_base->data);
+ writew(I2C_STAT_XRDY, &i2c_base->stat);
+ }
+ }
+ if (status & I2C_STAT_ARDY) {
+ writew(I2C_STAT_ARDY, &i2c_base->stat);
+ break;
+ }
+ }
+ }
+ /* Set slave address */
+ writew(chip, &i2c_base->sa);
+ /* Read len bytes from slave */
+ writew(len, &i2c_base->cnt);
+ /* Need stop bit here */
+ writew(I2C_CON_EN | I2C_CON_MST |
+ I2C_CON_STT | I2C_CON_STP,
+ &i2c_base->con);
+
+ /* Receive data */
+ while (1) {
+ status = wait_for_event(adap);
+ /*
+ * Try to identify bus that is not padconf'd for I2C. This
+ * state could be left over from previous transactions if
+ * the address phase is skipped due to alen=0.
+ */
+ if (status == I2C_STAT_XRDY) {
+ i2c_error = 2;
+ printf("i2c_read (data phase): pads on bus %d probably not configured (status=0x%x)\n",
+ adap->hwadapnr, status);
+ goto rd_exit;
+ }
+ if (status == 0 || status & I2C_STAT_NACK) {
+ i2c_error = 1;
+ goto rd_exit;
+ }
+ if (status & I2C_STAT_RRDY) {
+ *buffer++ = readb(&i2c_base->data);
+ writew(I2C_STAT_RRDY, &i2c_base->stat);
+ }
+ if (status & I2C_STAT_ARDY) {
+ writew(I2C_STAT_ARDY, &i2c_base->stat);
+ break;