brcmfmac: assure active clock request upon entering SLEEP state
authorArend van Spriel <arend@broadcom.com>
Sat, 15 Mar 2014 16:18:20 +0000 (17:18 +0100)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 17 Mar 2014 17:44:14 +0000 (13:44 -0400)
When the SDIO driver goes in low power state it must assure that
a clock request in ChipCLKCSR is set. Otherwise waking up the
device can fail. The register is read and if necessary the ALP
clock will be requested.

Reviewed-by: Daniel (Deognyoun) Kim <dekim@broadcom.com>
Reviewed-by: Hante Meuleman <meuleman@broadcom.com>
Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com>
Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com>
Signed-off-by: Arend van Spriel <arend@broadcom.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c

index bcdaf72389f36e383bb7830a31f1352644b6d15f..859eddd526ef214115db4c7a5797417af761896c 100644 (file)
@@ -175,6 +175,7 @@ struct rte_console {
 #define SBSDIO_ALP_AVAIL               0x40
 /* Status: HT is ready */
 #define SBSDIO_HT_AVAIL                        0x80
+#define SBSDIO_CSR_MASK                        0x1F
 #define SBSDIO_AVBITS          (SBSDIO_HT_AVAIL | SBSDIO_ALP_AVAIL)
 #define SBSDIO_ALPAV(regval)   ((regval) & SBSDIO_AVBITS)
 #define SBSDIO_HTAV(regval)    (((regval) & SBSDIO_AVBITS) == SBSDIO_AVBITS)
@@ -720,16 +721,12 @@ brcmf_sdio_kso_control(struct brcmf_sdio *bus, bool on)
        int err = 0;
        int try_cnt = 0;
 
-       brcmf_dbg(TRACE, "Enter\n");
+       brcmf_dbg(TRACE, "Enter: on=%d\n", on);
 
        wr_val = (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT);
        /* 1st KSO write goes to AOS wake up core if device is asleep  */
        brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR,
                          wr_val, &err);
-       if (err) {
-               brcmf_err("SDIO_AOS KSO write error: %d\n", err);
-               return err;
-       }
 
        if (on) {
                /* device WAKEUP through KSO:
@@ -759,13 +756,19 @@ brcmf_sdio_kso_control(struct brcmf_sdio *bus, bool on)
                                           &err);
                if (((rd_val & bmask) == cmp_val) && !err)
                        break;
-               brcmf_dbg(SDIO, "KSO wr/rd retry:%d (max: %d) ERR:%x\n",
-                         try_cnt, MAX_KSO_ATTEMPTS, err);
+
                udelay(KSO_WAIT_US);
                brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_SLEEPCSR,
                                  wr_val, &err);
        } while (try_cnt++ < MAX_KSO_ATTEMPTS);
 
+       if (try_cnt > 2)
+               brcmf_dbg(SDIO, "try_cnt=%d rd_val=0x%x err=%d\n", try_cnt,
+                         rd_val, err);
+
+       if (try_cnt > MAX_KSO_ATTEMPTS)
+               brcmf_err("max tries: rd_val=0x%x err=%d\n", rd_val, err);
+
        return err;
 }
 
@@ -966,6 +969,7 @@ static int
 brcmf_sdio_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok)
 {
        int err = 0;
+       u8 clkcsr;
 
        brcmf_dbg(SDIO, "Enter: request %s currently %s\n",
                  (sleep ? "SLEEP" : "WAKE"),
@@ -984,8 +988,20 @@ brcmf_sdio_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok)
                            atomic_read(&bus->ipend) > 0 ||
                            (!atomic_read(&bus->fcstate) &&
                            brcmu_pktq_mlen(&bus->txq, ~bus->flowcontrol) &&
-                           data_ok(bus)))
-                                return -EBUSY;
+                           data_ok(bus))) {
+                                err = -EBUSY;
+                                goto done;
+                       }
+
+                       clkcsr = brcmf_sdiod_regrb(bus->sdiodev,
+                                                  SBSDIO_FUNC1_CHIPCLKCSR,
+                                                  &err);
+                       if ((clkcsr & SBSDIO_CSR_MASK) == 0) {
+                               brcmf_dbg(SDIO, "no clock, set ALP\n");
+                               brcmf_sdiod_regwb(bus->sdiodev,
+                                                 SBSDIO_FUNC1_CHIPCLKCSR,
+                                                 SBSDIO_ALP_AVAIL_REQ, &err);
+                       }
                        err = brcmf_sdio_kso_control(bus, false);
                        /* disable watchdog */
                        if (!err)
@@ -1002,7 +1018,7 @@ brcmf_sdio_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok)
                } else {
                        brcmf_err("error while changing bus sleep state %d\n",
                                  err);
-                       return err;
+                       goto done;
                }
        }
 
@@ -1014,7 +1030,8 @@ end:
        } else {
                brcmf_sdio_clkctl(bus, CLK_AVAIL, pendok);
        }
-
+done:
+       brcmf_dbg(SDIO, "Exit: err=%d\n", err);
        return err;
 
 }