Many customers met the issue with wifi driver. The following command shows sdhc clock not being disabled when wifi driver is removed.
# cat /proc/cpu/clocks | busybox grep sdhc
mxsdhci.3-3 ______ 0 200000000 (200MHz)
mxsdhci.2-2 ______ 0 200000000 (200MHz)
mxsdhci.1-1 ______ 0 200000000 (200MHz)
mxsdhci.0-0 ______ 0 200000000 (200MHz)
#
# insmod ar6000.ko
AR6000: configuration opcode 7 is only used for RTOS systems, not Linux systems#
AR6K: ** HIF layer does not support scatter requests (17)
wmi_control_rx() : Unknown id 0x101e
#
# cat /proc/cpu/clocks | busybox grep sdhc
mxsdhci.3-3 ______ 0 200000000 (200MHz)
mxsdhci.2-2 ______ 0 200000000 (200MHz)
mxsdhci.1-1 ______ 1 200000000 (200MHz)
mxsdhci.0-0 ______ 1 200000000 (200MHz)
#
#
# rmmod ar6000.ko
debug_hdr_ptr: 0x541e40
Attempting to reset target on instance destroy....
#
# cat /proc/cpu/clocks | busybox grep sdhc
mxsdhci.3-3 ______ 0 200000000 (200MHz)
mxsdhci.2-2 ______ 0 200000000 (200MHz)
mxsdhci.1-1 ______ 1 200000000 (200MHz)
Before digging it, why we care this clock seriously?
FSL implement one *mechanism* that can save more power by putting DDR into self refresh. The idea behind this is that, copies the code/data into iram, cpu then execute the instruction from iram. Then DDR can enter self refresh mode.
To start this mechanism, we need to make sure all the clock referenced from DDR must not being used since putting DDR into self refresh mode will turn off its clock.
SD's clock is this case, it referenced from DDR clock.
Then, how to disable SD clock?
In the sd host driver, we export a function to do this:
132 void sdhci_clock_enable(struct mmc_host *mmc, unsigned int enable)
133 {
134 struct sdhci_host *host;
135
136 host = mmc_priv(mmc);
137 if (enable) {
138 clk_enable(host->clk);
139 host->plat_data->clk_flg = 1;
140 } else {
141 clk_disable(host->clk);
142 host->plat_data->clk_flg = 0;
143 }
144 }
145 EXPORT_SYMBOL(sdhci_clock_enable);
It hopes its client driver, i.e., wifi driver, to call this explicitly to disable clock. Take Atheros for example:
static void hifDeviceRemoved(struct sdio_func *func)
{
struct mmc_host *host = func->card->host;
...
sdhci_clock_enable(host, 0);
}
static struct sdio_driver ar6k_driver = {
.name = "ar6k_wlan",
.id_table = ar6k_id_table,
.probe = hifDeviceInserted,
.remove = hifDeviceRemoved,
};
When rmmod this driver, hifDeviceRemoved() got called, it *notifies* host driver to disable clock for it.
Why host not smart to disable clock when its client not used?
To look into the host driver more as below,
1066 static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
1067 {
1068 struct sdhci_host *host;
1069 unsigned long flags;
1070
1071 host = mmc_priv(mmc);
1072
1073 /* Enable the clock */
1074 if (!host->plat_data->clk_flg) {
1075 clk_enable(host->clk);
1076 host->plat_data->clk_flg = 1;
1077 }
...
}
It turns on the clock when to access *SD card*, and disables clock after finishing accessing card.
1340 static void sdhci_finish_worker(struct work_struct *work)
1341 {
....
1421 if (req_done && host->plat_data->clk_flg &&
1422 !(host->plat_data->clk_always_on) &&
1423 !(func && sdio_func_present(func) && func->dev.driver)) {
1424 clk_disable(host->clk);
1425 host->plat_data->clk_flg = 0;
1426 }
....
}
It checks particularly when it's not SDIO. (Wifi is using SDIO) In other words, host driver can be smart to SD card but not SDIO.
In SD card case, all read/write command issued from host, and always the one way direction, so host can be smart this way.
For SDIO, it is not always that transaction is issued by host. When data packets arrived, it interrupts cpu.
On this case, its clock can not disabled otherwise we can't get the interrupt.
One alternative solution is that, we turn one data pin to gpio and configured it as wake up source.
We can then disable SDIO clock, when wifi driver needs to wake up host, it triggers the gpio. Host can then configure the gpio back to data pin and turn on clock.
Not sure if it can really be used this way, just my thought. :-)
Can you decrible the ploatform and software version you are using?
We have fixed this issue in our iMX.6 ICS recently.
Why does the clock still on after removing wifi's driver? "Sdio funcs" are enabled after insmoding wifi drivers. Disable them after rmmoding wifi drivers.
And the sdio devices will be still at present , not removed. This is decided by your hardware designs.
Here I can give two ways to fix this issue:
For the first way, we can add "force-remove" when doing rmmod driver. Then the sdio devices will be powered off with clock disabled. when doing insmod driver, we should do "force-detect" card. For different kernel versin, the patch is also different. Give me your software info I can give you a patch to try.
For the second way, we must enable runtime power management config. and add MMC_REMOVE_CARD capacity for sdhci host. Then it will do power off sdio drivers when doing rmmod driver.
About "One alternative solution is that, we turn one data pin to gpio and configured it as wake up source.We can then disable SDIO clock, when wifi driver needs to wake up host, it triggers the gpio. Host can then configure the gpio back to data pin and turn on clock.", it is an important feature of wifi----wake up application processor in suspend mode. Only when both wifi and host support this feature, we can then realize it.
Hope this can help you.