enum aspeed_i2c_master_state {
        ASPEED_I2C_MASTER_INACTIVE,
+       ASPEED_I2C_MASTER_PENDING,
        ASPEED_I2C_MASTER_START,
        ASPEED_I2C_MASTER_TX_FIRST,
        ASPEED_I2C_MASTER_TX,
 };
 
 enum aspeed_i2c_slave_state {
-       ASPEED_I2C_SLAVE_STOP,
+       ASPEED_I2C_SLAVE_INACTIVE,
        ASPEED_I2C_SLAVE_START,
        ASPEED_I2C_SLAVE_READ_REQUESTED,
        ASPEED_I2C_SLAVE_READ_PROCESSED,
        ASPEED_I2C_SLAVE_WRITE_REQUESTED,
        ASPEED_I2C_SLAVE_WRITE_RECEIVED,
+       ASPEED_I2C_SLAVE_STOP,
 };
 
 struct aspeed_i2c_bus {
        int                             cmd_err;
        /* Protected only by i2c_lock_bus */
        int                             master_xfer_result;
+       /* Multi-master */
+       bool                            multi_master;
 #if IS_ENABLED(CONFIG_I2C_SLAVE)
        struct i2c_client               *slave;
        enum aspeed_i2c_slave_state     slave_state;
        }
 
        /* Slave is not currently active, irq was for someone else. */
-       if (bus->slave_state == ASPEED_I2C_SLAVE_STOP)
+       if (bus->slave_state == ASPEED_I2C_SLAVE_INACTIVE)
                return irq_handled;
 
        dev_dbg(bus->dev, "slave irq status 0x%08x, cmd 0x%08x\n",
                irq_handled |= ASPEED_I2CD_INTR_NORMAL_STOP;
                bus->slave_state = ASPEED_I2C_SLAVE_STOP;
        }
