Skip to content

Commit

Permalink
arch/risc-v/src/mpfs/mpfs_i2c.c: Correct i2c reset / error recovery
Browse files Browse the repository at this point in the history
- 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 <[email protected]>
  • Loading branch information
jlaitine committed Jan 11, 2024
1 parent ad3078d commit 5b73f31
Showing 1 changed file with 22 additions and 23 deletions.
45 changes: 22 additions & 23 deletions arch/risc-v/src/mpfs/mpfs_i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -837,35 +853,26 @@ 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;
}

priv->tx_size = 0;
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;
}
Expand Down Expand Up @@ -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)
{
Expand Down

0 comments on commit 5b73f31

Please sign in to comment.