#define SPACEMIT_RCR_SDA_GLITCH_NOFIX BIT(7) /* bypass the SDA glitch fix */ /* the cycles of SCL during bus reset */ #define SPACEMIT_RCR_FIELD_RST_CYC GENMASK(3, 0)
/* index of the current message being processed */
u32 msg_idx;
u8 *msg_buf; /* the number of unprocessed bytes remaining in the current message */
u32 unprocessed;
/* if bus is locked, reset unit. 0: locked */
status = readl(i2c->base + SPACEMIT_IBMR); if ((status & SPACEMIT_BMR_SDA) && (status & SPACEMIT_BMR_SCL)) return;
spacemit_i2c_reset(i2c);
usleep_range(10, 20);
for (clk_cnt = 0; clk_cnt < SPACEMIT_BUS_RESET_CLK_CNT_MAX; clk_cnt++) {
status = readl(i2c->base + SPACEMIT_IBMR); if (status & SPACEMIT_BMR_SDA) return;
/* There's nothing left to save here, we are about to exit */
writel(FIELD_PREP(SPACEMIT_RCR_FIELD_RST_CYC, 1),
i2c->base + SPACEMIT_IRCR);
writel(SPACEMIT_CR_RSTREQ, i2c->base + SPACEMIT_ICR);
usleep_range(20, 30);
}
/* check sda again here */
status = readl(i2c->base + SPACEMIT_IBMR); if (!(status & SPACEMIT_BMR_SDA))
dev_warn_ratelimited(i2c->dev, "unit reset failed\n");
}
staticint spacemit_i2c_wait_bus_idle(struct spacemit_i2c_dev *i2c)
{ int ret;
u32 val;
val = readl(i2c->base + SPACEMIT_ISR); if (!(val & (SPACEMIT_SR_UB | SPACEMIT_SR_IBB))) return 0;
ret = readl_poll_timeout(i2c->base + SPACEMIT_ISR,
val, !(val & (SPACEMIT_SR_UB | SPACEMIT_SR_IBB)),
1500, SPACEMIT_I2C_BUS_BUSY_TIMEOUT); if (ret)
spacemit_i2c_reset(i2c);
return ret;
}
staticvoid spacemit_i2c_check_bus_release(struct spacemit_i2c_dev *i2c)
{ /* in case bus is not released after transfer completes */ if (readl(i2c->base + SPACEMIT_ISR) & SPACEMIT_SR_EBB) {
spacemit_i2c_conditionally_reset_bus(i2c);
usleep_range(90, 150);
}
}
/* * Unmask interrupt bits for all xfer mode: * bus error, arbitration loss detected. * For transaction complete signal, we use master stop * interrupt, so we don't need to unmask SPACEMIT_CR_TXDONEIE.
*/
val = SPACEMIT_CR_BEIE | SPACEMIT_CR_ALDIE;
/* * Unmask interrupt bits for interrupt xfer mode: * When IDBR receives a byte, an interrupt is triggered. * * For the tx empty interrupt, it will be enabled in the * i2c_start function. * Otherwise, it will cause an erroneous empty interrupt before i2c_start.
*/
val |= SPACEMIT_CR_DRFIE;
if (i2c->clock_freq == SPACEMIT_I2C_MAX_FAST_MODE_FREQ)
val |= SPACEMIT_CR_MODE_FAST;
/* disable response to general call */
val |= SPACEMIT_CR_GCD;
/* enable SCL clock output */
val |= SPACEMIT_CR_SCLE;
/* * The glitch fix in the K1 I2C controller introduces a delay * on restart signals, so we disable the fix here.
*/
val = readl(i2c->base + SPACEMIT_IRCR);
val |= SPACEMIT_RCR_SDA_GLITCH_NOFIX;
writel(val, i2c->base + SPACEMIT_IRCR);
}
staticvoid spacemit_i2c_handle_write(struct spacemit_i2c_dev *i2c)
{ /* if transfer completes, SPACEMIT_ISR will handle it */ if (i2c->status & SPACEMIT_SR_MSD) return;
if (i2c->unprocessed) {
writel(*i2c->msg_buf++, i2c->base + SPACEMIT_IDBR);
i2c->unprocessed--; return;
}
/* * Here the transaction is already done, we don't need any * other interrupt signals from now, in case any interrupt * happens before spacemit_i2c_xfer to disable irq and i2c unit, * we mask all the interrupt signals and clear the interrupt * status.
*/
val = readl(i2c->base + SPACEMIT_ICR);
val &= ~SPACEMIT_I2C_INT_CTRL_MASK;
writel(val, i2c->base + SPACEMIT_ICR);
/* * Multiply by 9 because each byte in I2C transmission requires * 9 clock cycles: 8 bits of data plus 1 ACK/NACK bit.
*/
timeout = cnt * 9 * USEC_PER_SEC / i2c->clock_freq;
staticint spacemit_i2c_xfer(struct i2c_adapter *adapt, struct i2c_msg *msgs, int num)
{ struct spacemit_i2c_dev *i2c = i2c_get_adapdata(adapt); int ret;
i2c->msgs = msgs;
i2c->msg_num = num;
spacemit_i2c_calc_timeout(i2c);
spacemit_i2c_init(i2c);
spacemit_i2c_enable(i2c);
ret = spacemit_i2c_wait_bus_idle(i2c); if (!ret) {
ret = spacemit_i2c_xfer_msg(i2c); if (ret < 0)
dev_dbg(i2c->dev, "i2c transfer error: %d\n", ret);
} else {
spacemit_i2c_check_bus_release(i2c);
}
spacemit_i2c_disable(i2c);
if (ret == -ETIMEDOUT || ret == -EAGAIN)
dev_err(i2c->dev, "i2c transfer failed, ret %d err 0x%lx\n",
ret, i2c->status & SPACEMIT_SR_ERR);
i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL); if (!i2c) return -ENOMEM;
ret = of_property_read_u32(of_node, "clock-frequency", &i2c->clock_freq); if (ret && ret != -EINVAL)
dev_warn(dev, "failed to read clock-frequency property: %d\n", ret);
/* For now, this driver doesn't support high-speed. */ if (!i2c->clock_freq || i2c->clock_freq > SPACEMIT_I2C_MAX_FAST_MODE_FREQ) {
dev_warn(dev, "unsupported clock frequency %u; using %u\n",
i2c->clock_freq, SPACEMIT_I2C_MAX_FAST_MODE_FREQ);
i2c->clock_freq = SPACEMIT_I2C_MAX_FAST_MODE_FREQ;
} elseif (i2c->clock_freq < SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ) {
dev_warn(dev, "unsupported clock frequency %u; using %u\n",
i2c->clock_freq, SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ);
i2c->clock_freq = SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ;
}
i2c->dev = &pdev->dev;
i2c->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(i2c->base)) return dev_err_probe(dev, PTR_ERR(i2c->base), "failed to do ioremap");
i2c->irq = platform_get_irq(pdev, 0); if (i2c->irq < 0) return dev_err_probe(dev, i2c->irq, "failed to get irq resource");
ret = devm_request_irq(i2c->dev, i2c->irq, spacemit_i2c_irq_handler,
IRQF_NO_SUSPEND | IRQF_ONESHOT, dev_name(i2c->dev), i2c); if (ret) return dev_err_probe(dev, ret, "failed to request irq");
clk = devm_clk_get_enabled(dev, "func"); if (IS_ERR(clk)) return dev_err_probe(dev, PTR_ERR(clk), "failed to enable func clock");
clk = devm_clk_get_enabled(dev, "bus"); if (IS_ERR(clk)) return dev_err_probe(dev, PTR_ERR(clk), "failed to enable bus clock");
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.