Merge tag 'mmc-updates-for-3.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc

Pull MMC updates from Chris Ball:
 "MMC highlights for 3.11:

  Core:
   - Add support for eMMC 5.1 devices
   - Add MMC_CAP_AGGRESSIVE_PM capability for aggressive power
     management of eMMC/SD between requests, using runtime PM
   - Add an ioctl to perform the eMMC 4.5 Sanitize command.  Sample code
     at:

       git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc-utils.git

  Drivers:
   - dw_mmc: Add support for Rockchip's Cortex-A9 SoCs
   - dw_mmc: Add support for Altera SoCFPGAs
   - sdhci-esdhc-imx: Add support for 8-bit bus width, non-removable
     cards
   - sdhci-bcm-kona: New driver for Broadcom Kona (281xx) SoCs
   - sdhi/tmio: Add DT DMA support"

* tag 'mmc-updates-for-3.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: (87 commits)
  mmc: bcm281xx SDHCI driver
  mmc: sdhci: add card_event callback to sdhci
  mmc: core: Fixup Oops for SDIO shutdown
  mmc: sdhci-pci: add another device id
  mmc: esdhc: Fix bug when writing to SDHCI_HOST_CONTROL register
  mmc: esdhc: Add support for 8-bit bus width and non-removable card
  mmc: core: production year for eMMC 4.41 and later
  mmc: omap: remove unnecessary #if 0's
  mmc: sdhci: fix ctrl_2 on super-speed selection
  mmc: dw_mmc-pltfm: add Rockchip variant
  mmc: dw_mmc-pltfm: move probe and remove below dt match table
  mmc: dw_mmc-pltfm: remove static from dw_mci_pltfm_remove
  mmc: sdhci-acpi: add support for eMMC hardware reset for HID 80860F14
  mmc: sdhci-pci: add support for eMMC hardware reset for BYT eMMC.
  mmc: dw_mmc: Add support DW SD/MMC driver on SOCFPGA
  mmc: sdhci: fix caps2 for HS200
  sdhci-pxav3: Fix runtime PM initialization
  mmc: core: Add DT-bindings for MMC_CAP2_FULL_PWR_CYCLE
  mmc: core: Invent MMC_CAP2_FULL_PWR_CYCLE
  mmc: core: Enable power_off_notify for eMMC shutdown sequence
  ...
This commit is contained in:
Linus Torvalds
2013-07-10 11:16:00 -07:00
73 changed files with 1811 additions and 794 deletions

View File

@@ -122,15 +122,39 @@ static int mmc_bus_remove(struct device *dev)
return 0;
}
static void mmc_bus_shutdown(struct device *dev)
{
struct mmc_driver *drv = to_mmc_driver(dev->driver);
struct mmc_card *card = mmc_dev_to_card(dev);
struct mmc_host *host = card->host;
int ret;
if (dev->driver && drv->shutdown)
drv->shutdown(card);
if (host->bus_ops->shutdown) {
ret = host->bus_ops->shutdown(host);
if (ret)
pr_warn("%s: error %d during shutdown\n",
mmc_hostname(host), ret);
}
}
#ifdef CONFIG_PM_SLEEP
static int mmc_bus_suspend(struct device *dev)
{
struct mmc_driver *drv = to_mmc_driver(dev->driver);
struct mmc_card *card = mmc_dev_to_card(dev);
int ret = 0;
struct mmc_host *host = card->host;
int ret;
if (dev->driver && drv->suspend)
if (dev->driver && drv->suspend) {
ret = drv->suspend(card);
if (ret)
return ret;
}
ret = host->bus_ops->suspend(host);
return ret;
}
@@ -138,10 +162,17 @@ static int mmc_bus_resume(struct device *dev)
{
struct mmc_driver *drv = to_mmc_driver(dev->driver);
struct mmc_card *card = mmc_dev_to_card(dev);
int ret = 0;
struct mmc_host *host = card->host;
int ret;
ret = host->bus_ops->resume(host);
if (ret)
pr_warn("%s: error %d during resume (card was removed?)\n",
mmc_hostname(host), ret);
if (dev->driver && drv->resume)
ret = drv->resume(card);
return ret;
}
#endif
@@ -151,15 +182,25 @@ static int mmc_bus_resume(struct device *dev)
static int mmc_runtime_suspend(struct device *dev)
{
struct mmc_card *card = mmc_dev_to_card(dev);
struct mmc_host *host = card->host;
int ret = 0;
return mmc_power_save_host(card->host);
if (host->bus_ops->runtime_suspend)
ret = host->bus_ops->runtime_suspend(host);
return ret;
}
static int mmc_runtime_resume(struct device *dev)
{
struct mmc_card *card = mmc_dev_to_card(dev);
struct mmc_host *host = card->host;
int ret = 0;
return mmc_power_restore_host(card->host);
if (host->bus_ops->runtime_resume)
ret = host->bus_ops->runtime_resume(host);
return ret;
}
static int mmc_runtime_idle(struct device *dev)
@@ -182,6 +223,7 @@ static struct bus_type mmc_bus_type = {
.uevent = mmc_bus_uevent,
.probe = mmc_bus_probe,
.remove = mmc_bus_remove,
.shutdown = mmc_bus_shutdown,
.pm = &mmc_bus_pm_ops,
};

