提交 c2ac2ae4 编写于 作者: L Linus Torvalds

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

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

  Core:
   - Improve runtime PM support, remove mmc_{suspend,resume}_host().
   - Add MMC_CAP_RUNTIME_RESUME, for delaying MMC resume until we're
     outside of the resume sequence (in runtime_resume) to decrease
     system resume time.

  Drivers:
   - dw_mmc: Support HS200 mode.
   - sdhci-eshdc-imx: Support SD3.0 SDR clock tuning, DDR on IMX6.
   - sdhci-pci: Add support for Intel Clovertrail and Merrifield"

* tag 'mmc-updates-for-3.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: (108 commits)
  mmc: wbsd: Silence compiler warning
  mmc: core: Silence compiler warning in __mmc_switch
  mmc: sh_mmcif: Convert to clk_prepare|unprepare
  mmc: sh_mmcif: Convert to PM macros when defining dev_pm_ops
  mmc: dw_mmc: exynos: Revert the sdr_timing assignment
  mmc: sdhci: Avoid needless loop while handling SDIO interrupts in sdhci_irq
  mmc: core: Add MMC_CAP_RUNTIME_RESUME to resume at runtime_resume
  mmc: core: Improve runtime PM support during suspend/resume for sd/mmc
  mmc: core: Remove redundant mmc_power_up|off at runtime callbacks
  mmc: Don't force card to active state when entering suspend/shutdown
  MIPS: db1235: Don't use MMC_CLKGATE
  mmc: core: Remove deprecated mmc_suspend|resume_host APIs
  mmc: mmci: Move away from using deprecated APIs
  mmc: via-sdmmc: Move away from using deprecated APIs
  mmc: tmio: Move away from using deprecated APIs
  mmc: sh_mmcif: Move away from using deprecated APIs
  mmc: sdricoh_cs: Move away from using deprecated APIs
  mmc: rtsx: Remove redundant suspend and resume callbacks
  mmc: wbsd: Move away from using deprecated APIs
  mmc: pxamci: Remove redundant suspend and resume callbacks
  ...
