JayTu

disable sdhc clock while it is not used -blog archive

Discussion created by JayTu Employee on Aug 29, 2012
Latest reply on Sep 15, 2012 by waterzhou

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. :-)

Outcomes