Use small lock to protect resources related to i2c master and slave.

Signed-off-by: wangzhi16 <wangzhi16@xiaomi.com>
This commit is contained in:
wangzhi16 2025-01-23 15:14:28 +08:00 committed by Xiang Xiao
parent f8501fa3ea
commit 2c4fe28d4e
7 changed files with 150 additions and 76 deletions

View file

@ -60,7 +60,7 @@
#include <nuttx/semaphore.h>
#include <nuttx/i2c/i2c_master.h>
#include <nuttx/irq.h>
#include <nuttx/spinlock.h>
#include <arch/board/board.h>
#include "chip.h"
@ -136,6 +136,7 @@ struct lpc54_i2cdev_s
int16_t result; /* The result of the transfer */
mutex_t lock; /* Only one thread can access at a time */
spinlock_t spinlock; /* Spinlock */
#ifndef CONFIG_I2C_POLLED
sem_t waitsem; /* Supports wait for state machine completion */
uint16_t irq; /* Flexcomm IRQ number */
@ -186,6 +187,7 @@ struct i2c_ops_s lpc54_i2c_ops =
static struct lpc54_i2cdev_s g_i2c0_dev =
{
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
# ifndef CONFIG_I2C_POLLED
.waitsem = SEM_INITIALIZER(0),
# endif
@ -196,6 +198,7 @@ static struct lpc54_i2cdev_s g_i2c0_dev =
static struct lpc54_i2cdev_s g_i2c1_dev =
{
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
# ifndef CONFIG_I2C_POLLED
.waitsem = SEM_INITIALIZER(0),
# endif
@ -206,6 +209,7 @@ static struct lpc54_i2cdev_s g_i2c1_dev =
static struct lpc54_i2cdev_s g_i2c2_dev =
{
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
# ifndef CONFIG_I2C_POLLED
.waitsem = SEM_INITIALIZER(0),
# endif
@ -216,6 +220,7 @@ static struct lpc54_i2cdev_s g_i2c2_dev =
static struct lpc54_i2cdev_s g_i2c3_dev =
{
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
# ifndef CONFIG_I2C_POLLED
.waitsem = SEM_INITIALIZER(0),
# endif
@ -226,6 +231,7 @@ static struct lpc54_i2cdev_s g_i2c3_dev =
static struct lpc54_i2cdev_s g_i2c4_dev =
{
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
# ifndef CONFIG_I2C_POLLED
.waitsem = SEM_INITIALIZER(0),
# endif
@ -236,6 +242,7 @@ static struct lpc54_i2cdev_s g_i2c4_dev =
static struct lpc54_i2cdev_s g_i2c5_dev =
{
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
# ifndef CONFIG_I2C_POLLED
.waitsem = SEM_INITIALIZER(0),
# endif
@ -246,6 +253,7 @@ static struct lpc54_i2cdev_s g_i2c5_dev =
static struct lpc54_i2cdev_s g_i2c6_dev =
{
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
# ifndef CONFIG_I2C_POLLED
.waitsem = SEM_INITIALIZER(0),
# endif
@ -256,6 +264,7 @@ static struct lpc54_i2cdev_s g_i2c6_dev =
static struct lpc54_i2cdev_s g_i2c7_dev =
{
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
# ifndef CONFIG_I2C_POLLED
.waitsem = SEM_INITIALIZER(0),
# endif
@ -266,6 +275,7 @@ static struct lpc54_i2cdev_s g_i2c7_dev =
static struct lpc54_i2cdev_s g_i2c8_dev =
{
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
# ifndef CONFIG_I2C_POLLED
.waitsem = SEM_INITIALIZER(0),
# endif
@ -276,6 +286,7 @@ static struct lpc54_i2cdev_s g_i2c8_dev =
static struct lpc54_i2cdev_s g_i2c9_dev =
{
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
# ifndef CONFIG_I2C_POLLED
.waitsem = SEM_INITIALIZER(0),
# endif
@ -409,7 +420,7 @@ static void lpc54_i2c_timeout(wdparm_t arg)
struct lpc54_i2cdev_s *priv = (struct lpc54_i2cdev_s *)arg;
#ifndef CONFIG_I2C_POLLED
irqstate_t flags = enter_critical_section();
irqstate_t flags = spin_lock_irqsave(&priv->spinlock);
#endif
i2cerr("ERROR: Timeout! state=%u\n", priv->state);
@ -430,7 +441,7 @@ static void lpc54_i2c_timeout(wdparm_t arg)
/* Wake up any waiters */
nxsem_post(&priv->waitsem);
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->spinlock, flags);
#endif
}
@ -521,7 +532,7 @@ static bool lpc54_i2c_nextmsg(struct lpc54_i2cdev_s *priv)
* here.
*/
flags = enter_critical_section();
flags = spin_lock_irqsave(&priv->spinlock);
i2cinfo("nmsgs=%u\n", priv->nmsgs - 1);
@ -535,7 +546,7 @@ static bool lpc54_i2c_nextmsg(struct lpc54_i2cdev_s *priv)
lpc54_i2c_xfrsetup(priv);
i2cinfo("state=%u\n", priv->state);
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->spinlock, flags);
return false;
}
else
@ -552,7 +563,7 @@ static bool lpc54_i2c_nextmsg(struct lpc54_i2cdev_s *priv)
priv->state = I2CSTATE_IDLE;
i2cinfo("state=%u\n", priv->state);
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->spinlock, flags);
return true;
}
}
@ -903,7 +914,7 @@ struct i2c_master_s *lpc54_i2cbus_initialize(int port)
i2cinfo("port=%d\n", port);
flags = enter_critical_section();
flags = spin_lock_irqsave(&priv->spinlock);
/* Configure the requestin I2C peripheral */
@ -1252,12 +1263,12 @@ struct i2c_master_s *lpc54_i2cbus_initialize(int port)
else
#endif
{
spin_unlock_irqrestore(&priv->spinlock, flags);
i2cerr("ERROR: Unsupported port=%d\n", port);
leave_critical_section(flags);
return NULL;
}
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->spinlock, flags);
/* Install our operations */

View file

@ -37,7 +37,7 @@
#include <nuttx/arch.h>
#include <nuttx/i2c/i2c_slave.h>
#include <nuttx/irq.h>
#include <nuttx/spinlock.h>
#include <nuttx/kmalloc.h>
#include <arch/chip/i2c_slave.h>
@ -77,6 +77,8 @@ typedef struct rp2040_i2c_slave_s
i2c_slave_callback_t *callback; /* Callback function */
void *callback_arg; /* Argument for callback */
spinlock_t spinlock; /* Spinlock */
} rp2040_i2c_slave_t;
/****************************************************************************
@ -123,6 +125,7 @@ rp2040_i2c_slave_t i2c0_slave_dev =
{
.dev.ops = &i2c_slaveops, /* Slave operations */
.controller = 0, /* I2C controller number */
.spinlock = SP_UNLOCKED, /* Spinlock */
};
#endif
@ -133,6 +136,7 @@ rp2040_i2c_slave_t i2c1_slave_dev =
{
.dev.ops = &i2c_slaveops, /* Slave operations */
.controller = 1, /* I2C controller number */
.spinlock = SP_UNLOCKED, /* Spinlock */
};
#endif
@ -312,12 +316,9 @@ static int i2c_interrupt(int irq, void *context, void *arg)
*
****************************************************************************/
static void enable_i2c_slave(struct i2c_slave_s *dev)
static void enable_i2c_slave_nolock(struct i2c_slave_s *dev)
{
rp2040_i2c_slave_t *priv = (rp2040_i2c_slave_t *) dev;
irqstate_t flags;
flags = enter_critical_section();
uint32_t intr_mask = RP2040_I2C_IC_INTR_STAT_R_RD_REQ
| RP2040_I2C_IC_INTR_STAT_R_RX_FULL
@ -344,8 +345,15 @@ static void enable_i2c_slave(struct i2c_slave_s *dev)
putreg32(RP2040_I2C_IC_ENABLE_ENABLE,
RP2040_I2C_IC_ENABLE(priv->controller));
}
leave_critical_section(flags);
static void enable_i2c_slave(struct i2c_slave_s *dev)
{
irqstate_t flags;
flags = spin_lock_irqsave(&priv->spinlock);
enable_i2c_slave_nolock(dev);
spin_unlock_irqrestore(&priv->spinlock, flags);
}
/****************************************************************************
@ -366,7 +374,7 @@ static int my_set_own_address(struct i2c_slave_s *dev,
| RP2040_I2C_IC_CON_SPEED_FAST;
irqstate_t flags;
flags = enter_critical_section();
flags = spin_lock_irqsave(&priv->spinlock);
putreg32(address, RP2040_I2C_IC_SAR(priv->controller));
@ -377,9 +385,9 @@ static int my_set_own_address(struct i2c_slave_s *dev,
putreg32(con, RP2040_I2C_IC_CON(priv->controller));
enable_i2c_slave(dev);
enable_i2c_slave_nolock(dev);
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->spinlock, flags);
return OK;
}
@ -399,13 +407,13 @@ static int my_write(struct i2c_slave_s *dev,
rp2040_i2c_slave_t *priv = (rp2040_i2c_slave_t *) dev;
irqstate_t flags;
flags = enter_critical_section();
flags = spin_lock_irqsave(&priv->spinlock);
priv->tx_buffer = buffer;
priv->tx_buf_ptr = buffer;
priv->tx_buf_end = priv->tx_buffer + length;
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->spinlock, flags);
return OK;
}
@ -426,13 +434,13 @@ static int my_read(struct i2c_slave_s *dev,
rp2040_i2c_slave_t *priv = (rp2040_i2c_slave_t *) dev;
irqstate_t flags;
flags = enter_critical_section();
flags = spin_lock_irqsave(&priv->spinlock);
priv->rx_buffer = buffer;
priv->rx_buf_ptr = buffer;
priv->rx_buf_end = priv->rx_buffer + length;
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->spinlock, flags);
return OK;
}
@ -453,12 +461,12 @@ static int my_register_callback(struct i2c_slave_s *dev,
rp2040_i2c_slave_t *priv = (rp2040_i2c_slave_t *) dev;
irqstate_t flags;
flags = enter_critical_section();
flags = spin_lock_irqsave(&priv->spinlock);
priv->callback = callback;
priv->callback_arg = arg;
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->spinlock, flags);
return OK;
}

View file

@ -37,7 +37,7 @@
#include <nuttx/arch.h>
#include <nuttx/i2c/i2c_slave.h>
#include <nuttx/irq.h>
#include <nuttx/spinlock.h>
#include <nuttx/kmalloc.h>
#include <arch/chip/i2c_slave.h>
@ -77,6 +77,8 @@ typedef struct rp23xx_i2c_slave_s
i2c_slave_callback_t *callback; /* Callback function */
void *callback_arg; /* Argument for callback */
spinlock_t spinlock; /* Spinlock */
} rp23xx_i2c_slave_t;
/****************************************************************************
@ -123,6 +125,7 @@ rp23xx_i2c_slave_t i2c0_slave_dev =
{
.dev.ops = &i2c_slaveops, /* Slave operations */
.controller = 0, /* I2C controller number */
.spinlock = SP_UNLOCKED, /* Spinlock */
};
#endif
@ -133,6 +136,7 @@ rp23xx_i2c_slave_t i2c1_slave_dev =
{
.dev.ops = &i2c_slaveops, /* Slave operations */
.controller = 1, /* I2C controller number */
.spinlock = SP_UNLOCKED, /* Spinlock */
};
#endif
@ -312,12 +316,9 @@ static int i2c_interrupt(int irq, void *context, void *arg)
*
****************************************************************************/
static void enable_i2c_slave(struct i2c_slave_s *dev)
static void enable_i2c_slave_nolock(struct i2c_slave_s *dev)
{
rp23xx_i2c_slave_t *priv = (rp23xx_i2c_slave_t *) dev;
irqstate_t flags;
flags = enter_critical_section();
uint32_t intr_mask = RP23XX_I2C_IC_INTR_STAT_R_RD_REQ
| RP23XX_I2C_IC_INTR_STAT_R_RX_FULL
@ -344,8 +345,15 @@ static void enable_i2c_slave(struct i2c_slave_s *dev)
putreg32(RP23XX_I2C_IC_ENABLE_ENABLE,
RP23XX_I2C_IC_ENABLE(priv->controller));
}
leave_critical_section(flags);
static void enable_i2c_slave(struct i2c_slave_s *dev)
{
irqstate_t flags;
flags = spin_lock_irqsave(&priv->spinlock);
enable_i2c_slave_nolock(dev);
spin_unlock_irqrestore(&priv->spinlock, flags);
}
/****************************************************************************
@ -366,7 +374,7 @@ static int my_set_own_address(struct i2c_slave_s *dev,
| RP23XX_I2C_IC_CON_SPEED_FAST;
irqstate_t flags;
flags = enter_critical_section();
flags = spin_lock_irqsave(&priv->spinlock);
putreg32(address, RP23XX_I2C_IC_SAR(priv->controller));
@ -377,9 +385,9 @@ static int my_set_own_address(struct i2c_slave_s *dev,
putreg32(con, RP23XX_I2C_IC_CON(priv->controller));
enable_i2c_slave(dev);
enable_i2c_slave_nolock(dev);
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->spinlock, flags);
return OK;
}
@ -399,13 +407,13 @@ static int my_write(struct i2c_slave_s *dev,
rp23xx_i2c_slave_t *priv = (rp23xx_i2c_slave_t *) dev;
irqstate_t flags;
flags = enter_critical_section();
flags = spin_lock_irqsave(&priv->spinlock);
priv->tx_buffer = buffer;
priv->tx_buf_ptr = buffer;
priv->tx_buf_end = priv->tx_buffer + length;
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->spinlock, flags);
return OK;
}
@ -426,13 +434,13 @@ static int my_read(struct i2c_slave_s *dev,
rp23xx_i2c_slave_t *priv = (rp23xx_i2c_slave_t *) dev;
irqstate_t flags;
flags = enter_critical_section();
flags = spin_lock_irqsave(&priv->spinlock);
priv->rx_buffer = buffer;
priv->rx_buf_ptr = buffer;
priv->rx_buf_end = priv->rx_buffer + length;
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->spinlock, flags);
return OK;
}
@ -453,12 +461,12 @@ static int my_register_callback(struct i2c_slave_s *dev,
rp23xx_i2c_slave_t *priv = (rp23xx_i2c_slave_t *) dev;
irqstate_t flags;
flags = enter_critical_section();
flags = spin_lock_irqsave(&priv->spinlock);
priv->callback = callback;
priv->callback_arg = arg;
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->spinlock, flags);
return OK;
}

View file

@ -58,7 +58,7 @@
#include <debug.h>
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include <nuttx/spinlock.h>
#include <nuttx/wdog.h>
#include <nuttx/clock.h>
#include <nuttx/mutex.h>
@ -171,6 +171,7 @@ struct sam_i2c_dev_s
uint16_t nextflags; /* Next message flags */
mutex_t lock; /* Only one thread can access at a time */
spinlock_t spinlock; /* Spinlock */
sem_t waitsem; /* Wait for I2C transfer completion */
volatile int result; /* The result of the transfer */
volatile int xfrd; /* Number of bytes transfers */
@ -284,6 +285,7 @@ static struct sam_i2c_dev_s g_i2c0 =
},
.attr = &g_i2c0attr,
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
.waitsem = SEM_INITIALIZER(0),
};
#endif
@ -310,6 +312,7 @@ static struct sam_i2c_dev_s g_i2c1 =
},
.attr = &g_i2c1attr,
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
.waitsem = SEM_INITIALIZER(0),
};
#endif
@ -337,6 +340,7 @@ static struct sam_i2c_dev_s g_i2c2 =
},
.attr = &g_i2c2attr,
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
.waitsem = SEM_INITIALIZER(0),
};
#endif
@ -364,6 +368,7 @@ static struct sam_i2c_dev_s g_i2c3 =
},
.attr = &g_i2c3attr,
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
.waitsem = SEM_INITIALIZER(0),
};
#endif
@ -391,6 +396,7 @@ static struct sam_i2c_dev_s g_i2c4 =
},
.attr = &g_i2c4attr,
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
.waitsem = SEM_INITIALIZER(0),
};
#endif
@ -418,6 +424,7 @@ static struct sam_i2c_dev_s g_i2c5 =
},
.attr = &g_i2c5attr,
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
.waitsem = SEM_INITIALIZER(0),
};
#endif
@ -1018,14 +1025,16 @@ static int sam_i2c_transfer(struct i2c_master_s *dev,
{
priv->msg = msgs;
priv->nextflags = count == 0 ? 0 : msgs[1].flags;
flags = enter_critical_section();
flags = spin_lock_irqsave(&priv->spinlock);
i2c_startmessage(priv, msgs);
/* And wait for the transfers to complete.
* Interrupts will be re-enabled while we are waiting.
*/
spin_unlock_irqrestore(&priv->spinlock, flags);
ret = i2c_wait_for_bus(priv, msgs->length);
flags = spin_lock_irqsave(&priv->spinlock);
if (ret < 0)
{
#if 0
@ -1040,12 +1049,12 @@ static int sam_i2c_transfer(struct i2c_master_s *dev,
i2c_putreg8(priv, I2C_INT_MB | I2C_INT_SB,
SAM_I2C_INTENCLR_OFFSET);
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->spinlock, flags);
nxmutex_unlock(&priv->lock);
return ret;
}
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->spinlock, flags);
/* Move to the next message */
@ -1169,9 +1178,9 @@ static uint32_t sam_i2c_setfrequency(struct sam_i2c_dev_s *priv,
*
****************************************************************************/
static void i2c_hw_initialize(struct sam_i2c_dev_s *priv, uint32_t frequency)
static void i2c_hw_initialize_nolock(struct sam_i2c_dev_s *priv,
uint32_t frequency)
{
irqstate_t flags;
uint32_t regval;
uint32_t ctrla = 0;
@ -1179,7 +1188,6 @@ static void i2c_hw_initialize(struct sam_i2c_dev_s *priv, uint32_t frequency)
/* Enable clocking to the SERCOM module in PM */
flags = enter_critical_section();
sercom_enable(priv->attr->sercom);
/* Configure the GCLKs for the SERCOM module */
@ -1194,7 +1202,6 @@ static void i2c_hw_initialize(struct sam_i2c_dev_s *priv, uint32_t frequency)
{
i2cerr
("ERROR: Cannot initialize I2C because it is already initialized!\n");
leave_critical_section(flags);
return;
}
@ -1204,7 +1211,6 @@ static void i2c_hw_initialize(struct sam_i2c_dev_s *priv, uint32_t frequency)
if (regval & I2C_CTRLA_SWRST)
{
i2cerr("ERROR: Module is in RESET process!\n");
leave_critical_section(flags);
return;
}
@ -1244,7 +1250,15 @@ static void i2c_hw_initialize(struct sam_i2c_dev_s *priv, uint32_t frequency)
/* Enable SERCOM interrupts at the NVIC */
up_enable_irq(priv->attr->irq);
leave_critical_section(flags);
}
static void i2c_hw_initialize(struct sam_i2c_dev_s *priv, uint32_t frequency)
{
irqstate_t flags;
flags = spin_lock_irqsave(&priv->spinlock);
i2c_hw_initialize_nolock(priv, frequency);
spin_unlock_irqrestore(&priv->spinlock, flags);
}
/****************************************************************************
@ -1369,7 +1383,7 @@ struct i2c_master_s *sam_i2c_master_initialize(int bus)
/* Perform one-time I2C initialization */
flags = enter_critical_section();
flags = spin_lock_irqsave(&priv->spinlock);
/* Attach Interrupt Handler */
@ -1377,14 +1391,14 @@ struct i2c_master_s *sam_i2c_master_initialize(int bus)
if (ret < 0)
{
i2cerr("ERROR: Failed to attach irq %d\n", priv->attr->irq);
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->spinlock, flags);
return NULL;
}
/* Perform repeatable I2C hardware initialization */
i2c_hw_initialize(priv, frequency);
leave_critical_section(flags);
i2c_hw_initialize_nolock(priv, frequency);
spin_unlock_irqrestore(&priv->spinlock, flags);
return &priv->dev;
}

