/* * Copyright (c) 2003-2015 Broadcom Corporation * * This file is licensed under the terms of the GNU General Public * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied.
*/
if (priv->len_recv) /* interrupt after the first read to examine * the length byte before proceeding further
*/
thres = 1; elseif (priv->msg_buf_remaining > XLP9XX_I2C_FIFO_SIZE)
thres = XLP9XX_I2C_FIFO_SIZE; else
thres = priv->msg_buf_remaining;
/* * Update receive length. Re-read len to get the latest value, * and then add 4 to have a minimum value that can be safely * written. This is to account for the byte read above, the * transfer in progress and any delays in the register I/O
*/
val = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_CTRL);
len = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_FIFOWCNT) &
XLP9XX_I2C_FIFO_WCNT_MASK;
len = max_t(u32, priv->msg_len, len + 4); if (len >= I2C_SMBUS_BLOCK_MAX + 2) return;
val = (val & ~XLP9XX_I2C_CTRL_MCTLEN_MASK) |
(len << XLP9XX_I2C_CTRL_MCTLEN_SHIFT);
xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, val);
}
len = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_FIFOWCNT) &
XLP9XX_I2C_FIFO_WCNT_MASK; if (!len) return; if (priv->len_recv) { /* read length byte */
rlen = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO);
/* * We expect at least 2 interrupts for I2C_M_RECV_LEN * transactions. The length is updated during the first * interrupt, and the buffer contents are only copied * during subsequent interrupts. If in case the interrupts * get merged we would complete the transaction without * copying out the bytes from RX fifo. To avoid this now we * drain the fifo as and when data is available. * We drained the rlen byte already, decrement total length * by one.
*/
/* SADDR ACK for SMBUS_QUICK */ if ((status & XLP9XX_I2C_INTEN_SADDR) && (priv->msg_len == 0)) goto xfer_done;
if (!priv->msg_read) { if (status & XLP9XX_I2C_INTEN_MFIFOEMTY) { /* TX FIFO got empty, fill it up again */ if (priv->msg_buf_remaining)
xlp9xx_i2c_fill_tx_fifo(priv); else
xlp9xx_i2c_mask_irq(priv,
XLP9XX_I2C_INTEN_MFIFOEMTY);
}
} else { if (status & (XLP9XX_I2C_INTEN_DATADONE |
XLP9XX_I2C_INTEN_MFIFOHI)) { /* data is in FIFO, read it */ if (priv->msg_buf_remaining)
xlp9xx_i2c_drain_rx_fifo(priv);
}
}
/* Transfer complete */ if (status & XLP9XX_I2C_INTEN_DATADONE) goto xfer_done;
/* Build control word for transfer */
val = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_CTRL); if (!priv->msg_read)
val &= ~XLP9XX_I2C_CTRL_FIFORD; else
val |= XLP9XX_I2C_CTRL_FIFORD; /* read */
if (msg->flags & I2C_M_TEN)
val |= XLP9XX_I2C_CTRL_ADDMODE; /* 10-bit address mode*/ else
val &= ~XLP9XX_I2C_CTRL_ADDMODE;
/* set FIFO threshold if reading */ if (priv->msg_read)
xlp9xx_i2c_update_rx_fifo_thres(priv);
/* set data length to be transferred */
val = (val & ~XLP9XX_I2C_CTRL_MCTLEN_MASK) |
(len << XLP9XX_I2C_CTRL_MCTLEN_SHIFT);
xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, val);
/* fill fifo during tx */ if (!priv->msg_read)
xlp9xx_i2c_fill_tx_fifo(priv);
if (timeleft == 0) {
dev_dbg(priv->dev, "i2c transfer timed out!\n");
xlp9xx_i2c_init(priv); return -ETIMEDOUT;
}
/* update msg->len with actual received length */ if (msg->flags & I2C_M_RECV_LEN) { if (!priv->msg_len) return -EPROTO;
msg->len = priv->msg_len;
} return 0;
}
staticint xlp9xx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{ int i, ret; struct xlp9xx_i2c_dev *priv = i2c_get_adapdata(adap);
ret = xlp9xx_i2c_check_bus_status(priv); if (ret) {
xlp9xx_i2c_init(priv);
ret = xlp9xx_i2c_check_bus_status(priv); if (ret) return ret;
}
for (i = 0; i < num; i++) {
ret = xlp9xx_i2c_xfer_msg(priv, &msgs[i], i == num - 1); if (ret != 0) return ret;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.