mvebu: puzzle-mcu: add mcu write retry function
authorIan Chang <ianchang@ieiworld.com>
Tue, 11 Apr 2023 08:07:24 +0000 (16:07 +0800)
committerDaniel Golle <daniel@makrotopia.org>
Thu, 13 Apr 2023 00:07:54 +0000 (01:07 +0100)
Avoid MCU getting "command reply receive timed out" message when LED
configuration setting trigger function is enabled in heartbeat mode.

Signed-off-by: Ian Chang <ianchang@ieiworld.com>
target/linux/mvebu/patches-5.10/911-drivers-leds-wt61p803-puzzle-mcu-retry.patch [new file with mode: 0644]
target/linux/mvebu/patches-5.15/911-drivers-leds-wt61p803-puzzle-mcu-retry.patch [new file with mode: 0644]

diff --git a/target/linux/mvebu/patches-5.10/911-drivers-leds-wt61p803-puzzle-mcu-retry.patch b/target/linux/mvebu/patches-5.10/911-drivers-leds-wt61p803-puzzle-mcu-retry.patch
new file mode 100644 (file)
index 0000000..2f0b178
--- /dev/null
@@ -0,0 +1,63 @@
+--- a/drivers/mfd/iei-wt61p803-puzzle.c
++++ b/drivers/mfd/iei-wt61p803-puzzle.c
+@@ -241,6 +241,7 @@ int iei_wt61p803_puzzle_write_command(st
+ {
+       struct device *dev = &mcu->serdev->dev;
+       int ret;
++      int retries;
+       if (size <= 1 || size > IEI_WT61P803_PUZZLE_MAX_COMMAND_LENGTH)
+               return -EINVAL;
+@@ -252,24 +253,36 @@ int iei_wt61p803_puzzle_write_command(st
+       print_hex_dump_debug("puzzle-mcu tx: ", DUMP_PREFIX_NONE,
+                            16, 1, cmd, size, false);
++      retries = 3;
+       /* Initialize reply struct */
+-      reinit_completion(&mcu->reply->received);
+-      mcu->reply->size = 0;
+-      usleep_range(2000, 10000);
+-      serdev_device_write_flush(mcu->serdev);
+-      ret = serdev_device_write_buf(mcu->serdev, cmd, size);
+-      if (ret < 0)
+-              goto exit;
+-
+-      serdev_device_wait_until_sent(mcu->serdev, IEI_WT61P803_PUZZLE_GENERAL_TIMEOUT);
+-      ret = wait_for_completion_timeout(&mcu->reply->received,
+-                                        IEI_WT61P803_PUZZLE_GENERAL_TIMEOUT);
+-      if (ret == 0) {
+-              dev_err(dev, "Command reply receive timeout\n");
+-              ret = -ETIMEDOUT;
+-              goto exit;
++      while (retries) {
++              reinit_completion(&mcu->reply->received);
++              mcu->reply->size = 0;
++              usleep_range(2000, 10000);
++              serdev_device_write_flush(mcu->serdev);
++              ret = serdev_device_write_buf(mcu->serdev, cmd, size);
++              if (ret < 0)
++                      goto exit;
++
++              serdev_device_wait_until_sent(mcu->serdev, IEI_WT61P803_PUZZLE_GENERAL_TIMEOUT);
++              ret = wait_for_completion_timeout(&mcu->reply->received,
++                                                IEI_WT61P803_PUZZLE_GENERAL_TIMEOUT);
++              retries--;
++              if (ret == 0) {
++                      if (retries == 0) {
++                              dev_err(dev, "Command reply receive timeout\n");
++                              ret = -ETIMEDOUT;
++                              goto exit;
++                      }
++              }
++              else {
++                      if (mcu->reply->data[0] == IEI_WT61P803_PUZZLE_CMD_HEADER_START &&
++                              mcu->reply->data[1] == IEI_WT61P803_PUZZLE_CMD_RESPONSE_OK &&
++                              mcu->reply->data[2] == IEI_WT61P803_PUZZLE_CHECKSUM_RESPONSE_OK) {
++                              break;
++                      }
++              }
+       }
+-
+       *reply_size = mcu->reply->size;
+       /* Copy the received data, as it will not be available after a new frame is received */
+       memcpy(reply_data, mcu->reply->data, mcu->reply->size);
diff --git a/target/linux/mvebu/patches-5.15/911-drivers-leds-wt61p803-puzzle-mcu-retry.patch b/target/linux/mvebu/patches-5.15/911-drivers-leds-wt61p803-puzzle-mcu-retry.patch
new file mode 100644 (file)
index 0000000..2f0b178
--- /dev/null
@@ -0,0 +1,63 @@
+--- a/drivers/mfd/iei-wt61p803-puzzle.c
++++ b/drivers/mfd/iei-wt61p803-puzzle.c
+@@ -241,6 +241,7 @@ int iei_wt61p803_puzzle_write_command(st
+ {
+       struct device *dev = &mcu->serdev->dev;
+       int ret;
++      int retries;
+       if (size <= 1 || size > IEI_WT61P803_PUZZLE_MAX_COMMAND_LENGTH)
+               return -EINVAL;
+@@ -252,24 +253,36 @@ int iei_wt61p803_puzzle_write_command(st
+       print_hex_dump_debug("puzzle-mcu tx: ", DUMP_PREFIX_NONE,
+                            16, 1, cmd, size, false);
++      retries = 3;
+       /* Initialize reply struct */
+-      reinit_completion(&mcu->reply->received);
+-      mcu->reply->size = 0;
+-      usleep_range(2000, 10000);
+-      serdev_device_write_flush(mcu->serdev);
+-      ret = serdev_device_write_buf(mcu->serdev, cmd, size);
+-      if (ret < 0)
+-              goto exit;
+-
+-      serdev_device_wait_until_sent(mcu->serdev, IEI_WT61P803_PUZZLE_GENERAL_TIMEOUT);
+-      ret = wait_for_completion_timeout(&mcu->reply->received,
+-                                        IEI_WT61P803_PUZZLE_GENERAL_TIMEOUT);
+-      if (ret == 0) {
+-              dev_err(dev, "Command reply receive timeout\n");
+-              ret = -ETIMEDOUT;
+-              goto exit;
++      while (retries) {
++              reinit_completion(&mcu->reply->received);
++              mcu->reply->size = 0;
++              usleep_range(2000, 10000);
++              serdev_device_write_flush(mcu->serdev);
++              ret = serdev_device_write_buf(mcu->serdev, cmd, size);
++              if (ret < 0)
++                      goto exit;
++
++              serdev_device_wait_until_sent(mcu->serdev, IEI_WT61P803_PUZZLE_GENERAL_TIMEOUT);
++              ret = wait_for_completion_timeout(&mcu->reply->received,
++                                                IEI_WT61P803_PUZZLE_GENERAL_TIMEOUT);
++              retries--;
++              if (ret == 0) {
++                      if (retries == 0) {
++                              dev_err(dev, "Command reply receive timeout\n");
++                              ret = -ETIMEDOUT;
++                              goto exit;
++                      }
++              }
++              else {
++                      if (mcu->reply->data[0] == IEI_WT61P803_PUZZLE_CMD_HEADER_START &&
++                              mcu->reply->data[1] == IEI_WT61P803_PUZZLE_CMD_RESPONSE_OK &&
++                              mcu->reply->data[2] == IEI_WT61P803_PUZZLE_CHECKSUM_RESPONSE_OK) {
++                              break;
++                      }
++              }
+       }
+-
+       *reply_size = mcu->reply->size;
+       /* Copy the received data, as it will not be available after a new frame is received */
+       memcpy(reply_data, mcu->reply->data, mcu->reply->size);