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

@@ -28,6 +28,7 @@ Optional properties:
- cap-mmc-highspeed: MMC high-speed timing is supported
- cap-power-off-card: powering off the card is safe
- cap-sdio-irq: enable SDIO IRQ signalling on this interface
- full-pwr-cycle: full power cycle of the card is supported
*NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line
polarity properties, we have to fix the meaning of the "normal" and "inverted"

View File

@@ -0,0 +1,23 @@
* Rockchip specific extensions to the Synopsis Designware Mobile
Storage Host Controller
The Synopsis designware mobile storage host controller is used to interface
a SoC with storage medium such as eMMC or SD/MMC cards. This file documents
differences between the core Synopsis dw mshc controller properties described
by synopsis-dw-mshc.txt and the properties used by the Rockchip specific
extensions to the Synopsis Designware Mobile Storage Host Controller.
Required Properties:
* compatible: should be
- "rockchip,rk2928-dw-mshc": for Rockchip RK2928 and following
Example:
rkdwmmc0@12200000 {
compatible = "rockchip,rk2928-dw-mshc";
reg = <0x12200000 0x1000>;
interrupts = <0 75 0>;
#address-cells = <1>;
#size-cells = <0>;
};

View File

@@ -39,6 +39,19 @@ Required Properties:
Optional properties:
* clocks: from common clock binding: handle to biu and ciu clocks for the
bus interface unit clock and the card interface unit clock.
* clock-names: from common clock binding: Shall be "biu" and "ciu".
If the biu clock is missing we'll simply skip enabling it. If the
ciu clock is missing we'll just assume that the clock is running at
clock-frequency. It is an error to omit both the ciu clock and the
clock-frequency.
* clock-frequency: should be the frequency (in Hz) of the ciu clock. If this
is specified and the ciu clock is specified then we'll try to set the ciu
clock to this at probe time.
* num-slots: specifies the number of slots supported by the controller.
The number of physical slots actually used could be equal or less than the
value specified by num-slots. If this property is not specified, the value
@@ -55,6 +68,9 @@ Optional properties:
* broken-cd: as documented in mmc core bindings.
* vmmc-supply: The phandle to the regulator to use for vmmc. If this is
specified we'll defer probe until we can find this regulator.
Aliases:
- All the MSHC controller nodes should be represented in the aliases node using
@@ -67,6 +83,8 @@ board specific portions as listed below.
dwmmc0@12200000 {
compatible = "snps,dw-mshc";
clocks = <&clock 351>, <&clock 132>;
clock-names = "biu", "ciu";
reg = <0x12200000 0x1000>;
interrupts = <0 75 0>;
#address-cells = <1>;
@@ -74,11 +92,13 @@ board specific portions as listed below.
};
dwmmc0@12200000 {
clock-frequency = <400000000>;
num-slots = <1>;
supports-highspeed;
broken-cd;
fifo-depth = <0x80>;
card-detect-delay = <200>;
vmmc-supply = <&buck8>;
slot@0 {
reg = <0>;

View File

@@ -78,6 +78,13 @@ CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_LCD_CLASS_DEVICE=y
CONFIG_BACKLIGHT_CLASS_DEVICE=y
# CONFIG_USB_SUPPORT is not set
CONFIG_MMC=y
CONFIG_MMC_UNSAFE_RESUME=y
CONFIG_MMC_BLOCK_MINORS=32
CONFIG_MMC_TEST=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_SDHCI_BCM_KONA=y
CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y
CONFIG_LEDS_TRIGGERS=y

View File

@@ -34,6 +34,7 @@
#include <linux/delay.h>
#include <linux/capability.h>
#include <linux/compat.h>
#include <linux/pm_runtime.h>
#include <linux/mmc/ioctl.h>
#include <linux/mmc/card.h>
@@ -58,6 +59,8 @@ MODULE_ALIAS("mmc:block");
#define INAND_CMD38_ARG_SECTRIM1 0x81
#define INAND_CMD38_ARG_SECTRIM2 0x88
#define MMC_BLK_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */
#define MMC_SANITIZE_REQ_TIMEOUT 240000
#define MMC_EXTRACT_INDEX_FROM_ARG(x) ((x & 0x00FF0000) >> 16)
#define mmc_req_rel_wr(req) (((req->cmd_flags & REQ_FUA) || \
(req->cmd_flags & REQ_META)) && \
@@ -222,7 +225,7 @@ static ssize_t power_ro_lock_store(struct device *dev,
md = mmc_blk_get(dev_to_disk(dev));
card = md->queue.card;
mmc_claim_host(card->host);
mmc_get_card(card);
ret = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BOOT_WP,
card->ext_csd.boot_ro_lock |
@@ -233,7 +236,7 @@ static ssize_t power_ro_lock_store(struct device *dev,
else
card->ext_csd.boot_ro_lock |= EXT_CSD_BOOT_WP_B_PWR_WP_EN;
mmc_release_host(card->host);
mmc_put_card(card);
if (!ret) {
pr_info("%s: Locking boot partition ro until next power on\n",
@@ -408,6 +411,35 @@ static int ioctl_rpmb_card_status_poll(struct mmc_card *card, u32 *status,
return err;
}
static int ioctl_do_sanitize(struct mmc_card *card)
{
int err;
if (!(mmc_can_sanitize(card) &&
(card->host->caps2 & MMC_CAP2_SANITIZE))) {
pr_warn("%s: %s - SANITIZE is not supported\n",
mmc_hostname(card->host), __func__);
err = -EOPNOTSUPP;
goto out;
}
pr_debug("%s: %s - SANITIZE IN PROGRESS...\n",
mmc_hostname(card->host), __func__);
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_SANITIZE_START, 1,
MMC_SANITIZE_REQ_TIMEOUT);
if (err)
pr_err("%s: %s - EXT_CSD_SANITIZE_START failed. err=%d\n",
mmc_hostname(card->host), __func__, err);
pr_debug("%s: %s - SANITIZE COMPLETED\n", mmc_hostname(card->host),
__func__);
out:
return err;
}
static int mmc_blk_ioctl_cmd(struct block_device *bdev,
struct mmc_ioc_cmd __user *ic_ptr)
{
@@ -491,7 +523,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
mrq.cmd = &cmd;
mmc_claim_host(card->host);
mmc_get_card(card);
err = mmc_blk_part_switch(card, md);
if (err)
@@ -510,6 +542,17 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
goto cmd_rel_host;
}
if ((MMC_EXTRACT_INDEX_FROM_ARG(cmd.arg) == EXT_CSD_SANITIZE_START) &&
(cmd.opcode == MMC_SWITCH)) {
err = ioctl_do_sanitize(card);
if (err)
pr_err("%s: ioctl_do_sanitize() failed. err = %d",
__func__, err);
goto cmd_rel_host;
}
mmc_wait_for_req(card->host, &mrq);
if (cmd.error) {
@@ -558,7 +601,7 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
}
cmd_rel_host:
mmc_release_host(card->host);
mmc_put_card(card);
cmd_done:
mmc_blk_put(md);
@@ -939,10 +982,10 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
{
struct mmc_blk_data *md = mq->data;
struct mmc_card *card = md->queue.card;
unsigned int from, nr, arg, trim_arg, erase_arg;
unsigned int from, nr, arg;
int err = 0, type = MMC_BLK_SECDISCARD;
if (!(mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))) {
if (!(mmc_can_secure_erase_trim(card))) {
err = -EOPNOTSUPP;
goto out;
}
@@ -950,23 +993,11 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq,
from = blk_rq_pos(req);
nr = blk_rq_sectors(req);
/* The sanitize operation is supported at v4.5 only */
if (mmc_can_sanitize(card)) {
erase_arg = MMC_ERASE_ARG;
trim_arg = MMC_TRIM_ARG;
} else {
erase_arg = MMC_SECURE_ERASE_ARG;
trim_arg = MMC_SECURE_TRIM1_ARG;
}
if (mmc_can_trim(card) && !mmc_erase_group_aligned(card, from, nr))
arg = MMC_SECURE_TRIM1_ARG;
else
arg = MMC_SECURE_ERASE_ARG;
if (mmc_erase_group_aligned(card, from, nr))
arg = erase_arg;
else if (mmc_can_trim(card))
arg = trim_arg;
else {
err = -EINVAL;
goto out;
}
retry:
if (card->quirks & MMC_QUIRK_INAND_CMD38) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
@@ -1002,9 +1033,6 @@ retry:
goto out;
}
if (mmc_can_sanitize(card))
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_SANITIZE_START, 1, 0);
out_retry:
if (err && !mmc_blk_reset(md, card->host, type))
goto retry;
@@ -1895,7 +1923,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
if (req && !mq->mqrq_prev->req)
/* claim host only for the first request */
mmc_claim_host(card->host);
mmc_get_card(card);
ret = mmc_blk_part_switch(card, md);
if (ret) {
@@ -1939,7 +1967,7 @@ out:
* In case sepecial request, there is no reentry to
* the 'mmc_blk_issue_rq' with 'mqrq_prev->req'.
*/
mmc_release_host(card->host);
mmc_put_card(card);
return ret;
}
@@ -2158,6 +2186,14 @@ static void mmc_blk_remove_req(struct mmc_blk_data *md)
struct mmc_card *card;
if (md) {
/*
* Flush remaining requests and free queues. It
* is freeing the queue that stops new requests
* from being accepted.
*/
mmc_cleanup_queue(&md->queue);
if (md->flags & MMC_BLK_PACKED_CMD)
mmc_packed_clean(&md->queue);
card = md->queue.card;
if (md->disk->flags & GENHD_FL_UP) {
device_remove_file(disk_to_dev(md->disk), &md->force_ro);
@@ -2166,14 +2202,8 @@ static void mmc_blk_remove_req(struct mmc_blk_data *md)
device_remove_file(disk_to_dev(md->disk),
&md->power_ro_lock);
/* Stop new requests from getting into the queue */
del_gendisk(md->disk);
}
/* Then flush out any already in there */
mmc_cleanup_queue(&md->queue);
if (md->flags & MMC_BLK_PACKED_CMD)
mmc_packed_clean(&md->queue);
mmc_blk_put(md);
}
}
@@ -2336,6 +2366,19 @@ static int mmc_blk_probe(struct mmc_card *card)
if (mmc_add_disk(part_md))
goto out;
}
pm_runtime_set_autosuspend_delay(&card->dev, 3000);
pm_runtime_use_autosuspend(&card->dev);
/*
* Don't enable runtime PM for SD-combo cards here. Leave that
* decision to be taken during the SDIO init sequence instead.
*/
if (card->type != MMC_TYPE_SD_COMBO) {
pm_runtime_set_active(&card->dev);
pm_runtime_enable(&card->dev);
}
return 0;
out:
@@ -2349,20 +2392,24 @@ static void mmc_blk_remove(struct mmc_card *card)
struct mmc_blk_data *md = mmc_get_drvdata(card);
mmc_blk_remove_parts(card, md);
pm_runtime_get_sync(&card->dev);
mmc_claim_host(card->host);
mmc_blk_part_switch(card, md);
mmc_release_host(card->host);
if (card->type != MMC_TYPE_SD_COMBO)
pm_runtime_disable(&card->dev);
pm_runtime_put_noidle(&card->dev);
mmc_blk_remove_req(md);
mmc_set_drvdata(card, NULL);
}
#ifdef CONFIG_PM
static int mmc_blk_suspend(struct mmc_card *card)
static int _mmc_blk_suspend(struct mmc_card *card)
{
struct mmc_blk_data *part_md;
struct mmc_blk_data *md = mmc_get_drvdata(card);
if (md) {
pm_runtime_get_sync(&card->dev);
mmc_queue_suspend(&md->queue);
list_for_each_entry(part_md, &md->part, part) {
mmc_queue_suspend(&part_md->queue);
@@ -2371,6 +2418,17 @@ static int mmc_blk_suspend(struct mmc_card *card)
return 0;
}
static void mmc_blk_shutdown(struct mmc_card *card)
{
_mmc_blk_suspend(card);
}
#ifdef CONFIG_PM
static int mmc_blk_suspend(struct mmc_card *card)
{
return _mmc_blk_suspend(card);
}
static int mmc_blk_resume(struct mmc_card *card)
{
struct mmc_blk_data *part_md;
@@ -2386,6 +2444,7 @@ static int mmc_blk_resume(struct mmc_card *card)
list_for_each_entry(part_md, &md->part, part) {
mmc_queue_resume(&part_md->queue);
}
pm_runtime_put(&card->dev);
}
return 0;
}
@@ -2402,6 +2461,7 @@ static struct mmc_driver mmc_driver = {
.remove = mmc_blk_remove,
.suspend = mmc_blk_suspend,
.resume = mmc_blk_resume,
.shutdown = mmc_blk_shutdown,
};
static int __init mmc_blk_init(void)

View File

@@ -3025,12 +3025,17 @@ static void mmc_test_remove(struct mmc_card *card)
mmc_test_free_dbgfs_file(card);
}
static void mmc_test_shutdown(struct mmc_card *card)
{
}
static struct mmc_driver mmc_driver = {
.drv = {
.name = "mmc_test",
},
.probe = mmc_test_probe,
.remove = mmc_test_remove,
.shutdown = mmc_test_shutdown,
};
static int __init mmc_test_init(void)

