diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index bb048e655be7..3ae74160001d 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -4,10 +4,12 @@
  *
  * Author: Mark A. Greer <mgreer@mvista.com>
  *
- * 2005 (c) MontaVista, Software, Inc.  This file is licensed under
- * the terms of the GNU General Public License version 2.  This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
+ * 2005 (c) MontaVista, Software, Inc.
+ * Copyright (c) 2024 Turing Machines, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License v2.
+ * This program is licensed "as is" without any warranty of any kind, whether
+ * express or implied.
  */
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -86,12 +88,24 @@
 enum mv64xxx_i2c_state {
 	MV64XXX_I2C_STATE_INVALID,
 	MV64XXX_I2C_STATE_IDLE,
-	MV64XXX_I2C_STATE_WAITING_FOR_START_COND,
-	MV64XXX_I2C_STATE_WAITING_FOR_RESTART,
-	MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK,
-	MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK,
-	MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK,
-	MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA,
+	MV64XXX_I2C_STATE_START,
+	MV64XXX_I2C_STATE_RESTART,
+	MV64XXX_I2C_STATE_SEND_ADDR_1,
+	MV64XXX_I2C_STATE_SEND_ADDR_2,
+	MV64XXX_I2C_STATE_WRITE,
+	MV64XXX_I2C_STATE_READ,
+};
+
+/* Driver events */
+enum mv64xxx_i2c_event {
+	MV64XXX_I2C_EVENT_INVALID,
+	MV64XXX_I2C_EVENT_STARTED,
+	MV64XXX_I2C_EVENT_ADDR_ACK,
+	MV64XXX_I2C_EVENT_ADDR_NO_ACK,
+	MV64XXX_I2C_EVENT_WR_ACK,
+	MV64XXX_I2C_EVENT_WR_NO_ACK,
+	MV64XXX_I2C_EVENT_RD_ACKED,
+	MV64XXX_I2C_EVENT_RD_UNACKED,
 };
 
 /* Driver actions */
@@ -232,9 +246,73 @@ mv64xxx_i2c_hw_init(struct mv64xxx_i2c_data *drv_data)
 	drv_data->state = MV64XXX_I2C_STATE_IDLE;
 }
 
