/* * It's safe to access the bus_ops pointer, as both userspace and the * workqueue for detecting cards are frozen at this point.
*/ if (!host->bus_ops) return 0;
/* Validate conditions for system suspend. */ if (host->bus_ops->pre_suspend) return host->bus_ops->pre_suspend(host);
/** * mmc_retune_enable() - enter a transfer mode that requires retuning * @host: host which should retune now
*/ void mmc_retune_enable(struct mmc_host *host)
{
host->can_retune = 1; if (host->retune_period)
mod_timer(&host->retune_timer,
jiffies + host->retune_period * HZ);
}
/* * Pause re-tuning for a small set of operations. The pause begins after the * next command.
*/ void mmc_retune_pause(struct mmc_host *host)
{ if (!host->retune_paused) {
host->retune_paused = 1;
mmc_retune_hold(host);
}
}
EXPORT_SYMBOL(mmc_retune_pause);
/** * mmc_retune_disable() - exit a transfer mode that requires retuning * @host: host which should not retune anymore * * It is not meant for temporarily preventing retuning!
*/ void mmc_retune_disable(struct mmc_host *host)
{
mmc_retune_unpause(host);
host->can_retune = 0;
timer_delete_sync(&host->retune_timer);
mmc_retune_clear(host);
}
/** * mmc_of_parse() - parse host's device properties * @host: host whose properties should be parsed. * * To keep the rest of the MMC subsystem unaware of whether DT has been * used to instantiate and configure this host instance or not, we * parse the properties and set respective generic mmc-host flags and * parameters.
*/ int mmc_of_parse(struct mmc_host *host)
{ struct device *dev = host->parent;
u32 bus_width, drv_type, cd_debounce_delay_ms; int ret;
if (!dev || !dev_fwnode(dev)) return 0;
/* "bus-width" is translated to MMC_CAP_*_BIT_DATA flags */ if (device_property_read_u32(dev, "bus-width", &bus_width) < 0) {
dev_dbg(host->parent, "\"bus-width\" property is missing, assuming 1 bit.\n");
bus_width = 1;
}
switch (bus_width) { case 8:
host->caps |= MMC_CAP_8_BIT_DATA;
fallthrough; /* Hosts capable of 8-bit can also do 4 bits */ case 4:
host->caps |= MMC_CAP_4_BIT_DATA; break; case 1: break; default:
dev_err(host->parent, "Invalid \"bus-width\" value %u!\n", bus_width); return -EINVAL;
}
/* f_max is obtained from the optional "max-frequency" property */
device_property_read_u32(dev, "max-frequency", &host->f_max);
/* * Configure CD and WP pins. They are both by default active low to * match the SDHCI spec. If GPIOs are provided for CD and / or WP, the * mmc-gpio helpers are used to attach, configure and use them. If * polarity inversion is specified in DT, one of MMC_CAP2_CD_ACTIVE_HIGH * and MMC_CAP2_RO_ACTIVE_HIGH capability-2 flags is set. If the * "broken-cd" property is provided, the MMC_CAP_NEEDS_POLL capability * is set. If the "non-removable" property is found, the * MMC_CAP_NONREMOVABLE capability is set and no card-detection * configuration is performed.
*/
/* Parse Card Detection */
if (device_property_read_bool(dev, "non-removable")) {
host->caps |= MMC_CAP_NONREMOVABLE;
} else { if (device_property_read_bool(dev, "cd-inverted"))
host->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
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, false,
cd_debounce_delay_ms * 1000); if (!ret)
dev_info(host->parent, "Got CD GPIO\n"); elseif (ret != -ENOENT && ret != -ENOSYS) return ret;
}
/* Parse Write Protection */
if (device_property_read_bool(dev, "wp-inverted"))
host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
ret = mmc_gpiod_request_ro(host, "wp", 0, 0); if (!ret)
dev_info(host->parent, "Got WP GPIO\n"); elseif (ret != -ENOENT && ret != -ENOSYS) return ret;
if (device_property_read_bool(dev, "disable-wp"))
host->caps2 |= MMC_CAP2_NO_WRITE_PROTECT;
if (device_property_read_bool(dev, "cap-sd-highspeed"))
host->caps |= MMC_CAP_SD_HIGHSPEED; if (device_property_read_bool(dev, "cap-mmc-highspeed"))
host->caps |= MMC_CAP_MMC_HIGHSPEED; if (device_property_read_bool(dev, "sd-uhs-sdr12"))
host->caps |= MMC_CAP_UHS_SDR12; if (device_property_read_bool(dev, "sd-uhs-sdr25"))
host->caps |= MMC_CAP_UHS_SDR25; if (device_property_read_bool(dev, "sd-uhs-sdr50"))
host->caps |= MMC_CAP_UHS_SDR50; if (device_property_read_bool(dev, "sd-uhs-sdr104"))
host->caps |= MMC_CAP_UHS_SDR104; if (device_property_read_bool(dev, "sd-uhs-ddr50"))
host->caps |= MMC_CAP_UHS_DDR50; if (device_property_read_bool(dev, "cap-power-off-card"))
host->caps |= MMC_CAP_POWER_OFF_CARD; if (device_property_read_bool(dev, "cap-mmc-hw-reset"))
host->caps |= MMC_CAP_HW_RESET; if (device_property_read_bool(dev, "cap-sdio-irq"))
host->caps |= MMC_CAP_SDIO_IRQ; if (device_property_read_bool(dev, "full-pwr-cycle"))
host->caps2 |= MMC_CAP2_FULL_PWR_CYCLE; if (device_property_read_bool(dev, "full-pwr-cycle-in-suspend"))
host->caps2 |= MMC_CAP2_FULL_PWR_CYCLE_IN_SUSPEND; if (device_property_read_bool(dev, "keep-power-in-suspend"))
host->pm_caps |= MMC_PM_KEEP_POWER; if (device_property_read_bool(dev, "wakeup-source") ||
device_property_read_bool(dev, "enable-sdio-wakeup")) /* legacy */
host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; if (device_property_read_bool(dev, "mmc-ddr-3_3v"))
host->caps |= MMC_CAP_3_3V_DDR; if (device_property_read_bool(dev, "mmc-ddr-1_8v"))
host->caps |= MMC_CAP_1_8V_DDR; if (device_property_read_bool(dev, "mmc-ddr-1_2v"))
host->caps |= MMC_CAP_1_2V_DDR; if (device_property_read_bool(dev, "mmc-hs200-1_8v"))
host->caps2 |= MMC_CAP2_HS200_1_8V_SDR; if (device_property_read_bool(dev, "mmc-hs200-1_2v"))
host->caps2 |= MMC_CAP2_HS200_1_2V_SDR; if (device_property_read_bool(dev, "mmc-hs400-1_8v"))
host->caps2 |= MMC_CAP2_HS400_1_8V | MMC_CAP2_HS200_1_8V_SDR; if (device_property_read_bool(dev, "mmc-hs400-1_2v"))
host->caps2 |= MMC_CAP2_HS400_1_2V | MMC_CAP2_HS200_1_2V_SDR; if (device_property_read_bool(dev, "mmc-hs400-enhanced-strobe"))
host->caps2 |= MMC_CAP2_HS400_ES; if (device_property_read_bool(dev, "no-sdio"))
host->caps2 |= MMC_CAP2_NO_SDIO; if (device_property_read_bool(dev, "no-sd"))
host->caps2 |= MMC_CAP2_NO_SD; if (device_property_read_bool(dev, "no-mmc"))
host->caps2 |= MMC_CAP2_NO_MMC; if (device_property_read_bool(dev, "no-mmc-hs400"))
host->caps2 &= ~(MMC_CAP2_HS400_1_8V | MMC_CAP2_HS400_1_2V |
MMC_CAP2_HS400_ES);
/* Must be after "non-removable" check */ if (device_property_read_u32(dev, "fixed-emmc-driver-type", &drv_type) == 0) { if (host->caps & MMC_CAP_NONREMOVABLE)
host->fixed_drv_type = drv_type; else
dev_err(host->parent, "can't use fixed driver type, media is removable\n");
}
host->dsr_req = !device_property_read_u32(dev, "dsr", &host->dsr); if (host->dsr_req && (host->dsr & ~0xffff)) {
dev_err(host->parent, "device tree specified broken value for DSR: 0x%x, ignoring\n",
host->dsr);
host->dsr_req = 0;
}
/** * mmc_of_parse_voltage - return mask of supported voltages * @host: host whose properties should be parsed. * @mask: mask of voltages available for MMC/SD/SDIO * * Parse the "voltage-ranges" property, returning zero if it is not * found, negative errno if the voltage-range specification is invalid, * or one if the voltage-range is specified and successfully parsed.
*/ int mmc_of_parse_voltage(struct mmc_host *host, u32 *mask)
{ constchar *prop = "voltage-ranges"; struct device *dev = host->parent;
u32 *voltage_ranges; int num_ranges, i; int ret;
/* * By default, hosts do not support SGIO or large requests. * They have to set these according to their abilities.
*/
host->max_segs = 1;
host->max_seg_size = PAGE_SIZE;
if (caps2 & (MMC_CAP2_HS400_ES | MMC_CAP2_HS400) &&
!(caps & MMC_CAP_8_BIT_DATA) && !(caps2 & MMC_CAP2_NO_MMC)) {
dev_warn(dev, "drop HS400 support since no 8-bit bus\n");
host->caps2 = caps2 & ~MMC_CAP2_HS400_ES & ~MMC_CAP2_HS400;
}
return 0;
}
/** * mmc_add_host - initialise host hardware * @host: mmc host * * Register the host with the driver model. The host must be * prepared to start servicing requests before this function * completes.
*/ int mmc_add_host(struct mmc_host *host)
{ int err;
err = mmc_validate_host_caps(host); if (err) return err;
err = device_add(&host->class_dev); if (err) return err;
/** * mmc_remove_host - remove host hardware * @host: mmc host * * Unregister and remove all cards associated with this host, * and power down the MMC bus. No new requests will be issued * after this function has returned.
*/ void mmc_remove_host(struct mmc_host *host)
{
mmc_stop_host(host);
mmc_remove_host_debugfs(host);
device_del(&host->class_dev);
led_trigger_unregister_simple(host->led);
}
EXPORT_SYMBOL(mmc_remove_host);
/** * mmc_free_host - free the host structure * @host: mmc host * * Free the host once all references to it have been dropped.
*/ void mmc_free_host(struct mmc_host *host)
{
cancel_delayed_work_sync(&host->detect);
mmc_pwrseq_free(host);
put_device(&host->class_dev);
}
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.