mirror of
https://github.com/apache/nuttx.git
synced 2026-06-05 15:58:59 +08:00
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:
committed by
Xiang Xiao
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
|
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,
|
static int mpfs_i2c_transfer(struct i2c_master_s *dev,
|
||||||
struct i2c_msg_s *msgs,
|
struct i2c_msg_s *msgs,
|
||||||
int count);
|
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)
|
static int mpfs_i2c_init(struct mpfs_i2c_priv_s *priv)
|
||||||
{
|
{
|
||||||
|
int ret = OK;
|
||||||
|
|
||||||
if (!priv->initialized)
|
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)
|
if (priv->fpga)
|
||||||
{
|
{
|
||||||
/* FIC3 is used by many, don't reset it here, or many
|
/* 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;
|
struct mpfs_i2c_priv_s *priv = (struct mpfs_i2c_priv_s *)dev;
|
||||||
int ret;
|
int ret;
|
||||||
irqstate_t flags;
|
|
||||||
|
|
||||||
DEBUGASSERT(priv != NULL);
|
nxmutex_lock(&priv->lock);
|
||||||
|
|
||||||
flags = enter_critical_section();
|
mpfs_i2c_deinit(priv);
|
||||||
|
|
||||||
/* 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;
|
|
||||||
|
|
||||||
ret = mpfs_i2c_init(priv);
|
ret = mpfs_i2c_init(priv);
|
||||||
if (ret != OK)
|
if (ret != OK)
|
||||||
{
|
{
|
||||||
leave_critical_section(flags);
|
nxmutex_unlock(&priv->lock);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -865,8 +870,10 @@ static int mpfs_i2c_reset(struct i2c_master_s *dev)
|
|||||||
priv->tx_idx = 0;
|
priv->tx_idx = 0;
|
||||||
priv->rx_size = 0;
|
priv->rx_size = 0;
|
||||||
priv->rx_idx = 0;
|
priv->rx_idx = 0;
|
||||||
|
priv->inflight = false;
|
||||||
|
priv->status = MPFS_I2C_SUCCESS;
|
||||||
|
|
||||||
leave_critical_section(flags);
|
nxmutex_unlock(&priv->lock);
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@@ -1060,14 +1067,6 @@ struct i2c_master_s *mpfs_i2cbus_initialize(int port)
|
|||||||
priv->fpga = true;
|
priv->fpga = true;
|
||||||
#endif
|
#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);
|
ret = mpfs_i2c_init(priv);
|
||||||
if (ret != OK)
|
if (ret != OK)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user