/* ICCCR2 */ #define FMPE BIT(7) /* Fast Mode Plus Enable */ #define CDFD BIT(2) /* CDF Disable */ #define HLSE BIT(1) /* HIGH/LOW Separate Control Enable */ #define SME BIT(0) /* SCL Mask Enable */
/* ICFBSCR */ #define TCYC17 0x0f /* 17*Tcyc delay 1st bit between SDA and SCL */
#define RCAR_MIN_DMA_LEN 8
/* SCL low/high ratio 5:4 to meet all I2C timing specs (incl safety margin) */ #define RCAR_SCLD_RATIO 5 #define RCAR_SCHD_RATIO 4 /* * SMD should be smaller than SCLD/SCHD and is always around 20 in the docs. * Thus, we simply use 20 which works for low and high speeds.
*/ #define RCAR_DEFAULT_SMD 20
err_no_val:
dev_err(dev, "it is impossible to calculate best SCL\n"); return -EINVAL;
}
/* * We don't have a test case but the HW engineers say that the write order of * ICMSR and ICMCR depends on whether we issue START or REP_START. So, ICMSR * handling is outside of this function. First messages clear ICMSR before this * function, interrupt handlers clear the relevant bits after this function.
*/ staticvoid rcar_i2c_prepare_msg(struct rcar_i2c_priv *priv)
{ int read = !!rcar_i2c_is_recv(priv); bool rep_start = !(priv->flags & ID_REP_AFTER_RD);
priv->pos = 0;
priv->flags &= ID_P_MASK;
if (priv->msgs_left == 1)
priv->flags |= ID_LAST_MSG;
if (rep_start)
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START);
}
staticvoid rcar_i2c_first_msg(struct rcar_i2c_priv *priv, struct i2c_msg *msgs, int num)
{
priv->msg = msgs;
priv->msgs_left = num;
rcar_i2c_write(priv, ICMSR, 0); /* must be before preparing msg */
rcar_i2c_prepare_msg(priv);
}
staticvoid rcar_i2c_next_msg(struct rcar_i2c_priv *priv)
{
priv->msg++;
priv->msgs_left--;
rcar_i2c_prepare_msg(priv); /* ICMSR handling must come afterwards in the irq handler */
}
/* Gen3+ can only do one RXDMA per transfer and we just completed it */ if (priv->devtype >= I2C_RCAR_GEN3 &&
priv->dma_direction == DMA_FROM_DEVICE)
priv->flags |= ID_P_NO_RXDMA;
priv->dma_direction = DMA_NONE;
/* Disable DMA Master Received/Transmitted, must be last! */
rcar_i2c_write(priv, ICDMAER, 0);
}
/* Do various checks to see if DMA is feasible at all */ if (!(priv->flags & ID_P_NOT_ATOMIC) || IS_ERR(chan) || msg->len < RCAR_MIN_DMA_LEN ||
!(msg->flags & I2C_M_DMA_SAFE) || (read && priv->flags & ID_P_NO_RXDMA)) returnfalse;
if (read) { /* * The last two bytes needs to be fetched using PIO in * order for the STOP phase to work.
*/
buf = priv->msg->buf;
len = priv->msg->len - 2;
} else { /* * First byte in message was sent using PIO.
*/
buf = priv->msg->buf + 1;
len = priv->msg->len - 1;
}
dma_addr = dma_map_single(chan->device->dev, buf, len, dir); if (dma_mapping_error(chan->device->dev, dma_addr)) {
dev_dbg(dev, "dma map failed, using PIO\n"); returnfalse;
}
/* FIXME: sometimes, unknown interrupt happened. Do nothing */ if (WARN(!(msr & MDE), "spurious irq")) return;
if (msr & MAT)
irqs_to_clear |= MAT;
/* Check if DMA can be enabled and take over */ if (priv->pos == 1 && rcar_i2c_dma(priv)) return;
if (priv->pos < msg->len) { /* * Prepare next data to ICRXTX register. * This data will go to _SHIFT_ register. * * * * [ICRXTX] -> [SHIFT] -> [I2C bus]
*/
rcar_i2c_write(priv, ICRXTX, msg->buf[priv->pos]);
priv->pos++;
} else { /* * The last data was pushed to ICRXTX on _PREV_ empty irq. * It is on _SHIFT_ register, and will sent to I2C bus. * * * * [ICRXTX] -> [SHIFT] -> [I2C bus]
*/
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
rcar_i2c_next_msg(priv);
}
/* FIXME: sometimes, unknown interrupt happened. Do nothing */ if (!(msr & MDR)) return;
if (msr & MAT) {
irqs_to_clear |= MAT; /* * Address transfer phase finished, but no data at this point. * Try to use DMA to receive data.
*/
rcar_i2c_dma(priv);
} elseif (priv->pos < msg->len) { /* get received data */
u8 data = rcar_i2c_read(priv, ICRXTX);
msg->buf[priv->pos] = data; if (recv_len_init) { if (data == 0 || data > I2C_SMBUS_BLOCK_MAX) {
priv->flags |= ID_DONE | ID_EPROTO; return;
}
msg->len += msg->buf[0]; /* Enough data for DMA? */ if (rcar_i2c_dma(priv)) return; /* new length after RECV_LEN now properly initialized */
recv_len_init = false;
}
priv->pos++;
}
/* * If next received data is the _LAST_ and we are not waiting for a new * length because of RECV_LEN, then go to a new phase.
*/ if (priv->pos + 1 == msg->len && !recv_len_init) { if (priv->flags & ID_LAST_MSG) {
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP);
} else {
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START);
priv->flags |= ID_REP_AFTER_RD;
}
}
if (priv->pos == msg->len && !(priv->flags & ID_LAST_MSG))
rcar_i2c_next_msg(priv);
/* master wants to write to us */ if (ssr_filtered & SDR) {
value = rcar_i2c_read(priv, ICRXTX);
ret = i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_RECEIVED, &value); if (ret)
priv->slave_flags |= ID_SLAVE_NACK;
/* Send NACK in case of error, but it will come 1 byte late :( */
rcar_i2c_write(priv, ICSCR, SIE | SDBS |
(priv->slave_flags & ID_SLAVE_NACK ? FNA : 0));
rcar_i2c_write(priv, ICSSR, ~SDR & 0xff);
}
/* master wants to read from us */ if (ssr_filtered & SDE) {
i2c_slave_event(priv->slave, I2C_SLAVE_READ_PROCESSED, &value);
rcar_i2c_write(priv, ICRXTX, value);
rcar_i2c_write(priv, ICSSR, ~SDE & 0xff);
}
returntrue;
}
/* * This driver has a lock-free design because there are IP cores (at least * R-Car Gen2) which have an inherent race condition in their hardware design. * There, we need to switch to RCAR_BUS_PHASE_DATA as soon as possible after * the interrupt was generated, otherwise an unwanted repeated message gets * generated. It turned out that taking a spinlock at the beginning of the ISR * was already causing repeated messages. Thus, this driver was converted to * the now lockless behaviour. Please keep this in mind when hacking the driver. * R-Car Gen3 seems to have this fixed but earlier versions than R-Car Gen2 are * likely affected. Therefore, we have different interrupt handler entries.
*/ static irqreturn_t rcar_i2c_irq(int irq, struct rcar_i2c_priv *priv, u32 msr)
{ if (!msr) { if (rcar_i2c_slave_irq(priv)) return IRQ_HANDLED;
return IRQ_NONE;
}
/* Arbitration lost */ if (msr & MAL) {
priv->flags |= ID_DONE | ID_ARBLOST; goto out;
}
/* Nack */ if (msr & MNR) { /* HW automatically sends STOP after received NACK */ if (priv->flags & ID_P_NOT_ATOMIC)
rcar_i2c_write(priv, ICMIER, RCAR_IRQ_STOP);
priv->flags |= ID_NACK; goto out;
}
/* Stop */ if (msr & MST) {
priv->msgs_left--; /* The last message also made it */
priv->flags |= ID_DONE; goto out;
}
if (rcar_i2c_is_recv(priv))
rcar_i2c_irq_recv(priv, msr); else
rcar_i2c_irq_send(priv, msr);
out: if (priv->flags & ID_DONE) {
rcar_i2c_write(priv, ICMIER, 0);
rcar_i2c_write(priv, ICMSR, 0); if (priv->flags & ID_P_NOT_ATOMIC)
wake_up(&priv->wait);
}
/* Clear START or STOP immediately, except for REPSTART after read */ if (likely(!(priv->flags & ID_REP_AFTER_RD)))
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA);
/* Only handle interrupts that are currently enabled */
msr = rcar_i2c_read(priv, ICMSR); if (priv->flags & ID_P_NOT_ATOMIC)
msr &= rcar_i2c_read(priv, ICMIER);
/* Only handle interrupts that are currently enabled */
msr = rcar_i2c_read(priv, ICMSR); if (priv->flags & ID_P_NOT_ATOMIC)
msr &= rcar_i2c_read(priv, ICMIER);
/* * Clear START or STOP immediately, except for REPSTART after read or * if a spurious interrupt was detected.
*/ if (likely(!(priv->flags & ID_REP_AFTER_RD) && msr))
rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA);
staticint rcar_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{ struct rcar_i2c_priv *priv = i2c_get_adapdata(adap); struct device *dev = rcar_i2c_priv_to_dev(priv); int i, ret; long time_left;
priv->flags |= ID_P_NOT_ATOMIC;
pm_runtime_get_sync(dev);
/* Check bus state before init otherwise bus busy info will be lost */
ret = rcar_i2c_bus_barrier(priv); if (ret < 0) goto out;
/* Gen3+ needs a reset. That also allows RXDMA once */ if (priv->devtype >= I2C_RCAR_GEN3) {
ret = rcar_i2c_do_reset(priv); if (ret) goto out;
priv->flags &= ~ID_P_NO_RXDMA;
}
rcar_i2c_init(priv);
for (i = 0; i < num; i++)
rcar_i2c_request_dma(priv, msgs + i);
rcar_i2c_first_msg(priv, msgs, num);
time_left = wait_event_timeout(priv->wait, priv->flags & ID_DONE,
num * adap->timeout);
/* cleanup DMA if it couldn't complete properly due to an error */ if (priv->dma_direction != DMA_NONE)
rcar_i2c_cleanup_dma(priv, true);
if (!time_left) {
rcar_i2c_init(priv);
ret = -ETIMEDOUT;
} elseif (priv->flags & ID_NACK) {
ret = -ENXIO;
} elseif (priv->flags & ID_ARBLOST) {
ret = -EAGAIN;
} elseif (priv->flags & ID_EPROTO) {
ret = -EPROTO;
} else {
ret = num - priv->msgs_left; /* The number of transfer */
}
out:
pm_runtime_put(dev);
if (ret < 0 && ret != -ENXIO)
dev_err(dev, "error %d : %x\n", ret, priv->flags);
if (!time_left) {
rcar_i2c_init(priv);
ret = -ETIMEDOUT;
} elseif (priv->flags & ID_NACK) {
ret = -ENXIO;
} elseif (priv->flags & ID_ARBLOST) {
ret = -EAGAIN;
} elseif (priv->flags & ID_EPROTO) {
ret = -EPROTO;
} else {
ret = num - priv->msgs_left; /* The number of transfer */
}
out:
pm_runtime_put(dev);
if (ret < 0 && ret != -ENXIO)
dev_err(dev, "error %d : %x\n", ret, priv->flags);
/* Activate device for clock calculation */
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
ret = rcar_i2c_clock_calculate(priv); if (ret < 0) {
pm_runtime_put(dev); goto out_pm_disable;
}
/* Bring hardware to known state */
rcar_i2c_init(priv);
rcar_i2c_reset_slave(priv);
/* Stay always active when multi-master to keep arbitration working */ if (of_property_read_bool(dev->of_node, "multi-master"))
priv->flags |= ID_P_PM_BLOCKED; else
pm_runtime_put(dev);
if (of_property_read_bool(dev->of_node, "smbus"))
priv->flags |= ID_P_HOST_NOTIFY;
if (priv->devtype < I2C_RCAR_GEN3) {
irqflags |= IRQF_NO_THREAD;
irqhandler = rcar_i2c_gen2_irq;
} else { /* R-Car Gen3+ needs a reset before every transfer */
priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); if (IS_ERR(priv->rstc)) {
ret = PTR_ERR(priv->rstc); goto out_pm_put;
}
ret = reset_control_status(priv->rstc); if (ret < 0) goto out_pm_put;
/* hard reset disturbs HostNotify local target, so disable it */
priv->flags &= ~ID_P_HOST_NOTIFY;
}
ret = platform_get_irq(pdev, 0); if (ret < 0) goto out_pm_put;
priv->irq = ret;
ret = devm_request_irq(dev, priv->irq, irqhandler, irqflags, dev_name(dev), priv); if (ret < 0) {
dev_err(dev, "cannot get irq %d\n", priv->irq); goto out_pm_put;
}
platform_set_drvdata(pdev, priv);
ret = i2c_add_numbered_adapter(adap); if (ret < 0) goto out_pm_put;
if (priv->flags & ID_P_HOST_NOTIFY) {
priv->host_notify_client = i2c_new_slave_host_notify_device(adap); if (IS_ERR(priv->host_notify_client)) {
ret = PTR_ERR(priv->host_notify_client); goto out_del_device;
}
}
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.