View File

@@ -173,7 +173,7 @@ static void mmc_queue_setup_discard(struct request_queue *q,
/* granularity must not be greater than max. discard */
if (card->pref_erase > max_discard)
q->limits.discard_granularity = 0;
if (mmc_can_secure_erase_trim(card) || mmc_can_sanitize(card))
if (mmc_can_secure_erase_trim(card))
queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, q);
}

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,
};

View File

@@ -249,6 +249,17 @@ config MMC_SDHCI_S3C_DMA
YMMV.
config MMC_SDHCI_BCM_KONA
tristate "SDHCI support on Broadcom KONA platform"
depends on ARCH_BCM
select MMC_SDHCI_PLTFM
help
This selects the Broadcom Kona Secure Digital Host Controller
Interface(SDHCI) support.
This is used in Broadcom mobile SoCs.
If you have a controller with this interface, say Y or M here.
config MMC_SDHCI_BCM2835
tristate "SDHCI platform support for the BCM2835 SD/MMC Controller"
depends on ARCH_BCM2835
@@ -556,6 +567,14 @@ config MMC_DW_EXYNOS
Synopsys DesignWare Memory Card Interface driver. Select this option
for platforms based on Exynos4 and Exynos5 SoC's.
config MMC_DW_SOCFPGA
tristate "SOCFPGA specific extensions for Synopsys DW Memory Card Interface"
depends on MMC_DW
select MMC_DW_PLTFM
help
This selects support for Altera SoCFPGA specific extensions to the
Synopsys DesignWare Memory Card Interface driver.
config MMC_DW_PCI
tristate "Synopsys Designware MCI support on PCI bus"
depends on MMC_DW && PCI

