|
@@ -2303,6 +2303,87 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
|
|
|
return cnt;
|
|
|
}
|
|
|
|
|
|
+static void brcmf_sdbrcm_bus_stop(struct device *dev)
|
|
|
+{
|
|
|
+ u32 local_hostintmask;
|
|
|
+ u8 saveclk;
|
|
|
+ uint retries;
|
|
|
+ int err;
|
|
|
+ struct brcmf_bus *bus_if = dev_get_drvdata(dev);
|
|
|
+ struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
|
|
|
+ struct brcmf_sdio *bus = sdiodev->bus;
|
|
|
+
|
|
|
+ brcmf_dbg(TRACE, "Enter\n");
|
|
|
+
|
|
|
+ if (bus->watchdog_tsk) {
|
|
|
+ send_sig(SIGTERM, bus->watchdog_tsk, 1);
|
|
|
+ kthread_stop(bus->watchdog_tsk);
|
|
|
+ bus->watchdog_tsk = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (bus->dpc_tsk && bus->dpc_tsk != current) {
|
|
|
+ send_sig(SIGTERM, bus->dpc_tsk, 1);
|
|
|
+ kthread_stop(bus->dpc_tsk);
|
|
|
+ bus->dpc_tsk = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ down(&bus->sdsem);
|
|
|
+
|
|
|
+ bus_wake(bus);
|
|
|
+
|
|
|
+ /* Enable clock for device interrupts */
|
|
|
+ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
|
|
|
+
|
|
|
+ /* Disable and clear interrupts at the chip level also */
|
|
|
+ w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask), &retries);
|
|
|
+ local_hostintmask = bus->hostintmask;
|
|
|
+ bus->hostintmask = 0;
|
|
|
+
|
|
|
+ /* Change our idea of bus state */
|
|
|
+ bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
|
|
|
+
|
|
|
+ /* Force clocks on backplane to be sure F2 interrupt propagates */
|
|
|
+ saveclk = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
|
|
|
+ SBSDIO_FUNC1_CHIPCLKCSR, &err);
|
|
|
+ if (!err) {
|
|
|
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
|
|
|
+ SBSDIO_FUNC1_CHIPCLKCSR,
|
|
|
+ (saveclk | SBSDIO_FORCE_HT), &err);
|
|
|
+ }
|
|
|
+ if (err)
|
|
|
+ brcmf_dbg(ERROR, "Failed to force clock for F2: err %d\n", err);
|
|
|
+
|
|
|
+ /* Turn off the bus (F2), free any pending packets */
|
|
|
+ brcmf_dbg(INTR, "disable SDIO interrupts\n");
|
|
|
+ brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx,
|
|
|
+ SDIO_FUNC_ENABLE_1, NULL);
|
|
|
+
|
|
|
+ /* Clear any pending interrupts now that F2 is disabled */
|
|
|
+ w_sdreg32(bus, local_hostintmask,
|
|
|
+ offsetof(struct sdpcmd_regs, intstatus), &retries);
|
|
|
+
|
|
|
+ /* Turn off the backplane clock (only) */
|
|
|
+ brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
|
|
|
+
|
|
|
+ /* Clear the data packet queues */
|
|
|
+ brcmu_pktq_flush(&bus->txq, true, NULL, NULL);
|
|
|
+
|
|
|
+ /* Clear any held glomming stuff */
|
|
|
+ if (bus->glomd)
|
|
|
+ brcmu_pkt_buf_free_skb(bus->glomd);
|
|
|
+ brcmf_sdbrcm_free_glom(bus);
|
|
|
+
|
|
|
+ /* Clear rx control and wake any waiters */
|
|
|
+ bus->rxlen = 0;
|
|
|
+ brcmf_sdbrcm_dcmd_resp_wake(bus);
|
|
|
+
|
|
|
+ /* Reset some F2 state stuff */
|
|
|
+ bus->rxskip = false;
|
|
|
+ bus->tx_seq = bus->rx_seq = 0;
|
|
|
+
|
|
|
+ up(&bus->sdsem);
|
|
|
+}
|
|
|
+
|
|
|
static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
|
|
|
{
|
|
|
u32 intstatus, newstatus = 0;
|
|
@@ -3342,87 +3423,6 @@ brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-void brcmf_sdbrcm_bus_stop(struct device *dev)
|
|
|
-{
|
|
|
- u32 local_hostintmask;
|
|
|
- u8 saveclk;
|
|
|
- uint retries;
|
|
|
- int err;
|
|
|
- struct brcmf_bus *bus_if = dev_get_drvdata(dev);
|
|
|
- struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv;
|
|
|
- struct brcmf_sdio *bus = sdiodev->bus;
|
|
|
-
|
|
|
- brcmf_dbg(TRACE, "Enter\n");
|
|
|
-
|
|
|
- if (bus->watchdog_tsk) {
|
|
|
- send_sig(SIGTERM, bus->watchdog_tsk, 1);
|
|
|
- kthread_stop(bus->watchdog_tsk);
|
|
|
- bus->watchdog_tsk = NULL;
|
|
|
- }
|
|
|
-
|
|
|
- if (bus->dpc_tsk && bus->dpc_tsk != current) {
|
|
|
- send_sig(SIGTERM, bus->dpc_tsk, 1);
|
|
|
- kthread_stop(bus->dpc_tsk);
|
|
|
- bus->dpc_tsk = NULL;
|
|
|
- }
|
|
|
-
|
|
|
- down(&bus->sdsem);
|
|
|
-
|
|
|
- bus_wake(bus);
|
|
|
-
|
|
|
- /* Enable clock for device interrupts */
|
|
|
- brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
|
|
|
-
|
|
|
- /* Disable and clear interrupts at the chip level also */
|
|
|
- w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask), &retries);
|
|
|
- local_hostintmask = bus->hostintmask;
|
|
|
- bus->hostintmask = 0;
|
|
|
-
|
|
|
- /* Change our idea of bus state */
|
|
|
- bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
|
|
|
-
|
|
|
- /* Force clocks on backplane to be sure F2 interrupt propagates */
|
|
|
- saveclk = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
|
|
|
- SBSDIO_FUNC1_CHIPCLKCSR, &err);
|
|
|
- if (!err) {
|
|
|
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
|
|
|
- SBSDIO_FUNC1_CHIPCLKCSR,
|
|
|
- (saveclk | SBSDIO_FORCE_HT), &err);
|
|
|
- }
|
|
|
- if (err)
|
|
|
- brcmf_dbg(ERROR, "Failed to force clock for F2: err %d\n", err);
|
|
|
-
|
|
|
- /* Turn off the bus (F2), free any pending packets */
|
|
|
- brcmf_dbg(INTR, "disable SDIO interrupts\n");
|
|
|
- brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx,
|
|
|
- SDIO_FUNC_ENABLE_1, NULL);
|
|
|
-
|
|
|
- /* Clear any pending interrupts now that F2 is disabled */
|
|
|
- w_sdreg32(bus, local_hostintmask,
|
|
|
- offsetof(struct sdpcmd_regs, intstatus), &retries);
|
|
|
-
|
|
|
- /* Turn off the backplane clock (only) */
|
|
|
- brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
|
|
|
-
|
|
|
- /* Clear the data packet queues */
|
|
|
- brcmu_pktq_flush(&bus->txq, true, NULL, NULL);
|
|
|
-
|
|
|
- /* Clear any held glomming stuff */
|
|
|
- if (bus->glomd)
|
|
|
- brcmu_pkt_buf_free_skb(bus->glomd);
|
|
|
- brcmf_sdbrcm_free_glom(bus);
|
|
|
-
|
|
|
- /* Clear rx control and wake any waiters */
|
|
|
- bus->rxlen = 0;
|
|
|
- brcmf_sdbrcm_dcmd_resp_wake(bus);
|
|
|
-
|
|
|
- /* Reset some F2 state stuff */
|
|
|
- bus->rxskip = false;
|
|
|
- bus->tx_seq = bus->rx_seq = 0;
|
|
|
-
|
|
|
- up(&bus->sdsem);
|
|
|
-}
|
|
|
-
|
|
|
int brcmf_sdbrcm_bus_init(struct device *dev)
|
|
|
{
|
|
|
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
|
|
@@ -3952,6 +3952,8 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
|
|
|
bus->dpc_tsk = NULL;
|
|
|
}
|
|
|
|
|
|
+ /* Assign bus interface call back */
|
|
|
+ bus->sdiodev->bus_if->brcmf_bus_stop = brcmf_sdbrcm_bus_stop;
|
|
|
/* Attach to the brcmf/OS/network interface */
|
|
|
ret = brcmf_attach(SDPCM_RESERVE, bus->sdiodev->dev);
|
|
|
if (ret != 0) {
|