View File

@@ -402,6 +402,7 @@ static int mmc_wait_for_data_req_done(struct mmc_host *host,
context_info->is_done_rcv = false;
context_info->is_new_req = false;
cmd = mrq->cmd;
if (!cmd->error || !cmd->retries ||
mmc_card_removed(host->card)) {
err = host->areq->err_check(host->card,
@@ -436,6 +437,24 @@ static void mmc_wait_for_req_done(struct mmc_host *host,
wait_for_completion(&mrq->completion);
cmd = mrq->cmd;
/*
* If host has timed out waiting for the sanitize
* to complete, card might be still in programming state
* so let's try to bring the card out of programming
* state.
*/
if (cmd->sanitize_busy && cmd->error == -ETIMEDOUT) {
if (!mmc_interrupt_hpi(host->card)) {
pr_warning("%s: %s: Interrupted sanitize\n",
mmc_hostname(host), __func__);
cmd->error = 0;
break;
} else {
pr_err("%s: %s: Failed to interrupt sanitize\n",
mmc_hostname(host), __func__);
}
}
if (!cmd->error || !cmd->retries ||
mmc_card_removed(host->card))
break;
@@ -951,6 +970,29 @@ void mmc_release_host(struct mmc_host *host)
}
EXPORT_SYMBOL(mmc_release_host);
/*
* This is a helper function, which fetches a runtime pm reference for the
* card device and also claims the host.
*/
void mmc_get_card(struct mmc_card *card)
{
pm_runtime_get_sync(&card->dev);
mmc_claim_host(card->host);
}
EXPORT_SYMBOL(mmc_get_card);
/*
* This is a helper function, which releases the host and drops the runtime
* pm reference for the card device.
*/
void mmc_put_card(struct mmc_card *card)
{
mmc_release_host(card->host);
pm_runtime_mark_last_busy(&card->dev);
pm_runtime_put_autosuspend(&card->dev);
}
EXPORT_SYMBOL(mmc_put_card);
/*
* Internal function that does the actual ios call to the host driver,
* optionally printing some debug output.
@@ -1459,7 +1501,7 @@ void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type)
* If a host does all the power sequencing itself, ignore the
* initial MMC_POWER_UP stage.
*/
static void mmc_power_up(struct mmc_host *host)
void mmc_power_up(struct mmc_host *host)
{
int bit;
@@ -2325,14 +2367,13 @@ int mmc_detect_card_removed(struct mmc_host *host)
* The card will be considered unchanged unless we have been asked to
* detect a change or host requires polling to provide card detection.
*/
if (!host->detect_change && !(host->caps & MMC_CAP_NEEDS_POLL) &&
!(host->caps2 & MMC_CAP2_DETECT_ON_ERR))
if (!host->detect_change && !(host->caps & MMC_CAP_NEEDS_POLL))
return ret;
host->detect_change = 0;
if (!ret) {
ret = _mmc_detect_card_removed(host);
if (ret && (host->caps2 & MMC_CAP2_DETECT_ON_ERR)) {
if (ret && (host->caps & MMC_CAP_NEEDS_POLL)) {
/*
* Schedule a detect work as soon as possible to let a
* rescan handle the card removal.
@@ -2442,9 +2483,7 @@ void mmc_stop_host(struct mmc_host *host)
mmc_bus_get(host);
if (host->bus_ops && !host->bus_dead) {
/* Calling bus_ops->remove() with a claimed host can deadlock */
if (host->bus_ops->remove)
host->bus_ops->remove(host);
host->bus_ops->remove(host);
mmc_claim_host(host);
mmc_detach_bus(host);
mmc_power_off(host);
@@ -2509,52 +2548,6 @@ int mmc_power_restore_host(struct mmc_host *host)
}
EXPORT_SYMBOL(mmc_power_restore_host);
int mmc_card_awake(struct mmc_host *host)
{
int err = -ENOSYS;
if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD)
return 0;
mmc_bus_get(host);
if (host->bus_ops && !host->bus_dead && host->bus_ops->awake)
err = host->bus_ops->awake(host);
mmc_bus_put(host);
return err;
}
EXPORT_SYMBOL(mmc_card_awake);
int mmc_card_sleep(struct mmc_host *host)
{
int err = -ENOSYS;
if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD)
return 0;
mmc_bus_get(host);
if (host->bus_ops && !host->bus_dead && host->bus_ops->sleep)
err = host->bus_ops->sleep(host);
mmc_bus_put(host);
return err;
}
EXPORT_SYMBOL(mmc_card_sleep);
int mmc_card_can_sleep(struct mmc_host *host)
{
struct mmc_card *card = host->card;
if (card && mmc_card_mmc(card) && card->ext_csd.rev >= 3)
return 1;
return 0;
}
EXPORT_SYMBOL(mmc_card_can_sleep);
/*
* Flush the cache to the non-volatile storage.
*/
@@ -2626,48 +2619,9 @@ EXPORT_SYMBOL(mmc_cache_ctrl);
*/
int mmc_suspend_host(struct mmc_host *host)
{
int err = 0;
cancel_delayed_work(&host->detect);
mmc_flush_scheduled_work();
mmc_bus_get(host);
if (host->bus_ops && !host->bus_dead) {
if (host->bus_ops->suspend) {
if (mmc_card_doing_bkops(host->card)) {
err = mmc_stop_bkops(host->card);
if (err)
goto out;
}
err = host->bus_ops->suspend(host);
}
if (err == -ENOSYS || !host->bus_ops->resume) {
/*
* We simply "remove" the card in this case.
* It will be redetected on resume. (Calling
* bus_ops->remove() with a claimed host can
* deadlock.)
*/
if (host->bus_ops->remove)
host->bus_ops->remove(host);
mmc_claim_host(host);
mmc_detach_bus(host);
mmc_power_off(host);
mmc_release_host(host);
host->pm_flags = 0;
err = 0;
}
}
mmc_bus_put(host);
if (!err && !mmc_card_keep_power(host))
mmc_power_off(host);
out:
return err;
/* This function is deprecated */
return 0;
}
EXPORT_SYMBOL(mmc_suspend_host);
/**
@@ -2676,39 +2630,8 @@ EXPORT_SYMBOL(mmc_suspend_host);
*/
int mmc_resume_host(struct mmc_host *host)
{
int err = 0;
mmc_bus_get(host);
if (host->bus_ops && !host->bus_dead) {
if (!mmc_card_keep_power(host)) {
mmc_power_up(host);
mmc_select_voltage(host, host->ocr);
/*
* Tell runtime PM core we just powered up the card,
* since it still believes the card is powered off.
* Note that currently runtime PM is only enabled
* for SDIO cards that are MMC_CAP_POWER_OFF_CARD
*/
if (mmc_card_sdio(host->card) &&
(host->caps & MMC_CAP_POWER_OFF_CARD)) {
pm_runtime_disable(&host->card->dev);
pm_runtime_set_active(&host->card->dev);
pm_runtime_enable(&host->card->dev);
}
}
BUG_ON(!host->bus_ops->resume);
err = host->bus_ops->resume(host);
if (err) {
pr_warning("%s: error %d during resume "
"(card was removed?)\n",
mmc_hostname(host), err);
err = 0;
}
}
host->pm_flags &= ~MMC_PM_KEEP_POWER;
mmc_bus_put(host);
return err;
/* This function is deprecated */
return 0;
}
EXPORT_SYMBOL(mmc_resume_host);
@@ -2727,29 +2650,22 @@ int mmc_pm_notify(struct notifier_block *notify_block,
switch (mode) {
case PM_HIBERNATION_PREPARE:
case PM_SUSPEND_PREPARE:
if (host->card && mmc_card_mmc(host->card) &&
mmc_card_doing_bkops(host->card)) {
err = mmc_stop_bkops(host->card);
if (err) {
pr_err("%s: didn't stop bkops\n",
mmc_hostname(host));
return err;
}
mmc_card_clr_doing_bkops(host->card);
}
spin_lock_irqsave(&host->lock, flags);
host->rescan_disable = 1;
spin_unlock_irqrestore(&host->lock, flags);
cancel_delayed_work_sync(&host->detect);
if (!host->bus_ops || host->bus_ops->suspend)
if (!host->bus_ops)
break;
/* Validate prerequisites for suspend */
if (host->bus_ops->pre_suspend)
err = host->bus_ops->pre_suspend(host);
if (!err && host->bus_ops->suspend)
break;
/* Calling bus_ops->remove() with a claimed host can deadlock */
if (host->bus_ops->remove)
host->bus_ops->remove(host);
host->bus_ops->remove(host);
mmc_claim_host(host);
mmc_detach_bus(host);
mmc_power_off(host);

View File

@@ -16,15 +16,17 @@
#define MMC_CMD_RETRIES 3
struct mmc_bus_ops {
int (*awake)(struct mmc_host *);
int (*sleep)(struct mmc_host *);
void (*remove)(struct mmc_host *);
void (*detect)(struct mmc_host *);
int (*pre_suspend)(struct mmc_host *);
int (*suspend)(struct mmc_host *);
int (*resume)(struct mmc_host *);
int (*runtime_suspend)(struct mmc_host *);
int (*runtime_resume)(struct mmc_host *);
int (*power_save)(struct mmc_host *);
int (*power_restore)(struct mmc_host *);
int (*alive)(struct mmc_host *);
int (*shutdown)(struct mmc_host *);
};
void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
@@ -44,6 +46,7 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
void mmc_set_timing(struct mmc_host *host, unsigned int timing);
void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
void mmc_power_up(struct mmc_host *host);
void mmc_power_off(struct mmc_host *host);
void mmc_power_cycle(struct mmc_host *host);

View File

@@ -258,13 +258,13 @@ static int mmc_dbg_card_status_get(void *data, u64 *val)
u32 status;
int ret;
mmc_claim_host(card->host);
mmc_get_card(card);
ret = mmc_send_status(data, &status);
if (!ret)
*val = status;
mmc_release_host(card->host);
mmc_put_card(card);
return ret;
}
@@ -291,9 +291,9 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp)
goto out_free;
}
mmc_claim_host(card->host);
mmc_get_card(card);
err = mmc_send_ext_csd(card, ext_csd);
mmc_release_host(card->host);
mmc_put_card(card);
if (err)
goto out_free;

View File

@@ -306,7 +306,7 @@ static inline void mmc_host_clk_sysfs_init(struct mmc_host *host)
* parse the properties and set respective generic mmc-host flags and
* parameters.
*/
void mmc_of_parse(struct mmc_host *host)
int mmc_of_parse(struct mmc_host *host)
{
struct device_node *np;
u32 bus_width;
@@ -315,7 +315,7 @@ void mmc_of_parse(struct mmc_host *host)
int len, ret, gpio;
if (!host->parent || !host->parent->of_node)
return;
return 0;
np = host->parent->of_node;
@@ -338,6 +338,7 @@ void mmc_of_parse(struct mmc_host *host)
default:
dev_err(host->parent,
"Invalid \"bus-width\" value %ud!\n", bus_width);
return -EINVAL;
}
/* f_max is obtained from the optional "max-frequency" property */
@@ -367,18 +368,22 @@ void mmc_of_parse(struct mmc_host *host)
host->caps |= MMC_CAP_NEEDS_POLL;
gpio = of_get_named_gpio_flags(np, "cd-gpios", 0, &flags);
if (gpio == -EPROBE_DEFER)
return gpio;
if (gpio_is_valid(gpio)) {
if (!(flags & OF_GPIO_ACTIVE_LOW))
gpio_inv_cd = true;
ret = mmc_gpio_request_cd(host, gpio);
if (ret < 0)
if (ret < 0) {
dev_err(host->parent,
"Failed to request CD GPIO #%d: %d!\n",
gpio, ret);
else
return ret;
} else {
dev_info(host->parent, "Got CD GPIO #%d.\n",
gpio);
}
}
if (explicit_inv_cd ^ gpio_inv_cd)
@@ -389,14 +394,23 @@ void mmc_of_parse(struct mmc_host *host)
explicit_inv_wp = of_property_read_bool(np, "wp-inverted");
gpio = of_get_named_gpio_flags(np, "wp-gpios", 0, &flags);
if (gpio == -EPROBE_DEFER) {
ret = -EPROBE_DEFER;
goto out;
}
if (gpio_is_valid(gpio)) {
if (!(flags & OF_GPIO_ACTIVE_LOW))
gpio_inv_wp = true;
ret = mmc_gpio_request_ro(host, gpio);
if (ret < 0)
if (ret < 0) {
dev_err(host->parent,
"Failed to request WP GPIO: %d!\n", ret);
goto out;
} else {
dev_info(host->parent, "Got WP GPIO #%d.\n",
gpio);
}
}
if (explicit_inv_wp ^ gpio_inv_wp)
host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
@@ -409,10 +423,18 @@ void mmc_of_parse(struct mmc_host *host)
host->caps |= MMC_CAP_POWER_OFF_CARD;
if (of_find_property(np, "cap-sdio-irq", &len))
host->caps |= MMC_CAP_SDIO_IRQ;
if (of_find_property(np, "full-pwr-cycle", &len))
host->caps2 |= MMC_CAP2_FULL_PWR_CYCLE;
if (of_find_property(np, "keep-power-in-suspend", &len))
host->pm_caps |= MMC_PM_KEEP_POWER;
if (of_find_property(np, "enable-sdio-wakeup", &len))
host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
return 0;
out:
mmc_gpio_free_cd(host);
return ret;
}
EXPORT_SYMBOL(mmc_of_parse);

View File

@@ -293,7 +293,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
}
card->ext_csd.rev = ext_csd[EXT_CSD_REV];
if (card->ext_csd.rev > 6) {
if (card->ext_csd.rev > 7) {
pr_err("%s: unrecognised EXT_CSD revision %d\n",
mmc_hostname(card->host), card->ext_csd.rev);
err = -EINVAL;
@@ -461,9 +461,31 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
*/
card->ext_csd.boot_ro_lock = ext_csd[EXT_CSD_BOOT_WP];
card->ext_csd.boot_ro_lockable = true;
/* Save power class values */
card->ext_csd.raw_pwr_cl_52_195 =
ext_csd[EXT_CSD_PWR_CL_52_195];
card->ext_csd.raw_pwr_cl_26_195 =
ext_csd[EXT_CSD_PWR_CL_26_195];
card->ext_csd.raw_pwr_cl_52_360 =
ext_csd[EXT_CSD_PWR_CL_52_360];
card->ext_csd.raw_pwr_cl_26_360 =
ext_csd[EXT_CSD_PWR_CL_26_360];
card->ext_csd.raw_pwr_cl_200_195 =
ext_csd[EXT_CSD_PWR_CL_200_195];
card->ext_csd.raw_pwr_cl_200_360 =
ext_csd[EXT_CSD_PWR_CL_200_360];
card->ext_csd.raw_pwr_cl_ddr_52_195 =
ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
card->ext_csd.raw_pwr_cl_ddr_52_360 =
ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
}
if (card->ext_csd.rev >= 5) {
/* Adjust production date as per JEDEC JESD84-B451 */
if (card->cid.year < 2010)
card->cid.year += 16;
/* check whether the eMMC card supports BKOPS */
if (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) {
card->ext_csd.bkops = 1;
@@ -607,7 +629,23 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
(card->ext_csd.raw_sectors[2] ==
bw_ext_csd[EXT_CSD_SEC_CNT + 2]) &&
(card->ext_csd.raw_sectors[3] ==
bw_ext_csd[EXT_CSD_SEC_CNT + 3]));
bw_ext_csd[EXT_CSD_SEC_CNT + 3]) &&
(card->ext_csd.raw_pwr_cl_52_195 ==
bw_ext_csd[EXT_CSD_PWR_CL_52_195]) &&
(card->ext_csd.raw_pwr_cl_26_195 ==
bw_ext_csd[EXT_CSD_PWR_CL_26_195]) &&
(card->ext_csd.raw_pwr_cl_52_360 ==
bw_ext_csd[EXT_CSD_PWR_CL_52_360]) &&
(card->ext_csd.raw_pwr_cl_26_360 ==
bw_ext_csd[EXT_CSD_PWR_CL_26_360]) &&
(card->ext_csd.raw_pwr_cl_200_195 ==
bw_ext_csd[EXT_CSD_PWR_CL_200_195]) &&
(card->ext_csd.raw_pwr_cl_200_360 ==
bw_ext_csd[EXT_CSD_PWR_CL_200_360]) &&
(card->ext_csd.raw_pwr_cl_ddr_52_195 ==
bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
(card->ext_csd.raw_pwr_cl_ddr_52_360 ==
bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
if (err)
err = -EINVAL;
@@ -676,11 +714,10 @@ static struct device_type mmc_type = {
* mmc_switch command.
*/
static int mmc_select_powerclass(struct mmc_card *card,
unsigned int bus_width, u8 *ext_csd)
unsigned int bus_width)
{
int err = 0;
unsigned int pwrclass_val;
unsigned int index = 0;
unsigned int pwrclass_val = 0;
struct mmc_host *host;
BUG_ON(!card);
@@ -688,9 +725,6 @@ static int mmc_select_powerclass(struct mmc_card *card,
host = card->host;
BUG_ON(!host);
if (ext_csd == NULL)
return 0;
/* Power class selection is supported for versions >= 4.0 */
if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
return 0;
@@ -702,13 +736,13 @@ static int mmc_select_powerclass(struct mmc_card *card,
switch (1 << host->ios.vdd) {
case MMC_VDD_165_195:
if (host->ios.clock <= 26000000)
index = EXT_CSD_PWR_CL_26_195;
pwrclass_val = card->ext_csd.raw_pwr_cl_26_195;
else if (host->ios.clock <= 52000000)
index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
EXT_CSD_PWR_CL_52_195 :
EXT_CSD_PWR_CL_DDR_52_195;
pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
card->ext_csd.raw_pwr_cl_52_195 :
card->ext_csd.raw_pwr_cl_ddr_52_195;
else if (host->ios.clock <= 200000000)
index = EXT_CSD_PWR_CL_200_195;
pwrclass_val = card->ext_csd.raw_pwr_cl_200_195;
break;
case MMC_VDD_27_28:
case MMC_VDD_28_29:
@@ -720,13 +754,13 @@ static int mmc_select_powerclass(struct mmc_card *card,
case MMC_VDD_34_35:
case MMC_VDD_35_36:
if (host->ios.clock <= 26000000)
index = EXT_CSD_PWR_CL_26_360;
pwrclass_val = card->ext_csd.raw_pwr_cl_26_360;
else if (host->ios.clock <= 52000000)
index = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
EXT_CSD_PWR_CL_52_360 :
EXT_CSD_PWR_CL_DDR_52_360;
pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
card->ext_csd.raw_pwr_cl_52_360 :
card->ext_csd.raw_pwr_cl_ddr_52_360;
else if (host->ios.clock <= 200000000)
index = EXT_CSD_PWR_CL_200_360;
pwrclass_val = card->ext_csd.raw_pwr_cl_200_360;
break;
default:
pr_warning("%s: Voltage range not supported "
@@ -734,8 +768,6 @@ static int mmc_select_powerclass(struct mmc_card *card,
return -EINVAL;
}
pwrclass_val = ext_csd[index];
if (bus_width & (EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_BUS_WIDTH_8))
pwrclass_val = (pwrclass_val & EXT_CSD_PWR_CL_8BIT_MASK) >>
EXT_CSD_PWR_CL_8BIT_SHIFT;
@@ -1013,11 +1045,9 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
}
/*
* If the host supports the power_off_notify capability then
* set the notification byte in the ext_csd register of device
* Enable power_off_notification byte in the ext_csd register
*/
if ((host->caps2 & MMC_CAP2_POWEROFF_NOTIFY) &&
(card->ext_csd.rev >= 6)) {
if (card->ext_csd.rev >= 6) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_POWER_OFF_NOTIFICATION,
EXT_CSD_POWER_ON,
@@ -1131,7 +1161,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
err = mmc_select_powerclass(card, ext_csd_bits, ext_csd);
err = mmc_select_powerclass(card, ext_csd_bits);
if (err)
pr_warning("%s: power class selection to bus width %d"
" failed\n", mmc_hostname(card->host),
@@ -1164,8 +1194,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
bus_width = bus_widths[idx];
if (bus_width == MMC_BUS_WIDTH_1)
ddr = 0; /* no DDR for 1-bit width */
err = mmc_select_powerclass(card, ext_csd_bits[idx][0],
ext_csd);
err = mmc_select_powerclass(card, ext_csd_bits[idx][0]);
if (err)
pr_warning("%s: power class selection to "
"bus width %d failed\n",
@@ -1195,8 +1224,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
}
if (!err && ddr) {
err = mmc_select_powerclass(card, ext_csd_bits[idx][1],
ext_csd);
err = mmc_select_powerclass(card, ext_csd_bits[idx][1]);
if (err)
pr_warning("%s: power class selection to "
"bus width %d ddr %d failed\n",
@@ -1321,6 +1349,45 @@ err:
return err;
}
static int mmc_can_sleep(struct mmc_card *card)
{
return (card && card->ext_csd.rev >= 3);
}
static int mmc_sleep(struct mmc_host *host)
{
struct mmc_command cmd = {0};
struct mmc_card *card = host->card;
int err;
if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD)
return 0;
err = mmc_deselect_cards(host);
if (err)
return err;
cmd.opcode = MMC_SLEEP_AWAKE;
cmd.arg = card->rca << 16;
cmd.arg |= 1 << 15;
cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
err = mmc_wait_for_cmd(host, &cmd, 0);
if (err)
return err;
/*
* If the host does not wait while the card signals busy, then we will
* will have to wait the sleep/awake timeout. Note, we cannot use the
* SEND_STATUS command to poll the status because that command (and most
* others) is invalid while the card sleeps.
*/
if (!(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
mmc_delay(DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000));
return err;
}
static int mmc_can_poweroff_notify(const struct mmc_card *card)
{
return card &&
@@ -1380,14 +1447,14 @@ static void mmc_detect(struct mmc_host *host)
BUG_ON(!host);
BUG_ON(!host->card);
mmc_claim_host(host);
mmc_get_card(host->card);
/*
* Just check if our card has been removed.
*/
err = _mmc_detect_card_removed(host);
mmc_release_host(host);
mmc_put_card(host->card);
if (err) {
mmc_remove(host);
@@ -1399,35 +1466,59 @@ static void mmc_detect(struct mmc_host *host)
}
}
/*
* Suspend callback from host.
*/
static int mmc_suspend(struct mmc_host *host)
static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
{
int err = 0;
unsigned int notify_type = is_suspend ? EXT_CSD_POWER_OFF_SHORT :
EXT_CSD_POWER_OFF_LONG;
BUG_ON(!host);
BUG_ON(!host->card);
mmc_claim_host(host);
if (mmc_card_doing_bkops(host->card)) {
err = mmc_stop_bkops(host->card);
if (err)
goto out;
}
err = mmc_cache_ctrl(host, 0);
if (err)
goto out;
if (mmc_can_poweroff_notify(host->card))
err = mmc_poweroff_notify(host->card, EXT_CSD_POWER_OFF_SHORT);
else if (mmc_card_can_sleep(host))
err = mmc_card_sleep(host);
if (mmc_can_poweroff_notify(host->card) &&
((host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) || !is_suspend))
err = mmc_poweroff_notify(host->card, notify_type);
else if (mmc_can_sleep(host->card))
err = mmc_sleep(host);
else if (!mmc_host_is_spi(host))
err = mmc_deselect_cards(host);
host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
if (!err)
mmc_power_off(host);
out:
mmc_release_host(host);
return err;
}
/*
* Suspend callback from host.
*/
static int mmc_suspend(struct mmc_host *host)
{
return _mmc_suspend(host, true);
}
/*
* Shutdown callback
*/
static int mmc_shutdown(struct mmc_host *host)
{
return _mmc_suspend(host, false);
}
/*
* Resume callback from host.
*
@@ -1442,12 +1533,62 @@ static int mmc_resume(struct mmc_host *host)
BUG_ON(!host->card);
mmc_claim_host(host);
mmc_power_up(host);
mmc_select_voltage(host, host->ocr);
err = mmc_init_card(host, host->ocr, host->card);
mmc_release_host(host);
return err;
}
/*
* Callback for runtime_suspend.
*/
static int mmc_runtime_suspend(struct mmc_host *host)
{
int err;
if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
return 0;
mmc_claim_host(host);
err = mmc_suspend(host);
if (err) {
pr_err("%s: error %d doing aggessive suspend\n",
mmc_hostname(host), err);
goto out;
}
mmc_power_off(host);
out:
mmc_release_host(host);
return err;
}
/*
* Callback for runtime_resume.
*/
static int mmc_runtime_resume(struct mmc_host *host)
{
int err;
if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
return 0;
mmc_claim_host(host);
mmc_power_up(host);
err = mmc_resume(host);
if (err)
pr_err("%s: error %d doing aggessive resume\n",
mmc_hostname(host), err);
mmc_release_host(host);
return 0;
}
static int mmc_power_restore(struct mmc_host *host)
{
int ret;
@@ -1460,56 +1601,26 @@ static int mmc_power_restore(struct mmc_host *host)
return ret;
}
static int mmc_sleep(struct mmc_host *host)
{
struct mmc_card *card = host->card;
int err = -ENOSYS;
if (card && card->ext_csd.rev >= 3) {
err = mmc_card_sleepawake(host, 1);
if (err < 0)
pr_debug("%s: Error %d while putting card into sleep",
mmc_hostname(host), err);
}
return err;
}
static int mmc_awake(struct mmc_host *host)
{
struct mmc_card *card = host->card;
int err = -ENOSYS;
if (card && card->ext_csd.rev >= 3) {
err = mmc_card_sleepawake(host, 0);
if (err < 0)
pr_debug("%s: Error %d while awaking sleeping card",
mmc_hostname(host), err);
}
return err;
}
static const struct mmc_bus_ops mmc_ops = {
.awake = mmc_awake,
.sleep = mmc_sleep,
.remove = mmc_remove,
.detect = mmc_detect,
.suspend = NULL,
.resume = NULL,
.power_restore = mmc_power_restore,
.alive = mmc_alive,
.shutdown = mmc_shutdown,
};
static const struct mmc_bus_ops mmc_ops_unsafe = {
.awake = mmc_awake,
.sleep = mmc_sleep,
.remove = mmc_remove,
.detect = mmc_detect,
.suspend = mmc_suspend,
.resume = mmc_resume,
.runtime_suspend = mmc_runtime_suspend,
.runtime_resume = mmc_runtime_resume,
.power_restore = mmc_power_restore,
.alive = mmc_alive,
.shutdown = mmc_shutdown,
};
static void mmc_attach_bus_ops(struct mmc_host *host)

View File

@@ -59,40 +59,6 @@ int mmc_deselect_cards(struct mmc_host *host)
return _mmc_select_card(host, NULL);
}
int mmc_card_sleepawake(struct mmc_host *host, int sleep)
{
struct mmc_command cmd = {0};
struct mmc_card *card = host->card;
int err;
if (sleep)
mmc_deselect_cards(host);
cmd.opcode = MMC_SLEEP_AWAKE;
cmd.arg = card->rca << 16;
if (sleep)
cmd.arg |= 1 << 15;
cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
err = mmc_wait_for_cmd(host, &cmd, 0);
if (err)
return err;
/*
* If the host does not wait while the card signals busy, then we will
* will have to wait the sleep/awake timeout. Note, we cannot use the
* SEND_STATUS command to poll the status because that command (and most
* others) is invalid while the card sleeps.
*/
if (!(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
mmc_delay(DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000));
if (!sleep)
err = mmc_select_card(card);
return err;
}
int mmc_go_idle(struct mmc_host *host)
{
int err;
@@ -431,6 +397,8 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
cmd.cmd_timeout_ms = timeout_ms;
if (index == EXT_CSD_SANITIZE_START)
cmd.sanitize_busy = true;
err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
if (err)

View File

@@ -24,7 +24,6 @@ int mmc_send_status(struct mmc_card *card, u32 *status);
int mmc_send_cid(struct mmc_host *host, u32 *cid);
int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp);
int mmc_spi_set_crc(struct mmc_host *host, int use_crc);
int mmc_card_sleepawake(struct mmc_host *host, int sleep);
int mmc_bus_test(struct mmc_card *card, u8 bus_width);
int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status);

View File

@@ -646,8 +646,13 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card)
if (err)
goto out;
/* SPI mode doesn't define CMD19 */
if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning) {
/*
* 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) && card->host->ops->execute_tuning &&
(card->sd_bus_speed == UHS_SDR50_BUS_SPEED ||
card->sd_bus_speed == UHS_SDR104_BUS_SPEED)) {
mmc_host_clk_hold(card->host);
err = card->host->ops->execute_tuning(card->host,
MMC_SEND_TUNING_BLOCK);
@@ -1037,14 +1042,14 @@ static void mmc_sd_detect(struct mmc_host *host)
BUG_ON(!host);
BUG_ON(!host->card);
mmc_claim_host(host);
mmc_get_card(host->card);
/*
* Just check if our card has been removed.
*/
err = _mmc_detect_card_removed(host);
mmc_release_host(host);
mmc_put_card(host->card);
if (err) {
mmc_sd_remove(host);
@@ -1070,6 +1075,8 @@ static int mmc_sd_suspend(struct mmc_host *host)
if (!mmc_host_is_spi(host))
err = mmc_deselect_cards(host);
host->card->state &= ~MMC_STATE_HIGHSPEED;
if (!err)
mmc_power_off(host);
mmc_release_host(host);
return err;
@@ -1089,12 +1096,61 @@ static int mmc_sd_resume(struct mmc_host *host)
BUG_ON(!host->card);
mmc_claim_host(host);
mmc_power_up(host);
mmc_select_voltage(host, host->ocr);
err = mmc_sd_init_card(host, host->ocr, host->card);
mmc_release_host(host);
return err;
}
/*
* Callback for runtime_suspend.
*/
static int mmc_sd_runtime_suspend(struct mmc_host *host)
{
int err;
if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
return 0;
mmc_claim_host(host);
err = mmc_sd_suspend(host);
if (err) {
pr_err("%s: error %d doing aggessive suspend\n",
mmc_hostname(host), err);
goto out;
}
mmc_power_off(host);
out:
mmc_release_host(host);
return err;
}
/*
* Callback for runtime_resume.
*/
static int mmc_sd_runtime_resume(struct mmc_host *host)
{
int err;
if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
return 0;
mmc_claim_host(host);
mmc_power_up(host);
err = mmc_sd_resume(host);
if (err)
pr_err("%s: error %d doing aggessive resume\n",
mmc_hostname(host), err);
mmc_release_host(host);
return 0;
}
static int mmc_sd_power_restore(struct mmc_host *host)
{
int ret;
@@ -1114,15 +1170,19 @@ static const struct mmc_bus_ops mmc_sd_ops = {
.resume = NULL,
.power_restore = mmc_sd_power_restore,
.alive = mmc_sd_alive,
.shutdown = mmc_sd_suspend,
};
static const struct mmc_bus_ops mmc_sd_ops_unsafe = {
.remove = mmc_sd_remove,
.detect = mmc_sd_detect,
.runtime_suspend = mmc_sd_runtime_suspend,
.runtime_resume = mmc_sd_runtime_resume,
.suspend = mmc_sd_suspend,
.resume = mmc_sd_resume,
.power_restore = mmc_sd_power_restore,
.alive = mmc_sd_alive,
.shutdown = mmc_sd_suspend,
};
static void mmc_sd_attach_bus_ops(struct mmc_host *host)

View File

@@ -563,10 +563,18 @@ static int mmc_sdio_init_uhs_card(struct mmc_card *card)
if (err)
goto out;
/* Initialize and start re-tuning timer */
if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning)
/*
* 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) && card->host->ops->execute_tuning &&
((card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR50) ||
(card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104))) {
mmc_host_clk_hold(card->host);
err = card->host->ops->execute_tuning(card->host,
MMC_SEND_TUNING_BLOCK);
mmc_host_clk_release(card->host);
}
out:
@@ -902,11 +910,11 @@ out:
}
/*
* SDIO suspend. We need to suspend all functions separately.
* SDIO pre_suspend. We need to suspend all functions separately.
* Therefore all registered functions must have drivers with suspend
* and resume methods. Failing that we simply remove the whole card.
*/
static int mmc_sdio_suspend(struct mmc_host *host)
static int mmc_sdio_pre_suspend(struct mmc_host *host)
{
int i, err = 0;
@@ -917,8 +925,26 @@ static int mmc_sdio_suspend(struct mmc_host *host)
if (!pmops || !pmops->suspend || !pmops->resume) {
/* force removal of entire card in that case */
err = -ENOSYS;
} else
err = pmops->suspend(&func->dev);
break;
}
}
}
return err;
}
/*
* SDIO suspend. Suspend all functions separately.
*/
static int mmc_sdio_suspend(struct mmc_host *host)
{
int i, err = 0;
for (i = 0; i < host->card->sdio_funcs; i++) {
struct sdio_func *func = host->card->sdio_func[i];
if (func && sdio_func_present(func) && func->dev.driver) {
const struct dev_pm_ops *pmops = func->dev.driver->pm;
err = pmops->suspend(&func->dev);
if (err)
break;
}
@@ -937,6 +963,9 @@ static int mmc_sdio_suspend(struct mmc_host *host)
mmc_release_host(host);
}
if (!err && !mmc_card_keep_power(host))
mmc_power_off(host);
return err;
}
@@ -950,6 +979,23 @@ static int mmc_sdio_resume(struct mmc_host *host)
/* Basic card reinitialization. */
mmc_claim_host(host);
/* Restore power if needed */
if (!mmc_card_keep_power(host)) {
mmc_power_up(host);
mmc_select_voltage(host, host->ocr);
/*
* Tell runtime PM core we just powered up the card,
* since it still believes the card is powered off.
* Note that currently runtime PM is only enabled
* for SDIO cards that are MMC_CAP_POWER_OFF_CARD
*/
if (host->caps & MMC_CAP_POWER_OFF_CARD) {
pm_runtime_disable(&host->card->dev);
pm_runtime_set_active(&host->card->dev);
pm_runtime_enable(&host->card->dev);
}
}
/* No need to reinitialize powered-resumed nonremovable cards */
if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) {
sdio_reset(host);
@@ -987,6 +1033,7 @@ static int mmc_sdio_resume(struct mmc_host *host)
}
}
host->pm_flags &= ~MMC_PM_KEEP_POWER;
return err;
}
@@ -1051,11 +1098,28 @@ out:
return ret;
}
static int mmc_sdio_runtime_suspend(struct mmc_host *host)
{
/* No references to the card, cut the power to it. */
mmc_power_off(host);
return 0;
}
static int mmc_sdio_runtime_resume(struct mmc_host *host)
{
/* Restore power and re-initialize. */
mmc_power_up(host);
return mmc_sdio_power_restore(host);
}
static const struct mmc_bus_ops mmc_sdio_ops = {
.remove = mmc_sdio_remove,
.detect = mmc_sdio_detect,
.pre_suspend = mmc_sdio_pre_suspend,
.suspend = mmc_sdio_suspend,
.resume = mmc_sdio_resume,
.runtime_suspend = mmc_sdio_runtime_suspend,
.runtime_resume = mmc_sdio_runtime_resume,
.power_restore = mmc_sdio_power_restore,
.alive = mmc_sdio_alive,
};