@@ -110,6 +110,48 @@ int i2c_dw_recovery_bus(const struct device *dev)
110
110
return ret ;
111
111
}
112
112
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
+
113
155
#ifdef CONFIG_I2C_DW_LPSS_DMA
114
156
void i2c_dw_enable_idma (const struct device * dev , bool enable )
115
157
{
@@ -312,6 +354,10 @@ static inline void i2c_dw_data_ask(const struct device *dev)
312
354
313
355
write_cmd_data (data , reg_base );
314
356
357
+ if (i2c_dw_error_chk (dev )) {
358
+ return ;
359
+ }
360
+
315
361
dw -> rx_pending ++ ;
316
362
dw -> request_bytes -- ;
317
363
cnt -- ;
@@ -340,6 +386,10 @@ static void i2c_dw_data_read(const struct device *dev)
340
386
if (dw -> xfr_len == 0U ) {
341
387
break ;
342
388
}
389
+
390
+ if (i2c_dw_error_chk (dev )) {
391
+ return ;
392
+ }
343
393
}
344
394
#endif
345
395
/* Nothing to receive anymore */
@@ -390,6 +440,10 @@ static int i2c_dw_data_send(const struct device *dev)
390
440
if (test_bit_intr_stat_tx_abrt (reg_base )) {
391
441
return - EIO ;
392
442
}
443
+
444
+ if (i2c_dw_error_chk (dev )) {
445
+ return - EIO ;
446
+ }
393
447
}
394
448
395
449
return 0 ;
@@ -464,6 +518,7 @@ static void i2c_dw_isr(const struct device *port)
464
518
DW_INTR_STAT_RX_UNDER | DW_INTR_STAT_SCL_STUCK_LOW ) &
465
519
intr_stat .raw ) {
466
520
dw -> state = I2C_DW_CMD_ERROR ;
521
+ i2c_dw_error_chk (port );
467
522
#if CONFIG_I2C_ALLOW_NO_STOP_TRANSACTIONS
468
523
dw -> need_setup = true;
469
524
#endif
@@ -776,7 +831,7 @@ static int i2c_dw_transfer(const struct device *dev, struct i2c_msg *msgs, uint8
776
831
* not execute PM policies that would turn off this ip block, causing an
777
832
* ongoing hw transaction to be left in an inconsistent state.
778
833
* 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
780
835
* somewhere else, or not needed as the driver's suspend()/resume()
781
836
* can handle everything
782
837
*/
0 commit comments