108
108
#define ASPEED_I2CD_S_TX_CMD BIT(2)
109
109
#define ASPEED_I2CD_M_TX_CMD BIT(1)
110
110
#define ASPEED_I2CD_M_START_CMD BIT(0)
111
+ #define ASPEED_I2CD_MASTER_CMDS_MASK \
112
+ (ASPEED_I2CD_M_STOP_CMD | \
113
+ ASPEED_I2CD_M_S_RX_CMD_LAST | \
114
+ ASPEED_I2CD_M_RX_CMD | \
115
+ ASPEED_I2CD_M_TX_CMD | \
116
+ ASPEED_I2CD_M_START_CMD)
111
117
112
118
/* 0x18 : I2CD Slave Device Address Register */
113
119
#define ASPEED_I2CD_DEV_ADDR_MASK GENMASK(6, 0)
@@ -336,18 +342,19 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus)
336
342
struct i2c_msg * msg = & bus -> msgs [bus -> msgs_index ];
337
343
u8 slave_addr = i2c_8bit_addr_from_msg (msg );
338
344
339
- bus -> master_state = ASPEED_I2C_MASTER_START ;
340
-
341
345
#if IS_ENABLED (CONFIG_I2C_SLAVE )
342
346
/*
343
347
* If it's requested in the middle of a slave session, set the master
344
348
* state to 'pending' then H/W will continue handling this master
345
349
* command when the bus comes back to the idle state.
346
350
*/
347
- if (bus -> slave_state != ASPEED_I2C_SLAVE_INACTIVE )
351
+ if (bus -> slave_state != ASPEED_I2C_SLAVE_INACTIVE ) {
348
352
bus -> master_state = ASPEED_I2C_MASTER_PENDING ;
353
+ return ;
354
+ }
349
355
#endif /* CONFIG_I2C_SLAVE */
350
356
357
+ bus -> master_state = ASPEED_I2C_MASTER_START ;
351
358
bus -> buf_index = 0 ;
352
359
353
360
if (msg -> flags & I2C_M_RD ) {
@@ -422,20 +429,6 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
422
429
}
423
430
}
424
431
425
- #if IS_ENABLED (CONFIG_I2C_SLAVE )
426
- /*
427
- * A pending master command will be started by H/W when the bus comes
428
- * back to idle state after completing a slave operation so change the
429
- * master state from 'pending' to 'start' at here if slave is inactive.
430
- */
431
- if (bus -> master_state == ASPEED_I2C_MASTER_PENDING ) {
432
- if (bus -> slave_state != ASPEED_I2C_SLAVE_INACTIVE )
433
- goto out_no_complete ;
434
-
435
- bus -> master_state = ASPEED_I2C_MASTER_START ;
436
- }
437
- #endif /* CONFIG_I2C_SLAVE */
438
-
439
432
/* Master is not currently active, irq was for someone else. */
440
433
if (bus -> master_state == ASPEED_I2C_MASTER_INACTIVE ||
441
434
bus -> master_state == ASPEED_I2C_MASTER_PENDING )
@@ -462,11 +455,15 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status)
462
455
#if IS_ENABLED (CONFIG_I2C_SLAVE )
463
456
/*
464
457
* If a peer master starts a xfer immediately after it queues a
465
- * master command, change its state to 'pending' then H/W will
466
- * continue the queued master xfer just after completing the
467
- * slave mode session.
458
+ * master command, clear the queued master command and change
459
+ * its state to 'pending'. To simplify handling of pending
460
+ * cases, it uses S/W solution instead of H/W command queue
461
+ * handling.
468
462
*/
469
463
if (unlikely (irq_status & ASPEED_I2CD_INTR_SLAVE_MATCH )) {
464
+ writel (readl (bus -> base + ASPEED_I2C_CMD_REG ) &
465
+ ~ASPEED_I2CD_MASTER_CMDS_MASK ,
466
+ bus -> base + ASPEED_I2C_CMD_REG );
470
467
bus -> master_state = ASPEED_I2C_MASTER_PENDING ;
471
468
dev_dbg (bus -> dev ,
472
469
"master goes pending due to a slave start\n" );
@@ -629,6 +626,14 @@ static irqreturn_t aspeed_i2c_bus_irq(int irq, void *dev_id)
629
626
irq_handled |= aspeed_i2c_master_irq (bus ,
630
627
irq_remaining );
631
628
}
629
+
630
+ /*
631
+ * Start a pending master command at here if a slave operation is
632
+ * completed.
633
+ */
634
+ if (bus -> master_state == ASPEED_I2C_MASTER_PENDING &&
635
+ bus -> slave_state == ASPEED_I2C_SLAVE_INACTIVE )
636
+ aspeed_i2c_do_start (bus );
632
637
#else
633
638
irq_handled = aspeed_i2c_master_irq (bus , irq_remaining );
634
639
#endif /* CONFIG_I2C_SLAVE */
@@ -691,6 +696,15 @@ static int aspeed_i2c_master_xfer(struct i2c_adapter *adap,
691
696
ASPEED_I2CD_BUS_BUSY_STS ))
692
697
aspeed_i2c_recover_bus (bus );
693
698
699
+ /*
700
+ * If timed out and the state is still pending, drop the pending
701
+ * master command.
702
+ */
703
+ spin_lock_irqsave (& bus -> lock , flags );
704
+ if (bus -> master_state == ASPEED_I2C_MASTER_PENDING )
705
+ bus -> master_state = ASPEED_I2C_MASTER_INACTIVE ;
706
+ spin_unlock_irqrestore (& bus -> lock , flags );
707
+
694
708
return - ETIMEDOUT ;
695
709
}
696
710
0 commit comments