Merge tag 'mmc-v4.18' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
Pull MMC updates from Ulf Hansson: "MMC core: - Decrease polling rate for erase/trim/discard - Allow non-sleeping GPIOs for card detect - Improve mmc block removal path - Enable support for mmc_sw_reset() for SDIO cards - Add mmc_sw_reset() to allow users to do a soft reset of the card - Allow power delay to be tunable via DT - Allow card detect debounce delay to be tunable via DT - Enable new quirk to limit clock rate for Marvell 8887 chip - Don't show eMMC RPMB and BOOT areas in /proc/partitions - Add capability to avoid 3.3V signaling for fragile HWs MMC host: - Improve/fixup support for handle highmem pages - Remove depends on HAS_DMA in case of platform dependency - mvsdio: Enable support for erase/trim/discard - rtsx_usb: Enable support for erase/trim/discard - renesas_sdhi: Fix WP logic regressions - renesas_sdhi: Add r8a77965 support - renesas_sdhi: Add R8A77980 to whitelist - meson: Add optional support for device reset - meson: Add support for the Meson-AXG platform - dw_mmc: Add new driver for BlueField DW variant - mediatek: Add support for 64G DRAM DMA - sunxi: Deploy runtime PM support - jz4740: Add support for JZ4780 - jz4740: Enable support for DT based platforms - sdhci: Various improvement to timeout handling - sdhci: Disable support for HS200/HS400/UHS when no 1.8V support - sdhci-omap: Add support for controller in k2g SoC - sdhci-omap: Add workarounds for a couple of Erratas - sdhci-omap: Enable support for generic sdhci DT properties - sdhci-cadence: Re-send tune request to deal with errata - sdhci-pci: Fix 3.3V voltage switch for some BYT-based Intel controllers - sdhci-pci: Avoid 3.3V signaling on some NI 904x - sdhci-esdhc-imx: Use watermark levels for PIO access - sdhci-msm: Improve card detection handling - sdhci-msm: Add support voltage pad switching" * tag 'mmc-v4.18' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (104 commits) mmc: renesas_sdhi: really fix WP logic regressions mmc: mvsdio: Enable MMC_CAP_ERASE mmc: mvsdio: Respect card busy time out from mmc core mmc: sdhci-msm: Remove NO_CARD_NO_RESET quirk mmc: sunxi: Use ifdef rather than __maybe_unused mmc: mxmmc: Use ifdef rather than __maybe_unused mmc: mxmmc: include linux/highmem.h mmc: sunxi: mark PM functions as __maybe_unused mmc: Throttle calls to MMC_SEND_STATUS during mmc_do_erase() mmc: au1xmmc: handle highmem pages mmc: Allow non-sleeping GPIO cd mmc: sdhci-*: Don't emit error msg if sdhci_add_host() fails mmc: sd: Define name for default speed dtr mmc: core: Move calls to ->prepare_hs400_tuning() closer to mmc code mmc: sdhci-xenon: use match_string() helper mmc: wbsd: handle highmem pages mmc: ushc: handle highmem pages mmc: mxcmmc: handle highmem pages mmc: atmel-mci: use sg_copy_{from,to}_buffer mmc: android-goldfish: use sg_copy_{from,to}_buffer ...
This commit is contained in:
@@ -2351,7 +2351,8 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
|
||||
set_disk_ro(md->disk, md->read_only || default_ro);
|
||||
md->disk->flags = GENHD_FL_EXT_DEVT;
|
||||
if (area_type & (MMC_BLK_DATA_AREA_RPMB | MMC_BLK_DATA_AREA_BOOT))
|
||||
md->disk->flags |= GENHD_FL_NO_PART_SCAN;
|
||||
md->disk->flags |= GENHD_FL_NO_PART_SCAN
|
||||
| GENHD_FL_SUPPRESS_PARTITION_INFO;
|
||||
|
||||
/*
|
||||
* As discussed on lkml, GENHD_FL_REMOVABLE should:
|
||||
@@ -2965,9 +2966,11 @@ static void mmc_blk_remove(struct mmc_card *card)
|
||||
mmc_blk_remove_debugfs(card, md);
|
||||
mmc_blk_remove_parts(card, md);
|
||||
pm_runtime_get_sync(&card->dev);
|
||||
mmc_claim_host(card->host);
|
||||
mmc_blk_part_switch(card, md->part_type);
|
||||
mmc_release_host(card->host);
|
||||
if (md->part_curr != md->part_type) {
|
||||
mmc_claim_host(card->host);
|
||||
mmc_blk_part_switch(card, md->part_type);
|
||||
mmc_release_host(card->host);
|
||||
}
|
||||
if (card->type != MMC_TYPE_SD_COMBO)
|
||||
pm_runtime_disable(&card->dev);
|
||||
pm_runtime_put_noidle(&card->dev);
|
||||
|
@@ -149,6 +149,12 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
|
||||
card->quirks &= ~data;
|
||||
}
|
||||
|
||||
static inline void __maybe_unused add_limit_rate_quirk(struct mmc_card *card,
|
||||
int data)
|
||||
{
|
||||
card->quirk_max_rate = data;
|
||||
}
|
||||
|
||||
/*
|
||||
* Quirk add/remove for MMC products.
|
||||
*/
|
||||
|
@@ -50,9 +50,6 @@
|
||||
#include "sd_ops.h"
|
||||
#include "sdio_ops.h"
|
||||
|
||||
/* If the device is not responding */
|
||||
#define MMC_CORE_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */
|
||||
|
||||
/* The max erase timeout, used when host->max_busy_timeout isn't specified */
|
||||
#define MMC_ERASE_TIMEOUT_MS (60 * 1000) /* 60 s */
|
||||
|
||||
@@ -1484,6 +1481,17 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
|
||||
|
||||
}
|
||||
|
||||
void mmc_set_initial_signal_voltage(struct mmc_host *host)
|
||||
{
|
||||
/* Try to set signal voltage to 3.3V but fall back to 1.8v or 1.2v */
|
||||
if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330))
|
||||
dev_dbg(mmc_dev(host), "Initial signal voltage of 3.3v\n");
|
||||
else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180))
|
||||
dev_dbg(mmc_dev(host), "Initial signal voltage of 1.8v\n");
|
||||
else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120))
|
||||
dev_dbg(mmc_dev(host), "Initial signal voltage of 1.2v\n");
|
||||
}
|
||||
|
||||
int mmc_host_set_uhs_voltage(struct mmc_host *host)
|
||||
{
|
||||
u32 clock;
|
||||
@@ -1646,19 +1654,13 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
|
||||
/* Set initial state and call mmc_set_ios */
|
||||
mmc_set_initial_state(host);
|
||||
|
||||
/* Try to set signal voltage to 3.3V but fall back to 1.8v or 1.2v */
|
||||
if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330))
|
||||
dev_dbg(mmc_dev(host), "Initial signal voltage of 3.3v\n");
|
||||
else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180))
|
||||
dev_dbg(mmc_dev(host), "Initial signal voltage of 1.8v\n");
|
||||
else if (!mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120))
|
||||
dev_dbg(mmc_dev(host), "Initial signal voltage of 1.2v\n");
|
||||
mmc_set_initial_signal_voltage(host);
|
||||
|
||||
/*
|
||||
* This delay should be sufficient to allow the power supply
|
||||
* to reach the minimum voltage.
|
||||
*/
|
||||
mmc_delay(10);
|
||||
mmc_delay(host->ios.power_delay_ms);
|
||||
|
||||
mmc_pwrseq_post_power_on(host);
|
||||
|
||||
@@ -1671,7 +1673,7 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
|
||||
* This delay must be at least 74 clock sizes, or 1 ms, or the
|
||||
* time required to reach a stable voltage.
|
||||
*/
|
||||
mmc_delay(10);
|
||||
mmc_delay(host->ios.power_delay_ms);
|
||||
}
|
||||
|
||||
void mmc_power_off(struct mmc_host *host)
|
||||
@@ -1967,6 +1969,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
|
||||
unsigned int qty = 0, busy_timeout = 0;
|
||||
bool use_r1b_resp = false;
|
||||
unsigned long timeout;
|
||||
int loop_udelay=64, udelay_max=32768;
|
||||
int err;
|
||||
|
||||
mmc_retune_hold(card->host);
|
||||
@@ -2091,9 +2094,15 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
|
||||
err = -EIO;
|
||||
goto out;
|
||||
}
|
||||
if ((cmd.resp[0] & R1_READY_FOR_DATA) &&
|
||||
R1_CURRENT_STATE(cmd.resp[0]) != R1_STATE_PRG)
|
||||
break;
|
||||
|
||||
usleep_range(loop_udelay, loop_udelay*2);
|
||||
if (loop_udelay < udelay_max)
|
||||
loop_udelay *= 2;
|
||||
} while (1);
|
||||
|
||||
} while (!(cmd.resp[0] & R1_READY_FOR_DATA) ||
|
||||
(R1_CURRENT_STATE(cmd.resp[0]) == R1_STATE_PRG));
|
||||
out:
|
||||
mmc_retune_release(card->host);
|
||||
return err;
|
||||
@@ -2435,22 +2444,46 @@ int mmc_hw_reset(struct mmc_host *host)
|
||||
return -EINVAL;
|
||||
|
||||
mmc_bus_get(host);
|
||||
if (!host->bus_ops || host->bus_dead || !host->bus_ops->reset) {
|
||||
if (!host->bus_ops || host->bus_dead || !host->bus_ops->hw_reset) {
|
||||
mmc_bus_put(host);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
ret = host->bus_ops->reset(host);
|
||||
ret = host->bus_ops->hw_reset(host);
|
||||
mmc_bus_put(host);
|
||||
|
||||
if (ret)
|
||||
pr_warn("%s: tried to reset card, got error %d\n",
|
||||
pr_warn("%s: tried to HW reset card, got error %d\n",
|
||||
mmc_hostname(host), ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_hw_reset);
|
||||
|
||||
int mmc_sw_reset(struct mmc_host *host)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!host->card)
|
||||
return -EINVAL;
|
||||
|
||||
mmc_bus_get(host);
|
||||
if (!host->bus_ops || host->bus_dead || !host->bus_ops->sw_reset) {
|
||||
mmc_bus_put(host);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
ret = host->bus_ops->sw_reset(host);
|
||||
mmc_bus_put(host);
|
||||
|
||||
if (ret)
|
||||
pr_warn("%s: tried to SW reset card, got error %d\n",
|
||||
mmc_hostname(host), ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_sw_reset);
|
||||
|
||||
static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
|
||||
{
|
||||
host->f_init = freq;
|
||||
|
@@ -32,7 +32,8 @@ struct mmc_bus_ops {
|
||||
int (*power_restore)(struct mmc_host *);
|
||||
int (*alive)(struct mmc_host *);
|
||||
int (*shutdown)(struct mmc_host *);
|
||||
int (*reset)(struct mmc_host *);
|
||||
int (*hw_reset)(struct mmc_host *);
|
||||
int (*sw_reset)(struct mmc_host *);
|
||||
};
|
||||
|
||||
void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
|
||||
@@ -51,6 +52,7 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
|
||||
int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr);
|
||||
int mmc_host_set_uhs_voltage(struct mmc_host *host);
|
||||
int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
|
||||
void mmc_set_initial_signal_voltage(struct mmc_host *host);
|
||||
void mmc_set_timing(struct mmc_host *host, unsigned int timing);
|
||||
void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
|
||||
int mmc_select_drive_strength(struct mmc_card *card, unsigned int max_dtr,
|
||||
|
@@ -143,9 +143,6 @@ int mmc_retune(struct mmc_host *host)
|
||||
goto out;
|
||||
|
||||
return_to_hs400 = true;
|
||||
|
||||
if (host->ops->prepare_hs400_tuning)
|
||||
host->ops->prepare_hs400_tuning(host, &host->ios);
|
||||
}
|
||||
|
||||
err = mmc_execute_tuning(host->card);
|
||||
@@ -179,7 +176,7 @@ static void mmc_retune_timer(struct timer_list *t)
|
||||
int mmc_of_parse(struct mmc_host *host)
|
||||
{
|
||||
struct device *dev = host->parent;
|
||||
u32 bus_width, drv_type;
|
||||
u32 bus_width, drv_type, cd_debounce_delay_ms;
|
||||
int ret;
|
||||
bool cd_cap_invert, cd_gpio_invert = false;
|
||||
bool ro_cap_invert, ro_gpio_invert = false;
|
||||
@@ -230,11 +227,16 @@ int mmc_of_parse(struct mmc_host *host)
|
||||
} else {
|
||||
cd_cap_invert = device_property_read_bool(dev, "cd-inverted");
|
||||
|
||||
if (device_property_read_u32(dev, "cd-debounce-delay-ms",
|
||||
&cd_debounce_delay_ms))
|
||||
cd_debounce_delay_ms = 200;
|
||||
|
||||
if (device_property_read_bool(dev, "broken-cd"))
|
||||
host->caps |= MMC_CAP_NEEDS_POLL;
|
||||
|
||||
ret = mmc_gpiod_request_cd(host, "cd", 0, true,
|
||||
0, &cd_gpio_invert);
|
||||
cd_debounce_delay_ms,
|
||||
&cd_gpio_invert);
|
||||
if (!ret)
|
||||
dev_info(host->parent, "Got CD GPIO\n");
|
||||
else if (ret != -ENOENT && ret != -ENOSYS)
|
||||
@@ -338,6 +340,9 @@ int mmc_of_parse(struct mmc_host *host)
|
||||
host->dsr_req = 0;
|
||||
}
|
||||
|
||||
device_property_read_u32(dev, "post-power-on-delay-ms",
|
||||
&host->ios.power_delay_ms);
|
||||
|
||||
return mmc_pwrseq_alloc(host);
|
||||
}
|
||||
|
||||
@@ -403,6 +408,7 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
|
||||
host->max_blk_count = PAGE_SIZE / 512;
|
||||
|
||||
host->fixed_drv_type = -EINVAL;
|
||||
host->ios.power_delay_ms = 10;
|
||||
|
||||
return host;
|
||||
}
|
||||
|
@@ -1282,6 +1282,10 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
|
||||
|
||||
mmc_set_bus_speed(card);
|
||||
|
||||
/* Prepare tuning for HS400 mode. */
|
||||
if (host->ops->prepare_hs400_tuning)
|
||||
host->ops->prepare_hs400_tuning(host, &host->ios);
|
||||
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
@@ -1830,6 +1834,14 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
||||
}
|
||||
}
|
||||
|
||||
if (host->caps2 & MMC_CAP2_AVOID_3_3V &&
|
||||
host->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
|
||||
pr_err("%s: Host failed to negotiate down from 3.3V\n",
|
||||
mmc_hostname(host));
|
||||
err = -EINVAL;
|
||||
goto free_card;
|
||||
}
|
||||
|
||||
if (!oldcard)
|
||||
host->card = card;
|
||||
|
||||
@@ -2117,7 +2129,7 @@ static int mmc_can_reset(struct mmc_card *card)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int mmc_reset(struct mmc_host *host)
|
||||
static int _mmc_hw_reset(struct mmc_host *host)
|
||||
{
|
||||
struct mmc_card *card = host->card;
|
||||
|
||||
@@ -2151,7 +2163,7 @@ static const struct mmc_bus_ops mmc_ops = {
|
||||
.runtime_resume = mmc_runtime_resume,
|
||||
.alive = mmc_alive,
|
||||
.shutdown = mmc_shutdown,
|
||||
.reset = mmc_reset,
|
||||
.hw_reset = _mmc_hw_reset,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@@ -40,14 +40,18 @@ static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq,
|
||||
struct gpio_descs *reset_gpios = pwrseq->reset_gpios;
|
||||
|
||||
if (!IS_ERR(reset_gpios)) {
|
||||
int i;
|
||||
int values[reset_gpios->ndescs];
|
||||
int i, *values;
|
||||
int nvalues = reset_gpios->ndescs;
|
||||
|
||||
for (i = 0; i < reset_gpios->ndescs; i++)
|
||||
values = kmalloc_array(nvalues, sizeof(int), GFP_KERNEL);
|
||||
if (!values)
|
||||
return;
|
||||
|
||||
for (i = 0; i < nvalues; i++)
|
||||
values[i] = value;
|
||||
|
||||
gpiod_set_array_value_cansleep(
|
||||
reset_gpios->ndescs, reset_gpios->desc, values);
|
||||
gpiod_set_array_value_cansleep(nvalues, reset_gpios->desc, values);
|
||||
kfree(values);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -132,6 +132,9 @@ static const struct mmc_fixup sdio_fixup_methods[] = {
|
||||
SDIO_FIXUP(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8797_F0,
|
||||
add_quirk, MMC_QUIRK_BROKEN_IRQ_POLLING),
|
||||
|
||||
SDIO_FIXUP(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8887WLAN,
|
||||
add_limit_rate_quirk, 150000000),
|
||||
|
||||
END_FIXUP
|
||||
};
|
||||
|
||||
|
@@ -1058,6 +1058,14 @@ retry:
|
||||
mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
|
||||
}
|
||||
}
|
||||
|
||||
if (host->caps2 & MMC_CAP2_AVOID_3_3V &&
|
||||
host->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
|
||||
pr_err("%s: Host failed to negotiate down from 3.3V\n",
|
||||
mmc_hostname(host));
|
||||
err = -EINVAL;
|
||||
goto free_card;
|
||||
}
|
||||
done:
|
||||
host->card = card;
|
||||
return 0;
|
||||
@@ -1214,7 +1222,7 @@ static int mmc_sd_runtime_resume(struct mmc_host *host)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mmc_sd_reset(struct mmc_host *host)
|
||||
static int mmc_sd_hw_reset(struct mmc_host *host)
|
||||
{
|
||||
mmc_power_cycle(host, host->card->ocr);
|
||||
return mmc_sd_init_card(host, host->card->ocr, host->card);
|
||||
@@ -1229,7 +1237,7 @@ static const struct mmc_bus_ops mmc_sd_ops = {
|
||||
.resume = mmc_sd_resume,
|
||||
.alive = mmc_sd_alive,
|
||||
.shutdown = mmc_sd_suspend,
|
||||
.reset = mmc_sd_reset,
|
||||
.hw_reset = mmc_sd_hw_reset,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@@ -444,6 +444,7 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card)
|
||||
unsigned int bus_speed, timing;
|
||||
int err;
|
||||
unsigned char speed;
|
||||
unsigned int max_rate;
|
||||
|
||||
/*
|
||||
* If the host doesn't support any of the UHS-I modes, fallback on
|
||||
@@ -500,9 +501,12 @@ static int sdio_set_bus_speed_mode(struct mmc_card *card)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
max_rate = min_not_zero(card->quirk_max_rate,
|
||||
card->sw_caps.uhs_max_dtr);
|
||||
|
||||
if (bus_speed) {
|
||||
mmc_set_timing(card->host, timing);
|
||||
mmc_set_clock(card->host, card->sw_caps.uhs_max_dtr);
|
||||
mmc_set_clock(card->host, max_rate);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -788,6 +792,14 @@ try_again:
|
||||
if (err)
|
||||
goto remove;
|
||||
}
|
||||
|
||||
if (host->caps2 & MMC_CAP2_AVOID_3_3V &&
|
||||
host->ios.signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
|
||||
pr_err("%s: Host failed to negotiate down from 3.3V\n",
|
||||
mmc_hostname(host));
|
||||
err = -EINVAL;
|
||||
goto remove;
|
||||
}
|
||||
finish:
|
||||
if (!oldcard)
|
||||
host->card = card;
|
||||
@@ -801,6 +813,22 @@ err:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int mmc_sdio_reinit_card(struct mmc_host *host, bool powered_resume)
|
||||
{
|
||||
int ret;
|
||||
|
||||
sdio_reset(host);
|
||||
mmc_go_idle(host);
|
||||
mmc_send_if_cond(host, host->card->ocr);
|
||||
|
||||
ret = mmc_send_io_op_cond(host, 0, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return mmc_sdio_init_card(host, host->card->ocr, host->card,
|
||||
powered_resume);
|
||||
}
|
||||
|
||||
/*
|
||||
* Host is being removed. Free up the current card.
|
||||
*/
|
||||
@@ -948,14 +976,7 @@ static int mmc_sdio_resume(struct mmc_host *host)
|
||||
|
||||
/* No need to reinitialize powered-resumed nonremovable cards */
|
||||
if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) {
|
||||
sdio_reset(host);
|
||||
mmc_go_idle(host);
|
||||
mmc_send_if_cond(host, host->card->ocr);
|
||||
err = mmc_send_io_op_cond(host, 0, NULL);
|
||||
if (!err)
|
||||
err = mmc_sdio_init_card(host, host->card->ocr,
|
||||
host->card,
|
||||
mmc_card_keep_power(host));
|
||||
err = mmc_sdio_reinit_card(host, mmc_card_keep_power(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);
|
||||
@@ -978,8 +999,6 @@ static int mmc_sdio_power_restore(struct mmc_host *host)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mmc_claim_host(host);
|
||||
|
||||
/*
|
||||
* Reset the card by performing the same steps that are taken by
|
||||
* mmc_rescan_try_freq() and mmc_attach_sdio() during a "normal" probe.
|
||||
@@ -997,20 +1016,12 @@ static int mmc_sdio_power_restore(struct mmc_host *host)
|
||||
*
|
||||
*/
|
||||
|
||||
sdio_reset(host);
|
||||
mmc_go_idle(host);
|
||||
mmc_send_if_cond(host, host->card->ocr);
|
||||
mmc_claim_host(host);
|
||||
|
||||
ret = mmc_send_io_op_cond(host, 0, NULL);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
ret = mmc_sdio_init_card(host, host->card->ocr, host->card,
|
||||
mmc_card_keep_power(host));
|
||||
ret = mmc_sdio_reinit_card(host, mmc_card_keep_power(host));
|
||||
if (!ret && host->sdio_irqs)
|
||||
mmc_signal_sdio_irq(host);
|
||||
|
||||
out:
|
||||
mmc_release_host(host);
|
||||
|
||||
return ret;
|
||||
@@ -1039,12 +1050,24 @@ static int mmc_sdio_runtime_resume(struct mmc_host *host)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mmc_sdio_reset(struct mmc_host *host)
|
||||
static int mmc_sdio_hw_reset(struct mmc_host *host)
|
||||
{
|
||||
mmc_power_cycle(host, host->card->ocr);
|
||||
return mmc_sdio_power_restore(host);
|
||||
}
|
||||
|
||||
static int mmc_sdio_sw_reset(struct mmc_host *host)
|
||||
{
|
||||
mmc_set_clock(host, host->f_init);
|
||||
sdio_reset(host);
|
||||
mmc_go_idle(host);
|
||||
|
||||
mmc_set_initial_state(host);
|
||||
mmc_set_initial_signal_voltage(host);
|
||||
|
||||
return mmc_sdio_reinit_card(host, 0);
|
||||
}
|
||||
|
||||
static const struct mmc_bus_ops mmc_sdio_ops = {
|
||||
.remove = mmc_sdio_remove,
|
||||
.detect = mmc_sdio_detect,
|
||||
@@ -1055,7 +1078,8 @@ static const struct mmc_bus_ops mmc_sdio_ops = {
|
||||
.runtime_resume = mmc_sdio_runtime_resume,
|
||||
.power_restore = mmc_sdio_power_restore,
|
||||
.alive = mmc_sdio_alive,
|
||||
.reset = mmc_sdio_reset,
|
||||
.hw_reset = mmc_sdio_hw_reset,
|
||||
.sw_reset = mmc_sdio_sw_reset,
|
||||
};
|
||||
|
||||
|
||||
|
@@ -28,15 +28,17 @@ struct mmc_gpio {
|
||||
irqreturn_t (*cd_gpio_isr)(int irq, void *dev_id);
|
||||
char *ro_label;
|
||||
char cd_label[0];
|
||||
u32 cd_debounce_delay_ms;
|
||||
};
|
||||
|
||||
static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id)
|
||||
{
|
||||
/* Schedule a card detection after a debounce timeout */
|
||||
struct mmc_host *host = dev_id;
|
||||
struct mmc_gpio *ctx = host->slot.handler_priv;
|
||||
|
||||
host->trigger_card_event = true;
|
||||
mmc_detect_change(host, msecs_to_jiffies(200));
|
||||
mmc_detect_change(host, msecs_to_jiffies(ctx->cd_debounce_delay_ms));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@@ -49,6 +51,7 @@ int mmc_gpio_alloc(struct mmc_host *host)
|
||||
|
||||
if (ctx) {
|
||||
ctx->ro_label = ctx->cd_label + len;
|
||||
ctx->cd_debounce_delay_ms = 200;
|
||||
snprintf(ctx->cd_label, len, "%s cd", dev_name(host->parent));
|
||||
snprintf(ctx->ro_label, len, "%s ro", dev_name(host->parent));
|
||||
host->slot.handler_priv = ctx;
|
||||
@@ -76,15 +79,22 @@ EXPORT_SYMBOL(mmc_gpio_get_ro);
|
||||
int mmc_gpio_get_cd(struct mmc_host *host)
|
||||
{
|
||||
struct mmc_gpio *ctx = host->slot.handler_priv;
|
||||
int cansleep;
|
||||
|
||||
if (!ctx || !ctx->cd_gpio)
|
||||
return -ENOSYS;
|
||||
|
||||
if (ctx->override_cd_active_level)
|
||||
return !gpiod_get_raw_value_cansleep(ctx->cd_gpio) ^
|
||||
!!(host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH);
|
||||
cansleep = gpiod_cansleep(ctx->cd_gpio);
|
||||
if (ctx->override_cd_active_level) {
|
||||
int value = cansleep ?
|
||||
gpiod_get_raw_value_cansleep(ctx->cd_gpio) :
|
||||
gpiod_get_raw_value(ctx->cd_gpio);
|
||||
return !value ^ !!(host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH);
|
||||
}
|
||||
|
||||
return gpiod_get_value_cansleep(ctx->cd_gpio);
|
||||
return cansleep ?
|
||||
gpiod_get_value_cansleep(ctx->cd_gpio) :
|
||||
gpiod_get_value(ctx->cd_gpio);
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_gpio_get_cd);
|
||||
|
||||
@@ -261,7 +271,7 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
|
||||
if (debounce) {
|
||||
ret = gpiod_set_debounce(desc, debounce);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
ctx->cd_debounce_delay_ms = debounce;
|
||||
}
|
||||
|
||||
if (gpio_invert)
|
||||
|
Reference in New Issue
Block a user