rcar_i2c_write(priv, ICMIER, read ? RCAR_IRQ_RECV : RCAR_IRQ_SEND);
}
+static void rcar_i2c_next_msg(struct rcar_i2c_priv *priv)
+{
+ priv->msg++;
+ priv->msgs_left--;
+ rcar_i2c_prepare_msg(priv);
+}
+
/*
* interrupt functions
*/
* [ICRXTX] -> [SHIFT] -> [I2C bus]
*/
- if (priv->flags & ID_LAST_MSG)
+ if (priv->flags & ID_LAST_MSG) {
/*
* If current msg is the _LAST_ msg,
* prepare stop condition here.
* ID_DONE will be set on STOP irq.
*/
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP);
- else
- /*
- * If current msg is _NOT_ last msg,
- * it doesn't call stop phase.
- * thus, there is no STOP irq.
- * return ID_DONE here.
- */
- return ID_DONE;
+ } else {
+ rcar_i2c_next_msg(priv);
+ return 0;
+ }
}
rcar_i2c_write(priv, ICMSR, RCAR_IRQ_ACK_SEND);
else
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA);
- rcar_i2c_write(priv, ICMSR, RCAR_IRQ_ACK_RECV);
+ if (priv->pos == msg->len && !(priv->flags & ID_LAST_MSG))
+ rcar_i2c_next_msg(priv);
+ else
+ rcar_i2c_write(priv, ICMSR, RCAR_IRQ_ACK_RECV);
return 0;
}
/* Stop */
if (msr & MST) {
+ priv->msgs_left--; /* The last message also made it */
rcar_i2c_flags_set(priv, ID_DONE);
goto out;
}
/* This HW can't send STOP after address phase */
if (msgs[i].len == 0) {
ret = -EOPNOTSUPP;
- break;
- }
-
- /* init each data */
- priv->msg = &msgs[i];
- priv->msgs_left = num - i;
-
- rcar_i2c_prepare_msg(priv);
-
- time_left = wait_event_timeout(priv->wait,
- rcar_i2c_flags_has(priv, ID_DONE),
- adap->timeout);
- if (!time_left) {
- rcar_i2c_init(priv);
- ret = -ETIMEDOUT;
- break;
- }
-
- if (rcar_i2c_flags_has(priv, ID_NACK)) {
- ret = -ENXIO;
- break;
- }
-
- if (rcar_i2c_flags_has(priv, ID_ARBLOST)) {
- ret = -EAGAIN;
- break;
+ goto out;
}
+ }
- ret = i + 1; /* The number of transfer */
+ /* init data */
+ priv->msg = msgs;
+ priv->msgs_left = num;
+
+ rcar_i2c_prepare_msg(priv);
+
+ time_left = wait_event_timeout(priv->wait,
+ rcar_i2c_flags_has(priv, ID_DONE),
+ num * adap->timeout);
+ if (!time_left) {
+ rcar_i2c_init(priv);
+ ret = -ETIMEDOUT;
+ } else if (rcar_i2c_flags_has(priv, ID_NACK)) {
+ ret = -ENXIO;
+ } else if (rcar_i2c_flags_has(priv, ID_ARBLOST)) {
+ ret = -EAGAIN;
+ } else {
+ ret = num - priv->msgs_left; /* The number of transfer */
}
out:
pm_runtime_put(dev);