From 5b73f3117aa9ca8b45faafef9313414284fcd9a0 Mon Sep 17 00:00:00 2001 From: Jukka Laitinen Date: Thu, 11 Jan 2024 12:13:35 +0200 Subject: [PATCH] arch/risc-v/src/mpfs/mpfs_i2c.c: Correct i2c reset / error recovery - Use mpfs_i2c_deinit+mpfs_i2c_init sequence to re-initialize i2c block - Use the i2c mutex to protect the reset; in case there are several devices on the same bus, and one of them resets the bus, reset must not occur in the middle of another device's transfer. - Move irq attach to the i2c_init as the irq detach is in i2c_deinit Signed-off-by: Jukka Laitinen --- arch/risc-v/src/mpfs/mpfs_i2c.c | 45 ++++++++++++++++----------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/arch/risc-v/src/mpfs/mpfs_i2c.c b/arch/risc-v/src/mpfs/mpfs_i2c.c index cc0ce76461b94..4dd24665effd4 100644 --- a/arch/risc-v/src/mpfs/mpfs_i2c.c +++ b/arch/risc-v/src/mpfs/mpfs_i2c.c @@ -125,6 +125,8 @@ static const uint32_t mpfs_i2c_freqs_fpga[MPFS_I2C_NUMBER_OF_DIVIDERS] = MPFS_FPGA_BCLK / 8 }; +static int mpfs_i2c_irq(int cpuint, void *context, void *arg); + static int mpfs_i2c_transfer(struct i2c_master_s *dev, struct i2c_msg_s *msgs, int count); @@ -300,8 +302,22 @@ static uint32_t mpfs_i2c_timeout(int msgc, struct i2c_msg_s *msgv); static int mpfs_i2c_init(struct mpfs_i2c_priv_s *priv) { + int ret = OK; + if (!priv->initialized) { + /* Clear any pending serial interrupt flag */ + + modifyreg32(MPFS_I2C_CTRL, MPFS_I2C_CTRL_SI_MASK, 0); + + /* Attach interrupt */ + + ret = irq_attach(priv->plic_irq, mpfs_i2c_irq, priv); + if (ret != OK) + { + return ret; + } + if (priv->fpga) { /* FIC3 is used by many, don't reset it here, or many @@ -837,26 +853,15 @@ static int mpfs_i2c_reset(struct i2c_master_s *dev) { struct mpfs_i2c_priv_s *priv = (struct mpfs_i2c_priv_s *)dev; int ret; - irqstate_t flags; - - DEBUGASSERT(priv != NULL); - flags = enter_critical_section(); - - /* Disabling I2C interrupts. - * NOTE: up_enable_irq() will be called at mpfs_i2c_sendstart() - */ - - up_disable_irq(priv->plic_irq); + nxmutex_lock(&priv->lock); - priv->inflight = false; - priv->status = MPFS_I2C_SUCCESS; - priv->initialized = false; + mpfs_i2c_deinit(priv); ret = mpfs_i2c_init(priv); if (ret != OK) { - leave_critical_section(flags); + nxmutex_unlock(&priv->lock); return ret; } @@ -864,8 +869,10 @@ static int mpfs_i2c_reset(struct i2c_master_s *dev) priv->tx_idx = 0; priv->rx_size = 0; priv->rx_idx = 0; + priv->inflight = false; + priv->status = MPFS_I2C_SUCCESS; - leave_critical_section(flags); + nxmutex_unlock(&priv->lock); return OK; } @@ -1059,14 +1066,6 @@ struct i2c_master_s *mpfs_i2cbus_initialize(int port) priv->fpga = true; #endif - ret = irq_attach(priv->plic_irq, mpfs_i2c_irq, priv); - if (ret != OK) - { - priv->refs--; - nxmutex_unlock(&priv->lock); - return NULL; - } - ret = mpfs_i2c_init(priv); if (ret != OK) {