/* Intermediates for recording the transfer process */ struct completion *completion; struct i2c_msg *msgs; int msg_num; int msg_tx_idx; int buf_tx_idx; int msg_rx_idx; int buf_rx_idx;
u16 tar_addr;
u32 xfer_err;
/* * Initialize the transfer information and start the I2C bus transfer. * We only configure the transfer and do some pre/post works here, and * wait for the transfer done. The major transfer process is performed * in the IRQ handler.
*/ staticint hisi_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
{ struct hisi_i2c_controller *ctlr = i2c_get_adapdata(adap);
DECLARE_COMPLETION_ONSTACK(done); int ret = num;
/* Update the transfer index after per message transfer is done. */ if (ctlr->buf_tx_idx == cur_msg->len) {
ctlr->buf_tx_idx = 0;
ctlr->msg_tx_idx++;
}
if ((fifo_state & HISI_I2C_FIFO_STATE_TX_FULL) ||
max_write == 0) break;
}
/* * Disable the TX_EMPTY interrupt after finishing all the messages to * avoid overwhelming the CPU.
*/ if (ctlr->msg_tx_idx == ctlr->msg_num)
hisi_i2c_disable_int(ctlr, HISI_I2C_INT_TX_EMPTY);
/* * Don't handle the interrupt if cltr->completion is NULL. We may * reach here because the interrupt is spurious or the transfer is * started by another port (e.g. firmware) rather than us.
*/ if (!ctlr->completion) return IRQ_NONE;
/* Drain the rx fifo before finish the transfer */ if (int_stat & (HISI_I2C_INT_TRANS_CPLT | HISI_I2C_INT_RX_FULL))
hisi_i2c_read_rx_fifo(ctlr);
out: /* * Only use TRANS_CPLT to indicate the completion. On error cases we'll * get two interrupts, INT_ERR first then TRANS_CPLT.
*/ if (int_stat & HISI_I2C_INT_TRANS_CPLT) {
hisi_i2c_disable_int(ctlr, HISI_I2C_INT_ALL);
hisi_i2c_clear_int(ctlr, HISI_I2C_INT_ALL);
hisi_i2c_clear_tx_int(ctlr, HISI_I2C_TX_AEMPTY_INT);
complete(ctlr->completion);
}
return IRQ_HANDLED;
}
/* * Helper function for calculating and configuring the HIGH and LOW * periods of SCL clock. The caller will pass the ratio of the * counts (divide / divisor) according to the target speed mode, * and the target registers.
*/ staticvoid hisi_i2c_set_scl(struct hisi_i2c_controller *ctlr,
u32 divide, u32 divisor,
u32 reg_hcnt, u32 reg_lcnt)
{
u32 total_cnt, t_scl_hcnt, t_scl_lcnt, scl_fall_cnt, scl_rise_cnt;
u32 scl_hcnt, scl_lcnt;
/* Total SCL clock cycles per speed period */
total_cnt = DIV_ROUND_UP_ULL(ctlr->clk_rate_khz * HZ_PER_KHZ, ctlr->t.bus_freq_hz); /* Total HIGH level SCL clock cycles including edges */
t_scl_hcnt = DIV_ROUND_UP_ULL(total_cnt * divide, divisor); /* Total LOW level SCL clock cycles including edges */
t_scl_lcnt = total_cnt - t_scl_hcnt; /* Fall edge SCL clock cycles */
scl_fall_cnt = NSEC_TO_CYCLES(ctlr->t.scl_fall_ns, ctlr->clk_rate_khz); /* Rise edge SCL clock cycles */
scl_rise_cnt = NSEC_TO_CYCLES(ctlr->t.scl_rise_ns, ctlr->clk_rate_khz);
/* Calculated HIGH and LOW periods of SCL clock */
scl_hcnt = t_scl_hcnt - ctlr->spk_len - 7 - scl_fall_cnt;
scl_lcnt = t_scl_lcnt - 1 - scl_rise_cnt;
/* For default condition force the bus speed to standard mode. */
ctlr->t.bus_freq_hz = I2C_MAX_STANDARD_MODE_FREQ;
hisi_i2c_set_scl(ctlr, 40, 87, HISI_I2C_SS_SCL_HCNT, HISI_I2C_SS_SCL_LCNT); break;
}
MODULE_AUTHOR("Yicong Yang <yangyicong@hisilicon.com>");
MODULE_DESCRIPTION("HiSilicon I2C Controller Driver");
MODULE_LICENSE("GPL");
Messung V0.5 in Prozent
¤ 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.0.15Bemerkung:
(vorverarbeitet am 2026-06-08)
¤
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.