-       if (irq_status & ASPEED_I2CD_INTR_TX_NAK) {
+       if (irq_status & ASPEED_I2CD_INTR_TX_NAK &&
+           bus->slave_state == ASPEED_I2C_SLAVE_READ_PROCESSED) {
                irq_handled |= ASPEED_I2CD_INTR_TX_NAK;
                bus->slave_state = ASPEED_I2C_SLAVE_STOP;
        }
-       if (irq_status & ASPEED_I2CD_INTR_TX_ACK)
-               irq_handled |= ASPEED_I2CD_INTR_TX_ACK;
 
        switch (bus->slave_state) {
        case ASPEED_I2C_SLAVE_READ_REQUESTED:
-               if (irq_status & ASPEED_I2CD_INTR_TX_ACK)
+               if (unlikely(irq_status & ASPEED_I2CD_INTR_TX_ACK))
                        dev_err(bus->dev, "Unexpected ACK on read request.\n");
                bus->slave_state = ASPEED_I2C_SLAVE_READ_PROCESSED;
                i2c_slave_event(slave, I2C_SLAVE_READ_REQUESTED, &value);
                writel(ASPEED_I2CD_S_TX_CMD, bus->base + ASPEED_I2C_CMD_REG);
                break;
        case ASPEED_I2C_SLAVE_READ_PROCESSED:
-               if (!(irq_status & ASPEED_I2CD_INTR_TX_ACK))
+               if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
                        dev_err(bus->dev,
                                "Expected ACK after processed read.\n");
+                       break;
+               }
+               irq_handled |= ASPEED_I2CD_INTR_TX_ACK;
                i2c_slave_event(slave, I2C_SLAVE_READ_PROCESSED, &value);
                writel(value, bus->base + ASPEED_I2C_BYTE_BUF_REG);
                writel(ASPEED_I2CD_S_TX_CMD, bus->base + ASPEED_I2C_CMD_REG);
                break;
        case ASPEED_I2C_SLAVE_STOP:
                i2c_slave_event(slave, I2C_SLAVE_STOP, &value);
+               bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE;
+               break;
+       case ASPEED_I2C_SLAVE_START:
+               /* Slave was just started. Waiting for the next event. */;
                break;
        default:
-               dev_err(bus->dev, "unhandled slave_state: %d\n",
+               dev_err(bus->dev, "unknown slave_state: %d\n",
                        bus->slave_state);
+               bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE;
                break;
        }
 
        u8 slave_addr = i2c_8bit_addr_from_msg(msg);
 
        bus->master_state = ASPEED_I2C_MASTER_START;
+
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+       /*
+        * If it's requested in the middle of a slave session, set the master
+        * state to 'pending' then H/W will continue handling this master
+        * command when the bus comes back to the idle state.
+        */
+       if (bus->slave_state != ASPEED_I2C_SLAVE_INACTIVE)
+               bus->master_state = ASPEED_I2C_MASTER_PENDING;
+#endif /* CONFIG_I2C_SLAVE */
+
        bus->buf_index = 0;
 
        if (msg->flags & I2C_M_RD) {
                bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
                irq_handled |= ASPEED_I2CD_INTR_BUS_RECOVER_DONE;
                goto out_complete;
-       } else {
-               /* Master is not currently active, irq was for someone else. */
-               if (bus->master_state == ASPEED_I2C_MASTER_INACTIVE)
-                       goto out_no_complete;
        }
 
        /*
        if (ret) {
                dev_dbg(bus->dev, "received error interrupt: 0x%08x\n",
                        irq_status);
-               bus->cmd_err = ret;
-               bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
                irq_handled |= (irq_status & ASPEED_I2CD_INTR_MASTER_ERRORS);
-               goto out_complete;
+               if (bus->master_state != ASPEED_I2C_MASTER_INACTIVE) {
+                       bus->cmd_err = ret;
+                       bus->master_state = ASPEED_I2C_MASTER_INACTIVE;
+                       goto out_complete;
+               }
+       }
+
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+       /*
+        * A pending master command will be started by H/W when the bus comes
+        * back to idle state after completing a slave operation so change the
+        * master state from 'pending' to 'start' at here if slave is inactive.
+        */
+       if (bus->master_state == ASPEED_I2C_MASTER_PENDING) {
+               if (bus->slave_state != ASPEED_I2C_SLAVE_INACTIVE)
+                       goto out_no_complete;
+
+               bus->master_state = ASPEED_I2C_MASTER_START;
        }
+#endif /* CONFIG_I2C_SLAVE */
+
+       /* Master is not currently active, irq was for someone else. */
+       if (bus->master_state == ASPEED_I2C_MASTER_INACTIVE ||
+           bus->master_state == ASPEED_I2C_MASTER_PENDING)
+               goto out_no_complete;
 
        /* We are in an invalid state; reset bus to a known state. */
        if (!bus->msgs) {
         * then update the state and handle the new state below.
         */
        if (bus->master_state == ASPEED_I2C_MASTER_START) {
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
+               /*
+                * If a peer master starts a xfer immediately after it queues a
+                * master command, change its state to 'pending' then H/W will
+                * continue the queued master xfer just after completing the
+                * slave mode session.
+                */
+               if (unlikely(irq_status & ASPEED_I2CD_INTR_SLAVE_MATCH)) {
+                       bus->master_state = ASPEED_I2C_MASTER_PENDING;
+                       dev_dbg(bus->dev,
+                               "master goes pending due to a slave start\n");
+                       goto out_no_complete;
+               }
+#endif /* CONFIG_I2C_SLAVE */
                if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_ACK))) {
                        if (unlikely(!(irq_status & ASPEED_I2CD_INTR_TX_NAK))) {
                                bus->cmd_err = -ENXIO;
         * interrupt bits. Each case needs to be handled using corresponding
         * handlers depending on the current state.
         */
-       if (bus->master_state != ASPEED_I2C_MASTER_INACTIVE) {
+       if (bus->master_state != ASPEED_I2C_MASTER_INACTIVE &&
+           bus->master_state != ASPEED_I2C_MASTER_PENDING) {
                irq_handled = aspeed_i2c_master_irq(bus, irq_remaining);
                irq_remaining &= ~irq_handled;
                if (irq_remaining)
 {
        struct aspeed_i2c_bus *bus = i2c_get_adapdata(adap);
        unsigned long time_left, flags;
-       int ret = 0;
 
        spin_lock_irqsave(&bus->lock, flags);
        bus->cmd_err = 0;
 
-       /* If bus is busy, attempt recovery. We assume a single master
-        * environment.
-        */
-       if (readl(bus->base + ASPEED_I2C_CMD_REG) & ASPEED_I2CD_BUS_BUSY_STS) {
+       /* If bus is busy in a single master environment, attempt recovery. */
+       if (!bus->multi_master &&
+           (readl(bus->base + ASPEED_I2C_CMD_REG) &
+            ASPEED_I2CD_BUS_BUSY_STS)) {
+               int ret;
+
                spin_unlock_irqrestore(&bus->lock, flags);
                ret = aspeed_i2c_recover_bus(bus);
                if (ret)
        time_left = wait_for_completion_timeout(&bus->cmd_complete,
                                                bus->adap.timeout);
 
-       if (time_left == 0)
+       if (time_left == 0) {
+               /*
+                * If timed out and bus is still busy in a multi master
+                * environment, attempt recovery at here.
+                */
+               if (bus->multi_master &&
+                   (readl(bus->base + ASPEED_I2C_CMD_REG) &
+                    ASPEED_I2CD_BUS_BUSY_STS))
+                       aspeed_i2c_recover_bus(bus);
+
                return -ETIMEDOUT;
-       else
-               return bus->master_xfer_result;
+       }
+
+       return bus->master_xfer_result;
 }
 
 static u32 aspeed_i2c_functionality(struct i2c_adapter *adap)
        __aspeed_i2c_reg_slave(bus, client->addr);
 
        bus->slave = client;
-       bus->slave_state = ASPEED_I2C_SLAVE_STOP;
+       bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE;
        spin_unlock_irqrestore(&bus->lock, flags);
 
        return 0;
        if (ret < 0)
                return ret;
 
-       if (!of_property_read_bool(pdev->dev.of_node, "multi-master"))
+       if (of_property_read_bool(pdev->dev.of_node, "multi-master"))
+               bus->multi_master = true;
+       else
                fun_ctrl_reg |= ASPEED_I2CD_MULTI_MASTER_DIS;
 
        /* Enable Master Mode */