return ret;
 }
 
-static int joycon_hid_send_sync(struct joycon_ctlr *ctlr, u8 *data, size_t len)
+static int joycon_hid_send_sync(struct joycon_ctlr *ctlr, u8 *data, size_t len,
+                               u32 timeout)
 {
        int ret;
+       int tries = 2;
 
-       ret = __joycon_hid_send(ctlr->hdev, data, len);
-       if (ret < 0) {
-               memset(ctlr->input_buf, 0, JC_MAX_RESP_SIZE);
-               return ret;
-       }
+       /*
+        * The controller occasionally seems to drop subcommands. In testing,
+        * doing one retry after a timeout appears to always work.
+        */
+       while (tries--) {
+               ret = __joycon_hid_send(ctlr->hdev, data, len);
+               if (ret < 0) {
+                       memset(ctlr->input_buf, 0, JC_MAX_RESP_SIZE);
+                       return ret;
+               }
 
-       if (!wait_event_timeout(ctlr->wait, ctlr->received_resp, HZ)) {
-               hid_dbg(ctlr->hdev, "synchronous send/receive timed out\n");
-               memset(ctlr->input_buf, 0, JC_MAX_RESP_SIZE);
-               return -ETIMEDOUT;
+               ret = wait_event_timeout(ctlr->wait, ctlr->received_resp,
+                                        timeout);
+               if (!ret) {
+                       hid_dbg(ctlr->hdev,
+                               "synchronous send/receive timed out\n");
+                       if (tries) {
+                               hid_dbg(ctlr->hdev,
+                                       "retrying sync send after timeout\n");
+                       }
+                       memset(ctlr->input_buf, 0, JC_MAX_RESP_SIZE);
+                       ret = -ETIMEDOUT;
+               } else {
+                       ret = 0;
+                       break;
+               }
        }
 
        ctlr->received_resp = false;
-       return 0;
+       return ret;
 }
 
-static int joycon_send_usb(struct joycon_ctlr *ctlr, u8 cmd)
+static int joycon_send_usb(struct joycon_ctlr *ctlr, u8 cmd, u32 timeout)
 {
        int ret;
        u8 buf[2] = {JC_OUTPUT_USB_CMD};
        buf[1] = cmd;
        ctlr->usb_ack_match = cmd;
        ctlr->msg_type = JOYCON_MSG_TYPE_USB;
-       ret = joycon_hid_send_sync(ctlr, buf, sizeof(buf));
+       ret = joycon_hid_send_sync(ctlr, buf, sizeof(buf), timeout);
        if (ret)
                hid_dbg(ctlr->hdev, "send usb command failed; ret=%d\n", ret);
        return ret;
 
 static int joycon_send_subcmd(struct joycon_ctlr *ctlr,
                              struct joycon_subcmd_request *subcmd,
-                             size_t data_len)
+                             size_t data_len, u32 timeout)
 {
        int ret;
        unsigned long flags;
        ctlr->msg_type = JOYCON_MSG_TYPE_SUBCMD;
 
        ret = joycon_hid_send_sync(ctlr, (u8 *)subcmd,
-                                  sizeof(*subcmd) + data_len);
+                                  sizeof(*subcmd) + data_len, timeout);
        if (ret < 0)
                hid_dbg(ctlr->hdev, "send subcommand failed; ret=%d\n", ret);
        else
        req->data[0] = (flash << 4) | on;
 
        hid_dbg(ctlr->hdev, "setting player leds\n");
-       return joycon_send_subcmd(ctlr, req, 1);
+       return joycon_send_subcmd(ctlr, req, 1, HZ/4);
 }
 
 static const u16 DFLT_STICK_CAL_CEN = 2000;
        data[4] = JC_CAL_DATA_SIZE;
 
        hid_dbg(ctlr->hdev, "requesting cal data\n");
-       ret = joycon_send_subcmd(ctlr, req, 5);
+       ret = joycon_send_subcmd(ctlr, req, 5, HZ);
        if (ret) {
                hid_warn(ctlr->hdev,
                         "Failed to read stick cal, using defaults; ret=%d\n",
        req->data[0] = 0x30; /* standard, full report mode */
 
        hid_dbg(ctlr->hdev, "setting controller report mode\n");
-       return joycon_send_subcmd(ctlr, req, 1);
+       return joycon_send_subcmd(ctlr, req, 1, HZ);
 }
 
 static int joycon_enable_rumble(struct joycon_ctlr *ctlr)
        req->data[0] = 0x01; /* note: 0x00 would disable */
 
        hid_dbg(ctlr->hdev, "enabling rumble\n");
-       return joycon_send_subcmd(ctlr, req, 1);
+       return joycon_send_subcmd(ctlr, req, 1, HZ/4);
 }
 
 static s32 joycon_map_stick_val(struct joycon_stick_cal *cal, s32 val)
 
        hid_dbg(hdev, "setting home led brightness\n");
        mutex_lock(&ctlr->output_mutex);
-       ret = joycon_send_subcmd(ctlr, req, 5);
+       ret = joycon_send_subcmd(ctlr, req, 5, HZ/4);
        mutex_unlock(&ctlr->output_mutex);
 
        return ret;
        mutex_lock(&ctlr->output_mutex);
        /* if handshake command fails, assume ble pro controller */
        if (hdev->product == USB_DEVICE_ID_NINTENDO_PROCON &&
-           !joycon_send_usb(ctlr, JC_USB_CMD_HANDSHAKE)) {
+           !joycon_send_usb(ctlr, JC_USB_CMD_HANDSHAKE, HZ)) {
                hid_dbg(hdev, "detected USB controller\n");
                /* set baudrate for improved latency */
-               ret = joycon_send_usb(ctlr, JC_USB_CMD_BAUDRATE_3M);
+               ret = joycon_send_usb(ctlr, JC_USB_CMD_BAUDRATE_3M, HZ);
                if (ret) {
                        hid_err(hdev, "Failed to set baudrate; ret=%d\n", ret);
                        goto err_mutex;
                }
                /* handshake */
-               ret = joycon_send_usb(ctlr, JC_USB_CMD_HANDSHAKE);
+               ret = joycon_send_usb(ctlr, JC_USB_CMD_HANDSHAKE, HZ);
                if (ret) {
                        hid_err(hdev, "Failed handshake; ret=%d\n", ret);
                        goto err_mutex;
                 * Set no timeout (to keep controller in USB mode).
                 * This doesn't send a response, so ignore the timeout.
                 */
-               joycon_send_usb(ctlr, JC_USB_CMD_NO_TIMEOUT);
+               joycon_send_usb(ctlr, JC_USB_CMD_NO_TIMEOUT, HZ/10);
        }
 
        /* get controller calibration data, and parse it */