MMC highlights for 3.16:

Core:
  - support HS400 mode of eMMC 5.0, via DT bindings mmc-hs400-1_{2,8}v
  - if card init at 3.3v doesn't work, try 1.8v and 1.2v too
 
 Drivers:
  - moxart: New driver for MOXA ART SoCs
  - rtsx_usb_sdmmc: New driver for Realtek USB card readers
  - sdhci: Large rework around IRQ/regulator handling, remove card_tasklet
  - sdhci-pci-o2micro: Add SeaBird SeaEagle SD3 support
  - sunxi: New driver for Allwinner sunxi SoCs
  - usdhi6rol0: New driver for Renesas SD/SDIO controller
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJTl199AAoJEHNBYZ7TNxYMutUQAIHOkbFeEmHiwhhM5snpywAg
 wRLIdiOWTYGrqRzvINDGsH4MVpt+acK5QuS5rNO5sEqhSovAZCNbQAvI4wXP60Uy
 bnXyqnq7uPHjQxUWu9ES1l3gvX1djLVCD0f5sqyG1nL4SA3h8CFbEKkGHEMEXpWY
 tOwUGxrM6IHk1Z7l1FzWiN4nidvsX9maKDiCEyCF86xMEyqsxd/gz5pjhF3GgZBY
 z174+XU7Vlb5HkpeH/anhSVfYALURlRNNdtJaMQoR1Goldhr/KfnaqkuQNLanqOS
 R1BselxeZxFUcSGJ87WrLE7jFa9i9qUzMdxJRrzssNCA7JZl1hOwTE4EAFCxMADZ
 fbZl/kwoQo/nO6HHQtJ3J+UeinA9aFGUR0jpN8l9jZkwb9VsyYenrd27+OcUcJGP
 ZyQ636oT+mB44RwHBz2mZVLLTrV84x9d4VVqjZ3QrMYNWVhXyIyjFSinoJvcNGOk
 xQ4zsAsyPXHzr6pR6diKab8tLYC+VoeWKdmqPDQtPY+L+D23qQNAarvS1oPjsgx8
 IZIIdh4ikftsXALriU2OqVi3zIw+mVTDlq7xp3gSI/Zf4Srlx+6V0X7KVUVoMB0h
 O19+HgKJv6pCoL54+FgFDdKcgdUANWG2s/BSmhRNgFJY97/tvahHlyoTmrVhXqil
 L/nmuknP3lB4RTQ7E5Kk
 =OZao
 -----END PGP SIGNATURE-----

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

Pull MMC update from Chris Ball:
 "MMC highlights for 3.16:

  Core:
   - support HS400 mode of eMMC 5.0, via DT bindings mmc-hs400-1_{2,8}v
   - if card init at 3.3v doesn't work, try 1.8v and 1.2v too

  Drivers:
   - moxart: New driver for MOXA ART SoCs
   - rtsx_usb_sdmmc: New driver for Realtek USB card readers
   - sdhci: Large rework around IRQ/regulator handling, remove card_tasklet
   - sdhci-pci-o2micro: Add SeaBird SeaEagle SD3 support
   - sunxi: New driver for Allwinner sunxi SoCs
   - usdhi6rol0: New driver for Renesas SD/SDIO controller"

* tag 'mmc-updates-for-3.16-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc: (95 commits)
  mmc: sdhci-s3c: use mmc_of_parse and remove the card_tasklet
  mmc: add a driver for the Renesas usdhi6rol0 SD/SDIO host controller
  mmc: sdhci-of-esdhc: Fixup compile error
  mmc: tegra: fix reporting of base clock frequency
  mmc: tegra: disable UHS modes
  mmc: sdhci-dove: use mmc_of_parse() and remove card_tasklet CD handler
  MAINTAINERS: mmc: Add path to git tree
  mmc: dove: fix missing MACH_DOVE dependency
  mmc: sdhci: SD tuning is broken for some controllers
  mmc: sdhci-esdhc-imx: fix mmc ddr mode regression issue
  mmc: sdhci-pci-o2micro: Add SeaBird SeaEagle SD3 support
  mmc: omap_hsmmc: split omap-dma header file
  mmc: omap_hsmmc: fix cmd23 multiblock read/write
  mmc: omap_hsmmc: use devm_ioremap_resource
  mmc: omap_hsmmc: use devm_request_threaded_irq
  mmc: omap_hsmmc: use devm_request_irq
  mmc: omap_hsmmc: use devm_clk_get
  mmc: sunxi: Add driver for SD/MMC hosts found on Allwinner sunxi SoCs
  mmc: wmt-sdmmc: Use GFP_KERNEL instead of hard-coded value
  mmc: omap: Use DIV_ROUND_UP instead of open coded
  ...
This commit is contained in:
Linus Torvalds 2014-06-10 14:35:22 -07:00
commit 07888238f5
65 changed files with 4110 additions and 1495 deletions

View file

@ -38,6 +38,8 @@ Optional properties:
- mmc-highspeed-ddr-1_2v: eMMC high-speed DDR mode(1.2V I/O) is supported - mmc-highspeed-ddr-1_2v: eMMC high-speed DDR mode(1.2V I/O) is supported
- mmc-hs200-1_8v: eMMC HS200 mode(1.8V I/O) is supported - mmc-hs200-1_8v: eMMC HS200 mode(1.8V I/O) is supported
- mmc-hs200-1_2v: eMMC HS200 mode(1.2V I/O) is supported - mmc-hs200-1_2v: eMMC HS200 mode(1.2V I/O) is supported
- mmc-hs400-1_8v: eMMC HS400 mode(1.8V I/O) is supported
- mmc-hs400-1_2v: eMMC HS400 mode(1.2V I/O) is supported
*NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line *NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line
polarity properties, we have to fix the meaning of the "normal" and "inverted" polarity properties, we have to fix the meaning of the "normal" and "inverted"

View file

@ -0,0 +1,30 @@
MOXA ART MMC Host Controller Interface
Inherits from mmc binding[1].
[1] Documentation/devicetree/bindings/mmc/mmc.txt
Required properties:
- compatible : Must be "moxa,moxart-mmc" or "faraday,ftsdc010"
- reg : Should contain registers location and length
- interrupts : Should contain the interrupt number
- clocks : Should contain phandle for the clock feeding the MMC controller
Optional properties:
- dmas : Should contain two DMA channels, line request number must be 5 for
both channels
- dma-names : Must be "tx", "rx"
Example:
mmc: mmc@98e00000 {
compatible = "moxa,moxart-mmc";
reg = <0x98e00000 0x5C>;
interrupts = <5 0>;
clocks = <&clk_apb>;
dmas = <&dma 5>,
<&dma 5>;
dma-names = "tx", "rx";
};

View file

@ -69,10 +69,6 @@ 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
@ -103,7 +99,6 @@ board specific portions as listed below.
clock-freq-min-max = <400000 200000000>; 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>;

View file

@ -0,0 +1,33 @@
* Renesas usdhi6rol0 SD/SDIO host controller
Required properties:
- compatible: must be
"renesas,usdhi6rol0"
- interrupts: 3 interrupts, named "card detect", "data" and "SDIO" must be
specified
- clocks: a clock binding for the IMCLK input
Optional properties:
- vmmc-supply: a phandle of a regulator, supplying Vcc to the card
- vqmmc-supply: a phandle of a regulator, supplying VccQ to the card
Additionally any standard mmc bindings from mmc.txt can be used.
Example:
sd0: sd@ab000000 {
compatible = "renesas,usdhi6rol0";
reg = <0xab000000 0x200>;
interrupts = <0 23 0x4
0 24 0x4
0 25 0x4>;
interrupt-names = "card detect", "data", "SDIO";
bus-width = <4>;
max-frequency = <50000000>;
cap-power-off-card;
clocks = <&imclk>;
vmmc-supply = <&vcc_sd0>;
vqmmc-supply = <&vccq_sd0>;
};

View file

@ -5974,6 +5974,7 @@ M: Chris Ball <chris@printf.net>
M: Ulf Hansson <ulf.hansson@linaro.org> M: Ulf Hansson <ulf.hansson@linaro.org>
L: linux-mmc@vger.kernel.org L: linux-mmc@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc.git
T: git git://git.linaro.org/people/ulf.hansson/mmc.git
S: Maintained S: Maintained
F: drivers/mmc/ F: drivers/mmc/
F: include/linux/mmc/ F: include/linux/mmc/
@ -9103,7 +9104,7 @@ F: include/linux/toshiba.h
F: include/uapi/linux/toshiba.h F: include/uapi/linux/toshiba.h
TMIO MMC DRIVER TMIO MMC DRIVER
M: Ian Molton <ian@mnementh.co.uk> M: Ian Molton <ian.molton@codethink.co.uk>
L: linux-mmc@vger.kernel.org L: linux-mmc@vger.kernel.org
S: Maintained S: Maintained
F: drivers/mmc/host/tmio_mmc* F: drivers/mmc/host/tmio_mmc*

View file

@ -341,16 +341,17 @@ int mmc_add_card(struct mmc_card *card)
if (mmc_host_is_spi(card->host)) { if (mmc_host_is_spi(card->host)) {
pr_info("%s: new %s%s%s card on SPI\n", pr_info("%s: new %s%s%s card on SPI\n",
mmc_hostname(card->host), mmc_hostname(card->host),
mmc_card_highspeed(card) ? "high speed " : "", mmc_card_hs(card) ? "high speed " : "",
mmc_card_ddr_mode(card) ? "DDR " : "", mmc_card_ddr52(card) ? "DDR " : "",
type); type);
} else { } else {
pr_info("%s: new %s%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_hostname(card->host),
mmc_card_uhs(card) ? "ultra high speed " : mmc_card_uhs(card) ? "ultra high speed " :
(mmc_card_highspeed(card) ? "high speed " : ""), (mmc_card_hs(card) ? "high speed " : ""),
mmc_card_hs400(card) ? "HS400 " :
(mmc_card_hs200(card) ? "HS200 " : ""), (mmc_card_hs200(card) ? "HS200 " : ""),
mmc_card_ddr_mode(card) ? "DDR " : "", mmc_card_ddr52(card) ? "DDR " : "",
uhs_bus_speed_mode, type, card->rca); uhs_bus_speed_mode, type, card->rca);
} }

View file

