// SPDX-License-Identifier: GPL-2.0-only /* * linux/drivers/mmc/core/sd.c * * Copyright (C) 2003-2004 Russell King, All Rights Reserved. * SD support Copyright (C) 2004 Ian Molton, All Rights Reserved. * Copyright (C) 2005-2007 Pierre Ossman, All Rights Reserved.
*/
/* * Given the decoded CSD structure, decode the raw CID to our CID structure.
*/ void mmc_decode_cid(struct mmc_card *card)
{
u32 *resp = card->raw_cid;
/* * Add the raw card ID (cid) data to the entropy pool. It doesn't * matter that not all of it is unique, it's just bonus entropy.
*/
add_device_randomness(&card->raw_cid, sizeof(card->raw_cid));
/* * SD doesn't currently have a version field so we will * have to assume we can parse this.
*/
card->cid.manfid = unstuff_bits(resp, 120, 8);
card->cid.oemid = unstuff_bits(resp, 104, 16);
card->cid.prod_name[0] = unstuff_bits(resp, 96, 8);
card->cid.prod_name[1] = unstuff_bits(resp, 88, 8);
card->cid.prod_name[2] = unstuff_bits(resp, 80, 8);
card->cid.prod_name[3] = unstuff_bits(resp, 72, 8);
card->cid.prod_name[4] = unstuff_bits(resp, 64, 8);
card->cid.hwrev = unstuff_bits(resp, 60, 4);
card->cid.fwrev = unstuff_bits(resp, 56, 4);
card->cid.serial = unstuff_bits(resp, 24, 32);
card->cid.year = unstuff_bits(resp, 12, 8);
card->cid.month = unstuff_bits(resp, 8, 4);
card->cid.year += 2000; /* SD cards year offset */
/* some product names may include trailing whitespace */
strim(card->cid.prod_name);
}
/* * Given a 128-bit response, decode to our card CSD structure.
*/ staticint mmc_decode_csd(struct mmc_card *card, bool is_sduc)
{ struct mmc_csd *csd = &card->csd; unsignedint e, m, csd_struct;
u32 *resp = card->raw_csd;
if (unstuff_bits(resp, 13, 1))
mmc_card_set_readonly(card); break; case 1: case 2: /* * This is a block-addressed SDHC, SDXC or SDUC card. * Most interesting fields are unused and have fixed * values. To avoid getting tripped by buggy cards, * we assume those fixed values ourselves.
*/
mmc_card_set_blockaddr(card);
/* SD Spec says: any SD Card shall set at least bits 0 and 2 */ if (!(scr->bus_widths & SD_SCR_BUS_WIDTH_1) ||
!(scr->bus_widths & SD_SCR_BUS_WIDTH_4)) {
pr_err("%s: invalid bus width\n", mmc_hostname(card->host)); return -EINVAL;
}
return 0;
}
/* * Fetch and process SD Status register.
*/ staticint mmc_read_ssr(struct mmc_card *card)
{ unsignedint au, es, et, eo;
__be32 *raw_ssr;
u32 resp[4] = {};
u8 discard_support; int i;
if (!(card->csd.cmdclass & CCC_APP_SPEC)) {
pr_warn("%s: card lacks mandatory SD Status function\n",
mmc_hostname(card->host)); return 0;
}
raw_ssr = kmalloc(sizeof(card->raw_ssr), GFP_KERNEL); if (!raw_ssr) return -ENOMEM;
if (mmc_app_sd_status(card, raw_ssr)) {
pr_warn("%s: problem reading SD Status register\n",
mmc_hostname(card->host));
kfree(raw_ssr); return 0;
}
for (i = 0; i < 16; i++)
card->raw_ssr[i] = be32_to_cpu(raw_ssr[i]);
kfree(raw_ssr);
/* * unstuff_bits only works with four u32s so we have to offset the * bitfield positions accordingly.
*/
au = unstuff_bits(card->raw_ssr, 428 - 384, 4); if (au) { if (au <= 9 || card->scr.sda_spec3) {
card->ssr.au = sd_au_size[au];
es = unstuff_bits(card->raw_ssr, 408 - 384, 16);
et = unstuff_bits(card->raw_ssr, 402 - 384, 6); if (es && et) {
eo = unstuff_bits(card->raw_ssr, 400 - 384, 2);
card->ssr.erase_timeout = (et * 1000) / es;
card->ssr.erase_offset = eo * 1000;
}
} else {
pr_warn("%s: SD Status: Invalid Allocation Unit size\n",
mmc_hostname(card->host));
}
}
/* * starting SD5.1 discard is supported if DISCARD_SUPPORT (b313) is set
*/
resp[3] = card->raw_ssr[6];
discard_support = unstuff_bits(resp, 313 - 288, 1);
card->erase_arg = (card->scr.sda_specx && discard_support) ?
SD_DISCARD_ARG : SD_ERASE_ARG;
return 0;
}
/* * Fetches and decodes switch information
*/ staticint mmc_read_switch(struct mmc_card *card)
{ int err;
u8 *status;
status = kmalloc(64, GFP_KERNEL); if (!status) return -ENOMEM;
/* * Find out the card's support bits with a mode 0 operation. * The argument does not matter, as the support bits do not * change with the arguments.
*/
err = mmc_sd_switch(card, SD_SWITCH_CHECK, 0, 0, status); if (err) { /* * If the host or the card can't do the switch, * fail more gracefully.
*/ if (err != -EINVAL && err != -ENOSYS && err != -EFAULT) goto out;
pr_warn("%s: problem reading Bus Speed modes\n",
mmc_hostname(card->host));
err = 0;
goto out;
}
if (status[13] & SD_MODE_HIGH_SPEED)
card->sw_caps.hs_max_dtr = HIGH_SPEED_MAX_DTR;
if (card->scr.sda_spec3) {
card->sw_caps.sd3_bus_mode = status[13]; /* Driver Strengths supported by the card */
card->sw_caps.sd3_drv_type = status[9];
card->sw_caps.sd3_curr_limit = status[7] | status[6] << 8;
}
out:
kfree(status);
return err;
}
/* * Test if the card supports high-speed mode and, if so, switch to it.
*/ int mmc_sd_switch_hs(struct mmc_card *card)
{ int err;
u8 *status;
if (card->scr.sda_vsn < SCR_SPEC_VER_1) return 0;
if (!(card->csd.cmdclass & CCC_SWITCH)) return 0;
if (!(card->host->caps & MMC_CAP_SD_HIGHSPEED)) return 0;
if (card->sw_caps.hs_max_dtr == 0) return 0;
status = kmalloc(64, GFP_KERNEL); if (!status) return -ENOMEM;
if (drive_strength) {
err = mmc_sd_switch(card, SD_SWITCH_SET, 2,
drive_strength, status); if (err) return err; if ((status[15] & 0xF) != drive_strength) {
pr_warn("%s: Problem setting drive strength!\n",
mmc_hostname(card->host)); return 0;
}
card->drive_strength = drive_strength;
}
if (drv_type)
mmc_set_driver_type(card->host, drv_type);
return 0;
}
staticvoid sd_update_bus_speed_mode(struct mmc_card *card)
{ /* * If the host doesn't support any of the UHS-I modes, fallback on * default speed.
*/ if (!mmc_host_can_uhs(card->host)) {
card->sd_bus_speed = 0; return;
}
if ((status[16] & 0xF) != card->sd_bus_speed)
pr_warn("%s: Problem setting bus speed mode!\n",
mmc_hostname(card->host)); else {
mmc_set_timing(card->host, timing);
mmc_set_clock(card->host, card->sw_caps.uhs_max_dtr);
}
return 0;
}
/* Get host's max current setting at its current voltage */ static u32 sd_get_host_max_current(struct mmc_host *host)
{
u32 voltage, max_current;
voltage = 1 << host->ios.vdd; switch (voltage) { case MMC_VDD_165_195:
max_current = host->max_current_180; break; case MMC_VDD_29_30: case MMC_VDD_30_31:
max_current = host->max_current_300; break; case MMC_VDD_32_33: case MMC_VDD_33_34:
max_current = host->max_current_330; break; default:
max_current = 0;
}
return max_current;
}
staticint sd_set_current_limit(struct mmc_card *card, u8 *status)
{ int current_limit = SD_SET_CURRENT_NO_CHANGE; int err;
u32 max_current;
/* * Current limit switch is only defined for SDR50, SDR104, and DDR50 * bus speed modes. For other bus speed modes, we do not change the * current limit.
*/ if ((card->sd_bus_speed != UHS_SDR50_BUS_SPEED) &&
(card->sd_bus_speed != UHS_SDR104_BUS_SPEED) &&
(card->sd_bus_speed != UHS_DDR50_BUS_SPEED)) return 0;
/* * Host has different current capabilities when operating at * different voltages, so find out its max current first.
*/
max_current = sd_get_host_max_current(card->host);
/* * We only check host's capability here, if we set a limit that is * higher than the card's maximum current, the card will be using its * maximum current, e.g. if the card's maximum current is 300ma, and * when we set current limit to 200ma, the card will draw 200ma, and * when we set current limit to 400/600/800ma, the card will draw its * maximum 300ma from the host. * * The above is incorrect: if we try to set a current limit that is * not supported by the card, the card can rightfully error out the * attempt, and remain at the default current limit. This results * in a 300mA card being limited to 200mA even though the host * supports 800mA. Failures seen with SanDisk 8GB UHS cards with * an iMX6 host. --rmk
*/ if (max_current >= 800 &&
card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_800)
current_limit = SD_SET_CURRENT_LIMIT_800; elseif (max_current >= 600 &&
card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_600)
current_limit = SD_SET_CURRENT_LIMIT_600; elseif (max_current >= 400 &&
card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_400)
current_limit = SD_SET_CURRENT_LIMIT_400; elseif (max_current >= 200 &&
card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_200)
current_limit = SD_SET_CURRENT_LIMIT_200;
if (current_limit != SD_SET_CURRENT_NO_CHANGE) {
err = mmc_sd_switch(card, SD_SWITCH_SET, 3,
current_limit, status); if (err) return err;
if (((status[15] >> 4) & 0x0F) != current_limit)
pr_warn("%s: Problem setting current limit!\n",
mmc_hostname(card->host));
}
return 0;
}
/* * Determine if the card should tune or not.
*/ staticbool mmc_sd_use_tuning(struct mmc_card *card)
{ /* * SPI mode doesn't define CMD19 and tuning is only valid for SDR50 and * SDR104 mode SD-cards. Note that tuning is mandatory for SDR104.
*/ if (mmc_host_is_spi(card->host)) returnfalse;
switch (card->host->ios.timing) { case MMC_TIMING_UHS_SDR50: case MMC_TIMING_UHS_SDR104: returntrue; case MMC_TIMING_UHS_DDR50: return !mmc_card_no_uhs_ddr50_tuning(card);
}
returnfalse;
}
/* * UHS-I specific initialization procedure
*/ staticint mmc_sd_init_uhs_card(struct mmc_card *card)
{ int err;
u8 *status;
if (!(card->csd.cmdclass & CCC_SWITCH)) return 0;
status = kmalloc(64, GFP_KERNEL); if (!status) return -ENOMEM;
/* Set 4-bit bus width */
err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4); if (err) goto out;
mmc_set_bus_width(card->host, MMC_BUS_WIDTH_4);
/* * Select the bus speed mode depending on host * and card capability.
*/
sd_update_bus_speed_mode(card);
/* Set the driver strength for the card */
err = sd_select_driver_type(card, status); if (err) goto out;
/* Set current limit for the card */
err = sd_set_current_limit(card, status); if (err) goto out;
/* Set bus speed mode of the card */
err = sd_set_bus_speed_mode(card, status); if (err) goto out;
if (mmc_sd_use_tuning(card)) {
err = mmc_execute_tuning(card);
/* * As SD Specifications Part1 Physical Layer Specification * Version 3.01 says, CMD19 tuning is available for unlocked * cards in transfer state of 1.8V signaling mode. The small * difference between v3.00 and 3.01 spec means that CMD19 * tuning is also available for DDR50 mode.
*/ if (err && card->host->ios.timing == MMC_TIMING_UHS_DDR50) {
pr_warn("%s: ddr50 tuning failed\n",
mmc_hostname(card->host));
err = 0;
}
}
/* * Fetch CID from card.
*/ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
{ int err;
u32 max_current; int retries = 10;
u32 pocr = ocr;
try_again: if (!retries) {
ocr &= ~SD_OCR_S18R;
pr_warn("%s: Skipping voltage switch\n", mmc_hostname(host));
}
/* * Since we're changing the OCR value, we seem to * need to tell some cards to go back to the idle * state. We wait 1ms to give cards time to * respond.
*/
mmc_go_idle(host);
/* * If SD_SEND_IF_COND indicates an SD 2.0 * compliant card and we should set bit 30 * of the ocr to indicate that we can handle * block-addressed SDHC cards.
*/
err = mmc_send_if_cond(host, ocr); if (!err) {
ocr |= SD_OCR_CCS; /* Set HO2T as well - SDUC card won't respond otherwise */
ocr |= SD_OCR_2T;
}
/* * If the host supports one of UHS-I modes, request the card * to switch to 1.8V signaling level. If the card has failed * repeatedly to switch however, skip this.
*/ if (retries && mmc_host_can_uhs(host))
ocr |= SD_OCR_S18R;
/* * If the host can supply more than 150mA at current voltage, * XPC should be set to 1.
*/
max_current = sd_get_host_max_current(host); if (max_current > 150)
ocr |= SD_OCR_XPC;
err = mmc_send_app_op_cond(host, ocr, rocr); if (err) return err;
/* * In case the S18A bit is set in the response, let's start the signal * voltage switch procedure. SPI mode doesn't support CMD11. * Note that, according to the spec, the S18A bit is not valid unless * the CCS bit is set as well. We deliberately deviate from the spec in * regards to this, which allows UHS-I to be supported for SDSC cards.
*/ if (!mmc_host_is_spi(host) && (ocr & SD_OCR_S18R) &&
rocr && (*rocr & SD_ROCR_S18A)) {
err = mmc_set_uhs_voltage(host, pocr); if (err == -EAGAIN) {
retries--; goto try_again;
} elseif (err) {
retries = 0; goto try_again;
}
}
err = mmc_send_cid(host, cid); return err;
}
int mmc_sd_get_csd(struct mmc_card *card, bool is_sduc)
{ int err;
/* * Fetch CSD from card.
*/
err = mmc_send_csd(card, card->raw_csd); if (err) return err;
err = mmc_decode_csd(card, is_sduc); if (err) return err;
return 0;
}
int mmc_sd_get_ro(struct mmc_host *host)
{ int ro;
/* * Some systems don't feature a write-protect pin and don't need one. * E.g. because they only have micro-SD card slot. For those systems * assume that the SD card is always read-write.
*/ if (host->caps2 & MMC_CAP2_NO_WRITE_PROTECT) return 0;
if (!host->ops->get_ro) return -1;
ro = host->ops->get_ro(host);
return ro;
}
int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card, bool reinit)
{ int err;
if (!reinit) { /* * Fetch SCR from card.
*/
err = mmc_app_send_scr(card); if (err) return err;
err = mmc_decode_scr(card); if (err) return err;
/* * Fetch and process SD Status register.
*/
err = mmc_read_ssr(card); if (err) return err;
/* Erase init depends on CSD and SSR */
mmc_init_erase(card);
}
/* * Fetch switch information from card. Note, sd3_bus_mode can change if * voltage switch outcome changes, so do this always.
*/
err = mmc_read_switch(card); if (err) return err;
/* * For SPI, enable CRC as appropriate. * This CRC enable is located AFTER the reading of the * card registers because some SDHC cards are not able * to provide valid CRCs for non-512-byte blocks.
*/ if (mmc_host_is_spi(host)) {
err = mmc_spi_set_crc(host, use_spi_crc); if (err) return err;
}
/* * Check if read-only switch is active.
*/ if (!reinit) { int ro = mmc_sd_get_ro(host);
if (ro < 0) {
pr_warn("%s: host does not support reading read-only switch, assuming write-enable\n",
mmc_hostname(host));
} elseif (ro > 0) {
mmc_card_set_readonly(card);
}
}
if (mmc_card_hs(card)) { if (max_dtr > card->sw_caps.hs_max_dtr)
max_dtr = card->sw_caps.hs_max_dtr;
} elseif (max_dtr > card->csd.max_dtr) {
max_dtr = card->csd.max_dtr;
}
return max_dtr;
}
staticbool mmc_sd_card_using_v18(struct mmc_card *card)
{ /* * According to the SD spec., the Bus Speed Mode (function group 1) bits * 2 to 4 are zero if the card is initialized at 3.3V signal level. Thus * they can be used to determine if the card has already switched to * 1.8V signaling.
*/ return card->sw_caps.sd3_bus_mode &
(SD_MODE_UHS_SDR50 | SD_MODE_UHS_SDR104 | SD_MODE_UHS_DDR50);
}
/* Power Off Notification support at bit 4. */ if ((reg_buf[1] & BIT(4)) && !mmc_card_broken_sd_poweroff_notify(card))
card->ext_power.feature_support |= SD_EXT_POWER_OFF_NOTIFY;
/* Power Sustenance support at bit 5. */ if (reg_buf[1] & BIT(5))
card->ext_power.feature_support |= SD_EXT_POWER_SUSTENANCE;
/* Power Down Mode support at bit 6. */ if (reg_buf[1] & BIT(6))
card->ext_power.feature_support |= SD_EXT_POWER_DOWN_MODE;
/* * Parse only one register set per extension, as that is sufficient to * support the standard functions. This means another 48 bytes in the * buffer must be available.
*/ if (ext + 48 > 512) return -EFAULT;
/* Standard Function Code */
memcpy(&sfc, &gen_info_buf[ext], 2);
/* Address to the next extension. */
memcpy(next_ext_addr, &gen_info_buf[ext + 40], 2);
/* Number of registers for this extension. */
num_regs = gen_info_buf[ext + 42];
/* We support only one register per extension. */ if (num_regs != 1) return 0;
if (!(card->scr.cmds & SD_SCR_CMD48_SUPPORT)) return 0;
gen_info_buf = kzalloc(512, GFP_KERNEL); if (!gen_info_buf) return -ENOMEM;
/* * Read 512 bytes of general info, which is found at function number 0, * at page 0 and with no offset.
*/
err = sd_read_ext_reg(card, 0, 0, 0, 512, gen_info_buf); if (err) {
pr_err("%s: error %d reading general info of SD ext reg\n",
mmc_hostname(card->host), err); goto out;
}
/* General info structure revision. */
memcpy(&rev, &gen_info_buf[0], 2);
/* Length of general info in bytes. */
memcpy(&len, &gen_info_buf[2], 2);
/* Number of extensions to be find. */
num_ext = gen_info_buf[4];
/* * We only support revision 0 and limit it to 512 bytes for simplicity. * No matter what, let's return zero to allow us to continue using the * card, even if we can't support the features from the SD function * extensions registers.
*/ if (rev != 0 || len > 512) {
pr_warn("%s: non-supported SD ext reg layout\n",
mmc_hostname(card->host)); goto out;
}
/* * Parse the extension registers. The first extension should start * immediately after the general info header (16 bytes).
*/
next_ext_addr = 16; for (i = 0; i < num_ext; i++) {
err = sd_parse_ext_reg(card, gen_info_buf, &next_ext_addr); if (err) {
pr_err("%s: error %d parsing SD ext reg\n",
mmc_hostname(card->host), err); goto out;
}
}
reg_buf = kzalloc(512, GFP_KERNEL); if (!reg_buf) return -ENOMEM;
/* * Set Flush Cache at bit 0 in the performance enhancement register at * 261 bytes offset.
*/
fno = card->ext_perf.fno;
page = card->ext_perf.page;
offset = card->ext_perf.offset + 261;
/* * Handle the detection and initialisation of a card. * * In the case of a resume, "oldcard" will contain the card * we're trying to reinitialise.
*/ staticint mmc_sd_init_card(struct mmc_host *host, u32 ocr, struct mmc_card *oldcard)
{ struct mmc_card *card; int err;
u32 cid[4];
u32 rocr = 0; bool v18_fixup_failed = false;
if (oldcard) { if (memcmp(cid, oldcard->raw_cid, sizeof(cid)) != 0) {
pr_debug("%s: Perhaps the card was replaced\n",
mmc_hostname(host)); return -ENOENT;
}
/* * Call the optional HC's init_card function to handle quirks.
*/ if (host->ops->init_card)
host->ops->init_card(host, card);
/* * For native busses: get card RCA and quit open drain mode.
*/ if (!mmc_host_is_spi(host)) {
err = mmc_send_relative_addr(host, &card->rca); if (err) goto free_card;
}
/* * If the card has not been power cycled, it may still be using 1.8V * signaling. Detect that situation and try to initialize a UHS-I (1.8V) * transfer mode.
*/ if (!v18_fixup_failed && !mmc_host_is_spi(host) && mmc_host_can_uhs(host) &&
mmc_sd_card_using_v18(card) &&
host->ios.signal_voltage != MMC_SIGNAL_VOLTAGE_180) { if (mmc_host_set_uhs_voltage(host) ||
mmc_sd_init_uhs_card(card)) {
v18_fixup_failed = true;
mmc_power_cycle(host, ocr); if (!oldcard)
mmc_remove_card(card); goto retry;
} goto cont;
}
/* Initialization sequence for UHS-I cards */ if (rocr & SD_ROCR_S18A && mmc_host_can_uhs(host)) {
err = mmc_sd_init_uhs_card(card); if (err) goto free_card;
} else { /* * Attempt to change to high-speed (if supported)
*/
err = mmc_sd_switch_hs(card); if (err > 0)
mmc_set_timing(card->host, MMC_TIMING_SD_HS); elseif (err) goto free_card;
/* * Set bus speed.
*/
mmc_set_clock(host, mmc_sd_get_max_clock(card));
if (host->ios.timing == MMC_TIMING_SD_HS &&
host->ops->prepare_sd_hs_tuning) {
err = host->ops->prepare_sd_hs_tuning(host, card); if (err) goto free_card;
}
/* * Switch to wider bus (if supported).
*/ if ((host->caps & MMC_CAP_4_BIT_DATA) &&
(card->scr.bus_widths & SD_SCR_BUS_WIDTH_4)) {
err = mmc_app_set_bus_width(card, MMC_BUS_WIDTH_4); if (err) goto free_card;
mmc_set_bus_width(host, MMC_BUS_WIDTH_4);
}
if (host->ios.timing == MMC_TIMING_SD_HS &&
host->ops->execute_sd_hs_tuning) {
err = host->ops->execute_sd_hs_tuning(host, card); if (err) goto free_card;
}
}
cont: if (!oldcard) { /* Read/parse the extension registers. */
err = sd_read_ext_regs(card); if (err) goto free_card;
}
/* Enable internal SD cache if supported. */ if (card->ext_perf.feature_support & SD_EXT_PERF_CACHE) {
err = sd_enable_cache(card); if (err) goto free_card;
}
/* * Read the status register for the power management function. It's at * one byte offset and is one byte long. The Power Off Notification * Ready is bit 0.
*/
err = sd_read_ext_reg(card, card->ext_power.fno, card->ext_power.page,
card->ext_power.offset + 1, 1, data->reg_buf); if (err) {
pr_warn("%s: error %d reading status reg of PM func\n",
mmc_hostname(card->host), err); return err;
}
reg_buf = kzalloc(512, GFP_KERNEL); if (!reg_buf) return -ENOMEM;
/* * Set the Power Off Notification bit in the power management settings * register at 2 bytes offset.
*/
err = sd_write_ext_reg(card, card->ext_power.fno, card->ext_power.page,
card->ext_power.offset + 2, BIT(0)); if (err) {
pr_warn("%s: error %d writing Power Off Notify bit\n",
mmc_hostname(card->host), err); goto out;
}
/* Find out when the command is completed. */
err = mmc_poll_for_busy(card, SD_WRITE_EXTR_SINGLE_TIMEOUT_MS, false,
MMC_BUSY_EXTR_SINGLE); if (err) goto out;
if (sd_can_poweroff_notify(card))
err = sd_poweroff_notify(card); elseif (!mmc_host_is_spi(host))
err = mmc_deselect_cards(host);
if (!err) {
mmc_power_off(host);
mmc_card_set_suspended(card);
}
out:
mmc_release_host(host); return err;
}
/* * Host is being removed. Free up the current card and do a graceful power-off.
*/ staticvoid mmc_sd_remove(struct mmc_host *host)
{
get_device(&host->card->dev);
mmc_remove_card(host->card);
_mmc_sd_suspend(host);
put_device(&host->card->dev);
host->card = NULL;
} /* * Callback for suspend
*/ staticint mmc_sd_suspend(struct mmc_host *host)
{ int err;
err = _mmc_sd_suspend(host); if (!err) {
pm_runtime_disable(&host->card->dev);
pm_runtime_set_suspended(&host->card->dev);
}
return err;
}
/* * This function tries to determine if the same card is still present * and, if so, restore all state to it.
*/ staticint _mmc_sd_resume(struct mmc_host *host)
{ int err = 0;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.