View file

@ -55,7 +55,7 @@
#include <debug.h>
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include <nuttx/spinlock.h>
#include <nuttx/wdog.h>
#include <nuttx/clock.h>
#include <nuttx/mutex.h>
@ -165,6 +165,7 @@ struct sam_i2c_dev_s
uint16_t nextflags; /* Next message flags */
mutex_t lock; /* Only one thread can access at a time */
spinlock_t spinlock; /* Spinlock */
sem_t waitsem; /* Wait for I2C transfer completion */
volatile int result; /* The result of the transfer */
volatile int xfrd; /* Number of bytes transfers */
@ -276,6 +277,7 @@ static struct sam_i2c_dev_s g_i2c0 =
},
.attr = &g_i2c0attr,
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
.waitsem = SEM_INITIALIZER(0),
};
#endif
@ -303,6 +305,7 @@ static struct sam_i2c_dev_s g_i2c1 =
},
.attr = &g_i2c1attr,
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
.waitsem = SEM_INITIALIZER(0),
};
#endif
@ -330,6 +333,7 @@ static struct sam_i2c_dev_s g_i2c2 =
},
.attr = &g_i2c2attr,
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
.waitsem = SEM_INITIALIZER(0),
};
#endif
@ -357,6 +361,7 @@ static struct sam_i2c_dev_s g_i2c3 =
},
.attr = &g_i2c3attr,
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
.waitsem = SEM_INITIALIZER(0),
};
#endif
@ -384,6 +389,7 @@ static struct sam_i2c_dev_s g_i2c4 =
},
.attr = &g_i2c4attr,
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
.waitsem = SEM_INITIALIZER(0),
};
#endif
@ -411,6 +417,7 @@ static struct sam_i2c_dev_s g_i2c5 =
},
.attr = &g_i2c5attr,
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
.waitsem = SEM_INITIALIZER(0),
};
#endif
@ -438,6 +445,7 @@ static struct sam_i2c_dev_s g_i2c6 =
},
.attr = &g_i2c6attr,
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
.waitsem = SEM_INITIALIZER(0),
};
#endif
@ -465,6 +473,7 @@ static struct sam_i2c_dev_s g_i2c7 =
},
.attr = &g_i2c7attr,
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
.waitsem = SEM_INITIALIZER(0),
};
#endif
@ -1068,22 +1077,24 @@ static int sam_i2c_transfer(struct i2c_master_s *dev,
{
priv->msg = msgs;
priv->nextflags = count == 0 ? 0 : msgs[1].flags;
flags = enter_critical_section();
flags = spin_lock_irqsave(&priv->spinlock);
i2c_startmessage(priv, msgs);
/* And wait for the transfers to complete.
* Interrupts will be re-enabled while we are waiting.
*/
spin_unlock_irqrestore(&priv->spinlock, flags);
ret = i2c_wait_for_bus(priv, msgs->length);
flags = spin_lock_irqsave(&priv->spinlock);
if (ret < 0)
{
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->spinlock, flags);
nxmutex_unlock(&priv->lock);
return ret;
}
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->spinlock, flags);
/* Move to the next message */
@ -1209,9 +1220,9 @@ static uint32_t sam_i2c_setfrequency(struct sam_i2c_dev_s *priv,
*
****************************************************************************/
static void i2c_hw_initialize(struct sam_i2c_dev_s *priv, uint32_t frequency)
static void i2c_hw_initialize_nolock(struct sam_i2c_dev_s *priv,
uint32_t frequency)
{
irqstate_t flags;
uint32_t regval;
uint32_t ctrla = 0;
@ -1219,7 +1230,6 @@ static void i2c_hw_initialize(struct sam_i2c_dev_s *priv, uint32_t frequency)
/* Enable clocking to the SERCOM module in PM */
flags = enter_critical_section();
sercom_enable(priv->attr->sercom);
/* Configure the GCLKs for the SERCOM module */
@ -1234,7 +1244,6 @@ static void i2c_hw_initialize(struct sam_i2c_dev_s *priv, uint32_t frequency)
{
i2cerr("ERROR: Cannot initialize I2C "
"because it is already initialized!\n");
leave_critical_section(flags);
return;
}
@ -1244,7 +1253,6 @@ static void i2c_hw_initialize(struct sam_i2c_dev_s *priv, uint32_t frequency)
if (regval & I2C_CTRLA_SWRST)
{
i2cerr("ERROR: Module is in RESET process!\n");
leave_critical_section(flags);
return;
}
@ -1288,7 +1296,15 @@ static void i2c_hw_initialize(struct sam_i2c_dev_s *priv, uint32_t frequency)
up_enable_irq(priv->attr->irq);
up_enable_irq(priv->attr->irq + 1);
leave_critical_section(flags);
}
static void i2c_hw_initialize(struct sam_i2c_dev_s *priv, uint32_t frequency)
{
irqstate_t flags;
flags = spin_lock_irqsave(&priv->spinlock);
i2c_hw_initialize_nolock(priv, frequency);
spin_unlock_irqrestore(&priv->spinlock, flags);
}
/****************************************************************************
@ -1433,7 +1449,7 @@ struct i2c_master_s *sam_i2c_master_initialize(int bus)
/* Perform one-time I2C initialization */
flags = enter_critical_section();
flags = spin_lock_irqsave(&priv->spinlock);
/* Attach Interrupt Handler */
@ -1441,7 +1457,7 @@ struct i2c_master_s *sam_i2c_master_initialize(int bus)
if (ret < 0)
{
i2cerr("ERROR: Failed to attach irq %d\n", priv->attr->irq);
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->spinlock, flags);
return NULL;
}
@ -1449,14 +1465,14 @@ struct i2c_master_s *sam_i2c_master_initialize(int bus)
if (ret < 0)
{
i2cerr("ERROR: Failed to attach irq %d\n", priv->attr->irq);
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->spinlock, flags);
return NULL;
}
/* Perform repeatable I2C hardware initialization */
i2c_hw_initialize(priv, frequency);
leave_critical_section(flags);
i2c_hw_initialize_nolock(priv, frequency);
spin_unlock_irqrestore(&priv->spinlock, flags);
return &priv->dev;
}