@ -800,6 +800,10 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card)
data->timeout_ns = limit_us * 1000; data->timeout_ns = limit_us * 1000;
data->timeout_clks = 0; data->timeout_clks = 0;
} }
/* assign limit value if invalid */
if (timeout_us == 0)
data->timeout_ns = limit_us * 1000;
} }
/* /*
@ -1310,31 +1314,38 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc,
} }
EXPORT_SYMBOL_GPL(mmc_regulator_set_ocr); EXPORT_SYMBOL_GPL(mmc_regulator_set_ocr);
#endif /* CONFIG_REGULATOR */
int mmc_regulator_get_supply(struct mmc_host *mmc) int mmc_regulator_get_supply(struct mmc_host *mmc)
{ {
struct device *dev = mmc_dev(mmc); struct device *dev = mmc_dev(mmc);
struct regulator *supply;
int ret; int ret;
supply = devm_regulator_get(dev, "vmmc"); mmc->supply.vmmc = devm_regulator_get_optional(dev, "vmmc");
mmc->supply.vmmc = supply;
mmc->supply.vqmmc = devm_regulator_get_optional(dev, "vqmmc"); mmc->supply.vqmmc = devm_regulator_get_optional(dev, "vqmmc");
if (IS_ERR(supply)) if (IS_ERR(mmc->supply.vmmc)) {
return PTR_ERR(supply); if (PTR_ERR(mmc->supply.vmmc) == -EPROBE_DEFER)
return -EPROBE_DEFER;
dev_info(dev, "No vmmc regulator found\n");
} else {
ret = mmc_regulator_get_ocrmask(mmc->supply.vmmc);
if (ret > 0)
mmc->ocr_avail = ret;
else
dev_warn(dev, "Failed getting OCR mask: %d\n", ret);
}
ret = mmc_regulator_get_ocrmask(supply); if (IS_ERR(mmc->supply.vqmmc)) {
if (ret > 0) if (PTR_ERR(mmc->supply.vqmmc) == -EPROBE_DEFER)
mmc->ocr_avail = ret; return -EPROBE_DEFER;
else dev_info(dev, "No vqmmc regulator found\n");
dev_warn(mmc_dev(mmc), "Failed getting OCR mask: %d\n", ret); }
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(mmc_regulator_get_supply); EXPORT_SYMBOL_GPL(mmc_regulator_get_supply);
#endif /* CONFIG_REGULATOR */
/* /*
* Mask off any voltages we don't support and select * Mask off any voltages we don't support and select
* the lowest voltage * the lowest voltage
@ -1533,8 +1544,13 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
host->ios.timing = MMC_TIMING_LEGACY; host->ios.timing = MMC_TIMING_LEGACY;
mmc_set_ios(host); mmc_set_ios(host);
/* Set signal voltage to 3.3V */ /* Try to set signal voltage to 3.3V but fall back to 1.8v or 1.2v */
__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330); if (__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330) == 0)
dev_dbg(mmc_dev(host), "Initial signal voltage of 3.3v\n");
else if (__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180) == 0)
dev_dbg(mmc_dev(host), "Initial signal voltage of 1.8v\n");
else if (__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120) == 0)
dev_dbg(mmc_dev(host), "Initial signal voltage of 1.2v\n");
/* /*
* This delay should be sufficient to allow the power supply * This delay should be sufficient to allow the power supply
@ -2183,7 +2199,7 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
{ {
struct mmc_command cmd = {0}; struct mmc_command cmd = {0};
if (mmc_card_blockaddr(card) || mmc_card_ddr_mode(card)) if (mmc_card_blockaddr(card) || mmc_card_ddr52(card))
return 0; return 0;
cmd.opcode = MMC_SET_BLOCKLEN; cmd.opcode = MMC_SET_BLOCKLEN;
@ -2263,7 +2279,6 @@ static int mmc_do_hw_reset(struct mmc_host *host, int check)
} }
} }
host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_DDR);
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;
host->ios.bus_mode = MMC_BUSMODE_PUSHPULL; host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
@ -2403,6 +2418,11 @@ void mmc_rescan(struct work_struct *work)
container_of(work, struct mmc_host, detect.work); container_of(work, struct mmc_host, detect.work);
int i; int i;
if (host->trigger_card_event && host->ops->card_event) {
host->ops->card_event(host);
host->trigger_card_event = false;
}
if (host->rescan_disable) if (host->rescan_disable)
return; return;

View file

@ -135,8 +135,14 @@ static int mmc_ios_show(struct seq_file *s, void *data)
case MMC_TIMING_UHS_DDR50: case MMC_TIMING_UHS_DDR50:
str = "sd uhs DDR50"; str = "sd uhs DDR50";
break; break;
case MMC_TIMING_MMC_DDR52:
str = "mmc DDR52";
break;
case MMC_TIMING_MMC_HS200: case MMC_TIMING_MMC_HS200:
str = "mmc high-speed SDR200"; str = "mmc HS200";
break;
case MMC_TIMING_MMC_HS400:
str = "mmc HS400";
break; break;
default: default:
str = "invalid"; str = "invalid";

View file

@ -447,6 +447,10 @@ int mmc_of_parse(struct mmc_host *host)
host->caps2 |= MMC_CAP2_HS200_1_8V_SDR; host->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
if (of_find_property(np, "mmc-hs200-1_2v", &len)) if (of_find_property(np, "mmc-hs200-1_2v", &len))
host->caps2 |= MMC_CAP2_HS200_1_2V_SDR; host->caps2 |= MMC_CAP2_HS200_1_2V_SDR;
if (of_find_property(np, "mmc-hs400-1_8v", &len))
host->caps2 |= MMC_CAP2_HS400_1_8V | MMC_CAP2_HS200_1_8V_SDR;
if (of_find_property(np, "mmc-hs400-1_2v", &len))
host->caps2 |= MMC_CAP2_HS400_1_2V | MMC_CAP2_HS200_1_2V_SDR;
return 0; return 0;

View file

@ -240,31 +240,62 @@ static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
static void mmc_select_card_type(struct mmc_card *card) static void mmc_select_card_type(struct mmc_card *card)
{ {
struct mmc_host *host = card->host; struct mmc_host *host = card->host;
u8 card_type = card->ext_csd.raw_card_type & EXT_CSD_CARD_TYPE_MASK; u8 card_type = card->ext_csd.raw_card_type;
u32 caps = host->caps, caps2 = host->caps2; u32 caps = host->caps, caps2 = host->caps2;
unsigned int hs_max_dtr = 0; unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
unsigned int avail_type = 0;
if (card_type & EXT_CSD_CARD_TYPE_26)
hs_max_dtr = MMC_HIGH_26_MAX_DTR;
if (caps & MMC_CAP_MMC_HIGHSPEED && if (caps & MMC_CAP_MMC_HIGHSPEED &&
card_type & EXT_CSD_CARD_TYPE_52) card_type & EXT_CSD_CARD_TYPE_HS_26) {
hs_max_dtr = MMC_HIGH_26_MAX_DTR;
avail_type |= EXT_CSD_CARD_TYPE_HS_26;
}
if (caps & MMC_CAP_MMC_HIGHSPEED &&
card_type & EXT_CSD_CARD_TYPE_HS_52) {
hs_max_dtr = MMC_HIGH_52_MAX_DTR; hs_max_dtr = MMC_HIGH_52_MAX_DTR;
avail_type |= EXT_CSD_CARD_TYPE_HS_52;
}
if ((caps & MMC_CAP_1_8V_DDR && if (caps & MMC_CAP_1_8V_DDR &&
card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) || card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) {
(caps & MMC_CAP_1_2V_DDR &&
card_type & EXT_CSD_CARD_TYPE_DDR_1_2V))
hs_max_dtr = MMC_HIGH_DDR_MAX_DTR; hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
}
if ((caps2 & MMC_CAP2_HS200_1_8V_SDR && if (caps & MMC_CAP_1_2V_DDR &&
card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) || card_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
(caps2 & MMC_CAP2_HS200_1_2V_SDR && hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
card_type & EXT_CSD_CARD_TYPE_SDR_1_2V)) avail_type |= EXT_CSD_CARD_TYPE_DDR_1_2V;
hs_max_dtr = MMC_HS200_MAX_DTR; }
if (caps2 & MMC_CAP2_HS200_1_8V_SDR &&
card_type & EXT_CSD_CARD_TYPE_HS200_1_8V) {
hs200_max_dtr = MMC_HS200_MAX_DTR;
avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
}
if (caps2 & MMC_CAP2_HS200_1_2V_SDR &&
card_type & EXT_CSD_CARD_TYPE_HS200_1_2V) {
hs200_max_dtr = MMC_HS200_MAX_DTR;
avail_type |= EXT_CSD_CARD_TYPE_HS200_1_2V;
}
if (caps2 & MMC_CAP2_HS400_1_8V &&
card_type & EXT_CSD_CARD_TYPE_HS400_1_8V) {
hs200_max_dtr = MMC_HS200_MAX_DTR;
avail_type |= EXT_CSD_CARD_TYPE_HS400_1_8V;
}
if (caps2 & MMC_CAP2_HS400_1_2V &&
card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) {
hs200_max_dtr = MMC_HS200_MAX_DTR;
avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
}
card->ext_csd.hs_max_dtr = hs_max_dtr; card->ext_csd.hs_max_dtr = hs_max_dtr;
card->ext_csd.card_type = card_type; card->ext_csd.hs200_max_dtr = hs200_max_dtr;
card->mmc_avail_type = avail_type;
} }
/* /*
@ -480,6 +511,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
ext_csd[EXT_CSD_PWR_CL_DDR_52_195]; ext_csd[EXT_CSD_PWR_CL_DDR_52_195];
card->ext_csd.raw_pwr_cl_ddr_52_360 = card->ext_csd.raw_pwr_cl_ddr_52_360 =
ext_csd[EXT_CSD_PWR_CL_DDR_52_360]; ext_csd[EXT_CSD_PWR_CL_DDR_52_360];
card->ext_csd.raw_pwr_cl_ddr_200_360 =
ext_csd[EXT_CSD_PWR_CL_DDR_200_360];
} }
if (card->ext_csd.rev >= 5) { if (card->ext_csd.rev >= 5) {
@ -646,7 +679,10 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
(card->ext_csd.raw_pwr_cl_ddr_52_195 == (card->ext_csd.raw_pwr_cl_ddr_52_195 ==
bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) && bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
(card->ext_csd.raw_pwr_cl_ddr_52_360 == (card->ext_csd.raw_pwr_cl_ddr_52_360 ==
bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360])); bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]) &&
(card->ext_csd.raw_pwr_cl_ddr_200_360 ==
bw_ext_csd[EXT_CSD_PWR_CL_DDR_200_360]));
if (err) if (err)
err = -EINVAL; err = -EINVAL;
@ -694,18 +730,10 @@ static struct attribute *mmc_std_attrs[] = {
&dev_attr_rel_sectors.attr, &dev_attr_rel_sectors.attr,
NULL, NULL,
}; };
ATTRIBUTE_GROUPS(mmc_std);
static struct attribute_group mmc_std_attr_group = {
.attrs = mmc_std_attrs,
};
static const struct attribute_group *mmc_attr_groups[] = {
&mmc_std_attr_group,
NULL,
};
static struct device_type mmc_type = { static struct device_type mmc_type = {
.groups = mmc_attr_groups, .groups = mmc_std_groups,
}; };
/* /*
@ -714,17 +742,13 @@ static struct device_type mmc_type = {
* extended CSD register, select it by executing the * extended CSD register, select it by executing the
* mmc_switch command. * mmc_switch command.
*/ */
static int mmc_select_powerclass(struct mmc_card *card, static int __mmc_select_powerclass(struct mmc_card *card,
unsigned int bus_width) unsigned int bus_width)
{ {
int err = 0; struct mmc_host *host = card->host;
struct mmc_ext_csd *ext_csd = &card->ext_csd;
unsigned int pwrclass_val = 0; unsigned int pwrclass_val = 0;
struct mmc_host *host; int err = 0;
BUG_ON(!card);
host = card->host;
BUG_ON(!host);
/* Power class selection is supported for versions >= 4.0 */ /* Power class selection is supported for versions >= 4.0 */
if (card->csd.mmca_vsn < CSD_SPEC_VER_4) if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
@ -736,14 +760,14 @@ static int mmc_select_powerclass(struct mmc_card *card,
switch (1 << host->ios.vdd) { switch (1 << host->ios.vdd) {
case MMC_VDD_165_195: case MMC_VDD_165_195:
if (host->ios.clock <= 26000000) if (host->ios.clock <= MMC_HIGH_26_MAX_DTR)
pwrclass_val = card->ext_csd.raw_pwr_cl_26_195; pwrclass_val = ext_csd->raw_pwr_cl_26_195;
else if (host->ios.clock <= 52000000) else if (host->ios.clock <= MMC_HIGH_52_MAX_DTR)
pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ? pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
card->ext_csd.raw_pwr_cl_52_195 : ext_csd->raw_pwr_cl_52_195 :
card->ext_csd.raw_pwr_cl_ddr_52_195; ext_csd->raw_pwr_cl_ddr_52_195;
else if (host->ios.clock <= 200000000) else if (host->ios.clock <= MMC_HS200_MAX_DTR)
pwrclass_val = card->ext_csd.raw_pwr_cl_200_195; pwrclass_val = ext_csd->raw_pwr_cl_200_195;
break; break;
case MMC_VDD_27_28: case MMC_VDD_27_28:
case MMC_VDD_28_29: case MMC_VDD_28_29:
@ -754,14 +778,16 @@ static int mmc_select_powerclass(struct mmc_card *card,
case MMC_VDD_33_34: case MMC_VDD_33_34:
case MMC_VDD_34_35: case MMC_VDD_34_35:
case MMC_VDD_35_36: case MMC_VDD_35_36:
if (host->ios.clock <= 26000000) if (host->ios.clock <= MMC_HIGH_26_MAX_DTR)
pwrclass_val = card->ext_csd.raw_pwr_cl_26_360; pwrclass_val = ext_csd->raw_pwr_cl_26_360;
else if (host->ios.clock <= 52000000) else if (host->ios.clock <= MMC_HIGH_52_MAX_DTR)
pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ? pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
card->ext_csd.raw_pwr_cl_52_360 : ext_csd->raw_pwr_cl_52_360 :
card->ext_csd.raw_pwr_cl_ddr_52_360; ext_csd->raw_pwr_cl_ddr_52_360;
else if (host->ios.clock <= 200000000) else if (host->ios.clock <= MMC_HS200_MAX_DTR)
pwrclass_val = card->ext_csd.raw_pwr_cl_200_360; pwrclass_val = (bus_width == EXT_CSD_DDR_BUS_WIDTH_8) ?
ext_csd->raw_pwr_cl_ddr_200_360 :
ext_csd->raw_pwr_cl_200_360;
break; break;
default: default:
pr_warning("%s: Voltage range not supported " pr_warning("%s: Voltage range not supported "
@ -787,40 +813,79 @@ static int mmc_select_powerclass(struct mmc_card *card,
return err; return err;
} }
/* static int mmc_select_powerclass(struct mmc_card *card)
* Selects the desired buswidth and switch to the HS200 mode {
* if bus width set without error struct mmc_host *host = card->host;
*/ u32 bus_width, ext_csd_bits;
static int mmc_select_hs200(struct mmc_card *card) int err, ddr;
/* Power class selection is supported for versions >= 4.0 */
if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
return 0;
bus_width = host->ios.bus_width;
/* Power class values are defined only for 4/8 bit bus */
if (bus_width == MMC_BUS_WIDTH_1)
return 0;
ddr = card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52;
if (ddr)
ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
else
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);
if (err)
pr_warn("%s: power class selection to bus width %d ddr %d failed\n",
mmc_hostname(host), 1 << bus_width, ddr);
return err;
}
/*
* Set the bus speed for the selected speed mode.
*/
static void mmc_set_bus_speed(struct mmc_card *card)
{
unsigned int max_dtr = (unsigned int)-1;
if ((mmc_card_hs200(card) || mmc_card_hs400(card)) &&
max_dtr > card->ext_csd.hs200_max_dtr)
max_dtr = card->ext_csd.hs200_max_dtr;
else if (mmc_card_hs(card) && max_dtr > card->ext_csd.hs_max_dtr)
max_dtr = card->ext_csd.hs_max_dtr;
else if (max_dtr > card->csd.max_dtr)
max_dtr = card->csd.max_dtr;
mmc_set_clock(card->host, max_dtr);
}
/*
* Select the bus width amoung 4-bit and 8-bit(SDR).
* If the bus width is changed successfully, return the selected width value.
* Zero is returned instead of error value if the wide width is not supported.
*/
static int mmc_select_bus_width(struct mmc_card *card)
{ {
int idx, err = -EINVAL;
struct mmc_host *host;
static unsigned ext_csd_bits[] = { static unsigned ext_csd_bits[] = {
EXT_CSD_BUS_WIDTH_4,
EXT_CSD_BUS_WIDTH_8, EXT_CSD_BUS_WIDTH_8,
EXT_CSD_BUS_WIDTH_4,
}; };
static unsigned bus_widths[] = { static unsigned bus_widths[] = {
MMC_BUS_WIDTH_4,
MMC_BUS_WIDTH_8, MMC_BUS_WIDTH_8,
MMC_BUS_WIDTH_4,
}; };
struct mmc_host *host = card->host;
unsigned idx, bus_width = 0;
int err = 0;
BUG_ON(!card); if ((card->csd.mmca_vsn < CSD_SPEC_VER_4) &&
!(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)))
return 0;
host = card->host; idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 0 : 1;
if (card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_2V &&
host->caps2 & MMC_CAP2_HS200_1_2V_SDR)
err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
if (err && card->ext_csd.card_type & EXT_CSD_CARD_TYPE_SDR_1_8V &&
host->caps2 & MMC_CAP2_HS200_1_8V_SDR)
err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
/* If fails try again during next card power cycle */
if (err)
goto err;
idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 1 : 0;
/* /*
* Unlike SD, MMC cards dont have a configuration register to notify * Unlike SD, MMC cards dont have a configuration register to notify
@ -828,8 +893,7 @@ static int mmc_select_hs200(struct mmc_card *card)
* the supported bus width or compare the ext csd values of current * the supported bus width or compare the ext csd values of current
* bus width and ext csd values of 1 bit mode read earlier. * bus width and ext csd values of 1 bit mode read earlier.
*/ */
for (; idx >= 0; idx--) { for (; idx < ARRAY_SIZE(bus_widths); idx++) {
/* /*
* Host is capable of 8bit transfer, then switch * Host is capable of 8bit transfer, then switch
* the device to work in 8bit transfer mode. If the * the device to work in 8bit transfer mode. If the
@ -844,26 +908,265 @@ static int mmc_select_hs200(struct mmc_card *card)
if (err) if (err)
continue; continue;
mmc_set_bus_width(card->host, bus_widths[idx]); bus_width = bus_widths[idx];
mmc_set_bus_width(host, bus_width);
/*
* If controller can't handle bus width test,
* compare ext_csd previously read in 1 bit mode
* against ext_csd at new bus width
*/
if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST)) if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
err = mmc_compare_ext_csds(card, bus_widths[idx]); err = mmc_compare_ext_csds(card, bus_width);
else else
err = mmc_bus_test(card, bus_widths[idx]); err = mmc_bus_test(card, bus_width);
if (!err)
if (!err) {
err = bus_width;
break; break;
} else {
pr_warn("%s: switch to bus width %d failed\n",
mmc_hostname(host), ext_csd_bits[idx]);
}
} }
/* switch to HS200 mode if bus width set successfully */ return err;
}
/*
* Switch to the high-speed mode
*/
static int mmc_select_hs(struct mmc_card *card)
{
int err;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
card->ext_csd.generic_cmd6_time,
true, true, true);
if (!err) if (!err)
mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
return err;
}
/*
* Activate wide bus and DDR if supported.
*/
static int mmc_select_hs_ddr(struct mmc_card *card)
{
struct mmc_host *host = card->host;
u32 bus_width, ext_csd_bits;
int err = 0;
if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_52))
return 0;
bus_width = host->ios.bus_width;
if (bus_width == MMC_BUS_WIDTH_1)
return 0;
ext_csd_bits = (bus_width == MMC_BUS_WIDTH_8) ?
EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH,
ext_csd_bits,
card->ext_csd.generic_cmd6_time);
if (err) {
pr_warn("%s: switch to bus width %d ddr failed\n",
mmc_hostname(host), 1 << bus_width);
return err;
}
/*
* eMMC cards can support 3.3V to 1.2V i/o (vccq)
* signaling.
*
* EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
*
* 1.8V vccq at 3.3V core voltage (vcc) is not required
* in the JEDEC spec for DDR.
*
* Do not force change in vccq since we are obviously
* working and no change to vccq is needed.
*
* WARNING: eMMC rules are NOT the same as SD DDR
*/
if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
err = __mmc_set_signal_voltage(host,
MMC_SIGNAL_VOLTAGE_120);
if (err)
return err;
}
mmc_set_timing(host, MMC_TIMING_MMC_DDR52);
return err;
}
static int mmc_select_hs400(struct mmc_card *card)
{
struct mmc_host *host = card->host;
int err = 0;
/*
* HS400 mode requires 8-bit bus width
*/
if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
host->ios.bus_width == MMC_BUS_WIDTH_8))
return 0;
/*
* Before switching to dual data rate operation for HS400,
* it is required to convert from HS200 mode to HS mode.
*/
mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
mmc_set_bus_speed(card);
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
card->ext_csd.generic_cmd6_time,
true, true, true);
if (err) {
pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
mmc_hostname(host), err);
return err;
}
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH,
EXT_CSD_DDR_BUS_WIDTH_8,
card->ext_csd.generic_cmd6_time);
if (err) {
pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
mmc_hostname(host), err);
return err;
}
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400,
card->ext_csd.generic_cmd6_time,
true, true, true);
if (err) {
pr_warn("%s: switch to hs400 failed, err:%d\n",
mmc_hostname(host), err);
return err;
}
mmc_set_timing(host, MMC_TIMING_MMC_HS400);
mmc_set_bus_speed(card);
return 0;
}
/*
* For device supporting HS200 mode, the following sequence
* should be done before executing the tuning process.
* 1. set the desired bus width(4-bit or 8-bit, 1-bit is not supported)
* 2. switch to HS200 mode
* 3. set the clock to > 52Mhz and <=200MHz
*/
static int mmc_select_hs200(struct mmc_card *card)
{
struct mmc_host *host = card->host;
int err = -EINVAL;
if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_2V)
err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_120);
if (err && card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200_1_8V)
err = __mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180);
/* If fails try again during next card power cycle */
if (err)
goto err;
/*
* Set the bus width(4 or 8) with host's support and
* switch to HS200 mode if bus width is set successfully.
*/
err = mmc_select_bus_width(card);
if (!IS_ERR_VALUE(err)) {
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, 2, EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
card->ext_csd.generic_cmd6_time, card->ext_csd.generic_cmd6_time,
true, true, true); true, true, true);
if (!err)
mmc_set_timing(host, MMC_TIMING_MMC_HS200);
}
err: err:
return err; return err;
} }
/*
* Activate High Speed or HS200 mode if supported.
*/
static int mmc_select_timing(struct mmc_card *card)
{
int err = 0;
if ((card->csd.mmca_vsn < CSD_SPEC_VER_4 &&
card->ext_csd.hs_max_dtr == 0))
goto bus_speed;
if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
err = mmc_select_hs200(card);
else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
err = mmc_select_hs(card);
if (err && err != -EBADMSG)
return err;
if (err) {
pr_warn("%s: switch to %s failed\n",
mmc_card_hs(card) ? "high-speed" :
(mmc_card_hs200(card) ? "hs200" : ""),
mmc_hostname(card->host));
err = 0;
}
bus_speed:
/*
* Set the bus speed to the selected bus timing.
* If timing is not selected, backward compatible is the default.
*/
mmc_set_bus_speed(card);
return err;
}
/*
* Execute tuning sequence to seek the proper bus operating
* conditions for HS200 and HS400, which sends CMD21 to the device.
*/
static int mmc_hs200_tuning(struct mmc_card *card)
{
struct mmc_host *host = card->host;
int err = 0;
/*
* Timing should be adjusted to the HS400 target
* operation frequency for tuning process
*/
if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
host->ios.bus_width == MMC_BUS_WIDTH_8)
if (host->ops->prepare_hs400_tuning)
host->ops->prepare_hs400_tuning(host, &host->ios);
if (host->ops->execute_tuning) {
mmc_host_clk_hold(host);
err = host->ops->execute_tuning(host,
MMC_SEND_TUNING_BLOCK_HS200);
mmc_host_clk_release(host);
if (err)
pr_warn("%s: tuning execution failed\n",
mmc_hostname(host));
}
return err;
}
/* /*
* Handle the detection and initialisation of a card. * Handle the detection and initialisation of a card.
* *
@ -874,9 +1177,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
struct mmc_card *oldcard) struct mmc_card *oldcard)
{ {
struct mmc_card *card; struct mmc_card *card;
int err, ddr = 0; int err;
u32 cid[4]; u32 cid[4];
unsigned int max_dtr;
u32 rocr; u32 rocr;
u8 *ext_csd = NULL; u8 *ext_csd = NULL;
@ -1068,206 +1370,34 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
} }
/* /*
* Activate high speed (if supported) * Select timing interface
*/ */
if (card->ext_csd.hs_max_dtr != 0) { err = mmc_select_timing(card);
err = 0; if (err)
if (card->ext_csd.hs_max_dtr > 52000000 && goto free_card;
host->caps2 & MMC_CAP2_HS200)
err = mmc_select_hs200(card);
else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, 1,
card->ext_csd.generic_cmd6_time,
true, true, true);
if (err && err != -EBADMSG)
goto free_card;
if (err) {
pr_warning("%s: switch to highspeed failed\n",
mmc_hostname(card->host));
err = 0;
} else {
if (card->ext_csd.hs_max_dtr > 52000000 &&
host->caps2 & MMC_CAP2_HS200) {
mmc_card_set_hs200(card);
mmc_set_timing(card->host,
MMC_TIMING_MMC_HS200);
} else {
mmc_card_set_highspeed(card);
mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
}
}
}
/*
* Compute bus speed.
*/
max_dtr = (unsigned int)-1;
if (mmc_card_highspeed(card) || mmc_card_hs200(card)) {
if (max_dtr > card->ext_csd.hs_max_dtr)
max_dtr = card->ext_csd.hs_max_dtr;
if (mmc_card_highspeed(card) && (max_dtr > 52000000))
max_dtr = 52000000;
} else if (max_dtr > card->csd.max_dtr) {
max_dtr = card->csd.max_dtr;
}
mmc_set_clock(host, max_dtr);
/*
* Indicate DDR mode (if supported).
*/
if (mmc_card_highspeed(card)) {
if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)
&& (host->caps & MMC_CAP_1_8V_DDR))
ddr = MMC_1_8V_DDR_MODE;
else if ((card->ext_csd.card_type & EXT_CSD_CARD_TYPE_DDR_1_2V)
&& (host->caps & MMC_CAP_1_2V_DDR))
ddr = MMC_1_2V_DDR_MODE;
}
/*
* Indicate HS200 SDR mode (if supported).
*/
if (mmc_card_hs200(card)) { if (mmc_card_hs200(card)) {
u32 ext_csd_bits; err = mmc_hs200_tuning(card);
u32 bus_width = card->host->ios.bus_width;
/*
* For devices supporting HS200 mode, the bus width has
* to be set before executing the tuning function. If
* set before tuning, then device will respond with CRC
* errors for responses on CMD line. So for HS200 the
* sequence will be
* 1. set bus width 4bit / 8 bit (1 bit not supported)
* 2. switch to HS200 mode
* 3. set the clock to > 52Mhz <=200MHz and
* 4. execute tuning for HS200
*/
if ((host->caps2 & MMC_CAP2_HS200) &&
card->host->ops->execute_tuning) {
mmc_host_clk_hold(card->host);
err = card->host->ops->execute_tuning(card->host,
MMC_SEND_TUNING_BLOCK_HS200);
mmc_host_clk_release(card->host);
}
if (err) {
pr_warning("%s: tuning execution failed\n",
mmc_hostname(card->host));
goto err;
}
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);
if (err) if (err)
pr_warning("%s: power class selection to bus width %d" goto err;
" failed\n", mmc_hostname(card->host),
1 << bus_width); err = mmc_select_hs400(card);
if (err)
goto err;
} else if (mmc_card_hs(card)) {
/* Select the desired bus width optionally */
err = mmc_select_bus_width(card);
if (!IS_ERR_VALUE(err)) {
err = mmc_select_hs_ddr(card);
if (err)
goto err;
}
} }
/* /*
* Activate wide bus and DDR (if supported). * Choose the power class with selected bus interface
*/ */
if (!mmc_card_hs200(card) && mmc_select_powerclass(card);
(card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
static unsigned ext_csd_bits[][2] = {
{ EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
{ EXT_CSD_BUS_WIDTH_4, EXT_CSD_DDR_BUS_WIDTH_4 },
{ EXT_CSD_BUS_WIDTH_1, EXT_CSD_BUS_WIDTH_1 },
};
static unsigned bus_widths[] = {
MMC_BUS_WIDTH_8,
MMC_BUS_WIDTH_4,
MMC_BUS_WIDTH_1
};
unsigned idx, bus_width = 0;
if (host->caps & MMC_CAP_8_BIT_DATA)
idx = 0;
else
idx = 1;
for (; idx < ARRAY_SIZE(bus_widths); idx++) {
bus_width = bus_widths[idx];
if (bus_width == MMC_BUS_WIDTH_1)
ddr = 0; /* no DDR for 1-bit width */
err = mmc_select_powerclass(card, ext_csd_bits[idx][0]);
if (err)
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,
ext_csd_bits[idx][0],
card->ext_csd.generic_cmd6_time);
if (!err) {
mmc_set_bus_width(card->host, bus_width);
/*
* If controller can't handle bus width test,
* compare ext_csd previously read in 1 bit mode
* against ext_csd at new bus width
*/
if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
err = mmc_compare_ext_csds(card,
bus_width);
else
err = mmc_bus_test(card, bus_width);
if (!err)
break;
}
}
if (!err && ddr) {
err = mmc_select_powerclass(card, ext_csd_bits[idx][1]);
if (err)
pr_warning("%s: power class selection to "
"bus width %d ddr %d failed\n",
mmc_hostname(card->host),
1 << bus_width, ddr);
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_BUS_WIDTH,
ext_csd_bits[idx][1],
card->ext_csd.generic_cmd6_time);
}
if (err) {
pr_warning("%s: switch to bus width %d ddr %d "
"failed\n", mmc_hostname(card->host),
1 << bus_width, ddr);
goto free_card;
} else if (ddr) {
/*
* eMMC cards can support 3.3V to 1.2V i/o (vccq)
* signaling.
*
* EXT_CSD_CARD_TYPE_DDR_1_8V means 3.3V or 1.8V vccq.
*
* 1.8V vccq at 3.3V core voltage (vcc) is not required
* in the JEDEC spec for DDR.
*
* Do not force change in vccq since we are obviously
* working and no change to vccq is needed.
*
* WARNING: eMMC rules are NOT the same as SD DDR
*/
if (ddr == MMC_1_2V_DDR_MODE) {
err = __mmc_set_signal_voltage(host,
MMC_SIGNAL_VOLTAGE_120);
if (err)
goto err;
}
mmc_card_set_ddr_mode(card);
mmc_set_timing(card->host, MMC_TIMING_UHS_DDR50);
mmc_set_bus_width(card->host, bus_width);
}
}
/* /*
* Enable HPI feature (if supported) * Enable HPI feature (if supported)
@ -1507,7 +1637,6 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
err = mmc_sleep(host); err = mmc_sleep(host);
else if (!mmc_host_is_spi(host)) else if (!mmc_host_is_spi(host))
err = mmc_deselect_cards(host); err = mmc_deselect_cards(host);
host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
if (!err) { if (!err) {
mmc_power_off(host); mmc_power_off(host);
@ -1637,7 +1766,6 @@ static int mmc_power_restore(struct mmc_host *host)
{ {
int ret; int ret;
host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
mmc_claim_host(host); mmc_claim_host(host);
ret = mmc_init_card(host, host->card->ocr, host->card); ret = mmc_init_card(host, host->card->ocr, host->card);
mmc_release_host(host); mmc_release_host(host);

View file

@ -707,18 +707,10 @@ static struct attribute *sd_std_attrs[] = {
&dev_attr_serial.attr, &dev_attr_serial.attr,
NULL, NULL,
}; };
ATTRIBUTE_GROUPS(sd_std);
static struct attribute_group sd_std_attr_group = {
.attrs = sd_std_attrs,
};
static const struct attribute_group *sd_attr_groups[] = {
&sd_std_attr_group,
NULL,
};
struct device_type sd_type = { struct device_type sd_type = {
.groups = sd_attr_groups, .groups = sd_std_groups,
}; };
/* /*
@ -895,7 +887,7 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card)
{ {
unsigned max_dtr = (unsigned int)-1; unsigned max_dtr = (unsigned int)-1;
if (mmc_card_highspeed(card)) { if (mmc_card_hs(card)) {
if (max_dtr > card->sw_caps.hs_max_dtr) if (max_dtr > card->sw_caps.hs_max_dtr)
max_dtr = card->sw_caps.hs_max_dtr; max_dtr = card->sw_caps.hs_max_dtr;
} else if (max_dtr > card->csd.max_dtr) { } else if (max_dtr > card->csd.max_dtr) {
@ -905,12 +897,6 @@ unsigned mmc_sd_get_max_clock(struct mmc_card *card)
return max_dtr; return max_dtr;
} }
void mmc_sd_go_highspeed(struct mmc_card *card)
{
mmc_card_set_highspeed(card);
mmc_set_timing(card->host, MMC_TIMING_SD_HS);
}
/* /*
* Handle the detection and initialisation of a card. * Handle the detection and initialisation of a card.
* *
@ -985,16 +971,13 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
err = mmc_sd_init_uhs_card(card); err = mmc_sd_init_uhs_card(card);
if (err) if (err)
goto free_card; goto free_card;
/* Card is an ultra-high-speed card */
mmc_card_set_uhs(card);
} else { } else {
/* /*
* Attempt to change to high-speed (if supported) * Attempt to change to high-speed (if supported)
*/ */
err = mmc_sd_switch_hs(card); err = mmc_sd_switch_hs(card);
if (err > 0) if (err > 0)
mmc_sd_go_highspeed(card); mmc_set_timing(card->host, MMC_TIMING_SD_HS);
else if (err) else if (err)
goto free_card; goto free_card;
@ -1089,7 +1072,7 @@ static int _mmc_sd_suspend(struct mmc_host *host)
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;
if (!err) { if (!err) {
mmc_power_off(host); mmc_power_off(host);
mmc_card_set_suspended(host->card); mmc_card_set_suspended(host->card);
@ -1198,7 +1181,6 @@ static int mmc_sd_power_restore(struct mmc_host *host)
{ {
int ret; int ret;
host->card->state &= ~MMC_STATE_HIGHSPEED;
mmc_claim_host(host); mmc_claim_host(host);
ret = mmc_sd_init_card(host, host->card->ocr, host->card); ret = mmc_sd_init_card(host, host->card->ocr, host->card);
mmc_release_host(host); mmc_release_host(host);

View file

@ -12,6 +12,5 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
bool reinit); bool reinit);
unsigned mmc_sd_get_max_clock(struct mmc_card *card); unsigned mmc_sd_get_max_clock(struct mmc_card *card);
int mmc_sd_switch_hs(struct mmc_card *card); int mmc_sd_switch_hs(struct mmc_card *card);
void mmc_sd_go_highspeed(struct mmc_card *card);
#endif #endif

View file

@ -363,7 +363,7 @@ static unsigned mmc_sdio_get_max_clock(struct mmc_card *card)
{ {
unsigned max_dtr; unsigned max_dtr;
if (mmc_card_highspeed(card)) { if (mmc_card_hs(card)) {
/* /*
* The SDIO specification doesn't mention how * The SDIO specification doesn't mention how
* the CIS transfer speed register relates to * the CIS transfer speed register relates to
@ -733,7 +733,6 @@ try_again:
mmc_set_clock(host, card->cis.max_dtr); mmc_set_clock(host, card->cis.max_dtr);
if (card->cccr.high_speed) { if (card->cccr.high_speed) {
mmc_card_set_highspeed(card);
mmc_set_timing(card->host, MMC_TIMING_SD_HS); mmc_set_timing(card->host, MMC_TIMING_SD_HS);
} }
@ -792,16 +791,13 @@ try_again:
err = mmc_sdio_init_uhs_card(card); err = mmc_sdio_init_uhs_card(card);
if (err) if (err)
goto remove; goto remove;
/* Card is an ultra-high-speed card */
mmc_card_set_uhs(card);
} else { } else {
/* /*
* Switch to high-speed (if supported). * Switch to high-speed (if supported).
*/ */
err = sdio_enable_hs(card); err = sdio_enable_hs(card);
if (err > 0) if (err > 0)
mmc_sd_go_highspeed(card); mmc_set_timing(card->host, MMC_TIMING_SD_HS);
else if (err) else if (err)
goto remove; goto remove;
@ -943,40 +939,21 @@ static int mmc_sdio_pre_suspend(struct mmc_host *host)
*/ */
static int mmc_sdio_suspend(struct mmc_host *host) static int mmc_sdio_suspend(struct mmc_host *host)
{ {
int i, err = 0; if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
for (i = 0; i < host->card->sdio_funcs; i++) {
struct sdio_func *func = host->card->sdio_func[i];
if (func && sdio_func_present(func) && func->dev.driver) {
const struct dev_pm_ops *pmops = func->dev.driver->pm;
err = pmops->suspend(&func->dev);
if (err)
break;
}
}
while (err && --i >= 0) {
struct sdio_func *func = host->card->sdio_func[i];
if (func && sdio_func_present(func) && func->dev.driver) {
const struct dev_pm_ops *pmops = func->dev.driver->pm;
pmops->resume(&func->dev);
}
}
if (!err && mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
mmc_claim_host(host); mmc_claim_host(host);
sdio_disable_wide(host->card); sdio_disable_wide(host->card);
mmc_release_host(host); mmc_release_host(host);
} }
if (!err && !mmc_card_keep_power(host)) if (!mmc_card_keep_power(host))
mmc_power_off(host); mmc_power_off(host);
return err; return 0;
} }
static int mmc_sdio_resume(struct mmc_host *host) static int mmc_sdio_resume(struct mmc_host *host)
{ {
int i, err = 0; int err = 0;
BUG_ON(!host); BUG_ON(!host);
BUG_ON(!host->card); BUG_ON(!host->card);
@ -1019,24 +996,6 @@ static int mmc_sdio_resume(struct mmc_host *host)
wake_up_process(host->sdio_irq_thread); wake_up_process(host->sdio_irq_thread);
mmc_release_host(host); mmc_release_host(host);
/*
* If the card looked to be the same as before suspending, then
* we proceed to resume all card functions. If one of them returns
* an error then we simply return that error to the core and the
* card will be redetected as new. It is the responsibility of
* the function driver to perform further tests with the extra
* knowledge it has of the card to confirm the card is indeed the
* same as before suspending (same MAC address for network cards,
* etc.) and return an error otherwise.
*/
for (i = 0; !err && i < host->card->sdio_funcs; i++) {
struct sdio_func *func = host->card->sdio_func[i];
if (func && sdio_func_present(func) && func->dev.driver) {
const struct dev_pm_ops *pmops = func->dev.driver->pm;
err = pmops->resume(&func->dev);
}
}
host->pm_flags &= ~MMC_PM_KEEP_POWER; host->pm_flags &= ~MMC_PM_KEEP_POWER;
return err; return err;
} }

View file

@ -197,20 +197,8 @@ static int sdio_bus_remove(struct device *dev)
#ifdef CONFIG_PM #ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP
static int pm_no_operation(struct device *dev)
{
/*
* Prevent the PM core from calling SDIO device drivers' suspend
* callback routines, which it is not supposed to do, by using this
* empty function as the bus type suspend callaback for SDIO.
*/
return 0;
}
#endif
static const struct dev_pm_ops sdio_bus_pm_ops = { static const struct dev_pm_ops sdio_bus_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_no_operation, pm_no_operation) SET_SYSTEM_SLEEP_PM_OPS(pm_generic_suspend, pm_generic_resume)
SET_RUNTIME_PM_OPS( SET_RUNTIME_PM_OPS(
pm_generic_runtime_suspend, pm_generic_runtime_suspend,
pm_generic_runtime_resume, pm_generic_runtime_resume,

View file

@ -90,6 +90,15 @@ static int process_sdio_pending_irqs(struct mmc_host *host)
return ret; return ret;
} }
void sdio_run_irqs(struct mmc_host *host)
{
mmc_claim_host(host);
host->sdio_irq_pending = true;
process_sdio_pending_irqs(host);
mmc_release_host(host);
}
EXPORT_SYMBOL_GPL(sdio_run_irqs);
static int sdio_irq_thread(void *_host) static int sdio_irq_thread(void *_host)
{ {
struct mmc_host *host = _host; struct mmc_host *host = _host;
@ -189,14 +198,20 @@ static int sdio_card_irq_get(struct mmc_card *card)
WARN_ON(!host->claimed); WARN_ON(!host->claimed);
if (!host->sdio_irqs++) { if (!host->sdio_irqs++) {
atomic_set(&host->sdio_irq_thread_abort, 0); if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) {
host->sdio_irq_thread = atomic_set(&host->sdio_irq_thread_abort, 0);
kthread_run(sdio_irq_thread, host, "ksdioirqd/%s", host->sdio_irq_thread =
mmc_hostname(host)); kthread_run(sdio_irq_thread, host,
if (IS_ERR(host->sdio_irq_thread)) { "ksdioirqd/%s", mmc_hostname(host));
int err = PTR_ERR(host->sdio_irq_thread); if (IS_ERR(host->sdio_irq_thread)) {
host->sdio_irqs--; int err = PTR_ERR(host->sdio_irq_thread);
return err; host->sdio_irqs--;
return err;
}
} else {
mmc_host_clk_hold(host);
host->ops->enable_sdio_irq(host, 1);
mmc_host_clk_release(host);
} }
} }
@ -211,8 +226,14 @@ static int sdio_card_irq_put(struct mmc_card *card)
BUG_ON(host->sdio_irqs < 1); BUG_ON(host->sdio_irqs < 1);
if (!--host->sdio_irqs) { if (!--host->sdio_irqs) {
atomic_set(&host->sdio_irq_thread_abort, 1); if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) {
kthread_stop(host->sdio_irq_thread); atomic_set(&host->sdio_irq_thread_abort, 1);
kthread_stop(host->sdio_irq_thread);
} else {
mmc_host_clk_hold(host);
host->ops->enable_sdio_irq(host, 0);
mmc_host_clk_release(host);
}
} }
return 0; return 0;

View file

@ -32,9 +32,7 @@ static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id)
/* Schedule a card detection after a debounce timeout */ /* Schedule a card detection after a debounce timeout */
struct mmc_host *host = dev_id; struct mmc_host *host = dev_id;
if (host->ops->card_event) host->trigger_card_event = true;
host->ops->card_event(host);
mmc_detect_change(host, msecs_to_jiffies(200)); mmc_detect_change(host, msecs_to_jiffies(200));
return IRQ_HANDLED; return IRQ_HANDLED;

View file

@ -168,7 +168,7 @@ config MMC_SDHCI_ESDHC_IMX
config MMC_SDHCI_DOVE config MMC_SDHCI_DOVE
tristate "SDHCI support on Marvell's Dove SoC" tristate "SDHCI support on Marvell's Dove SoC"
depends on ARCH_DOVE depends on ARCH_DOVE || MACH_DOVE
depends on MMC_SDHCI_PLTFM depends on MMC_SDHCI_PLTFM
select MMC_SDHCI_IO_ACCESSORS select MMC_SDHCI_IO_ACCESSORS
help help
@ -283,6 +283,15 @@ config MMC_SDHCI_BCM2835
If unsure, say N. If unsure, say N.
config MMC_MOXART
tristate "MOXART SD/MMC Host Controller support"
depends on ARCH_MOXART && MMC
help
This selects support for the MOXART SD/MMC Host Controller.
MOXA provides one multi-functional card reader which can
be found on some embedded hardware such as UC-7112-LX.
If you have a controller with this interface, say Y here.
config MMC_OMAP config MMC_OMAP
tristate "TI OMAP Multimedia Card Interface support" tristate "TI OMAP Multimedia Card Interface support"
depends on ARCH_OMAP depends on ARCH_OMAP
@ -688,6 +697,12 @@ config MMC_WMT
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called wmt-sdmmc. module will be called wmt-sdmmc.
config MMC_USDHI6ROL0
tristate "Renesas USDHI6ROL0 SD/SDIO Host Controller support"
help
This selects support for the Renesas USDHI6ROL0 SD/SDIO
Host Controller
config MMC_REALTEK_PCI config MMC_REALTEK_PCI
tristate "Realtek PCI-E SD/MMC Card Interface Driver" tristate "Realtek PCI-E SD/MMC Card Interface Driver"
depends on MFD_RTSX_PCI depends on MFD_RTSX_PCI

View file

@ -50,7 +50,9 @@ obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o
obj-$(CONFIG_MMC_VUB300) += vub300.o obj-$(CONFIG_MMC_VUB300) += vub300.o
obj-$(CONFIG_MMC_USHC) += ushc.o obj-$(CONFIG_MMC_USHC) += ushc.o
obj-$(CONFIG_MMC_WMT) += wmt-sdmmc.o obj-$(CONFIG_MMC_WMT) += wmt-sdmmc.o
obj-$(CONFIG_MMC_MOXART) += moxart-mmc.o
obj-$(CONFIG_MMC_SUNXI) += sunxi-mmc.o obj-$(CONFIG_MMC_SUNXI) += sunxi-mmc.o
obj-$(CONFIG_MMC_USDHI6ROL0) += usdhi6rol0.o
obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o
obj-$(CONFIG_MMC_REALTEK_USB) += rtsx_usb_sdmmc.o obj-$(CONFIG_MMC_REALTEK_USB) += rtsx_usb_sdmmc.o

View file

@ -820,16 +820,9 @@ static void atmci_pdc_complete(struct atmel_mci *host)
atmci_pdc_cleanup(host); atmci_pdc_cleanup(host);
/* dev_dbg(&host->pdev->dev, "(%s) set pending xfer complete\n", __func__);
* If the card was removed, data will be NULL. No point trying atmci_set_pending(host, EVENT_XFER_COMPLETE);
* to send the stop command or waiting for NBUSY in this case. tasklet_schedule(&host->tasklet);
*/
if (host->data) {
dev_dbg(&host->pdev->dev,
"(%s) set pending xfer complete\n", __func__);
atmci_set_pending(host, EVENT_XFER_COMPLETE);
tasklet_schedule(&host->tasklet);
}
} }
static void atmci_dma_cleanup(struct atmel_mci *host) static void atmci_dma_cleanup(struct atmel_mci *host)

View file

@ -187,7 +187,7 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
unsigned long actual; unsigned long actual;
u8 div = priv->ciu_div + 1; u8 div = priv->ciu_div + 1;
if (ios->timing == MMC_TIMING_UHS_DDR50) { if (ios->timing == MMC_TIMING_MMC_DDR52) {
mci_writel(host, CLKSEL, priv->ddr_timing); mci_writel(host, CLKSEL, priv->ddr_timing);
/* Should be double rate for DDR mode */ /* Should be double rate for DDR mode */
if (ios->bus_width == MMC_BUS_WIDTH_8) if (ios->bus_width == MMC_BUS_WIDTH_8)
@ -386,8 +386,7 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot, u32 opcode,
/* 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_1_8V_DDR | MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
MMC_CAP_CMD23, MMC_CAP_CMD23,
MMC_CAP_CMD23, MMC_CAP_CMD23,
MMC_CAP_CMD23, MMC_CAP_CMD23,
@ -426,7 +425,7 @@ 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 = { static const struct dev_pm_ops dw_mci_exynos_pmops = {
SET_SYSTEM_SLEEP_PM_OPS(dw_mci_exynos_suspend, dw_mci_exynos_resume) SET_SYSTEM_SLEEP_PM_OPS(dw_mci_exynos_suspend, dw_mci_exynos_resume)
.resume_noirq = dw_mci_exynos_resume_noirq, .resume_noirq = dw_mci_exynos_resume_noirq,
.thaw_noirq = dw_mci_exynos_resume_noirq, .thaw_noirq = dw_mci_exynos_resume_noirq,

View file

@ -235,12 +235,6 @@ err:
} }
#endif /* defined(CONFIG_DEBUG_FS) */ #endif /* defined(CONFIG_DEBUG_FS) */
static void dw_mci_set_timeout(struct dw_mci *host)
{
/* timeout (maximum) */
mci_writel(host, TMOUT, 0xffffffff);
}
static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd) static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
{ {
struct mmc_data *data; struct mmc_data *data;
@ -257,9 +251,8 @@ static u32 dw_mci_prepare_command(struct mmc_host *mmc, struct mmc_command *cmd)
(cmd->opcode == SD_IO_RW_DIRECT && (cmd->opcode == SD_IO_RW_DIRECT &&
((cmd->arg >> 9) & 0x1FFFF) == SDIO_CCCR_ABORT)) ((cmd->arg >> 9) & 0x1FFFF) == SDIO_CCCR_ABORT))
cmdr |= SDMMC_CMD_STOP; cmdr |= SDMMC_CMD_STOP;
else else if (cmd->opcode != MMC_SEND_STATUS && cmd->data)
if (cmd->opcode != MMC_SEND_STATUS && cmd->data) cmdr |= SDMMC_CMD_PRV_DAT_WAIT;
cmdr |= SDMMC_CMD_PRV_DAT_WAIT;
if (cmd->flags & MMC_RSP_PRESENT) { if (cmd->flags & MMC_RSP_PRESENT) {
/* We expect a response, so set this bit */ /* We expect a response, so set this bit */
@ -850,8 +843,6 @@ static void __dw_mci_start_request(struct dw_mci *host,
u32 cmdflags; u32 cmdflags;
mrq = slot->mrq; mrq = slot->mrq;
if (host->pdata->select_slot)
host->pdata->select_slot(slot->id);
host->cur_slot = slot; host->cur_slot = slot;
host->mrq = mrq; host->mrq = mrq;
@ -864,7 +855,7 @@ static void __dw_mci_start_request(struct dw_mci *host,
data = cmd->data; data = cmd->data;
if (data) { if (data) {
dw_mci_set_timeout(host); mci_writel(host, TMOUT, 0xFFFFFFFF);
mci_writel(host, BYTCNT, data->blksz*data->blocks); mci_writel(host, BYTCNT, data->blksz*data->blocks);
mci_writel(host, BLKSIZ, data->blksz); mci_writel(host, BLKSIZ, data->blksz);
} }
@ -962,7 +953,7 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
regs = mci_readl(slot->host, UHS_REG); regs = mci_readl(slot->host, UHS_REG);
/* DDR mode set */ /* DDR mode set */
if (ios->timing == MMC_TIMING_UHS_DDR50) if (ios->timing == MMC_TIMING_MMC_DDR52)
regs |= ((0x1 << slot->id) << 16); regs |= ((0x1 << slot->id) << 16);
else else
regs &= ~((0x1 << slot->id) << 16); regs &= ~((0x1 << slot->id) << 16);
@ -985,17 +976,11 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
switch (ios->power_mode) { switch (ios->power_mode) {
case MMC_POWER_UP: case MMC_POWER_UP:
set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags); set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags);
/* Power up slot */
if (slot->host->pdata->setpower)
slot->host->pdata->setpower(slot->id, mmc->ocr_avail);
regs = mci_readl(slot->host, PWREN); regs = mci_readl(slot->host, PWREN);
regs |= (1 << slot->id); regs |= (1 << slot->id);
mci_writel(slot->host, PWREN, regs); mci_writel(slot->host, PWREN, regs);
break; break;
case MMC_POWER_OFF: case MMC_POWER_OFF:
/* Power down slot */
if (slot->host->pdata->setpower)
slot->host->pdata->setpower(slot->id, 0);
regs = mci_readl(slot->host, PWREN); regs = mci_readl(slot->host, PWREN);
regs &= ~(1 << slot->id); regs &= ~(1 << slot->id);
mci_writel(slot->host, PWREN, regs); mci_writel(slot->host, PWREN, regs);
@ -1009,15 +994,13 @@ static int dw_mci_get_ro(struct mmc_host *mmc)
{ {
int read_only; int read_only;
struct dw_mci_slot *slot = mmc_priv(mmc); struct dw_mci_slot *slot = mmc_priv(mmc);
struct dw_mci_board *brd = slot->host->pdata; int gpio_ro = mmc_gpio_get_ro(mmc);
/* Use platform get_ro function, else try on board write protect */ /* Use platform get_ro function, else try on board write protect */
if (slot->quirks & DW_MCI_SLOT_QUIRK_NO_WRITE_PROTECT) if (slot->quirks & DW_MCI_SLOT_QUIRK_NO_WRITE_PROTECT)
read_only = 0; read_only = 0;
else if (brd->get_ro) else if (!IS_ERR_VALUE(gpio_ro))
read_only = brd->get_ro(slot->id); read_only = gpio_ro;
else if (gpio_is_valid(slot->wp_gpio))
read_only = gpio_get_value(slot->wp_gpio);
else else
read_only = read_only =
mci_readl(slot->host, WRTPRT) & (1 << slot->id) ? 1 : 0; mci_readl(slot->host, WRTPRT) & (1 << slot->id) ? 1 : 0;
@ -1039,8 +1022,6 @@ static int dw_mci_get_cd(struct mmc_host *mmc)
/* Use platform get_cd function, else try onboard card detect */ /* Use platform get_cd function, else try onboard card detect */
if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION) if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION)
present = 1; present = 1;
else if (brd->get_cd)
present = !brd->get_cd(slot->id);
else if (!IS_ERR_VALUE(gpio_cd)) else if (!IS_ERR_VALUE(gpio_cd))
present = gpio_cd; present = gpio_cd;
else else
@ -1248,7 +1229,7 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data)
data->error = -EIO; data->error = -EIO;
} }
dev_err(host->dev, "data error, status 0x%08x\n", status); dev_dbg(host->dev, "data error, status 0x%08x\n", status);
/* /*
* After an error, there may be data lingering * After an error, there may be data lingering
@ -2045,86 +2026,15 @@ static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot)
return quirks; return quirks;
} }
/* find out bus-width for a given slot */
static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
{
struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
u32 bus_wd = 1;
if (!np)
return 1;
if (of_property_read_u32(np, "bus-width", &bus_wd))
dev_err(dev, "bus-width property not found, assuming width"
" as 1\n");
return bus_wd;
}
/* find the write protect gpio for a given slot; or -1 if none specified */
static int dw_mci_of_get_wp_gpio(struct device *dev, u8 slot)
{
struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
int gpio;
if (!np)
return -EINVAL;
gpio = of_get_named_gpio(np, "wp-gpios", 0);
/* Having a missing entry is valid; return silently */
if (!gpio_is_valid(gpio))
return -EINVAL;
if (devm_gpio_request(dev, gpio, "dw-mci-wp")) {
dev_warn(dev, "gpio [%d] request failed\n", gpio);
return -EINVAL;
}
return gpio;
}
/* find the cd gpio for a given slot */
static void dw_mci_of_get_cd_gpio(struct device *dev, u8 slot,
struct mmc_host *mmc)
{
struct device_node *np = dw_mci_of_find_slot_node(dev, slot);
int gpio;
if (!np)
return;
gpio = of_get_named_gpio(np, "cd-gpios", 0);
/* Having a missing entry is valid; return silently */
if (!gpio_is_valid(gpio))
return;
if (mmc_gpio_request_cd(mmc, gpio, 0))
dev_warn(dev, "gpio [%d] request failed\n", gpio);
}
#else /* CONFIG_OF */ #else /* CONFIG_OF */
static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot) static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot)
{ {
return 0; return 0;
} }
static u32 dw_mci_of_get_bus_wd(struct device *dev, u8 slot)
{
return 1;
}
static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot) static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
{ {
return NULL; return NULL;
} }
static int dw_mci_of_get_wp_gpio(struct device *dev, u8 slot)
{
return -EINVAL;
}
static void dw_mci_of_get_cd_gpio(struct device *dev, u8 slot,
struct mmc_host *mmc)
{
return;
}
#endif /* CONFIG_OF */ #endif /* CONFIG_OF */
static int dw_mci_init_slot(struct dw_mci *host, unsigned int id) static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
@ -2134,7 +2044,6 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
const struct dw_mci_drv_data *drv_data = host->drv_data; const struct dw_mci_drv_data *drv_data = host->drv_data;
int ctrl_id, ret; int ctrl_id, ret;
u32 freq[2]; u32 freq[2];
u8 bus_width;
mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev); mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev);
if (!mmc) if (!mmc)
@ -2158,17 +2067,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
mmc->f_max = freq[1]; mmc->f_max = freq[1];
} }
if (host->pdata->get_ocr) mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
mmc->ocr_avail = host->pdata->get_ocr(id);
else
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
/*
* Start with slot power disabled, it will be enabled when a card
* is detected.
*/
if (host->pdata->setpower)
host->pdata->setpower(id, 0);
if (host->pdata->caps) if (host->pdata->caps)
mmc->caps = host->pdata->caps; mmc->caps = host->pdata->caps;
@ -2189,19 +2088,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
if (host->pdata->caps2) if (host->pdata->caps2)
mmc->caps2 = host->pdata->caps2; mmc->caps2 = host->pdata->caps2;
if (host->pdata->get_bus_wd) mmc_of_parse(mmc);
bus_width = host->pdata->get_bus_wd(slot->id);
else if (host->dev->of_node)
bus_width = dw_mci_of_get_bus_wd(host->dev, slot->id);
else
bus_width = 1;
switch (bus_width) {
case 8:
mmc->caps |= MMC_CAP_8_BIT_DATA;
case 4:
mmc->caps |= MMC_CAP_4_BIT_DATA;
}
if (host->pdata->blk_settings) { if (host->pdata->blk_settings) {
mmc->max_segs = host->pdata->blk_settings->max_segs; mmc->max_segs = host->pdata->blk_settings->max_segs;
@ -2226,8 +2113,10 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
#endif /* CONFIG_MMC_DW_IDMAC */ #endif /* CONFIG_MMC_DW_IDMAC */
} }
slot->wp_gpio = dw_mci_of_get_wp_gpio(host->dev, slot->id); if (dw_mci_get_cd(mmc))
dw_mci_of_get_cd_gpio(host->dev, slot->id, mmc); set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
else
clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
ret = mmc_add_host(mmc); ret = mmc_add_host(mmc);
if (ret) if (ret)
@ -2249,10 +2138,6 @@ err_setup_bus:
static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id) static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
{ {
/* Shutdown detect IRQ */
if (slot->host->pdata->exit)
slot->host->pdata->exit(id);
/* Debugfs stuff is cleaned up by mmc core */ /* Debugfs stuff is cleaned up by mmc core */
mmc_remove_host(slot->mmc); mmc_remove_host(slot->mmc);
slot->host->slot[id] = NULL; slot->host->slot[id] = NULL;
@ -2399,24 +2284,9 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
return ERR_PTR(ret); return ERR_PTR(ret);
} }
if (of_find_property(np, "keep-power-in-suspend", NULL))
pdata->pm_caps |= MMC_PM_KEEP_POWER;
if (of_find_property(np, "enable-sdio-wakeup", NULL))
pdata->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
if (of_find_property(np, "supports-highspeed", NULL)) if (of_find_property(np, "supports-highspeed", NULL))
pdata->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED; pdata->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED;
if (of_find_property(np, "caps2-mmc-hs200-1_8v", NULL))
pdata->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
if (of_find_property(np, "caps2-mmc-hs200-1_2v", NULL))
pdata->caps2 |= MMC_CAP2_HS200_1_2V_SDR;
if (of_get_property(np, "cd-inverted", NULL))
pdata->caps2 |= MMC_CAP2_CD_ACTIVE_HIGH;
return pdata; return pdata;
} }
@ -2442,9 +2312,9 @@ int dw_mci_probe(struct dw_mci *host)
} }
} }
if (!host->pdata->select_slot && host->pdata->num_slots > 1) { if (host->pdata->num_slots > 1) {
dev_err(host->dev, dev_err(host->dev,
"Platform data must supply select_slot function\n"); "Platform data must supply num_slots.\n");
return -ENODEV; return -ENODEV;
} }
@ -2474,12 +2344,19 @@ int dw_mci_probe(struct dw_mci *host)
ret = clk_set_rate(host->ciu_clk, host->pdata->bus_hz); ret = clk_set_rate(host->ciu_clk, host->pdata->bus_hz);
if (ret) if (ret)
dev_warn(host->dev, dev_warn(host->dev,
"Unable to set bus rate to %ul\n", "Unable to set bus rate to %uHz\n",
host->pdata->bus_hz); host->pdata->bus_hz);
} }
host->bus_hz = clk_get_rate(host->ciu_clk); host->bus_hz = clk_get_rate(host->ciu_clk);
} }
if (!host->bus_hz) {
dev_err(host->dev,
"Platform data must supply bus speed\n");
ret = -ENODEV;
goto err_clk_ciu;
}
if (drv_data && drv_data->init) { if (drv_data && drv_data->init) {
ret = drv_data->init(host); ret = drv_data->init(host);
if (ret) { if (ret) {
@ -2516,13 +2393,6 @@ int dw_mci_probe(struct dw_mci *host)
} }
} }
if (!host->bus_hz) {
dev_err(host->dev,
"Platform data must supply bus speed\n");
ret = -ENODEV;
goto err_regulator;
}
host->quirks = host->pdata->quirks; host->quirks = host->pdata->quirks;
spin_lock_init(&host->lock); spin_lock_init(&host->lock);
@ -2666,8 +2536,6 @@ err_workqueue:
err_dmaunmap: err_dmaunmap:
if (host->use_dma && host->dma_ops->exit) if (host->use_dma && host->dma_ops->exit)
host->dma_ops->exit(host); host->dma_ops->exit(host);
err_regulator:
if (host->vmmc) if (host->vmmc)
regulator_disable(host->vmmc); regulator_disable(host->vmmc);

View file

@ -195,7 +195,6 @@ extern int dw_mci_resume(struct dw_mci *host);
* @mmc: The mmc_host representing this slot. * @mmc: The mmc_host representing this slot.
* @host: The MMC controller this slot is using. * @host: The MMC controller this slot is using.
* @quirks: Slot-level quirks (DW_MCI_SLOT_QUIRK_XXX) * @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. * @ctype: Card type for this slot.
* @mrq: mmc_request currently being processed or waiting to be * @mrq: mmc_request currently being processed or waiting to be
* processed, or NULL when the slot is idle. * processed, or NULL when the slot is idle.
@ -214,7 +213,6 @@ struct dw_mci_slot {
struct dw_mci *host; struct dw_mci *host;
int quirks; int quirks;
int wp_gpio;
u32 ctype; u32 ctype;

View file

@ -515,10 +515,13 @@ static irqreturn_t jz_mmc_irq_worker(int irq, void *devid)
jz4740_mmc_send_command(host, req->stop); jz4740_mmc_send_command(host, req->stop);
timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_PRG_DONE); if (mmc_resp_type(req->stop) & MMC_RSP_BUSY) {
if (timeout) { timeout = jz4740_mmc_poll_irq(host,
host->state = JZ4740_MMC_STATE_DONE; JZ_MMC_IRQ_PRG_DONE);
break; if (timeout) {
host->state = JZ4740_MMC_STATE_DONE;
break;
}
} }
case JZ4740_MMC_STATE_DONE: case JZ4740_MMC_STATE_DONE:
break; break;

View file

@ -301,7 +301,8 @@ static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8) if (host->mmc->ios.bus_width == MMC_BUS_WIDTH_8)
clk |= MCI_ST_8BIT_BUS; clk |= MCI_ST_8BIT_BUS;
if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50) if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50 ||
host->mmc->ios.timing == MMC_TIMING_MMC_DDR52)
clk |= MCI_ST_UX500_NEG_EDGE; clk |= MCI_ST_UX500_NEG_EDGE;
mmci_write_clkreg(host, clk); mmci_write_clkreg(host, clk);
@ -764,7 +765,8 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
mmci_write_clkreg(host, clk); mmci_write_clkreg(host, clk);
} }
if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50) if (host->mmc->ios.timing == MMC_TIMING_UHS_DDR50 ||
host->mmc->ios.timing == MMC_TIMING_MMC_DDR52)
datactrl |= MCI_ST_DPSM_DDRMODE; datactrl |= MCI_ST_DPSM_DDRMODE;
/* /*

View file

@ -0,0 +1,730 @@
/*
* MOXA ART MMC host driver.
*
* Copyright (C) 2014 Jonas Jensen
*
* Jonas Jensen <jonas.jensen@gmail.com>
*
* Based on code from
* Moxa Technologies Co., Ltd. <www.moxa.com>
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*/
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/blkdev.h>
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sd.h>
#include <linux/sched.h>
#include <linux/io.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/clk.h>
#include <linux/bitops.h>
#include <linux/of_dma.h>
#include <linux/spinlock.h>
#define REG_COMMAND 0
#define REG_ARGUMENT 4
#define REG_RESPONSE0 8
#define REG_RESPONSE1 12
#define REG_RESPONSE2 16
#define REG_RESPONSE3 20
#define REG_RESPONSE_COMMAND 24
#define REG_DATA_CONTROL 28
#define REG_DATA_TIMER 32
#define REG_DATA_LENGTH 36
#define REG_STATUS 40
#define REG_CLEAR 44
#define REG_INTERRUPT_MASK 48
#define REG_POWER_CONTROL 52
#define REG_CLOCK_CONTROL 56
#define REG_BUS_WIDTH 60
#define REG_DATA_WINDOW 64
#define REG_FEATURE 68
#define REG_REVISION 72
/* REG_COMMAND */
#define CMD_SDC_RESET BIT(10)
#define CMD_EN BIT(9)
#define CMD_APP_CMD BIT(8)
#define CMD_LONG_RSP BIT(7)
#define CMD_NEED_RSP BIT(6)
#define CMD_IDX_MASK 0x3f
/* REG_RESPONSE_COMMAND */
#define RSP_CMD_APP BIT(6)
#define RSP_CMD_IDX_MASK 0x3f
/* REG_DATA_CONTROL */
#define DCR_DATA_FIFO_RESET BIT(8)
#define DCR_DATA_THRES BIT(7)
#define DCR_DATA_EN BIT(6)
#define DCR_DMA_EN BIT(5)
#define DCR_DATA_WRITE BIT(4)
#define DCR_BLK_SIZE 0x0f
/* REG_DATA_LENGTH */
#define DATA_LEN_MASK 0xffffff
/* REG_STATUS */
#define WRITE_PROT BIT(12)
#define CARD_DETECT BIT(11)
/* 1-10 below can be sent to either registers, interrupt or clear. */
#define CARD_CHANGE BIT(10)
#define FIFO_ORUN BIT(9)
#define FIFO_URUN BIT(8)
#define DATA_END BIT(7)
#define CMD_SENT BIT(6)
#define DATA_CRC_OK BIT(5)
#define RSP_CRC_OK BIT(4)
#define DATA_TIMEOUT BIT(3)
#define RSP_TIMEOUT BIT(2)
#define DATA_CRC_FAIL BIT(1)
#define RSP_CRC_FAIL BIT(0)
#define MASK_RSP (RSP_TIMEOUT | RSP_CRC_FAIL | \
RSP_CRC_OK | CARD_DETECT | CMD_SENT)
#define MASK_DATA (DATA_CRC_OK | DATA_END | \
DATA_CRC_FAIL | DATA_TIMEOUT)
#define MASK_INTR_PIO (FIFO_URUN | FIFO_ORUN | CARD_CHANGE)
/* REG_POWER_CONTROL */
#define SD_POWER_ON BIT(4)
#define SD_POWER_MASK 0x0f
/* REG_CLOCK_CONTROL */
#define CLK_HISPD BIT(9)
#define CLK_OFF BIT(8)
#define CLK_SD BIT(7)
#define CLK_DIV_MASK 0x7f
/* REG_BUS_WIDTH */
#define BUS_WIDTH_8 BIT(2)
#define BUS_WIDTH_4 BIT(1)
#define BUS_WIDTH_1 BIT(0)
#define MMC_VDD_360 23
#define MIN_POWER (MMC_VDD_360 - SD_POWER_MASK)
#define MAX_RETRIES 500000
struct moxart_host {
spinlock_t lock;
void __iomem *base;
phys_addr_t reg_phys;
struct dma_chan *dma_chan_tx;
struct dma_chan *dma_chan_rx;
struct dma_async_tx_descriptor *tx_desc;
struct mmc_host *mmc;
struct mmc_request *mrq;
struct scatterlist *cur_sg;
struct completion dma_complete;
struct completion pio_complete;
u32 num_sg;
u32 data_remain;
u32 data_len;
u32 fifo_width;
u32 timeout;
u32 rate;
long sysclk;
bool have_dma;
bool is_removed;
};
static inline void moxart_init_sg(struct moxart_host *host,
struct mmc_data *data)
{
host->cur_sg = data->sg;
host->num_sg = data->sg_len;
host->data_remain = host->cur_sg->length;
if (host->data_remain > host->data_len)
host->data_remain = host->data_len;
}
static inline int moxart_next_sg(struct moxart_host *host)
{
int remain;
struct mmc_data *data = host->mrq->cmd->data;
host->cur_sg++;
host->num_sg--;
if (host->num_sg > 0) {
host->data_remain = host->cur_sg->length;
remain = host->data_len - data->bytes_xfered;
if (remain > 0 && remain < host->data_remain)
host->data_remain = remain;
}
return host->num_sg;
}
static int moxart_wait_for_status(struct moxart_host *host,
u32 mask, u32 *status)
{
int ret = -ETIMEDOUT;
u32 i;
for (i = 0; i < MAX_RETRIES; i++) {
*status = readl(host->base + REG_STATUS);
if (!(*status & mask)) {
udelay(5);
continue;
}
writel(*status & mask, host->base + REG_CLEAR);
ret = 0;
break;
}
if (ret)
dev_err(mmc_dev(host->mmc), "timed out waiting for status\n");
return ret;
}
static void moxart_send_command(struct moxart_host *host,
struct mmc_command *cmd)
{
u32 status, cmdctrl;
writel(RSP_TIMEOUT | RSP_CRC_OK |
RSP_CRC_FAIL | CMD_SENT, host->base + REG_CLEAR);
writel(cmd->arg, host->base + REG_ARGUMENT);
cmdctrl = cmd->opcode & CMD_IDX_MASK;
if (cmdctrl == SD_APP_SET_BUS_WIDTH || cmdctrl == SD_APP_OP_COND ||
cmdctrl == SD_APP_SEND_SCR || cmdctrl == SD_APP_SD_STATUS ||
cmdctrl == SD_APP_SEND_NUM_WR_BLKS)
cmdctrl |= CMD_APP_CMD;
if (cmd->flags & MMC_RSP_PRESENT)
cmdctrl |= CMD_NEED_RSP;
if (cmd->flags & MMC_RSP_136)
cmdctrl |= CMD_LONG_RSP;
writel(cmdctrl | CMD_EN, host->base + REG_COMMAND);
if (moxart_wait_for_status(host, MASK_RSP, &status) == -ETIMEDOUT)
cmd->error = -ETIMEDOUT;
if (status & RSP_TIMEOUT) {
cmd->error = -ETIMEDOUT;
return;
}
if (status & RSP_CRC_FAIL) {
cmd->error = -EIO;
return;
}
if (status & RSP_CRC_OK) {
if (cmd->flags & MMC_RSP_136) {
cmd->resp[3] = readl(host->base + REG_RESPONSE0);
cmd->resp[2] = readl(host->base + REG_RESPONSE1);
cmd->resp[1] = readl(host->base + REG_RESPONSE2);
cmd->resp[0] = readl(host->base + REG_RESPONSE3);
} else {
cmd->resp[0] = readl(host->base + REG_RESPONSE0);
}
}
}
static void moxart_dma_complete(void *param)
{
struct moxart_host *host = param;
complete(&host->dma_complete);
}
static void moxart_transfer_dma(struct mmc_data *data, struct moxart_host *host)
{
u32 len, dir_data, dir_slave;
unsigned long dma_time;
struct dma_async_tx_descriptor *desc = NULL;
struct dma_chan *dma_chan;
if (host->data_len == data->bytes_xfered)
return;
if (data->flags & MMC_DATA_WRITE) {
dma_chan = host->dma_chan_tx;
dir_data = DMA_TO_DEVICE;
dir_slave = DMA_MEM_TO_DEV;
} else {
dma_chan = host->dma_chan_rx;
dir_data = DMA_FROM_DEVICE;
dir_slave = DMA_DEV_TO_MEM;
}
len = dma_map_sg(dma_chan->device->dev, data->sg,
data->sg_len, dir_data);
if (len > 0) {
desc = dmaengine_prep_slave_sg(dma_chan, data->sg,
len, dir_slave,
DMA_PREP_INTERRUPT |
DMA_CTRL_ACK);
} else {
dev_err(mmc_dev(host->mmc), "dma_map_sg returned zero length\n");
}
if (desc) {
host->tx_desc = desc;
desc->callback = moxart_dma_complete;
desc->callback_param = host;
dmaengine_submit(desc);
dma_async_issue_pending(dma_chan);
}
data->bytes_xfered += host->data_remain;
dma_time = wait_for_completion_interruptible_timeout(
&host->dma_complete, host->timeout);
dma_unmap_sg(dma_chan->device->dev,
data->sg, data->sg_len,
dir_data);
}
static void moxart_transfer_pio(struct moxart_host *host)
{
struct mmc_data *data = host->mrq->cmd->data;
u32 *sgp, len = 0, remain, status;
if (host->data_len == data->bytes_xfered)
return;
sgp = sg_virt(host->cur_sg);
remain = host->data_remain;
if (data->flags & MMC_DATA_WRITE) {
while (remain > 0) {
if (moxart_wait_for_status(host, FIFO_URUN, &status)
== -ETIMEDOUT) {
data->error = -ETIMEDOUT;
complete(&host->pio_complete);
return;
}
for (len = 0; len < remain && len < host->fifo_width;) {
iowrite32(*sgp, host->base + REG_DATA_WINDOW);
sgp++;
len += 4;
}
remain -= len;
}
} else {
while (remain > 0) {
if (moxart_wait_for_status(host, FIFO_ORUN, &status)
== -ETIMEDOUT) {
data->error = -ETIMEDOUT;
complete(&host->pio_complete);
return;
}
for (len = 0; len < remain && len < host->fifo_width;) {
/* SCR data must be read in big endian. */
if (data->mrq->cmd->opcode == SD_APP_SEND_SCR)
*sgp = ioread32be(host->base +
REG_DATA_WINDOW);
else
*sgp = ioread32(host->base +
REG_DATA_WINDOW);
sgp++;
len += 4;
}
remain -= len;
}
}
data->bytes_xfered += host->data_remain - remain;
host->data_remain = remain;
if (host->data_len != data->bytes_xfered)
moxart_next_sg(host);
else
complete(&host->pio_complete);
}
static void moxart_prepare_data(struct moxart_host *host)
{
struct mmc_data *data = host->mrq->cmd->data;
u32 datactrl;
int blksz_bits;
if (!data)
return;
host->data_len = data->blocks * data->blksz;
blksz_bits = ffs(data->blksz) - 1;
BUG_ON(1 << blksz_bits != data->blksz);
moxart_init_sg(host, data);
datactrl = DCR_DATA_EN | (blksz_bits & DCR_BLK_SIZE);
if (data->flags & MMC_DATA_WRITE)
datactrl |= DCR_DATA_WRITE;
if ((host->data_len > host->fifo_width) && host->have_dma)
datactrl |= DCR_DMA_EN;
writel(DCR_DATA_FIFO_RESET, host->base + REG_DATA_CONTROL);
writel(MASK_DATA | FIFO_URUN | FIFO_ORUN, host->base + REG_CLEAR);
writel(host->rate, host->base + REG_DATA_TIMER);
writel(host->data_len, host->base + REG_DATA_LENGTH);
writel(datactrl, host->base + REG_DATA_CONTROL);
}
static void moxart_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct moxart_host *host = mmc_priv(mmc);
unsigned long pio_time, flags;
u32 status;
spin_lock_irqsave(&host->lock, flags);
init_completion(&host->dma_complete);
init_completion(&host->pio_complete);
host->mrq = mrq;
if (readl(host->base + REG_STATUS) & CARD_DETECT) {
mrq->cmd->error = -ETIMEDOUT;
goto request_done;
}
moxart_prepare_data(host);
moxart_send_command(host, host->mrq->cmd);
if (mrq->cmd->data) {
if ((host->data_len > host->fifo_width) && host->have_dma) {
writel(CARD_CHANGE, host->base + REG_INTERRUPT_MASK);
spin_unlock_irqrestore(&host->lock, flags);
moxart_transfer_dma(mrq->cmd->data, host);
spin_lock_irqsave(&host->lock, flags);
} else {
writel(MASK_INTR_PIO, host->base + REG_INTERRUPT_MASK);
spin_unlock_irqrestore(&host->lock, flags);
/* PIO transfers start from interrupt. */
pio_time = wait_for_completion_interruptible_timeout(
&host->pio_complete, host->timeout);
spin_lock_irqsave(&host->lock, flags);
}
if (host->is_removed) {
dev_err(mmc_dev(host->mmc), "card removed\n");
mrq->cmd->error = -ETIMEDOUT;
goto request_done;
}
if (moxart_wait_for_status(host, MASK_DATA, &status)
== -ETIMEDOUT) {
mrq->cmd->data->error = -ETIMEDOUT;
goto request_done;
}
if (status & DATA_CRC_FAIL)
mrq->cmd->data->error = -ETIMEDOUT;
if (mrq->cmd->data->stop)
moxart_send_command(host, mrq->cmd->data->stop);
}
request_done:
spin_unlock_irqrestore(&host->lock, flags);
mmc_request_done(host->mmc, mrq);
}
static irqreturn_t moxart_irq(int irq, void *devid)
{
struct moxart_host *host = (struct moxart_host *)devid;
u32 status;
unsigned long flags;
spin_lock_irqsave(&host->lock, flags);
status = readl(host->base + REG_STATUS);
if (status & CARD_CHANGE) {
host->is_removed = status & CARD_DETECT;
if (host->is_removed && host->have_dma) {
dmaengine_terminate_all(host->dma_chan_tx);
dmaengine_terminate_all(host->dma_chan_rx);
}
host->mrq = NULL;
writel(MASK_INTR_PIO, host->base + REG_CLEAR);
writel(CARD_CHANGE, host->base + REG_INTERRUPT_MASK);
mmc_detect_change(host->mmc, 0);
}
if (status & (FIFO_ORUN | FIFO_URUN) && host->mrq)
moxart_transfer_pio(host);
spin_unlock_irqrestore(&host->lock, flags);
return IRQ_HANDLED;
}
static void moxart_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct moxart_host *host = mmc_priv(mmc);
unsigned long flags;
u8 power, div;
u32 ctrl;
spin_lock_irqsave(&host->lock, flags);
if (ios->clock) {
for (div = 0; div < CLK_DIV_MASK; ++div) {
if (ios->clock >= host->sysclk / (2 * (div + 1)))
break;
}
ctrl = CLK_SD | div;
host->rate = host->sysclk / (2 * (div + 1));
if (host->rate > host->sysclk)
ctrl |= CLK_HISPD;
writel(ctrl, host->base + REG_CLOCK_CONTROL);
}
if (ios->power_mode == MMC_POWER_OFF) {
writel(readl(host->base + REG_POWER_CONTROL) & ~SD_POWER_ON,
host->base + REG_POWER_CONTROL);
} else {
if (ios->vdd < MIN_POWER)
power = 0;
else
power = ios->vdd - MIN_POWER;
writel(SD_POWER_ON | (u32) power,
host->base + REG_POWER_CONTROL);
}
switch (ios->bus_width) {
case MMC_BUS_WIDTH_4:
writel(BUS_WIDTH_4, host->base + REG_BUS_WIDTH);
break;
case MMC_BUS_WIDTH_8:
writel(BUS_WIDTH_8, host->base + REG_BUS_WIDTH);
break;
default:
writel(BUS_WIDTH_1, host->base + REG_BUS_WIDTH);
break;
}
spin_unlock_irqrestore(&host->lock, flags);
}
static int moxart_get_ro(struct mmc_host *mmc)
{
struct moxart_host *host = mmc_priv(mmc);
return !!(readl(host->base + REG_STATUS) & WRITE_PROT);
}
static struct mmc_host_ops moxart_ops = {
.request = moxart_request,
.set_ios = moxart_set_ios,
.get_ro = moxart_get_ro,
};
static int moxart_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *node = dev->of_node;
struct resource res_mmc;
struct mmc_host *mmc;
struct moxart_host *host = NULL;
struct dma_slave_config cfg;
struct clk *clk;
void __iomem *reg_mmc;
dma_cap_mask_t mask;
int irq, ret;
u32 i;
mmc = mmc_alloc_host(sizeof(struct moxart_host), dev);
if (!mmc) {
dev_err(dev, "mmc_alloc_host failed\n");
ret = -ENOMEM;
goto out;
}
ret = of_address_to_resource(node, 0, &res_mmc);
if (ret) {
dev_err(dev, "of_address_to_resource failed\n");
goto out;
}
irq = irq_of_parse_and_map(node, 0);
if (irq <= 0) {
dev_err(dev, "irq_of_parse_and_map failed\n");
ret = -EINVAL;
goto out;
}
clk = of_clk_get(node, 0);
if (IS_ERR(clk)) {
dev_err(dev, "of_clk_get failed\n");
ret = PTR_ERR(clk);
goto out;
}
reg_mmc = devm_ioremap_resource(dev, &res_mmc);
if (IS_ERR(reg_mmc)) {
ret = PTR_ERR(reg_mmc);
goto out;
}
mmc_of_parse(mmc);
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
host = mmc_priv(mmc);
host->mmc = mmc;
host->base = reg_mmc;
host->reg_phys = res_mmc.start;
host->timeout = msecs_to_jiffies(1000);
host->sysclk = clk_get_rate(clk);
host->fifo_width = readl(host->base + REG_FEATURE) << 2;
host->dma_chan_tx = of_dma_request_slave_channel(node, "tx");
host->dma_chan_rx = of_dma_request_slave_channel(node, "rx");
spin_lock_init(&host->lock);
mmc->ops = &moxart_ops;
mmc->f_max = DIV_ROUND_CLOSEST(host->sysclk, 2);
mmc->f_min = DIV_ROUND_CLOSEST(host->sysclk, CLK_DIV_MASK * 2);
mmc->ocr_avail = 0xffff00; /* Support 2.0v - 3.6v power. */
if (IS_ERR(host->dma_chan_tx) || IS_ERR(host->dma_chan_rx)) {
dev_dbg(dev, "PIO mode transfer enabled\n");
host->have_dma = false;
} else {
dev_dbg(dev, "DMA channels found (%p,%p)\n",
host->dma_chan_tx, host->dma_chan_rx);
host->have_dma = true;
cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
cfg.direction = DMA_MEM_TO_DEV;
cfg.src_addr = 0;
cfg.dst_addr = host->reg_phys + REG_DATA_WINDOW;
dmaengine_slave_config(host->dma_chan_tx, &cfg);
cfg.direction = DMA_DEV_TO_MEM;
cfg.src_addr = host->reg_phys + REG_DATA_WINDOW;
cfg.dst_addr = 0;
dmaengine_slave_config(host->dma_chan_rx, &cfg);
}
switch ((readl(host->base + REG_BUS_WIDTH) >> 3) & 3) {
case 1:
mmc->caps |= MMC_CAP_4_BIT_DATA;
break;
case 2:
mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
break;
default:
break;
}
writel(0, host->base + REG_INTERRUPT_MASK);
writel(CMD_SDC_RESET, host->base + REG_COMMAND);
for (i = 0; i < MAX_RETRIES; i++) {
if (!(readl(host->base + REG_COMMAND) & CMD_SDC_RESET))
break;
udelay(5);
}
ret = devm_request_irq(dev, irq, moxart_irq, 0, "moxart-mmc", host);
if (ret)
goto out;
dev_set_drvdata(dev, mmc);
mmc_add_host(mmc);
dev_dbg(dev, "IRQ=%d, FIFO is %d bytes\n", irq, host->fifo_width);
return 0;
out:
if (mmc)
mmc_free_host(mmc);
return ret;
}
static int moxart_remove(struct platform_device *pdev)
{
struct mmc_host *mmc = dev_get_drvdata(&pdev->dev);
struct moxart_host *host = mmc_priv(mmc);
dev_set_drvdata(&pdev->dev, NULL);
if (mmc) {
if (!IS_ERR(host->dma_chan_tx))
dma_release_channel(host->dma_chan_tx);
if (!IS_ERR(host->dma_chan_rx))
dma_release_channel(host->dma_chan_rx);
mmc_remove_host(mmc);
mmc_free_host(mmc);
writel(0, host->base + REG_INTERRUPT_MASK);
writel(0, host->base + REG_POWER_CONTROL);
writel(readl(host->base + REG_CLOCK_CONTROL) | CLK_OFF,
host->base + REG_CLOCK_CONTROL);
}
kfree(host);
return 0;
}
static const struct of_device_id moxart_mmc_match[] = {
{ .compatible = "moxa,moxart-mmc" },
{ .compatible = "faraday,ftsdc010" },
{ }
};
static struct platform_driver moxart_mmc_driver = {
.probe = moxart_probe,
.remove = moxart_remove,
.driver = {
.name = "mmc-moxart",
.owner = THIS_MODULE,
.of_match_table = moxart_mmc_match,
},
};
module_platform_driver(moxart_mmc_driver);
MODULE_ALIAS("platform:mmc-moxart");
MODULE_DESCRIPTION("MOXA ART MMC driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Jonas Jensen <jonas.jensen@gmail.com>");

View file

@ -354,6 +354,20 @@ static irqreturn_t mvsd_irq(int irq, void *dev)
intr_status, mvsd_read(MVSD_NOR_INTR_EN), intr_status, mvsd_read(MVSD_NOR_INTR_EN),
mvsd_read(MVSD_HW_STATE)); mvsd_read(MVSD_HW_STATE));
/*
* It looks like, SDIO IP can issue one late, spurious irq
* although all irqs should be disabled. To work around this,
* bail out early, if we didn't expect any irqs to occur.
*/
if (!mvsd_read(MVSD_NOR_INTR_EN) && !mvsd_read(MVSD_ERR_INTR_EN)) {
dev_dbg(host->dev, "spurious irq detected intr 0x%04x intr_en 0x%04x erri 0x%04x erri_en 0x%04x\n",
mvsd_read(MVSD_NOR_INTR_STATUS),
mvsd_read(MVSD_NOR_INTR_EN),
mvsd_read(MVSD_ERR_INTR_STATUS),
mvsd_read(MVSD_ERR_INTR_EN));
return IRQ_HANDLED;
}
spin_lock(&host->lock); spin_lock(&host->lock);
/* PIO handling, if needed. Messy business... */ /* PIO handling, if needed. Messy business... */
@ -801,10 +815,10 @@ static int mvsd_probe(struct platform_device *pdev)
goto out; goto out;
if (!(mmc->caps & MMC_CAP_NEEDS_POLL)) if (!(mmc->caps & MMC_CAP_NEEDS_POLL))
dev_notice(&pdev->dev, "using GPIO for card detection\n"); dev_dbg(&pdev->dev, "using GPIO for card detection\n");
else else
dev_notice(&pdev->dev, dev_dbg(&pdev->dev, "lacking card detect (fall back to polling)\n");
"lacking card detect (fall back to polling)\n");
return 0; return 0;
out: out:

View file

@ -124,9 +124,8 @@ enum mxcmci_type {
struct mxcmci_host { struct mxcmci_host {
struct mmc_host *mmc; struct mmc_host *mmc;
struct resource *res;
void __iomem *base; void __iomem *base;
int irq; dma_addr_t phys_base;
int detect_irq; int detect_irq;
struct dma_chan *dma; struct dma_chan *dma;
struct dma_async_tx_descriptor *desc; struct dma_async_tx_descriptor *desc;
@ -154,8 +153,6 @@ struct mxcmci_host {
struct work_struct datawork; struct work_struct datawork;
spinlock_t lock; spinlock_t lock;
struct regulator *vcc;
int burstlen; int burstlen;
int dmareq; int dmareq;
struct dma_slave_config dma_slave_config; struct dma_slave_config dma_slave_config;
@ -241,37 +238,15 @@ static inline void mxcmci_writew(struct mxcmci_host *host, u16 val, int reg)
static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios); static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios);
static inline void mxcmci_init_ocr(struct mxcmci_host *host) static void mxcmci_set_power(struct mxcmci_host *host, unsigned int vdd)
{ {
host->vcc = regulator_get(mmc_dev(host->mmc), "vmmc"); if (!IS_ERR(host->mmc->supply.vmmc)) {
if (host->power_mode == MMC_POWER_UP)
if (IS_ERR(host->vcc)) { mmc_regulator_set_ocr(host->mmc,
host->vcc = NULL; host->mmc->supply.vmmc, vdd);
} else { else if (host->power_mode == MMC_POWER_OFF)
host->mmc->ocr_avail = mmc_regulator_get_ocrmask(host->vcc); mmc_regulator_set_ocr(host->mmc,
if (host->pdata && host->pdata->ocr_avail) host->mmc->supply.vmmc, 0);
dev_warn(mmc_dev(host->mmc),
"pdata->ocr_avail will not be used\n");
}
if (host->vcc == NULL) {
/* fall-back to platform data */
if (host->pdata && host->pdata->ocr_avail)
host->mmc->ocr_avail = host->pdata->ocr_avail;
else
host->mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
}
}
static inline void mxcmci_set_power(struct mxcmci_host *host,
unsigned char power_mode,
unsigned int vdd)
{
if (host->vcc) {
if (power_mode == MMC_POWER_UP)
mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
else if (power_mode == MMC_POWER_OFF)
mmc_regulator_set_ocr(host->mmc, host->vcc, 0);
} }
if (host->pdata && host->pdata->setpower) if (host->pdata && host->pdata->setpower)
@ -299,7 +274,6 @@ static void mxcmci_softreset(struct mxcmci_host *host)
mxcmci_writew(host, 0xff, MMC_REG_RES_TO); mxcmci_writew(host, 0xff, MMC_REG_RES_TO);
} }
static int mxcmci_setup_dma(struct mmc_host *mmc);
#if IS_ENABLED(CONFIG_PPC_MPC512x) #if IS_ENABLED(CONFIG_PPC_MPC512x)
static inline void buffer_swap32(u32 *buf, int len) static inline void buffer_swap32(u32 *buf, int len)
@ -868,8 +842,8 @@ static int mxcmci_setup_dma(struct mmc_host *mmc)
struct mxcmci_host *host = mmc_priv(mmc); struct mxcmci_host *host = mmc_priv(mmc);
struct dma_slave_config *config = &host->dma_slave_config; struct dma_slave_config *config = &host->dma_slave_config;
config->dst_addr = host->res->start + MMC_REG_BUFFER_ACCESS; config->dst_addr = host->phys_base + MMC_REG_BUFFER_ACCESS;
config->src_addr = host->res->start + MMC_REG_BUFFER_ACCESS; config->src_addr = host->phys_base + MMC_REG_BUFFER_ACCESS;
config->dst_addr_width = 4; config->dst_addr_width = 4;
config->src_addr_width = 4; config->src_addr_width = 4;
config->dst_maxburst = host->burstlen; config->dst_maxburst = host->burstlen;
@ -911,8 +885,8 @@ static void mxcmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
host->cmdat &= ~CMD_DAT_CONT_BUS_WIDTH_4; host->cmdat &= ~CMD_DAT_CONT_BUS_WIDTH_4;
if (host->power_mode != ios->power_mode) { if (host->power_mode != ios->power_mode) {
mxcmci_set_power(host, ios->power_mode, ios->vdd);
host->power_mode = ios->power_mode; host->power_mode = ios->power_mode;
mxcmci_set_power(host, ios->vdd);
if (ios->power_mode == MMC_POWER_ON) if (ios->power_mode == MMC_POWER_ON)
host->cmdat |= CMD_DAT_CONT_INIT; host->cmdat |= CMD_DAT_CONT_INIT;
@ -1040,8 +1014,8 @@ static const struct mmc_host_ops mxcmci_ops = {
static int mxcmci_probe(struct platform_device *pdev) static int mxcmci_probe(struct platform_device *pdev)
{ {
struct mmc_host *mmc; struct mmc_host *mmc;
struct mxcmci_host *host = NULL; struct mxcmci_host *host;
struct resource *iores, *r; struct resource *res;
int ret = 0, irq; int ret = 0, irq;
bool dat3_card_detect = false; bool dat3_card_detect = false;
dma_cap_mask_t mask; dma_cap_mask_t mask;
@ -1052,21 +1026,25 @@ static int mxcmci_probe(struct platform_device *pdev)
of_id = of_match_device(mxcmci_of_match, &pdev->dev); of_id = of_match_device(mxcmci_of_match, &pdev->dev);
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (!iores || irq < 0) if (irq < 0)
return -EINVAL; return -EINVAL;
r = request_mem_region(iores->start, resource_size(iores), pdev->name); mmc = mmc_alloc_host(sizeof(*host), &pdev->dev);
if (!r) if (!mmc)
return -EBUSY; return -ENOMEM;
mmc = mmc_alloc_host(sizeof(struct mxcmci_host), &pdev->dev); host = mmc_priv(mmc);
if (!mmc) {
ret = -ENOMEM; host->base = devm_ioremap_resource(&pdev->dev, res);
goto out_release_mem; if (IS_ERR(host->base)) {
ret = PTR_ERR(host->base);
goto out_free;
} }
host->phys_base = res->start;
ret = mmc_of_parse(mmc); ret = mmc_of_parse(mmc);
if (ret) if (ret)
goto out_free; goto out_free;
@ -1084,13 +1062,6 @@ static int mxcmci_probe(struct platform_device *pdev)
mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count; mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
mmc->max_seg_size = mmc->max_req_size; mmc->max_seg_size = mmc->max_req_size;
host = mmc_priv(mmc);
host->base = ioremap(r->start, resource_size(r));
if (!host->base) {
ret = -ENOMEM;
goto out_free;
}
if (of_id) { if (of_id) {
const struct platform_device_id *id_entry = of_id->data; const struct platform_device_id *id_entry = of_id->data;
host->devtype = id_entry->driver_data; host->devtype = id_entry->driver_data;
@ -1112,7 +1083,14 @@ static int mxcmci_probe(struct platform_device *pdev)
&& !of_property_read_bool(pdev->dev.of_node, "cd-gpios")) && !of_property_read_bool(pdev->dev.of_node, "cd-gpios"))
dat3_card_detect = true; dat3_card_detect = true;
mxcmci_init_ocr(host); ret = mmc_regulator_get_supply(mmc);
if (ret) {
if (pdata && ret != -EPROBE_DEFER)
mmc->ocr_avail = pdata->ocr_avail ? :
MMC_VDD_32_33 | MMC_VDD_33_34;
else
goto out_free;
}
if (dat3_card_detect) if (dat3_card_detect)
host->default_irq_mask = host->default_irq_mask =
@ -1120,19 +1098,16 @@ static int mxcmci_probe(struct platform_device *pdev)
else else
host->default_irq_mask = 0; host->default_irq_mask = 0;
host->res = r;
host->irq = irq;
host->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); host->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
if (IS_ERR(host->clk_ipg)) { if (IS_ERR(host->clk_ipg)) {
ret = PTR_ERR(host->clk_ipg); ret = PTR_ERR(host->clk_ipg);
goto out_iounmap; goto out_free;
} }
host->clk_per = devm_clk_get(&pdev->dev, "per"); host->clk_per = devm_clk_get(&pdev->dev, "per");
if (IS_ERR(host->clk_per)) { if (IS_ERR(host->clk_per)) {
ret = PTR_ERR(host->clk_per); ret = PTR_ERR(host->clk_per);
goto out_iounmap; goto out_free;
} }
clk_prepare_enable(host->clk_per); clk_prepare_enable(host->clk_per);
@ -1159,9 +1134,9 @@ static int mxcmci_probe(struct platform_device *pdev)
if (!host->pdata) { if (!host->pdata) {
host->dma = dma_request_slave_channel(&pdev->dev, "rx-tx"); host->dma = dma_request_slave_channel(&pdev->dev, "rx-tx");
} else { } else {
r = platform_get_resource(pdev, IORESOURCE_DMA, 0); res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (r) { if (res) {
host->dmareq = r->start; host->dmareq = res->start;
host->dma_data.peripheral_type = IMX_DMATYPE_SDHC; host->dma_data.peripheral_type = IMX_DMATYPE_SDHC;
host->dma_data.priority = DMA_PRIO_LOW; host->dma_data.priority = DMA_PRIO_LOW;
host->dma_data.dma_request = host->dmareq; host->dma_data.dma_request = host->dmareq;
@ -1178,7 +1153,8 @@ static int mxcmci_probe(struct platform_device *pdev)
INIT_WORK(&host->datawork, mxcmci_datawork); INIT_WORK(&host->datawork, mxcmci_datawork);
ret = request_irq(host->irq, mxcmci_irq, 0, DRIVER_NAME, host); ret = devm_request_irq(&pdev->dev, irq, mxcmci_irq, 0,
dev_name(&pdev->dev), host);
if (ret) if (ret)
goto out_free_dma; goto out_free_dma;
@ -1188,7 +1164,7 @@ static int mxcmci_probe(struct platform_device *pdev)
ret = host->pdata->init(&pdev->dev, mxcmci_detect_irq, ret = host->pdata->init(&pdev->dev, mxcmci_detect_irq,
host->mmc); host->mmc);
if (ret) if (ret)
goto out_free_irq; goto out_free_dma;
} }
init_timer(&host->watchdog); init_timer(&host->watchdog);
@ -1199,20 +1175,17 @@ static int mxcmci_probe(struct platform_device *pdev)
return 0; return 0;
out_free_irq:
free_irq(host->irq, host);
out_free_dma: out_free_dma:
if (host->dma) if (host->dma)
dma_release_channel(host->dma); dma_release_channel(host->dma);
out_clk_put: out_clk_put:
clk_disable_unprepare(host->clk_per); clk_disable_unprepare(host->clk_per);
clk_disable_unprepare(host->clk_ipg); clk_disable_unprepare(host->clk_ipg);
out_iounmap:
iounmap(host->base);
out_free: out_free:
mmc_free_host(mmc); mmc_free_host(mmc);
out_release_mem:
release_mem_region(iores->start, resource_size(iores));
return ret; return ret;
} }
@ -1223,30 +1196,21 @@ static int mxcmci_remove(struct platform_device *pdev)
mmc_remove_host(mmc); mmc_remove_host(mmc);
if (host->vcc)
regulator_put(host->vcc);
if (host->pdata && host->pdata->exit) if (host->pdata && host->pdata->exit)
host->pdata->exit(&pdev->dev, mmc); host->pdata->exit(&pdev->dev, mmc);
free_irq(host->irq, host);
iounmap(host->base);
if (host->dma) if (host->dma)
dma_release_channel(host->dma); dma_release_channel(host->dma);
clk_disable_unprepare(host->clk_per); clk_disable_unprepare(host->clk_per);
clk_disable_unprepare(host->clk_ipg); clk_disable_unprepare(host->clk_ipg);
release_mem_region(host->res->start, resource_size(host->res));
mmc_free_host(mmc); mmc_free_host(mmc);
return 0; return 0;
} }
#ifdef CONFIG_PM static int __maybe_unused mxcmci_suspend(struct device *dev)
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);
@ -1256,7 +1220,7 @@ static int mxcmci_suspend(struct device *dev)
return 0; return 0;
} }
static int mxcmci_resume(struct device *dev) static int __maybe_unused 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);
@ -1266,11 +1230,7 @@ static int mxcmci_resume(struct device *dev)
return 0; return 0;
} }
static const struct dev_pm_ops mxcmci_pm_ops = { static SIMPLE_DEV_PM_OPS(mxcmci_pm_ops, mxcmci_suspend, mxcmci_resume);
.suspend = mxcmci_suspend,
.resume = mxcmci_resume,
};
#endif
static struct platform_driver mxcmci_driver = { static struct platform_driver mxcmci_driver = {
.probe = mxcmci_probe, .probe = mxcmci_probe,
@ -1279,9 +1239,7 @@ static struct platform_driver mxcmci_driver = {
.driver = { .driver = {
.name = DRIVER_NAME, .name = DRIVER_NAME,
.owner = THIS_MODULE, .owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &mxcmci_pm_ops, .pm = &mxcmci_pm_ops,
#endif
.of_match_table = mxcmci_of_match, .of_match_table = mxcmci_of_match,
} }
}; };

View file

@ -70,6 +70,7 @@ struct mxs_mmc_host {
unsigned char bus_width; unsigned char bus_width;
spinlock_t lock; spinlock_t lock;
int sdio_irq_en; int sdio_irq_en;
bool broken_cd;
}; };
static int mxs_mmc_get_cd(struct mmc_host *mmc) static int mxs_mmc_get_cd(struct mmc_host *mmc)
@ -78,6 +79,9 @@ static int mxs_mmc_get_cd(struct mmc_host *mmc)
struct mxs_ssp *ssp = &host->ssp; struct mxs_ssp *ssp = &host->ssp;
int present, ret; int present, ret;
if (host->broken_cd)
return -ENOSYS;
ret = mmc_gpio_get_cd(mmc); ret = mmc_gpio_get_cd(mmc);
if (ret >= 0) if (ret >= 0)
return ret; return ret;
@ -568,6 +572,7 @@ static int mxs_mmc_probe(struct platform_device *pdev)
{ {
const struct of_device_id *of_id = const struct of_device_id *of_id =
of_match_device(mxs_mmc_dt_ids, &pdev->dev); of_match_device(mxs_mmc_dt_ids, &pdev->dev);
struct device_node *np = pdev->dev.of_node;
struct mxs_mmc_host *host; struct mxs_mmc_host *host;
struct mmc_host *mmc; struct mmc_host *mmc;
struct resource *iores; struct resource *iores;
@ -634,6 +639,8 @@ static int mxs_mmc_probe(struct platform_device *pdev)
mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED | mmc->caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED |
MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL; MMC_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL;
host->broken_cd = of_property_read_bool(np, "broken-cd");
mmc->f_min = 400000; mmc->f_min = 400000;
mmc->f_max = 288000000; mmc->f_max = 288000000;

View file

@ -177,7 +177,7 @@ static void mmc_omap_fclk_offdelay(struct mmc_omap_slot *slot)
unsigned long tick_ns; unsigned long tick_ns;
if (slot != NULL && slot->host->fclk_enabled && slot->fclk_freq > 0) { if (slot != NULL && slot->host->fclk_enabled && slot->fclk_freq > 0) {
tick_ns = (1000000000 + slot->fclk_freq - 1) / slot->fclk_freq; tick_ns = DIV_ROUND_UP(NSEC_PER_SEC, slot->fclk_freq);
ndelay(8 * tick_ns); ndelay(8 * tick_ns);
} }
} }
@ -435,7 +435,7 @@ static void mmc_omap_send_stop_work(struct work_struct *work)
struct mmc_data *data = host->stop_data; struct mmc_data *data = host->stop_data;
unsigned long tick_ns; unsigned long tick_ns;
tick_ns = (1000000000 + slot->fclk_freq - 1)/slot->fclk_freq; tick_ns = DIV_ROUND_UP(NSEC_PER_SEC, slot->fclk_freq);
ndelay(8*tick_ns); ndelay(8*tick_ns);
mmc_omap_start_command(host, data->stop); mmc_omap_start_command(host, data->stop);
@ -477,7 +477,7 @@ mmc_omap_send_abort(struct mmc_omap_host *host, int maxloops)
u16 stat = 0; u16 stat = 0;
/* Sending abort takes 80 clocks. Have some extra and round up */ /* Sending abort takes 80 clocks. Have some extra and round up */
timeout = (120*1000000 + slot->fclk_freq - 1)/slot->fclk_freq; timeout = DIV_ROUND_UP(120 * USEC_PER_SEC, slot->fclk_freq);
restarts = 0; restarts = 0;
while (restarts < maxloops) { while (restarts < maxloops) {
OMAP_MMC_WRITE(host, STAT, 0xFFFF); OMAP_MMC_WRITE(host, STAT, 0xFFFF);
@ -677,8 +677,8 @@ mmc_omap_xfer_data(struct mmc_omap_host *host, int write)
if (n > host->buffer_bytes_left) if (n > host->buffer_bytes_left)
n = host->buffer_bytes_left; n = host->buffer_bytes_left;
nwords = n / 2; /* Round up to handle odd number of bytes to transfer */
nwords += n & 1; /* handle odd number of bytes to transfer */ nwords = DIV_ROUND_UP(n, 2);
host->buffer_bytes_left -= n; host->buffer_bytes_left -= n;
host->total_bytes_left -= n; host->total_bytes_left -= n;

View file

@ -31,7 +31,7 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/omap-dma.h> #include <linux/omap-dmaengine.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/mmc/core.h> #include <linux/mmc/core.h>
#include <linux/mmc/mmc.h> #include <linux/mmc/mmc.h>
@ -582,7 +582,7 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)
* - MMC/SD clock coming out of controller > 25MHz * - MMC/SD clock coming out of controller > 25MHz
*/ */
if ((mmc_slot(host).features & HSMMC_HAS_HSPE_SUPPORT) && if ((mmc_slot(host).features & HSMMC_HAS_HSPE_SUPPORT) &&
(ios->timing != MMC_TIMING_UHS_DDR50) && (ios->timing != MMC_TIMING_MMC_DDR52) &&
((OMAP_HSMMC_READ(host->base, CAPA) & HSS) == HSS)) { ((OMAP_HSMMC_READ(host->base, CAPA) & HSS) == HSS)) {
regval = OMAP_HSMMC_READ(host->base, HCTL); regval = OMAP_HSMMC_READ(host->base, HCTL);
if (clkdiv && (clk_get_rate(host->fclk)/clkdiv) > 25000000) if (clkdiv && (clk_get_rate(host->fclk)/clkdiv) > 25000000)
@ -602,7 +602,7 @@ static void omap_hsmmc_set_bus_width(struct omap_hsmmc_host *host)
u32 con; u32 con;
con = OMAP_HSMMC_READ(host->base, CON); con = OMAP_HSMMC_READ(host->base, CON);
if (ios->timing == MMC_TIMING_UHS_DDR50) if (ios->timing == MMC_TIMING_MMC_DDR52)
con |= DDR; /* configure in DDR mode */ con |= DDR; /* configure in DDR mode */
else else
con &= ~DDR; con &= ~DDR;
@ -920,16 +920,17 @@ omap_hsmmc_xfer_done(struct omap_hsmmc_host *host, struct mmc_data *data)
static void static void
omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd) omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd)
{ {
host->cmd = NULL;
if (host->mrq->sbc && (host->cmd == host->mrq->sbc) && if (host->mrq->sbc && (host->cmd == host->mrq->sbc) &&
!host->mrq->sbc->error && !(host->flags & AUTO_CMD23)) { !host->mrq->sbc->error && !(host->flags & AUTO_CMD23)) {
host->cmd = NULL;
omap_hsmmc_start_dma_transfer(host); omap_hsmmc_start_dma_transfer(host);
omap_hsmmc_start_command(host, host->mrq->cmd, omap_hsmmc_start_command(host, host->mrq->cmd,
host->mrq->data); host->mrq->data);
return; return;
} }
host->cmd = NULL;
if (cmd->flags & MMC_RSP_PRESENT) { if (cmd->flags & MMC_RSP_PRESENT) {
if (cmd->flags & MMC_RSP_136) { if (cmd->flags & MMC_RSP_136) {
/* response type 2 */ /* response type 2 */
@ -1851,6 +1852,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
unsigned tx_req, rx_req; unsigned tx_req, rx_req;
struct pinctrl *pinctrl; struct pinctrl *pinctrl;
const struct omap_mmc_of_data *data; const struct omap_mmc_of_data *data;
void __iomem *base;
match = of_match_device(of_match_ptr(omap_mmc_of_match), &pdev->dev); match = of_match_device(of_match_ptr(omap_mmc_of_match), &pdev->dev);
if (match) { if (match) {
@ -1881,9 +1883,9 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
if (res == NULL || irq < 0) if (res == NULL || irq < 0)
return -ENXIO; return -ENXIO;
res = request_mem_region(res->start, resource_size(res), pdev->name); base = devm_ioremap_resource(&pdev->dev, res);
if (res == NULL) if (IS_ERR(base))
return -EBUSY; return PTR_ERR(base);
ret = omap_hsmmc_gpio_init(pdata); ret = omap_hsmmc_gpio_init(pdata);
if (ret) if (ret)
@ -1904,7 +1906,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
host->irq = irq; host->irq = irq;
host->slot_id = 0; host->slot_id = 0;
host->mapbase = res->start + pdata->reg_offset; host->mapbase = res->start + pdata->reg_offset;
host->base = ioremap(host->mapbase, SZ_4K); host->base = base + pdata->reg_offset;
host->power_mode = MMC_POWER_OFF; host->power_mode = MMC_POWER_OFF;
host->next_data.cookie = 1; host->next_data.cookie = 1;
host->pbias_enabled = 0; host->pbias_enabled = 0;
@ -1922,7 +1924,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
spin_lock_init(&host->irq_lock); spin_lock_init(&host->irq_lock);
host->fclk = clk_get(&pdev->dev, "fck"); host->fclk = devm_clk_get(&pdev->dev, "fck");
if (IS_ERR(host->fclk)) { if (IS_ERR(host->fclk)) {
ret = PTR_ERR(host->fclk); ret = PTR_ERR(host->fclk);
host->fclk = NULL; host->fclk = NULL;
@ -1941,7 +1943,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
omap_hsmmc_context_save(host); omap_hsmmc_context_save(host);
host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck"); host->dbclk = devm_clk_get(&pdev->dev, "mmchsdb_fck");
/* /*
* MMC can still work without debounce clock. * MMC can still work without debounce clock.
*/ */
@ -1949,7 +1951,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
host->dbclk = NULL; host->dbclk = NULL;
} else if (clk_prepare_enable(host->dbclk) != 0) { } else if (clk_prepare_enable(host->dbclk) != 0) {
dev_warn(mmc_dev(host->mmc), "Failed to enable debounce clk\n"); dev_warn(mmc_dev(host->mmc), "Failed to enable debounce clk\n");
clk_put(host->dbclk);
host->dbclk = NULL; host->dbclk = NULL;
} }
@ -2018,7 +2019,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
} }
/* Request IRQ for MMC operations */ /* Request IRQ for MMC operations */
ret = request_irq(host->irq, omap_hsmmc_irq, 0, ret = devm_request_irq(&pdev->dev, host->irq, omap_hsmmc_irq, 0,
mmc_hostname(mmc), host); mmc_hostname(mmc), host);
if (ret) { if (ret) {
dev_err(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n"); dev_err(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n");
@ -2029,7 +2030,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
if (pdata->init(&pdev->dev) != 0) { if (pdata->init(&pdev->dev) != 0) {
dev_err(mmc_dev(host->mmc), dev_err(mmc_dev(host->mmc),
"Unable to configure MMC IRQs\n"); "Unable to configure MMC IRQs\n");
goto err_irq_cd_init; goto err_irq;
} }
} }
@ -2044,9 +2045,9 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
/* Request IRQ for card detect */ /* Request IRQ for card detect */
if ((mmc_slot(host).card_detect_irq)) { if ((mmc_slot(host).card_detect_irq)) {
ret = request_threaded_irq(mmc_slot(host).card_detect_irq, ret = devm_request_threaded_irq(&pdev->dev,
NULL, mmc_slot(host).card_detect_irq,
omap_hsmmc_detect, NULL, omap_hsmmc_detect,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
mmc_hostname(mmc), host); mmc_hostname(mmc), host);
if (ret) { if (ret) {
@ -2089,15 +2090,12 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
err_slot_name: err_slot_name:
mmc_remove_host(mmc); mmc_remove_host(mmc);
free_irq(mmc_slot(host).card_detect_irq, host);
err_irq_cd: err_irq_cd:
if (host->use_reg) if (host->use_reg)
omap_hsmmc_reg_put(host); omap_hsmmc_reg_put(host);
err_reg: err_reg:
if (host->pdata->cleanup) if (host->pdata->cleanup)
host->pdata->cleanup(&pdev->dev); host->pdata->cleanup(&pdev->dev);
err_irq_cd_init:
free_irq(host->irq, host);
err_irq: err_irq:
if (host->tx_chan) if (host->tx_chan)
dma_release_channel(host->tx_chan); dma_release_channel(host->tx_chan);
@ -2105,27 +2103,19 @@ err_irq:
dma_release_channel(host->rx_chan); dma_release_channel(host->rx_chan);
pm_runtime_put_sync(host->dev); pm_runtime_put_sync(host->dev);
pm_runtime_disable(host->dev); pm_runtime_disable(host->dev);
clk_put(host->fclk); if (host->dbclk)
if (host->dbclk) {
clk_disable_unprepare(host->dbclk); clk_disable_unprepare(host->dbclk);
clk_put(host->dbclk);
}
err1: err1:
iounmap(host->base);
mmc_free_host(mmc); mmc_free_host(mmc);
err_alloc: err_alloc:
omap_hsmmc_gpio_free(pdata); omap_hsmmc_gpio_free(pdata);
err: err:
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res)
release_mem_region(res->start, resource_size(res));
return ret; return ret;
} }
static int omap_hsmmc_remove(struct platform_device *pdev) static int omap_hsmmc_remove(struct platform_device *pdev)
{ {
struct omap_hsmmc_host *host = platform_get_drvdata(pdev); struct omap_hsmmc_host *host = platform_get_drvdata(pdev);
struct resource *res;
pm_runtime_get_sync(host->dev); pm_runtime_get_sync(host->dev);
mmc_remove_host(host->mmc); mmc_remove_host(host->mmc);
@ -2133,9 +2123,6 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
omap_hsmmc_reg_put(host); omap_hsmmc_reg_put(host);
if (host->pdata->cleanup) if (host->pdata->cleanup)
host->pdata->cleanup(&pdev->dev); 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);
if (host->tx_chan) if (host->tx_chan)
dma_release_channel(host->tx_chan); dma_release_channel(host->tx_chan);
@ -2144,20 +2131,12 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
pm_runtime_put_sync(host->dev); pm_runtime_put_sync(host->dev);
pm_runtime_disable(host->dev); pm_runtime_disable(host->dev);
clk_put(host->fclk); if (host->dbclk)
if (host->dbclk) {
clk_disable_unprepare(host->dbclk); clk_disable_unprepare(host->dbclk);
clk_put(host->dbclk);
}
omap_hsmmc_gpio_free(host->pdata); omap_hsmmc_gpio_free(host->pdata);
iounmap(host->base);
mmc_free_host(host->mmc); mmc_free_host(host->mmc);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res)
release_mem_region(res->start, resource_size(res));
return 0; return 0;
} }

View file

@ -236,6 +236,9 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,
case MMC_RSP_R1: case MMC_RSP_R1:
rsp_type = SD_RSP_TYPE_R1; rsp_type = SD_RSP_TYPE_R1;
break; break;
case MMC_RSP_R1 & ~MMC_RSP_CRC:
rsp_type = SD_RSP_TYPE_R1 | SD_NO_CHECK_CRC7;
break;
case MMC_RSP_R1B: case MMC_RSP_R1B:
rsp_type = SD_RSP_TYPE_R1b; rsp_type = SD_RSP_TYPE_R1b;
break; break;
@ -816,6 +819,7 @@ static int sd_set_timing(struct realtek_pci_sdmmc *host, unsigned char timing)
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CLK_LOW_FREQ, 0); rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CLK_CTL, CLK_LOW_FREQ, 0);
break; break;
case MMC_TIMING_MMC_DDR52:
case MMC_TIMING_UHS_DDR50: case MMC_TIMING_UHS_DDR50:
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG1, rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG1,
0x0C | SD_ASYNC_FIFO_NOT_RST, 0x0C | SD_ASYNC_FIFO_NOT_RST,
@ -896,6 +900,7 @@ static void sdmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
host->vpclk = true; host->vpclk = true;
host->double_clk = false; host->double_clk = false;
break; break;
case MMC_TIMING_MMC_DDR52:
case MMC_TIMING_UHS_DDR50: case MMC_TIMING_UHS_DDR50:
case MMC_TIMING_UHS_SDR25: case MMC_TIMING_UHS_SDR25:
host->ssc_depth = RTSX_SSC_DEPTH_1M; host->ssc_depth = RTSX_SSC_DEPTH_1M;

View file

@ -34,7 +34,8 @@
#include <linux/mfd/rtsx_usb.h> #include <linux/mfd/rtsx_usb.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) #if defined(CONFIG_LEDS_CLASS) || (defined(CONFIG_LEDS_CLASS_MODULE) && \
defined(CONFIG_MMC_REALTEK_USB_MODULE))
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#define RTSX_USB_USE_LEDS_CLASS #define RTSX_USB_USE_LEDS_CLASS
@ -59,7 +60,7 @@ struct rtsx_usb_sdmmc {
unsigned char power_mode; unsigned char power_mode;
#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE) #ifdef RTSX_USB_USE_LEDS_CLASS
struct led_classdev led; struct led_classdev led;
char led_name[32]; char led_name[32];
struct work_struct led_work; struct work_struct led_work;

View file

@ -102,11 +102,19 @@ static void sdhci_acpi_int_hw_reset(struct sdhci_host *host)
} }
static const struct sdhci_ops sdhci_acpi_ops_dflt = { static const struct sdhci_ops sdhci_acpi_ops_dflt = {
.set_clock = sdhci_set_clock,
.enable_dma = sdhci_acpi_enable_dma, .enable_dma = sdhci_acpi_enable_dma,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
}; };
static const struct sdhci_ops sdhci_acpi_ops_int = { static const struct sdhci_ops sdhci_acpi_ops_int = {
.set_clock = sdhci_set_clock,
.enable_dma = sdhci_acpi_enable_dma, .enable_dma = sdhci_acpi_enable_dma,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
.hw_reset = sdhci_acpi_int_hw_reset, .hw_reset = sdhci_acpi_int_hw_reset,
}; };

View file

@ -206,9 +206,13 @@ static void sdhci_bcm_kona_init_74_clocks(struct sdhci_host *host,
} }
static struct sdhci_ops sdhci_bcm_kona_ops = { static struct sdhci_ops sdhci_bcm_kona_ops = {
.set_clock = sdhci_set_clock,
.get_max_clock = sdhci_bcm_kona_get_max_clk, .get_max_clock = sdhci_bcm_kona_get_max_clk,
.get_timeout_clock = sdhci_bcm_kona_get_timeout_clock, .get_timeout_clock = sdhci_bcm_kona_get_timeout_clock,
.platform_send_init_74_clocks = sdhci_bcm_kona_init_74_clocks, .platform_send_init_74_clocks = sdhci_bcm_kona_init_74_clocks,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
.card_event = sdhci_bcm_kona_card_event, .card_event = sdhci_bcm_kona_card_event,
}; };

View file

@ -131,8 +131,12 @@ static const struct sdhci_ops bcm2835_sdhci_ops = {
.read_l = bcm2835_sdhci_readl, .read_l = bcm2835_sdhci_readl,
.read_w = bcm2835_sdhci_readw, .read_w = bcm2835_sdhci_readw,
.read_b = bcm2835_sdhci_readb, .read_b = bcm2835_sdhci_readb,
.set_clock = sdhci_set_clock,
.get_max_clock = sdhci_pltfm_clk_get_max_clock, .get_max_clock = sdhci_pltfm_clk_get_max_clock,
.get_min_clock = bcm2835_sdhci_get_min_clock, .get_min_clock = bcm2835_sdhci_get_min_clock,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
}; };
static const struct sdhci_pltfm_data bcm2835_sdhci_pdata = { static const struct sdhci_pltfm_data bcm2835_sdhci_pdata = {

View file

@ -30,13 +30,12 @@ static void sdhci_cns3xxx_set_clock(struct sdhci_host *host, unsigned int clock)
u16 clk; u16 clk;
unsigned long timeout; unsigned long timeout;
if (clock == host->clock) host->mmc->actual_clock = 0;
return;
sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
if (clock == 0) if (clock == 0)
goto out; return;
while (host->max_clk / div > clock) { while (host->max_clk / div > clock) {
/* /*
@ -75,13 +74,14 @@ static void sdhci_cns3xxx_set_clock(struct sdhci_host *host, unsigned int clock)
clk |= SDHCI_CLOCK_CARD_EN; clk |= SDHCI_CLOCK_CARD_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
out:
host->clock = clock;
} }
static const struct sdhci_ops sdhci_cns3xxx_ops = { static const struct sdhci_ops sdhci_cns3xxx_ops = {
.get_max_clock = sdhci_cns3xxx_get_max_clk, .get_max_clock = sdhci_cns3xxx_get_max_clk,
.set_clock = sdhci_cns3xxx_set_clock, .set_clock = sdhci_cns3xxx_set_clock,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
}; };
static const struct sdhci_pltfm_data sdhci_cns3xxx_pdata = { static const struct sdhci_pltfm_data sdhci_cns3xxx_pdata = {
@ -90,8 +90,7 @@ static const struct sdhci_pltfm_data sdhci_cns3xxx_pdata = {
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
SDHCI_QUIRK_INVERTED_WRITE_PROTECT | SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
SDHCI_QUIRK_NONSTANDARD_CLOCK,
}; };
static int sdhci_cns3xxx_probe(struct platform_device *pdev) static int sdhci_cns3xxx_probe(struct platform_device *pdev)

View file

@ -21,28 +21,17 @@
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/gpio.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/mmc/host.h> #include <linux/mmc/host.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_gpio.h>
#include "sdhci-pltfm.h" #include "sdhci-pltfm.h"
struct sdhci_dove_priv { struct sdhci_dove_priv {
struct clk *clk; struct clk *clk;
int gpio_cd;
}; };
static irqreturn_t sdhci_dove_carddetect_irq(int irq, void *data)
{
struct sdhci_host *host = data;
tasklet_schedule(&host->card_tasklet);
return IRQ_HANDLED;
}
static u16 sdhci_dove_readw(struct sdhci_host *host, int reg) static u16 sdhci_dove_readw(struct sdhci_host *host, int reg)
{ {
u16 ret; u16 ret;
@ -60,8 +49,6 @@ static u16 sdhci_dove_readw(struct sdhci_host *host, int reg)
static u32 sdhci_dove_readl(struct sdhci_host *host, int reg) static u32 sdhci_dove_readl(struct sdhci_host *host, int reg)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_dove_priv *priv = pltfm_host->priv;
u32 ret; u32 ret;
ret = readl(host->ioaddr + reg); ret = readl(host->ioaddr + reg);
@ -71,14 +58,6 @@ static u32 sdhci_dove_readl(struct sdhci_host *host, int reg)
/* Mask the support for 3.0V */ /* Mask the support for 3.0V */
ret &= ~SDHCI_CAN_VDD_300; ret &= ~SDHCI_CAN_VDD_300;
break; break;
case SDHCI_PRESENT_STATE:
if (gpio_is_valid(priv->gpio_cd)) {
if (gpio_get_value(priv->gpio_cd) == 0)
ret |= SDHCI_CARD_PRESENT;
else
ret &= ~SDHCI_CARD_PRESENT;
}
break;
} }
return ret; return ret;
} }
@ -86,6 +65,10 @@ static u32 sdhci_dove_readl(struct sdhci_host *host, int reg)
static const struct sdhci_ops sdhci_dove_ops = { static const struct sdhci_ops sdhci_dove_ops = {
.read_w = sdhci_dove_readw, .read_w = sdhci_dove_readw,
.read_l = sdhci_dove_readl, .read_l = sdhci_dove_readl,
.set_clock = sdhci_set_clock,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
}; };
static const struct sdhci_pltfm_data sdhci_dove_pdata = { static const struct sdhci_pltfm_data sdhci_dove_pdata = {
@ -113,28 +96,9 @@ static int sdhci_dove_probe(struct platform_device *pdev)
priv->clk = devm_clk_get(&pdev->dev, NULL); priv->clk = devm_clk_get(&pdev->dev, NULL);
if (pdev->dev.of_node) {
priv->gpio_cd = of_get_named_gpio(pdev->dev.of_node,
"cd-gpios", 0);
} else {
priv->gpio_cd = -EINVAL;
}
if (gpio_is_valid(priv->gpio_cd)) {
ret = gpio_request(priv->gpio_cd, "sdhci-cd");
if (ret) {
dev_err(&pdev->dev, "card detect gpio request failed: %d\n",
ret);
return ret;
}
gpio_direction_input(priv->gpio_cd);
}
host = sdhci_pltfm_init(pdev, &sdhci_dove_pdata, 0); host = sdhci_pltfm_init(pdev, &sdhci_dove_pdata, 0);
if (IS_ERR(host)) { if (IS_ERR(host))
ret = PTR_ERR(host); return PTR_ERR(host);
goto err_sdhci_pltfm_init;
}
pltfm_host = sdhci_priv(host); pltfm_host = sdhci_priv(host);
pltfm_host->priv = priv; pltfm_host->priv = priv;
@ -142,39 +106,20 @@ static int sdhci_dove_probe(struct platform_device *pdev)
if (!IS_ERR(priv->clk)) if (!IS_ERR(priv->clk))
clk_prepare_enable(priv->clk); clk_prepare_enable(priv->clk);
sdhci_get_of_property(pdev); ret = mmc_of_parse(host->mmc);
if (ret)
goto err_sdhci_add;
ret = sdhci_add_host(host); ret = sdhci_add_host(host);
if (ret) if (ret)
goto err_sdhci_add; goto err_sdhci_add;
/*
* We must request the IRQ after sdhci_add_host(), as the tasklet only
* gets setup in sdhci_add_host() and we oops.
*/
if (gpio_is_valid(priv->gpio_cd)) {
ret = request_irq(gpio_to_irq(priv->gpio_cd),
sdhci_dove_carddetect_irq,
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
mmc_hostname(host->mmc), host);
if (ret) {
dev_err(&pdev->dev, "card detect irq request failed: %d\n",
ret);
goto err_request_irq;
}
}
return 0; return 0;
err_request_irq:
sdhci_remove_host(host, 0);
err_sdhci_add: err_sdhci_add:
if (!IS_ERR(priv->clk)) if (!IS_ERR(priv->clk))
clk_disable_unprepare(priv->clk); clk_disable_unprepare(priv->clk);
sdhci_pltfm_free(pdev); sdhci_pltfm_free(pdev);
err_sdhci_pltfm_init:
if (gpio_is_valid(priv->gpio_cd))
gpio_free(priv->gpio_cd);
return ret; return ret;
} }
@ -186,11 +131,6 @@ static int sdhci_dove_remove(struct platform_device *pdev)
sdhci_pltfm_unregister(pdev); sdhci_pltfm_unregister(pdev);
if (gpio_is_valid(priv->gpio_cd)) {
free_irq(gpio_to_irq(priv->gpio_cd), host);
gpio_free(priv->gpio_cd);
}
if (!IS_ERR(priv->clk)) if (!IS_ERR(priv->clk))
clk_disable_unprepare(priv->clk); clk_disable_unprepare(priv->clk);

