Skip to content

Commit 582d0c8

Browse files
committed
drivers: i2c: add i2c dw support error checks.
support errors check for 1. tx_abrt: nack and sda stuck low 2. scl stuck low Signed-off-by: Titan Chen <[email protected]>
1 parent c9ca9f8 commit 582d0c8

File tree

1 file changed

+56
-1
lines changed

1 file changed

+56
-1
lines changed

drivers/i2c/i2c_dw.c

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,48 @@ int i2c_dw_recovery_bus(const struct device *dev)
110110
return ret;
111111
}
112112

113+
static int i2c_dw_error_chk(const struct device *dev)
114+
{
115+
struct i2c_dw_dev_config *const dw = dev->data;
116+
uint32_t reg_base = get_regs(dev);
117+
union ic_interrupt_register intr_stat;
118+
union ic_txabrt_register ic_txabrt_src;
119+
uint32_t value;
120+
/* Cache ic_intr_stat and txabrt_src for processing,
121+
* so there is no need to read the register multiple times.
122+
*/
123+
intr_stat.raw = read_intr_stat(reg_base);
124+
ic_txabrt_src.raw = read_txabrt_src(reg_base);
125+
/* NACK and SDA_STUCK are below TX_Abort */
126+
if (intr_stat.bits.tx_abrt) {
127+
/* check 7bit NACK Tx Abort */
128+
if (ic_txabrt_src.bits.ADDR7BNACK) {
129+
dw->state |= I2C_DW_NACK;
130+
LOG_ERR("NACK on %s", dev->name);
131+
}
132+
/* check SDA stuck low Tx abort, need to do bus recover */
133+
if (ic_txabrt_src.bits.SDASTUCKLOW) {
134+
dw->state |= I2C_DW_SDA_STUCK;
135+
LOG_ERR("SDA Stuck Low on %s", dev->name);
136+
}
137+
/* clear RTS5912_INTR_STAT_TX_ABRT */
138+
value = read_clr_tx_abrt(reg_base);
139+
}
140+
/* check SCL stuck low */
141+
if (intr_stat.bits.scl_stuck_low) {
142+
dw->state |= I2C_DW_SCL_STUCK;
143+
LOG_ERR("SCL Stuck Low on %s", dev->name);
144+
}
145+
if (dw->state & I2C_DW_ERR_MASK) {
146+
#if CONFIG_I2C_ALLOW_NO_STOP_TRANSACTIONS
147+
dw->need_setup = true;
148+
#endif
149+
LOG_ERR("IO Fail on %s", dev->name);
150+
return -EIO;
151+
}
152+
return 0;
153+
}
154+
113155
#ifdef CONFIG_I2C_DW_LPSS_DMA
114156
void i2c_dw_enable_idma(const struct device *dev, bool enable)
115157
{
@@ -312,6 +354,10 @@ static inline void i2c_dw_data_ask(const struct device *dev)
312354

313355
write_cmd_data(data, reg_base);
314356

357+
if (i2c_dw_error_chk(dev)) {
358+
return;
359+
}
360+
315361
dw->rx_pending++;
316362
dw->request_bytes--;
317363
cnt--;
@@ -340,6 +386,10 @@ static void i2c_dw_data_read(const struct device *dev)
340386
if (dw->xfr_len == 0U) {
341387
break;
342388
}
389+
390+
if (i2c_dw_error_chk(dev)) {
391+
return;
392+
}
343393
}
344394
#endif
345395
/* Nothing to receive anymore */
@@ -390,6 +440,10 @@ static int i2c_dw_data_send(const struct device *dev)
390440
if (test_bit_intr_stat_tx_abrt(reg_base)) {
391441
return -EIO;
392442
}
443+
444+
if (i2c_dw_error_chk(dev)) {
445+
return -EIO;
446+
}
393447
}
394448

395449
return 0;
@@ -464,6 +518,7 @@ static void i2c_dw_isr(const struct device *port)
464518
DW_INTR_STAT_RX_UNDER | DW_INTR_STAT_SCL_STUCK_LOW) &
465519
intr_stat.raw) {
466520
dw->state = I2C_DW_CMD_ERROR;
521+
i2c_dw_error_chk(port);
467522
#if CONFIG_I2C_ALLOW_NO_STOP_TRANSACTIONS
468523
dw->need_setup = true;
469524
#endif
@@ -776,7 +831,7 @@ static int i2c_dw_transfer(const struct device *dev, struct i2c_msg *msgs, uint8
776831
* not execute PM policies that would turn off this ip block, causing an
777832
* ongoing hw transaction to be left in an inconsistent state.
778833
* Note : This is just a sample to show a possible use of the API, it is
779-
* upto the driver expert to see, if he actually needs it here, or
834+
* up to the driver expert to see, if he actually needs it here, or
780835
* somewhere else, or not needed as the driver's suspend()/resume()
781836
* can handle everything
782837
*/

0 commit comments

Comments
 (0)