drivers: i2c: npcx: prevent unexpected target address match ISR
This commit prevents the hardware from generating an unexpected target slave address match ISR by the following change: 1. Enable the New Match Interrupt Enable bit (NMINTEN) only when necessary. 2. Explicitly clear all SMBnADDRx registers because they are not cleared when the I2C hardware is disabled. It will cause the asynchrinization between SMBnADDRx and registered_target_mask if the system jumps from the RO image to the RW image. Signed-off-by: Jun Lin <CHLin56@nuvoton.com> Signed-off-by: Alvis Sun <yfsun@nuvoton.com>
This commit is contained in:
parent
8bfb08fbda
commit
8ab712a235
1 changed files with 42 additions and 33 deletions
|
@ -403,6 +403,37 @@ static inline void i2c_ctrl_fifo_clear_status(const struct device *dev)
|
|||
inst->SMBFIF_CTS |= BIT(NPCX_SMBFIF_CTS_CLR_FIFO);
|
||||
}
|
||||
|
||||
/* I2C target reg access */
|
||||
#ifdef CONFIG_I2C_TARGET
|
||||
static volatile uint8_t *npcx_i2c_ctrl_target_get_reg_smbaddr(const struct device *i2c_dev,
|
||||
int index)
|
||||
{
|
||||
struct smb_reg *const inst = HAL_I2C_INSTANCE(i2c_dev);
|
||||
|
||||
switch (index) {
|
||||
case 0:
|
||||
return &inst->SMBADDR1;
|
||||
case 1:
|
||||
return &inst->SMBADDR2;
|
||||
case 2:
|
||||
return &inst->SMBADDR3;
|
||||
case 3:
|
||||
return &inst->SMBADDR4;
|
||||
case 4:
|
||||
return &inst->SMBADDR5;
|
||||
case 5:
|
||||
return &inst->SMBADDR6;
|
||||
case 6:
|
||||
return &inst->SMBADDR7;
|
||||
case 7:
|
||||
return &inst->SMBADDR8;
|
||||
default:
|
||||
LOG_ERR("Invalid SMBADDR index: %d", index);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_I2C_TARGET */
|
||||
|
||||
/*
|
||||
* I2C local functions which touch the registers in 'Normal' bank. These
|
||||
* utilities will change bank back to FIFO mode when leaving themselves in case
|
||||
|
@ -433,6 +464,16 @@ static void i2c_ctrl_init_module(const struct device *dev)
|
|||
/* Enable module - before configuring CTL1 */
|
||||
inst->SMBCTL2 |= BIT(NPCX_SMBCTL2_ENABLE);
|
||||
|
||||
#ifdef CONFIG_I2C_TARGET
|
||||
volatile uint8_t *reg_smbaddr;
|
||||
|
||||
/* Clear all the SMBnADDR */
|
||||
for (int i = 0; i < NPCX_I2C_FLAG_COUNT; i++) {
|
||||
reg_smbaddr = npcx_i2c_ctrl_target_get_reg_smbaddr(dev, i);
|
||||
*reg_smbaddr = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Enable SMB interrupt and 'New Address Match' interrupt source */
|
||||
inst->SMBCTL1 |= BIT(NPCX_SMBCTL1_NMINTE) | BIT(NPCX_SMBCTL1_INTEN);
|
||||
|
||||
|
@ -1194,33 +1235,6 @@ recover_exit:
|
|||
}
|
||||
|
||||
#ifdef CONFIG_I2C_TARGET
|
||||
static volatile uint8_t *npcx_i2c_ctrl_target_get_reg_smbaddr(const struct device *i2c_dev,
|
||||
int index)
|
||||
{
|
||||
struct smb_reg *const inst = HAL_I2C_INSTANCE(i2c_dev);
|
||||
|
||||
switch (index) {
|
||||
case 0:
|
||||
return &inst->SMBADDR1;
|
||||
case 1:
|
||||
return &inst->SMBADDR2;
|
||||
case 2:
|
||||
return &inst->SMBADDR3;
|
||||
case 3:
|
||||
return &inst->SMBADDR4;
|
||||
case 4:
|
||||
return &inst->SMBADDR5;
|
||||
case 5:
|
||||
return &inst->SMBADDR6;
|
||||
case 6:
|
||||
return &inst->SMBADDR7;
|
||||
case 7:
|
||||
return &inst->SMBADDR8;
|
||||
default:
|
||||
LOG_ERR("Invalid SMBADDR index: %d", index);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int npcx_i2c_ctrl_target_register(const struct device *i2c_dev,
|
||||
struct i2c_target_config *target_cfg, uint8_t port)
|
||||
|
@ -1372,7 +1386,7 @@ int npcx_i2c_ctrl_target_unregister(const struct device *i2c_dev,
|
|||
i2c_ctrl_bank_sel(i2c_dev, NPCX_I2C_BANK_FIFO);
|
||||
|
||||
/* Reconfigure SMBCTL1 */
|
||||
inst->SMBCTL1 |= BIT(NPCX_SMBCTL1_NMINTE) | BIT(NPCX_SMBCTL1_INTEN);
|
||||
inst->SMBCTL1 |= BIT(NPCX_SMBCTL1_INTEN);
|
||||
|
||||
/* Disable irq of smb wake-up event */
|
||||
if (IS_ENABLED(CONFIG_PM)) {
|
||||
|
@ -1392,14 +1406,9 @@ int npcx_i2c_ctrl_target_unregister(const struct device *i2c_dev,
|
|||
|
||||
static void i2c_target_wk_isr(const struct device *dev, struct npcx_wui *wui)
|
||||
{
|
||||
struct smb_reg *const inst = HAL_I2C_INSTANCE(dev);
|
||||
|
||||
/* Clear wake up detection event status */
|
||||
npcx_i2c_target_clear_detection_event();
|
||||
|
||||
/* Reconfigure SMBCTL1 */
|
||||
inst->SMBCTL1 |= BIT(NPCX_SMBCTL1_NMINTE) | BIT(NPCX_SMBCTL1_INTEN);
|
||||
|
||||
/*
|
||||
* Suspend-to-idle stops SMB module clocks (derived from APB2/APB3), which must remain
|
||||
* active during a transaction.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue