MMC fixes for 3.4-rc2:
The major fixes here are: * Disable use of MSI in sdhci-pci, which caused multiple chipsets to stop working in 3.4-rc1. I'll wait to turn this on again until we have a chipset whitelist for it. * Fix a libertas SDIO powered-resume regression introduced in 3.3; thanks to Neil Brown and Rafael Wysocki for this fix. * Fix module reloading on omap_hsmmc. * Stop trusting the spec/card's specified maximum data timeout length, and use three seconds instead. Previously we used 300ms. Also cleanups and fixes for s3c, atmel, sh_mmcif and omap_hsmmc. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJPfzfxAAoJEHNBYZ7TNxYMGBoP/02Drw+n4c7xykXdB7SSloq8 SGIAmh25EBFyZhcEmQ8Mm5qn4voHG8+Jm7ZXA3OipJ4xucu5fdoCIu/n8arGYa2u GRB+GYOz92maCNBwLGZIMm7A64m2rkrRdwTw4pkjOZuJLh28GCshK2E+ZWoMKVNU flaUna7NQc/p2eXulCNirry+4l1xxGW00lYaSOq78MTOKUMwWLCJZw+TUvfvxjX8 5BFc3b2+5fQKc1M0qh23oEcneRdOUUK6dWzvZHuQso1SkDeB1cetN9fzrhnys9or tooIqd+GQRPJ6oGqe+VD8MT8HGMPb6oETZaFM7h7bt8nFcScu3iVjmJQLIbnsNBY ho8AUkMbZtDtRBWDtk11zM9qrOWGufRdB0qW4R+4Zik1JohNp6SAeV7YSllIT4sT lT5gdzAxAiZ992iwYKuwAn0SQOlevN2BjHMFGg8abZtlOWEWE2YIQ0nTJS2SCIyj qbM9wmLZ2Ymo9KabRY+huRgrbViNHDzAQOLB/LEyvbPwD97arJE1R/OVNEasiv52 rh5pCsIa5oeUeX1fsfysfug+cO96Xm1oL/cGyLRj8WZB++nurHRm7ZAo36r8FLK1 4LpMokEEwpoPcbNqsfFvOy3aRV4sGNTDj+U8B4zyq9GigSoUwSAK7Nn2qbY9zIWj W+oh3jfoyMbyVE5+00X7 =CCKD -----END PGP SIGNATURE----- Merge tag 'mmc-fixes-for-3.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc Pull MMC fixes from Chris Ball: - Disable use of MSI in sdhci-pci, which caused multiple chipsets to stop working in 3.4-rc1. I'll wait to turn this on again until we have a chipset whitelist for it. - Fix a libertas SDIO powered-resume regression introduced in 3.3; thanks to Neil Brown and Rafael Wysocki for this fix. - Fix module reloading on omap_hsmmc. - Stop trusting the spec/card's specified maximum data timeout length, and use three seconds instead. Previously we used 300ms. Also cleanups and fixes for s3c, atmel, sh_mmcif and omap_hsmmc. * tag 'mmc-fixes-for-3.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: (28 commits) mmc: use really long write timeout to deal with crappy cards mmc: sdhci-dove: Fix compile error by including module.h mmc: Prevent 1.8V switch for SD hosts that don't support UHS modes. Revert "mmc: sdhci-pci: Add MSI support" Revert "mmc: sdhci-pci: add quirks for broken MSI on O2Micro controllers" mmc: core: fix power class selection mmc: omap_hsmmc: fix module re-insertion mmc: omap_hsmmc: convert to module_platform_driver mmc: omap_hsmmc: make it behave well as a module mmc: omap_hsmmc: trivial cleanups mmc: omap_hsmmc: context save after enabling runtime pm mmc: omap_hsmmc: use runtime put sync in probe error patch mmc: sdio: Use empty system suspend/resume callbacks at the bus level mmc: bus: print bus speed mode of UHS-I card mmc: sdhci-pci: add quirks for broken MSI on O2Micro controllers mmc: sh_mmcif: Simplify calculation of mmc->f_min mmc: sh_mmcif: mmc->f_max should be half of the bus clock mmc: sh_mmcif: double clock speed mmc: block: Remove use of mmc_blk_set_blksize mmc: atmel-mci: add support for odd clock dividers ...
This commit is contained in:
commit
1ddca05743
|
@ -1623,24 +1623,6 @@ static int mmc_blk_alloc_parts(struct mmc_card *card, struct mmc_blk_data *md)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
|
||||
{
|
||||
int err;
|
||||
|
||||
mmc_claim_host(card->host);
|
||||
err = mmc_set_blocklen(card, 512);
|
||||
mmc_release_host(card->host);
|
||||
|
||||
if (err) {
|
||||
pr_err("%s: unable to set block size to 512: %d\n",
|
||||
md->disk->disk_name, err);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mmc_blk_remove_req(struct mmc_blk_data *md)
|
||||
{
|
||||
struct mmc_card *card;
|
||||
|
@ -1768,7 +1750,6 @@ static const struct mmc_fixup blk_fixups[] =
|
|||
static int mmc_blk_probe(struct mmc_card *card)
|
||||
{
|
||||
struct mmc_blk_data *md, *part_md;
|
||||
int err;
|
||||
char cap_str[10];
|
||||
|
||||
/*
|
||||
|
@ -1781,10 +1762,6 @@ static int mmc_blk_probe(struct mmc_card *card)
|
|||
if (IS_ERR(md))
|
||||
return PTR_ERR(md);
|
||||
|
||||
err = mmc_blk_set_blksize(md, card);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
string_get_size((u64)get_capacity(md->disk) << 9, STRING_UNITS_2,
|
||||
cap_str, sizeof(cap_str));
|
||||
pr_info("%s: %s %s %s %s\n",
|
||||
|
@ -1809,7 +1786,7 @@ static int mmc_blk_probe(struct mmc_card *card)
|
|||
out:
|
||||
mmc_blk_remove_parts(card, md);
|
||||
mmc_blk_remove_req(md);
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mmc_blk_remove(struct mmc_card *card)
|
||||
|
@ -1845,8 +1822,6 @@ static int mmc_blk_resume(struct mmc_card *card)
|
|||
struct mmc_blk_data *md = mmc_get_drvdata(card);
|
||||
|
||||
if (md) {
|
||||
mmc_blk_set_blksize(md, card);
|
||||
|
||||
/*
|
||||
* Resume involves the card going into idle state,
|
||||
* so current partition is always the main one.
|
||||
|
|
|
@ -267,6 +267,15 @@ int mmc_add_card(struct mmc_card *card)
|
|||
{
|
||||
int ret;
|
||||
const char *type;
|
||||
const char *uhs_bus_speed_mode = "";
|
||||
static const char *const uhs_speeds[] = {
|
||||
[UHS_SDR12_BUS_SPEED] = "SDR12 ",
|
||||
[UHS_SDR25_BUS_SPEED] = "SDR25 ",
|
||||
[UHS_SDR50_BUS_SPEED] = "SDR50 ",
|
||||
[UHS_SDR104_BUS_SPEED] = "SDR104 ",
|
||||
[UHS_DDR50_BUS_SPEED] = "DDR50 ",
|
||||
};
|
||||
|
||||
|
||||
dev_set_name(&card->dev, "%s:%04x", mmc_hostname(card->host), card->rca);
|
||||
|
||||
|
@ -296,6 +305,10 @@ int mmc_add_card(struct mmc_card *card)
|
|||
break;
|
||||
}
|
||||
|
||||
if (mmc_sd_card_uhs(card) &&
|
||||
(card->sd_bus_speed < ARRAY_SIZE(uhs_speeds)))
|
||||
uhs_bus_speed_mode = uhs_speeds[card->sd_bus_speed];
|
||||
|
||||
if (mmc_host_is_spi(card->host)) {
|
||||
pr_info("%s: new %s%s%s card on SPI\n",
|
||||
mmc_hostname(card->host),
|
||||
|
@ -303,13 +316,13 @@ int mmc_add_card(struct mmc_card *card)
|
|||
mmc_card_ddr_mode(card) ? "DDR " : "",
|
||||
type);
|
||||
} else {
|
||||
pr_info("%s: new %s%s%s%s card at address %04x\n",
|
||||
pr_info("%s: new %s%s%s%s%s card at address %04x\n",
|
||||
mmc_hostname(card->host),
|
||||
mmc_card_uhs(card) ? "ultra high speed " :
|
||||
(mmc_card_highspeed(card) ? "high speed " : ""),
|
||||
(mmc_card_hs200(card) ? "HS200 " : ""),
|
||||
mmc_card_ddr_mode(card) ? "DDR " : "",
|
||||
type, card->rca);
|
||||
uhs_bus_speed_mode, type, card->rca);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
|
|
@ -527,10 +527,14 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
|
|||
|
||||
if (data->flags & MMC_DATA_WRITE)
|
||||
/*
|
||||
* The limit is really 250 ms, but that is
|
||||
* insufficient for some crappy cards.
|
||||
* The MMC spec "It is strongly recommended
|
||||
* for hosts to implement more than 500ms
|
||||
* timeout value even if the card indicates
|
||||
* the 250ms maximum busy length." Even the
|
||||
* previous value of 300ms is known to be
|
||||
* insufficient for some cards.
|
||||
*/
|
||||
limit_us = 300000;
|
||||
limit_us = 3000000;
|
||||
else
|
||||
limit_us = 100000;
|
||||
|
||||
|
|
|
@ -695,6 +695,11 @@ static int mmc_select_powerclass(struct mmc_card *card,
|
|||
else if (host->ios.clock <= 200000000)
|
||||
index = EXT_CSD_PWR_CL_200_195;
|
||||
break;
|
||||
case MMC_VDD_27_28:
|
||||
case MMC_VDD_28_29:
|
||||
case MMC_VDD_29_30:
|
||||
case MMC_VDD_30_31:
|
||||
case MMC_VDD_31_32:
|
||||
case MMC_VDD_32_33:
|
||||
case MMC_VDD_33_34:
|
||||
case MMC_VDD_34_35:
|
||||
|
@ -1111,11 +1116,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
|||
ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
|
||||
EXT_CSD_BUS_WIDTH_8 : EXT_CSD_BUS_WIDTH_4;
|
||||
err = mmc_select_powerclass(card, ext_csd_bits, ext_csd);
|
||||
if (err) {
|
||||
pr_err("%s: power class selection to bus width %d failed\n",
|
||||
mmc_hostname(card->host), 1 << bus_width);
|
||||
goto err;
|
||||
}
|
||||
if (err)
|
||||
pr_warning("%s: power class selection to bus width %d"
|
||||
" failed\n", mmc_hostname(card->host),
|
||||
1 << bus_width);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1147,10 +1151,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
|||
err = mmc_select_powerclass(card, ext_csd_bits[idx][0],
|
||||
ext_csd);
|
||||
if (err)
|
||||
pr_err("%s: power class selection to "
|
||||
"bus width %d failed\n",
|
||||
mmc_hostname(card->host),
|
||||
1 << bus_width);
|
||||
pr_warning("%s: power class selection to "
|
||||
"bus width %d failed\n",
|
||||
mmc_hostname(card->host),
|
||||
1 << bus_width);
|
||||
|
||||
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_BUS_WIDTH,
|
||||
|
@ -1178,10 +1182,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
|||
err = mmc_select_powerclass(card, ext_csd_bits[idx][1],
|
||||
ext_csd);
|
||||
if (err)
|
||||
pr_err("%s: power class selection to "
|
||||
"bus width %d ddr %d failed\n",
|
||||
mmc_hostname(card->host),
|
||||
1 << bus_width, ddr);
|
||||
pr_warning("%s: power class selection to "
|
||||
"bus width %d ddr %d failed\n",
|
||||
mmc_hostname(card->host),
|
||||
1 << bus_width, ddr);
|
||||
|
||||
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_BUS_WIDTH,
|
||||
|
|
|
@ -192,9 +192,15 @@ static int sdio_bus_remove(struct device *dev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static int pm_no_operation(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops sdio_bus_pm_ops = {
|
||||
SET_SYSTEM_SLEEP_PM_OPS(pm_no_operation, pm_no_operation)
|
||||
SET_RUNTIME_PM_OPS(
|
||||
pm_generic_runtime_suspend,
|
||||
pm_generic_runtime_resume,
|
||||
|
@ -204,11 +210,11 @@ static const struct dev_pm_ops sdio_bus_pm_ops = {
|
|||
|
||||
#define SDIO_PM_OPS_PTR (&sdio_bus_pm_ops)
|
||||
|
||||
#else /* !CONFIG_PM_RUNTIME */
|
||||
#else /* !CONFIG_PM */
|
||||
|
||||
#define SDIO_PM_OPS_PTR NULL
|
||||
|
||||
#endif /* !CONFIG_PM_RUNTIME */
|
||||
#endif /* !CONFIG_PM */
|
||||
|
||||
static struct bus_type sdio_bus_type = {
|
||||
.name = "sdio",
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
# define ATMCI_MR_PDCFBYTE ( 1 << 13) /* Force Byte Transfer */
|
||||
# define ATMCI_MR_PDCPADV ( 1 << 14) /* Padding Value */
|
||||
# define ATMCI_MR_PDCMODE ( 1 << 15) /* PDC-oriented Mode */
|
||||
# define ATMCI_MR_CLKODD(x) ((x) << 16) /* LSB of Clock Divider */
|
||||
#define ATMCI_DTOR 0x0008 /* Data Timeout */
|
||||
# define ATMCI_DTOCYC(x) ((x) << 0) /* Data Timeout Cycles */
|
||||
# define ATMCI_DTOMUL(x) ((x) << 4) /* Data Timeout Multiplier */
|
||||
|
|
|
@ -77,6 +77,7 @@ struct atmel_mci_caps {
|
|||
bool has_cstor_reg;
|
||||
bool has_highspeed;
|
||||
bool has_rwproof;
|
||||
bool has_odd_clk_div;
|
||||
};
|
||||
|
||||
struct atmel_mci_dma {
|
||||
|
@ -482,7 +483,14 @@ err:
|
|||
static inline unsigned int atmci_ns_to_clocks(struct atmel_mci *host,
|
||||
unsigned int ns)
|
||||
{
|
||||
return (ns * (host->bus_hz / 1000000) + 999) / 1000;
|
||||
/*
|
||||
* It is easier here to use us instead of ns for the timeout,
|
||||
* it prevents from overflows during calculation.
|
||||
*/
|
||||
unsigned int us = DIV_ROUND_UP(ns, 1000);
|
||||
|
||||
/* Maximum clock frequency is host->bus_hz/2 */
|
||||
return us * (DIV_ROUND_UP(host->bus_hz, 2000000));
|
||||
}
|
||||
|
||||
static void atmci_set_timeout(struct atmel_mci *host,
|
||||
|
@ -1127,16 +1135,27 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
|
|||
}
|
||||
|
||||
/* Calculate clock divider */
|
||||
clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * clock_min) - 1;
|
||||
if (clkdiv > 255) {
|
||||
dev_warn(&mmc->class_dev,
|
||||
"clock %u too slow; using %lu\n",
|
||||
clock_min, host->bus_hz / (2 * 256));
|
||||
clkdiv = 255;
|
||||
if (host->caps.has_odd_clk_div) {
|
||||
clkdiv = DIV_ROUND_UP(host->bus_hz, clock_min) - 2;
|
||||
if (clkdiv > 511) {
|
||||
dev_warn(&mmc->class_dev,
|
||||
"clock %u too slow; using %lu\n",
|
||||
clock_min, host->bus_hz / (511 + 2));
|
||||
clkdiv = 511;
|
||||
}
|
||||
host->mode_reg = ATMCI_MR_CLKDIV(clkdiv >> 1)
|
||||
| ATMCI_MR_CLKODD(clkdiv & 1);
|
||||
} else {
|
||||
clkdiv = DIV_ROUND_UP(host->bus_hz, 2 * clock_min) - 1;
|
||||
if (clkdiv > 255) {
|
||||
dev_warn(&mmc->class_dev,
|
||||
"clock %u too slow; using %lu\n",
|
||||
clock_min, host->bus_hz / (2 * 256));
|
||||
clkdiv = 255;
|
||||
}
|
||||
host->mode_reg = ATMCI_MR_CLKDIV(clkdiv);
|
||||
}
|
||||
|
||||
host->mode_reg = ATMCI_MR_CLKDIV(clkdiv);
|
||||
|
||||
/*
|
||||
* WRPROOF and RDPROOF prevent overruns/underruns by
|
||||
* stopping the clock when the FIFO is full/empty.
|
||||
|
@ -2007,35 +2026,35 @@ static void __init atmci_get_cap(struct atmel_mci *host)
|
|||
"version: 0x%x\n", version);
|
||||
|
||||
host->caps.has_dma = 0;
|
||||
host->caps.has_pdc = 0;
|
||||
host->caps.has_pdc = 1;
|
||||
host->caps.has_cfg_reg = 0;
|
||||
host->caps.has_cstor_reg = 0;
|
||||
host->caps.has_highspeed = 0;
|
||||
host->caps.has_rwproof = 0;
|
||||
host->caps.has_odd_clk_div = 0;
|
||||
|
||||
/* keep only major version number */
|
||||
switch (version & 0xf00) {
|
||||
case 0x100:
|
||||
case 0x200:
|
||||
host->caps.has_pdc = 1;
|
||||
host->caps.has_rwproof = 1;
|
||||
break;
|
||||
case 0x300:
|
||||
case 0x400:
|
||||
case 0x500:
|
||||
host->caps.has_odd_clk_div = 1;
|
||||
case 0x400:
|
||||
case 0x300:
|
||||
#ifdef CONFIG_AT_HDMAC
|
||||
host->caps.has_dma = 1;
|
||||
#else
|
||||
host->caps.has_dma = 0;
|
||||
dev_info(&host->pdev->dev,
|
||||
"has dma capability but dma engine is not selected, then use pio\n");
|
||||
#endif
|
||||
host->caps.has_pdc = 0;
|
||||
host->caps.has_cfg_reg = 1;
|
||||
host->caps.has_cstor_reg = 1;
|
||||
host->caps.has_highspeed = 1;
|
||||
case 0x200:
|
||||
host->caps.has_rwproof = 1;
|
||||
case 0x100:
|
||||
break;
|
||||
default:
|
||||
host->caps.has_pdc = 0;
|
||||
dev_warn(&host->pdev->dev,
|
||||
"Unmanaged mci version, set minimum capabilities\n");
|
||||
break;
|
||||
|
|
|
@ -1785,7 +1785,7 @@ static inline struct omap_mmc_platform_data
|
|||
}
|
||||
#endif
|
||||
|
||||
static int __init omap_hsmmc_probe(struct platform_device *pdev)
|
||||
static int __devinit omap_hsmmc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_mmc_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct mmc_host *mmc;
|
||||
|
@ -1818,8 +1818,6 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
|
|||
if (res == NULL || irq < 0)
|
||||
return -ENXIO;
|
||||
|
||||
res->start += pdata->reg_offset;
|
||||
res->end += pdata->reg_offset;
|
||||
res = request_mem_region(res->start, resource_size(res), pdev->name);
|
||||
if (res == NULL)
|
||||
return -EBUSY;
|
||||
|
@ -1843,7 +1841,7 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
|
|||
host->dma_ch = -1;
|
||||
host->irq = irq;
|
||||
host->slot_id = 0;
|
||||
host->mapbase = res->start;
|
||||
host->mapbase = res->start + pdata->reg_offset;
|
||||
host->base = ioremap(host->mapbase, SZ_4K);
|
||||
host->power_mode = MMC_POWER_OFF;
|
||||
host->next_data.cookie = 1;
|
||||
|
@ -1875,8 +1873,6 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
|
|||
goto err1;
|
||||
}
|
||||
|
||||
omap_hsmmc_context_save(host);
|
||||
|
||||
if (host->pdata->controller_flags & OMAP_HSMMC_BROKEN_MULTIBLOCK_READ) {
|
||||
dev_info(&pdev->dev, "multiblock reads disabled due to 35xx erratum 2.1.1.128; MMC read performance may suffer\n");
|
||||
mmc->caps2 |= MMC_CAP2_NO_MULTI_READ;
|
||||
|
@ -1887,6 +1883,8 @@ static int __init omap_hsmmc_probe(struct platform_device *pdev)
|
|||
pm_runtime_set_autosuspend_delay(host->dev, MMC_AUTOSUSPEND_DELAY);
|
||||
pm_runtime_use_autosuspend(host->dev);
|
||||
|
||||
omap_hsmmc_context_save(host);
|
||||
|
||||
if (cpu_is_omap2430()) {
|
||||
host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck");
|
||||
/*
|
||||
|
@ -2018,8 +2016,7 @@ err_reg:
|
|||
err_irq_cd_init:
|
||||
free_irq(host->irq, host);
|
||||
err_irq:
|
||||
pm_runtime_mark_last_busy(host->dev);
|
||||
pm_runtime_put_autosuspend(host->dev);
|
||||
pm_runtime_put_sync(host->dev);
|
||||
pm_runtime_disable(host->dev);
|
||||
clk_put(host->fclk);
|
||||
if (host->got_dbclk) {
|
||||
|
@ -2037,35 +2034,33 @@ err:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int omap_hsmmc_remove(struct platform_device *pdev)
|
||||
static int __devexit omap_hsmmc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct omap_hsmmc_host *host = platform_get_drvdata(pdev);
|
||||
struct resource *res;
|
||||
|
||||
if (host) {
|
||||
pm_runtime_get_sync(host->dev);
|
||||
mmc_remove_host(host->mmc);
|
||||
if (host->use_reg)
|
||||
omap_hsmmc_reg_put(host);
|
||||
if (host->pdata->cleanup)
|
||||
host->pdata->cleanup(&pdev->dev);
|
||||
free_irq(host->irq, host);
|
||||
if (mmc_slot(host).card_detect_irq)
|
||||
free_irq(mmc_slot(host).card_detect_irq, host);
|
||||
pm_runtime_get_sync(host->dev);
|
||||
mmc_remove_host(host->mmc);
|
||||
if (host->use_reg)
|
||||
omap_hsmmc_reg_put(host);
|
||||
if (host->pdata->cleanup)
|
||||
host->pdata->cleanup(&pdev->dev);
|
||||
free_irq(host->irq, host);
|
||||
if (mmc_slot(host).card_detect_irq)
|
||||
free_irq(mmc_slot(host).card_detect_irq, host);
|
||||
|
||||
pm_runtime_put_sync(host->dev);
|
||||
pm_runtime_disable(host->dev);
|
||||
clk_put(host->fclk);
|
||||
if (host->got_dbclk) {
|
||||
clk_disable(host->dbclk);
|
||||
clk_put(host->dbclk);
|
||||
}
|
||||
|
||||
mmc_free_host(host->mmc);
|
||||
iounmap(host->base);
|
||||
omap_hsmmc_gpio_free(pdev->dev.platform_data);
|
||||
pm_runtime_put_sync(host->dev);
|
||||
pm_runtime_disable(host->dev);
|
||||
clk_put(host->fclk);
|
||||
if (host->got_dbclk) {
|
||||
clk_disable(host->dbclk);
|
||||
clk_put(host->dbclk);
|
||||
}
|
||||
|
||||
mmc_free_host(host->mmc);
|
||||
iounmap(host->base);
|
||||
omap_hsmmc_gpio_free(pdev->dev.platform_data);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (res)
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
|
@ -2078,49 +2073,45 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
|
|||
static int omap_hsmmc_suspend(struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct omap_hsmmc_host *host = platform_get_drvdata(pdev);
|
||||
struct omap_hsmmc_host *host = dev_get_drvdata(dev);
|
||||
|
||||
if (!host)
|
||||
return 0;
|
||||
|
||||
if (host && host->suspended)
|
||||
return 0;
|
||||
|
||||
if (host) {
|
||||
pm_runtime_get_sync(host->dev);
|
||||
host->suspended = 1;
|
||||
if (host->pdata->suspend) {
|
||||
ret = host->pdata->suspend(&pdev->dev,
|
||||
host->slot_id);
|
||||
if (ret) {
|
||||
dev_dbg(mmc_dev(host->mmc),
|
||||
"Unable to handle MMC board"
|
||||
" level suspend\n");
|
||||
host->suspended = 0;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
ret = mmc_suspend_host(host->mmc);
|
||||
|
||||
pm_runtime_get_sync(host->dev);
|
||||
host->suspended = 1;
|
||||
if (host->pdata->suspend) {
|
||||
ret = host->pdata->suspend(dev, host->slot_id);
|
||||
if (ret) {
|
||||
dev_dbg(dev, "Unable to handle MMC board"
|
||||
" level suspend\n");
|
||||
host->suspended = 0;
|
||||
if (host->pdata->resume) {
|
||||
ret = host->pdata->resume(&pdev->dev,
|
||||
host->slot_id);
|
||||
if (ret)
|
||||
dev_dbg(mmc_dev(host->mmc),
|
||||
"Unmask interrupt failed\n");
|
||||
}
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) {
|
||||
omap_hsmmc_disable_irq(host);
|
||||
OMAP_HSMMC_WRITE(host->base, HCTL,
|
||||
OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP);
|
||||
}
|
||||
if (host->got_dbclk)
|
||||
clk_disable(host->dbclk);
|
||||
|
||||
}
|
||||
ret = mmc_suspend_host(host->mmc);
|
||||
|
||||
if (ret) {
|
||||
host->suspended = 0;
|
||||
if (host->pdata->resume) {
|
||||
ret = host->pdata->resume(dev, host->slot_id);
|
||||
if (ret)
|
||||
dev_dbg(dev, "Unmask interrupt failed\n");
|
||||
}
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER)) {
|
||||
omap_hsmmc_disable_irq(host);
|
||||
OMAP_HSMMC_WRITE(host->base, HCTL,
|
||||
OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP);
|
||||
}
|
||||
|
||||
if (host->got_dbclk)
|
||||
clk_disable(host->dbclk);
|
||||
err:
|
||||
pm_runtime_put_sync(host->dev);
|
||||
return ret;
|
||||
|
@ -2130,39 +2121,38 @@ err:
|
|||
static int omap_hsmmc_resume(struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct omap_hsmmc_host *host = platform_get_drvdata(pdev);
|
||||
struct omap_hsmmc_host *host = dev_get_drvdata(dev);
|
||||
|
||||
if (!host)
|
||||
return 0;
|
||||
|
||||
if (host && !host->suspended)
|
||||
return 0;
|
||||
|
||||
if (host) {
|
||||
pm_runtime_get_sync(host->dev);
|
||||
pm_runtime_get_sync(host->dev);
|
||||
|
||||
if (host->got_dbclk)
|
||||
clk_enable(host->dbclk);
|
||||
if (host->got_dbclk)
|
||||
clk_enable(host->dbclk);
|
||||
|
||||
if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER))
|
||||
omap_hsmmc_conf_bus_power(host);
|
||||
if (!(host->mmc->pm_flags & MMC_PM_KEEP_POWER))
|
||||
omap_hsmmc_conf_bus_power(host);
|
||||
|
||||
if (host->pdata->resume) {
|
||||
ret = host->pdata->resume(&pdev->dev, host->slot_id);
|
||||
if (ret)
|
||||
dev_dbg(mmc_dev(host->mmc),
|
||||
"Unmask interrupt failed\n");
|
||||
}
|
||||
|
||||
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_put_autosuspend(host->dev);
|
||||
if (host->pdata->resume) {
|
||||
ret = host->pdata->resume(dev, host->slot_id);
|
||||
if (ret)
|
||||
dev_dbg(dev, "Unmask interrupt failed\n");
|
||||
}
|
||||
|
||||
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_put_autosuspend(host->dev);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
@ -2178,7 +2168,7 @@ static int omap_hsmmc_runtime_suspend(struct device *dev)
|
|||
|
||||
host = platform_get_drvdata(to_platform_device(dev));
|
||||
omap_hsmmc_context_save(host);
|
||||
dev_dbg(mmc_dev(host->mmc), "disabled\n");
|
||||
dev_dbg(dev, "disabled\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2189,7 +2179,7 @@ static int omap_hsmmc_runtime_resume(struct device *dev)
|
|||
|
||||
host = platform_get_drvdata(to_platform_device(dev));
|
||||
omap_hsmmc_context_restore(host);
|
||||
dev_dbg(mmc_dev(host->mmc), "enabled\n");
|
||||
dev_dbg(dev, "enabled\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2202,7 +2192,8 @@ static struct dev_pm_ops omap_hsmmc_dev_pm_ops = {
|
|||
};
|
||||
|
||||
static struct platform_driver omap_hsmmc_driver = {
|
||||
.remove = omap_hsmmc_remove,
|
||||
.probe = omap_hsmmc_probe,
|
||||
.remove = __devexit_p(omap_hsmmc_remove),
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
|
@ -2211,21 +2202,7 @@ static struct platform_driver omap_hsmmc_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
static int __init omap_hsmmc_init(void)
|
||||
{
|
||||
/* Register the MMC driver */
|
||||
return platform_driver_probe(&omap_hsmmc_driver, omap_hsmmc_probe);
|
||||
}
|
||||
|
||||
static void __exit omap_hsmmc_cleanup(void)
|
||||
{
|
||||
/* Unregister MMC driver */
|
||||
platform_driver_unregister(&omap_hsmmc_driver);
|
||||
}
|
||||
|
||||
module_init(omap_hsmmc_init);
|
||||
module_exit(omap_hsmmc_cleanup);
|
||||
|
||||
module_platform_driver(omap_hsmmc_driver);
|
||||
MODULE_DESCRIPTION("OMAP High Speed Multimedia Card driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:" DRIVER_NAME);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mmc/host.h>
|
||||
|
||||
#include "sdhci-pltfm.h"
|
||||
|
|
|
@ -1418,8 +1418,6 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev,
|
|||
|
||||
slots = chip->num_slots; /* Quirk may have changed this */
|
||||
|
||||
pci_enable_msi(pdev);
|
||||
|
||||
for (i = 0; i < slots; i++) {
|
||||
slot = sdhci_pci_probe_slot(pdev, chip, first_bar, i);
|
||||
if (IS_ERR(slot)) {
|
||||
|
@ -1438,8 +1436,6 @@ static int __devinit sdhci_pci_probe(struct pci_dev *pdev,
|
|||
return 0;
|
||||
|
||||
free:
|
||||
pci_disable_msi(pdev);
|
||||
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
kfree(chip);
|
||||
|
||||
|
@ -1462,8 +1458,6 @@ static void __devexit sdhci_pci_remove(struct pci_dev *pdev)
|
|||
for (i = 0; i < chip->num_slots; i++)
|
||||
sdhci_pci_remove_slot(chip->slots[i]);
|
||||
|
||||
pci_disable_msi(pdev);
|
||||
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
kfree(chip);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,10 @@
|
|||
#include <linux/io.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include <linux/mmc/host.h>
|
||||
|
||||
|
@ -53,6 +57,18 @@ struct sdhci_s3c {
|
|||
struct clk *clk_bus[MAX_BUS_CLK];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct sdhci_s3c_driver_data - S3C SDHCI platform specific driver data
|
||||
* @sdhci_quirks: sdhci host specific quirks.
|
||||
*
|
||||
* Specifies platform specific configuration of sdhci controller.
|
||||
* Note: A structure for driver specific platform data is used for future
|
||||
* expansion of its usage.
|
||||
*/
|
||||
struct sdhci_s3c_drv_data {
|
||||
unsigned int sdhci_quirks;
|
||||
};
|
||||
|
||||
static inline struct sdhci_s3c *to_s3c(struct sdhci_host *host)
|
||||
{
|
||||
return sdhci_priv(host);
|
||||
|
@ -132,10 +148,10 @@ static unsigned int sdhci_s3c_consider_clock(struct sdhci_s3c *ourhost,
|
|||
return UINT_MAX;
|
||||
|
||||
/*
|
||||
* Clock divider's step is different as 1 from that of host controller
|
||||
* when 'clk_type' is S3C_SDHCI_CLK_DIV_EXTERNAL.
|
||||
* If controller uses a non-standard clock division, find the best clock
|
||||
* speed possible with selected clock source and skip the division.
|
||||
*/
|
||||
if (ourhost->pdata->clk_type) {
|
||||
if (ourhost->host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) {
|
||||
rate = clk_round_rate(clksrc, wanted);
|
||||
return wanted - rate;
|
||||
}
|
||||
|
@ -272,6 +288,8 @@ static unsigned int sdhci_cmu_get_min_clock(struct sdhci_host *host)
|
|||
static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
|
||||
{
|
||||
struct sdhci_s3c *ourhost = to_s3c(host);
|
||||
unsigned long timeout;
|
||||
u16 clk = 0;
|
||||
|
||||
/* don't bother if the clock is going off */
|
||||
if (clock == 0)
|
||||
|
@ -282,6 +300,25 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
|
|||
clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock);
|
||||
|
||||
host->clock = clock;
|
||||
|
||||
clk = SDHCI_CLOCK_INT_EN;
|
||||
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
|
||||
|
||||
/* Wait max 20 ms */
|
||||
timeout = 20;
|
||||
while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
|
||||
& SDHCI_CLOCK_INT_STABLE)) {
|
||||
if (timeout == 0) {
|
||||
printk(KERN_ERR "%s: Internal clock never "
|
||||
"stabilised.\n", mmc_hostname(host->mmc));
|
||||
return;
|
||||
}
|
||||
timeout--;
|
||||
mdelay(1);
|
||||
}
|
||||
|
||||
clk |= SDHCI_CLOCK_CARD_EN;
|
||||
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -382,16 +419,24 @@ static void sdhci_s3c_setup_card_detect_gpio(struct sdhci_s3c *sc)
|
|||
}
|
||||
}
|
||||
|
||||
static inline struct sdhci_s3c_drv_data *sdhci_s3c_get_driver_data(
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
return (struct sdhci_s3c_drv_data *)
|
||||
platform_get_device_id(pdev)->driver_data;
|
||||
}
|
||||
|
||||
static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct s3c_sdhci_platdata *pdata = pdev->dev.platform_data;
|
||||
struct s3c_sdhci_platdata *pdata;
|
||||
struct sdhci_s3c_drv_data *drv_data;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct sdhci_host *host;
|
||||
struct sdhci_s3c *sc;
|
||||
struct resource *res;
|
||||
int ret, irq, ptr, clks;
|
||||
|
||||
if (!pdata) {
|
||||
if (!pdev->dev.platform_data) {
|
||||
dev_err(dev, "no device data specified\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
@ -402,18 +447,20 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
|
|||
return irq;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(dev, "no memory specified\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
host = sdhci_alloc_host(dev, sizeof(struct sdhci_s3c));
|
||||
if (IS_ERR(host)) {
|
||||
dev_err(dev, "sdhci_alloc_host() failed\n");
|
||||
return PTR_ERR(host);
|
||||
}
|
||||
|
||||
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata) {
|
||||
ret = -ENOMEM;
|
||||
goto err_io_clk;
|
||||
}
|
||||
memcpy(pdata, pdev->dev.platform_data, sizeof(*pdata));
|
||||
|
||||
drv_data = sdhci_s3c_get_driver_data(pdev);
|
||||
sc = sdhci_priv(host);
|
||||
|
||||
sc->host = host;
|
||||
|
@ -464,15 +511,8 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
|
|||
goto err_no_busclks;
|
||||
}
|
||||
|
||||
sc->ioarea = request_mem_region(res->start, resource_size(res),
|
||||
mmc_hostname(host->mmc));
|
||||
if (!sc->ioarea) {
|
||||
dev_err(dev, "failed to reserve register area\n");
|
||||
ret = -ENXIO;
|
||||
goto err_req_regs;
|
||||
}
|
||||
|
||||
host->ioaddr = ioremap_nocache(res->start, resource_size(res));
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
host->ioaddr = devm_request_and_ioremap(&pdev->dev, res);
|
||||
if (!host->ioaddr) {
|
||||
dev_err(dev, "failed to map registers\n");
|
||||
ret = -ENXIO;
|
||||
|
@ -491,6 +531,8 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
|
|||
/* Setup quirks for the controller */
|
||||
host->quirks |= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC;
|
||||
host->quirks |= SDHCI_QUIRK_NO_HISPD_BIT;
|
||||
if (drv_data)
|
||||
host->quirks |= drv_data->sdhci_quirks;
|
||||
|
||||
#ifndef CONFIG_MMC_SDHCI_S3C_DMA
|
||||
|
||||
|
@ -518,6 +560,14 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
|
|||
if (pdata->cd_type == S3C_SDHCI_CD_PERMANENT)
|
||||
host->mmc->caps = MMC_CAP_NONREMOVABLE;
|
||||
|
||||
switch (pdata->max_width) {
|
||||
case 8:
|
||||
host->mmc->caps |= MMC_CAP_8_BIT_DATA;
|
||||
case 4:
|
||||
host->mmc->caps |= MMC_CAP_4_BIT_DATA;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pdata->pm_caps)
|
||||
host->mmc->pm_caps |= pdata->pm_caps;
|
||||
|
||||
|
@ -531,7 +581,7 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
|
|||
* If controller does not have internal clock divider,
|
||||
* we can use overriding functions instead of default.
|
||||
*/
|
||||
if (pdata->clk_type) {
|
||||
if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) {
|
||||
sdhci_s3c_ops.set_clock = sdhci_cmu_set_clock;
|
||||
sdhci_s3c_ops.get_min_clock = sdhci_cmu_get_min_clock;
|
||||
sdhci_s3c_ops.get_max_clock = sdhci_cmu_get_max_clock;
|
||||
|
@ -544,10 +594,17 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
|
|||
if (pdata->host_caps2)
|
||||
host->mmc->caps2 |= pdata->host_caps2;
|
||||
|
||||
pm_runtime_enable(&pdev->dev);
|
||||
pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
|
||||
pm_runtime_use_autosuspend(&pdev->dev);
|
||||
pm_suspend_ignore_children(&pdev->dev, 1);
|
||||
|
||||
ret = sdhci_add_host(host);
|
||||
if (ret) {
|
||||
dev_err(dev, "sdhci_add_host() failed\n");
|
||||
goto err_add_host;
|
||||
pm_runtime_forbid(&pdev->dev);
|
||||
pm_runtime_get_noresume(&pdev->dev);
|
||||
goto err_req_regs;
|
||||
}
|
||||
|
||||
/* The following two methods of card detection might call
|
||||
|
@ -561,10 +618,6 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev)
|
|||
|
||||
return 0;
|
||||
|
||||
err_add_host:
|
||||
release_resource(sc->ioarea);
|
||||
kfree(sc->ioarea);
|
||||
|
||||
err_req_regs:
|
||||
for (ptr = 0; ptr < MAX_BUS_CLK; ptr++) {
|
||||
if (sc->clk_bus[ptr]) {
|
||||
|
@ -601,6 +654,8 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev)
|
|||
|
||||
sdhci_remove_host(host, 1);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
for (ptr = 0; ptr < 3; ptr++) {
|
||||
if (sc->clk_bus[ptr]) {
|
||||
clk_disable(sc->clk_bus[ptr]);
|
||||
|
@ -610,18 +665,13 @@ static int __devexit sdhci_s3c_remove(struct platform_device *pdev)
|
|||
clk_disable(sc->clk_io);
|
||||
clk_put(sc->clk_io);
|
||||
|
||||
iounmap(host->ioaddr);
|
||||
release_resource(sc->ioarea);
|
||||
kfree(sc->ioarea);
|
||||
|
||||
sdhci_free_host(host);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int sdhci_s3c_suspend(struct device *dev)
|
||||
{
|
||||
struct sdhci_host *host = dev_get_drvdata(dev);
|
||||
|
@ -635,10 +685,29 @@ static int sdhci_s3c_resume(struct device *dev)
|
|||
|
||||
return sdhci_resume_host(host);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM_RUNTIME
|
||||
static int sdhci_s3c_runtime_suspend(struct device *dev)
|
||||
{
|
||||
struct sdhci_host *host = dev_get_drvdata(dev);
|
||||
|
||||
return sdhci_runtime_suspend_host(host);
|
||||
}
|
||||
|
||||
static int sdhci_s3c_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct sdhci_host *host = dev_get_drvdata(dev);
|
||||
|
||||
return sdhci_runtime_resume_host(host);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static const struct dev_pm_ops sdhci_s3c_pmops = {
|
||||
.suspend = sdhci_s3c_suspend,
|
||||
.resume = sdhci_s3c_resume,
|
||||
SET_SYSTEM_SLEEP_PM_OPS(sdhci_s3c_suspend, sdhci_s3c_resume)
|
||||
SET_RUNTIME_PM_OPS(sdhci_s3c_runtime_suspend, sdhci_s3c_runtime_resume,
|
||||
NULL)
|
||||
};
|
||||
|
||||
#define SDHCI_S3C_PMOPS (&sdhci_s3c_pmops)
|
||||
|
@ -647,9 +716,31 @@ static const struct dev_pm_ops sdhci_s3c_pmops = {
|
|||
#define SDHCI_S3C_PMOPS NULL
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_CPU_EXYNOS4210) || defined(CONFIG_SOC_EXYNOS4212)
|
||||
static struct sdhci_s3c_drv_data exynos4_sdhci_drv_data = {
|
||||
.sdhci_quirks = SDHCI_QUIRK_NONSTANDARD_CLOCK,
|
||||
};
|
||||
#define EXYNOS4_SDHCI_DRV_DATA ((kernel_ulong_t)&exynos4_sdhci_drv_data)
|
||||
#else
|
||||
#define EXYNOS4_SDHCI_DRV_DATA ((kernel_ulong_t)NULL)
|
||||
#endif
|
||||
|
||||
static struct platform_device_id sdhci_s3c_driver_ids[] = {
|
||||
{
|
||||
.name = "s3c-sdhci",
|
||||
.driver_data = (kernel_ulong_t)NULL,
|
||||
}, {
|
||||
.name = "exynos4-sdhci",
|
||||
.driver_data = EXYNOS4_SDHCI_DRV_DATA,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, sdhci_s3c_driver_ids);
|
||||
|
||||
static struct platform_driver sdhci_s3c_driver = {
|
||||
.probe = sdhci_s3c_probe,
|
||||
.remove = __devexit_p(sdhci_s3c_remove),
|
||||
.id_table = sdhci_s3c_driver_ids,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "s3c-sdhci",
|
||||
|
|
|
@ -2782,8 +2782,9 @@ int sdhci_add_host(struct sdhci_host *host)
|
|||
mmc_card_is_removable(mmc))
|
||||
mmc->caps |= MMC_CAP_NEEDS_POLL;
|
||||
|
||||
/* UHS-I mode(s) supported by the host controller. */
|
||||
if (host->version >= SDHCI_SPEC_300)
|
||||
/* Any UHS-I mode in caps implies SDR12 and SDR25 support. */
|
||||
if (caps[1] & (SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 |
|
||||
SDHCI_SUPPORT_DDR50))
|
||||
mmc->caps |= MMC_CAP_UHS_SDR12 | MMC_CAP_UHS_SDR25;
|
||||
|
||||
/* SDR104 supports also implies SDR50 support */
|
||||
|
|
|
@ -454,7 +454,8 @@ static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk)
|
|||
sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_SUP_PCLK);
|
||||
else
|
||||
sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR &
|
||||
((fls(host->clk / clk) - 1) << 16));
|
||||
((fls(DIV_ROUND_UP(host->clk,
|
||||
clk) - 1) - 1) << 16));
|
||||
|
||||
sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE);
|
||||
}
|
||||
|
@ -1297,14 +1298,8 @@ static int __devinit sh_mmcif_probe(struct platform_device *pdev)
|
|||
spin_lock_init(&host->lock);
|
||||
|
||||
mmc->ops = &sh_mmcif_ops;
|
||||
mmc->f_max = host->clk;
|
||||
/* close to 400KHz */
|
||||
if (mmc->f_max < 51200000)
|
||||
mmc->f_min = mmc->f_max / 128;
|
||||
else if (mmc->f_max < 102400000)
|
||||
mmc->f_min = mmc->f_max / 256;
|
||||
else
|
||||
mmc->f_min = mmc->f_max / 512;
|
||||
mmc->f_max = host->clk / 2;
|
||||
mmc->f_min = host->clk / 512;
|
||||
if (pd->ocr)
|
||||
mmc->ocr_avail = pd->ocr;
|
||||
mmc->caps = MMC_CAP_MMC_HIGHSPEED;
|
||||
|
|
Loading…
Reference in New Issue