Skip to content

Commit

Permalink
Use small lock to protect resources related to i2c master and slave.
Browse files Browse the repository at this point in the history
Signed-off-by: wangzhi16 <[email protected]>
  • Loading branch information
wangzhi-art authored and xiaoxiang781216 committed Jan 23, 2025
1 parent f8501fa commit 2c4fe28
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 76 deletions.
29 changes: 20 additions & 9 deletions arch/arm/src/lpc54xx/lpc54_i2c_master.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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);
Expand All @@ -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
}

Expand Down Expand Up @@ -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);

Expand All @@ -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
Expand All @@ -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;
}
}
Expand Down Expand Up @@ -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 */

Expand Down Expand Up @@ -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 */

Expand Down
38 changes: 23 additions & 15 deletions arch/arm/src/rp2040/rp2040_i2c_slave.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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;

/****************************************************************************
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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));
}

static void enable_i2c_slave(struct i2c_slave_s *dev)
{
irqstate_t flags;

leave_critical_section(flags);
flags = spin_lock_irqsave(&priv->spinlock);
enable_i2c_slave_nolock(dev);
spin_unlock_irqrestore(&priv->spinlock, flags);
}

/****************************************************************************
Expand All @@ -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));

Expand All @@ -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;
}
Expand All @@ -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;
}
Expand All @@ -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;
}
Expand All @@ -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;
}
Expand Down
Loading

0 comments on commit 2c4fe28

Please sign in to comment.