View file

@ -89,7 +89,7 @@
#include <debug.h>
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include <nuttx/spinlock.h>
#include <nuttx/clock.h>
#include <nuttx/mutex.h>
#include <nuttx/semaphore.h>
@ -288,6 +288,7 @@ struct stm32_i2c_priv_s
int refs; /* Reference count */
mutex_t lock; /* Mutual exclusion mutex */
spinlock_t spinlock; /* Spinlock */
#ifndef CONFIG_I2C_POLLED
sem_t sem_isr; /* Interrupt wait semaphore */
#endif
@ -406,6 +407,7 @@ static struct stm32_i2c_priv_s stm32_i2c1_priv =
.config = &stm32_i2c1_config,
.refs = 0,
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
#ifndef CONFIG_I2C_POLLED
.sem_isr = SEM_INITIALIZER(0),
#endif
@ -439,6 +441,7 @@ static struct stm32_i2c_priv_s stm32_i2c2_priv =
.config = &stm32_i2c2_config,
.refs = 0,
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
#ifndef CONFIG_I2C_POLLED
.sem_isr = SEM_INITIALIZER(0),
#endif
@ -472,6 +475,7 @@ static struct stm32_i2c_priv_s stm32_i2c3_priv =
.config = &stm32_i2c3_config,
.refs = 0,
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
#ifndef CONFIG_I2C_POLLED
.sem_isr = SEM_INITIALIZER(0),
#endif
@ -577,7 +581,7 @@ static int stm32_i2c_sem_waitdone(struct stm32_i2c_priv_s *priv)
uint32_t regval;
int ret;
flags = enter_critical_section();
flags = spin_lock_irqsave(&priv->spinlock);
/* Enable I2C interrupts */
@ -593,6 +597,8 @@ static int stm32_i2c_sem_waitdone(struct stm32_i2c_priv_s *priv)
priv->intstate = INTSTATE_WAITING;
do
{
spin_unlock_irqrestore(&priv->spinlock, flags);
/* Wait until either the transfer is complete or the timeout expires */
#ifdef CONFIG_STM32_I2C_DYNTIMEO
@ -611,6 +617,8 @@ static int stm32_i2c_sem_waitdone(struct stm32_i2c_priv_s *priv)
break;
}
flags = spin_lock_irqsave(&priv->spinlock);
}
/* Loop until the interrupt level transfer is complete. */
@ -627,7 +635,7 @@ static int stm32_i2c_sem_waitdone(struct stm32_i2c_priv_s *priv)
regval &= ~I2C_CR2_ALLINTS;
stm32_i2c_putreg(priv, STM32_I2C_CR2_OFFSET, regval);
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->spinlock, flags);
return ret;
}
#else

