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 <jukkax@ssrc.tii.ae>
This commit is contained in:
Jukka Laitinen 2024-01-11 12:13:35 +02:00 committed by Xiang Xiao
parent fc4b39b1dd
commit 120dfbd45f

View File

@ -126,6 +126,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);
@ -301,8 +303,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
@ -838,26 +854,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);
nxmutex_lock(&priv->lock);
flags = enter_critical_section();
/* Disabling I2C interrupts.
* NOTE: up_enable_irq() will be called at mpfs_i2c_sendstart()
*/
up_disable_irq(priv->plic_irq);
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;
}
@ -865,8 +870,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;
}
@ -1060,14 +1067,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)
{