...@@ -12,6 +12,11 @@ Required properties: ...@@ -12,6 +12,11 @@ Required properties:
Optional properties: Optional properties:
- fsl,cd-controller : Indicate to use controller internal card detection - fsl,cd-controller : Indicate to use controller internal card detection
- fsl,wp-controller : Indicate to use controller internal write protection - fsl,wp-controller : Indicate to use controller internal write protection
- fsl,delay-line : Specify the number of delay cells for override mode.
This is used to set the clock delay for DLL(Delay Line) on override mode
to select a proper data sampling window in case the clock quality is not good
due to signal path is too long on the board. Please refer to eSDHC/uSDHC
chapter, DLL (Delay Line) section in RM for details.
Examples: Examples:
......
...@@ -52,6 +52,9 @@ Optional properties: ...@@ -52,6 +52,9 @@ Optional properties:
is specified and the ciu clock is specified then we'll try to set the ciu is specified and the ciu clock is specified then we'll try to set the ciu
clock to this at probe time. clock to this at probe time.
* clock-freq-min-max: Minimum and Maximum clock frequency for card output
clock(cclk_out). If it's not specified, max is 200MHZ and min is 400KHz by default.
* num-slots: specifies the number of slots supported by the controller. * 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 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 value specified by num-slots. If this property is not specified, the value
...@@ -66,6 +69,10 @@ Optional properties: ...@@ -66,6 +69,10 @@ Optional properties:
* supports-highspeed: Enables support for high speed cards (up to 50MHz) * supports-highspeed: Enables support for high speed cards (up to 50MHz)
* caps2-mmc-hs200-1_8v: Supports mmc HS200 SDR 1.8V mode
* caps2-mmc-hs200-1_2v: Supports mmc HS200 SDR 1.2V mode
* broken-cd: as documented in mmc core bindings. * broken-cd: as documented in mmc core bindings.
* vmmc-supply: The phandle to the regulator to use for vmmc. If this is * vmmc-supply: The phandle to the regulator to use for vmmc. If this is
...@@ -93,8 +100,10 @@ board specific portions as listed below. ...@@ -93,8 +100,10 @@ board specific portions as listed below.
dwmmc0@12200000 { dwmmc0@12200000 {
clock-frequency = <400000000>; clock-frequency = <400000000>;
clock-freq-min-max = <400000 200000000>;
num-slots = <1>; num-slots = <1>;
supports-highspeed; supports-highspeed;
caps2-mmc-hs200-1_8v;
broken-cd; broken-cd;
fifo-depth = <0x80>; fifo-depth = <0x80>;
card-detect-delay = <200>; card-detect-delay = <200>;
......
...@@ -351,7 +351,6 @@ CONFIG_USB_OHCI_HCD=y ...@@ -351,7 +351,6 @@ CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_HCD_PLATFORM=y CONFIG_USB_OHCI_HCD_PLATFORM=y
CONFIG_USB_STORAGE=y CONFIG_USB_STORAGE=y
CONFIG_MMC=y CONFIG_MMC=y
CONFIG_MMC_CLKGATE=y
CONFIG_MMC_AU1X=y CONFIG_MMC_AU1X=y
CONFIG_NEW_LEDS=y CONFIG_NEW_LEDS=y
CONFIG_LEDS_CLASS=y CONFIG_LEDS_CLASS=y
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/mmc/sh_mmcif.h> #include <linux/mmc/sh_mmcif.h>
#include <linux/mmc/sh_mobile_sdhi.h> #include <linux/mmc/sh_mobile_sdhi.h>
#include <linux/mtd/physmap.h> #include <linux/mtd/physmap.h>
#include <linux/mfd/tmio.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
......
...@@ -2448,7 +2448,6 @@ static int _mmc_blk_suspend(struct mmc_card *card) ...@@ -2448,7 +2448,6 @@ static int _mmc_blk_suspend(struct mmc_card *card)
struct mmc_blk_data *md = mmc_get_drvdata(card); struct mmc_blk_data *md = mmc_get_drvdata(card);
if (md) { if (md) {
pm_runtime_get_sync(&card->dev);
mmc_queue_suspend(&md->queue); mmc_queue_suspend(&md->queue);
list_for_each_entry(part_md, &md->part, part) { list_for_each_entry(part_md, &md->part, part) {
mmc_queue_suspend(&part_md->queue); mmc_queue_suspend(&part_md->queue);
...@@ -2483,7 +2482,6 @@ static int mmc_blk_resume(struct mmc_card *card) ...@@ -2483,7 +2482,6 @@ static int mmc_blk_resume(struct mmc_card *card)
list_for_each_entry(part_md, &md->part, part) { list_for_each_entry(part_md, &md->part, part) {
mmc_queue_resume(&part_md->queue); mmc_queue_resume(&part_md->queue);
} }
pm_runtime_put(&card->dev);
} }
return 0; return 0;
} }
......
...@@ -342,7 +342,7 @@ int mmc_add_card(struct mmc_card *card) ...@@ -342,7 +342,7 @@ int mmc_add_card(struct mmc_card *card)
break; break;
} }
if (mmc_sd_card_uhs(card) && if (mmc_card_uhs(card) &&
(card->sd_bus_speed < ARRAY_SIZE(uhs_speeds))) (card->sd_bus_speed < ARRAY_SIZE(uhs_speeds)))
uhs_bus_speed_mode = uhs_speeds[card->sd_bus_speed]; uhs_bus_speed_mode = uhs_speeds[card->sd_bus_speed];
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/log2.h> #include <linux/log2.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/pm_wakeup.h>
#include <linux/suspend.h> #include <linux/suspend.h>
#include <linux/fault-inject.h> #include <linux/fault-inject.h>
#include <linux/random.h> #include <linux/random.h>
...@@ -301,7 +302,7 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception) ...@@ -301,7 +302,7 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
} }
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BKOPS_START, 1, timeout, use_busy_signal); EXT_CSD_BKOPS_START, 1, timeout, use_busy_signal, true);
if (err) { if (err) {
pr_warn("%s: Error %d starting bkops\n", pr_warn("%s: Error %d starting bkops\n",
mmc_hostname(card->host), err); mmc_hostname(card->host), err);
...@@ -917,31 +918,6 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort) ...@@ -917,31 +918,6 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
EXPORT_SYMBOL(__mmc_claim_host); EXPORT_SYMBOL(__mmc_claim_host);
/**
* mmc_try_claim_host - try exclusively to claim a host
* @host: mmc host to claim
*
* Returns %1 if the host is claimed, %0 otherwise.
*/
int mmc_try_claim_host(struct mmc_host *host)
{
int claimed_host = 0;
unsigned long flags;
spin_lock_irqsave(&host->lock, flags);
if (!host->claimed || host->claimer == current) {
host->claimed = 1;
host->claimer = current;
host->claim_cnt += 1;
claimed_host = 1;
}
spin_unlock_irqrestore(&host->lock, flags);
if (host->ops->enable && claimed_host && host->claim_cnt == 1)
host->ops->enable(host);
return claimed_host;
}
EXPORT_SYMBOL(mmc_try_claim_host);
/** /**
* mmc_release_host - release a host * mmc_release_host - release a host
* @host: mmc host to release * @host: mmc host to release
...@@ -1382,22 +1358,31 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr) ...@@ -1382,22 +1358,31 @@ u32 mmc_select_voltage(struct mmc_host *host, u32 ocr)
{ {
int bit; int bit;
ocr &= host->ocr_avail; /*
* Sanity check the voltages that the card claims to
* support.
*/
if (ocr & 0x7F) {
dev_warn(mmc_dev(host),
"card claims to support voltages below defined range\n");
ocr &= ~0x7F;
}
bit = ffs(ocr); ocr &= host->ocr_avail;
if (bit) { if (!ocr) {
bit -= 1; dev_warn(mmc_dev(host), "no support for card's volts\n");
return 0;
}
if (host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) {
bit = ffs(ocr) - 1;
ocr &= 3 << bit; ocr &= 3 << bit;
mmc_power_cycle(host, ocr);
mmc_host_clk_hold(host);
host->ios.vdd = bit;
mmc_set_ios(host);
mmc_host_clk_release(host);
} else { } else {
pr_warning("%s: host doesn't support card's voltages\n", bit = fls(ocr) - 1;
mmc_hostname(host)); ocr &= 3 << bit;
ocr = 0; if (bit != host->ios.vdd)
dev_warn(mmc_dev(host), "exceeding card's volts\n");
} }
return ocr; return ocr;
...@@ -1422,7 +1407,7 @@ int __mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage) ...@@ -1422,7 +1407,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) int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr)
{ {
struct mmc_command cmd = {0}; struct mmc_command cmd = {0};
int err = 0; int err = 0;
...@@ -1504,7 +1489,7 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage) ...@@ -1504,7 +1489,7 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
if (err) { if (err) {
pr_debug("%s: Signal voltage switch failed, " pr_debug("%s: Signal voltage switch failed, "
"power cycling card\n", mmc_hostname(host)); "power cycling card\n", mmc_hostname(host));
mmc_power_cycle(host); mmc_power_cycle(host, ocr);
} }
mmc_host_clk_release(host); mmc_host_clk_release(host);
...@@ -1545,22 +1530,14 @@ void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type) ...@@ -1545,22 +1530,14 @@ void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type)
* If a host does all the power sequencing itself, ignore the * If a host does all the power sequencing itself, ignore the
* initial MMC_POWER_UP stage. * initial MMC_POWER_UP stage.
*/ */
void mmc_power_up(struct mmc_host *host) void mmc_power_up(struct mmc_host *host, u32 ocr)
{ {
int bit;
if (host->ios.power_mode == MMC_POWER_ON) if (host->ios.power_mode == MMC_POWER_ON)
return; return;
mmc_host_clk_hold(host); mmc_host_clk_hold(host);
/* If ocr is set, we use it */ host->ios.vdd = fls(ocr) - 1;
if (host->ocr)
bit = ffs(host->ocr) - 1;
else
bit = fls(host->ocr_avail) - 1;
host->ios.vdd = bit;
if (mmc_host_is_spi(host)) if (mmc_host_is_spi(host))
host->ios.chip_select = MMC_CS_HIGH; host->ios.chip_select = MMC_CS_HIGH;
else else
...@@ -1604,13 +1581,6 @@ void mmc_power_off(struct mmc_host *host) ...@@ -1604,13 +1581,6 @@ void mmc_power_off(struct mmc_host *host)
host->ios.clock = 0; host->ios.clock = 0;
host->ios.vdd = 0; host->ios.vdd = 0;
/*
* Reset ocr mask to be the highest possible voltage supported for
* this mmc host. This value will be used at next power up.
*/
host->ocr = 1 << (fls(host->ocr_avail) - 1);
if (!mmc_host_is_spi(host)) { if (!mmc_host_is_spi(host)) {
host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
host->ios.chip_select = MMC_CS_DONTCARE; host->ios.chip_select = MMC_CS_DONTCARE;
...@@ -1630,12 +1600,12 @@ void mmc_power_off(struct mmc_host *host) ...@@ -1630,12 +1600,12 @@ void mmc_power_off(struct mmc_host *host)
mmc_host_clk_release(host); mmc_host_clk_release(host);
} }
void mmc_power_cycle(struct mmc_host *host) void mmc_power_cycle(struct mmc_host *host, u32 ocr)
{ {
mmc_power_off(host); mmc_power_off(host);
/* Wait at least 1 ms according to SD spec */ /* Wait at least 1 ms according to SD spec */
mmc_delay(1); mmc_delay(1);
mmc_power_up(host); mmc_power_up(host, ocr);
} }
/* /*
...@@ -1723,6 +1693,28 @@ void mmc_detach_bus(struct mmc_host *host) ...@@ -1723,6 +1693,28 @@ void mmc_detach_bus(struct mmc_host *host)
mmc_bus_put(host); mmc_bus_put(host);
} }
static void _mmc_detect_change(struct mmc_host *host, unsigned long delay,
bool cd_irq)
{
#ifdef CONFIG_MMC_DEBUG
unsigned long flags;
spin_lock_irqsave(&host->lock, flags);
WARN_ON(host->removed);
spin_unlock_irqrestore(&host->lock, flags);
#endif
/*
* If the device is configured as wakeup, we prevent a new sleep for
* 5 s to give provision for user space to consume the event.
*/
if (cd_irq && !(host->caps & MMC_CAP_NEEDS_POLL) &&
device_can_wakeup(mmc_dev(host)))
pm_wakeup_event(mmc_dev(host), 5000);
host->detect_change = 1;
mmc_schedule_delayed_work(&host->detect, delay);
}
/** /**
* mmc_detect_change - process change of state on a MMC socket * mmc_detect_change - process change of state on a MMC socket
* @host: host which changed state. * @host: host which changed state.
...@@ -1735,16 +1727,8 @@ void mmc_detach_bus(struct mmc_host *host) ...@@ -1735,16 +1727,8 @@ void mmc_detach_bus(struct mmc_host *host)
*/ */
void mmc_detect_change(struct mmc_host *host, unsigned long delay) void mmc_detect_change(struct mmc_host *host, unsigned long delay)
{ {
#ifdef CONFIG_MMC_DEBUG _mmc_detect_change(host, delay, true);
unsigned long flags;
spin_lock_irqsave(&host->lock, flags);
WARN_ON(host->removed);
spin_unlock_irqrestore(&host->lock, flags);
#endif
host->detect_change = 1;
mmc_schedule_delayed_work(&host->detect, delay);
} }
EXPORT_SYMBOL(mmc_detect_change); EXPORT_SYMBOL(mmc_detect_change);
void mmc_init_erase(struct mmc_card *card) void mmc_init_erase(struct mmc_card *card)
...@@ -2334,7 +2318,7 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq) ...@@ -2334,7 +2318,7 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
pr_info("%s: %s: trying to init card at %u Hz\n", pr_info("%s: %s: trying to init card at %u Hz\n",
mmc_hostname(host), __func__, host->f_init); mmc_hostname(host), __func__, host->f_init);
#endif #endif
mmc_power_up(host); mmc_power_up(host, host->ocr_avail);
/* /*
* Some eMMCs (with VCCQ always on) may not be reset after power up, so * Some eMMCs (with VCCQ always on) may not be reset after power up, so
...@@ -2423,7 +2407,7 @@ int mmc_detect_card_removed(struct mmc_host *host) ...@@ -2423,7 +2407,7 @@ int mmc_detect_card_removed(struct mmc_host *host)
* rescan handle the card removal. * rescan handle the card removal.
*/ */
cancel_delayed_work(&host->detect); cancel_delayed_work(&host->detect);
mmc_detect_change(host, 0); _mmc_detect_change(host, 0, false);
} }
} }
...@@ -2504,8 +2488,8 @@ void mmc_start_host(struct mmc_host *host) ...@@ -2504,8 +2488,8 @@ void mmc_start_host(struct mmc_host *host)
if (host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP) if (host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)
mmc_power_off(host); mmc_power_off(host);
else else
mmc_power_up(host); mmc_power_up(host, host->ocr_avail);
mmc_detect_change(host, 0); _mmc_detect_change(host, 0, false);
} }
void mmc_stop_host(struct mmc_host *host) void mmc_stop_host(struct mmc_host *host)
...@@ -2583,7 +2567,7 @@ int mmc_power_restore_host(struct mmc_host *host) ...@@ -2583,7 +2567,7 @@ int mmc_power_restore_host(struct mmc_host *host)
return -EINVAL; return -EINVAL;
} }
mmc_power_up(host); mmc_power_up(host, host->card->ocr);
ret = host->bus_ops->power_restore(host); ret = host->bus_ops->power_restore(host);
mmc_bus_put(host); mmc_bus_put(host);
...@@ -2657,28 +2641,6 @@ EXPORT_SYMBOL(mmc_cache_ctrl); ...@@ -2657,28 +2641,6 @@ EXPORT_SYMBOL(mmc_cache_ctrl);
#ifdef CONFIG_PM #ifdef CONFIG_PM
/**
* mmc_suspend_host - suspend a host
* @host: mmc host
*/
int mmc_suspend_host(struct mmc_host *host)
{
/* This function is deprecated */
return 0;
}
EXPORT_SYMBOL(mmc_suspend_host);
/**
* mmc_resume_host - resume a previously suspended host
* @host: mmc host
*/
int mmc_resume_host(struct mmc_host *host)
{
/* This function is deprecated */
return 0;
}
EXPORT_SYMBOL(mmc_resume_host);
/* Do the card removal on suspend if card is assumed removeable /* Do the card removal on suspend if card is assumed removeable
* Do that in pm notifier while userspace isn't yet frozen, so we will be able * Do that in pm notifier while userspace isn't yet frozen, so we will be able
to sync the card. to sync the card.
...@@ -2724,7 +2686,7 @@ int mmc_pm_notify(struct notifier_block *notify_block, ...@@ -2724,7 +2686,7 @@ int mmc_pm_notify(struct notifier_block *notify_block,
spin_lock_irqsave(&host->lock, flags); spin_lock_irqsave(&host->lock, flags);
host->rescan_disable = 0; host->rescan_disable = 0;
spin_unlock_irqrestore(&host->lock, flags); spin_unlock_irqrestore(&host->lock, flags);
mmc_detect_change(host, 0); _mmc_detect_change(host, 0, false);
} }
......
...@@ -42,13 +42,13 @@ void mmc_set_ungated(struct mmc_host *host); ...@@ -42,13 +42,13 @@ void mmc_set_ungated(struct mmc_host *host);
void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode); void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
void mmc_set_bus_width(struct mmc_host *host, unsigned int width); void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
u32 mmc_select_voltage(struct mmc_host *host, u32 ocr); u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage); int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr);
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_timing(struct mmc_host *host, unsigned int timing);
void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type); void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
void mmc_power_up(struct mmc_host *host); void mmc_power_up(struct mmc_host *host, u32 ocr);
void mmc_power_off(struct mmc_host *host); void mmc_power_off(struct mmc_host *host);
void mmc_power_cycle(struct mmc_host *host); void mmc_power_cycle(struct mmc_host *host, u32 ocr);
static inline void mmc_delay(unsigned int ms) static inline void mmc_delay(unsigned int ms)
{ {
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/pm_runtime.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/card.h> #include <linux/mmc/card.h>
...@@ -934,6 +935,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr, ...@@ -934,6 +935,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
goto err; goto err;
} }
card->ocr = ocr;
card->type = MMC_TYPE_MMC; card->type = MMC_TYPE_MMC;
card->rca = 1; card->rca = 1;
memcpy(card->raw_cid, cid, sizeof(card->raw_cid)); memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
...@@ -1404,9 +1406,9 @@ static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type) ...@@ -1404,9 +1406,9 @@ static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type)
if (notify_type == EXT_CSD_POWER_OFF_LONG) if (notify_type == EXT_CSD_POWER_OFF_LONG)
timeout = card->ext_csd.power_off_longtime; timeout = card->ext_csd.power_off_longtime;
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_POWER_OFF_NOTIFICATION, EXT_CSD_POWER_OFF_NOTIFICATION,
notify_type, timeout); notify_type, timeout, true, false);
if (err) if (err)
pr_err("%s: Power Off Notification timed out, %u\n", pr_err("%s: Power Off Notification timed out, %u\n",
mmc_hostname(card->host), timeout); mmc_hostname(card->host), timeout);
...@@ -1477,6 +1479,9 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend) ...@@ -1477,6 +1479,9 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
mmc_claim_host(host); mmc_claim_host(host);
if (mmc_card_suspended(host->card))
goto out;
if (mmc_card_doing_bkops(host->card)) { if (mmc_card_doing_bkops(host->card)) {
err = mmc_stop_bkops(host->card); err = mmc_stop_bkops(host->card);
if (err) if (err)
...@@ -1496,51 +1501,93 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend) ...@@ -1496,51 +1501,93 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
err = mmc_deselect_cards(host); err = mmc_deselect_cards(host);
host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200); host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
if (!err) if (!err) {
mmc_power_off(host); mmc_power_off(host);
mmc_card_set_suspended(host->card);
}
out: out:
mmc_release_host(host); mmc_release_host(host);
return err; return err;
} }
/* /*
* Suspend callback from host. * Suspend callback
*/ */
static int mmc_suspend(struct mmc_host *host) static int mmc_suspend(struct mmc_host *host)
{ {
return _mmc_suspend(host, true); int err;
}
/* err = _mmc_suspend(host, true);
* Shutdown callback if (!err) {
*/ pm_runtime_disable(&host->card->dev);
static int mmc_shutdown(struct mmc_host *host) pm_runtime_set_suspended(&host->card->dev);
{ }
return _mmc_suspend(host, false);
return err;
} }
/* /*
* Resume callback from host.
*
* This function tries to determine if the same card is still present * This function tries to determine if the same card is still present
* and, if so, restore all state to it. * and, if so, restore all state to it.
*/ */
static int mmc_resume(struct mmc_host *host) static int _mmc_resume(struct mmc_host *host)
{ {
int err; int err = 0;
BUG_ON(!host); BUG_ON(!host);
BUG_ON(!host->card); BUG_ON(!host->card);
mmc_claim_host(host); mmc_claim_host(host);
mmc_power_up(host);
mmc_select_voltage(host, host->ocr); if (!mmc_card_suspended(host->card))
err = mmc_init_card(host, host->ocr, host->card); goto out;
mmc_power_up(host, host->card->ocr);
err = mmc_init_card(host, host->card->ocr, host->card);
mmc_card_clr_suspended(host->card);
out:
mmc_release_host(host); mmc_release_host(host);
return err;
}
/*
* Shutdown callback
*/
static int mmc_shutdown(struct mmc_host *host)
{
int err = 0;
/*
* In a specific case for poweroff notify, we need to resume the card
* before we can shutdown it properly.
*/
if (mmc_can_poweroff_notify(host->card) &&
!(host->caps2 & MMC_CAP2_FULL_PWR_CYCLE))
err = _mmc_resume(host);
if (!err)
err = _mmc_suspend(host, false);
return err; return err;
} }
/*
* Callback for resume.
*/
static int mmc_resume(struct mmc_host *host)
{
int err = 0;
if (!(host->caps & MMC_CAP_RUNTIME_RESUME)) {
err = _mmc_resume(host);
pm_runtime_set_active(&host->card->dev);
pm_runtime_mark_last_busy(&host->card->dev);
}
pm_runtime_enable(&host->card->dev);
return err;
}
/* /*
* Callback for runtime_suspend. * Callback for runtime_suspend.
...@@ -1552,18 +1599,11 @@ static int mmc_runtime_suspend(struct mmc_host *host) ...@@ -1552,18 +1599,11 @@ static int mmc_runtime_suspend(struct mmc_host *host)
if (!(host->caps & MMC_CAP_AGGRESSIVE_PM)) if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
return 0; return 0;
mmc_claim_host(host); err = _mmc_suspend(host, true);
if (err)
err = mmc_suspend(host);
if (err) {
pr_err("%s: error %d doing aggessive suspend\n", pr_err("%s: error %d doing aggessive suspend\n",
mmc_hostname(host), err); mmc_hostname(host), err);
goto out;
}
mmc_power_off(host);
out:
mmc_release_host(host);
return err; return err;
} }
...@@ -1574,18 +1614,14 @@ static int mmc_runtime_resume(struct mmc_host *host) ...@@ -1574,18 +1614,14 @@ static int mmc_runtime_resume(struct mmc_host *host)
{ {
int err; int err;
if (!(host->caps & MMC_CAP_AGGRESSIVE_PM)) if (!(host->caps & (MMC_CAP_AGGRESSIVE_PM | MMC_CAP_RUNTIME_RESUME)))
return 0; return 0;
mmc_claim_host(host); err = _mmc_resume(host);
mmc_power_up(host);
err = mmc_resume(host);
if (err) if (err)
pr_err("%s: error %d doing aggessive resume\n", pr_err("%s: error %d doing aggessive resume\n",
mmc_hostname(host), err); mmc_hostname(host), err);
mmc_release_host(host);
return 0; return 0;
} }
...@@ -1595,7 +1631,7 @@ static int mmc_power_restore(struct mmc_host *host) ...@@ -1595,7 +1631,7 @@ static int mmc_power_restore(struct mmc_host *host)
host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200); host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
mmc_claim_host(host); mmc_claim_host(host);
ret = mmc_init_card(host, host->ocr, host->card); ret = mmc_init_card(host, host->card->ocr, host->card);
mmc_release_host(host); mmc_release_host(host);
return ret; return ret;
...@@ -1640,7 +1676,7 @@ static void mmc_attach_bus_ops(struct mmc_host *host) ...@@ -1640,7 +1676,7 @@ static void mmc_attach_bus_ops(struct mmc_host *host)
int mmc_attach_mmc(struct mmc_host *host) int mmc_attach_mmc(struct mmc_host *host)
{ {
int err; int err;
u32 ocr; u32 ocr, rocr;
BUG_ON(!host); BUG_ON(!host);
WARN_ON(!host->claimed); WARN_ON(!host->claimed);
...@@ -1666,23 +1702,12 @@ int mmc_attach_mmc(struct mmc_host *host) ...@@ -1666,23 +1702,12 @@ int mmc_attach_mmc(struct mmc_host *host)
goto err; goto err;
} }
/* rocr = mmc_select_voltage(host, ocr);
* Sanity check the voltages that the card claims to
* support.
*/
if (ocr & 0x7F) {
pr_warning("%s: card claims to support voltages "
"below the defined range. These will be ignored.\n",
mmc_hostname(host));
ocr &= ~0x7F;
}
host->ocr = mmc_select_voltage(host, ocr);
/* /*
* Can we support the voltage of the card? * Can we support the voltage of the card?
*/ */
if (!host->ocr) { if (!rocr) {
err = -EINVAL; err = -EINVAL;
goto err; goto err;
} }
...@@ -1690,7 +1715,7 @@ int mmc_attach_mmc(struct mmc_host *host) ...@@ -1690,7 +1715,7 @@ int mmc_attach_mmc(struct mmc_host *host)
/* /*
* Detect and init the card. * Detect and init the card.
*/ */
err = mmc_init_card(host, host->ocr, NULL); err = mmc_init_card(host, rocr, NULL);
if (err) if (err)
goto err; goto err;
......
...@@ -23,6 +23,40 @@ ...@@ -23,6 +23,40 @@
#define MMC_OPS_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */ #define MMC_OPS_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */
static inline int __mmc_send_status(struct mmc_card *card, u32 *status,
bool ignore_crc)
{
int err;
struct mmc_command cmd = {0};
BUG_ON(!card);
BUG_ON(!card->host);
cmd.opcode = MMC_SEND_STATUS;
if (!mmc_host_is_spi(card->host))
cmd.arg = card->rca << 16;
cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
if (ignore_crc)
cmd.flags &= ~MMC_RSP_CRC;
err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
if (err)
return err;
/* NOTE: callers are required to understand the difference
* between "native" and SPI format status words!
*/
if (status)
*status = cmd.resp[0];
return 0;
}
int mmc_send_status(struct mmc_card *card, u32 *status)
{
return __mmc_send_status(card, status, false);
}
static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card) static int _mmc_select_card(struct mmc_host *host, struct mmc_card *card)
{ {
int err; int err;
...@@ -370,16 +404,18 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc) ...@@ -370,16 +404,18 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
* @timeout_ms: timeout (ms) for operation performed by register write, * @timeout_ms: timeout (ms) for operation performed by register write,
* timeout of zero implies maximum possible timeout * timeout of zero implies maximum possible timeout
* @use_busy_signal: use the busy signal as response type * @use_busy_signal: use the busy signal as response type
* @send_status: send status cmd to poll for busy
* *
* Modifies the EXT_CSD register for selected card. * Modifies the EXT_CSD register for selected card.
*/ */
int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
unsigned int timeout_ms, bool use_busy_signal) unsigned int timeout_ms, bool use_busy_signal, bool send_status)
{ {
int err; int err;
struct mmc_command cmd = {0}; struct mmc_command cmd = {0};
unsigned long timeout; unsigned long timeout;
u32 status; u32 status = 0;
bool ignore_crc = false;
BUG_ON(!card); BUG_ON(!card);
BUG_ON(!card->host); BUG_ON(!card->host);
...@@ -408,17 +444,37 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, ...@@ -408,17 +444,37 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
if (!use_busy_signal) if (!use_busy_signal)
return 0; return 0;
/* Must check status to be sure of no errors */ /*
* Must check status to be sure of no errors
* If CMD13 is to check the busy completion of the timing change,
* disable the check of CRC error.
*/
if (index == EXT_CSD_HS_TIMING &&
!(card->host->caps & MMC_CAP_WAIT_WHILE_BUSY))
ignore_crc = true;
timeout = jiffies + msecs_to_jiffies(MMC_OPS_TIMEOUT_MS); timeout = jiffies + msecs_to_jiffies(MMC_OPS_TIMEOUT_MS);
do { do {
err = mmc_send_status(card, &status); if (send_status) {
if (err) err = __mmc_send_status(card, &status, ignore_crc);
return err; if (err)
return err;
}
if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY)
break; break;
if (mmc_host_is_spi(card->host)) if (mmc_host_is_spi(card->host))
break; break;
/*
* We are not allowed to issue a status command and the host
* does'nt support MMC_CAP_WAIT_WHILE_BUSY, then we can only
* rely on waiting for the stated timeout to be sufficient.
*/
if (!send_status) {
mmc_delay(timeout_ms);
return 0;
}
/* Timeout if the device never leaves the program state. */ /* Timeout if the device never leaves the program state. */
if (time_after(jiffies, timeout)) { if (time_after(jiffies, timeout)) {
pr_err("%s: Card stuck in programming state! %s\n", pr_err("%s: Card stuck in programming state! %s\n",
...@@ -445,36 +501,10 @@ EXPORT_SYMBOL_GPL(__mmc_switch); ...@@ -445,36 +501,10 @@ EXPORT_SYMBOL_GPL(__mmc_switch);
int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value, int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
unsigned int timeout_ms) unsigned int timeout_ms)
{ {
return __mmc_switch(card, set, index, value, timeout_ms, true); return __mmc_switch(card, set, index, value, timeout_ms, true, true);
} }
EXPORT_SYMBOL_GPL(mmc_switch); EXPORT_SYMBOL_GPL(mmc_switch);
int mmc_send_status(struct mmc_card *card, u32 *status)
{
int err;
struct mmc_command cmd = {0};
BUG_ON(!card);
BUG_ON(!card->host);
cmd.opcode = MMC_SEND_STATUS;
if (!mmc_host_is_spi(card->host))
cmd.arg = card->rca << 16;
cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
if (err)
return err;
/* NOTE: callers are required to understand the difference
* between "native" and SPI format status words!
*/
if (status)
*status = cmd.resp[0];
return 0;
}
static int static int
mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode, mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
u8 len) u8 len)
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/stat.h> #include <linux/stat.h>
#include <linux/pm_runtime.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/card.h> #include <linux/mmc/card.h>
...@@ -721,6 +722,7 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr) ...@@ -721,6 +722,7 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
int err; int err;
u32 max_current; u32 max_current;
int retries = 10; int retries = 10;
u32 pocr = ocr;
try_again: try_again:
if (!retries) { if (!retries) {
...@@ -773,7 +775,8 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr) ...@@ -773,7 +775,8 @@ int mmc_sd_get_cid(struct mmc_host *host, u32 ocr, u32 *cid, u32 *rocr)
*/ */
if (!mmc_host_is_spi(host) && rocr && if (!mmc_host_is_spi(host) && rocr &&
((*rocr & 0x41000000) == 0x41000000)) { ((*rocr & 0x41000000) == 0x41000000)) {
err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180); err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180,
pocr);
if (err == -EAGAIN) { if (err == -EAGAIN) {
retries--; retries--;
goto try_again; goto try_again;
...@@ -935,6 +938,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr, ...@@ -935,6 +938,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
if (IS_ERR(card)) if (IS_ERR(card))
return PTR_ERR(card); return PTR_ERR(card);
card->ocr = ocr;
card->type = MMC_TYPE_SD; card->type = MMC_TYPE_SD;
memcpy(card->raw_cid, cid, sizeof(card->raw_cid)); memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
} }
...@@ -1064,10 +1068,7 @@ static void mmc_sd_detect(struct mmc_host *host) ...@@ -1064,10 +1068,7 @@ static void mmc_sd_detect(struct mmc_host *host)
} }
} }
/* static int _mmc_sd_suspend(struct mmc_host *host)
* Suspend callback from host.
*/
static int mmc_sd_suspend(struct mmc_host *host)
{ {
int err = 0; int err = 0;
...@@ -1075,34 +1076,77 @@ static int mmc_sd_suspend(struct mmc_host *host) ...@@ -1075,34 +1076,77 @@ static int mmc_sd_suspend(struct mmc_host *host)
BUG_ON(!host->card); BUG_ON(!host->card);
mmc_claim_host(host); mmc_claim_host(host);
if (mmc_card_suspended(host->card))
goto out;
if (!mmc_host_is_spi(host)) if (!mmc_host_is_spi(host))
err = mmc_deselect_cards(host); err = mmc_deselect_cards(host);
host->card->state &= ~MMC_STATE_HIGHSPEED; host->card->state &= ~MMC_STATE_HIGHSPEED;
if (!err) if (!err) {
mmc_power_off(host); mmc_power_off(host);
mmc_card_set_suspended(host->card);
}
out:
mmc_release_host(host); mmc_release_host(host);
return err;
}
/*
* Callback for suspend
*/
static int 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; return err;
} }
/* /*
* Resume callback from host.
*
* This function tries to determine if the same card is still present * This function tries to determine if the same card is still present
* and, if so, restore all state to it. * and, if so, restore all state to it.
*/ */
static int mmc_sd_resume(struct mmc_host *host) static int _mmc_sd_resume(struct mmc_host *host)
{ {
int err; int err = 0;
BUG_ON(!host); BUG_ON(!host);
BUG_ON(!host->card); BUG_ON(!host->card);
mmc_claim_host(host); mmc_claim_host(host);
mmc_power_up(host);
mmc_select_voltage(host, host->ocr); if (!mmc_card_suspended(host->card))
err = mmc_sd_init_card(host, host->ocr, host->card); goto out;
mmc_power_up(host, host->card->ocr);
err = mmc_sd_init_card(host, host->card->ocr, host->card);
mmc_card_clr_suspended(host->card);
out:
mmc_release_host(host); mmc_release_host(host);
return err;
}
/*
* Callback for resume
*/
static int mmc_sd_resume(struct mmc_host *host)
{
int err = 0;
if (!(host->caps & MMC_CAP_RUNTIME_RESUME)) {
err = _mmc_sd_resume(host);
pm_runtime_set_active(&host->card->dev);
pm_runtime_mark_last_busy(&host->card->dev);
}
pm_runtime_enable(&host->card->dev);
return err; return err;
} }
...@@ -1117,18 +1161,11 @@ static int mmc_sd_runtime_suspend(struct mmc_host *host) ...@@ -1117,18 +1161,11 @@ static int mmc_sd_runtime_suspend(struct mmc_host *host)
if (!(host->caps & MMC_CAP_AGGRESSIVE_PM)) if (!(host->caps & MMC_CAP_AGGRESSIVE_PM))
return 0; return 0;
mmc_claim_host(host); err = _mmc_sd_suspend(host);
if (err)
err = mmc_sd_suspend(host);
if (err) {
pr_err("%s: error %d doing aggessive suspend\n", pr_err("%s: error %d doing aggessive suspend\n",
mmc_hostname(host), err); mmc_hostname(host), err);
goto out;
}
mmc_power_off(host);
out:
mmc_release_host(host);
return err; return err;
} }
...@@ -1139,18 +1176,14 @@ static int mmc_sd_runtime_resume(struct mmc_host *host) ...@@ -1139,18 +1176,14 @@ static int mmc_sd_runtime_resume(struct mmc_host *host)
{ {
int err; int err;
if (!(host->caps & MMC_CAP_AGGRESSIVE_PM)) if (!(host->caps & (MMC_CAP_AGGRESSIVE_PM | MMC_CAP_RUNTIME_RESUME)))
return 0; return 0;
mmc_claim_host(host); err = _mmc_sd_resume(host);
mmc_power_up(host);
err = mmc_sd_resume(host);
if (err) if (err)
pr_err("%s: error %d doing aggessive resume\n", pr_err("%s: error %d doing aggessive resume\n",
mmc_hostname(host), err); mmc_hostname(host), err);
mmc_release_host(host);
return 0; return 0;
} }
...@@ -1160,7 +1193,7 @@ static int mmc_sd_power_restore(struct mmc_host *host) ...@@ -1160,7 +1193,7 @@ static int mmc_sd_power_restore(struct mmc_host *host)
host->card->state &= ~MMC_STATE_HIGHSPEED; host->card->state &= ~MMC_STATE_HIGHSPEED;
mmc_claim_host(host); mmc_claim_host(host);
ret = mmc_sd_init_card(host, host->ocr, host->card); ret = mmc_sd_init_card(host, host->card->ocr, host->card);
mmc_release_host(host); mmc_release_host(host);
return ret; return ret;
...@@ -1205,7 +1238,7 @@ static void mmc_sd_attach_bus_ops(struct mmc_host *host) ...@@ -1205,7 +1238,7 @@ static void mmc_sd_attach_bus_ops(struct mmc_host *host)
int mmc_attach_sd(struct mmc_host *host) int mmc_attach_sd(struct mmc_host *host)
{ {
int err; int err;
u32 ocr; u32 ocr, rocr;
BUG_ON(!host); BUG_ON(!host);
WARN_ON(!host->claimed); WARN_ON(!host->claimed);
...@@ -1229,31 +1262,12 @@ int mmc_attach_sd(struct mmc_host *host) ...@@ -1229,31 +1262,12 @@ int mmc_attach_sd(struct mmc_host *host)
goto err; goto err;
} }
/* rocr = mmc_select_voltage(host, ocr);
* Sanity check the voltages that the card claims to
* support.
*/
if (ocr & 0x7F) {
pr_warning("%s: card claims to support voltages "
"below the defined range. These will be ignored.\n",
mmc_hostname(host));
ocr &= ~0x7F;
}
if ((ocr & MMC_VDD_165_195) &&
!(host->ocr_avail_sd & MMC_VDD_165_195)) {
pr_warning("%s: SD card claims to support the "
"incompletely defined 'low voltage range'. This "
"will be ignored.\n", mmc_hostname(host));
ocr &= ~MMC_VDD_165_195;
}
host->ocr = mmc_select_voltage(host, ocr);
/* /*
* Can we support the voltage(s) of the card(s)? * Can we support the voltage(s) of the card(s)?
*/ */
if (!host->ocr) { if (!rocr) {
err = -EINVAL; err = -EINVAL;
goto err; goto err;
} }
...@@ -1261,7 +1275,7 @@ int mmc_attach_sd(struct mmc_host *host) ...@@ -1261,7 +1275,7 @@ int mmc_attach_sd(struct mmc_host *host)
/* /*
* Detect and init the card. * Detect and init the card.
*/ */
err = mmc_sd_init_card(host, host->ocr, NULL); err = mmc_sd_init_card(host, rocr, NULL);
if (err) if (err)
goto err; goto err;
......
...@@ -593,23 +593,28 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, ...@@ -593,23 +593,28 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
struct mmc_card *card; struct mmc_card *card;
int err; int err;
int retries = 10; int retries = 10;
u32 rocr = 0;
u32 ocr_card = ocr;
BUG_ON(!host); BUG_ON(!host);
WARN_ON(!host->claimed); WARN_ON(!host->claimed);
/* to query card if 1.8V signalling is supported */
if (mmc_host_uhs(host))
ocr |= R4_18V_PRESENT;
try_again: try_again:
if (!retries) { if (!retries) {
pr_warning("%s: Skipping voltage switch\n", pr_warning("%s: Skipping voltage switch\n",
mmc_hostname(host)); mmc_hostname(host));
ocr &= ~R4_18V_PRESENT; ocr &= ~R4_18V_PRESENT;
host->ocr &= ~R4_18V_PRESENT;
} }
/* /*
* Inform the card of the voltage * Inform the card of the voltage
*/ */
if (!powered_resume) { if (!powered_resume) {
err = mmc_send_io_op_cond(host, host->ocr, &ocr); err = mmc_send_io_op_cond(host, ocr, &rocr);
if (err) if (err)
goto err; goto err;
} }
...@@ -632,8 +637,8 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, ...@@ -632,8 +637,8 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
goto err; goto err;
} }
if ((ocr & R4_MEMORY_PRESENT) && if ((rocr & R4_MEMORY_PRESENT) &&
mmc_sd_get_cid(host, host->ocr & ocr, card->raw_cid, NULL) == 0) { mmc_sd_get_cid(host, ocr & rocr, card->raw_cid, NULL) == 0) {
card->type = MMC_TYPE_SD_COMBO; card->type = MMC_TYPE_SD_COMBO;
if (oldcard && (oldcard->type != MMC_TYPE_SD_COMBO || if (oldcard && (oldcard->type != MMC_TYPE_SD_COMBO ||
...@@ -663,8 +668,9 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, ...@@ -663,8 +668,9 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
* systems that claim 1.8v signalling in fact do not support * systems that claim 1.8v signalling in fact do not support
* it. * it.
*/ */
if (!powered_resume && (ocr & R4_18V_PRESENT) && mmc_host_uhs(host)) { if (!powered_resume && (rocr & ocr & R4_18V_PRESENT)) {
err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180); err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180,
ocr);
if (err == -EAGAIN) { if (err == -EAGAIN) {
sdio_reset(host); sdio_reset(host);
mmc_go_idle(host); mmc_go_idle(host);
...@@ -674,12 +680,10 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, ...@@ -674,12 +680,10 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
goto try_again; goto try_again;
} else if (err) { } else if (err) {
ocr &= ~R4_18V_PRESENT; ocr &= ~R4_18V_PRESENT;
host->ocr &= ~R4_18V_PRESENT;
} }
err = 0; err = 0;
} else { } else {
ocr &= ~R4_18V_PRESENT; ocr &= ~R4_18V_PRESENT;
host->ocr &= ~R4_18V_PRESENT;
} }
/* /*
...@@ -759,6 +763,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr, ...@@ -759,6 +763,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
card = oldcard; card = oldcard;
} }
card->ocr = ocr_card;
mmc_fixup_device(card, NULL); mmc_fixup_device(card, NULL);
if (card->type == MMC_TYPE_SD_COMBO) { if (card->type == MMC_TYPE_SD_COMBO) {
...@@ -981,8 +986,7 @@ static int mmc_sdio_resume(struct mmc_host *host) ...@@ -981,8 +986,7 @@ static int mmc_sdio_resume(struct mmc_host *host)
/* Restore power if needed */ /* Restore power if needed */
if (!mmc_card_keep_power(host)) { if (!mmc_card_keep_power(host)) {
mmc_power_up(host); mmc_power_up(host, host->card->ocr);
mmc_select_voltage(host, host->ocr);
/* /*
* Tell runtime PM core we just powered up the card, * Tell runtime PM core we just powered up the card,
* since it still believes the card is powered off. * since it still believes the card is powered off.
...@@ -1000,7 +1004,7 @@ static int mmc_sdio_resume(struct mmc_host *host) ...@@ -1000,7 +1004,7 @@ static int mmc_sdio_resume(struct mmc_host *host)
if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) { if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) {
sdio_reset(host); sdio_reset(host);
mmc_go_idle(host); mmc_go_idle(host);
err = mmc_sdio_init_card(host, host->ocr, host->card, err = mmc_sdio_init_card(host, host->card->ocr, host->card,
mmc_card_keep_power(host)); mmc_card_keep_power(host));
} else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) { } else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
/* We may have switched to 1-bit mode during suspend */ /* We may have switched to 1-bit mode during suspend */
...@@ -1040,7 +1044,6 @@ static int mmc_sdio_resume(struct mmc_host *host) ...@@ -1040,7 +1044,6 @@ static int mmc_sdio_resume(struct mmc_host *host)
static int mmc_sdio_power_restore(struct mmc_host *host) static int mmc_sdio_power_restore(struct mmc_host *host)
{ {
int ret; int ret;
u32 ocr;
BUG_ON(!host); BUG_ON(!host);
BUG_ON(!host->card); BUG_ON(!host->card);
...@@ -1062,32 +1065,17 @@ static int mmc_sdio_power_restore(struct mmc_host *host) ...@@ -1062,32 +1065,17 @@ static int mmc_sdio_power_restore(struct mmc_host *host)
* for OLPC SD8686 (which expects a [CMD5,5,3,7] init sequence), and * for OLPC SD8686 (which expects a [CMD5,5,3,7] init sequence), and
* harmless in other situations. * harmless in other situations.
* *
* With these steps taken, mmc_select_voltage() is also required to
* restore the correct voltage setting of the card.
*/ */
sdio_reset(host); sdio_reset(host);
mmc_go_idle(host); mmc_go_idle(host);
mmc_send_if_cond(host, host->ocr_avail); mmc_send_if_cond(host, host->ocr_avail);
ret = mmc_send_io_op_cond(host, 0, &ocr); ret = mmc_send_io_op_cond(host, 0, NULL);
if (ret) if (ret)
goto out; goto out;
if (host->ocr_avail_sdio) ret = mmc_sdio_init_card(host, host->card->ocr, host->card,
host->ocr_avail = host->ocr_avail_sdio;
host->ocr = mmc_select_voltage(host, ocr & ~0x7F);
if (!host->ocr) {
ret = -EINVAL;
goto out;
}
if (mmc_host_uhs(host))
/* to query card if 1.8V signalling is supported */
host->ocr |= R4_18V_PRESENT;
ret = mmc_sdio_init_card(host, host->ocr, host->card,
mmc_card_keep_power(host)); mmc_card_keep_power(host));
if (!ret && host->sdio_irqs) if (!ret && host->sdio_irqs)
mmc_signal_sdio_irq(host); mmc_signal_sdio_irq(host);
...@@ -1108,7 +1096,7 @@ static int mmc_sdio_runtime_suspend(struct mmc_host *host) ...@@ -1108,7 +1096,7 @@ static int mmc_sdio_runtime_suspend(struct mmc_host *host)
static int mmc_sdio_runtime_resume(struct mmc_host *host) static int mmc_sdio_runtime_resume(struct mmc_host *host)
{ {
/* Restore power and re-initialize. */ /* Restore power and re-initialize. */
mmc_power_up(host); mmc_power_up(host, host->card->ocr);
return mmc_sdio_power_restore(host); return mmc_sdio_power_restore(host);
} }
...@@ -1131,7 +1119,7 @@ static const struct mmc_bus_ops mmc_sdio_ops = { ...@@ -1131,7 +1119,7 @@ static const struct mmc_bus_ops mmc_sdio_ops = {
int mmc_attach_sdio(struct mmc_host *host) int mmc_attach_sdio(struct mmc_host *host)
{ {
int err, i, funcs; int err, i, funcs;
u32 ocr; u32 ocr, rocr;
struct mmc_card *card; struct mmc_card *card;
BUG_ON(!host); BUG_ON(!host);
...@@ -1145,23 +1133,13 @@ int mmc_attach_sdio(struct mmc_host *host) ...@@ -1145,23 +1133,13 @@ int mmc_attach_sdio(struct mmc_host *host)
if (host->ocr_avail_sdio) if (host->ocr_avail_sdio)
host->ocr_avail = host->ocr_avail_sdio; host->ocr_avail = host->ocr_avail_sdio;
/*
* Sanity check the voltages that the card claims to
* support.
*/
if (ocr & 0x7F) {
pr_warning("%s: card claims to support voltages "
"below the defined range. These will be ignored.\n",
mmc_hostname(host));
ocr &= ~0x7F;
}
host->ocr = mmc_select_voltage(host, ocr); rocr = mmc_select_voltage(host, ocr);
/* /*
* Can we support the voltage(s) of the card(s)? * Can we support the voltage(s) of the card(s)?
*/ */
if (!host->ocr) { if (!rocr) {
err = -EINVAL; err = -EINVAL;
goto err; goto err;
} }
...@@ -1169,22 +1147,10 @@ int mmc_attach_sdio(struct mmc_host *host) ...@@ -1169,22 +1147,10 @@ int mmc_attach_sdio(struct mmc_host *host)
/* /*
* Detect and init the card. * Detect and init the card.
*/ */
if (mmc_host_uhs(host)) err = mmc_sdio_init_card(host, rocr, NULL, 0);
/* to query card if 1.8V signalling is supported */ if (err)
host->ocr |= R4_18V_PRESENT; goto err;
err = mmc_sdio_init_card(host, host->ocr, NULL, 0);
if (err) {
if (err == -EAGAIN) {
/*
* Retry initialization with S18R set to 0.
*/
host->ocr &= ~R4_18V_PRESENT;
err = mmc_sdio_init_card(host, host->ocr, NULL, 0);
}
if (err)
goto err;
}
card = host->card; card = host->card;
/* /*
......
...@@ -255,7 +255,6 @@ struct atmel_mci_slot { ...@@ -255,7 +255,6 @@ struct atmel_mci_slot {
#define ATMCI_CARD_PRESENT 0 #define ATMCI_CARD_PRESENT 0
#define ATMCI_CARD_NEED_INIT 1 #define ATMCI_CARD_NEED_INIT 1
#define ATMCI_SHUTDOWN 2 #define ATMCI_SHUTDOWN 2
#define ATMCI_SUSPENDED 3
int detect_pin; int detect_pin;
int wp_pin; int wp_pin;
...@@ -589,6 +588,13 @@ static void atmci_timeout_timer(unsigned long data) ...@@ -589,6 +588,13 @@ static void atmci_timeout_timer(unsigned long data)
if (host->mrq->cmd->data) { if (host->mrq->cmd->data) {
host->mrq->cmd->data->error = -ETIMEDOUT; host->mrq->cmd->data->error = -ETIMEDOUT;
host->data = NULL; host->data = NULL;
/*
* With some SDIO modules, sometimes DMA transfer hangs. If
* stop_transfer() is not called then the DMA request is not
* removed, following ones are queued and never computed.
*/
if (host->state == STATE_DATA_XFER)
host->stop_transfer(host);
} else { } else {
host->mrq->cmd->error = -ETIMEDOUT; host->mrq->cmd->error = -ETIMEDOUT;
host->cmd = NULL; host->cmd = NULL;
...@@ -1803,12 +1809,14 @@ static void atmci_tasklet_func(unsigned long priv) ...@@ -1803,12 +1809,14 @@ static void atmci_tasklet_func(unsigned long priv)
if (unlikely(status)) { if (unlikely(status)) {
host->stop_transfer(host); host->stop_transfer(host);
host->data = NULL; host->data = NULL;
if (status & ATMCI_DTOE) { if (data) {
data->error = -ETIMEDOUT; if (status & ATMCI_DTOE) {
} else if (status & ATMCI_DCRCE) { data->error = -ETIMEDOUT;
data->error = -EILSEQ; } else if (status & ATMCI_DCRCE) {
} else { data->error = -EILSEQ;
data->error = -EIO; } else {
data->error = -EIO;
}
} }
} }
...@@ -2520,70 +2528,10 @@ static int __exit atmci_remove(struct platform_device *pdev) ...@@ -2520,70 +2528,10 @@ static int __exit atmci_remove(struct platform_device *pdev)
return 0; return 0;
} }
#ifdef CONFIG_PM_SLEEP
static int atmci_suspend(struct device *dev)
{
struct atmel_mci *host = dev_get_drvdata(dev);
int i;
for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
struct atmel_mci_slot *slot = host->slot[i];
int ret;
if (!slot)
continue;
ret = mmc_suspend_host(slot->mmc);
if (ret < 0) {
while (--i >= 0) {
slot = host->slot[i];
if (slot
&& test_bit(ATMCI_SUSPENDED, &slot->flags)) {
mmc_resume_host(host->slot[i]->mmc);
clear_bit(ATMCI_SUSPENDED, &slot->flags);
}
}
return ret;
} else {
set_bit(ATMCI_SUSPENDED, &slot->flags);
}
}
return 0;
}
static int atmci_resume(struct device *dev)
{
struct atmel_mci *host = dev_get_drvdata(dev);
int i;
int ret = 0;
for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
struct atmel_mci_slot *slot = host->slot[i];
int err;
slot = host->slot[i];
if (!slot)
continue;
if (!test_bit(ATMCI_SUSPENDED, &slot->flags))
continue;
err = mmc_resume_host(slot->mmc);
if (err < 0)
ret = err;
else
clear_bit(ATMCI_SUSPENDED, &slot->flags);
}
return ret;
}
#endif
static SIMPLE_DEV_PM_OPS(atmci_pm, atmci_suspend, atmci_resume);
static struct platform_driver atmci_driver = { static struct platform_driver atmci_driver = {
.remove = __exit_p(atmci_remove), .remove = __exit_p(atmci_remove),
.driver = { .driver = {
.name = "atmel_mci", .name = "atmel_mci",
.pm = &atmci_pm,
.of_match_table = of_match_ptr(atmci_dt_ids), .of_match_table = of_match_ptr(atmci_dt_ids),
}, },
}; };
......
...@@ -1157,11 +1157,6 @@ static int au1xmmc_remove(struct platform_device *pdev) ...@@ -1157,11 +1157,6 @@ static int au1xmmc_remove(struct platform_device *pdev)
static int au1xmmc_suspend(struct platform_device *pdev, pm_message_t state) static int au1xmmc_suspend(struct platform_device *pdev, pm_message_t state)
{ {
struct au1xmmc_host *host = platform_get_drvdata(pdev); struct au1xmmc_host *host = platform_get_drvdata(pdev);
int ret;
ret = mmc_suspend_host(host->mmc);
if (ret)
return ret;
au_writel(0, HOST_CONFIG2(host)); au_writel(0, HOST_CONFIG2(host));
au_writel(0, HOST_CONFIG(host)); au_writel(0, HOST_CONFIG(host));
...@@ -1178,7 +1173,7 @@ static int au1xmmc_resume(struct platform_device *pdev) ...@@ -1178,7 +1173,7 @@ static int au1xmmc_resume(struct platform_device *pdev)
au1xmmc_reset_controller(host); au1xmmc_reset_controller(host);
return mmc_resume_host(host->mmc); return 0;
} }
#else #else
#define au1xmmc_suspend NULL #define au1xmmc_suspend NULL
......
...@@ -391,6 +391,7 @@ static void sdh_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ...@@ -391,6 +391,7 @@ static void sdh_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
/* Disable 4 bit SDIO */ /* Disable 4 bit SDIO */
cfg &= ~SD4E; cfg &= ~SD4E;
} }
bfin_write_SDH_CFG(cfg);
host->power_mode = ios->power_mode; host->power_mode = ios->power_mode;
#ifndef RSI_BLKSZ #ifndef RSI_BLKSZ
...@@ -415,7 +416,6 @@ static void sdh_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ...@@ -415,7 +416,6 @@ static void sdh_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
cfg &= ~SD_CMD_OD; cfg &= ~SD_CMD_OD;
# endif # endif
if (ios->power_mode != MMC_POWER_OFF) if (ios->power_mode != MMC_POWER_OFF)
cfg |= PWR_ON; cfg |= PWR_ON;
else else
...@@ -433,7 +433,6 @@ static void sdh_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ...@@ -433,7 +433,6 @@ static void sdh_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
clk_ctl |= CLK_E; clk_ctl |= CLK_E;
host->clk_div = clk_div; host->clk_div = clk_div;
bfin_write_SDH_CLK_CTL(clk_ctl); bfin_write_SDH_CLK_CTL(clk_ctl);
} else } else
sdh_stop_clock(host); sdh_stop_clock(host);
...@@ -640,21 +639,15 @@ static int sdh_remove(struct platform_device *pdev) ...@@ -640,21 +639,15 @@ static int sdh_remove(struct platform_device *pdev)
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int sdh_suspend(struct platform_device *dev, pm_message_t state) static int sdh_suspend(struct platform_device *dev, pm_message_t state)
{ {
struct mmc_host *mmc = platform_get_drvdata(dev);
struct bfin_sd_host *drv_data = get_sdh_data(dev); struct bfin_sd_host *drv_data = get_sdh_data(dev);
int ret = 0;
if (mmc)
ret = mmc_suspend_host(mmc);
peripheral_free_list(drv_data->pin_req); peripheral_free_list(drv_data->pin_req);
return ret; return 0;
} }
static int sdh_resume(struct platform_device *dev) static int sdh_resume(struct platform_device *dev)
{ {
struct mmc_host *mmc = platform_get_drvdata(dev);
struct bfin_sd_host *drv_data = get_sdh_data(dev); struct bfin_sd_host *drv_data = get_sdh_data(dev);
int ret = 0; int ret = 0;
...@@ -665,10 +658,6 @@ static int sdh_resume(struct platform_device *dev) ...@@ -665,10 +658,6 @@ static int sdh_resume(struct platform_device *dev)
} }
sdh_reset(); sdh_reset();
if (mmc)
ret = mmc_resume_host(mmc);
return ret; return ret;
} }
#else #else
......
...@@ -667,12 +667,6 @@ static const struct mmc_host_ops cb710_mmc_host = { ...@@ -667,12 +667,6 @@ static const struct mmc_host_ops cb710_mmc_host = {
static int cb710_mmc_suspend(struct platform_device *pdev, pm_message_t state) static int cb710_mmc_suspend(struct platform_device *pdev, pm_message_t state)
{ {
struct cb710_slot *slot = cb710_pdev_to_slot(pdev); struct cb710_slot *slot = cb710_pdev_to_slot(pdev);
struct mmc_host *mmc = cb710_slot_to_mmc(slot);
int err;
err = mmc_suspend_host(mmc);
if (err)
return err;
cb710_mmc_enable_irq(slot, 0, ~0); cb710_mmc_enable_irq(slot, 0, ~0);
return 0; return 0;
...@@ -681,11 +675,9 @@ static int cb710_mmc_suspend(struct platform_device *pdev, pm_message_t state) ...@@ -681,11 +675,9 @@ static int cb710_mmc_suspend(struct platform_device *pdev, pm_message_t state)
static int cb710_mmc_resume(struct platform_device *pdev) static int cb710_mmc_resume(struct platform_device *pdev)
{ {
struct cb710_slot *slot = cb710_pdev_to_slot(pdev); struct cb710_slot *slot = cb710_pdev_to_slot(pdev);
struct mmc_host *mmc = cb710_slot_to_mmc(slot);
cb710_mmc_enable_irq(slot, 0, ~0); cb710_mmc_enable_irq(slot, 0, ~0);
return 0;
return mmc_resume_host(mmc);
} }
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
......
...@@ -193,7 +193,6 @@ struct mmc_davinci_host { ...@@ -193,7 +193,6 @@ struct mmc_davinci_host {
#define DAVINCI_MMC_DATADIR_READ 1 #define DAVINCI_MMC_DATADIR_READ 1
#define DAVINCI_MMC_DATADIR_WRITE 2 #define DAVINCI_MMC_DATADIR_WRITE 2
unsigned char data_dir; unsigned char data_dir;
unsigned char suspended;
/* buffer is used during PIO of one scatterlist segment, and /* buffer is used during PIO of one scatterlist segment, and
* is updated along with buffer_bytes_left. bytes_left applies * is updated along with buffer_bytes_left. bytes_left applies
...@@ -1435,38 +1434,23 @@ static int davinci_mmcsd_suspend(struct device *dev) ...@@ -1435,38 +1434,23 @@ static int davinci_mmcsd_suspend(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
struct mmc_davinci_host *host = platform_get_drvdata(pdev); struct mmc_davinci_host *host = platform_get_drvdata(pdev);
int ret;
ret = mmc_suspend_host(host->mmc); writel(0, host->base + DAVINCI_MMCIM);
if (!ret) { mmc_davinci_reset_ctrl(host, 1);
writel(0, host->base + DAVINCI_MMCIM); clk_disable(host->clk);
mmc_davinci_reset_ctrl(host, 1);
clk_disable(host->clk);
host->suspended = 1;
} else {
host->suspended = 0;
}
return ret; return 0;
} }
static int davinci_mmcsd_resume(struct device *dev) static int davinci_mmcsd_resume(struct device *dev)
{ {
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
struct mmc_davinci_host *host = platform_get_drvdata(pdev); struct mmc_davinci_host *host = platform_get_drvdata(pdev);
int ret;
if (!host->suspended)
return 0;
clk_enable(host->clk); clk_enable(host->clk);
mmc_davinci_reset_ctrl(host, 0); mmc_davinci_reset_ctrl(host, 0);
ret = mmc_resume_host(host->mmc);
if (!ret)
host->suspended = 0;
return ret; return 0;
} }
static const struct dev_pm_ops davinci_mmcsd_pm = { static const struct dev_pm_ops davinci_mmcsd_pm = {
......
...@@ -14,8 +14,10 @@ ...@@ -14,8 +14,10 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/dw_mmc.h> #include <linux/mmc/dw_mmc.h>
#include <linux/mmc/mmc.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
#include <linux/slab.h>
#include "dw_mmc.h" #include "dw_mmc.h"
#include "dw_mmc-pltfm.h" #include "dw_mmc-pltfm.h"
...@@ -30,16 +32,39 @@ ...@@ -30,16 +32,39 @@
#define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) | \ #define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) | \
SDMMC_CLKSEL_CCLK_DRIVE(y) | \ SDMMC_CLKSEL_CCLK_DRIVE(y) | \
SDMMC_CLKSEL_CCLK_DIVIDER(z)) SDMMC_CLKSEL_CCLK_DIVIDER(z))
#define SDMMC_CLKSEL_WAKEUP_INT BIT(11)
#define EXYNOS4210_FIXED_CIU_CLK_DIV 2 #define EXYNOS4210_FIXED_CIU_CLK_DIV 2
#define EXYNOS4412_FIXED_CIU_CLK_DIV 4 #define EXYNOS4412_FIXED_CIU_CLK_DIV 4
/* Block number in eMMC */
#define DWMCI_BLOCK_NUM 0xFFFFFFFF
#define SDMMC_EMMCP_BASE 0x1000
#define SDMMC_MPSECURITY (SDMMC_EMMCP_BASE + 0x0010)
#define SDMMC_MPSBEGIN0 (SDMMC_EMMCP_BASE + 0x0200)
#define SDMMC_MPSEND0 (SDMMC_EMMCP_BASE + 0x0204)
#define SDMMC_MPSCTRL0 (SDMMC_EMMCP_BASE + 0x020C)
/* SMU control bits */
#define DWMCI_MPSCTRL_SECURE_READ_BIT BIT(7)
#define DWMCI_MPSCTRL_SECURE_WRITE_BIT BIT(6)
#define DWMCI_MPSCTRL_NON_SECURE_READ_BIT BIT(5)
#define DWMCI_MPSCTRL_NON_SECURE_WRITE_BIT BIT(4)
#define DWMCI_MPSCTRL_USE_FUSE_KEY BIT(3)
#define DWMCI_MPSCTRL_ECB_MODE BIT(2)
#define DWMCI_MPSCTRL_ENCRYPTION BIT(1)
#define DWMCI_MPSCTRL_VALID BIT(0)
#define EXYNOS_CCLKIN_MIN 50000000 /* unit: HZ */
/* Variations in Exynos specific dw-mshc controller */ /* Variations in Exynos specific dw-mshc controller */
enum dw_mci_exynos_type { enum dw_mci_exynos_type {
DW_MCI_TYPE_EXYNOS4210, DW_MCI_TYPE_EXYNOS4210,
DW_MCI_TYPE_EXYNOS4412, DW_MCI_TYPE_EXYNOS4412,
DW_MCI_TYPE_EXYNOS5250, DW_MCI_TYPE_EXYNOS5250,
DW_MCI_TYPE_EXYNOS5420, DW_MCI_TYPE_EXYNOS5420,
DW_MCI_TYPE_EXYNOS5420_SMU,
}; };
/* Exynos implementation specific driver private data */ /* Exynos implementation specific driver private data */
...@@ -48,6 +73,7 @@ struct dw_mci_exynos_priv_data { ...@@ -48,6 +73,7 @@ struct dw_mci_exynos_priv_data {
u8 ciu_div; u8 ciu_div;
u32 sdr_timing; u32 sdr_timing;
u32 ddr_timing; u32 ddr_timing;
u32 cur_speed;
}; };
static struct dw_mci_exynos_compatible { static struct dw_mci_exynos_compatible {
...@@ -66,44 +92,80 @@ static struct dw_mci_exynos_compatible { ...@@ -66,44 +92,80 @@ static struct dw_mci_exynos_compatible {
}, { }, {
.compatible = "samsung,exynos5420-dw-mshc", .compatible = "samsung,exynos5420-dw-mshc",
.ctrl_type = DW_MCI_TYPE_EXYNOS5420, .ctrl_type = DW_MCI_TYPE_EXYNOS5420,
}, {
.compatible = "samsung,exynos5420-dw-mshc-smu",
.ctrl_type = DW_MCI_TYPE_EXYNOS5420_SMU,
}, },
}; };
static int dw_mci_exynos_priv_init(struct dw_mci *host) static int dw_mci_exynos_priv_init(struct dw_mci *host)
{ {
struct dw_mci_exynos_priv_data *priv; struct dw_mci_exynos_priv_data *priv = host->priv;
int idx;
priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
if (!priv) {
dev_err(host->dev, "mem alloc failed for private data\n");
return -ENOMEM;
}
for (idx = 0; idx < ARRAY_SIZE(exynos_compat); idx++) { if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5420_SMU) {
if (of_device_is_compatible(host->dev->of_node, mci_writel(host, MPSBEGIN0, 0);
exynos_compat[idx].compatible)) mci_writel(host, MPSEND0, DWMCI_BLOCK_NUM);
priv->ctrl_type = exynos_compat[idx].ctrl_type; mci_writel(host, MPSCTRL0, DWMCI_MPSCTRL_SECURE_WRITE_BIT |
DWMCI_MPSCTRL_NON_SECURE_READ_BIT |
DWMCI_MPSCTRL_VALID |
DWMCI_MPSCTRL_NON_SECURE_WRITE_BIT);
} }
host->priv = priv;
return 0; return 0;
} }
static int dw_mci_exynos_setup_clock(struct dw_mci *host) static int dw_mci_exynos_setup_clock(struct dw_mci *host)
{ {
struct dw_mci_exynos_priv_data *priv = host->priv; struct dw_mci_exynos_priv_data *priv = host->priv;
unsigned long rate = clk_get_rate(host->ciu_clk);
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5250 || host->bus_hz = rate / (priv->ciu_div + 1);
priv->ctrl_type == DW_MCI_TYPE_EXYNOS5420) return 0;
host->bus_hz /= (priv->ciu_div + 1); }
else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412)
host->bus_hz /= EXYNOS4412_FIXED_CIU_CLK_DIV; #ifdef CONFIG_PM_SLEEP
else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210) static int dw_mci_exynos_suspend(struct device *dev)
host->bus_hz /= EXYNOS4210_FIXED_CIU_CLK_DIV; {
struct dw_mci *host = dev_get_drvdata(dev);
return dw_mci_suspend(host);
}
static int dw_mci_exynos_resume(struct device *dev)
{
struct dw_mci *host = dev_get_drvdata(dev);
dw_mci_exynos_priv_init(host);
return dw_mci_resume(host);
}
/**
* dw_mci_exynos_resume_noirq - Exynos-specific resume code
*
* On exynos5420 there is a silicon errata that will sometimes leave the
* WAKEUP_INT bit in the CLKSEL register asserted. This bit is 1 to indicate
* that it fired and we can clear it by writing a 1 back. Clear it to prevent
* interrupts from going off constantly.
*
* We run this code on all exynos variants because it doesn't hurt.
*/
static int dw_mci_exynos_resume_noirq(struct device *dev)
{
struct dw_mci *host = dev_get_drvdata(dev);
u32 clksel;
clksel = mci_readl(host, CLKSEL);
if (clksel & SDMMC_CLKSEL_WAKEUP_INT)
mci_writel(host, CLKSEL, clksel);
return 0; return 0;
} }
#else
#define dw_mci_exynos_suspend NULL
#define dw_mci_exynos_resume NULL
#define dw_mci_exynos_resume_noirq NULL
#endif /* CONFIG_PM_SLEEP */
static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr) static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr)
{ {
...@@ -121,23 +183,68 @@ static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr) ...@@ -121,23 +183,68 @@ static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr)
static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios) static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
{ {
struct dw_mci_exynos_priv_data *priv = host->priv; struct dw_mci_exynos_priv_data *priv = host->priv;
unsigned int wanted = ios->clock;
unsigned long actual;
u8 div = priv->ciu_div + 1;
if (ios->timing == MMC_TIMING_UHS_DDR50) if (ios->timing == MMC_TIMING_UHS_DDR50) {
mci_writel(host, CLKSEL, priv->ddr_timing); mci_writel(host, CLKSEL, priv->ddr_timing);
else /* Should be double rate for DDR mode */
if (ios->bus_width == MMC_BUS_WIDTH_8)
wanted <<= 1;
} else {
mci_writel(host, CLKSEL, priv->sdr_timing); mci_writel(host, CLKSEL, priv->sdr_timing);
}
/* Don't care if wanted clock is zero */
if (!wanted)
return;
/* Guaranteed minimum frequency for cclkin */
if (wanted < EXYNOS_CCLKIN_MIN)
wanted = EXYNOS_CCLKIN_MIN;
if (wanted != priv->cur_speed) {
int ret = clk_set_rate(host->ciu_clk, wanted * div);
if (ret)
dev_warn(host->dev,
"failed to set clk-rate %u error: %d\n",
wanted * div, ret);
actual = clk_get_rate(host->ciu_clk);
host->bus_hz = actual / div;
priv->cur_speed = wanted;
host->current_speed = 0;
}
} }
static int dw_mci_exynos_parse_dt(struct dw_mci *host) static int dw_mci_exynos_parse_dt(struct dw_mci *host)
{ {
struct dw_mci_exynos_priv_data *priv = host->priv; struct dw_mci_exynos_priv_data *priv;
struct device_node *np = host->dev->of_node; struct device_node *np = host->dev->of_node;
u32 timing[2]; u32 timing[2];
u32 div = 0; u32 div = 0;
int idx;
int ret; int ret;
of_property_read_u32(np, "samsung,dw-mshc-ciu-div", &div); priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
priv->ciu_div = div; if (!priv) {
dev_err(host->dev, "mem alloc failed for private data\n");
return -ENOMEM;
}
for (idx = 0; idx < ARRAY_SIZE(exynos_compat); idx++) {
if (of_device_is_compatible(np, exynos_compat[idx].compatible))
priv->ctrl_type = exynos_compat[idx].ctrl_type;
}
if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4412)
priv->ciu_div = EXYNOS4412_FIXED_CIU_CLK_DIV - 1;
else if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS4210)
priv->ciu_div = EXYNOS4210_FIXED_CIU_CLK_DIV - 1;
else {
of_property_read_u32(np, "samsung,dw-mshc-ciu-div", &div);
priv->ciu_div = div;
}
ret = of_property_read_u32_array(np, ret = of_property_read_u32_array(np,
"samsung,dw-mshc-sdr-timing", timing, 2); "samsung,dw-mshc-sdr-timing", timing, 2);
...@@ -152,9 +259,131 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host) ...@@ -152,9 +259,131 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host)
return ret; return ret;
priv->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div); priv->ddr_timing = SDMMC_CLKSEL_TIMING(timing[0], timing[1], div);
host->priv = priv;
return 0; return 0;
} }
static inline u8 dw_mci_exynos_get_clksmpl(struct dw_mci *host)
{
return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL));
}
static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample)
{
u32 clksel;
clksel = mci_readl(host, CLKSEL);
clksel = (clksel & ~0x7) | SDMMC_CLKSEL_CCLK_SAMPLE(sample);
mci_writel(host, CLKSEL, clksel);
}
static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host)
{
u32 clksel;
u8 sample;
clksel = mci_readl(host, CLKSEL);
sample = (clksel + 1) & 0x7;
clksel = (clksel & ~0x7) | sample;
mci_writel(host, CLKSEL, clksel);
return sample;
}
static s8 dw_mci_exynos_get_best_clksmpl(u8 candiates)
{
const u8 iter = 8;
u8 __c;
s8 i, loc = -1;
for (i = 0; i < iter; i++) {
__c = ror8(candiates, i);
if ((__c & 0xc7) == 0xc7) {
loc = i;
goto out;
}
}
for (i = 0; i < iter; i++) {
__c = ror8(candiates, i);
if ((__c & 0x83) == 0x83) {
loc = i;
goto out;
}
}
out:
return loc;
}
static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot, u32 opcode,
struct dw_mci_tuning_data *tuning_data)
{
struct dw_mci *host = slot->host;
struct mmc_host *mmc = slot->mmc;
const u8 *blk_pattern = tuning_data->blk_pattern;
u8 *blk_test;
unsigned int blksz = tuning_data->blksz;
u8 start_smpl, smpl, candiates = 0;
s8 found = -1;
int ret = 0;
blk_test = kmalloc(blksz, GFP_KERNEL);
if (!blk_test)
return -ENOMEM;
start_smpl = dw_mci_exynos_get_clksmpl(host);
do {
struct mmc_request mrq = {NULL};
struct mmc_command cmd = {0};
struct mmc_command stop = {0};
struct mmc_data data = {0};
struct scatterlist sg;
cmd.opcode = opcode;
cmd.arg = 0;
cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
stop.opcode = MMC_STOP_TRANSMISSION;
stop.arg = 0;
stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
data.blksz = blksz;
data.blocks = 1;
data.flags = MMC_DATA_READ;
data.sg = &sg;
data.sg_len = 1;
sg_init_one(&sg, blk_test, blksz);
mrq.cmd = &cmd;
mrq.stop = &stop;
mrq.data = &data;
host->mrq = &mrq;
mci_writel(host, TMOUT, ~0);
smpl = dw_mci_exynos_move_next_clksmpl(host);
mmc_wait_for_req(mmc, &mrq);
if (!cmd.error && !data.error) {
if (!memcmp(blk_pattern, blk_test, blksz))
candiates |= (1 << smpl);
} else {
dev_dbg(host->dev,
"Tuning error: cmd.error:%d, data.error:%d\n",
cmd.error, data.error);
}
} while (start_smpl != smpl);
found = dw_mci_exynos_get_best_clksmpl(candiates);
if (found >= 0)
dw_mci_exynos_set_clksmpl(host, found);
else
ret = -EIO;
kfree(blk_test);
return ret;
}
/* Common capabilities of Exynos4/Exynos5 SoC */ /* Common capabilities of Exynos4/Exynos5 SoC */
static unsigned long exynos_dwmmc_caps[4] = { static unsigned long exynos_dwmmc_caps[4] = {
MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR | MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR |
...@@ -171,6 +400,7 @@ static const struct dw_mci_drv_data exynos_drv_data = { ...@@ -171,6 +400,7 @@ static const struct dw_mci_drv_data exynos_drv_data = {
.prepare_command = dw_mci_exynos_prepare_command, .prepare_command = dw_mci_exynos_prepare_command,
.set_ios = dw_mci_exynos_set_ios, .set_ios = dw_mci_exynos_set_ios,
.parse_dt = dw_mci_exynos_parse_dt, .parse_dt = dw_mci_exynos_parse_dt,
.execute_tuning = dw_mci_exynos_execute_tuning,
}; };
static const struct of_device_id dw_mci_exynos_match[] = { static const struct of_device_id dw_mci_exynos_match[] = {
...@@ -180,6 +410,8 @@ static const struct of_device_id dw_mci_exynos_match[] = { ...@@ -180,6 +410,8 @@ static const struct of_device_id dw_mci_exynos_match[] = {
.data = &exynos_drv_data, }, .data = &exynos_drv_data, },
{ .compatible = "samsung,exynos5420-dw-mshc", { .compatible = "samsung,exynos5420-dw-mshc",
.data = &exynos_drv_data, }, .data = &exynos_drv_data, },
{ .compatible = "samsung,exynos5420-dw-mshc-smu",
.data = &exynos_drv_data, },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, dw_mci_exynos_match); MODULE_DEVICE_TABLE(of, dw_mci_exynos_match);
...@@ -194,13 +426,20 @@ static int dw_mci_exynos_probe(struct platform_device *pdev) ...@@ -194,13 +426,20 @@ static int dw_mci_exynos_probe(struct platform_device *pdev)
return dw_mci_pltfm_register(pdev, drv_data); return dw_mci_pltfm_register(pdev, drv_data);
} }
const struct dev_pm_ops dw_mci_exynos_pmops = {
SET_SYSTEM_SLEEP_PM_OPS(dw_mci_exynos_suspend, dw_mci_exynos_resume)
.resume_noirq = dw_mci_exynos_resume_noirq,
.thaw_noirq = dw_mci_exynos_resume_noirq,
.restore_noirq = dw_mci_exynos_resume_noirq,
};
static struct platform_driver dw_mci_exynos_pltfm_driver = { static struct platform_driver dw_mci_exynos_pltfm_driver = {
.probe = dw_mci_exynos_probe, .probe = dw_mci_exynos_probe,
.remove = __exit_p(dw_mci_pltfm_remove), .remove = __exit_p(dw_mci_pltfm_remove),
.driver = { .driver = {
.name = "dwmmc_exynos", .name = "dwmmc_exynos",
.of_match_table = dw_mci_exynos_match, .of_match_table = dw_mci_exynos_match,
.pm = &dw_mci_pltfm_pmops, .pm = &dw_mci_exynos_pmops,
}, },
}; };
......
...@@ -39,7 +39,6 @@ int dw_mci_pltfm_register(struct platform_device *pdev, ...@@ -39,7 +39,6 @@ int dw_mci_pltfm_register(struct platform_device *pdev,
{ {
struct dw_mci *host; struct dw_mci *host;
struct resource *regs; struct resource *regs;
int ret;
host = devm_kzalloc(&pdev->dev, sizeof(struct dw_mci), GFP_KERNEL); host = devm_kzalloc(&pdev->dev, sizeof(struct dw_mci), GFP_KERNEL);
if (!host) if (!host)
...@@ -59,12 +58,6 @@ int dw_mci_pltfm_register(struct platform_device *pdev, ...@@ -59,12 +58,6 @@ int dw_mci_pltfm_register(struct platform_device *pdev,
if (IS_ERR(host->regs)) if (IS_ERR(host->regs))
return PTR_ERR(host->regs); return PTR_ERR(host->regs);
if (drv_data && drv_data->init) {
ret = drv_data->init(host);
if (ret)
return ret;
}
platform_set_drvdata(pdev, host); platform_set_drvdata(pdev, host);
return dw_mci_probe(host); return dw_mci_probe(host);
} }
......
...@@ -38,21 +38,6 @@ struct dw_mci_socfpga_priv_data { ...@@ -38,21 +38,6 @@ struct dw_mci_socfpga_priv_data {
static int dw_mci_socfpga_priv_init(struct dw_mci *host) static int dw_mci_socfpga_priv_init(struct dw_mci *host)
{ {
struct dw_mci_socfpga_priv_data *priv;
priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
if (!priv) {
dev_err(host->dev, "mem alloc failed for private data\n");
return -ENOMEM;
}
priv->sysreg = syscon_regmap_lookup_by_compatible("altr,sys-mgr");
if (IS_ERR(priv->sysreg)) {
dev_err(host->dev, "regmap for altr,sys-mgr lookup failed.\n");
return PTR_ERR(priv->sysreg);
}
host->priv = priv;
return 0; return 0;
} }
...@@ -79,12 +64,24 @@ static void dw_mci_socfpga_prepare_command(struct dw_mci *host, u32 *cmdr) ...@@ -79,12 +64,24 @@ static void dw_mci_socfpga_prepare_command(struct dw_mci *host, u32 *cmdr)
static int dw_mci_socfpga_parse_dt(struct dw_mci *host) static int dw_mci_socfpga_parse_dt(struct dw_mci *host)
{ {
struct dw_mci_socfpga_priv_data *priv = host->priv; struct dw_mci_socfpga_priv_data *priv;
struct device_node *np = host->dev->of_node; struct device_node *np = host->dev->of_node;
u32 timing[2]; u32 timing[2];
u32 div = 0; u32 div = 0;
int ret; int ret;
priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
if (!priv) {
dev_err(host->dev, "mem alloc failed for private data\n");
return -ENOMEM;
}
priv->sysreg = syscon_regmap_lookup_by_compatible("altr,sys-mgr");
if (IS_ERR(priv->sysreg)) {
dev_err(host->dev, "regmap for altr,sys-mgr lookup failed.\n");
return PTR_ERR(priv->sysreg);
}
ret = of_property_read_u32(np, "altr,dw-mshc-ciu-div", &div); ret = of_property_read_u32(np, "altr,dw-mshc-ciu-div", &div);
if (ret) if (ret)
dev_info(host->dev, "No dw-mshc-ciu-div specified, assuming 1"); dev_info(host->dev, "No dw-mshc-ciu-div specified, assuming 1");
...@@ -96,6 +93,7 @@ static int dw_mci_socfpga_parse_dt(struct dw_mci *host) ...@@ -96,6 +93,7 @@ static int dw_mci_socfpga_parse_dt(struct dw_mci *host)
return ret; return ret;
priv->hs_timing = SYSMGR_SDMMC_CTRL_SET(timing[0], timing[1]); priv->hs_timing = SYSMGR_SDMMC_CTRL_SET(timing[0], timing[1]);
host->priv = priv;
return 0; return 0;
} }
...@@ -113,7 +111,7 @@ static const struct of_device_id dw_mci_socfpga_match[] = { ...@@ -113,7 +111,7 @@ static const struct of_device_id dw_mci_socfpga_match[] = {
}; };
MODULE_DEVICE_TABLE(of, dw_mci_socfpga_match); MODULE_DEVICE_TABLE(of, dw_mci_socfpga_match);
int dw_mci_socfpga_probe(struct platform_device *pdev) static int dw_mci_socfpga_probe(struct platform_device *pdev)
{ {
const struct dw_mci_drv_data *drv_data; const struct dw_mci_drv_data *drv_data;
const struct of_device_id *match; const struct of_device_id *match;
...@@ -128,7 +126,7 @@ static struct platform_driver dw_mci_socfpga_pltfm_driver = { ...@@ -128,7 +126,7 @@ static struct platform_driver dw_mci_socfpga_pltfm_driver = {
.remove = __exit_p(dw_mci_pltfm_remove), .remove = __exit_p(dw_mci_pltfm_remove),
.driver = { .driver = {
.name = "dwmmc_socfpga", .name = "dwmmc_socfpga",
.of_match_table = of_match_ptr(dw_mci_socfpga_match), .of_match_table = dw_mci_socfpga_match,
.pm = &dw_mci_pltfm_pmops, .pm = &dw_mci_pltfm_pmops,
}, },
}; };
......
此差异已折叠。
...@@ -53,6 +53,7 @@ ...@@ -53,6 +53,7 @@
#define SDMMC_IDINTEN 0x090 #define SDMMC_IDINTEN 0x090
#define SDMMC_DSCADDR 0x094 #define SDMMC_DSCADDR 0x094
#define SDMMC_BUFADDR 0x098 #define SDMMC_BUFADDR 0x098
#define SDMMC_CDTHRCTL 0x100
#define SDMMC_DATA(x) (x) #define SDMMC_DATA(x) (x)
/* /*
...@@ -128,6 +129,10 @@ ...@@ -128,6 +129,10 @@
#define SDMMC_CMD_INDX(n) ((n) & 0x1F) #define SDMMC_CMD_INDX(n) ((n) & 0x1F)
/* Status register defines */ /* Status register defines */
#define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF) #define SDMMC_GET_FCNT(x) (((x)>>17) & 0x1FFF)
/* FIFOTH register defines */
#define SDMMC_SET_FIFOTH(m, r, t) (((m) & 0x7) << 28 | \
((r) & 0xFFF) << 16 | \
((t) & 0xFFF))
/* Internal DMAC interrupt defines */ /* Internal DMAC interrupt defines */
#define SDMMC_IDMAC_INT_AI BIT(9) #define SDMMC_IDMAC_INT_AI BIT(9)
#define SDMMC_IDMAC_INT_NI BIT(8) #define SDMMC_IDMAC_INT_NI BIT(8)
...@@ -142,6 +147,8 @@ ...@@ -142,6 +147,8 @@
#define SDMMC_IDMAC_SWRESET BIT(0) #define SDMMC_IDMAC_SWRESET BIT(0)
/* Version ID register define */ /* Version ID register define */
#define SDMMC_GET_VERID(x) ((x) & 0xFFFF) #define SDMMC_GET_VERID(x) ((x) & 0xFFFF)
/* Card read threshold */
#define SDMMC_SET_RD_THLD(v, x) (((v) & 0x1FFF) << 16 | (x))
/* Register access macros */ /* Register access macros */
#define mci_readl(dev, reg) \ #define mci_readl(dev, reg) \
...@@ -183,6 +190,52 @@ extern int dw_mci_suspend(struct dw_mci *host); ...@@ -183,6 +190,52 @@ extern int dw_mci_suspend(struct dw_mci *host);
extern int dw_mci_resume(struct dw_mci *host); extern int dw_mci_resume(struct dw_mci *host);
#endif #endif
/**
* struct dw_mci_slot - MMC slot state
* @mmc: The mmc_host representing this slot.
* @host: The MMC controller this slot is using.
* @quirks: Slot-level quirks (DW_MCI_SLOT_QUIRK_XXX)
* @wp_gpio: If gpio_is_valid() we'll use this to read write protect.
* @ctype: Card type for this slot.
* @mrq: mmc_request currently being processed or waiting to be
* processed, or NULL when the slot is idle.
* @queue_node: List node for placing this node in the @queue list of
* &struct dw_mci.
* @clock: Clock rate configured by set_ios(). Protected by host->lock.
* @__clk_old: The last updated clock with reflecting clock divider.
* Keeping track of this helps us to avoid spamming the console
* with CONFIG_MMC_CLKGATE.
* @flags: Random state bits associated with the slot.
* @id: Number of this slot.
* @last_detect_state: Most recently observed card detect state.
*/
struct dw_mci_slot {
struct mmc_host *mmc;
struct dw_mci *host;
int quirks;
int wp_gpio;
u32 ctype;
struct mmc_request *mrq;
struct list_head queue_node;
unsigned int clock;
unsigned int __clk_old;
unsigned long flags;
#define DW_MMC_CARD_PRESENT 0
#define DW_MMC_CARD_NEED_INIT 1
int id;
int last_detect_state;
};
struct dw_mci_tuning_data {
const u8 *blk_pattern;
unsigned int blksz;
};
/** /**
* dw_mci driver data - dw-mshc implementation specific driver data. * dw_mci driver data - dw-mshc implementation specific driver data.
* @caps: mmc subsystem specified capabilities of the controller(s). * @caps: mmc subsystem specified capabilities of the controller(s).
...@@ -203,5 +256,7 @@ struct dw_mci_drv_data { ...@@ -203,5 +256,7 @@ struct dw_mci_drv_data {
void (*prepare_command)(struct dw_mci *host, u32 *cmdr); void (*prepare_command)(struct dw_mci *host, u32 *cmdr);
void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios); void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios);
int (*parse_dt)(struct dw_mci *host); int (*parse_dt)(struct dw_mci *host);
int (*execute_tuning)(struct dw_mci_slot *slot, u32 opcode,
struct dw_mci_tuning_data *tuning_data);
}; };
#endif /* _DW_MMC_H_ */ #endif /* _DW_MMC_H_ */
...@@ -880,8 +880,6 @@ static int jz4740_mmc_suspend(struct device *dev) ...@@ -880,8 +880,6 @@ static int jz4740_mmc_suspend(struct device *dev)
{ {
struct jz4740_mmc_host *host = dev_get_drvdata(dev); struct jz4740_mmc_host *host = dev_get_drvdata(dev);
mmc_suspend_host(host->mmc);
jz_gpio_bulk_suspend(jz4740_mmc_pins, jz4740_mmc_num_pins(host)); jz_gpio_bulk_suspend(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
return 0; return 0;
...@@ -893,8 +891,6 @@ static int jz4740_mmc_resume(struct device *dev) ...@@ -893,8 +891,6 @@ static int jz4740_mmc_resume(struct device *dev)
jz_gpio_bulk_resume(jz4740_mmc_pins, jz4740_mmc_num_pins(host)); jz_gpio_bulk_resume(jz4740_mmc_pins, jz4740_mmc_num_pins(host));
mmc_resume_host(host->mmc);
return 0; return 0;
} }
......
...@@ -1730,37 +1730,28 @@ static int mmci_suspend(struct device *dev) ...@@ -1730,37 +1730,28 @@ static int mmci_suspend(struct device *dev)
{ {
struct amba_device *adev = to_amba_device(dev); struct amba_device *adev = to_amba_device(dev);
struct mmc_host *mmc = amba_get_drvdata(adev); struct mmc_host *mmc = amba_get_drvdata(adev);
int ret = 0;
if (mmc) { if (mmc) {
struct mmci_host *host = mmc_priv(mmc); struct mmci_host *host = mmc_priv(mmc);
pm_runtime_get_sync(dev);
ret = mmc_suspend_host(mmc); writel(0, host->base + MMCIMASK0);
if (ret == 0) {
pm_runtime_get_sync(dev);
writel(0, host->base + MMCIMASK0);
}
} }
return ret; return 0;
} }
static int mmci_resume(struct device *dev) static int mmci_resume(struct device *dev)
{ {
struct amba_device *adev = to_amba_device(dev); struct amba_device *adev = to_amba_device(dev);
struct mmc_host *mmc = amba_get_drvdata(adev); struct mmc_host *mmc = amba_get_drvdata(adev);
int ret = 0;
if (mmc) { if (mmc) {
struct mmci_host *host = mmc_priv(mmc); struct mmci_host *host = mmc_priv(mmc);
writel(MCI_IRQENABLE, host->base + MMCIMASK0); writel(MCI_IRQENABLE, host->base + MMCIMASK0);
pm_runtime_put(dev); pm_runtime_put(dev);
ret = mmc_resume_host(mmc);
} }
return ret; return 0;
} }
#endif #endif
......
...@@ -1416,28 +1416,10 @@ msmsdcc_probe(struct platform_device *pdev) ...@@ -1416,28 +1416,10 @@ msmsdcc_probe(struct platform_device *pdev)
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
#ifdef CONFIG_MMC_MSM7X00A_RESUME_IN_WQ
static void
do_resume_work(struct work_struct *work)
{
struct msmsdcc_host *host =
container_of(work, struct msmsdcc_host, resume_task);
struct mmc_host *mmc = host->mmc;
if (mmc) {
mmc_resume_host(mmc);
if (host->stat_irq)
enable_irq(host->stat_irq);
}
}
#endif
static int static int
msmsdcc_suspend(struct platform_device *dev, pm_message_t state) msmsdcc_suspend(struct platform_device *dev, pm_message_t state)
{ {
struct mmc_host *mmc = mmc_get_drvdata(dev); struct mmc_host *mmc = mmc_get_drvdata(dev);
int rc = 0;
if (mmc) { if (mmc) {
struct msmsdcc_host *host = mmc_priv(mmc); struct msmsdcc_host *host = mmc_priv(mmc);
...@@ -1445,14 +1427,11 @@ msmsdcc_suspend(struct platform_device *dev, pm_message_t state) ...@@ -1445,14 +1427,11 @@ msmsdcc_suspend(struct platform_device *dev, pm_message_t state)
if (host->stat_irq) if (host->stat_irq)
disable_irq(host->stat_irq); disable_irq(host->stat_irq);
if (mmc->card && mmc->card->type != MMC_TYPE_SDIO) msmsdcc_writel(host, 0, MMCIMASK0);
rc = mmc_suspend_host(mmc);
if (!rc)
msmsdcc_writel(host, 0, MMCIMASK0);
if (host->clks_on) if (host->clks_on)
msmsdcc_disable_clocks(host, 0); msmsdcc_disable_clocks(host, 0);
} }
return rc; return 0;
} }
static int static int
...@@ -1467,8 +1446,6 @@ msmsdcc_resume(struct platform_device *dev) ...@@ -1467,8 +1446,6 @@ msmsdcc_resume(struct platform_device *dev)
msmsdcc_writel(host, host->saved_irq0mask, MMCIMASK0); msmsdcc_writel(host, host->saved_irq0mask, MMCIMASK0);
if (mmc->card && mmc->card->type != MMC_TYPE_SDIO)
mmc_resume_host(mmc);
if (host->stat_irq) if (host->stat_irq)
enable_irq(host->stat_irq); enable_irq(host->stat_irq);
#if BUSCLK_PWRSAVE #if BUSCLK_PWRSAVE
......
...@@ -775,9 +775,9 @@ static int mvsd_probe(struct platform_device *pdev) ...@@ -775,9 +775,9 @@ static int mvsd_probe(struct platform_device *pdev)
spin_lock_init(&host->lock); spin_lock_init(&host->lock);
host->base = devm_request_and_ioremap(&pdev->dev, r); host->base = devm_ioremap_resource(&pdev->dev, r);
if (!host->base) { if (IS_ERR(host->base)) {
ret = -ENOMEM; ret = PTR_ERR(host->base);
goto out; goto out;
} }
...@@ -838,33 +838,6 @@ static int mvsd_remove(struct platform_device *pdev) ...@@ -838,33 +838,6 @@ static int mvsd_remove(struct platform_device *pdev)
return 0; return 0;
} }
#ifdef CONFIG_PM
static int mvsd_suspend(struct platform_device *dev, pm_message_t state)
{
struct mmc_host *mmc = platform_get_drvdata(dev);
int ret = 0;
if (mmc)
ret = mmc_suspend_host(mmc);
return ret;
}
static int mvsd_resume(struct platform_device *dev)
{
struct mmc_host *mmc = platform_get_drvdata(dev);
int ret = 0;
if (mmc)
ret = mmc_resume_host(mmc);
return ret;
}
#else
#define mvsd_suspend NULL
#define mvsd_resume NULL
#endif
static const struct of_device_id mvsdio_dt_ids[] = { static const struct of_device_id mvsdio_dt_ids[] = {
{ .compatible = "marvell,orion-sdio" }, { .compatible = "marvell,orion-sdio" },
{ /* sentinel */ } { /* sentinel */ }
...@@ -874,8 +847,6 @@ MODULE_DEVICE_TABLE(of, mvsdio_dt_ids); ...@@ -874,8 +847,6 @@ MODULE_DEVICE_TABLE(of, mvsdio_dt_ids);
static struct platform_driver mvsd_driver = { static struct platform_driver mvsd_driver = {
.probe = mvsd_probe, .probe = mvsd_probe,
.remove = mvsd_remove, .remove = mvsd_remove,
.suspend = mvsd_suspend,
.resume = mvsd_resume,
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.of_match_table = mvsdio_dt_ids, .of_match_table = mvsdio_dt_ids,
......
...@@ -1250,28 +1250,20 @@ static int mxcmci_suspend(struct device *dev) ...@@ -1250,28 +1250,20 @@ static int mxcmci_suspend(struct device *dev)
{ {
struct mmc_host *mmc = dev_get_drvdata(dev); struct mmc_host *mmc = dev_get_drvdata(dev);
struct mxcmci_host *host = mmc_priv(mmc); struct mxcmci_host *host = mmc_priv(mmc);
int ret = 0;
if (mmc)
ret = mmc_suspend_host(mmc);
clk_disable_unprepare(host->clk_per); clk_disable_unprepare(host->clk_per);
clk_disable_unprepare(host->clk_ipg); clk_disable_unprepare(host->clk_ipg);
return 0;
return ret;
} }
static int mxcmci_resume(struct device *dev) static int mxcmci_resume(struct device *dev)
{ {
struct mmc_host *mmc = dev_get_drvdata(dev); struct mmc_host *mmc = dev_get_drvdata(dev);
struct mxcmci_host *host = mmc_priv(mmc); struct mxcmci_host *host = mmc_priv(mmc);
int ret = 0;
clk_prepare_enable(host->clk_per); clk_prepare_enable(host->clk_per);
clk_prepare_enable(host->clk_ipg); clk_prepare_enable(host->clk_ipg);
if (mmc) return 0;
ret = mmc_resume_host(mmc);
return ret;
} }
static const struct dev_pm_ops mxcmci_pm_ops = { static const struct dev_pm_ops mxcmci_pm_ops = {
......
...@@ -724,13 +724,9 @@ static int mxs_mmc_suspend(struct device *dev) ...@@ -724,13 +724,9 @@ static int mxs_mmc_suspend(struct device *dev)
struct mmc_host *mmc = dev_get_drvdata(dev); struct mmc_host *mmc = dev_get_drvdata(dev);
struct mxs_mmc_host *host = mmc_priv(mmc); struct mxs_mmc_host *host = mmc_priv(mmc);
struct mxs_ssp *ssp = &host->ssp; struct mxs_ssp *ssp = &host->ssp;
int ret = 0;
ret = mmc_suspend_host(mmc);
clk_disable_unprepare(ssp->clk); clk_disable_unprepare(ssp->clk);
return 0;
return ret;
} }
static int mxs_mmc_resume(struct device *dev) static int mxs_mmc_resume(struct device *dev)
...@@ -738,13 +734,9 @@ static int mxs_mmc_resume(struct device *dev) ...@@ -738,13 +734,9 @@ static int mxs_mmc_resume(struct device *dev)
struct mmc_host *mmc = dev_get_drvdata(dev); struct mmc_host *mmc = dev_get_drvdata(dev);
struct mxs_mmc_host *host = mmc_priv(mmc); struct mxs_mmc_host *host = mmc_priv(mmc);
struct mxs_ssp *ssp = &host->ssp; struct mxs_ssp *ssp = &host->ssp;
int ret = 0;
clk_prepare_enable(ssp->clk); clk_prepare_enable(ssp->clk);
return 0;
ret = mmc_resume_host(mmc);
return ret;
} }
static const struct dev_pm_ops mxs_mmc_pm_ops = { static const struct dev_pm_ops mxs_mmc_pm_ops = {
......
...@@ -128,7 +128,6 @@ struct mmc_omap_slot { ...@@ -128,7 +128,6 @@ struct mmc_omap_slot {
struct mmc_omap_host { struct mmc_omap_host {
int initialized; int initialized;
int suspended;
struct mmc_request * mrq; struct mmc_request * mrq;
struct mmc_command * cmd; struct mmc_command * cmd;
struct mmc_data * data; struct mmc_data * data;
...@@ -1513,61 +1512,9 @@ static int mmc_omap_remove(struct platform_device *pdev) ...@@ -1513,61 +1512,9 @@ static int mmc_omap_remove(struct platform_device *pdev)
return 0; return 0;
} }
#ifdef CONFIG_PM
static int mmc_omap_suspend(struct platform_device *pdev, pm_message_t mesg)
{
int i, ret = 0;
struct mmc_omap_host *host = platform_get_drvdata(pdev);
if (host == NULL || host->suspended)
return 0;
for (i = 0; i < host->nr_slots; i++) {
struct mmc_omap_slot *slot;
slot = host->slots[i];
ret = mmc_suspend_host(slot->mmc);
if (ret < 0) {
while (--i >= 0) {
slot = host->slots[i];
mmc_resume_host(slot->mmc);
}
return ret;
}
}
host->suspended = 1;
return 0;
}
static int mmc_omap_resume(struct platform_device *pdev)
{
int i, ret = 0;
struct mmc_omap_host *host = platform_get_drvdata(pdev);
if (host == NULL || !host->suspended)
return 0;
for (i = 0; i < host->nr_slots; i++) {
struct mmc_omap_slot *slot;
slot = host->slots[i];
ret = mmc_resume_host(slot->mmc);
if (ret < 0)
return ret;
host->suspended = 0;
}
return 0;
}
#else
#define mmc_omap_suspend NULL
#define mmc_omap_resume NULL
#endif
static struct platform_driver mmc_omap_driver = { static struct platform_driver mmc_omap_driver = {
.probe = mmc_omap_probe, .probe = mmc_omap_probe,
.remove = mmc_omap_remove, .remove = mmc_omap_remove,
.suspend = mmc_omap_suspend,
.resume = mmc_omap_resume,
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.owner = THIS_MODULE, .owner = THIS_MODULE,
......
...@@ -75,6 +75,7 @@ ...@@ -75,6 +75,7 @@
#define ICE 0x1 #define ICE 0x1
#define ICS 0x2 #define ICS 0x2
#define CEN (1 << 2) #define CEN (1 << 2)
#define CLKD_MAX 0x3FF /* max clock divisor: 1023 */
#define CLKD_MASK 0x0000FFC0 #define CLKD_MASK 0x0000FFC0
#define CLKD_SHIFT 6 #define CLKD_SHIFT 6
#define DTO_MASK 0x000F0000 #define DTO_MASK 0x000F0000
...@@ -119,7 +120,8 @@ ...@@ -119,7 +120,8 @@
BRR_EN | BWR_EN | TC_EN | CC_EN) BRR_EN | BWR_EN | TC_EN | CC_EN)
#define MMC_AUTOSUSPEND_DELAY 100 #define MMC_AUTOSUSPEND_DELAY 100
#define MMC_TIMEOUT_MS 20 #define MMC_TIMEOUT_MS 20 /* 20 mSec */
#define MMC_TIMEOUT_US 20000 /* 20000 micro Sec */
#define OMAP_MMC_MIN_CLOCK 400000 #define OMAP_MMC_MIN_CLOCK 400000
#define OMAP_MMC_MAX_CLOCK 52000000 #define OMAP_MMC_MAX_CLOCK 52000000
#define DRIVER_NAME "omap_hsmmc" #define DRIVER_NAME "omap_hsmmc"
...@@ -171,6 +173,10 @@ struct omap_hsmmc_host { ...@@ -171,6 +173,10 @@ struct omap_hsmmc_host {
unsigned char bus_mode; unsigned char bus_mode;
unsigned char power_mode; unsigned char power_mode;
int suspended; int suspended;
u32 con;
u32 hctl;
u32 sysctl;
u32 capa;
int irq; int irq;
int use_dma, dma_ch; int use_dma, dma_ch;
struct dma_chan *tx_chan; struct dma_chan *tx_chan;
...@@ -183,7 +189,6 @@ struct omap_hsmmc_host { ...@@ -183,7 +189,6 @@ struct omap_hsmmc_host {
int use_reg; int use_reg;
int req_in_progress; int req_in_progress;
struct omap_hsmmc_next next_data; struct omap_hsmmc_next next_data;
struct omap_mmc_platform_data *pdata; struct omap_mmc_platform_data *pdata;
}; };
...@@ -493,8 +498,8 @@ static u16 calc_divisor(struct omap_hsmmc_host *host, struct mmc_ios *ios) ...@@ -493,8 +498,8 @@ static u16 calc_divisor(struct omap_hsmmc_host *host, struct mmc_ios *ios)
if (ios->clock) { if (ios->clock) {
dsor = DIV_ROUND_UP(clk_get_rate(host->fclk), ios->clock); dsor = DIV_ROUND_UP(clk_get_rate(host->fclk), ios->clock);
if (dsor > 250) if (dsor > CLKD_MAX)
dsor = 250; dsor = CLKD_MAX;
} }
return dsor; return dsor;
...@@ -597,25 +602,20 @@ static void omap_hsmmc_set_bus_mode(struct omap_hsmmc_host *host) ...@@ -597,25 +602,20 @@ static void omap_hsmmc_set_bus_mode(struct omap_hsmmc_host *host)
static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host) static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
{ {
struct mmc_ios *ios = &host->mmc->ios; struct mmc_ios *ios = &host->mmc->ios;
struct omap_mmc_platform_data *pdata = host->pdata;
int context_loss = 0;
u32 hctl, capa; u32 hctl, capa;
unsigned long timeout; unsigned long timeout;
if (pdata->get_context_loss_count) {
context_loss = pdata->get_context_loss_count(host->dev);
if (context_loss < 0)
return 1;
}
dev_dbg(mmc_dev(host->mmc), "context was %slost\n",
context_loss == host->context_loss ? "not " : "");
if (host->context_loss == context_loss)
return 1;
if (!OMAP_HSMMC_READ(host->base, SYSSTATUS) & RESETDONE) if (!OMAP_HSMMC_READ(host->base, SYSSTATUS) & RESETDONE)
return 1; return 1;
if (host->con == OMAP_HSMMC_READ(host->base, CON) &&
host->hctl == OMAP_HSMMC_READ(host->base, HCTL) &&
host->sysctl == OMAP_HSMMC_READ(host->base, SYSCTL) &&
host->capa == OMAP_HSMMC_READ(host->base, CAPA))
return 0;
host->context_loss++;
if (host->pdata->controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT) { if (host->pdata->controller_flags & OMAP_HSMMC_SUPPORTS_DUAL_VOLT) {
if (host->power_mode != MMC_POWER_OFF && if (host->power_mode != MMC_POWER_OFF &&
(1 << ios->vdd) <= MMC_VDD_23_24) (1 << ios->vdd) <= MMC_VDD_23_24)
...@@ -655,9 +655,8 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host) ...@@ -655,9 +655,8 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
omap_hsmmc_set_bus_mode(host); omap_hsmmc_set_bus_mode(host);
out: out:
host->context_loss = context_loss; dev_dbg(mmc_dev(host->mmc), "context is restored: restore count %d\n",
host->context_loss);
dev_dbg(mmc_dev(host->mmc), "context is restored\n");
return 0; return 0;
} }
...@@ -666,15 +665,10 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host) ...@@ -666,15 +665,10 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
*/ */
static void omap_hsmmc_context_save(struct omap_hsmmc_host *host) static void omap_hsmmc_context_save(struct omap_hsmmc_host *host)
{ {
struct omap_mmc_platform_data *pdata = host->pdata; host->con = OMAP_HSMMC_READ(host->base, CON);
int context_loss; host->hctl = OMAP_HSMMC_READ(host->base, HCTL);
host->sysctl = OMAP_HSMMC_READ(host->base, SYSCTL);
if (pdata->get_context_loss_count) { host->capa = OMAP_HSMMC_READ(host->base, CAPA);
context_loss = pdata->get_context_loss_count(host->dev);
if (context_loss < 0)
return;
host->context_loss = context_loss;
}
} }
#else #else
...@@ -975,8 +969,7 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host, ...@@ -975,8 +969,7 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host,
unsigned long bit) unsigned long bit)
{ {
unsigned long i = 0; unsigned long i = 0;
unsigned long limit = (loops_per_jiffy * unsigned long limit = MMC_TIMEOUT_US;
msecs_to_jiffies(MMC_TIMEOUT_MS));
OMAP_HSMMC_WRITE(host->base, SYSCTL, OMAP_HSMMC_WRITE(host->base, SYSCTL,
OMAP_HSMMC_READ(host->base, SYSCTL) | bit); OMAP_HSMMC_READ(host->base, SYSCTL) | bit);
...@@ -988,13 +981,13 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host, ...@@ -988,13 +981,13 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host,
if (mmc_slot(host).features & HSMMC_HAS_UPDATED_RESET) { if (mmc_slot(host).features & HSMMC_HAS_UPDATED_RESET) {
while ((!(OMAP_HSMMC_READ(host->base, SYSCTL) & bit)) while ((!(OMAP_HSMMC_READ(host->base, SYSCTL) & bit))
&& (i++ < limit)) && (i++ < limit))
cpu_relax(); udelay(1);
} }
i = 0; i = 0;
while ((OMAP_HSMMC_READ(host->base, SYSCTL) & bit) && while ((OMAP_HSMMC_READ(host->base, SYSCTL) & bit) &&
(i++ < limit)) (i++ < limit))
cpu_relax(); udelay(1);
if (OMAP_HSMMC_READ(host->base, SYSCTL) & bit) if (OMAP_HSMMC_READ(host->base, SYSCTL) & bit)
dev_err(mmc_dev(host->mmc), dev_err(mmc_dev(host->mmc),
...@@ -1178,9 +1171,6 @@ static irqreturn_t omap_hsmmc_detect(int irq, void *dev_id) ...@@ -1178,9 +1171,6 @@ static irqreturn_t omap_hsmmc_detect(int irq, void *dev_id)
struct omap_mmc_slot_data *slot = &mmc_slot(host); struct omap_mmc_slot_data *slot = &mmc_slot(host);
int carddetect; int carddetect;
if (host->suspended)
return IRQ_HANDLED;
sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch"); sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch");
if (slot->card_detect) if (slot->card_detect)
...@@ -1635,18 +1625,9 @@ static int omap_hsmmc_regs_show(struct seq_file *s, void *data) ...@@ -1635,18 +1625,9 @@ static int omap_hsmmc_regs_show(struct seq_file *s, void *data)
{ {
struct mmc_host *mmc = s->private; struct mmc_host *mmc = s->private;
struct omap_hsmmc_host *host = mmc_priv(mmc); struct omap_hsmmc_host *host = mmc_priv(mmc);
int context_loss = 0;
if (host->pdata->get_context_loss_count)
context_loss = host->pdata->get_context_loss_count(host->dev);
seq_printf(s, "mmc%d:\n ctx_loss:\t%d:%d\n\nregs:\n", seq_printf(s, "mmc%d:\n ctx_loss:\t%d\n\nregs:\n",
mmc->index, host->context_loss, context_loss); mmc->index, host->context_loss);
if (host->suspended) {
seq_printf(s, "host suspended, can't read registers\n");
return 0;
}
pm_runtime_get_sync(host->dev); pm_runtime_get_sync(host->dev);
...@@ -1838,13 +1819,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev) ...@@ -1838,13 +1819,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
mmc->ops = &omap_hsmmc_ops; mmc->ops = &omap_hsmmc_ops;
/*
* If regulator_disable can only put vcc_aux to sleep then there is
* no off state.
*/
if (mmc_slot(host).vcc_aux_disable_is_sleep)
mmc_slot(host).no_off = 1;
mmc->f_min = OMAP_MMC_MIN_CLOCK; mmc->f_min = OMAP_MMC_MIN_CLOCK;
if (pdata->max_freq > 0) if (pdata->max_freq > 0)
...@@ -1874,7 +1848,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev) ...@@ -1874,7 +1848,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
omap_hsmmc_context_save(host); omap_hsmmc_context_save(host);
/* This can be removed once we support PBIAS with DT */ /* This can be removed once we support PBIAS with DT */
if (host->dev->of_node && host->mapbase == 0x4809c000) if (host->dev->of_node && res->start == 0x4809c000)
host->pbias_disable = 1; host->pbias_disable = 1;
host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck"); host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck");
...@@ -2119,23 +2093,12 @@ static void omap_hsmmc_complete(struct device *dev) ...@@ -2119,23 +2093,12 @@ static void omap_hsmmc_complete(struct device *dev)
static int omap_hsmmc_suspend(struct device *dev) static int omap_hsmmc_suspend(struct device *dev)
{ {
int ret = 0;
struct omap_hsmmc_host *host = dev_get_drvdata(dev); struct omap_hsmmc_host *host = dev_get_drvdata(dev);
if (!host) if (!host)
return 0; return 0;
if (host && host->suspended)
return 0;
pm_runtime_get_sync(host->dev); pm_runtime_get_sync(host->dev);
host->suspended = 1;
ret = mmc_suspend_host(host->mmc);
if (ret) {
host->suspended = 0;
goto err;
}
if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) { if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) {
omap_hsmmc_disable_irq(host); omap_hsmmc_disable_irq(host);
...@@ -2145,23 +2108,19 @@ static int omap_hsmmc_suspend(struct device *dev) ...@@ -2145,23 +2108,19 @@ static int omap_hsmmc_suspend(struct device *dev)
if (host->dbclk) if (host->dbclk)
clk_disable_unprepare(host->dbclk); clk_disable_unprepare(host->dbclk);
err:
pm_runtime_put_sync(host->dev); pm_runtime_put_sync(host->dev);
return ret; return 0;
} }
/* Routine to resume the MMC device */ /* Routine to resume the MMC device */
static int omap_hsmmc_resume(struct device *dev) static int omap_hsmmc_resume(struct device *dev)
{ {
int ret = 0;
struct omap_hsmmc_host *host = dev_get_drvdata(dev); struct omap_hsmmc_host *host = dev_get_drvdata(dev);
if (!host) if (!host)
return 0; return 0;
if (host && !host->suspended)
return 0;
pm_runtime_get_sync(host->dev); pm_runtime_get_sync(host->dev);
if (host->dbclk) if (host->dbclk)
...@@ -2172,16 +2131,9 @@ static int omap_hsmmc_resume(struct device *dev) ...@@ -2172,16 +2131,9 @@ static int omap_hsmmc_resume(struct device *dev)
omap_hsmmc_protect_card(host); omap_hsmmc_protect_card(host);
/* Notify the core to resume the host */
ret = mmc_resume_host(host->mmc);
if (ret == 0)
host->suspended = 0;
pm_runtime_mark_last_busy(host->dev); pm_runtime_mark_last_busy(host->dev);
pm_runtime_put_autosuspend(host->dev); pm_runtime_put_autosuspend(host->dev);
return 0;
return ret;
} }
#else #else
......
...@@ -880,35 +880,6 @@ static int pxamci_remove(struct platform_device *pdev) ...@@ -880,35 +880,6 @@ static int pxamci_remove(struct platform_device *pdev)
return 0; return 0;
} }
#ifdef CONFIG_PM
static int pxamci_suspend(struct device *dev)
{
struct mmc_host *mmc = dev_get_drvdata(dev);
int ret = 0;
if (mmc)
ret = mmc_suspend_host(mmc);
return ret;
}
static int pxamci_resume(struct device *dev)
{
struct mmc_host *mmc = dev_get_drvdata(dev);
int ret = 0;
if (mmc)
ret = mmc_resume_host(mmc);
return ret;
}
static const struct dev_pm_ops pxamci_pm_ops = {
.suspend = pxamci_suspend,
.resume = pxamci_resume,
};
#endif
static struct platform_driver pxamci_driver = { static struct platform_driver pxamci_driver = {
.probe = pxamci_probe, .probe = pxamci_probe,
.remove = pxamci_remove, .remove = pxamci_remove,
...@@ -916,9 +887,6 @@ static struct platform_driver pxamci_driver = { ...@@ -916,9 +887,6 @@ static struct platform_driver pxamci_driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = of_match_ptr(pxa_mmc_dt_ids), .of_match_table = of_match_ptr(pxa_mmc_dt_ids),
#ifdef CONFIG_PM
.pm = &pxamci_pm_ops,
#endif
}, },
}; };
......
...@@ -364,7 +364,7 @@ static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq) ...@@ -364,7 +364,7 @@ static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq)
struct mmc_host *mmc = host->mmc; struct mmc_host *mmc = host->mmc;
struct mmc_card *card = mmc->card; struct mmc_card *card = mmc->card;
struct mmc_data *data = mrq->data; struct mmc_data *data = mrq->data;
int uhs = mmc_sd_card_uhs(card); int uhs = mmc_card_uhs(card);
int read = (data->flags & MMC_DATA_READ) ? 1 : 0; int read = (data->flags & MMC_DATA_READ) ? 1 : 0;
u8 cfg2, trans_mode; u8 cfg2, trans_mode;
int err; int err;
...@@ -1197,37 +1197,6 @@ static const struct mmc_host_ops realtek_pci_sdmmc_ops = { ...@@ -1197,37 +1197,6 @@ static const struct mmc_host_ops realtek_pci_sdmmc_ops = {
.execute_tuning = sdmmc_execute_tuning, .execute_tuning = sdmmc_execute_tuning,
}; };
#ifdef CONFIG_PM
static int rtsx_pci_sdmmc_suspend(struct platform_device *pdev,
pm_message_t state)
{
struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev);
struct mmc_host *mmc = host->mmc;
int err;
dev_dbg(sdmmc_dev(host), "--> %s\n", __func__);
err = mmc_suspend_host(mmc);
if (err)
return err;
return 0;
}
static int rtsx_pci_sdmmc_resume(struct platform_device *pdev)
{
struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev);
struct mmc_host *mmc = host->mmc;
dev_dbg(sdmmc_dev(host), "--> %s\n", __func__);
return mmc_resume_host(mmc);
}
#else /* CONFIG_PM */
#define rtsx_pci_sdmmc_suspend NULL
#define rtsx_pci_sdmmc_resume NULL
#endif /* CONFIG_PM */
static void init_extra_caps(struct realtek_pci_sdmmc *host) static void init_extra_caps(struct realtek_pci_sdmmc *host)
{ {
struct mmc_host *mmc = host->mmc; struct mmc_host *mmc = host->mmc;
...@@ -1367,8 +1336,6 @@ static struct platform_driver rtsx_pci_sdmmc_driver = { ...@@ -1367,8 +1336,6 @@ static struct platform_driver rtsx_pci_sdmmc_driver = {
.probe = rtsx_pci_sdmmc_drv_probe, .probe = rtsx_pci_sdmmc_drv_probe,
.remove = rtsx_pci_sdmmc_drv_remove, .remove = rtsx_pci_sdmmc_drv_remove,
.id_table = rtsx_pci_sdmmc_ids, .id_table = rtsx_pci_sdmmc_ids,
.suspend = rtsx_pci_sdmmc_suspend,
.resume = rtsx_pci_sdmmc_resume,
.driver = { .driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.name = DRV_NAME_RTSX_PCI_SDMMC, .name = DRV_NAME_RTSX_PCI_SDMMC,
......
...@@ -1949,39 +1949,10 @@ static struct platform_device_id s3cmci_driver_ids[] = { ...@@ -1949,39 +1949,10 @@ static struct platform_device_id s3cmci_driver_ids[] = {
MODULE_DEVICE_TABLE(platform, s3cmci_driver_ids); MODULE_DEVICE_TABLE(platform, s3cmci_driver_ids);
#ifdef CONFIG_PM
static int s3cmci_suspend(struct device *dev)
{
struct mmc_host *mmc = platform_get_drvdata(to_platform_device(dev));
return mmc_suspend_host(mmc);
}
static int s3cmci_resume(struct device *dev)
{
struct mmc_host *mmc = platform_get_drvdata(to_platform_device(dev));
return mmc_resume_host(mmc);
}
static const struct dev_pm_ops s3cmci_pm = {
.suspend = s3cmci_suspend,
.resume = s3cmci_resume,
};
#define s3cmci_pm_ops &s3cmci_pm
#else /* CONFIG_PM */
#define s3cmci_pm_ops NULL
#endif /* CONFIG_PM */
static struct platform_driver s3cmci_driver = { static struct platform_driver s3cmci_driver = {
.driver = { .driver = {
.name = "s3c-sdi", .name = "s3c-sdi",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.pm = s3cmci_pm_ops,
}, },
.id_table = s3cmci_driver_ids, .id_table = s3cmci_driver_ids,
.probe = s3cmci_probe, .probe = s3cmci_probe,
......
...@@ -316,19 +316,7 @@ static int sdhci_bcm_kona_probe(struct platform_device *pdev) ...@@ -316,19 +316,7 @@ static int sdhci_bcm_kona_probe(struct platform_device *pdev)
static int __exit sdhci_bcm_kona_remove(struct platform_device *pdev) static int __exit sdhci_bcm_kona_remove(struct platform_device *pdev)
{ {
struct sdhci_host *host = platform_get_drvdata(pdev); return sdhci_pltfm_unregister(pdev);
int dead;
u32 scratch;
dead = 0;
scratch = readl(host->ioaddr + SDHCI_INT_STATUS);
if (scratch == (u32)-1)
dead = 1;
sdhci_remove_host(host, dead);
sdhci_free_host(host);
return 0;
} }
static struct platform_driver sdhci_bcm_kona_driver = { static struct platform_driver sdhci_bcm_kona_driver = {
......
...@@ -178,13 +178,7 @@ static int bcm2835_sdhci_probe(struct platform_device *pdev) ...@@ -178,13 +178,7 @@ static int bcm2835_sdhci_probe(struct platform_device *pdev)
static int bcm2835_sdhci_remove(struct platform_device *pdev) static int bcm2835_sdhci_remove(struct platform_device *pdev)
{ {
struct sdhci_host *host = platform_get_drvdata(pdev); return sdhci_pltfm_unregister(pdev);
int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
sdhci_remove_host(host, dead);
sdhci_pltfm_free(pdev);
return 0;
} }
static const struct of_device_id bcm2835_sdhci_of_match[] = { static const struct of_device_id bcm2835_sdhci_of_match[] = {
......
此差异已折叠。
...@@ -49,41 +49,4 @@ ...@@ -49,41 +49,4 @@
#define ESDHC_HOST_CONTROL_RES 0x05 #define ESDHC_HOST_CONTROL_RES 0x05
static inline void esdhc_set_clock(struct sdhci_host *host, unsigned int clock,
unsigned int host_clock)
{
int pre_div = 2;
int div = 1;
u32 temp;
if (clock == 0)
goto out;
temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
| ESDHC_CLOCK_MASK);
sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
while (host_clock / pre_div / 16 > clock && pre_div < 256)
pre_div *= 2;
while (host_clock / pre_div / div > clock && div < 16)
div++;
dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
clock, host_clock / pre_div / div);
pre_div >>= 1;
div--;
temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
temp |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
| (div << ESDHC_DIVIDER_SHIFT)
| (pre_div << ESDHC_PREDIV_SHIFT));
sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
mdelay(1);
out:
host->clock = clock;
}
#endif /* _DRIVERS_MMC_SDHCI_ESDHC_H */ #endif /* _DRIVERS_MMC_SDHCI_ESDHC_H */
...@@ -199,6 +199,14 @@ static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host) ...@@ -199,6 +199,14 @@ static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)
static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
{ {
int pre_div = 2;
int div = 1;
u32 temp;
if (clock == 0)
goto out;
/* Workaround to reduce the clock frequency for p1010 esdhc */ /* Workaround to reduce the clock frequency for p1010 esdhc */
if (of_find_compatible_node(NULL, NULL, "fsl,p1010-esdhc")) { if (of_find_compatible_node(NULL, NULL, "fsl,p1010-esdhc")) {
if (clock > 20000000) if (clock > 20000000)
...@@ -207,8 +215,31 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) ...@@ -207,8 +215,31 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
clock -= 5000000; clock -= 5000000;
} }
/* Set the clock */ temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
esdhc_set_clock(host, clock, host->max_clk); temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
| ESDHC_CLOCK_MASK);
sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
while (host->max_clk / pre_div / 16 > clock && pre_div < 256)
pre_div *= 2;
while (host->max_clk / pre_div / div > clock && div < 16)
div++;
dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
clock, host->max_clk / pre_div / div);
pre_div >>= 1;
div--;
temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
temp |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
| (div << ESDHC_DIVIDER_SHIFT)
| (pre_div << ESDHC_PREDIV_SHIFT));
sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
mdelay(1);
out:
host->clock = clock;
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM
......
...@@ -37,6 +37,12 @@ ...@@ -37,6 +37,12 @@
#define PCI_DEVICE_ID_INTEL_BYT_SDIO 0x0f15 #define PCI_DEVICE_ID_INTEL_BYT_SDIO 0x0f15
#define PCI_DEVICE_ID_INTEL_BYT_SD 0x0f16 #define PCI_DEVICE_ID_INTEL_BYT_SD 0x0f16
#define PCI_DEVICE_ID_INTEL_BYT_EMMC2 0x0f50 #define PCI_DEVICE_ID_INTEL_BYT_EMMC2 0x0f50
#define PCI_DEVICE_ID_INTEL_MRFL_MMC 0x1190
#define PCI_DEVICE_ID_INTEL_CLV_SDIO0 0x08f9
#define PCI_DEVICE_ID_INTEL_CLV_SDIO1 0x08fa
#define PCI_DEVICE_ID_INTEL_CLV_SDIO2 0x08fb
#define PCI_DEVICE_ID_INTEL_CLV_EMMC0 0x08e5
#define PCI_DEVICE_ID_INTEL_CLV_EMMC1 0x08e6
/* /*
* PCI registers * PCI registers
...@@ -356,6 +362,28 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sd = { ...@@ -356,6 +362,28 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
.allow_runtime_pm = true, .allow_runtime_pm = true,
}; };
/* Define Host controllers for Intel Merrifield platform */
#define INTEL_MRFL_EMMC_0 0
#define INTEL_MRFL_EMMC_1 1
static int intel_mrfl_mmc_probe_slot(struct sdhci_pci_slot *slot)
{
if ((PCI_FUNC(slot->chip->pdev->devfn) != INTEL_MRFL_EMMC_0) &&
(PCI_FUNC(slot->chip->pdev->devfn) != INTEL_MRFL_EMMC_1))
/* SD support is not ready yet */
return -ENODEV;
slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE |
MMC_CAP_1_8V_DDR;
return 0;
}
static const struct sdhci_pci_fixes sdhci_intel_mrfl_mmc = {
.quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.probe_slot = intel_mrfl_mmc_probe_slot,
};
/* O2Micro extra registers */ /* O2Micro extra registers */
#define O2_SD_LOCK_WP 0xD3 #define O2_SD_LOCK_WP 0xD3
#define O2_SD_MULTI_VCC3V 0xEE #define O2_SD_MULTI_VCC3V 0xEE
...@@ -939,6 +967,54 @@ static const struct pci_device_id pci_ids[] = { ...@@ -939,6 +967,54 @@ static const struct pci_device_id pci_ids[] = {
.driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc, .driver_data = (kernel_ulong_t)&sdhci_intel_byt_emmc,
}, },
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_CLV_SDIO0,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_intel_mfd_sd,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_CLV_SDIO1,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_intel_mfd_sdio,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_CLV_SDIO2,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_intel_mfd_sdio,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_CLV_EMMC0,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_intel_mfd_emmc,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_CLV_EMMC1,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_intel_mfd_emmc,
},
{
.vendor = PCI_VENDOR_ID_INTEL,
.device = PCI_DEVICE_ID_INTEL_MRFL_MMC,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_intel_mrfl_mmc,
},
{ {
.vendor = PCI_VENDOR_ID_O2, .vendor = PCI_VENDOR_ID_O2,
.device = PCI_DEVICE_ID_O2_8120, .device = PCI_DEVICE_ID_O2_8120,
......
...@@ -49,7 +49,6 @@ static unsigned int debug_quirks2; ...@@ -49,7 +49,6 @@ static unsigned int debug_quirks2;
static void sdhci_finish_data(struct sdhci_host *); static void sdhci_finish_data(struct sdhci_host *);
static void sdhci_send_command(struct sdhci_host *, struct mmc_command *);
static void sdhci_finish_command(struct sdhci_host *); static void sdhci_finish_command(struct sdhci_host *);
static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode); static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
static void sdhci_tuning_timer(unsigned long data); static void sdhci_tuning_timer(unsigned long data);
...@@ -981,7 +980,7 @@ static void sdhci_finish_data(struct sdhci_host *host) ...@@ -981,7 +980,7 @@ static void sdhci_finish_data(struct sdhci_host *host)
tasklet_schedule(&host->finish_tasklet); tasklet_schedule(&host->finish_tasklet);
} }
static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
{ {
int flags; int flags;
u32 mask; u32 mask;
...@@ -1053,6 +1052,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) ...@@ -1053,6 +1052,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND); sdhci_writew(host, SDHCI_MAKE_CMD(cmd->opcode, flags), SDHCI_COMMAND);
} }
EXPORT_SYMBOL_GPL(sdhci_send_command);
static void sdhci_finish_command(struct sdhci_host *host) static void sdhci_finish_command(struct sdhci_host *host)
{ {
...@@ -1435,7 +1435,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) ...@@ -1435,7 +1435,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
} }
if (host->version >= SDHCI_SPEC_300 && if (host->version >= SDHCI_SPEC_300 &&
(ios->power_mode == MMC_POWER_UP)) (ios->power_mode == MMC_POWER_UP) &&
!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN))
sdhci_enable_preset_value(host, false); sdhci_enable_preset_value(host, false);
sdhci_set_clock(host, ios->clock); sdhci_set_clock(host, ios->clock);
...@@ -1875,6 +1876,14 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) ...@@ -1875,6 +1876,14 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
return 0; return 0;
} }
if (host->ops->platform_execute_tuning) {
spin_unlock(&host->lock);
enable_irq(host->irq);
err = host->ops->platform_execute_tuning(host, opcode);
sdhci_runtime_pm_put(host);
return err;
}
sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
/* /*
...@@ -1981,6 +1990,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode) ...@@ -1981,6 +1990,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
if (!tuning_loop_counter || !timeout) { if (!tuning_loop_counter || !timeout) {
ctrl &= ~SDHCI_CTRL_TUNED_CLK; ctrl &= ~SDHCI_CTRL_TUNED_CLK;
sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2); sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
err = -EIO;
} else { } else {
if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) { if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) {
pr_info(DRIVER_NAME ": Tuning procedure" pr_info(DRIVER_NAME ": Tuning procedure"
...@@ -2491,6 +2501,14 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) ...@@ -2491,6 +2501,14 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
result = IRQ_HANDLED; result = IRQ_HANDLED;
intmask = sdhci_readl(host, SDHCI_INT_STATUS); intmask = sdhci_readl(host, SDHCI_INT_STATUS);
/*
* If we know we'll call the driver to signal SDIO IRQ, disregard
* further indications of Card Interrupt in the status to avoid a
* needless loop.
*/
if (cardint)
intmask &= ~SDHCI_INT_CARD_INT;
if (intmask && --max_loops) if (intmask && --max_loops)
goto again; goto again;
out: out:
...@@ -2546,8 +2564,6 @@ EXPORT_SYMBOL_GPL(sdhci_disable_irq_wakeups); ...@@ -2546,8 +2564,6 @@ EXPORT_SYMBOL_GPL(sdhci_disable_irq_wakeups);
int sdhci_suspend_host(struct sdhci_host *host) int sdhci_suspend_host(struct sdhci_host *host)
{ {
int ret;
if (host->ops->platform_suspend) if (host->ops->platform_suspend)
host->ops->platform_suspend(host); host->ops->platform_suspend(host);
...@@ -2559,19 +2575,6 @@ int sdhci_suspend_host(struct sdhci_host *host) ...@@ -2559,19 +2575,6 @@ int sdhci_suspend_host(struct sdhci_host *host)
host->flags &= ~SDHCI_NEEDS_RETUNING; host->flags &= ~SDHCI_NEEDS_RETUNING;
} }
ret = mmc_suspend_host(host->mmc);
if (ret) {
if (host->flags & SDHCI_USING_RETUNING_TIMER) {
host->flags |= SDHCI_NEEDS_RETUNING;
mod_timer(&host->tuning_timer, jiffies +
host->tuning_count * HZ);
}
sdhci_enable_card_detection(host);
return ret;
}
if (!device_may_wakeup(mmc_dev(host->mmc))) { if (!device_may_wakeup(mmc_dev(host->mmc))) {
sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK); sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
free_irq(host->irq, host); free_irq(host->irq, host);
...@@ -2579,14 +2582,14 @@ int sdhci_suspend_host(struct sdhci_host *host) ...@@ -2579,14 +2582,14 @@ int sdhci_suspend_host(struct sdhci_host *host)
sdhci_enable_irq_wakeups(host); sdhci_enable_irq_wakeups(host);
enable_irq_wake(host->irq); enable_irq_wake(host->irq);
} }
return ret; return 0;
} }
EXPORT_SYMBOL_GPL(sdhci_suspend_host); EXPORT_SYMBOL_GPL(sdhci_suspend_host);
int sdhci_resume_host(struct sdhci_host *host) int sdhci_resume_host(struct sdhci_host *host)
{ {
int ret; int ret = 0;
if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) { if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
if (host->ops->enable_dma) if (host->ops->enable_dma)
...@@ -2615,7 +2618,6 @@ int sdhci_resume_host(struct sdhci_host *host) ...@@ -2615,7 +2618,6 @@ int sdhci_resume_host(struct sdhci_host *host)
mmiowb(); mmiowb();
} }
ret = mmc_resume_host(host->mmc);
sdhci_enable_card_detection(host); sdhci_enable_card_detection(host);
if (host->ops->platform_resume) if (host->ops->platform_resume)
......
...@@ -288,6 +288,7 @@ struct sdhci_ops { ...@@ -288,6 +288,7 @@ struct sdhci_ops {
unsigned int (*get_ro)(struct sdhci_host *host); unsigned int (*get_ro)(struct sdhci_host *host);
void (*platform_reset_enter)(struct sdhci_host *host, u8 mask); void (*platform_reset_enter)(struct sdhci_host *host, u8 mask);
void (*platform_reset_exit)(struct sdhci_host *host, u8 mask); void (*platform_reset_exit)(struct sdhci_host *host, u8 mask);
int (*platform_execute_tuning)(struct sdhci_host *host, u32 opcode);
int (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs); int (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
void (*hw_reset)(struct sdhci_host *host); void (*hw_reset)(struct sdhci_host *host);
void (*platform_suspend)(struct sdhci_host *host); void (*platform_suspend)(struct sdhci_host *host);
...@@ -393,6 +394,8 @@ static inline void *sdhci_priv(struct sdhci_host *host) ...@@ -393,6 +394,8 @@ static inline void *sdhci_priv(struct sdhci_host *host)
extern void sdhci_card_detect(struct sdhci_host *host); extern void sdhci_card_detect(struct sdhci_host *host);
extern int sdhci_add_host(struct sdhci_host *host); extern int sdhci_add_host(struct sdhci_host *host);
extern void sdhci_remove_host(struct sdhci_host *host, int dead); extern void sdhci_remove_host(struct sdhci_host *host, int dead);
extern void sdhci_send_command(struct sdhci_host *host,
struct mmc_command *cmd);
#ifdef CONFIG_PM #ifdef CONFIG_PM
extern int sdhci_suspend_host(struct sdhci_host *host); extern int sdhci_suspend_host(struct sdhci_host *host);
......
...@@ -516,9 +516,7 @@ static void sdricoh_pcmcia_detach(struct pcmcia_device *link) ...@@ -516,9 +516,7 @@ static void sdricoh_pcmcia_detach(struct pcmcia_device *link)
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int sdricoh_pcmcia_suspend(struct pcmcia_device *link) static int sdricoh_pcmcia_suspend(struct pcmcia_device *link)
{ {
struct mmc_host *mmc = link->priv;
dev_dbg(&link->dev, "suspend\n"); dev_dbg(&link->dev, "suspend\n");
mmc_suspend_host(mmc);
return 0; return 0;
} }
...@@ -527,7 +525,6 @@ static int sdricoh_pcmcia_resume(struct pcmcia_device *link) ...@@ -527,7 +525,6 @@ static int sdricoh_pcmcia_resume(struct pcmcia_device *link)
struct mmc_host *mmc = link->priv; struct mmc_host *mmc = link->priv;
dev_dbg(&link->dev, "resume\n"); dev_dbg(&link->dev, "resume\n");
sdricoh_reset(mmc_priv(mmc)); sdricoh_reset(mmc_priv(mmc));
mmc_resume_host(mmc);
return 0; return 0;
} }
#else #else
......
...@@ -964,7 +964,7 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq) ...@@ -964,7 +964,7 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
static int sh_mmcif_clk_update(struct sh_mmcif_host *host) static int sh_mmcif_clk_update(struct sh_mmcif_host *host)
{ {
int ret = clk_enable(host->hclk); int ret = clk_prepare_enable(host->hclk);
if (!ret) { if (!ret) {
host->clk = clk_get_rate(host->hclk); host->clk = clk_get_rate(host->hclk);
...@@ -1018,7 +1018,7 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) ...@@ -1018,7 +1018,7 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
} }
if (host->power) { if (host->power) {
pm_runtime_put_sync(&host->pd->dev); pm_runtime_put_sync(&host->pd->dev);
clk_disable(host->hclk); clk_disable_unprepare(host->hclk);
host->power = false; host->power = false;
if (ios->power_mode == MMC_POWER_OFF) if (ios->power_mode == MMC_POWER_OFF)
sh_mmcif_set_power(host, ios); sh_mmcif_set_power(host, ios);
...@@ -1466,7 +1466,7 @@ static int sh_mmcif_probe(struct platform_device *pdev) ...@@ -1466,7 +1466,7 @@ static int sh_mmcif_probe(struct platform_device *pdev)
mutex_init(&host->thread_lock); mutex_init(&host->thread_lock);
clk_disable(host->hclk); clk_disable_unprepare(host->hclk);
ret = mmc_add_host(mmc); ret = mmc_add_host(mmc);
if (ret < 0) if (ret < 0)
goto emmcaddh; goto emmcaddh;
...@@ -1487,7 +1487,7 @@ static int sh_mmcif_probe(struct platform_device *pdev) ...@@ -1487,7 +1487,7 @@ static int sh_mmcif_probe(struct platform_device *pdev)
ereqirq0: ereqirq0:
pm_runtime_suspend(&pdev->dev); pm_runtime_suspend(&pdev->dev);
eresume: eresume:
clk_disable(host->hclk); clk_disable_unprepare(host->hclk);
eclkupdate: eclkupdate:
clk_put(host->hclk); clk_put(host->hclk);
eclkget: eclkget:
...@@ -1505,7 +1505,7 @@ static int sh_mmcif_remove(struct platform_device *pdev) ...@@ -1505,7 +1505,7 @@ static int sh_mmcif_remove(struct platform_device *pdev)
int irq[2]; int irq[2];
host->dying = true; host->dying = true;
clk_enable(host->hclk); clk_prepare_enable(host->hclk);
pm_runtime_get_sync(&pdev->dev); pm_runtime_get_sync(&pdev->dev);
dev_pm_qos_hide_latency_limit(&pdev->dev); dev_pm_qos_hide_latency_limit(&pdev->dev);
...@@ -1530,7 +1530,7 @@ static int sh_mmcif_remove(struct platform_device *pdev) ...@@ -1530,7 +1530,7 @@ static int sh_mmcif_remove(struct platform_device *pdev)
if (irq[1] >= 0) if (irq[1] >= 0)
free_irq(irq[1], host); free_irq(irq[1], host);
clk_disable(host->hclk); clk_disable_unprepare(host->hclk);
mmc_free_host(host->mmc); mmc_free_host(host->mmc);
pm_runtime_put_sync(&pdev->dev); pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
...@@ -1538,28 +1538,21 @@ static int sh_mmcif_remove(struct platform_device *pdev) ...@@ -1538,28 +1538,21 @@ static int sh_mmcif_remove(struct platform_device *pdev)
return 0; return 0;
} }
#ifdef CONFIG_PM #ifdef CONFIG_PM_SLEEP
static int sh_mmcif_suspend(struct device *dev) static int sh_mmcif_suspend(struct device *dev)
{ {
struct sh_mmcif_host *host = dev_get_drvdata(dev); struct sh_mmcif_host *host = dev_get_drvdata(dev);
int ret = mmc_suspend_host(host->mmc);
if (!ret) sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL);
return ret; return 0;
} }
static int sh_mmcif_resume(struct device *dev) static int sh_mmcif_resume(struct device *dev)
{ {
struct sh_mmcif_host *host = dev_get_drvdata(dev); return 0;
return mmc_resume_host(host->mmc);
} }
#else #endif
#define sh_mmcif_suspend NULL
#define sh_mmcif_resume NULL
#endif /* CONFIG_PM */
static const struct of_device_id mmcif_of_match[] = { static const struct of_device_id mmcif_of_match[] = {
{ .compatible = "renesas,sh-mmcif" }, { .compatible = "renesas,sh-mmcif" },
...@@ -1568,8 +1561,7 @@ static const struct of_device_id mmcif_of_match[] = { ...@@ -1568,8 +1561,7 @@ static const struct of_device_id mmcif_of_match[] = {
MODULE_DEVICE_TABLE(of, mmcif_of_match); MODULE_DEVICE_TABLE(of, mmcif_of_match);
static const struct dev_pm_ops sh_mmcif_dev_pm_ops = { static const struct dev_pm_ops sh_mmcif_dev_pm_ops = {
.suspend = sh_mmcif_suspend, SET_SYSTEM_SLEEP_PM_OPS(sh_mmcif_suspend, sh_mmcif_resume)
.resume = sh_mmcif_resume,
}; };
static struct platform_driver sh_mmcif_driver = { static struct platform_driver sh_mmcif_driver = {
......
...@@ -1030,7 +1030,7 @@ static void tifm_sd_remove(struct tifm_dev *sock) ...@@ -1030,7 +1030,7 @@ static void tifm_sd_remove(struct tifm_dev *sock)
static int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state) static int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state)
{ {
return mmc_suspend_host(tifm_get_drvdata(sock)); return 0;
} }
static int tifm_sd_resume(struct tifm_dev *sock) static int tifm_sd_resume(struct tifm_dev *sock)
...@@ -1044,8 +1044,6 @@ static int tifm_sd_resume(struct tifm_dev *sock) ...@@ -1044,8 +1044,6 @@ static int tifm_sd_resume(struct tifm_dev *sock)
if (rc) if (rc)
host->eject = 1; host->eject = 1;
else
rc = mmc_resume_host(mmc);
return rc; return rc;
} }
......
...@@ -1145,12 +1145,9 @@ int tmio_mmc_host_suspend(struct device *dev) ...@@ -1145,12 +1145,9 @@ int tmio_mmc_host_suspend(struct device *dev)
{ {
struct mmc_host *mmc = dev_get_drvdata(dev); struct mmc_host *mmc = dev_get_drvdata(dev);
struct tmio_mmc_host *host = mmc_priv(mmc); struct tmio_mmc_host *host = mmc_priv(mmc);
int ret = mmc_suspend_host(mmc);
if (!ret) tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_ALL);
tmio_mmc_disable_mmc_irqs(host, TMIO_MASK_ALL); return 0;
return ret;
} }
EXPORT_SYMBOL(tmio_mmc_host_suspend); EXPORT_SYMBOL(tmio_mmc_host_suspend);
...@@ -1163,7 +1160,7 @@ int tmio_mmc_host_resume(struct device *dev) ...@@ -1163,7 +1160,7 @@ int tmio_mmc_host_resume(struct device *dev)
/* The MMC core will perform the complete set up */ /* The MMC core will perform the complete set up */
host->resuming = true; host->resuming = true;
return mmc_resume_host(mmc); return 0;
} }
EXPORT_SYMBOL(tmio_mmc_host_resume); EXPORT_SYMBOL(tmio_mmc_host_resume);
......
...@@ -1269,21 +1269,18 @@ static void via_init_sdc_pm(struct via_crdr_mmc_host *host) ...@@ -1269,21 +1269,18 @@ static void via_init_sdc_pm(struct via_crdr_mmc_host *host)
static int via_sd_suspend(struct pci_dev *pcidev, pm_message_t state) static int via_sd_suspend(struct pci_dev *pcidev, pm_message_t state)
{ {
struct via_crdr_mmc_host *host; struct via_crdr_mmc_host *host;
int ret = 0;
host = pci_get_drvdata(pcidev); host = pci_get_drvdata(pcidev);
via_save_pcictrlreg(host); via_save_pcictrlreg(host);
via_save_sdcreg(host); via_save_sdcreg(host);
ret = mmc_suspend_host(host->mmc);
pci_save_state(pcidev); pci_save_state(pcidev);
pci_enable_wake(pcidev, pci_choose_state(pcidev, state), 0); pci_enable_wake(pcidev, pci_choose_state(pcidev, state), 0);
pci_disable_device(pcidev); pci_disable_device(pcidev);
pci_set_power_state(pcidev, pci_choose_state(pcidev, state)); pci_set_power_state(pcidev, pci_choose_state(pcidev, state));
return ret; return 0;
} }
static int via_sd_resume(struct pci_dev *pcidev) static int via_sd_resume(struct pci_dev *pcidev)
...@@ -1316,8 +1313,6 @@ static int via_sd_resume(struct pci_dev *pcidev) ...@@ -1316,8 +1313,6 @@ static int via_sd_resume(struct pci_dev *pcidev)
via_restore_pcictrlreg(sdhost); via_restore_pcictrlreg(sdhost);
via_init_sdc_pm(sdhost); via_init_sdc_pm(sdhost);
ret = mmc_resume_host(sdhost->mmc);
return ret; return ret;
} }
......
...@@ -2392,26 +2392,12 @@ static void vub300_disconnect(struct usb_interface *interface) ...@@ -2392,26 +2392,12 @@ static void vub300_disconnect(struct usb_interface *interface)
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int vub300_suspend(struct usb_interface *intf, pm_message_t message) static int vub300_suspend(struct usb_interface *intf, pm_message_t message)
{ {
struct vub300_mmc_host *vub300 = usb_get_intfdata(intf); return 0;
if (!vub300 || !vub300->mmc) {
return 0;
} else {
struct mmc_host *mmc = vub300->mmc;
mmc_suspend_host(mmc);
return 0;
}
} }
static int vub300_resume(struct usb_interface *intf) static int vub300_resume(struct usb_interface *intf)
{ {
struct vub300_mmc_host *vub300 = usb_get_intfdata(intf); return 0;
if (!vub300 || !vub300->mmc) {
return 0;
} else {
struct mmc_host *mmc = vub300->mmc;
mmc_resume_host(mmc);
return 0;
}
} }
#else #else
#define vub300_suspend NULL #define vub300_suspend NULL
......
...@@ -1814,28 +1814,11 @@ static void wbsd_pnp_remove(struct pnp_dev *dev) ...@@ -1814,28 +1814,11 @@ static void wbsd_pnp_remove(struct pnp_dev *dev)
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int wbsd_suspend(struct wbsd_host *host, pm_message_t state)
{
BUG_ON(host == NULL);
return mmc_suspend_host(host->mmc);
}
static int wbsd_resume(struct wbsd_host *host)
{
BUG_ON(host == NULL);
wbsd_init_device(host);
return mmc_resume_host(host->mmc);
}
static int wbsd_platform_suspend(struct platform_device *dev, static int wbsd_platform_suspend(struct platform_device *dev,
pm_message_t state) pm_message_t state)
{ {
struct mmc_host *mmc = platform_get_drvdata(dev); struct mmc_host *mmc = platform_get_drvdata(dev);
struct wbsd_host *host; struct wbsd_host *host;
int ret;
if (mmc == NULL) if (mmc == NULL)
return 0; return 0;
...@@ -1844,12 +1827,7 @@ static int wbsd_platform_suspend(struct platform_device *dev, ...@@ -1844,12 +1827,7 @@ static int wbsd_platform_suspend(struct platform_device *dev,
host = mmc_priv(mmc); host = mmc_priv(mmc);
ret = wbsd_suspend(host, state);
if (ret)
return ret;
wbsd_chip_poweroff(host); wbsd_chip_poweroff(host);
return 0; return 0;
} }
...@@ -1872,7 +1850,8 @@ static int wbsd_platform_resume(struct platform_device *dev) ...@@ -1872,7 +1850,8 @@ static int wbsd_platform_resume(struct platform_device *dev)
*/ */
mdelay(5); mdelay(5);
return wbsd_resume(host); wbsd_init_device(host);
return 0;
} }
#ifdef CONFIG_PNP #ifdef CONFIG_PNP
...@@ -1880,16 +1859,12 @@ static int wbsd_platform_resume(struct platform_device *dev) ...@@ -1880,16 +1859,12 @@ static int wbsd_platform_resume(struct platform_device *dev)
static int wbsd_pnp_suspend(struct pnp_dev *pnp_dev, pm_message_t state) static int wbsd_pnp_suspend(struct pnp_dev *pnp_dev, pm_message_t state)
{ {
struct mmc_host *mmc = dev_get_drvdata(&pnp_dev->dev); struct mmc_host *mmc = dev_get_drvdata(&pnp_dev->dev);
struct wbsd_host *host;
if (mmc == NULL) if (mmc == NULL)
return 0; return 0;
DBGF("Suspending...\n"); DBGF("Suspending...\n");
return 0;
host = mmc_priv(mmc);
return wbsd_suspend(host, state);
} }
static int wbsd_pnp_resume(struct pnp_dev *pnp_dev) static int wbsd_pnp_resume(struct pnp_dev *pnp_dev)
...@@ -1922,7 +1897,8 @@ static int wbsd_pnp_resume(struct pnp_dev *pnp_dev) ...@@ -1922,7 +1897,8 @@ static int wbsd_pnp_resume(struct pnp_dev *pnp_dev)
*/ */
mdelay(5); mdelay(5);
return wbsd_resume(host); wbsd_init_device(host);
return 0;
} }
#endif /* CONFIG_PNP */ #endif /* CONFIG_PNP */
......
此差异已折叠。
...@@ -240,6 +240,7 @@ struct mmc_part { ...@@ -240,6 +240,7 @@ struct mmc_part {
struct mmc_card { struct mmc_card {
struct mmc_host *host; /* the host this device belongs to */ struct mmc_host *host; /* the host this device belongs to */
struct device dev; /* the device */ struct device dev; /* the device */
u32 ocr; /* the current OCR setting */
unsigned int rca; /* relative card address of device */ unsigned int rca; /* relative card address of device */
unsigned int type; /* card type */ unsigned int type; /* card type */
#define MMC_TYPE_MMC 0 /* MMC card */ #define MMC_TYPE_MMC 0 /* MMC card */
...@@ -257,6 +258,7 @@ struct mmc_card { ...@@ -257,6 +258,7 @@ struct mmc_card {
#define MMC_CARD_REMOVED (1<<7) /* card has been removed */ #define MMC_CARD_REMOVED (1<<7) /* card has been removed */
#define MMC_STATE_HIGHSPEED_200 (1<<8) /* card is in HS200 mode */ #define MMC_STATE_HIGHSPEED_200 (1<<8) /* card is in HS200 mode */
#define MMC_STATE_DOING_BKOPS (1<<10) /* card is doing BKOPS */ #define MMC_STATE_DOING_BKOPS (1<<10) /* card is doing BKOPS */
#define MMC_STATE_SUSPENDED (1<<11) /* card is suspended */
unsigned int quirks; /* card quirks */ unsigned int quirks; /* card quirks */
#define MMC_QUIRK_LENIENT_FN0 (1<<0) /* allow SDIO FN0 writes outside of the VS CCCR range */ #define MMC_QUIRK_LENIENT_FN0 (1<<0) /* allow SDIO FN0 writes outside of the VS CCCR range */
#define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func->cur_blksize */ #define MMC_QUIRK_BLKSZ_FOR_BYTE_MODE (1<<1) /* use func->cur_blksize */
...@@ -420,10 +422,10 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data) ...@@ -420,10 +422,10 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
#define mmc_card_blockaddr(c) ((c)->state & MMC_STATE_BLOCKADDR) #define mmc_card_blockaddr(c) ((c)->state & MMC_STATE_BLOCKADDR)
#define mmc_card_ddr_mode(c) ((c)->state & MMC_STATE_HIGHSPEED_DDR) #define mmc_card_ddr_mode(c) ((c)->state & MMC_STATE_HIGHSPEED_DDR)
#define mmc_card_uhs(c) ((c)->state & MMC_STATE_ULTRAHIGHSPEED) #define mmc_card_uhs(c) ((c)->state & MMC_STATE_ULTRAHIGHSPEED)
#define mmc_sd_card_uhs(c) ((c)->state & MMC_STATE_ULTRAHIGHSPEED)
#define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC) #define mmc_card_ext_capacity(c) ((c)->state & MMC_CARD_SDXC)
#define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED)) #define mmc_card_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED))
#define mmc_card_doing_bkops(c) ((c)->state & MMC_STATE_DOING_BKOPS) #define mmc_card_doing_bkops(c) ((c)->state & MMC_STATE_DOING_BKOPS)
#define mmc_card_suspended(c) ((c)->state & MMC_STATE_SUSPENDED)
#define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT) #define mmc_card_set_present(c) ((c)->state |= MMC_STATE_PRESENT)
#define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY) #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
...@@ -432,11 +434,12 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data) ...@@ -432,11 +434,12 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
#define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR) #define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
#define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR) #define mmc_card_set_ddr_mode(c) ((c)->state |= MMC_STATE_HIGHSPEED_DDR)
#define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED) #define mmc_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
#define mmc_sd_card_set_uhs(c) ((c)->state |= MMC_STATE_ULTRAHIGHSPEED)
#define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC) #define mmc_card_set_ext_capacity(c) ((c)->state |= MMC_CARD_SDXC)
#define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED) #define mmc_card_set_removed(c) ((c)->state |= MMC_CARD_REMOVED)
#define mmc_card_set_doing_bkops(c) ((c)->state |= MMC_STATE_DOING_BKOPS) #define mmc_card_set_doing_bkops(c) ((c)->state |= MMC_STATE_DOING_BKOPS)
#define mmc_card_clr_doing_bkops(c) ((c)->state &= ~MMC_STATE_DOING_BKOPS) #define mmc_card_clr_doing_bkops(c) ((c)->state &= ~MMC_STATE_DOING_BKOPS)
#define mmc_card_set_suspended(c) ((c)->state |= MMC_STATE_SUSPENDED)
#define mmc_card_clr_suspended(c) ((c)->state &= ~MMC_STATE_SUSPENDED)
/* /*
* Quirk add/remove for MMC products. * Quirk add/remove for MMC products.
......
...@@ -151,7 +151,8 @@ extern int mmc_app_cmd(struct mmc_host *, struct mmc_card *); ...@@ -151,7 +151,8 @@ extern int mmc_app_cmd(struct mmc_host *, struct mmc_card *);
extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *, extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,
struct mmc_command *, int); struct mmc_command *, int);
extern void mmc_start_bkops(struct mmc_card *card, bool from_exception); extern void mmc_start_bkops(struct mmc_card *card, bool from_exception);
extern int __mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int, bool); extern int __mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int, bool,
bool);
extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int); extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int);
extern int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd); extern int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
...@@ -188,7 +189,6 @@ extern unsigned int mmc_align_data_size(struct mmc_card *, unsigned int); ...@@ -188,7 +189,6 @@ extern unsigned int mmc_align_data_size(struct mmc_card *, unsigned int);
extern int __mmc_claim_host(struct mmc_host *host, atomic_t *abort); extern int __mmc_claim_host(struct mmc_host *host, atomic_t *abort);
extern void mmc_release_host(struct mmc_host *host); extern void mmc_release_host(struct mmc_host *host);
extern int mmc_try_claim_host(struct mmc_host *host);
extern void mmc_get_card(struct mmc_card *card); extern void mmc_get_card(struct mmc_card *card);
extern void mmc_put_card(struct mmc_card *card); extern void mmc_put_card(struct mmc_card *card);
......
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册