Hello Yicong, 22.03.2021 14:10, Yicong Yang пишет: > Add HiSilicon I2C controller driver for the Kunpeng SoC. It provides > the access to the i2c busses, which connects to the eeprom, rtc, etc. > > The driver works with IRQ mode, and supports basic I2C features and 10bit > address. The DMA is not supported. > > Signed-off-by: Yicong Yang <yangyicong@xxxxxxxxxxxxx> > --- > drivers/i2c/busses/Kconfig | 10 + > drivers/i2c/busses/Makefile | 1 + > drivers/i2c/busses/i2c-hisi.c | 525 ++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 536 insertions(+) > create mode 100644 drivers/i2c/busses/i2c-hisi.c ... > + > +#define NSEC_TO_CYCLES(ns, clk_rate_khz) (DIV_ROUND_UP_ULL((clk_rate_khz) * (ns), NSEC_PER_MSEC)) This is a very long line, you should split it into two. Parens around DIV_ROUND_UP_ULL aren't needed. ... > +static void hisi_i2c_enable_int(struct hisi_i2c_controller *ctlr, u32 mask) > +{ > + writel(mask, ctlr->iobase + HISI_I2C_INT_MASK); Why you don't use relaxed versions of readl/writel? Do you really need to insert memory barriers? > +} > + > +static void hisi_i2c_disable_int(struct hisi_i2c_controller *ctlr, u32 mask) > +{ > + writel((~mask) & HISI_I2C_INT_ALL, ctlr->iobase + HISI_I2C_INT_MASK); > +} > + > +static void hisi_i2c_clear_int(struct hisi_i2c_controller *ctlr, u32 mask) > +{ > + writel(mask, ctlr->iobase + HISI_I2C_INT_CLR); > +} > + > +static void hisi_i2c_handle_errors(struct hisi_i2c_controller *ctlr) > +{ > + u32 int_err = ctlr->xfer_err, reg; > + > + if (int_err & HISI_I2C_INT_FIFO_ERR) { > + reg = readl(ctlr->iobase + HISI_I2C_FIFO_STATE); > + > + if (reg & HISI_I2C_FIFO_STATE_RX_RERR) > + dev_err(ctlr->dev, "rx fifo error read.\n"); The dot "." in the end of error messages is unnecessary. ... > +/* > + * 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. > + */ > +static int hisi_i2c_master_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; > + > + hisi_i2c_reset_xfer(ctlr); > + ctlr->completion = &done; > + ctlr->msg_num = num; > + ctlr->msgs = msgs; > + > + hisi_i2c_start_xfer(ctlr); > + > + if (!wait_for_completion_timeout(ctlr->completion, adap->timeout)) { > + hisi_i2c_disable_int(ctlr, HISI_I2C_INT_ALL); This doesn't save you from racing with the interrupt handler. It looks like you need to enable/disable IRQ around the completion, similarly to what NVIDIA Tegra I2C driver does.