Commit 61840edc authored by Ulf Hansson's avatar Ulf Hansson

mmc: dw_mmc: Drop use of ->init_card() callback

For dw_mmc, the ->init_card() callback is being used to turn on/off
automatic internal clock gating for powersave, which is needed to properly
support SDIO irqs on DAT1.

However, using the ->init_card() comes with a drawback in this case, as it
means that the powersave feature becomes disabled, no matter whether the
SDIO irqs becomes turned on or not. To improve the behaviour, let's change
into using the ->enable_sdio_irq() callback instead. This works fine,
because dw_mmc uses sdio_signal_irq() to signal the irqs, thus the
->enable_sdio_irq() is never executed from within atomic context.
Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
Reviewed-by: default avatarDouglas Anderson <dianders@chromium.org>
Link: https://lore.kernel.org/r/20211020102907.70195-1-ulf.hansson@linaro.orgSigned-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
parent f85a15c5
......@@ -1611,37 +1611,32 @@ static void dw_mci_hw_reset(struct mmc_host *mmc)
usleep_range(200, 300);
}
static void dw_mci_init_card(struct mmc_host *mmc, struct mmc_card *card)
static void dw_mci_prepare_sdio_irq(struct dw_mci_slot *slot, bool prepare)
{
struct dw_mci_slot *slot = mmc_priv(mmc);
struct dw_mci *host = slot->host;
const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id;
u32 clk_en_a_old;
u32 clk_en_a;
/*
* Low power mode will stop the card clock when idle. According to the
* description of the CLKENA register we should disable low power mode
* for SDIO cards if we need SDIO interrupts to work.
*/
if (mmc->caps & MMC_CAP_SDIO_IRQ) {
const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id;
u32 clk_en_a_old;
u32 clk_en_a;
clk_en_a_old = mci_readl(host, CLKENA);
if (card->type == MMC_TYPE_SDIO ||
card->type == MMC_TYPE_SD_COMBO) {
set_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags);
clk_en_a = clk_en_a_old & ~clken_low_pwr;
} else {
clear_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags);
clk_en_a = clk_en_a_old | clken_low_pwr;
}
clk_en_a_old = mci_readl(host, CLKENA);
if (prepare) {
set_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags);
clk_en_a = clk_en_a_old & ~clken_low_pwr;
} else {
clear_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags);
clk_en_a = clk_en_a_old | clken_low_pwr;
}
if (clk_en_a != clk_en_a_old) {
mci_writel(host, CLKENA, clk_en_a);
mci_send_cmd(slot, SDMMC_CMD_UPD_CLK |
SDMMC_CMD_PRV_DAT_WAIT, 0);
}
if (clk_en_a != clk_en_a_old) {
mci_writel(host, CLKENA, clk_en_a);
mci_send_cmd(slot, SDMMC_CMD_UPD_CLK | SDMMC_CMD_PRV_DAT_WAIT,
0);
}
}
......@@ -1669,6 +1664,7 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
struct dw_mci_slot *slot = mmc_priv(mmc);
struct dw_mci *host = slot->host;
dw_mci_prepare_sdio_irq(slot, enb);
__dw_mci_enable_sdio_irq(slot, enb);
/* Avoid runtime suspending the device when SDIO IRQ is enabled */
......@@ -1790,7 +1786,6 @@ static const struct mmc_host_ops dw_mci_ops = {
.execute_tuning = dw_mci_execute_tuning,
.card_busy = dw_mci_card_busy,
.start_signal_voltage_switch = dw_mci_switch_voltage,
.init_card = dw_mci_init_card,
.prepare_hs400_tuning = dw_mci_prepare_hs400_tuning,
};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment