| @@ -108,6 +108,12 @@ · 107 unmodified lines |
| 108 | #define ASPEED_I2CD_S_TX_CMD BIT(2) | 108 | #define ASPEED_I2CD_S_TX_CMD BIT(2) |
| 109 | #define ASPEED_I2CD_M_TX_CMD BIT(1) | 109 | #define ASPEED_I2CD_M_TX_CMD BIT(1) |
| 110 | #define ASPEED_I2CD_M_START_CMD BIT(0) | 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 | /* 0x18 : I2CD Slave Device Address Register */ | 118 | /* 0x18 : I2CD Slave Device Address Register */ |
| 113 | #define ASPEED_I2CD_DEV_ADDR_MASK GENMASK(6, 0) | 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) · 222 unmodified lines |
| 336 | struct i2c_msg *msg = &bus->msgs[bus->msgs_index]; | 342 | struct i2c_msg *msg = &bus->msgs[bus->msgs_index]; |
| 337 | u8 slave_addr = i2c_8bit_addr_from_msg(msg); | 343 | u8 slave_addr = i2c_8bit_addr_from_msg(msg); |
| 338 | | 344 | |
| 339 | bus->master_state = ASPEED_I2C_MASTER_START; | | |
| 340 | | | |
| 341 | #if IS_ENABLED(CONFIG_I2C_SLAVE) | 345 | #if IS_ENABLED(CONFIG_I2C_SLAVE) |
| 342 | /* | 346 | /* |
| 343 | * If it's requested in the middle of a slave session, set the master | 347 | * If it's requested in the middle of a slave session, set the master |
| 344 | * state to 'pending' then H/W will continue handling this master | 348 | * state to 'pending' then H/W will continue handling this master |
| 345 | * command when the bus comes back to the idle state. | 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 | bus->master_state = ASPEED_I2C_MASTER_PENDING; | 352 | bus->master_state = ASPEED_I2C_MASTER_PENDING; |
| | 353 | return; |
| | 354 | } |
| 349 | #endif /* CONFIG_I2C_SLAVE */ | 355 | #endif /* CONFIG_I2C_SLAVE */ |
| 350 | | 356 | |
| | 357 | bus->master_state = ASPEED_I2C_MASTER_START; |
| 351 | bus->buf_index = 0; | 358 | bus->buf_index = 0; |
| 352 | | 359 | |
| 353 | if (msg->flags & I2C_M_RD) { | 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) · 68 unmodified lines |
| 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 | /* Master is not currently active, irq was for someone else. */ | 432 | /* Master is not currently active, irq was for someone else. */ |
| 440 | if (bus->master_state == ASPEED_I2C_MASTER_INACTIVE || | 433 | if (bus->master_state == ASPEED_I2C_MASTER_INACTIVE || |
| 441 | bus->master_state == ASPEED_I2C_MASTER_PENDING) | 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) · 20 unmodified lines |
| 462 | #if IS_ENABLED(CONFIG_I2C_SLAVE) | 455 | #if IS_ENABLED(CONFIG_I2C_SLAVE) |
| 463 | /* | 456 | /* |
| 464 | * If a peer master starts a xfer immediately after it queues a | 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 | 458 | * master command, clear the queued master command and change |
| 466 | * continue the queued master xfer just after completing the | 459 | * its state to 'pending'. To simplify handling of pending |
| 467 | * slave mode session. | 460 | * cases, it uses S/W solution instead of H/W command queue |
| | 461 | * handling. |
| 468 | */ | 462 | */ |
| 469 | if (unlikely(irq_status & ASPEED_I2CD_INTR_SLAVE_MATCH)) { | 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 | bus->master_state = ASPEED_I2C_MASTER_PENDING; | 467 | bus->master_state = ASPEED_I2C_MASTER_PENDING; |
| 471 | dev_dbg(bus->dev, | 468 | dev_dbg(bus->dev, |
| 472 | "master goes pending due to a slave start\n"); | 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) · 156 unmodified lines |
| 629 | irq_handled |= aspeed_i2c_master_irq(bus, | 626 | irq_handled |= aspeed_i2c_master_irq(bus, |
| 630 | irq_remaining); | 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 | #else | 637 | #else |
| 633 | irq_handled = aspeed_i2c_master_irq(bus, irq_remaining); | 638 | irq_handled = aspeed_i2c_master_irq(bus, irq_remaining); |
| 634 | #endif /* CONFIG_I2C_SLAVE */ | 639 | #endif /* CONFIG_I2C_SLAVE */ |
| @@ -691,6 +696,15 @@ static int aspeed_i2c_master_xfer(struct i2c_adapter *adap, · 56 unmodified lines |
| 691 | ASPEED_I2CD_BUS_BUSY_STS)) | 696 | ASPEED_I2CD_BUS_BUSY_STS)) |
| 692 | aspeed_i2c_recover_bus(bus); | 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 | return -ETIMEDOUT; | 708 | return -ETIMEDOUT; |
| 695 | } | 709 | } |
| 696 | | 710 | |