Loading drivers/mmc/core/bus.c +7 −0 Original line number Diff line number Diff line Loading @@ -380,6 +380,13 @@ int mmc_add_card(struct mmc_card *card) #endif card->dev.of_node = mmc_of_find_child_device(card->host, 0); if (mmc_card_sdio(card)) { ret = device_init_wakeup(&card->dev, true); if (ret) pr_err("%s: %s: failed to init wakeup: %d\n", mmc_hostname(card->host), __func__, ret); } device_enable_async_suspend(&card->dev); ret = device_add(&card->dev); Loading drivers/mmc/core/host.c +28 −0 Original line number Diff line number Diff line Loading @@ -182,6 +182,34 @@ int mmc_retune(struct mmc_host *host) return err; } /** * mmc_host_may_gate_card - check if this card may be gated * @card: card to check. */ bool mmc_host_may_gate_card(struct mmc_card *card) { /* If there is no card we may gate it */ if (!card) return true; /* * SDIO3.0 card allows the clock to be gated off so check if * that is the case or not */ if (mmc_card_sdio(card) && card->cccr.async_intr_sup) return true; /* * Don't gate SDIO cards! These need to be clocked at all times * since they may be independent systems generating interrupts * and other events. The clock requests counter from the core will * go down to zero since the core does not need it, but we will not * gate the clock, because there is somebody out there that may still * be using it. */ return !(card->quirks & MMC_QUIRK_BROKEN_CLK_GATING); } static void mmc_retune_timer(struct timer_list *t) { struct mmc_host *host = from_timer(host, t, retune_timer); Loading drivers/mmc/core/quirks.h +23 −0 Original line number Diff line number Diff line Loading @@ -153,6 +153,21 @@ static const struct mmc_fixup sdio_fixup_methods[] = { SDIO_FIXUP(SDIO_VENDOR_ID_TI_WL1251, SDIO_DEVICE_ID_TI_WL1251, add_quirk, MMC_QUIRK_DISABLE_CD), SDIO_FIXUP(SDIO_VENDOR_ID_MSM_QCA, SDIO_DEVICE_ID_MSM_QCA_AR6003_1, remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING), SDIO_FIXUP(SDIO_VENDOR_ID_MSM_QCA, SDIO_DEVICE_ID_MSM_QCA_AR6003_2, remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING), SDIO_FIXUP(SDIO_VENDOR_ID_MSM_QCA, SDIO_DEVICE_ID_MSM_QCA_AR6004_1, remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING), SDIO_FIXUP(SDIO_VENDOR_ID_MSM_QCA, SDIO_DEVICE_ID_MSM_QCA_AR6004_2, remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING), SDIO_FIXUP(SDIO_VENDOR_ID_MSM, SDIO_DEVICE_ID_MSM_WCN1314, remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING), SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271, add_quirk, MMC_QUIRK_NONSTD_FUNC_IF), Loading @@ -168,6 +183,14 @@ static const struct mmc_fixup sdio_fixup_methods[] = { SDIO_FIXUP(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8887WLAN, add_limit_rate_quirk, 150000000), SDIO_FIXUP(SDIO_VENDOR_ID_QCA6574, SDIO_DEVICE_ID_QCA6574, add_quirk, MMC_QUIRK_QCA6574_SETTINGS), SDIO_FIXUP(SDIO_VENDOR_ID_QCA9377, SDIO_DEVICE_ID_QCA9377, add_quirk, MMC_QUIRK_QCA9377_SETTINGS), SDIO_FIXUP(SDIO_VENDOR_ID_QCA9379, SDIO_DEVICE_ID_QCA9379, add_quirk, MMC_QUIRK_QCA9379_SETTINGS), END_FIXUP }; Loading drivers/mmc/core/sdio.c +91 −6 Original line number Diff line number Diff line Loading @@ -184,6 +184,23 @@ 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_EXTENSION, 0, &data); if (ret) goto out; if (data & SDIO_SUPPORT_ASYNC_INTR) { if (card->host->caps2 & MMC_CAP2_ASYNC_SDIO_IRQ_4BIT_MODE) { data |= SDIO_ENABLE_ASYNC_INTR; ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_INTERRUPT_EXTENSION, data, NULL); if (ret) goto out; card->cccr.async_intr_sup = 1; } } } /* if no uhs mode ensure we check for high speed */ Loading @@ -202,12 +219,61 @@ static int sdio_read_cccr(struct mmc_card *card, u32 ocr) return ret; } static void sdio_enable_vendor_specific_settings(struct mmc_card *card) { int ret; u8 settings; if (mmc_enable_qca6574_settings(card) || mmc_enable_qca9377_settings(card) || mmc_enable_qca9379_settings(card)) { ret = mmc_io_rw_direct(card, 1, 0, 0xF2, 0x0F, NULL); if (ret) { pr_crit("%s: failed to write to fn 0xf2 %d\n", mmc_hostname(card->host), ret); goto out; } ret = mmc_io_rw_direct(card, 0, 0, 0xF1, 0, &settings); if (ret) { pr_crit("%s: failed to read fn 0xf1 %d\n", mmc_hostname(card->host), ret); goto out; } settings |= 0x80; ret = mmc_io_rw_direct(card, 1, 0, 0xF1, settings, NULL); if (ret) { pr_crit("%s: failed to write to fn 0xf1 %d\n", mmc_hostname(card->host), ret); goto out; } ret = mmc_io_rw_direct(card, 0, 0, 0xF0, 0, &settings); if (ret) { pr_crit("%s: failed to read fn 0xf0 %d\n", mmc_hostname(card->host), ret); goto out; } settings |= 0x20; ret = mmc_io_rw_direct(card, 1, 0, 0xF0, settings, NULL); if (ret) { pr_crit("%s: failed to write to fn 0xf0 %d\n", mmc_hostname(card->host), ret); goto out; } } out: return; } static int sdio_enable_wide(struct mmc_card *card) { int ret; u8 ctrl; if (!(card->host->caps & MMC_CAP_4_BIT_DATA)) if (!(card->host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) return 0; if (card->cccr.low_speed && !card->cccr.wide_bus) Loading @@ -223,6 +289,9 @@ static int sdio_enable_wide(struct mmc_card *card) /* set as 4-bit bus width */ ctrl &= ~SDIO_BUS_WIDTH_MASK; if (card->host->caps & MMC_CAP_8_BIT_DATA) ctrl |= SDIO_BUS_WIDTH_8BIT; else if (card->host->caps & MMC_CAP_4_BIT_DATA) ctrl |= SDIO_BUS_WIDTH_4BIT; ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_IF, ctrl, NULL); Loading Loading @@ -264,7 +333,7 @@ static int sdio_disable_wide(struct mmc_card *card) int ret; u8 ctrl; if (!(card->host->caps & MMC_CAP_4_BIT_DATA)) if (!(card->host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) return 0; if (card->cccr.low_speed && !card->cccr.wide_bus) Loading @@ -274,10 +343,10 @@ static int sdio_disable_wide(struct mmc_card *card) if (ret) return ret; if (!(ctrl & SDIO_BUS_WIDTH_4BIT)) if (!(ctrl & (SDIO_BUS_WIDTH_4BIT | SDIO_BUS_WIDTH_8BIT))) return 0; ctrl &= ~SDIO_BUS_WIDTH_4BIT; ctrl &= ~(SDIO_BUS_WIDTH_4BIT | SDIO_BUS_WIDTH_8BIT); ctrl |= SDIO_BUS_ASYNC_INT; ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_IF, ctrl, NULL); Loading Loading @@ -495,6 +564,9 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card) if (err) return err; /* Vendor specific settings based on card quirks */ sdio_enable_vendor_specific_settings(card); speed &= ~SDIO_SPEED_BSS_MASK; speed |= bus_speed; err = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_SPEED, speed, NULL); Loading Loading @@ -790,7 +862,12 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, * Switch to wider bus (if supported). */ err = sdio_enable_4bit_bus(card); if (err) if (err > 0) { if (card->host->caps & MMC_CAP_8_BIT_DATA) mmc_set_bus_width(card->host, MMC_BUS_WIDTH_8); else if (card->host->caps & MMC_CAP_4_BIT_DATA) mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); } else if (err) goto remove; } Loading Loading @@ -988,6 +1065,13 @@ static int mmc_sdio_resume(struct mmc_host *host) } else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) { /* We may have switched to 1-bit mode during suspend */ err = sdio_enable_4bit_bus(host->card); if (err > 0) { if (host->caps & MMC_CAP_8_BIT_DATA) mmc_set_bus_width(host, MMC_BUS_WIDTH_8); else if (host->caps & MMC_CAP_4_BIT_DATA) mmc_set_bus_width(host, MMC_BUS_WIDTH_4); err = 0; } } if (err) Loading @@ -1008,6 +1092,7 @@ static int mmc_sdio_resume(struct mmc_host *host) mmc_release_host(host); host->pm_flags &= ~MMC_PM_KEEP_POWER; host->pm_flags &= ~MMC_PM_WAKE_SDIO_IRQ; return err; } Loading drivers/mmc/core/sdio_cis.c +8 −2 Original line number Diff line number Diff line Loading @@ -278,9 +278,15 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func) break; /* null entries have no link field or data */ if (tpl_code == 0x00) if (tpl_code == 0x00) { if (card->cis.vendor == 0x70 && (card->cis.device == 0x2460 || card->cis.device == 0x0460 || card->cis.device == 0x23F1 || card->cis.device == 0x23F0)) break; continue; } ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_link); if (ret) break; Loading Loading
drivers/mmc/core/bus.c +7 −0 Original line number Diff line number Diff line Loading @@ -380,6 +380,13 @@ int mmc_add_card(struct mmc_card *card) #endif card->dev.of_node = mmc_of_find_child_device(card->host, 0); if (mmc_card_sdio(card)) { ret = device_init_wakeup(&card->dev, true); if (ret) pr_err("%s: %s: failed to init wakeup: %d\n", mmc_hostname(card->host), __func__, ret); } device_enable_async_suspend(&card->dev); ret = device_add(&card->dev); Loading
drivers/mmc/core/host.c +28 −0 Original line number Diff line number Diff line Loading @@ -182,6 +182,34 @@ int mmc_retune(struct mmc_host *host) return err; } /** * mmc_host_may_gate_card - check if this card may be gated * @card: card to check. */ bool mmc_host_may_gate_card(struct mmc_card *card) { /* If there is no card we may gate it */ if (!card) return true; /* * SDIO3.0 card allows the clock to be gated off so check if * that is the case or not */ if (mmc_card_sdio(card) && card->cccr.async_intr_sup) return true; /* * Don't gate SDIO cards! These need to be clocked at all times * since they may be independent systems generating interrupts * and other events. The clock requests counter from the core will * go down to zero since the core does not need it, but we will not * gate the clock, because there is somebody out there that may still * be using it. */ return !(card->quirks & MMC_QUIRK_BROKEN_CLK_GATING); } static void mmc_retune_timer(struct timer_list *t) { struct mmc_host *host = from_timer(host, t, retune_timer); Loading
drivers/mmc/core/quirks.h +23 −0 Original line number Diff line number Diff line Loading @@ -153,6 +153,21 @@ static const struct mmc_fixup sdio_fixup_methods[] = { SDIO_FIXUP(SDIO_VENDOR_ID_TI_WL1251, SDIO_DEVICE_ID_TI_WL1251, add_quirk, MMC_QUIRK_DISABLE_CD), SDIO_FIXUP(SDIO_VENDOR_ID_MSM_QCA, SDIO_DEVICE_ID_MSM_QCA_AR6003_1, remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING), SDIO_FIXUP(SDIO_VENDOR_ID_MSM_QCA, SDIO_DEVICE_ID_MSM_QCA_AR6003_2, remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING), SDIO_FIXUP(SDIO_VENDOR_ID_MSM_QCA, SDIO_DEVICE_ID_MSM_QCA_AR6004_1, remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING), SDIO_FIXUP(SDIO_VENDOR_ID_MSM_QCA, SDIO_DEVICE_ID_MSM_QCA_AR6004_2, remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING), SDIO_FIXUP(SDIO_VENDOR_ID_MSM, SDIO_DEVICE_ID_MSM_WCN1314, remove_quirk, MMC_QUIRK_BROKEN_CLK_GATING), SDIO_FIXUP(SDIO_VENDOR_ID_TI, SDIO_DEVICE_ID_TI_WL1271, add_quirk, MMC_QUIRK_NONSTD_FUNC_IF), Loading @@ -168,6 +183,14 @@ static const struct mmc_fixup sdio_fixup_methods[] = { SDIO_FIXUP(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8887WLAN, add_limit_rate_quirk, 150000000), SDIO_FIXUP(SDIO_VENDOR_ID_QCA6574, SDIO_DEVICE_ID_QCA6574, add_quirk, MMC_QUIRK_QCA6574_SETTINGS), SDIO_FIXUP(SDIO_VENDOR_ID_QCA9377, SDIO_DEVICE_ID_QCA9377, add_quirk, MMC_QUIRK_QCA9377_SETTINGS), SDIO_FIXUP(SDIO_VENDOR_ID_QCA9379, SDIO_DEVICE_ID_QCA9379, add_quirk, MMC_QUIRK_QCA9379_SETTINGS), END_FIXUP }; Loading
drivers/mmc/core/sdio.c +91 −6 Original line number Diff line number Diff line Loading @@ -184,6 +184,23 @@ 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_EXTENSION, 0, &data); if (ret) goto out; if (data & SDIO_SUPPORT_ASYNC_INTR) { if (card->host->caps2 & MMC_CAP2_ASYNC_SDIO_IRQ_4BIT_MODE) { data |= SDIO_ENABLE_ASYNC_INTR; ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_INTERRUPT_EXTENSION, data, NULL); if (ret) goto out; card->cccr.async_intr_sup = 1; } } } /* if no uhs mode ensure we check for high speed */ Loading @@ -202,12 +219,61 @@ static int sdio_read_cccr(struct mmc_card *card, u32 ocr) return ret; } static void sdio_enable_vendor_specific_settings(struct mmc_card *card) { int ret; u8 settings; if (mmc_enable_qca6574_settings(card) || mmc_enable_qca9377_settings(card) || mmc_enable_qca9379_settings(card)) { ret = mmc_io_rw_direct(card, 1, 0, 0xF2, 0x0F, NULL); if (ret) { pr_crit("%s: failed to write to fn 0xf2 %d\n", mmc_hostname(card->host), ret); goto out; } ret = mmc_io_rw_direct(card, 0, 0, 0xF1, 0, &settings); if (ret) { pr_crit("%s: failed to read fn 0xf1 %d\n", mmc_hostname(card->host), ret); goto out; } settings |= 0x80; ret = mmc_io_rw_direct(card, 1, 0, 0xF1, settings, NULL); if (ret) { pr_crit("%s: failed to write to fn 0xf1 %d\n", mmc_hostname(card->host), ret); goto out; } ret = mmc_io_rw_direct(card, 0, 0, 0xF0, 0, &settings); if (ret) { pr_crit("%s: failed to read fn 0xf0 %d\n", mmc_hostname(card->host), ret); goto out; } settings |= 0x20; ret = mmc_io_rw_direct(card, 1, 0, 0xF0, settings, NULL); if (ret) { pr_crit("%s: failed to write to fn 0xf0 %d\n", mmc_hostname(card->host), ret); goto out; } } out: return; } static int sdio_enable_wide(struct mmc_card *card) { int ret; u8 ctrl; if (!(card->host->caps & MMC_CAP_4_BIT_DATA)) if (!(card->host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) return 0; if (card->cccr.low_speed && !card->cccr.wide_bus) Loading @@ -223,6 +289,9 @@ static int sdio_enable_wide(struct mmc_card *card) /* set as 4-bit bus width */ ctrl &= ~SDIO_BUS_WIDTH_MASK; if (card->host->caps & MMC_CAP_8_BIT_DATA) ctrl |= SDIO_BUS_WIDTH_8BIT; else if (card->host->caps & MMC_CAP_4_BIT_DATA) ctrl |= SDIO_BUS_WIDTH_4BIT; ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_IF, ctrl, NULL); Loading Loading @@ -264,7 +333,7 @@ static int sdio_disable_wide(struct mmc_card *card) int ret; u8 ctrl; if (!(card->host->caps & MMC_CAP_4_BIT_DATA)) if (!(card->host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) return 0; if (card->cccr.low_speed && !card->cccr.wide_bus) Loading @@ -274,10 +343,10 @@ static int sdio_disable_wide(struct mmc_card *card) if (ret) return ret; if (!(ctrl & SDIO_BUS_WIDTH_4BIT)) if (!(ctrl & (SDIO_BUS_WIDTH_4BIT | SDIO_BUS_WIDTH_8BIT))) return 0; ctrl &= ~SDIO_BUS_WIDTH_4BIT; ctrl &= ~(SDIO_BUS_WIDTH_4BIT | SDIO_BUS_WIDTH_8BIT); ctrl |= SDIO_BUS_ASYNC_INT; ret = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_IF, ctrl, NULL); Loading Loading @@ -495,6 +564,9 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card) if (err) return err; /* Vendor specific settings based on card quirks */ sdio_enable_vendor_specific_settings(card); speed &= ~SDIO_SPEED_BSS_MASK; speed |= bus_speed; err = mmc_io_rw_direct(card, 1, 0, SDIO_CCCR_SPEED, speed, NULL); Loading Loading @@ -790,7 +862,12 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, * Switch to wider bus (if supported). */ err = sdio_enable_4bit_bus(card); if (err) if (err > 0) { if (card->host->caps & MMC_CAP_8_BIT_DATA) mmc_set_bus_width(card->host, MMC_BUS_WIDTH_8); else if (card->host->caps & MMC_CAP_4_BIT_DATA) mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4); } else if (err) goto remove; } Loading Loading @@ -988,6 +1065,13 @@ static int mmc_sdio_resume(struct mmc_host *host) } else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) { /* We may have switched to 1-bit mode during suspend */ err = sdio_enable_4bit_bus(host->card); if (err > 0) { if (host->caps & MMC_CAP_8_BIT_DATA) mmc_set_bus_width(host, MMC_BUS_WIDTH_8); else if (host->caps & MMC_CAP_4_BIT_DATA) mmc_set_bus_width(host, MMC_BUS_WIDTH_4); err = 0; } } if (err) Loading @@ -1008,6 +1092,7 @@ static int mmc_sdio_resume(struct mmc_host *host) mmc_release_host(host); host->pm_flags &= ~MMC_PM_KEEP_POWER; host->pm_flags &= ~MMC_PM_WAKE_SDIO_IRQ; return err; } Loading
drivers/mmc/core/sdio_cis.c +8 −2 Original line number Diff line number Diff line Loading @@ -278,9 +278,15 @@ static int sdio_read_cis(struct mmc_card *card, struct sdio_func *func) break; /* null entries have no link field or data */ if (tpl_code == 0x00) if (tpl_code == 0x00) { if (card->cis.vendor == 0x70 && (card->cis.device == 0x2460 || card->cis.device == 0x0460 || card->cis.device == 0x23F1 || card->cis.device == 0x23F0)) break; continue; } ret = mmc_io_rw_direct(card, 0, 0, ptr++, 0, &tpl_link); if (ret) break; Loading