View file

@ -160,7 +160,6 @@ struct pltfm_imx_data {
MULTIBLK_IN_PROCESS, /* exact multiblock cmd in process */ MULTIBLK_IN_PROCESS, /* exact multiblock cmd in process */
WAIT_FOR_INT, /* sent CMD12, waiting for response INT */ WAIT_FOR_INT, /* sent CMD12, waiting for response INT */
} multiblock_status; } multiblock_status;
u32 uhs_mode;
u32 is_ddr; u32 is_ddr;
}; };
@ -382,7 +381,6 @@ static u16 esdhc_readw_le(struct sdhci_host *host, int reg)
if (val & ESDHC_MIX_CTRL_SMPCLK_SEL) if (val & ESDHC_MIX_CTRL_SMPCLK_SEL)
ret |= SDHCI_CTRL_TUNED_CLK; ret |= SDHCI_CTRL_TUNED_CLK;
ret |= (imx_data->uhs_mode & SDHCI_CTRL_UHS_MASK);
ret &= ~SDHCI_CTRL_PRESET_VAL_ENABLE; ret &= ~SDHCI_CTRL_PRESET_VAL_ENABLE;
return ret; return ret;
@ -429,7 +427,6 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
else else
new_val &= ~ESDHC_VENDOR_SPEC_VSELECT; new_val &= ~ESDHC_VENDOR_SPEC_VSELECT;
writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC); writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC);
imx_data->uhs_mode = val & SDHCI_CTRL_UHS_MASK;
if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) { if (imx_data->socdata->flags & ESDHC_FLAG_MAN_TUNING) {
new_val = readl(host->ioaddr + ESDHC_MIX_CTRL); new_val = readl(host->ioaddr + ESDHC_MIX_CTRL);
if (val & SDHCI_CTRL_TUNED_CLK) if (val & SDHCI_CTRL_TUNED_CLK)
@ -600,12 +597,14 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
u32 temp, val; u32 temp, val;
if (clock == 0) { if (clock == 0) {
host->mmc->actual_clock = 0;
if (esdhc_is_usdhc(imx_data)) { if (esdhc_is_usdhc(imx_data)) {
val = readl(host->ioaddr + ESDHC_VENDOR_SPEC); val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON, writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
host->ioaddr + ESDHC_VENDOR_SPEC); host->ioaddr + ESDHC_VENDOR_SPEC);
} }
goto out; return;
} }
if (esdhc_is_usdhc(imx_data) && !imx_data->is_ddr) if (esdhc_is_usdhc(imx_data) && !imx_data->is_ddr)
@ -645,8 +644,6 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
} }
mdelay(1); mdelay(1);
out:
host->clock = clock;
} }
static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host) static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
@ -668,7 +665,7 @@ static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
return -ENOSYS; return -ENOSYS;
} }
static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width) static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width)
{ {
u32 ctrl; u32 ctrl;
@ -686,8 +683,6 @@ static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width)
esdhc_clrset_le(host, ESDHC_CTRL_BUSWIDTH_MASK, ctrl, esdhc_clrset_le(host, ESDHC_CTRL_BUSWIDTH_MASK, ctrl,
SDHCI_HOST_CONTROL); SDHCI_HOST_CONTROL);
return 0;
} }
static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val) static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val)
@ -697,6 +692,7 @@ static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val)
/* FIXME: delay a bit for card to be ready for next tuning due to errors */ /* FIXME: delay a bit for card to be ready for next tuning due to errors */
mdelay(1); mdelay(1);
/* This is balanced by the runtime put in sdhci_tasklet_finish */
pm_runtime_get_sync(host->mmc->parent); pm_runtime_get_sync(host->mmc->parent);
reg = readl(host->ioaddr + ESDHC_MIX_CTRL); reg = readl(host->ioaddr + ESDHC_MIX_CTRL);
reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL | reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL |
@ -713,13 +709,12 @@ static void esdhc_request_done(struct mmc_request *mrq)
complete(&mrq->completion); complete(&mrq->completion);
} }
static int esdhc_send_tuning_cmd(struct sdhci_host *host, u32 opcode) static int esdhc_send_tuning_cmd(struct sdhci_host *host, u32 opcode,
struct scatterlist *sg)
{ {
struct mmc_command cmd = {0}; struct mmc_command cmd = {0};
struct mmc_request mrq = {NULL}; struct mmc_request mrq = {NULL};
struct mmc_data data = {0}; struct mmc_data data = {0};
struct scatterlist sg;
char tuning_pattern[ESDHC_TUNING_BLOCK_PATTERN_LEN];
cmd.opcode = opcode; cmd.opcode = opcode;
cmd.arg = 0; cmd.arg = 0;
@ -728,11 +723,9 @@ static int esdhc_send_tuning_cmd(struct sdhci_host *host, u32 opcode)
data.blksz = ESDHC_TUNING_BLOCK_PATTERN_LEN; data.blksz = ESDHC_TUNING_BLOCK_PATTERN_LEN;
data.blocks = 1; data.blocks = 1;
data.flags = MMC_DATA_READ; data.flags = MMC_DATA_READ;
data.sg = &sg; data.sg = sg;
data.sg_len = 1; data.sg_len = 1;
sg_init_one(&sg, tuning_pattern, sizeof(tuning_pattern));
mrq.cmd = &cmd; mrq.cmd = &cmd;
mrq.cmd->mrq = &mrq; mrq.cmd->mrq = &mrq;
mrq.data = &data; mrq.data = &data;
@ -742,14 +735,12 @@ static int esdhc_send_tuning_cmd(struct sdhci_host *host, u32 opcode)
mrq.done = esdhc_request_done; mrq.done = esdhc_request_done;
init_completion(&(mrq.completion)); init_completion(&(mrq.completion));
disable_irq(host->irq); spin_lock_irq(&host->lock);
spin_lock(&host->lock);
host->mrq = &mrq; host->mrq = &mrq;
sdhci_send_command(host, mrq.cmd); sdhci_send_command(host, mrq.cmd);
spin_unlock(&host->lock); spin_unlock_irq(&host->lock);
enable_irq(host->irq);
wait_for_completion(&mrq.completion); wait_for_completion(&mrq.completion);
@ -772,13 +763,21 @@ static void esdhc_post_tuning(struct sdhci_host *host)
static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode) static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
{ {
struct scatterlist sg;
char *tuning_pattern;
int min, max, avg, ret; int min, max, avg, ret;
tuning_pattern = kmalloc(ESDHC_TUNING_BLOCK_PATTERN_LEN, GFP_KERNEL);
if (!tuning_pattern)
return -ENOMEM;
sg_init_one(&sg, tuning_pattern, ESDHC_TUNING_BLOCK_PATTERN_LEN);
/* find the mininum delay first which can pass tuning */ /* find the mininum delay first which can pass tuning */
min = ESDHC_TUNE_CTRL_MIN; min = ESDHC_TUNE_CTRL_MIN;
while (min < ESDHC_TUNE_CTRL_MAX) { while (min < ESDHC_TUNE_CTRL_MAX) {
esdhc_prepare_tuning(host, min); esdhc_prepare_tuning(host, min);
if (!esdhc_send_tuning_cmd(host, opcode)) if (!esdhc_send_tuning_cmd(host, opcode, &sg))
break; break;
min += ESDHC_TUNE_CTRL_STEP; min += ESDHC_TUNE_CTRL_STEP;
} }
@ -787,7 +786,7 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
max = min + ESDHC_TUNE_CTRL_STEP; max = min + ESDHC_TUNE_CTRL_STEP;
while (max < ESDHC_TUNE_CTRL_MAX) { while (max < ESDHC_TUNE_CTRL_MAX) {
esdhc_prepare_tuning(host, max); esdhc_prepare_tuning(host, max);
if (esdhc_send_tuning_cmd(host, opcode)) { if (esdhc_send_tuning_cmd(host, opcode, &sg)) {
max -= ESDHC_TUNE_CTRL_STEP; max -= ESDHC_TUNE_CTRL_STEP;
break; break;
} }
@ -797,9 +796,11 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
/* use average delay to get the best timing */ /* use average delay to get the best timing */
avg = (min + max) / 2; avg = (min + max) / 2;
esdhc_prepare_tuning(host, avg); esdhc_prepare_tuning(host, avg);
ret = esdhc_send_tuning_cmd(host, opcode); ret = esdhc_send_tuning_cmd(host, opcode, &sg);
esdhc_post_tuning(host); esdhc_post_tuning(host);
kfree(tuning_pattern);
dev_dbg(mmc_dev(host->mmc), "tunning %s at 0x%x ret %d\n", dev_dbg(mmc_dev(host->mmc), "tunning %s at 0x%x ret %d\n",
ret ? "failed" : "passed", avg, ret); ret ? "failed" : "passed", avg, ret);
@ -837,28 +838,21 @@ static int esdhc_change_pinstate(struct sdhci_host *host,
return pinctrl_select_state(imx_data->pinctrl, pinctrl); return pinctrl_select_state(imx_data->pinctrl, pinctrl);
} }
static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = pltfm_host->priv; struct pltfm_imx_data *imx_data = pltfm_host->priv;
struct esdhc_platform_data *boarddata = &imx_data->boarddata; struct esdhc_platform_data *boarddata = &imx_data->boarddata;
switch (uhs) { switch (timing) {
case MMC_TIMING_UHS_SDR12: case MMC_TIMING_UHS_SDR12:
imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR12;
break;
case MMC_TIMING_UHS_SDR25: case MMC_TIMING_UHS_SDR25:
imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR25;
break;
case MMC_TIMING_UHS_SDR50: case MMC_TIMING_UHS_SDR50:
imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR50;
break;
case MMC_TIMING_UHS_SDR104: case MMC_TIMING_UHS_SDR104:
case MMC_TIMING_MMC_HS200: case MMC_TIMING_MMC_HS200:
imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR104;
break; break;
case MMC_TIMING_UHS_DDR50: case MMC_TIMING_UHS_DDR50:
imx_data->uhs_mode = SDHCI_CTRL_UHS_DDR50; case MMC_TIMING_MMC_DDR52:
writel(readl(host->ioaddr + ESDHC_MIX_CTRL) | writel(readl(host->ioaddr + ESDHC_MIX_CTRL) |
ESDHC_MIX_CTRL_DDREN, ESDHC_MIX_CTRL_DDREN,
host->ioaddr + ESDHC_MIX_CTRL); host->ioaddr + ESDHC_MIX_CTRL);
@ -875,7 +869,15 @@ static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
break; break;
} }
return esdhc_change_pinstate(host, uhs); esdhc_change_pinstate(host, timing);
}
static void esdhc_reset(struct sdhci_host *host, u8 mask)
{
sdhci_reset(host, mask);
sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
} }
static struct sdhci_ops sdhci_esdhc_ops = { static struct sdhci_ops sdhci_esdhc_ops = {
@ -888,8 +890,9 @@ static struct sdhci_ops sdhci_esdhc_ops = {
.get_max_clock = esdhc_pltfm_get_max_clock, .get_max_clock = esdhc_pltfm_get_max_clock,
.get_min_clock = esdhc_pltfm_get_min_clock, .get_min_clock = esdhc_pltfm_get_min_clock,
.get_ro = esdhc_pltfm_get_ro, .get_ro = esdhc_pltfm_get_ro,
.platform_bus_width = esdhc_pltfm_bus_width, .set_bus_width = esdhc_pltfm_set_bus_width,
.set_uhs_signaling = esdhc_set_uhs_signaling, .set_uhs_signaling = esdhc_set_uhs_signaling,
.reset = esdhc_reset,
}; };
static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = { static const struct sdhci_pltfm_data sdhci_esdhc_imx_pdata = {
@ -1170,8 +1173,10 @@ static int sdhci_esdhc_runtime_suspend(struct device *dev)
ret = sdhci_runtime_suspend_host(host); ret = sdhci_runtime_suspend_host(host);
clk_disable_unprepare(imx_data->clk_per); if (!sdhci_sdio_irq_enabled(host)) {
clk_disable_unprepare(imx_data->clk_ipg); clk_disable_unprepare(imx_data->clk_per);
clk_disable_unprepare(imx_data->clk_ipg);
}
clk_disable_unprepare(imx_data->clk_ahb); clk_disable_unprepare(imx_data->clk_ahb);
return ret; return ret;
@ -1183,8 +1188,10 @@ static int sdhci_esdhc_runtime_resume(struct device *dev)
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct pltfm_imx_data *imx_data = pltfm_host->priv; struct pltfm_imx_data *imx_data = pltfm_host->priv;
clk_prepare_enable(imx_data->clk_per); if (!sdhci_sdio_irq_enabled(host)) {
clk_prepare_enable(imx_data->clk_ipg); clk_prepare_enable(imx_data->clk_per);
clk_prepare_enable(imx_data->clk_ipg);
}
clk_prepare_enable(imx_data->clk_ahb); clk_prepare_enable(imx_data->clk_ahb);
return sdhci_runtime_resume_host(host); return sdhci_runtime_resume_host(host);

View file

@ -20,10 +20,8 @@
#define ESDHC_DEFAULT_QUIRKS (SDHCI_QUIRK_FORCE_BLK_SZ_2048 | \ #define ESDHC_DEFAULT_QUIRKS (SDHCI_QUIRK_FORCE_BLK_SZ_2048 | \
SDHCI_QUIRK_NO_BUSY_IRQ | \ SDHCI_QUIRK_NO_BUSY_IRQ | \
SDHCI_QUIRK_NONSTANDARD_CLOCK | \
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | \ SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | \
SDHCI_QUIRK_PIO_NEEDS_DELAY | \ SDHCI_QUIRK_PIO_NEEDS_DELAY)
SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
#define ESDHC_SYSTEM_CONTROL 0x2c #define ESDHC_SYSTEM_CONTROL 0x2c
#define ESDHC_CLOCK_MASK 0x0000fff0 #define ESDHC_CLOCK_MASK 0x0000fff0

View file

@ -52,8 +52,12 @@ static unsigned int sdhci_arasan_get_timeout_clock(struct sdhci_host *host)
} }
static struct sdhci_ops sdhci_arasan_ops = { static struct sdhci_ops sdhci_arasan_ops = {
.set_clock = sdhci_set_clock,
.get_max_clock = sdhci_pltfm_clk_get_max_clock, .get_max_clock = sdhci_pltfm_clk_get_max_clock,
.get_timeout_clock = sdhci_arasan_get_timeout_clock, .get_timeout_clock = sdhci_arasan_get_timeout_clock,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
}; };
static struct sdhci_pltfm_data sdhci_arasan_pdata = { static struct sdhci_pltfm_data sdhci_arasan_pdata = {

View file

@ -199,13 +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 pre_div = 2;
int div = 1; int div = 1;
u32 temp; u32 temp;
host->mmc->actual_clock = 0;
if (clock == 0) if (clock == 0)
goto out; return;
/* 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")) {
@ -238,24 +239,8 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
| (pre_div << ESDHC_PREDIV_SHIFT)); | (pre_div << ESDHC_PREDIV_SHIFT));
sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL); sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
mdelay(1); mdelay(1);
out:
host->clock = clock;
} }
#ifdef CONFIG_PM
static u32 esdhc_proctl;
static void esdhc_of_suspend(struct sdhci_host *host)
{
esdhc_proctl = sdhci_be32bs_readl(host, SDHCI_HOST_CONTROL);
}
static void esdhc_of_resume(struct sdhci_host *host)
{
esdhc_of_enable_dma(host);
sdhci_be32bs_writel(host, esdhc_proctl, SDHCI_HOST_CONTROL);
}
#endif
static void esdhc_of_platform_init(struct sdhci_host *host) static void esdhc_of_platform_init(struct sdhci_host *host)
{ {
u32 vvn; u32 vvn;
@ -269,7 +254,7 @@ static void esdhc_of_platform_init(struct sdhci_host *host)
host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ; host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ;
} }
static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width) static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width)
{ {
u32 ctrl; u32 ctrl;
@ -289,8 +274,6 @@ static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width)
clrsetbits_be32(host->ioaddr + SDHCI_HOST_CONTROL, clrsetbits_be32(host->ioaddr + SDHCI_HOST_CONTROL,
ESDHC_CTRL_BUSWIDTH_MASK, ctrl); ESDHC_CTRL_BUSWIDTH_MASK, ctrl);
return 0;
} }
static const struct sdhci_ops sdhci_esdhc_ops = { static const struct sdhci_ops sdhci_esdhc_ops = {
@ -305,14 +288,47 @@ static const struct sdhci_ops sdhci_esdhc_ops = {
.get_max_clock = esdhc_of_get_max_clock, .get_max_clock = esdhc_of_get_max_clock,
.get_min_clock = esdhc_of_get_min_clock, .get_min_clock = esdhc_of_get_min_clock,
.platform_init = esdhc_of_platform_init, .platform_init = esdhc_of_platform_init,
#ifdef CONFIG_PM
.platform_suspend = esdhc_of_suspend,
.platform_resume = esdhc_of_resume,
#endif
.adma_workaround = esdhci_of_adma_workaround, .adma_workaround = esdhci_of_adma_workaround,
.platform_bus_width = esdhc_pltfm_bus_width, .set_bus_width = esdhc_pltfm_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
}; };
#ifdef CONFIG_PM
static u32 esdhc_proctl;
static int esdhc_of_suspend(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
esdhc_proctl = sdhci_be32bs_readl(host, SDHCI_HOST_CONTROL);
return sdhci_suspend_host(host);
}
static int esdhc_of_resume(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
int ret = sdhci_resume_host(host);
if (ret == 0) {
/* Isn't this already done by sdhci_resume_host() ? --rmk */
esdhc_of_enable_dma(host);
sdhci_be32bs_writel(host, esdhc_proctl, SDHCI_HOST_CONTROL);
}
return ret;
}
static const struct dev_pm_ops esdhc_pmops = {
.suspend = esdhc_of_suspend,
.resume = esdhc_of_resume,
};
#define ESDHC_PMOPS (&esdhc_pmops)
#else
#define ESDHC_PMOPS NULL
#endif
static const struct sdhci_pltfm_data sdhci_esdhc_pdata = { static const struct sdhci_pltfm_data sdhci_esdhc_pdata = {
/* /*
* card detection could be handled via GPIO * card detection could be handled via GPIO
@ -374,7 +390,7 @@ static struct platform_driver sdhci_esdhc_driver = {
.name = "sdhci-esdhc", .name = "sdhci-esdhc",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = sdhci_esdhc_of_match, .of_match_table = sdhci_esdhc_of_match,
.pm = SDHCI_PLTFM_PMOPS, .pm = ESDHC_PMOPS,
}, },
.probe = sdhci_esdhc_probe, .probe = sdhci_esdhc_probe,
.remove = sdhci_esdhc_remove, .remove = sdhci_esdhc_remove,

View file

@ -58,6 +58,10 @@ static const struct sdhci_ops sdhci_hlwd_ops = {
.write_l = sdhci_hlwd_writel, .write_l = sdhci_hlwd_writel,
.write_w = sdhci_hlwd_writew, .write_w = sdhci_hlwd_writew,
.write_b = sdhci_hlwd_writeb, .write_b = sdhci_hlwd_writeb,
.set_clock = sdhci_set_clock,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
}; };
static const struct sdhci_pltfm_data sdhci_hlwd_pdata = { static const struct sdhci_pltfm_data sdhci_hlwd_pdata = {

View file

@ -21,6 +21,45 @@
#include "sdhci-pci.h" #include "sdhci-pci.h"
#include "sdhci-pci-o2micro.h" #include "sdhci-pci-o2micro.h"
static void o2_pci_set_baseclk(struct sdhci_pci_chip *chip, u32 value)
{
u32 scratch_32;
pci_read_config_dword(chip->pdev,
O2_SD_PLL_SETTING, &scratch_32);
scratch_32 &= 0x0000FFFF;
scratch_32 |= value;
pci_write_config_dword(chip->pdev,
O2_SD_PLL_SETTING, scratch_32);
}
static void o2_pci_led_enable(struct sdhci_pci_chip *chip)
{
int ret;
u32 scratch_32;
/* Set led of SD host function enable */
ret = pci_read_config_dword(chip->pdev,
O2_SD_FUNC_REG0, &scratch_32);
if (ret)
return;
scratch_32 &= ~O2_SD_FREG0_LEDOFF;
pci_write_config_dword(chip->pdev,
O2_SD_FUNC_REG0, scratch_32);
ret = pci_read_config_dword(chip->pdev,
O2_SD_TEST_REG, &scratch_32);
if (ret)
return;
scratch_32 |= O2_SD_LED_ENABLE;
pci_write_config_dword(chip->pdev,
O2_SD_TEST_REG, scratch_32);
}
void sdhci_pci_o2_fujin2_pci_init(struct sdhci_pci_chip *chip) void sdhci_pci_o2_fujin2_pci_init(struct sdhci_pci_chip *chip)
{ {
u32 scratch_32; u32 scratch_32;
@ -216,6 +255,40 @@ int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip)
scratch &= 0x7f; scratch &= 0x7f;
pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
/* DevId=8520 subId= 0x11 or 0x12 Type Chip support */
if (chip->pdev->device == PCI_DEVICE_ID_O2_FUJIN2) {
ret = pci_read_config_dword(chip->pdev,
O2_SD_FUNC_REG0,
&scratch_32);
scratch_32 = ((scratch_32 & 0xFF000000) >> 24);
/* Check Whether subId is 0x11 or 0x12 */
if ((scratch_32 == 0x11) || (scratch_32 == 0x12)) {
scratch_32 = 0x2c280000;
/* Set Base Clock to 208MZ */
o2_pci_set_baseclk(chip, scratch_32);
ret = pci_read_config_dword(chip->pdev,
O2_SD_FUNC_REG4,
&scratch_32);
/* Enable Base Clk setting change */
scratch_32 |= O2_SD_FREG4_ENABLE_CLK_SET;
pci_write_config_dword(chip->pdev,
O2_SD_FUNC_REG4,
scratch_32);
/* Set Tuning Window to 4 */
pci_write_config_byte(chip->pdev,
O2_SD_TUNING_CTRL, 0x44);
break;
}
}
/* Enable 8520 led function */
o2_pci_led_enable(chip);
/* Set timeout CLK */ /* Set timeout CLK */
ret = pci_read_config_dword(chip->pdev, ret = pci_read_config_dword(chip->pdev,
O2_SD_CLK_SETTING, &scratch_32); O2_SD_CLK_SETTING, &scratch_32);
@ -276,7 +349,7 @@ int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip)
pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch); pci_write_config_byte(chip->pdev, O2_SD_LOCK_WP, scratch);
ret = pci_read_config_dword(chip->pdev, ret = pci_read_config_dword(chip->pdev,
O2_SD_FUNC_REG0, &scratch_32); O2_SD_PLL_SETTING, &scratch_32);
if ((scratch_32 & 0xff000000) == 0x01000000) { if ((scratch_32 & 0xff000000) == 0x01000000) {
scratch_32 &= 0x0000FFFF; scratch_32 &= 0x0000FFFF;
@ -299,6 +372,9 @@ int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip)
O2_SD_FUNC_REG4, scratch_32); O2_SD_FUNC_REG4, scratch_32);
} }
/* Set Tuning Windows to 5 */
pci_write_config_byte(chip->pdev,
O2_SD_TUNING_CTRL, 0x55);
/* Lock WP */ /* Lock WP */
ret = pci_read_config_byte(chip->pdev, ret = pci_read_config_byte(chip->pdev,
O2_SD_LOCK_WP, &scratch); O2_SD_LOCK_WP, &scratch);

View file

@ -57,6 +57,9 @@
#define O2_SD_UHS2_L1_CTRL 0x35C #define O2_SD_UHS2_L1_CTRL 0x35C
#define O2_SD_FUNC_REG3 0x3E0 #define O2_SD_FUNC_REG3 0x3E0
#define O2_SD_FUNC_REG4 0x3E4 #define O2_SD_FUNC_REG4 0x3E4
#define O2_SD_LED_ENABLE BIT(6)
#define O2_SD_FREG0_LEDOFF BIT(13)
#define O2_SD_FREG4_ENABLE_CLK_SET BIT(22)
#define O2_SD_VENDOR_SETTING 0x110 #define O2_SD_VENDOR_SETTING 0x110
#define O2_SD_VENDOR_SETTING2 0x1C8 #define O2_SD_VENDOR_SETTING2 0x1C8

View file

@ -1031,7 +1031,7 @@ static int sdhci_pci_enable_dma(struct sdhci_host *host)
return 0; return 0;
} }
static int sdhci_pci_bus_width(struct sdhci_host *host, int width) static void sdhci_pci_set_bus_width(struct sdhci_host *host, int width)
{ {
u8 ctrl; u8 ctrl;
@ -1052,8 +1052,6 @@ static int sdhci_pci_bus_width(struct sdhci_host *host, int width)
} }
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
return 0;
} }
static void sdhci_pci_gpio_hw_reset(struct sdhci_host *host) static void sdhci_pci_gpio_hw_reset(struct sdhci_host *host)
@ -1080,8 +1078,11 @@ static void sdhci_pci_hw_reset(struct sdhci_host *host)
} }
static const struct sdhci_ops sdhci_pci_ops = { static const struct sdhci_ops sdhci_pci_ops = {
.set_clock = sdhci_set_clock,
.enable_dma = sdhci_pci_enable_dma, .enable_dma = sdhci_pci_enable_dma,
.platform_bus_width = sdhci_pci_bus_width, .set_bus_width = sdhci_pci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
.hw_reset = sdhci_pci_hw_reset, .hw_reset = sdhci_pci_hw_reset,
}; };

View file