View File

@@ -42,6 +42,7 @@ obj-$(CONFIG_SDH_BFIN) += bfin_sdh.o
obj-$(CONFIG_MMC_DW) += dw_mmc.o
obj-$(CONFIG_MMC_DW_PLTFM) += dw_mmc-pltfm.o
obj-$(CONFIG_MMC_DW_EXYNOS) += dw_mmc-exynos.o
obj-$(CONFIG_MMC_DW_SOCFPGA) += dw_mmc-socfpga.o
obj-$(CONFIG_MMC_DW_PCI) += dw_mmc-pci.o
obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o
obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o
@@ -60,6 +61,7 @@ obj-$(CONFIG_MMC_SDHCI_DOVE) += sdhci-dove.o
obj-$(CONFIG_MMC_SDHCI_TEGRA) += sdhci-tegra.o
obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o
obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o
obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o
obj-$(CONFIG_MMC_SDHCI_BCM2835) += sdhci-bcm2835.o
ifeq ($(CONFIG_CB710_DEBUG),y)

View File

@@ -546,8 +546,6 @@ static int goldfish_mmc_remove(struct platform_device *pdev)
{
struct goldfish_mmc_host *host = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
BUG_ON(host == NULL);
mmc_remove_host(host->mmc);

Some files were not shown because too many files have changed in this diff Show More