/* Wait for status change */ while (readl(i2c->base + LPC24XX_I2STAT) != M_I2C_IDLE) { if (time_after(jiffies, timeout)) { /* Bus was not idle, try to reset adapter */
i2c_lpc2k_reset(i2c); return -EBUSY;
}
case MR_DATA_R_NACK: /* *TheI2CshowsNACKstatusonreads,soweneedtoaccept *theNACKasanACKhere.Thisshouldbeok,asthereal *BACKwouldofbeencaughtontheaddresswrite.
*/ case MR_DATA_R_ACK: /* Data was received */ if (i2c->msg_idx < i2c->msg->len) {
i2c->msg->buf[i2c->msg_idx] =
readl(i2c->base + LPC24XX_I2DAT);
}
/* If transfer is done, send STOP */ if (i2c->msg_idx >= i2c->msg->len - 1 && i2c->is_last) {
writel(LPC24XX_STO_AA, i2c->base + LPC24XX_I2CONSET);
writel(LPC24XX_SI, i2c->base + LPC24XX_I2CONCLR);
i2c->msg_status = 0;
}
/* Message is done */ if (i2c->msg_idx >= i2c->msg->len - 1) {
i2c->msg_status = 0;
disable_irq_nosync(i2c->irq);
}
/* *Onepre-lastdatainput,sendNACKtotellthetargetthat *thisisgoingtobethelastdatabytetobetransferred.
*/ if (i2c->msg_idx >= i2c->msg->len - 2) { /* One byte left to receive - NACK */
writel(LPC24XX_AA, i2c->base + LPC24XX_I2CONCLR);
} else { /* More than one byte left to receive - ACK */
writel(LPC24XX_AA, i2c->base + LPC24XX_I2CONSET);
}
staticint lpc2k_process_msg(struct lpc2k_i2c *i2c, int msgidx)
{ /* A new transfer is kicked off by initiating a start condition */ if (!msgidx) {
writel(LPC24XX_STA, i2c->base + LPC24XX_I2CONSET);
} else { /* *Amulti-messageI2Ctransfercontinueswherethe *previousI2Ctransferleftoffandusesthe *currentconditionoftheI2Cadapter.
*/ if (unlikely(i2c->msg->flags & I2C_M_NOSTART)) {
WARN_ON(i2c->msg->len == 0);
if (!(i2c->msg->flags & I2C_M_RD)) { /* Start transmit of data */
writel(i2c->msg->buf[0],
i2c->base + LPC24XX_I2DAT);
i2c->msg_idx++;
}
} else { /* Start or repeated start */
writel(LPC24XX_STA, i2c->base + LPC24XX_I2CONSET);
}
/* Wait for transfer completion */ if (wait_event_timeout(i2c->wait, i2c->msg_status != -EBUSY,
msecs_to_jiffies(1000)) == 0) {
disable_irq_nosync(i2c->irq);
return -ETIMEDOUT;
}
return i2c->msg_status;
}
staticint i2c_lpc2k_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int msg_num)
{ struct lpc2k_i2c *i2c = i2c_get_adapdata(adap); int ret, i;
u32 stat;
/* Check for bus idle condition */
stat = readl(i2c->base + LPC24XX_I2STAT); if (stat != M_I2C_IDLE) { /* Something is holding the bus, try to clear it */ return i2c_lpc2k_clear_arb(i2c);
}
/* Process a single message at a time */ for (i = 0; i < msg_num; i++) { /* Save message pointer and current message data index */
i2c->msg = &msgs[i];
i2c->msg_idx = 0;
i2c->msg_status = -EBUSY;
i2c->is_last = (i == (msg_num - 1));
ret = lpc2k_process_msg(i2c, i); if (ret) 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.