@ -45,6 +45,10 @@ unsigned int sdhci_pltfm_clk_get_max_clock(struct sdhci_host *host)
EXPORT_SYMBOL_GPL(sdhci_pltfm_clk_get_max_clock); EXPORT_SYMBOL_GPL(sdhci_pltfm_clk_get_max_clock);
static const struct sdhci_ops sdhci_pltfm_ops = { static const struct sdhci_ops sdhci_pltfm_ops = {
.set_clock = sdhci_set_clock,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
}; };
#ifdef CONFIG_OF #ifdef CONFIG_OF

View file

@ -51,11 +51,13 @@
#define MMC_CARD 0x1000 #define MMC_CARD 0x1000
#define MMC_WIDTH 0x0100 #define MMC_WIDTH 0x0100
static void pxav2_set_private_registers(struct sdhci_host *host, u8 mask) static void pxav2_reset(struct sdhci_host *host, u8 mask)
{ {
struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc)); struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc));
struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data; struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data;
sdhci_reset(host, mask);
if (mask == SDHCI_RESET_ALL) { if (mask == SDHCI_RESET_ALL) {
u16 tmp = 0; u16 tmp = 0;
@ -88,7 +90,7 @@ static void pxav2_set_private_registers(struct sdhci_host *host, u8 mask)
} }
} }
static int pxav2_mmc_set_width(struct sdhci_host *host, int width) static void pxav2_mmc_set_bus_width(struct sdhci_host *host, int width)
{ {
u8 ctrl; u8 ctrl;
u16 tmp; u16 tmp;
@ -107,14 +109,14 @@ static int pxav2_mmc_set_width(struct sdhci_host *host, int width)
} }
writew(tmp, host->ioaddr + SD_CE_ATA_2); writew(tmp, host->ioaddr + SD_CE_ATA_2);
writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL); writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
return 0;
} }
static const struct sdhci_ops pxav2_sdhci_ops = { static const struct sdhci_ops pxav2_sdhci_ops = {
.set_clock = sdhci_set_clock,
.get_max_clock = sdhci_pltfm_clk_get_max_clock, .get_max_clock = sdhci_pltfm_clk_get_max_clock,
.platform_reset_exit = pxav2_set_private_registers, .set_bus_width = pxav2_mmc_set_bus_width,
.platform_bus_width = pxav2_mmc_set_width, .reset = pxav2_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
}; };
#ifdef CONFIG_OF #ifdef CONFIG_OF

View file

