From 91f059c95c6a5dbc0907a5f871e7915a5e93c1f9 Mon Sep 17 00:00:00 2001 From: Shaik Sajida Bhanu Date: Fri, 27 May 2022 23:23:52 +0530 Subject: mmc: core: Capture eMMC and SD card errors Add changes to capture eMMC and SD card errors. This is useful for debug and testing. Signed-off-by: Liangliang Lu Signed-off-by: Sayali Lokhande Signed-off-by: Bao D. Nguyen Signed-off-by: Ram Prakash Gupta Signed-off-by: Shaik Sajida Bhanu Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/1653674036-21829-2-git-send-email-quic_c_sbhanu@quicinc.com Signed-off-by: Ulf Hansson --- include/linux/mmc/host.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'include/linux') diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index c193c50ccd78..eb8bc5b9b0b7 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -93,6 +93,25 @@ struct mmc_clk_phase_map { struct mmc_host; +enum mmc_err_stat { + MMC_ERR_CMD_TIMEOUT, + MMC_ERR_CMD_CRC, + MMC_ERR_DAT_TIMEOUT, + MMC_ERR_DAT_CRC, + MMC_ERR_AUTO_CMD, + MMC_ERR_ADMA, + MMC_ERR_TUNING, + MMC_ERR_CMDQ_RED, + MMC_ERR_CMDQ_GCE, + MMC_ERR_CMDQ_ICCE, + MMC_ERR_REQ_TIMEOUT, + MMC_ERR_CMDQ_REQ_TIMEOUT, + MMC_ERR_ICE_CFG, + MMC_ERR_CTRL_TIMEOUT, + MMC_ERR_UNEXPECTED_IRQ, + MMC_ERR_MAX, +}; + struct mmc_host_ops { /* * It is optional for the host to implement pre_req and post_req in @@ -501,6 +520,7 @@ struct mmc_host { /* Host Software Queue support */ bool hsq_enabled; + u32 err_stats[MMC_ERR_MAX]; unsigned long private[] ____cacheline_aligned; }; @@ -635,6 +655,12 @@ static inline enum dma_data_direction mmc_get_dma_dir(struct mmc_data *data) return data->flags & MMC_DATA_WRITE ? DMA_TO_DEVICE : DMA_FROM_DEVICE; } +static inline void mmc_debugfs_err_stats_inc(struct mmc_host *host, + enum mmc_err_stat stat) +{ + host->err_stats[stat] += 1; +} + int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error); int mmc_send_abort_tuning(struct mmc_host *host, u32 opcode); int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd); -- cgit v1.2.3-70-g09d2 From efe8f5c9b5e118070f424205078ababc46fd130a Mon Sep 17 00:00:00 2001 From: Shaik Sajida Bhanu Date: Fri, 27 May 2022 23:23:53 +0530 Subject: mmc: sdhci: Capture eMMC and SD card errors Add changes to capture eMMC and SD card errors. This is useful for debug and testing. Signed-off-by: Liangliang Lu Signed-off-by: Sayali Lokhande Signed-off-by: Bao D. Nguyen Signed-off-by: Shaik Sajida Bhanu Acked-by: Adrian Hunter Link: https://lore.kernel.org/r/1653674036-21829-3-git-send-email-quic_c_sbhanu@quicinc.com Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 59 ++++++++++++++++++++++++++++++++++++------------ drivers/mmc/host/sdhci.h | 3 +++ include/linux/mmc/mmc.h | 6 +++++ 3 files changed, 53 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 22152029e14c..7689ffec5ad1 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -224,6 +224,7 @@ void sdhci_reset(struct sdhci_host *host, u8 mask) if (timedout) { pr_err("%s: Reset 0x%x never completed.\n", mmc_hostname(host->mmc), (int)mask); + sdhci_err_stats_inc(host, CTRL_TIMEOUT); sdhci_dumpregs(host); return; } @@ -1716,6 +1717,7 @@ static bool sdhci_send_command_retry(struct sdhci_host *host, if (!timeout--) { pr_err("%s: Controller never released inhibit bit(s).\n", mmc_hostname(host->mmc)); + sdhci_err_stats_inc(host, CTRL_TIMEOUT); sdhci_dumpregs(host); cmd->error = -EIO; return false; @@ -1965,6 +1967,7 @@ void sdhci_enable_clk(struct sdhci_host *host, u16 clk) if (timedout) { pr_err("%s: Internal clock never stabilised.\n", mmc_hostname(host->mmc)); + sdhci_err_stats_inc(host, CTRL_TIMEOUT); sdhci_dumpregs(host); return; } @@ -1987,6 +1990,7 @@ void sdhci_enable_clk(struct sdhci_host *host, u16 clk) if (timedout) { pr_err("%s: PLL clock never stabilised.\n", mmc_hostname(host->mmc)); + sdhci_err_stats_inc(host, CTRL_TIMEOUT); sdhci_dumpregs(host); return; } @@ -3161,6 +3165,7 @@ static void sdhci_timeout_timer(struct timer_list *t) if (host->cmd && !sdhci_data_line_cmd(host->cmd)) { pr_err("%s: Timeout waiting for hardware cmd interrupt.\n", mmc_hostname(host->mmc)); + sdhci_err_stats_inc(host, REQ_TIMEOUT); sdhci_dumpregs(host); host->cmd->error = -ETIMEDOUT; @@ -3183,6 +3188,7 @@ static void sdhci_timeout_data_timer(struct timer_list *t) (host->cmd && sdhci_data_line_cmd(host->cmd))) { pr_err("%s: Timeout waiting for hardware interrupt.\n", mmc_hostname(host->mmc)); + sdhci_err_stats_inc(host, REQ_TIMEOUT); sdhci_dumpregs(host); if (host->data) { @@ -3234,17 +3240,21 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *intmask_p) return; pr_err("%s: Got command interrupt 0x%08x even though no command operation was in progress.\n", mmc_hostname(host->mmc), (unsigned)intmask); + sdhci_err_stats_inc(host, UNEXPECTED_IRQ); sdhci_dumpregs(host); return; } if (intmask & (SDHCI_INT_TIMEOUT | SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX)) { - if (intmask & SDHCI_INT_TIMEOUT) + if (intmask & SDHCI_INT_TIMEOUT) { host->cmd->error = -ETIMEDOUT; - else + sdhci_err_stats_inc(host, CMD_TIMEOUT); + } else { host->cmd->error = -EILSEQ; - + if (!mmc_op_tuning(host->cmd->opcode)) + sdhci_err_stats_inc(host, CMD_CRC); + } /* Treat data command CRC error the same as data CRC error */ if (host->cmd->data && (intmask & (SDHCI_INT_CRC | SDHCI_INT_TIMEOUT)) == @@ -3266,6 +3276,8 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *intmask_p) -ETIMEDOUT : -EILSEQ; + sdhci_err_stats_inc(host, AUTO_CMD); + if (sdhci_auto_cmd23(host, mrq)) { mrq->sbc->error = err; __sdhci_finish_mrq(host, mrq); @@ -3342,6 +3354,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) if (intmask & SDHCI_INT_DATA_TIMEOUT) { host->data_cmd = NULL; data_cmd->error = -ETIMEDOUT; + sdhci_err_stats_inc(host, CMD_TIMEOUT); __sdhci_finish_mrq(host, data_cmd->mrq); return; } @@ -3370,23 +3383,30 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) pr_err("%s: Got data interrupt 0x%08x even though no data operation was in progress.\n", mmc_hostname(host->mmc), (unsigned)intmask); + sdhci_err_stats_inc(host, UNEXPECTED_IRQ); sdhci_dumpregs(host); return; } - if (intmask & SDHCI_INT_DATA_TIMEOUT) + if (intmask & SDHCI_INT_DATA_TIMEOUT) { host->data->error = -ETIMEDOUT; - else if (intmask & SDHCI_INT_DATA_END_BIT) + sdhci_err_stats_inc(host, DAT_TIMEOUT); + } else if (intmask & SDHCI_INT_DATA_END_BIT) { host->data->error = -EILSEQ; - else if ((intmask & SDHCI_INT_DATA_CRC) && + if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)))) + sdhci_err_stats_inc(host, DAT_CRC); + } else if ((intmask & SDHCI_INT_DATA_CRC) && SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)) - != MMC_BUS_TEST_R) + != MMC_BUS_TEST_R) { host->data->error = -EILSEQ; - else if (intmask & SDHCI_INT_ADMA_ERROR) { + if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)))) + sdhci_err_stats_inc(host, DAT_CRC); + } else if (intmask & SDHCI_INT_ADMA_ERROR) { pr_err("%s: ADMA error: 0x%08x\n", mmc_hostname(host->mmc), intmask); sdhci_adma_show_error(host); + sdhci_err_stats_inc(host, ADMA); host->data->error = -EIO; if (host->ops->adma_workaround) host->ops->adma_workaround(host, intmask); @@ -3584,6 +3604,7 @@ out: if (unexpected) { pr_err("%s: Unexpected interrupt 0x%08x.\n", mmc_hostname(host->mmc), unexpected); + sdhci_err_stats_inc(host, UNEXPECTED_IRQ); sdhci_dumpregs(host); } @@ -3905,20 +3926,27 @@ bool sdhci_cqe_irq(struct sdhci_host *host, u32 intmask, int *cmd_error, if (!host->cqe_on) return false; - if (intmask & (SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC)) + if (intmask & (SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC)) { *cmd_error = -EILSEQ; - else if (intmask & SDHCI_INT_TIMEOUT) + if (!mmc_op_tuning(host->cmd->opcode)) + sdhci_err_stats_inc(host, CMD_CRC); + } else if (intmask & SDHCI_INT_TIMEOUT) { *cmd_error = -ETIMEDOUT; - else + sdhci_err_stats_inc(host, CMD_TIMEOUT); + } else *cmd_error = 0; - if (intmask & (SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC)) + if (intmask & (SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC)) { *data_error = -EILSEQ; - else if (intmask & SDHCI_INT_DATA_TIMEOUT) + if (!mmc_op_tuning(host->cmd->opcode)) + sdhci_err_stats_inc(host, DAT_CRC); + } else if (intmask & SDHCI_INT_DATA_TIMEOUT) { *data_error = -ETIMEDOUT; - else if (intmask & SDHCI_INT_ADMA_ERROR) + sdhci_err_stats_inc(host, DAT_TIMEOUT); + } else if (intmask & SDHCI_INT_ADMA_ERROR) { *data_error = -EIO; - else + sdhci_err_stats_inc(host, ADMA); + } else *data_error = 0; /* Clear selected interrupts. */ @@ -3934,6 +3962,7 @@ bool sdhci_cqe_irq(struct sdhci_host *host, u32 intmask, int *cmd_error, sdhci_writel(host, intmask, SDHCI_INT_STATUS); pr_err("%s: CQE: Unexpected interrupt 0x%08x.\n", mmc_hostname(host->mmc), intmask); + sdhci_err_stats_inc(host, UNEXPECTED_IRQ); sdhci_dumpregs(host); } diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index d7929d725730..95a08f09df30 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -356,6 +356,9 @@ struct sdhci_adma2_64_desc { */ #define MMC_CMD_TRANSFER_TIME (10 * NSEC_PER_MSEC) /* max 10 ms */ +#define sdhci_err_stats_inc(host, err_name) \ + mmc_debugfs_err_stats_inc((host)->mmc, MMC_ERR_##err_name) + enum sdhci_cookie { COOKIE_UNMAPPED, COOKIE_PRE_MAPPED, /* mapped by sdhci_pre_req() */ diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index d9a65c6a8816..9c50bc40f8ff 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h @@ -99,6 +99,12 @@ static inline bool mmc_op_multi(u32 opcode) opcode == MMC_READ_MULTIPLE_BLOCK; } +static inline bool mmc_op_tuning(u32 opcode) +{ + return opcode == MMC_SEND_TUNING_BLOCK || + opcode == MMC_SEND_TUNING_BLOCK_HS200; +} + /* * MMC_SWITCH argument format: * -- cgit v1.2.3-70-g09d2 From 3beb0ab5bffba625007ea5c9e5e0ee5eef05c1ea Mon Sep 17 00:00:00 2001 From: Seunghui Lee Date: Wed, 13 Jul 2022 12:36:34 +0900 Subject: mmc: core: Use mmc_card_* macro and add a new for the sd_combo type Add mmc_card_sd_combo() macro for sd combo type card and use the mmc_card_* macro to simplify code instead of comparing card->type. Signed-off-by: Seunghui Lee Link: https://lore.kernel.org/r/20220713033635.28432-2-sh043.lee@samsung.com Signed-off-by: Ulf Hansson --- drivers/mmc/core/block.c | 4 ++-- drivers/mmc/core/bus.c | 4 ++-- drivers/mmc/core/sd.c | 2 +- drivers/mmc/core/sdio.c | 16 ++++++++-------- include/linux/mmc/card.h | 1 + 5 files changed, 14 insertions(+), 13 deletions(-) (limited to 'include/linux') diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index f4a1281658db..9c642b3b7c20 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -2988,7 +2988,7 @@ static int mmc_blk_probe(struct mmc_card *card) * Don't enable runtime PM for SD-combo cards here. Leave that * decision to be taken during the SDIO init sequence instead. */ - if (card->type != MMC_TYPE_SD_COMBO) { + if (!mmc_card_sd_combo(card)) { pm_runtime_set_active(&card->dev); pm_runtime_enable(&card->dev); } @@ -3015,7 +3015,7 @@ static void mmc_blk_remove(struct mmc_card *card) mmc_blk_part_switch(card, md->part_type); mmc_release_host(card->host); } - if (card->type != MMC_TYPE_SD_COMBO) + if (!mmc_card_sd_combo(card)) pm_runtime_disable(&card->dev); pm_runtime_put_noidle(&card->dev); mmc_blk_remove_req(md); diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c index 58a60afa650b..d8762fa3d5cd 100644 --- a/drivers/mmc/core/bus.c +++ b/drivers/mmc/core/bus.c @@ -85,7 +85,7 @@ mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env) return retval; } - if (card->type == MMC_TYPE_SDIO || card->type == MMC_TYPE_SD_COMBO) { + if (mmc_card_sdio(card) || mmc_card_sd_combo(card)) { retval = add_uevent_var(env, "SDIO_ID=%04X:%04X", card->cis.vendor, card->cis.device); if (retval) @@ -107,7 +107,7 @@ mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env) * SDIO (non-combo) cards are not handled by mmc_block driver and do not * have accessible CID register which used by mmc_card_name() function. */ - if (card->type == MMC_TYPE_SDIO) + if (mmc_card_sdio(card)) return 0; retval = add_uevent_var(env, "MMC_NAME=%s", mmc_card_name(card)); diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index d2023837dd72..cee4c0b59f43 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -793,7 +793,7 @@ static umode_t sd_std_is_visible(struct kobject *kobj, struct attribute *attr, attr == &dev_attr_info2.attr || attr == &dev_attr_info3.attr || attr == &dev_attr_info4.attr - ) && card->type != MMC_TYPE_SD_COMBO) + ) &&!mmc_card_sd_combo(card)) return 0; return attr->mode; diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index 25799accf8a0..b589df1c35e0 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -335,7 +335,7 @@ static int sdio_disable_4bit_bus(struct mmc_card *card) { int err; - if (card->type == MMC_TYPE_SDIO) + if (mmc_card_sdio(card)) goto out; if (!(card->host->caps & MMC_CAP_4_BIT_DATA)) @@ -360,7 +360,7 @@ static int sdio_enable_4bit_bus(struct mmc_card *card) err = sdio_enable_wide(card); if (err <= 0) return err; - if (card->type == MMC_TYPE_SDIO) + if (mmc_card_sdio(card)) goto out; if (card->scr.bus_widths & SD_SCR_BUS_WIDTH_4) { @@ -415,7 +415,7 @@ static int sdio_enable_hs(struct mmc_card *card) int ret; ret = mmc_sdio_switch_hs(card, true); - if (ret <= 0 || card->type == MMC_TYPE_SDIO) + if (ret <= 0 || mmc_card_sdio(card)) return ret; ret = mmc_sd_switch_hs(card); @@ -441,7 +441,7 @@ static unsigned mmc_sdio_get_max_clock(struct mmc_card *card) max_dtr = card->cis.max_dtr; } - if (card->type == MMC_TYPE_SD_COMBO) + if (mmc_card_sd_combo(card)) max_dtr = min(max_dtr, mmc_sd_get_max_clock(card)); return max_dtr; @@ -689,7 +689,7 @@ try_again: mmc_sd_get_cid(host, ocr & rocr, card->raw_cid, NULL) == 0) { card->type = MMC_TYPE_SD_COMBO; - if (oldcard && (oldcard->type != MMC_TYPE_SD_COMBO || + if (oldcard && (!mmc_card_sd_combo(oldcard) || memcmp(card->raw_cid, oldcard->raw_cid, sizeof(card->raw_cid)) != 0)) { err = -ENOENT; goto mismatch; @@ -697,7 +697,7 @@ try_again: } else { card->type = MMC_TYPE_SDIO; - if (oldcard && oldcard->type != MMC_TYPE_SDIO) { + if (oldcard && !mmc_card_sdio(oldcard)) { err = -ENOENT; goto mismatch; } @@ -754,7 +754,7 @@ try_again: /* * Read CSD, before selecting the card */ - if (!oldcard && card->type == MMC_TYPE_SD_COMBO) { + if (!oldcard && mmc_card_sd_combo(card)) { err = mmc_sd_get_csd(card); if (err) goto remove; @@ -827,7 +827,7 @@ try_again: mmc_fixup_device(card, sdio_fixup_methods); - if (card->type == MMC_TYPE_SD_COMBO) { + if (mmc_card_sd_combo(card)) { err = mmc_sd_setup_card(host, card, oldcard != NULL); /* handle as SDIO-only card if memory init failed */ if (err) { diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 37f975875102..156a7b673a28 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -348,5 +348,6 @@ bool mmc_card_is_blockaddr(struct mmc_card *card); #define mmc_card_mmc(c) ((c)->type == MMC_TYPE_MMC) #define mmc_card_sd(c) ((c)->type == MMC_TYPE_SD) #define mmc_card_sdio(c) ((c)->type == MMC_TYPE_SDIO) +#define mmc_card_sd_combo(c) ((c)->type == MMC_TYPE_SD_COMBO) #endif /* LINUX_MMC_CARD_H */ -- cgit v1.2.3-70-g09d2 From 019e442bb0d5e7f25ada8eb4252e22e62d17a95e Mon Sep 17 00:00:00 2001 From: Axe Yang Date: Tue, 26 Jul 2022 14:28:41 +0800 Subject: mmc: core: Add support for SDIO wakeup interrupt If wakeup-source flag is set in host dts node, parse EAI information from SDIO CCCR interrupt externsion segment for in-band wakeup. If async interrupt is supported by SDIO card then enable it and set enable_async_irq flag in sdio_cccr structure to 1. The parse flow is implemented in sdio_read_cccr(). Reviewed-by: AngeloGioacchino Del Regno Signed-off-by: Axe Yang Link: https://lore.kernel.org/r/20220726062842.18846-3-axe.yang@mediatek.com Signed-off-by: Ulf Hansson --- drivers/mmc/core/sdio.c | 14 ++++++++++++++ include/linux/mmc/card.h | 8 +++++++- include/linux/mmc/sdio.h | 5 +++++ 3 files changed, 26 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c index b589df1c35e0..0b682a31cd3e 100644 --- a/drivers/mmc/core/sdio.c +++ b/drivers/mmc/core/sdio.c @@ -226,6 +226,20 @@ static int sdio_read_cccr(struct mmc_card *card, u32 ocr) card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_C; if (data & SDIO_DRIVE_SDTD) card->sw_caps.sd3_drv_type |= SD_DRIVER_TYPE_D; + + ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTERRUPT_EXT, 0, &data); + if (ret) + goto out; + + if (data & SDIO_INTERRUPT_EXT_SAI) { + data |= SDIO_INTERRUPT_EXT_EAI; + ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_INTERRUPT_EXT, + data, NULL); + if (ret) + goto out; + + card->cccr.enable_async_irq = 1; + } } /* if no uhs mode ensure we check for high speed */ diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 156a7b673a28..8a30de08e913 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -219,7 +219,8 @@ struct sdio_cccr { wide_bus:1, high_power:1, high_speed:1, - disable_cd:1; + disable_cd:1, + enable_async_irq:1; }; struct sdio_cis { @@ -343,6 +344,11 @@ static inline bool mmc_large_sector(struct mmc_card *card) return card->ext_csd.data_sector_size == 4096; } +static inline int mmc_card_enable_async_irq(struct mmc_card *card) +{ + return card->cccr.enable_async_irq; +} + bool mmc_card_is_blockaddr(struct mmc_card *card); #define mmc_card_mmc(c) ((c)->type == MMC_TYPE_MMC) diff --git a/include/linux/mmc/sdio.h b/include/linux/mmc/sdio.h index 2a05d1ac4f0e..1ef400f28642 100644 --- a/include/linux/mmc/sdio.h +++ b/include/linux/mmc/sdio.h @@ -159,6 +159,11 @@ #define SDIO_DTSx_SET_TYPE_A (1 << SDIO_DRIVE_DTSx_SHIFT) #define SDIO_DTSx_SET_TYPE_C (2 << SDIO_DRIVE_DTSx_SHIFT) #define SDIO_DTSx_SET_TYPE_D (3 << SDIO_DRIVE_DTSx_SHIFT) + +#define SDIO_CCCR_INTERRUPT_EXT 0x16 +#define SDIO_INTERRUPT_EXT_SAI (1 << 0) +#define SDIO_INTERRUPT_EXT_EAI (1 << 1) + /* * Function Basic Registers (FBR) */ -- cgit v1.2.3-70-g09d2