View file

@ -225,7 +225,7 @@
#include <debug.h>
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include <nuttx/spinlock.h>
#include <nuttx/mutex.h>
#include <nuttx/semaphore.h>
#include <nuttx/kmalloc.h>
@ -407,6 +407,7 @@ struct stm32_i2c_priv_s
int refs; /* Reference count */
mutex_t lock; /* Mutual exclusion mutex */
spinlock_t spinlock; /* Spinlock */
#ifndef CONFIG_I2C_POLLED
sem_t sem_isr; /* Interrupt wait semaphore */
#endif
@ -520,6 +521,7 @@ static struct stm32_i2c_priv_s stm32_i2c1_priv =
.config = &stm32_i2c1_config,
.refs = 0,
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
#ifndef CONFIG_I2C_POLLED
.sem_isr = SEM_INITIALIZER(0),
#endif
@ -556,6 +558,7 @@ static struct stm32_i2c_priv_s stm32_i2c2_priv =
.config = &stm32_i2c2_config,
.refs = 0,
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
#ifndef CONFIG_I2C_POLLED
.sem_isr = SEM_INITIALIZER(0),
#endif
@ -592,6 +595,7 @@ static struct stm32_i2c_priv_s stm32_i2c3_priv =
.config = &stm32_i2c3_config,
.refs = 0,
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
#ifndef CONFIG_I2C_POLLED
.sem_isr = SEM_INITIALIZER(0),
#endif
@ -628,6 +632,7 @@ static struct stm32_i2c_priv_s stm32_i2c4_priv =
.config = &stm32_i2c4_config,
.refs = 0,
.lock = NXMUTEX_INITIALIZER,
.spinlock = SP_UNLOCKED,
#ifndef CONFIG_I2C_POLLED
.sem_isr = SEM_INITIALIZER(0),
#endif
@ -793,7 +798,7 @@ static inline int stm32_i2c_sem_waitdone(struct stm32_i2c_priv_s *priv)
irqstate_t flags;
int ret;
flags = enter_critical_section();
flags = spin_lock_irqsave(&priv->spinlock);
/* Enable I2C interrupts */
@ -810,6 +815,8 @@ static inline int stm32_i2c_sem_waitdone(struct stm32_i2c_priv_s *priv)
priv->intstate = INTSTATE_WAITING;
do
{
spin_unlock_irqrestore(&priv->spinlock, flags);
/* Wait until either the transfer is complete or the timeout expires */
#ifdef CONFIG_STM32_I2C_DYNTIMEO
@ -828,6 +835,8 @@ static inline int stm32_i2c_sem_waitdone(struct stm32_i2c_priv_s *priv)
break;
}
flags = spin_lock_irqsave(&priv->spinlock);
}
/* Loop until the interrupt level transfer is complete. */
@ -842,7 +851,7 @@ static inline int stm32_i2c_sem_waitdone(struct stm32_i2c_priv_s *priv)
stm32_i2c_modifyreg32(priv, STM32_I2C_CR1_OFFSET, I2C_CR1_ALLINTS, 0);
leave_critical_section(flags);
spin_unlock_irqrestore(&priv->spinlock, flags);
return ret;
}
#else
@ -1742,7 +1751,7 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv)
*/
#ifdef CONFIG_I2C_POLLED
irqstate_t state = enter_critical_section();
irqstate_t state = spin_lock_irqsave(&priv->spinlock);
#endif
/* Receive a byte */
@ -1759,7 +1768,7 @@ static int stm32_i2c_isr_process(struct stm32_i2c_priv_s *priv)
priv->dcnt--;
#ifdef CONFIG_I2C_POLLED
leave_critical_section(state);
spin_unlock_irqrestore(&priv->spinlock, state);
#endif
}
else