@ -112,11 +112,13 @@ static int mv_conf_mbus_windows(struct platform_device *pdev,
return 0; return 0;
} }
static void pxav3_set_private_registers(struct sdhci_host *host, u8 mask) static void pxav3_reset(struct sdhci_host *host, u8 mask)
{ {
struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc)); struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc));
struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data; struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data;
sdhci_reset(host, mask);
if (mask == SDHCI_RESET_ALL) { if (mask == SDHCI_RESET_ALL) {
/* /*
* tune timing of read data/command when crc error happen * tune timing of read data/command when crc error happen
@ -184,7 +186,7 @@ static void pxav3_gen_init_74_clocks(struct sdhci_host *host, u8 power_mode)
pxa->power_mode = power_mode; pxa->power_mode = power_mode;
} }
static int pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs) static void pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
{ {
u16 ctrl_2; u16 ctrl_2;
@ -218,15 +220,16 @@ static int pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
dev_dbg(mmc_dev(host->mmc), dev_dbg(mmc_dev(host->mmc),
"%s uhs = %d, ctrl_2 = %04X\n", "%s uhs = %d, ctrl_2 = %04X\n",
__func__, uhs, ctrl_2); __func__, uhs, ctrl_2);
return 0;
} }
static const struct sdhci_ops pxav3_sdhci_ops = { static const struct sdhci_ops pxav3_sdhci_ops = {
.platform_reset_exit = pxav3_set_private_registers, .set_clock = sdhci_set_clock,
.set_uhs_signaling = pxav3_set_uhs_signaling, .set_uhs_signaling = pxav3_set_uhs_signaling,
.platform_send_init_74_clocks = pxav3_gen_init_74_clocks, .platform_send_init_74_clocks = pxav3_gen_init_74_clocks,
.get_max_clock = sdhci_pltfm_clk_get_max_clock, .get_max_clock = sdhci_pltfm_clk_get_max_clock,
.set_bus_width = sdhci_set_bus_width,
.reset = pxav3_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
}; };
static struct sdhci_pltfm_data sdhci_pxav3_pdata = { static struct sdhci_pltfm_data sdhci_pxav3_pdata = {

View file

@ -33,9 +33,6 @@
#define MAX_BUS_CLK (4) #define MAX_BUS_CLK (4)
/* Number of gpio's used is max data bus width + command and clock lines */
#define NUM_GPIOS(x) (x + 2)
/** /**
* struct sdhci_s3c - S3C SDHCI instance * struct sdhci_s3c - S3C SDHCI instance
* @host: The SDHCI host created * @host: The SDHCI host created
@ -58,6 +55,8 @@ struct sdhci_s3c {
struct clk *clk_io; struct clk *clk_io;
struct clk *clk_bus[MAX_BUS_CLK]; struct clk *clk_bus[MAX_BUS_CLK];
unsigned long clk_rates[MAX_BUS_CLK]; unsigned long clk_rates[MAX_BUS_CLK];
bool no_divider;
}; };
/** /**
@ -70,6 +69,7 @@ struct sdhci_s3c {
*/ */
struct sdhci_s3c_drv_data { struct sdhci_s3c_drv_data {
unsigned int sdhci_quirks; unsigned int sdhci_quirks;
bool no_divider;
}; };
static inline struct sdhci_s3c *to_s3c(struct sdhci_host *host) static inline struct sdhci_s3c *to_s3c(struct sdhci_host *host)
@ -119,7 +119,7 @@ static unsigned int sdhci_s3c_consider_clock(struct sdhci_s3c *ourhost,
* If controller uses a non-standard clock division, find the best clock * If controller uses a non-standard clock division, find the best clock
* speed possible with selected clock source and skip the division. * speed possible with selected clock source and skip the division.
*/ */
if (ourhost->host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) { if (ourhost->no_divider) {
rate = clk_round_rate(clksrc, wanted); rate = clk_round_rate(clksrc, wanted);
return wanted - rate; return wanted - rate;
} }
@ -161,9 +161,13 @@ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock)
int src; int src;
u32 ctrl; u32 ctrl;
host->mmc->actual_clock = 0;
/* don't bother if the clock is going off. */ /* don't bother if the clock is going off. */
if (clock == 0) if (clock == 0) {
sdhci_set_clock(host, clock);
return; return;
}
for (src = 0; src < MAX_BUS_CLK; src++) { for (src = 0; src < MAX_BUS_CLK; src++) {
delta = sdhci_s3c_consider_clock(ourhost, src, clock); delta = sdhci_s3c_consider_clock(ourhost, src, clock);
@ -215,6 +219,8 @@ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock)
if (clock < 25 * 1000000) if (clock < 25 * 1000000)
ctrl |= (S3C_SDHCI_CTRL3_FCSEL3 | S3C_SDHCI_CTRL3_FCSEL2); ctrl |= (S3C_SDHCI_CTRL3_FCSEL3 | S3C_SDHCI_CTRL3_FCSEL2);
writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL3); writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL3);
sdhci_set_clock(host, clock);
} }
/** /**
@ -295,10 +301,11 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
unsigned long timeout; unsigned long timeout;
u16 clk = 0; u16 clk = 0;
host->mmc->actual_clock = 0;
/* If the clock is going off, set to 0 at clock control register */ /* If the clock is going off, set to 0 at clock control register */
if (clock == 0) { if (clock == 0) {
sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
host->clock = clock;
return; return;
} }
@ -306,8 +313,6 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock); clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock);
host->clock = clock;
clk = SDHCI_CLOCK_INT_EN; clk = SDHCI_CLOCK_INT_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL); sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
@ -329,14 +334,14 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
} }
/** /**
* sdhci_s3c_platform_bus_width - support 8bit buswidth * sdhci_s3c_set_bus_width - support 8bit buswidth
* @host: The SDHCI host being queried * @host: The SDHCI host being queried
* @width: MMC_BUS_WIDTH_ macro for the bus width being requested * @width: MMC_BUS_WIDTH_ macro for the bus width being requested
* *
* We have 8-bit width support but is not a v3 controller. * We have 8-bit width support but is not a v3 controller.
* So we add platform_bus_width() and support 8bit width. * So we add platform_bus_width() and support 8bit width.
*/ */
static int sdhci_s3c_platform_bus_width(struct sdhci_host *host, int width) static void sdhci_s3c_set_bus_width(struct sdhci_host *host, int width)
{ {
u8 ctrl; u8 ctrl;
@ -358,93 +363,23 @@ static int sdhci_s3c_platform_bus_width(struct sdhci_host *host, int width)
} }
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
return 0;
} }
static struct sdhci_ops sdhci_s3c_ops = { static struct sdhci_ops sdhci_s3c_ops = {
.get_max_clock = sdhci_s3c_get_max_clk, .get_max_clock = sdhci_s3c_get_max_clk,
.set_clock = sdhci_s3c_set_clock, .set_clock = sdhci_s3c_set_clock,
.get_min_clock = sdhci_s3c_get_min_clock, .get_min_clock = sdhci_s3c_get_min_clock,
.platform_bus_width = sdhci_s3c_platform_bus_width, .set_bus_width = sdhci_s3c_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
}; };
static void sdhci_s3c_notify_change(struct platform_device *dev, int state)
{
struct sdhci_host *host = platform_get_drvdata(dev);
#ifdef CONFIG_PM_RUNTIME
struct sdhci_s3c *sc = sdhci_priv(host);
#endif
unsigned long flags;
if (host) {
spin_lock_irqsave(&host->lock, flags);
if (state) {
dev_dbg(&dev->dev, "card inserted.\n");
#ifdef CONFIG_PM_RUNTIME
clk_prepare_enable(sc->clk_io);
#endif
host->flags &= ~SDHCI_DEVICE_DEAD;
host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
} else {
dev_dbg(&dev->dev, "card removed.\n");
host->flags |= SDHCI_DEVICE_DEAD;
host->quirks &= ~SDHCI_QUIRK_BROKEN_CARD_DETECTION;
#ifdef CONFIG_PM_RUNTIME
clk_disable_unprepare(sc->clk_io);
#endif
}
tasklet_schedule(&host->card_tasklet);
spin_unlock_irqrestore(&host->lock, flags);
}
}
static irqreturn_t sdhci_s3c_gpio_card_detect_thread(int irq, void *dev_id)
{
struct sdhci_s3c *sc = dev_id;
int status = gpio_get_value(sc->ext_cd_gpio);
if (sc->pdata->ext_cd_gpio_invert)
status = !status;
sdhci_s3c_notify_change(sc->pdev, status);
return IRQ_HANDLED;
}
static void sdhci_s3c_setup_card_detect_gpio(struct sdhci_s3c *sc)
{
struct s3c_sdhci_platdata *pdata = sc->pdata;
struct device *dev = &sc->pdev->dev;
if (devm_gpio_request(dev, pdata->ext_cd_gpio, "SDHCI EXT CD") == 0) {
sc->ext_cd_gpio = pdata->ext_cd_gpio;
sc->ext_cd_irq = gpio_to_irq(pdata->ext_cd_gpio);
if (sc->ext_cd_irq &&
request_threaded_irq(sc->ext_cd_irq, NULL,
sdhci_s3c_gpio_card_detect_thread,
IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING |
IRQF_ONESHOT,
dev_name(dev), sc) == 0) {
int status = gpio_get_value(sc->ext_cd_gpio);
if (pdata->ext_cd_gpio_invert)
status = !status;
sdhci_s3c_notify_change(sc->pdev, status);
} else {
dev_warn(dev, "cannot request irq for card detect\n");
sc->ext_cd_irq = 0;
}
} else {
dev_err(dev, "cannot request gpio for card detect\n");
}
}
#ifdef CONFIG_OF #ifdef CONFIG_OF
static int sdhci_s3c_parse_dt(struct device *dev, static int sdhci_s3c_parse_dt(struct device *dev,
struct sdhci_host *host, struct s3c_sdhci_platdata *pdata) struct sdhci_host *host, struct s3c_sdhci_platdata *pdata)
{ {
struct device_node *node = dev->of_node; struct device_node *node = dev->of_node;
struct sdhci_s3c *ourhost = to_s3c(host);
u32 max_width; u32 max_width;
int gpio;
/* if the bus-width property is not specified, assume width as 1 */ /* if the bus-width property is not specified, assume width as 1 */
if (of_property_read_u32(node, "bus-width", &max_width)) if (of_property_read_u32(node, "bus-width", &max_width))
@ -462,18 +397,8 @@ static int sdhci_s3c_parse_dt(struct device *dev,
return 0; return 0;
} }
gpio = of_get_named_gpio(node, "cd-gpios", 0); if (of_get_named_gpio(node, "cd-gpios", 0))
if (gpio_is_valid(gpio)) {
pdata->cd_type = S3C_SDHCI_CD_GPIO;
pdata->ext_cd_gpio = gpio;
ourhost->ext_cd_gpio = -1;
if (of_get_property(node, "cd-inverted", NULL))
pdata->ext_cd_gpio_invert = 1;
return 0; return 0;
} else if (gpio != -ENOENT) {
dev_err(dev, "invalid card detect gpio specified\n");
return -EINVAL;
}
/* assuming internal card detect that will be configured by pinctrl */ /* assuming internal card detect that will be configured by pinctrl */
pdata->cd_type = S3C_SDHCI_CD_INTERNAL; pdata->cd_type = S3C_SDHCI_CD_INTERNAL;
@ -606,8 +531,10 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
/* Setup quirks for the controller */ /* Setup quirks for the controller */
host->quirks |= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC; host->quirks |= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC;
host->quirks |= SDHCI_QUIRK_NO_HISPD_BIT; host->quirks |= SDHCI_QUIRK_NO_HISPD_BIT;
if (drv_data) if (drv_data) {
host->quirks |= drv_data->sdhci_quirks; host->quirks |= drv_data->sdhci_quirks;
sc->no_divider = drv_data->no_divider;
}
#ifndef CONFIG_MMC_SDHCI_S3C_DMA #ifndef CONFIG_MMC_SDHCI_S3C_DMA
@ -656,7 +583,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
* If controller does not have internal clock divider, * If controller does not have internal clock divider,
* we can use overriding functions instead of default. * we can use overriding functions instead of default.
*/ */
if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK) { if (sc->no_divider) {
sdhci_s3c_ops.set_clock = sdhci_cmu_set_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_min_clock = sdhci_cmu_get_min_clock;
sdhci_s3c_ops.get_max_clock = sdhci_cmu_get_max_clock; sdhci_s3c_ops.get_max_clock = sdhci_cmu_get_max_clock;
@ -674,6 +601,8 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_use_autosuspend(&pdev->dev);
pm_suspend_ignore_children(&pdev->dev, 1); pm_suspend_ignore_children(&pdev->dev, 1);
mmc_of_parse(host->mmc);
ret = sdhci_add_host(host); ret = sdhci_add_host(host);
if (ret) { if (ret) {
dev_err(dev, "sdhci_add_host() failed\n"); dev_err(dev, "sdhci_add_host() failed\n");
@ -682,15 +611,6 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
goto err_req_regs; goto err_req_regs;
} }
/* The following two methods of card detection might call
sdhci_s3c_notify_change() immediately, so they can be called
only after sdhci_add_host(). Setup errors are ignored. */
if (pdata->cd_type == S3C_SDHCI_CD_EXTERNAL && pdata->ext_cd_init)
pdata->ext_cd_init(&sdhci_s3c_notify_change);
if (pdata->cd_type == S3C_SDHCI_CD_GPIO &&
gpio_is_valid(pdata->ext_cd_gpio))
sdhci_s3c_setup_card_detect_gpio(sc);
#ifdef CONFIG_PM_RUNTIME #ifdef CONFIG_PM_RUNTIME
if (pdata->cd_type != S3C_SDHCI_CD_INTERNAL) if (pdata->cd_type != S3C_SDHCI_CD_INTERNAL)
clk_disable_unprepare(sc->clk_io); clk_disable_unprepare(sc->clk_io);
@ -711,16 +631,12 @@ static int sdhci_s3c_remove(struct platform_device *pdev)
{ {
struct sdhci_host *host = platform_get_drvdata(pdev); struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_s3c *sc = sdhci_priv(host); struct sdhci_s3c *sc = sdhci_priv(host);
struct s3c_sdhci_platdata *pdata = sc->pdata;
if (pdata->cd_type == S3C_SDHCI_CD_EXTERNAL && pdata->ext_cd_cleanup)
pdata->ext_cd_cleanup(&sdhci_s3c_notify_change);
if (sc->ext_cd_irq) if (sc->ext_cd_irq)
free_irq(sc->ext_cd_irq, sc); free_irq(sc->ext_cd_irq, sc);
#ifdef CONFIG_PM_RUNTIME #ifdef CONFIG_PM_RUNTIME
if (pdata->cd_type != S3C_SDHCI_CD_INTERNAL) if (sc->pdata->cd_type != S3C_SDHCI_CD_INTERNAL)
clk_prepare_enable(sc->clk_io); clk_prepare_enable(sc->clk_io);
#endif #endif
sdhci_remove_host(host, 1); sdhci_remove_host(host, 1);
@ -797,7 +713,7 @@ static const struct dev_pm_ops sdhci_s3c_pmops = {
#if defined(CONFIG_CPU_EXYNOS4210) || defined(CONFIG_SOC_EXYNOS4212) #if defined(CONFIG_CPU_EXYNOS4210) || defined(CONFIG_SOC_EXYNOS4212)
static struct sdhci_s3c_drv_data exynos4_sdhci_drv_data = { static struct sdhci_s3c_drv_data exynos4_sdhci_drv_data = {
.sdhci_quirks = SDHCI_QUIRK_NONSTANDARD_CLOCK, .no_divider = true,
}; };
#define EXYNOS4_SDHCI_DRV_DATA ((kernel_ulong_t)&exynos4_sdhci_drv_data) #define EXYNOS4_SDHCI_DRV_DATA ((kernel_ulong_t)&exynos4_sdhci_drv_data)
#else #else

View file

@ -28,7 +28,11 @@ static unsigned int sdhci_sirf_get_max_clk(struct sdhci_host *host)
} }
static struct sdhci_ops sdhci_sirf_ops = { static struct sdhci_ops sdhci_sirf_ops = {
.set_clock = sdhci_set_clock,
.get_max_clock = sdhci_sirf_get_max_clk, .get_max_clock = sdhci_sirf_get_max_clk,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
}; };
static struct sdhci_pltfm_data sdhci_sirf_pdata = { static struct sdhci_pltfm_data sdhci_sirf_pdata = {

View file

@ -38,7 +38,10 @@ struct spear_sdhci {
/* sdhci ops */ /* sdhci ops */
static const struct sdhci_ops sdhci_pltfm_ops = { static const struct sdhci_ops sdhci_pltfm_ops = {
/* Nothing to do for now. */ .set_clock = sdhci_set_clock,
.set_bus_width = sdhci_set_bus_width,
.reset = sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
}; };
#ifdef CONFIG_OF #ifdef CONFIG_OF

View file

@ -32,11 +32,17 @@
/* Tegra SDHOST controller vendor register definitions */ /* Tegra SDHOST controller vendor register definitions */
#define SDHCI_TEGRA_VENDOR_MISC_CTRL 0x120 #define SDHCI_TEGRA_VENDOR_MISC_CTRL 0x120
#define SDHCI_MISC_CTRL_ENABLE_SDR104 0x8
#define SDHCI_MISC_CTRL_ENABLE_SDR50 0x10
#define SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300 0x20 #define SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300 0x20
#define SDHCI_MISC_CTRL_ENABLE_DDR50 0x200
#define NVQUIRK_FORCE_SDHCI_SPEC_200 BIT(0) #define NVQUIRK_FORCE_SDHCI_SPEC_200 BIT(0)
#define NVQUIRK_ENABLE_BLOCK_GAP_DET BIT(1) #define NVQUIRK_ENABLE_BLOCK_GAP_DET BIT(1)
#define NVQUIRK_ENABLE_SDHCI_SPEC_300 BIT(2) #define NVQUIRK_ENABLE_SDHCI_SPEC_300 BIT(2)
#define NVQUIRK_DISABLE_SDR50 BIT(3)
#define NVQUIRK_DISABLE_SDR104 BIT(4)
#define NVQUIRK_DISABLE_DDR50 BIT(5)
struct sdhci_tegra_soc_data { struct sdhci_tegra_soc_data {
const struct sdhci_pltfm_data *pdata; const struct sdhci_pltfm_data *pdata;
@ -48,19 +54,6 @@ struct sdhci_tegra {
int power_gpio; int power_gpio;
}; };
static u32 tegra_sdhci_readl(struct sdhci_host *host, int reg)
{
u32 val;
if (unlikely(reg == SDHCI_PRESENT_STATE)) {
/* Use wp_gpio here instead? */
val = readl(host->ioaddr + reg);
return val | SDHCI_WRITE_PROTECT;
}
return readl(host->ioaddr + reg);
}
static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg) static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@ -108,26 +101,33 @@ static unsigned int tegra_sdhci_get_ro(struct sdhci_host *host)
return mmc_gpio_get_ro(host->mmc); return mmc_gpio_get_ro(host->mmc);
} }
static void tegra_sdhci_reset_exit(struct sdhci_host *host, u8 mask) static void tegra_sdhci_reset(struct sdhci_host *host, u8 mask)
{ {
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_tegra *tegra_host = pltfm_host->priv; struct sdhci_tegra *tegra_host = pltfm_host->priv;
const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data; const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;
u32 misc_ctrl;
sdhci_reset(host, mask);
if (!(mask & SDHCI_RESET_ALL)) if (!(mask & SDHCI_RESET_ALL))
return; return;
misc_ctrl = sdhci_readw(host, SDHCI_TEGRA_VENDOR_MISC_CTRL);
/* Erratum: Enable SDHCI spec v3.00 support */ /* Erratum: Enable SDHCI spec v3.00 support */
if (soc_data->nvquirks & NVQUIRK_ENABLE_SDHCI_SPEC_300) { if (soc_data->nvquirks & NVQUIRK_ENABLE_SDHCI_SPEC_300)
u32 misc_ctrl;
misc_ctrl = sdhci_readb(host, SDHCI_TEGRA_VENDOR_MISC_CTRL);
misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300; misc_ctrl |= SDHCI_MISC_CTRL_ENABLE_SDHCI_SPEC_300;
sdhci_writeb(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL); /* Don't advertise UHS modes which aren't supported yet */
} if (soc_data->nvquirks & NVQUIRK_DISABLE_SDR50)
misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_SDR50;
if (soc_data->nvquirks & NVQUIRK_DISABLE_DDR50)
misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_DDR50;
if (soc_data->nvquirks & NVQUIRK_DISABLE_SDR104)
misc_ctrl &= ~SDHCI_MISC_CTRL_ENABLE_SDR104;
sdhci_writew(host, misc_ctrl, SDHCI_TEGRA_VENDOR_MISC_CTRL);
} }
static int tegra_sdhci_buswidth(struct sdhci_host *host, int bus_width) static void tegra_sdhci_set_bus_width(struct sdhci_host *host, int bus_width)
{ {
u32 ctrl; u32 ctrl;
@ -144,23 +144,25 @@ static int tegra_sdhci_buswidth(struct sdhci_host *host, int bus_width)
ctrl &= ~SDHCI_CTRL_4BITBUS; ctrl &= ~SDHCI_CTRL_4BITBUS;
} }
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL); sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
return 0;
} }
static const struct sdhci_ops tegra_sdhci_ops = { static const struct sdhci_ops tegra_sdhci_ops = {
.get_ro = tegra_sdhci_get_ro, .get_ro = tegra_sdhci_get_ro,
.read_l = tegra_sdhci_readl,
.read_w = tegra_sdhci_readw, .read_w = tegra_sdhci_readw,
.write_l = tegra_sdhci_writel, .write_l = tegra_sdhci_writel,
.platform_bus_width = tegra_sdhci_buswidth, .set_clock = sdhci_set_clock,
.platform_reset_exit = tegra_sdhci_reset_exit, .set_bus_width = tegra_sdhci_set_bus_width,
.reset = tegra_sdhci_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
}; };
static const struct sdhci_pltfm_data sdhci_tegra20_pdata = { static const struct sdhci_pltfm_data sdhci_tegra20_pdata = {
.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
SDHCI_QUIRK_SINGLE_POWER_WRITE | SDHCI_QUIRK_SINGLE_POWER_WRITE |
SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_NO_HISPD_BIT |
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC, SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
.ops = &tegra_sdhci_ops, .ops = &tegra_sdhci_ops,
}; };
@ -175,13 +177,16 @@ static const struct sdhci_pltfm_data sdhci_tegra30_pdata = {
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
SDHCI_QUIRK_SINGLE_POWER_WRITE | SDHCI_QUIRK_SINGLE_POWER_WRITE |
SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_NO_HISPD_BIT |
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC, SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
.ops = &tegra_sdhci_ops, .ops = &tegra_sdhci_ops,
}; };
static struct sdhci_tegra_soc_data soc_data_tegra30 = { static struct sdhci_tegra_soc_data soc_data_tegra30 = {
.pdata = &sdhci_tegra30_pdata, .pdata = &sdhci_tegra30_pdata,
.nvquirks = NVQUIRK_ENABLE_SDHCI_SPEC_300, .nvquirks = NVQUIRK_ENABLE_SDHCI_SPEC_300 |
NVQUIRK_DISABLE_SDR50 |
NVQUIRK_DISABLE_SDR104,
}; };
static const struct sdhci_pltfm_data sdhci_tegra114_pdata = { static const struct sdhci_pltfm_data sdhci_tegra114_pdata = {
@ -189,12 +194,16 @@ static const struct sdhci_pltfm_data sdhci_tegra114_pdata = {
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
SDHCI_QUIRK_SINGLE_POWER_WRITE | SDHCI_QUIRK_SINGLE_POWER_WRITE |
SDHCI_QUIRK_NO_HISPD_BIT | SDHCI_QUIRK_NO_HISPD_BIT |
SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC, SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC |
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
.ops = &tegra_sdhci_ops, .ops = &tegra_sdhci_ops,
}; };
static struct sdhci_tegra_soc_data soc_data_tegra114 = { static struct sdhci_tegra_soc_data soc_data_tegra114 = {
.pdata = &sdhci_tegra114_pdata, .pdata = &sdhci_tegra114_pdata,
.nvquirks = NVQUIRK_DISABLE_SDR50 |
NVQUIRK_DISABLE_DDR50 |
NVQUIRK_DISABLE_SDR104,
}; };
static const struct of_device_id sdhci_tegra_dt_match[] = { static const struct of_device_id sdhci_tegra_dt_match[] = {

File diff suppressed because it is too large Load diff

View file

@ -281,18 +281,14 @@ struct sdhci_ops {
unsigned int (*get_max_clock)(struct sdhci_host *host); unsigned int (*get_max_clock)(struct sdhci_host *host);
unsigned int (*get_min_clock)(struct sdhci_host *host); unsigned int (*get_min_clock)(struct sdhci_host *host);
unsigned int (*get_timeout_clock)(struct sdhci_host *host); unsigned int (*get_timeout_clock)(struct sdhci_host *host);
int (*platform_bus_width)(struct sdhci_host *host, void (*set_bus_width)(struct sdhci_host *host, int width);
int width);
void (*platform_send_init_74_clocks)(struct sdhci_host *host, void (*platform_send_init_74_clocks)(struct sdhci_host *host,
u8 power_mode); u8 power_mode);
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 (*reset)(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 (*platform_execute_tuning)(struct sdhci_host *host, u32 opcode);
int (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs); void (*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_resume)(struct sdhci_host *host);
void (*adma_workaround)(struct sdhci_host *host, u32 intmask); void (*adma_workaround)(struct sdhci_host *host, u32 intmask);
void (*platform_init)(struct sdhci_host *host); void (*platform_init)(struct sdhci_host *host);
void (*card_event)(struct sdhci_host *host); void (*card_event)(struct sdhci_host *host);
@ -397,6 +393,16 @@ extern void sdhci_remove_host(struct sdhci_host *host, int dead);
extern void sdhci_send_command(struct sdhci_host *host, extern void sdhci_send_command(struct sdhci_host *host,
struct mmc_command *cmd); struct mmc_command *cmd);
static inline bool sdhci_sdio_irq_enabled(struct sdhci_host *host)
{
return !!(host->flags & SDHCI_SDIO_IRQ_ENABLED);
}
void sdhci_set_clock(struct sdhci_host *host, unsigned int clock);
void sdhci_set_bus_width(struct sdhci_host *host, int width);
void sdhci_reset(struct sdhci_host *host, u8 mask);
void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing);
#ifdef CONFIG_PM #ifdef CONFIG_PM
extern int sdhci_suspend_host(struct sdhci_host *host); extern int sdhci_suspend_host(struct sdhci_host *host);
extern int sdhci_resume_host(struct sdhci_host *host); extern int sdhci_resume_host(struct sdhci_host *host);

View file

@ -803,12 +803,13 @@ static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host,
break; break;
} }
switch (host->timing) { switch (host->timing) {
case MMC_TIMING_UHS_DDR50: case MMC_TIMING_MMC_DDR52:
/* /*
* MMC core will only set this timing, if the host * MMC core will only set this timing, if the host
* advertises the MMC_CAP_UHS_DDR50 capability. MMCIF * advertises the MMC_CAP_1_8V_DDR/MMC_CAP_1_2V_DDR
* implementations with this capability, e.g. sh73a0, * capability. MMCIF implementations with this
* will have to set it in their platform data. * capability, e.g. sh73a0, will have to set it
* in their platform data.
*/ */
tmp |= CMD_SET_DARS; tmp |= CMD_SET_DARS;
break; break;

File diff suppressed because it is too large Load diff

View file

@ -840,7 +840,7 @@ static int wmt_mci_probe(struct platform_device *pdev)
priv->dma_desc_buffer = dma_alloc_coherent(&pdev->dev, priv->dma_desc_buffer = dma_alloc_coherent(&pdev->dev,
mmc->max_blk_count * 16, mmc->max_blk_count * 16,
&priv->dma_desc_device_addr, &priv->dma_desc_device_addr,
208); GFP_KERNEL);
if (!priv->dma_desc_buffer) { if (!priv->dma_desc_buffer) {
dev_err(&pdev->dev, "DMA alloc fail\n"); dev_err(&pdev->dev, "DMA alloc fail\n");
ret = -EPERM; ret = -EPERM;

View file

@ -285,7 +285,6 @@ static void rsi_reset_card(struct sdio_func *pfunction)
if (err) { if (err) {
rsi_dbg(ERR_ZONE, "%s: CCCR speed reg read failed: %d\n", rsi_dbg(ERR_ZONE, "%s: CCCR speed reg read failed: %d\n",
__func__, err); __func__, err);
card->state &= ~MMC_STATE_HIGHSPEED;
} else { } else {
err = rsi_cmd52writebyte(card, err = rsi_cmd52writebyte(card,
SDIO_CCCR_SPEED, SDIO_CCCR_SPEED,
@ -296,14 +295,13 @@ static void rsi_reset_card(struct sdio_func *pfunction)
__func__, err); __func__, err);
return; return;
} }
mmc_card_set_highspeed(card);
host->ios.timing = MMC_TIMING_SD_HS; host->ios.timing = MMC_TIMING_SD_HS;
host->ops->set_ios(host, &host->ios); host->ops->set_ios(host, &host->ios);
} }
} }
/* Set clock */ /* Set clock */
if (mmc_card_highspeed(card)) if (mmc_card_hs(card))
clock = 50000000; clock = 50000000;
else else
clock = card->cis.max_dtr; clock = card->cis.max_dtr;

View file

@ -63,12 +63,12 @@ struct mmc_ext_csd {
unsigned int power_off_longtime; /* Units: ms */ unsigned int power_off_longtime; /* Units: ms */
u8 power_off_notification; /* state */ u8 power_off_notification; /* state */
unsigned int hs_max_dtr; unsigned int hs_max_dtr;
unsigned int hs200_max_dtr;
#define MMC_HIGH_26_MAX_DTR 26000000 #define MMC_HIGH_26_MAX_DTR 26000000
#define MMC_HIGH_52_MAX_DTR 52000000 #define MMC_HIGH_52_MAX_DTR 52000000
#define MMC_HIGH_DDR_MAX_DTR 52000000 #define MMC_HIGH_DDR_MAX_DTR 52000000
#define MMC_HS200_MAX_DTR 200000000 #define MMC_HS200_MAX_DTR 200000000
unsigned int sectors; unsigned int sectors;
unsigned int card_type;
unsigned int hc_erase_size; /* In sectors */ unsigned int hc_erase_size; /* In sectors */
unsigned int hc_erase_timeout; /* In milliseconds */ unsigned int hc_erase_timeout; /* In milliseconds */
unsigned int sec_trim_mult; /* Secure trim multiplier */ unsigned int sec_trim_mult; /* Secure trim multiplier */
@ -110,6 +110,7 @@ struct mmc_ext_csd {
u8 raw_pwr_cl_200_360; /* 237 */ u8 raw_pwr_cl_200_360; /* 237 */
u8 raw_pwr_cl_ddr_52_195; /* 238 */ u8 raw_pwr_cl_ddr_52_195; /* 238 */
u8 raw_pwr_cl_ddr_52_360; /* 239 */ u8 raw_pwr_cl_ddr_52_360; /* 239 */
u8 raw_pwr_cl_ddr_200_360; /* 253 */
u8 raw_bkops_status; /* 246 */ u8 raw_bkops_status; /* 246 */
u8 raw_sectors[4]; /* 212 - 4 bytes */ u8 raw_sectors[4]; /* 212 - 4 bytes */
@ -194,6 +195,7 @@ struct sdio_cis {
}; };
struct mmc_host; struct mmc_host;
struct mmc_ios;
struct sdio_func; struct sdio_func;
struct sdio_func_tuple; struct sdio_func_tuple;
@ -250,15 +252,11 @@ struct mmc_card {
unsigned int state; /* (our) card state */ unsigned int state; /* (our) card state */
#define MMC_STATE_PRESENT (1<<0) /* present in sysfs */ #define MMC_STATE_PRESENT (1<<0) /* present in sysfs */
#define MMC_STATE_READONLY (1<<1) /* card is read-only */ #define MMC_STATE_READONLY (1<<1) /* card is read-only */
#define MMC_STATE_HIGHSPEED (1<<2) /* card is in high speed mode */ #define MMC_STATE_BLOCKADDR (1<<2) /* card uses block-addressing */
#define MMC_STATE_BLOCKADDR (1<<3) /* card uses block-addressing */ #define MMC_CARD_SDXC (1<<3) /* card is SDXC */
#define MMC_STATE_HIGHSPEED_DDR (1<<4) /* card is in high speed mode */ #define MMC_CARD_REMOVED (1<<4) /* card has been removed */
#define MMC_STATE_ULTRAHIGHSPEED (1<<5) /* card is in ultra high speed mode */ #define MMC_STATE_DOING_BKOPS (1<<5) /* card is doing BKOPS */
#define MMC_CARD_SDXC (1<<6) /* card is SDXC */ #define MMC_STATE_SUSPENDED (1<<6) /* card is suspended */
#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_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 */
@ -301,6 +299,7 @@ struct mmc_card {
struct sdio_func_tuple *tuples; /* unknown common tuples */ struct sdio_func_tuple *tuples; /* unknown common tuples */
unsigned int sd_bus_speed; /* Bus Speed Mode set for the card */ unsigned int sd_bus_speed; /* Bus Speed Mode set for the card */
unsigned int mmc_avail_type; /* supported device type by both host and card */
struct dentry *debugfs_root; struct dentry *debugfs_root;
struct mmc_part part[MMC_NUM_PHY_PARTITION]; /* physical partitions */ struct mmc_part part[MMC_NUM_PHY_PARTITION]; /* physical partitions */
@ -353,7 +352,7 @@ struct mmc_fixup {
#define CID_OEMID_ANY ((unsigned short) -1) #define CID_OEMID_ANY ((unsigned short) -1)
#define CID_NAME_ANY (NULL) #define CID_NAME_ANY (NULL)
#define END_FIXUP { 0 } #define END_FIXUP { NULL }
#define _FIXUP_EXT(_name, _manfid, _oemid, _rev_start, _rev_end, \ #define _FIXUP_EXT(_name, _manfid, _oemid, _rev_start, _rev_end, \
_cis_vendor, _cis_device, \ _cis_vendor, _cis_device, \
@ -418,11 +417,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
#define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT) #define mmc_card_present(c) ((c)->state & MMC_STATE_PRESENT)
#define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY) #define mmc_card_readonly(c) ((c)->state & MMC_STATE_READONLY)
#define mmc_card_highspeed(c) ((c)->state & MMC_STATE_HIGHSPEED)
#define mmc_card_hs200(c) ((c)->state & MMC_STATE_HIGHSPEED_200)
#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_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)
@ -430,11 +425,7 @@ static inline void __maybe_unused remove_quirk(struct mmc_card *card, int data)
#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)
#define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
#define mmc_card_set_hs200(c) ((c)->state |= MMC_STATE_HIGHSPEED_200)
#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_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)

View file

@ -248,20 +248,6 @@ struct dw_mci_board {
/* delay in mS before detecting cards after interrupt */ /* delay in mS before detecting cards after interrupt */
u32 detect_delay_ms; u32 detect_delay_ms;
int (*init)(u32 slot_id, irq_handler_t , void *);
int (*get_ro)(u32 slot_id);
int (*get_cd)(u32 slot_id);
int (*get_ocr)(u32 slot_id);
int (*get_bus_wd)(u32 slot_id);
/*
* Enable power to selected slot and set voltage to desired level.
* Voltage levels are specified using MMC_VDD_xxx defines defined
* in linux/mmc/host.h file.
*/
void (*setpower)(u32 slot_id, u32 volt);
void (*exit)(u32 slot_id);
void (*select_slot)(u32 slot_id);
struct dw_mci_dma_ops *dma_ops; struct dw_mci_dma_ops *dma_ops;
struct dma_pdata *data; struct dma_pdata *data;
struct block_settings *blk_settings; struct block_settings *blk_settings;

View file

@ -17,6 +17,7 @@
#include <linux/fault-inject.h> #include <linux/fault-inject.h>
#include <linux/mmc/core.h> #include <linux/mmc/core.h>
#include <linux/mmc/card.h>
#include <linux/mmc/pm.h> #include <linux/mmc/pm.h>
struct mmc_ios { struct mmc_ios {
@ -58,13 +59,9 @@ struct mmc_ios {
#define MMC_TIMING_UHS_SDR50 5 #define MMC_TIMING_UHS_SDR50 5
#define MMC_TIMING_UHS_SDR104 6 #define MMC_TIMING_UHS_SDR104 6
#define MMC_TIMING_UHS_DDR50 7 #define MMC_TIMING_UHS_DDR50 7
#define MMC_TIMING_MMC_HS200 8 #define MMC_TIMING_MMC_DDR52 8
#define MMC_TIMING_MMC_HS200 9
#define MMC_SDR_MODE 0 #define MMC_TIMING_MMC_HS400 10
#define MMC_1_2V_DDR_MODE 1
#define MMC_1_8V_DDR_MODE 2
#define MMC_1_2V_SDR_MODE 3
#define MMC_1_8V_SDR_MODE 4
unsigned char signal_voltage; /* signalling voltage (1.8V or 3.3V) */ unsigned char signal_voltage; /* signalling voltage (1.8V or 3.3V) */
@ -136,6 +133,9 @@ struct mmc_host_ops {
/* The tuning command opcode value is different for SD and eMMC cards */ /* The tuning command opcode value is different for SD and eMMC cards */
int (*execute_tuning)(struct mmc_host *host, u32 opcode); int (*execute_tuning)(struct mmc_host *host, u32 opcode);
/* Prepare HS400 target operating frequency depending host driver */
int (*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
int (*select_drive_strength)(unsigned int max_dtr, int host_drv, int card_drv); int (*select_drive_strength)(unsigned int max_dtr, int host_drv, int card_drv);
void (*hw_reset)(struct mmc_host *host); void (*hw_reset)(struct mmc_host *host);
void (*card_event)(struct mmc_host *host); void (*card_event)(struct mmc_host *host);
@ -278,6 +278,11 @@ struct mmc_host {
#define MMC_CAP2_PACKED_CMD (MMC_CAP2_PACKED_RD | \ #define MMC_CAP2_PACKED_CMD (MMC_CAP2_PACKED_RD | \
MMC_CAP2_PACKED_WR) MMC_CAP2_PACKED_WR)
#define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14) /* Don't power up before scan */ #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14) /* Don't power up before scan */
#define MMC_CAP2_HS400_1_8V (1 << 15) /* Can support HS400 1.8V */
#define MMC_CAP2_HS400_1_2V (1 << 16) /* Can support HS400 1.2V */
#define MMC_CAP2_HS400 (MMC_CAP2_HS400_1_8V | \
MMC_CAP2_HS400_1_2V)
#define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 17)
mmc_pm_flag_t pm_caps; /* supported pm features */ mmc_pm_flag_t pm_caps; /* supported pm features */
@ -318,6 +323,8 @@ struct mmc_host {
int rescan_disable; /* disable card detection */ int rescan_disable; /* disable card detection */
int rescan_entered; /* used with nonremovable devices */ int rescan_entered; /* used with nonremovable devices */
bool trigger_card_event; /* card_event necessary */
struct mmc_card *card; /* device attached to this host */ struct mmc_card *card; /* device attached to this host */
wait_queue_head_t wq; wait_queue_head_t wq;
@ -391,12 +398,13 @@ static inline void mmc_signal_sdio_irq(struct mmc_host *host)
wake_up_process(host->sdio_irq_thread); wake_up_process(host->sdio_irq_thread);
} }
void sdio_run_irqs(struct mmc_host *host);
#ifdef CONFIG_REGULATOR #ifdef CONFIG_REGULATOR
int mmc_regulator_get_ocrmask(struct regulator *supply); int mmc_regulator_get_ocrmask(struct regulator *supply);
int mmc_regulator_set_ocr(struct mmc_host *mmc, int mmc_regulator_set_ocr(struct mmc_host *mmc,
struct regulator *supply, struct regulator *supply,
unsigned short vdd_bit); unsigned short vdd_bit);
int mmc_regulator_get_supply(struct mmc_host *mmc);
#else #else
static inline int mmc_regulator_get_ocrmask(struct regulator *supply) static inline int mmc_regulator_get_ocrmask(struct regulator *supply)
{ {
@ -409,13 +417,10 @@ static inline int mmc_regulator_set_ocr(struct mmc_host *mmc,
{ {
return 0; return 0;
} }
static inline int mmc_regulator_get_supply(struct mmc_host *mmc)
{
return 0;
}
#endif #endif
int mmc_regulator_get_supply(struct mmc_host *mmc);
int mmc_pm_notify(struct notifier_block *notify_block, unsigned long, void *); int mmc_pm_notify(struct notifier_block *notify_block, unsigned long, void *);
static inline int mmc_card_is_removable(struct mmc_host *host) static inline int mmc_card_is_removable(struct mmc_host *host)
@ -475,4 +480,32 @@ static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
return host->ios.clock; return host->ios.clock;
} }
#endif #endif
static inline int mmc_card_hs(struct mmc_card *card)
{
return card->host->ios.timing == MMC_TIMING_SD_HS ||
card->host->ios.timing == MMC_TIMING_MMC_HS;
}
static inline int mmc_card_uhs(struct mmc_card *card)
{
return card->host->ios.timing >= MMC_TIMING_UHS_SDR12 &&
card->host->ios.timing <= MMC_TIMING_UHS_DDR50;
}
static inline bool mmc_card_hs200(struct mmc_card *card)
{
return card->host->ios.timing == MMC_TIMING_MMC_HS200;
}
static inline bool mmc_card_ddr52(struct mmc_card *card)
{
return card->host->ios.timing == MMC_TIMING_MMC_DDR52;
}
static inline bool mmc_card_hs400(struct mmc_card *card)
{
return card->host->ios.timing == MMC_TIMING_MMC_HS400;
}
#endif /* LINUX_MMC_HOST_H */ #endif /* LINUX_MMC_HOST_H */

View file

@ -325,6 +325,7 @@ struct _mmc_csd {
#define EXT_CSD_POWER_OFF_LONG_TIME 247 /* RO */ #define EXT_CSD_POWER_OFF_LONG_TIME 247 /* RO */
#define EXT_CSD_GENERIC_CMD6_TIME 248 /* RO */ #define EXT_CSD_GENERIC_CMD6_TIME 248 /* RO */
#define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */ #define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */
#define EXT_CSD_PWR_CL_DDR_200_360 253 /* RO */
#define EXT_CSD_TAG_UNIT_SIZE 498 /* RO */ #define EXT_CSD_TAG_UNIT_SIZE 498 /* RO */
#define EXT_CSD_DATA_TAG_SUPPORT 499 /* RO */ #define EXT_CSD_DATA_TAG_SUPPORT 499 /* RO */
#define EXT_CSD_MAX_PACKED_WRITES 500 /* RO */ #define EXT_CSD_MAX_PACKED_WRITES 500 /* RO */
@ -354,18 +355,25 @@ struct _mmc_csd {
#define EXT_CSD_CMD_SET_SECURE (1<<1) #define EXT_CSD_CMD_SET_SECURE (1<<1)
#define EXT_CSD_CMD_SET_CPSECURE (1<<2) #define EXT_CSD_CMD_SET_CPSECURE (1<<2)
#define EXT_CSD_CARD_TYPE_26 (1<<0) /* Card can run at 26MHz */ #define EXT_CSD_CARD_TYPE_HS_26 (1<<0) /* Card can run at 26MHz */
#define EXT_CSD_CARD_TYPE_52 (1<<1) /* Card can run at 52MHz */ #define EXT_CSD_CARD_TYPE_HS_52 (1<<1) /* Card can run at 52MHz */
#define EXT_CSD_CARD_TYPE_MASK 0x3F /* Mask out reserved bits */ #define EXT_CSD_CARD_TYPE_HS (EXT_CSD_CARD_TYPE_HS_26 | \
EXT_CSD_CARD_TYPE_HS_52)
#define EXT_CSD_CARD_TYPE_DDR_1_8V (1<<2) /* Card can run at 52MHz */ #define EXT_CSD_CARD_TYPE_DDR_1_8V (1<<2) /* Card can run at 52MHz */
/* DDR mode @1.8V or 3V I/O */ /* DDR mode @1.8V or 3V I/O */
#define EXT_CSD_CARD_TYPE_DDR_1_2V (1<<3) /* Card can run at 52MHz */ #define EXT_CSD_CARD_TYPE_DDR_1_2V (1<<3) /* Card can run at 52MHz */
/* DDR mode @1.2V I/O */ /* DDR mode @1.2V I/O */
#define EXT_CSD_CARD_TYPE_DDR_52 (EXT_CSD_CARD_TYPE_DDR_1_8V \ #define EXT_CSD_CARD_TYPE_DDR_52 (EXT_CSD_CARD_TYPE_DDR_1_8V \
| EXT_CSD_CARD_TYPE_DDR_1_2V) | EXT_CSD_CARD_TYPE_DDR_1_2V)
#define EXT_CSD_CARD_TYPE_SDR_1_8V (1<<4) /* Card can run at 200MHz */ #define EXT_CSD_CARD_TYPE_HS200_1_8V (1<<4) /* Card can run at 200MHz */
#define EXT_CSD_CARD_TYPE_SDR_1_2V (1<<5) /* Card can run at 200MHz */ #define EXT_CSD_CARD_TYPE_HS200_1_2V (1<<5) /* Card can run at 200MHz */
/* SDR mode @1.2V I/O */ /* SDR mode @1.2V I/O */
#define EXT_CSD_CARD_TYPE_HS200 (EXT_CSD_CARD_TYPE_HS200_1_8V | \
EXT_CSD_CARD_TYPE_HS200_1_2V)
#define EXT_CSD_CARD_TYPE_HS400_1_8V (1<<6) /* Card can run at 200MHz DDR, 1.8V */
#define EXT_CSD_CARD_TYPE_HS400_1_2V (1<<7) /* Card can run at 200MHz DDR, 1.2V */
#define EXT_CSD_CARD_TYPE_HS400 (EXT_CSD_CARD_TYPE_HS400_1_8V | \
EXT_CSD_CARD_TYPE_HS400_1_2V)
#define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */ #define EXT_CSD_BUS_WIDTH_1 0 /* Card is in 1 bit mode */
#define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */ #define EXT_CSD_BUS_WIDTH_4 1 /* Card is in 4 bit mode */
@ -373,6 +381,11 @@ struct _mmc_csd {
#define EXT_CSD_DDR_BUS_WIDTH_4 5 /* Card is in 4 bit DDR mode */ #define EXT_CSD_DDR_BUS_WIDTH_4 5 /* Card is in 4 bit DDR mode */
#define EXT_CSD_DDR_BUS_WIDTH_8 6 /* Card is in 8 bit DDR mode */ #define EXT_CSD_DDR_BUS_WIDTH_8 6 /* Card is in 8 bit DDR mode */
#define EXT_CSD_TIMING_BC 0 /* Backwards compatility */
#define EXT_CSD_TIMING_HS 1 /* High speed */
#define EXT_CSD_TIMING_HS200 2 /* HS200 */
#define EXT_CSD_TIMING_HS400 3 /* HS400 */
#define EXT_CSD_SEC_ER_EN BIT(0) #define EXT_CSD_SEC_ER_EN BIT(0)
#define EXT_CSD_SEC_BD_BLK_EN BIT(2) #define EXT_CSD_SEC_BD_BLK_EN BIT(2)
#define EXT_CSD_SEC_GB_CL_EN BIT(4) #define EXT_CSD_SEC_GB_CL_EN BIT(4)

View file

@ -57,12 +57,8 @@ struct sdhci_host {
#define SDHCI_QUIRK_BROKEN_CARD_DETECTION (1<<15) #define SDHCI_QUIRK_BROKEN_CARD_DETECTION (1<<15)
/* Controller reports inverted write-protect state */ /* Controller reports inverted write-protect state */
#define SDHCI_QUIRK_INVERTED_WRITE_PROTECT (1<<16) #define SDHCI_QUIRK_INVERTED_WRITE_PROTECT (1<<16)
/* Controller has nonstandard clock management */
#define SDHCI_QUIRK_NONSTANDARD_CLOCK (1<<17)
/* Controller does not like fast PIO transfers */ /* Controller does not like fast PIO transfers */
#define SDHCI_QUIRK_PIO_NEEDS_DELAY (1<<18) #define SDHCI_QUIRK_PIO_NEEDS_DELAY (1<<18)
/* Controller losing signal/interrupt enable states after reset */
#define SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET (1<<19)
/* Controller has to be forced to use block size of 2048 bytes */ /* Controller has to be forced to use block size of 2048 bytes */
#define SDHCI_QUIRK_FORCE_BLK_SZ_2048 (1<<20) #define SDHCI_QUIRK_FORCE_BLK_SZ_2048 (1<<20)
/* Controller cannot do multi-block transfers */ /* Controller cannot do multi-block transfers */
@ -147,6 +143,7 @@ struct sdhci_host {
bool runtime_suspended; /* Host is runtime suspended */ bool runtime_suspended; /* Host is runtime suspended */
bool bus_on; /* Bus power prevents runtime suspend */ bool bus_on; /* Bus power prevents runtime suspend */
bool preset_enabled; /* Preset is enabled */
struct mmc_request *mrq; /* Current request */ struct mmc_request *mrq; /* Current request */
struct mmc_command *cmd; /* Current command */ struct mmc_command *cmd; /* Current command */
@ -164,8 +161,7 @@ struct sdhci_host {
dma_addr_t adma_addr; /* Mapped ADMA descr. table */ dma_addr_t adma_addr; /* Mapped ADMA descr. table */
dma_addr_t align_addr; /* Mapped bounce buffer */ dma_addr_t align_addr; /* Mapped bounce buffer */
struct tasklet_struct card_tasklet; /* Tasklet structures */ struct tasklet_struct finish_tasklet; /* Tasklet structures */
struct tasklet_struct finish_tasklet;
struct timer_list timer; /* Timer for timeouts */ struct timer_list timer; /* Timer for timeouts */
@ -177,6 +173,13 @@ struct sdhci_host {
unsigned int ocr_avail_mmc; unsigned int ocr_avail_mmc;
u32 ocr_mask; /* available voltages */ u32 ocr_mask; /* available voltages */
unsigned timing; /* Current timing */
u32 thread_isr;
/* cached registers */
u32 ier;
wait_queue_head_t buf_ready_int; /* Waitqueue for Buffer Read Ready interrupt */ wait_queue_head_t buf_ready_int; /* Waitqueue for Buffer Read Ready interrupt */
unsigned int tuning_done; /* Condition flag set when CMD19 succeeds */ unsigned int tuning_done; /* Condition flag set when CMD19 succeeds */

View file

@ -1,23 +1,6 @@
/*
* OMAP DMA Engine support
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __LINUX_OMAP_DMA_H #ifndef __LINUX_OMAP_DMA_H
#define __LINUX_OMAP_DMA_H #define __LINUX_OMAP_DMA_H
#include <linux/omap-dmaengine.h>
struct dma_chan;
#if defined(CONFIG_DMA_OMAP) || (defined(CONFIG_DMA_OMAP_MODULE) && defined(MODULE))
bool omap_dma_filter_fn(struct dma_chan *, void *);
#else
static inline bool omap_dma_filter_fn(struct dma_chan *c, void *d)
{
return false;
}
#endif
/* /*
* Legacy OMAP DMA handling defines and functions * Legacy OMAP DMA handling defines and functions

View file

@ -0,0 +1,21 @@
/*
* OMAP DMA Engine support
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __LINUX_OMAP_DMAENGINE_H
#define __LINUX_OMAP_DMAENGINE_H
struct dma_chan;
#if defined(CONFIG_DMA_OMAP) || (defined(CONFIG_DMA_OMAP_MODULE) && defined(MODULE))
bool omap_dma_filter_fn(struct dma_chan *, void *);
#else
static inline bool omap_dma_filter_fn(struct dma_chan *c, void *d)
{
return false;
}
#endif
#endif /* __LINUX_OMAP_DMAENGINE_H */