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:
parent
fc4b39b1dd
commit
120dfbd45f
@ -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)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user