+static enum mv64xxx_i2c_event
+mv64xxx_i2c_decode_status(struct mv64xxx_i2c_data *drv_data, u32 status)
+{
+	/* Decode status to event (state-driven; catches unexpected status) */
+	switch (drv_data->state) {
+	case MV64XXX_I2C_STATE_RESTART:
+	case MV64XXX_I2C_STATE_START:
+		if (status == MV64XXX_I2C_STATUS_MAST_START ||
+		    status == MV64XXX_I2C_STATUS_MAST_REPEAT_START)
+			return MV64XXX_I2C_EVENT_STARTED;
+		return MV64XXX_I2C_EVENT_INVALID;
+
+	case MV64XXX_I2C_STATE_SEND_ADDR_1:
+		if (drv_data->msg->flags & I2C_M_RD) {
+			if (status == MV64XXX_I2C_STATUS_MAST_RD_ADDR_ACK)
+				return MV64XXX_I2C_EVENT_ADDR_ACK;
+			else if (status == MV64XXX_I2C_STATUS_MAST_RD_ADDR_NO_ACK)
+				return MV64XXX_I2C_EVENT_ADDR_NO_ACK;
+		} else {
+			if (status == MV64XXX_I2C_STATUS_MAST_WR_ADDR_ACK)
+				return MV64XXX_I2C_EVENT_ADDR_ACK;
+			else if (status == MV64XXX_I2C_STATUS_MAST_WR_ADDR_NO_ACK)
+				return MV64XXX_I2C_EVENT_ADDR_NO_ACK;
+		}
+		return MV64XXX_I2C_EVENT_INVALID;
+
+	case MV64XXX_I2C_STATE_SEND_ADDR_2:
+		if (drv_data->msg->flags & I2C_M_RD) {
+			if (status == MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_ACK)
+				return MV64XXX_I2C_EVENT_ADDR_ACK;
+			else if (status == MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_NO_ACK)
+				return MV64XXX_I2C_EVENT_ADDR_NO_ACK;
+		} else {
+			if (status == MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_ACK)
+				return MV64XXX_I2C_EVENT_ADDR_ACK;
+			else if (status == MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_NO_ACK)
+				return MV64XXX_I2C_EVENT_ADDR_NO_ACK;
+		}
+		return MV64XXX_I2C_EVENT_INVALID;
+
+	case MV64XXX_I2C_STATE_WRITE:
+		if (status == MV64XXX_I2C_STATUS_MAST_WR_ACK)
+			return MV64XXX_I2C_EVENT_WR_ACK;
+		else if (status == MV64XXX_I2C_STATUS_MAST_WR_NO_ACK)
+			return MV64XXX_I2C_EVENT_ADDR_NO_ACK;
+		return MV64XXX_I2C_EVENT_INVALID;
+
+	case MV64XXX_I2C_STATE_READ:
+		if (status == MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK)
+			return MV64XXX_I2C_EVENT_RD_ACKED;
+		else if (status == MV64XXX_I2C_STATUS_MAST_RD_DATA_NO_ACK)
+			return MV64XXX_I2C_EVENT_RD_UNACKED;
+		return MV64XXX_I2C_EVENT_INVALID;
+
+	default:
+		return MV64XXX_I2C_EVENT_INVALID;
+	}
+}
+
 static void
 mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status)
 {
+	enum mv64xxx_i2c_event event;
+	enum mv64xxx_i2c_state prev_state = drv_data->state;
+
+	drv_data->action = MV64XXX_I2C_ACTION_INVALID;
+
 	/*
 	 * If state is idle, then this is likely the remnants of an old
 	 * operation that driver has given up on or the user has killed.
@@ -245,99 +323,121 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status)
 		return;
 	}
 
-	/* The status from the ctlr [mostly] tells us what to do next */
-	switch (status) {
-	/* Start condition interrupt */
-	case MV64XXX_I2C_STATUS_MAST_START: /* 0x08 */
-	case MV64XXX_I2C_STATUS_MAST_REPEAT_START: /* 0x10 */
-		drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_1;
-		drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK;
+	/*
+	 * The FSM is broken into 3 parts:
+	 * 1) Decode `status` to determine the underlying hardware event
+	 * 2) Handle hardware event driven state transitions
+	 * 3) Perform internal state transitions and action emission
+	 */
+	event = mv64xxx_i2c_decode_status(drv_data, status);
+
+	/* Handle event; determine state transition */
+	switch (event) {
+	case MV64XXX_I2C_EVENT_STARTED:
+		drv_data->state = MV64XXX_I2C_STATE_SEND_ADDR_1;
 		break;
 
-	/* Performing a write */
-	case MV64XXX_I2C_STATUS_MAST_WR_ADDR_ACK: /* 0x18 */
-		if (drv_data->msg->flags & I2C_M_TEN) {
-			drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_2;
-			drv_data->state =
-				MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK;
-			break;
-		}
-		fallthrough;
-	case MV64XXX_I2C_STATUS_MAST_WR_ADDR_2_ACK: /* 0xd0 */
-	case MV64XXX_I2C_STATUS_MAST_WR_ACK: /* 0x28 */
-		if ((drv_data->bytes_left == 0)
-				|| (drv_data->aborting
-					&& (drv_data->byte_posn != 0))) {
-			if (drv_data->send_stop || drv_data->aborting) {
-				drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
-				drv_data->state = MV64XXX_I2C_STATE_IDLE;
-			} else {
-				drv_data->action =
-					MV64XXX_I2C_ACTION_SEND_RESTART;
-				drv_data->state =
-					MV64XXX_I2C_STATE_WAITING_FOR_RESTART;
-			}
-		} else {
-			drv_data->action = MV64XXX_I2C_ACTION_SEND_DATA;
-			drv_data->state =
-				MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK;
-			drv_data->bytes_left--;
-		}
+	case MV64XXX_I2C_EVENT_ADDR_ACK:
+		if ((drv_data->state == MV64XXX_I2C_STATE_SEND_ADDR_1)
+		    && (drv_data->msg->flags & I2C_M_TEN))
+			drv_data->state = MV64XXX_I2C_STATE_SEND_ADDR_2;
+		else if (drv_data->msg->flags & I2C_M_RD)
+			drv_data->state = MV64XXX_I2C_STATE_READ;
+		else
+			drv_data->state = MV64XXX_I2C_STATE_WRITE;
 		break;
 
-	/* Performing a read */
-	case MV64XXX_I2C_STATUS_MAST_RD_ADDR_ACK: /* 40 */
-		if (drv_data->msg->flags & I2C_M_TEN) {
-			drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_2;
-			drv_data->state =
-				MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK;
-			break;
-		}
-		fallthrough;
-	case MV64XXX_I2C_STATUS_MAST_RD_ADDR_2_ACK: /* 0xe0 */
-		if (drv_data->bytes_left == 0) {
-			drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
-			drv_data->state = MV64XXX_I2C_STATE_IDLE;
-			break;
-		}
-		fallthrough;
-	case MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK: /* 0x50 */
-		if (status != MV64XXX_I2C_STATUS_MAST_RD_DATA_ACK)
-			drv_data->action = MV64XXX_I2C_ACTION_CONTINUE;
-		else {
-			drv_data->action = MV64XXX_I2C_ACTION_RCV_DATA;
-			drv_data->bytes_left--;
-		}
-		drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA;
+	case MV64XXX_I2C_EVENT_ADDR_NO_ACK:
+	case MV64XXX_I2C_EVENT_WR_NO_ACK:
+		/* Doesn't seem to be a device at other end */
+		drv_data->state = MV64XXX_I2C_STATE_IDLE;
+		break;
 
-		if ((drv_data->bytes_left == 1) || drv_data->aborting)
-			drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_ACK;
+	case MV64XXX_I2C_EVENT_WR_ACK:
 		break;
 
-	case MV64XXX_I2C_STATUS_MAST_RD_DATA_NO_ACK: /* 0x58 */
-		drv_data->action = MV64XXX_I2C_ACTION_RCV_DATA_STOP;
-		drv_data->state = MV64XXX_I2C_STATE_IDLE;
+	case MV64XXX_I2C_EVENT_RD_ACKED:
+		BUG_ON(drv_data->bytes_left == 0);
 		break;
 
-	case MV64XXX_I2C_STATUS_MAST_WR_ADDR_NO_ACK: /* 0x20 */
-	case MV64XXX_I2C_STATUS_MAST_WR_NO_ACK: /* 30 */
-	case MV64XXX_I2C_STATUS_MAST_RD_ADDR_NO_ACK: /* 48 */
-		/* Doesn't seem to be a device at other end */
-		drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
-		drv_data->state = MV64XXX_I2C_STATE_IDLE;
-		drv_data->rc = -ENXIO;
+	case MV64XXX_I2C_EVENT_RD_UNACKED:
+		BUG_ON(drv_data->bytes_left != 0);
 		break;
 
+	case MV64XXX_I2C_EVENT_INVALID:
 	default:
 		dev_err(&drv_data->adapter.dev,
 			"mv64xxx_i2c_fsm: Ctlr Error -- state: 0x%x, "
-			"status: 0x%x, addr: 0x%x, flags: 0x%x\n",
-			 drv_data->state, status, drv_data->msg->addr,
+			"status: 0x%x, event: 0x%x, addr: 0x%x, flags: 0x%x\n",
+			 drv_data->state, status, event, drv_data->msg->addr,
 			 drv_data->msg->flags);
 		drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
 		mv64xxx_i2c_hw_init(drv_data);
 		i2c_recover_bus(&drv_data->adapter);
 		drv_data->rc = -EAGAIN;
+		return;
+	}
+
+	/* Internal FSM transitions and action emission */
+	switch (drv_data->state) {
+	case MV64XXX_I2C_STATE_IDLE:
+		drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
+		drv_data->rc = -ENXIO;
+		break;
+
+	case MV64XXX_I2C_STATE_SEND_ADDR_1:
+		drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_1;
+		break;
+
+	case MV64XXX_I2C_STATE_SEND_ADDR_2:
+		drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_2;
+		break;
+
+	case MV64XXX_I2C_STATE_READ:
+		if (drv_data->bytes_left == 0) {
+			if (prev_state == MV64XXX_I2C_STATE_READ)
+				drv_data->action = MV64XXX_I2C_ACTION_RCV_DATA_STOP;
+			else
+				drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
+			drv_data->state = MV64XXX_I2C_STATE_IDLE;
+		} else {
+			if (prev_state == MV64XXX_I2C_STATE_READ)
+				drv_data->action = MV64XXX_I2C_ACTION_RCV_DATA;
+			else
+				drv_data->action = MV64XXX_I2C_ACTION_CONTINUE;
+
+			/*
+			 * bytes_left counts the remaining read actions to send
+			 * to the hardware, not the remaining bytes to be
+			 * retrieved from the data register
+			 */
+			if (drv_data->aborting)
+				drv_data->bytes_left = 0;
+			else
+				drv_data->bytes_left--;
+
+			if (drv_data->bytes_left == 0)
+				drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_ACK;
+		}
+		break;
+
+	case MV64XXX_I2C_STATE_WRITE:
+		if ((drv_data->bytes_left == 0)
+		    || (drv_data->aborting && (drv_data->byte_posn != 0))) {
+			if (drv_data->send_stop || drv_data->aborting) {
+				drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP;
+				drv_data->state = MV64XXX_I2C_STATE_IDLE;
+			} else {
+				drv_data->action = MV64XXX_I2C_ACTION_SEND_RESTART;
+				drv_data->state = MV64XXX_I2C_STATE_RESTART;
+			}
+		} else {
+			drv_data->action = MV64XXX_I2C_ACTION_SEND_DATA;
+			drv_data->bytes_left--;
+		}
+		break;
+
+	default:
 	}
 }
 
@@ -611,7 +711,7 @@ mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg,
 
 	spin_lock_irqsave(&drv_data->lock, flags);
 
-	drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND;
+	drv_data->state = MV64XXX_I2C_STATE_START;
 
 	drv_data->send_stop = is_last;
 	drv_data->block = 1;
