1
0
Fork 0

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
  ...
hifive-unleashed-5.1
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-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-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
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)
* 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.
* 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>;
num-slots = <1>;
supports-highspeed;
caps2-mmc-hs200-1_8v;
broken-cd;
fifo-depth = <0x80>;
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>
L: linux-mmc@vger.kernel.org
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
F: drivers/mmc/
F: include/linux/mmc/
@ -9103,7 +9104,7 @@ F: include/linux/toshiba.h
F: include/uapi/linux/toshiba.h
TMIO MMC DRIVER
M: Ian Molton <ian@mnementh.co.uk>
M: Ian Molton <ian.molton@codethink.co.uk>
L: linux-mmc@vger.kernel.org
S: Maintained
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)) {
pr_info("%s: new %s%s%s card on SPI\n",
mmc_hostname(card->host),
mmc_card_highspeed(card) ? "high speed " : "",
mmc_card_ddr_mode(card) ? "DDR " : "",
mmc_card_hs(card) ? "high speed " : "",
mmc_card_ddr52(card) ? "DDR " : "",
type);
} else {
pr_info("%s: new %s%s%s%s%s card at address %04x\n",
mmc_hostname(card->host),
mmc_card_uhs(card) ? "ultra high speed " :
(mmc_card_highspeed(card) ? "high speed " : ""),
(mmc_card_hs(card) ? "high speed " : ""),
mmc_card_hs400(card) ? "HS400 " :
(mmc_card_hs200(card) ? "HS200 " : ""),
mmc_card_ddr_mode(card) ? "DDR " : "",
mmc_card_ddr52(card) ? "DDR " : "",
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_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);
#endif /* CONFIG_REGULATOR */
int mmc_regulator_get_supply(struct mmc_host *mmc)
{
struct device *dev = mmc_dev(mmc);
struct regulator *supply;
int ret;
supply = devm_regulator_get(dev, "vmmc");
mmc->supply.vmmc = supply;
mmc->supply.vmmc = devm_regulator_get_optional(dev, "vmmc");
mmc->supply.vqmmc = devm_regulator_get_optional(dev, "vqmmc");
if (IS_ERR(supply))
return PTR_ERR(supply);
if (IS_ERR(mmc->supply.vmmc)) {
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 (ret > 0)
mmc->ocr_avail = ret;
else
dev_warn(mmc_dev(mmc), "Failed getting OCR mask: %d\n", ret);
if (IS_ERR(mmc->supply.vqmmc)) {
if (PTR_ERR(mmc->supply.vqmmc) == -EPROBE_DEFER)
return -EPROBE_DEFER;
dev_info(dev, "No vqmmc regulator found\n");
}
return 0;
}
EXPORT_SYMBOL_GPL(mmc_regulator_get_supply);
#endif /* CONFIG_REGULATOR */
/*
* Mask off any voltages we don't support and select
* the lowest voltage
@ -1533,8 +1544,13 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
host->ios.timing = MMC_TIMING_LEGACY;
mmc_set_ios(host);
/* Set signal voltage to 3.3V */
__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330);
/* Try to set signal voltage to 3.3V but fall back to 1.8v or 1.2v */
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
@ -2183,7 +2199,7 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen)
{
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;
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)) {
host->ios.chip_select = MMC_CS_HIGH;
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);
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)
return;

View File

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

View File

@ -447,6 +447,10 @@ int mmc_of_parse(struct mmc_host *host)
host->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
if (of_find_property(np, "mmc-hs200-1_2v", &len))
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;

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)
{
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;
unsigned int hs_max_dtr = 0;
if (card_type & EXT_CSD_CARD_TYPE_26)
hs_max_dtr = MMC_HIGH_26_MAX_DTR;
unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
unsigned int avail_type = 0;
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;
avail_type |= EXT_CSD_CARD_TYPE_HS_52;
}
if ((caps & MMC_CAP_1_8V_DDR &&
card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) ||
(caps & MMC_CAP_1_2V_DDR &&
card_type & EXT_CSD_CARD_TYPE_DDR_1_2V))
if (caps & MMC_CAP_1_8V_DDR &&
card_type & EXT_CSD_CARD_TYPE_DDR_1_8V) {
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 &&
card_type & EXT_CSD_CARD_TYPE_SDR_1_8V) ||
(caps2 & MMC_CAP2_HS200_1_2V_SDR &&
card_type & EXT_CSD_CARD_TYPE_SDR_1_2V))
hs_max_dtr = MMC_HS200_MAX_DTR;
if (caps & MMC_CAP_1_2V_DDR &&
card_type & EXT_CSD_CARD_TYPE_DDR_1_2V) {
hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
avail_type |= EXT_CSD_CARD_TYPE_DDR_1_2V;
}
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.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];
card->ext_csd.raw_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) {
@ -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 ==
bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_195]) &&
(card->ext_csd.raw_pwr_cl_ddr_52_360 ==
bw_ext_csd[EXT_CSD_PWR_CL_DDR_52_360]));
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)
err = -EINVAL;
@ -694,18 +730,10 @@ static struct attribute *mmc_std_attrs[] = {
&dev_attr_rel_sectors.attr,
NULL,
};
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,
};
ATTRIBUTE_GROUPS(mmc_std);
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
* mmc_switch command.
*/
static int mmc_select_powerclass(struct mmc_card *card,
unsigned int bus_width)
static int __mmc_select_powerclass(struct mmc_card *card,
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;
struct mmc_host *host;
BUG_ON(!card);
host = card->host;
BUG_ON(!host);
int err = 0;
/* Power class selection is supported for versions >= 4.0 */
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) {
case MMC_VDD_165_195:
if (host->ios.clock <= 26000000)
pwrclass_val = card->ext_csd.raw_pwr_cl_26_195;
else if (host->ios.clock <= 52000000)
if (host->ios.clock <= MMC_HIGH_26_MAX_DTR)
pwrclass_val = ext_csd->raw_pwr_cl_26_195;
else if (host->ios.clock <= MMC_HIGH_52_MAX_DTR)
pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
card->ext_csd.raw_pwr_cl_52_195 :
card->ext_csd.raw_pwr_cl_ddr_52_195;
else if (host->ios.clock <= 200000000)
pwrclass_val = card->ext_csd.raw_pwr_cl_200_195;
ext_csd->raw_pwr_cl_52_195 :
ext_csd->raw_pwr_cl_ddr_52_195;
else if (host->ios.clock <= MMC_HS200_MAX_DTR)
pwrclass_val = ext_csd->raw_pwr_cl_200_195;
break;
case MMC_VDD_27_28:
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_34_35:
case MMC_VDD_35_36:
if (host->ios.clock <= 26000000)
pwrclass_val = card->ext_csd.raw_pwr_cl_26_360;
else if (host->ios.clock <= 52000000)
if (host->ios.clock <= MMC_HIGH_26_MAX_DTR)
pwrclass_val = ext_csd->raw_pwr_cl_26_360;
else if (host->ios.clock <= MMC_HIGH_52_MAX_DTR)
pwrclass_val = (bus_width <= EXT_CSD_BUS_WIDTH_8) ?
card->ext_csd.raw_pwr_cl_52_360 :
card->ext_csd.raw_pwr_cl_ddr_52_360;
else if (host->ios.clock <= 200000000)
pwrclass_val = card->ext_csd.raw_pwr_cl_200_360;
ext_csd->raw_pwr_cl_52_360 :
ext_csd->raw_pwr_cl_ddr_52_360;
else if (host->ios.clock <= MMC_HS200_MAX_DTR)
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;
default:
pr_warning("%s: Voltage range not supported "
@ -787,40 +813,79 @@ static int mmc_select_powerclass(struct mmc_card *card,
return err;
}
/*
* Selects the desired buswidth and switch to the HS200 mode
* if bus width set without error
*/
static int mmc_select_hs200(struct mmc_card *card)
static int mmc_select_powerclass(struct mmc_card *card)
{
struct mmc_host *host = card->host;
u32 bus_width, ext_csd_bits;
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[] = {
EXT_CSD_BUS_WIDTH_4,
EXT_CSD_BUS_WIDTH_8,
EXT_CSD_BUS_WIDTH_4,
};
static unsigned bus_widths[] = {
MMC_BUS_WIDTH_4,
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;
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;
idx = (host->caps & MMC_CAP_8_BIT_DATA) ? 0 : 1;
/*
* 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
* 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
* 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)
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))
err = mmc_compare_ext_csds(card, bus_widths[idx]);
err = mmc_compare_ext_csds(card, bus_width);
else
err = mmc_bus_test(card, bus_widths[idx]);
if (!err)
err = mmc_bus_test(card, bus_width);
if (!err) {
err = bus_width;
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)
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,
EXT_CSD_HS_TIMING, 2,
card->ext_csd.generic_cmd6_time,
true, true, true);
EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS200,
card->ext_csd.generic_cmd6_time,
true, true, true);
if (!err)
mmc_set_timing(host, MMC_TIMING_MMC_HS200);
}
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.
*
@ -874,9 +1177,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
struct mmc_card *oldcard)
{
struct mmc_card *card;
int err, ddr = 0;
int err;
u32 cid[4];
unsigned int max_dtr;
u32 rocr;
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 = 0;
if (card->ext_csd.hs_max_dtr > 52000000 &&
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);
err = mmc_select_timing(card);
if (err)
goto free_card;
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)) {
u32 ext_csd_bits;
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);
err = mmc_hs200_tuning(card);
if (err)
pr_warning("%s: power class selection to bus width %d"
" failed\n", mmc_hostname(card->host),
1 << bus_width);
goto err;
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) &&
(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);
}
}
mmc_select_powerclass(card);
/*
* Enable HPI feature (if supported)
@ -1507,7 +1637,6 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
err = mmc_sleep(host);
else if (!mmc_host_is_spi(host))
err = mmc_deselect_cards(host);
host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
if (!err) {
mmc_power_off(host);
@ -1637,7 +1766,6 @@ static int mmc_power_restore(struct mmc_host *host)
{
int ret;
host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
mmc_claim_host(host);
ret = mmc_init_card(host, host->card->ocr, host->card);
mmc_release_host(host);

View File

@ -707,18 +707,10 @@ static struct attribute *sd_std_attrs[] = {
&dev_attr_serial.attr,
NULL,
};
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,
};
ATTRIBUTE_GROUPS(sd_std);
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;
if (mmc_card_highspeed(card)) {
if (mmc_card_hs(card)) {
if (max_dtr > card->sw_caps.hs_max_dtr)
max_dtr = card->sw_caps.hs_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;
}
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.
*
@ -985,16 +971,13 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
err = mmc_sd_init_uhs_card(card);
if (err)
goto free_card;
/* Card is an ultra-high-speed card */
mmc_card_set_uhs(card);
} else {
/*
* Attempt to change to high-speed (if supported)
*/
err = mmc_sd_switch_hs(card);
if (err > 0)
mmc_sd_go_highspeed(card);
mmc_set_timing(card->host, MMC_TIMING_SD_HS);
else if (err)
goto free_card;
@ -1089,7 +1072,7 @@ static int _mmc_sd_suspend(struct mmc_host *host)
if (!mmc_host_is_spi(host))
err = mmc_deselect_cards(host);
host->card->state &= ~MMC_STATE_HIGHSPEED;
if (!err) {
mmc_power_off(host);
mmc_card_set_suspended(host->card);
@ -1198,7 +1181,6 @@ static int mmc_sd_power_restore(struct mmc_host *host)
{
int ret;
host->card->state &= ~MMC_STATE_HIGHSPEED;
mmc_claim_host(host);
ret = mmc_sd_init_card(host, host->card->ocr, host->card);
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);
unsigned mmc_sd_get_max_clock(struct mmc_card *card);
int mmc_sd_switch_hs(struct mmc_card *card);
void mmc_sd_go_highspeed(struct mmc_card *card);
#endif

View File

@ -363,7 +363,7 @@ static unsigned mmc_sdio_get_max_clock(struct mmc_card *card)
{
unsigned max_dtr;
if (mmc_card_highspeed(card)) {
if (mmc_card_hs(card)) {
/*
* The SDIO specification doesn't mention how
* the CIS transfer speed register relates to
@ -733,7 +733,6 @@ try_again:
mmc_set_clock(host, card->cis.max_dtr);
if (card->cccr.high_speed) {
mmc_card_set_highspeed(card);
mmc_set_timing(card->host, MMC_TIMING_SD_HS);
}
@ -792,16 +791,13 @@ try_again:
err = mmc_sdio_init_uhs_card(card);
if (err)
goto remove;
/* Card is an ultra-high-speed card */
mmc_card_set_uhs(card);
} else {
/*
* Switch to high-speed (if supported).
*/
err = sdio_enable_hs(card);
if (err > 0)
mmc_sd_go_highspeed(card);
mmc_set_timing(card->host, MMC_TIMING_SD_HS);
else if (err)
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)
{
int i, err = 0;
for (i = 0; i < host->card->sdio_funcs; i++) {
struct sdio_func *func = host->card->sdio_func[i];
if (func && sdio_func_present(func) && func->dev.driver) {
const struct dev_pm_ops *pmops = func->dev.driver->pm;
err = pmops->suspend(&func->dev);
if (err)
break;
}
}
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)) {
if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
mmc_claim_host(host);
sdio_disable_wide(host->card);
mmc_release_host(host);
}
if (!err && !mmc_card_keep_power(host))
if (!mmc_card_keep_power(host))
mmc_power_off(host);
return err;
return 0;
}
static int mmc_sdio_resume(struct mmc_host *host)
{
int i, err = 0;
int err = 0;
BUG_ON(!host);
BUG_ON(!host->card);
@ -1019,24 +996,6 @@ static int mmc_sdio_resume(struct mmc_host *host)
wake_up_process(host->sdio_irq_thread);
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;
return err;
}

View File

@ -197,20 +197,8 @@ static int sdio_bus_remove(struct device *dev)
#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 = {
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(
pm_generic_runtime_suspend,
pm_generic_runtime_resume,

View File

@ -90,6 +90,15 @@ static int process_sdio_pending_irqs(struct mmc_host *host)
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)
{
struct mmc_host *host = _host;
@ -189,14 +198,20 @@ static int sdio_card_irq_get(struct mmc_card *card)
WARN_ON(!host->claimed);
if (!host->sdio_irqs++) {
atomic_set(&host->sdio_irq_thread_abort, 0);
host->sdio_irq_thread =
kthread_run(sdio_irq_thread, host, "ksdioirqd/%s",
mmc_hostname(host));
if (IS_ERR(host->sdio_irq_thread)) {
int err = PTR_ERR(host->sdio_irq_thread);
host->sdio_irqs--;
return err;
if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) {
atomic_set(&host->sdio_irq_thread_abort, 0);
host->sdio_irq_thread =
kthread_run(sdio_irq_thread, host,
"ksdioirqd/%s", mmc_hostname(host));
if (IS_ERR(host->sdio_irq_thread)) {
int err = PTR_ERR(host->sdio_irq_thread);
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);
if (!--host->sdio_irqs) {
atomic_set(&host->sdio_irq_thread_abort, 1);
kthread_stop(host->sdio_irq_thread);
if (!(host->caps2 & MMC_CAP2_SDIO_IRQ_NOTHREAD)) {
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;

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 */
struct mmc_host *host = dev_id;
if (host->ops->card_event)
host->ops->card_event(host);
host->trigger_card_event = true;
mmc_detect_change(host, msecs_to_jiffies(200));
return IRQ_HANDLED;

View File

@ -168,7 +168,7 @@ config MMC_SDHCI_ESDHC_IMX
config MMC_SDHCI_DOVE
tristate "SDHCI support on Marvell's Dove SoC"
depends on ARCH_DOVE
depends on ARCH_DOVE || MACH_DOVE
depends on MMC_SDHCI_PLTFM
select MMC_SDHCI_IO_ACCESSORS
help
@ -283,6 +283,15 @@ config MMC_SDHCI_BCM2835
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
tristate "TI OMAP Multimedia Card Interface support"
depends on ARCH_OMAP
@ -688,6 +697,12 @@ config MMC_WMT
To compile this driver as a module, choose M here: the
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
tristate "Realtek PCI-E SD/MMC Card Interface Driver"
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_USHC) += ushc.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_USDHI6ROL0) += usdhi6rol0.o
obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_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);
/*
* If the card was removed, data will be NULL. No point trying
* to send the stop command or waiting for NBUSY in this case.
*/
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);
}
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)

View File

@ -187,7 +187,7 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
unsigned long actual;
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);
/* Should be double rate for DDR mode */
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 */
static unsigned long exynos_dwmmc_caps[4] = {
MMC_CAP_UHS_DDR50 | MMC_CAP_1_8V_DDR |
MMC_CAP_8_BIT_DATA | MMC_CAP_CMD23,
MMC_CAP_1_8V_DDR | MMC_CAP_8_BIT_DATA | 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);
}
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)
.resume_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) */
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)
{
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->arg >> 9) & 0x1FFFF) == SDIO_CCCR_ABORT))
cmdr |= SDMMC_CMD_STOP;
else
if (cmd->opcode != MMC_SEND_STATUS && cmd->data)
cmdr |= SDMMC_CMD_PRV_DAT_WAIT;
else if (cmd->opcode != MMC_SEND_STATUS && cmd->data)
cmdr |= SDMMC_CMD_PRV_DAT_WAIT;
if (cmd->flags & MMC_RSP_PRESENT) {
/* We expect a response, so set this bit */
@ -850,8 +843,6 @@ static void __dw_mci_start_request(struct dw_mci *host,
u32 cmdflags;
mrq = slot->mrq;
if (host->pdata->select_slot)
host->pdata->select_slot(slot->id);
host->cur_slot = slot;
host->mrq = mrq;
@ -864,7 +855,7 @@ static void __dw_mci_start_request(struct dw_mci *host,
data = cmd->data;
if (data) {
dw_mci_set_timeout(host);
mci_writel(host, TMOUT, 0xFFFFFFFF);
mci_writel(host, BYTCNT, data->blksz*data->blocks);
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);
/* DDR mode set */
if (ios->timing == MMC_TIMING_UHS_DDR50)
if (ios->timing == MMC_TIMING_MMC_DDR52)
regs |= ((0x1 << slot->id) << 16);
else
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) {
case MMC_POWER_UP:
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 |= (1 << slot->id);
mci_writel(slot->host, PWREN, regs);
break;
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 &= ~(1 << slot->id);
mci_writel(slot->host, PWREN, regs);
@ -1009,15 +994,13 @@ static int dw_mci_get_ro(struct mmc_host *mmc)
{
int read_only;
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 */
if (slot->quirks & DW_MCI_SLOT_QUIRK_NO_WRITE_PROTECT)
read_only = 0;
else if (brd->get_ro)
read_only = brd->get_ro(slot->id);
else if (gpio_is_valid(slot->wp_gpio))
read_only = gpio_get_value(slot->wp_gpio);
else if (!IS_ERR_VALUE(gpio_ro))
read_only = gpio_ro;
else
read_only =
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 */
if (brd->quirks & DW_MCI_QUIRK_BROKEN_CARD_DETECTION)
present = 1;
else if (brd->get_cd)
present = !brd->get_cd(slot->id);
else if (!IS_ERR_VALUE(gpio_cd))
present = gpio_cd;
else
@ -1248,7 +1229,7 @@ static int dw_mci_data_complete(struct dw_mci *host, struct mmc_data *data)
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
@ -2045,86 +2026,15 @@ static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot)
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 */
static int dw_mci_of_get_slot_quirks(struct device *dev, u8 slot)
{
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)
{
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 */
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;
int ctrl_id, ret;
u32 freq[2];
u8 bus_width;
mmc = mmc_alloc_host(sizeof(struct dw_mci_slot), host->dev);
if (!mmc)
@ -2158,17 +2067,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
mmc->f_max = freq[1];
}
if (host->pdata->get_ocr)
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);
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
if (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)
mmc->caps2 = host->pdata->caps2;
if (host->pdata->get_bus_wd)
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;
}
mmc_of_parse(mmc);
if (host->pdata->blk_settings) {
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 */
}
slot->wp_gpio = dw_mci_of_get_wp_gpio(host->dev, slot->id);
dw_mci_of_get_cd_gpio(host->dev, slot->id, mmc);
if (dw_mci_get_cd(mmc))
set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
else
clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
ret = mmc_add_host(mmc);
if (ret)
@ -2249,10 +2138,6 @@ err_setup_bus:
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 */
mmc_remove_host(slot->mmc);
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);
}
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))
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;
}
@ -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,
"Platform data must supply select_slot function\n");
"Platform data must supply num_slots.\n");
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);
if (ret)
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->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) {
ret = drv_data->init(host);
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;
spin_lock_init(&host->lock);
@ -2666,8 +2536,6 @@ err_workqueue:
err_dmaunmap:
if (host->use_dma && host->dma_ops->exit)
host->dma_ops->exit(host);
err_regulator:
if (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.
* @host: The MMC controller this slot is using.
* @quirks: Slot-level quirks (DW_MCI_SLOT_QUIRK_XXX)
* @wp_gpio: If gpio_is_valid() we'll use this to read write protect.
* @ctype: Card type for this slot.
* @mrq: mmc_request currently being processed or waiting to be
* processed, or NULL when the slot is idle.
@ -214,7 +213,6 @@ struct dw_mci_slot {
struct dw_mci *host;
int quirks;
int wp_gpio;
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);
timeout = jz4740_mmc_poll_irq(host, JZ_MMC_IRQ_PRG_DONE);
if (timeout) {
host->state = JZ4740_MMC_STATE_DONE;
break;
if (mmc_resp_type(req->stop) & MMC_RSP_BUSY) {
timeout = jz4740_mmc_poll_irq(host,
JZ_MMC_IRQ_PRG_DONE);
if (timeout) {
host->state = JZ4740_MMC_STATE_DONE;
break;
}
}
case JZ4740_MMC_STATE_DONE:
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)
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;
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);
}
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;
/*

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),
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);
/* PIO handling, if needed. Messy business... */
@ -801,10 +815,10 @@ static int mvsd_probe(struct platform_device *pdev)
goto out;
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
dev_notice(&pdev->dev,
"lacking card detect (fall back to polling)\n");
dev_dbg(&pdev->dev, "lacking card detect (fall back to polling)\n");
return 0;
out:

View File

@ -124,9 +124,8 @@ enum mxcmci_type {
struct mxcmci_host {
struct mmc_host *mmc;
struct resource *res;
void __iomem *base;
int irq;
dma_addr_t phys_base;
int detect_irq;
struct dma_chan *dma;
struct dma_async_tx_descriptor *desc;
@ -154,8 +153,6 @@ struct mxcmci_host {
struct work_struct datawork;
spinlock_t lock;
struct regulator *vcc;
int burstlen;
int dmareq;
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 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->vcc)) {
host->vcc = NULL;
} else {
host->mmc->ocr_avail = mmc_regulator_get_ocrmask(host->vcc);
if (host->pdata && host->pdata->ocr_avail)
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 (!IS_ERR(host->mmc->supply.vmmc)) {
if (host->power_mode == MMC_POWER_UP)
mmc_regulator_set_ocr(host->mmc,
host->mmc->supply.vmmc, vdd);
else if (host->power_mode == MMC_POWER_OFF)
mmc_regulator_set_ocr(host->mmc,
host->mmc->supply.vmmc, 0);
}
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);
}
static int mxcmci_setup_dma(struct mmc_host *mmc);
#if IS_ENABLED(CONFIG_PPC_MPC512x)
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 dma_slave_config *config = &host->dma_slave_config;
config->dst_addr = host->res->start + MMC_REG_BUFFER_ACCESS;
config->src_addr = host->res->start + MMC_REG_BUFFER_ACCESS;
config->dst_addr = host->phys_base + MMC_REG_BUFFER_ACCESS;
config->src_addr = host->phys_base + MMC_REG_BUFFER_ACCESS;
config->dst_addr_width = 4;
config->src_addr_width = 4;
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;
if (host->power_mode != ios->power_mode) {
mxcmci_set_power(host, ios->power_mode, ios->vdd);
host->power_mode = ios->power_mode;
mxcmci_set_power(host, ios->vdd);
if (ios->power_mode == MMC_POWER_ON)
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)
{
struct mmc_host *mmc;
struct mxcmci_host *host = NULL;
struct resource *iores, *r;
struct mxcmci_host *host;
struct resource *res;
int ret = 0, irq;
bool dat3_card_detect = false;
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);
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
if (!iores || irq < 0)
if (irq < 0)
return -EINVAL;
r = request_mem_region(iores->start, resource_size(iores), pdev->name);
if (!r)
return -EBUSY;
mmc = mmc_alloc_host(sizeof(*host), &pdev->dev);
if (!mmc)
return -ENOMEM;
mmc = mmc_alloc_host(sizeof(struct mxcmci_host), &pdev->dev);
if (!mmc) {
ret = -ENOMEM;
goto out_release_mem;
host = mmc_priv(mmc);
host->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(host->base)) {
ret = PTR_ERR(host->base);
goto out_free;
}
host->phys_base = res->start;
ret = mmc_of_parse(mmc);
if (ret)
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_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) {
const struct platform_device_id *id_entry = of_id->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"))
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)
host->default_irq_mask =
@ -1120,19 +1098,16 @@ static int mxcmci_probe(struct platform_device *pdev)
else
host->default_irq_mask = 0;
host->res = r;
host->irq = irq;
host->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
if (IS_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");
if (IS_ERR(host->clk_per)) {
ret = PTR_ERR(host->clk_per);
goto out_iounmap;
goto out_free;
}
clk_prepare_enable(host->clk_per);
@ -1159,9 +1134,9 @@ static int mxcmci_probe(struct platform_device *pdev)
if (!host->pdata) {
host->dma = dma_request_slave_channel(&pdev->dev, "rx-tx");
} else {
r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (r) {
host->dmareq = r->start;
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (res) {
host->dmareq = res->start;
host->dma_data.peripheral_type = IMX_DMATYPE_SDHC;
host->dma_data.priority = DMA_PRIO_LOW;
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);
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)
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,
host->mmc);
if (ret)
goto out_free_irq;
goto out_free_dma;
}
init_timer(&host->watchdog);
@ -1199,20 +1175,17 @@ static int mxcmci_probe(struct platform_device *pdev)
return 0;
out_free_irq:
free_irq(host->irq, host);
out_free_dma:
if (host->dma)
dma_release_channel(host->dma);
out_clk_put:
clk_disable_unprepare(host->clk_per);
clk_disable_unprepare(host->clk_ipg);
out_iounmap:
iounmap(host->base);
out_free:
mmc_free_host(mmc);
out_release_mem:
release_mem_region(iores->start, resource_size(iores));
return ret;
}
@ -1223,30 +1196,21 @@ static int mxcmci_remove(struct platform_device *pdev)
mmc_remove_host(mmc);
if (host->vcc)
regulator_put(host->vcc);
if (host->pdata && host->pdata->exit)
host->pdata->exit(&pdev->dev, mmc);
free_irq(host->irq, host);
iounmap(host->base);
if (host->dma)
dma_release_channel(host->dma);
clk_disable_unprepare(host->clk_per);
clk_disable_unprepare(host->clk_ipg);
release_mem_region(host->res->start, resource_size(host->res));
mmc_free_host(mmc);
return 0;
}
#ifdef CONFIG_PM
static int mxcmci_suspend(struct device *dev)
static int __maybe_unused mxcmci_suspend(struct device *dev)
{
struct mmc_host *mmc = dev_get_drvdata(dev);
struct mxcmci_host *host = mmc_priv(mmc);
@ -1256,7 +1220,7 @@ static int mxcmci_suspend(struct device *dev)
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 mxcmci_host *host = mmc_priv(mmc);
@ -1266,11 +1230,7 @@ static int mxcmci_resume(struct device *dev)
return 0;
}
static const struct dev_pm_ops mxcmci_pm_ops = {
.suspend = mxcmci_suspend,
.resume = mxcmci_resume,
};
#endif
static SIMPLE_DEV_PM_OPS(mxcmci_pm_ops, mxcmci_suspend, mxcmci_resume);
static struct platform_driver mxcmci_driver = {
.probe = mxcmci_probe,
@ -1279,9 +1239,7 @@ static struct platform_driver mxcmci_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
#ifdef CONFIG_PM
.pm = &mxcmci_pm_ops,
#endif
.of_match_table = mxcmci_of_match,
}
};

View File

@ -70,6 +70,7 @@ struct mxs_mmc_host {
unsigned char bus_width;
spinlock_t lock;
int sdio_irq_en;
bool broken_cd;
};
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;
int present, ret;
if (host->broken_cd)
return -ENOSYS;
ret = mmc_gpio_get_cd(mmc);
if (ret >= 0)
return ret;
@ -568,6 +572,7 @@ static int mxs_mmc_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id =
of_match_device(mxs_mmc_dt_ids, &pdev->dev);
struct device_node *np = pdev->dev.of_node;
struct mxs_mmc_host *host;
struct mmc_host *mmc;
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_CAP_SDIO_IRQ | MMC_CAP_NEEDS_POLL;
host->broken_cd = of_property_read_bool(np, "broken-cd");
mmc->f_min = 400000;
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;
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);
}
}
@ -435,7 +435,7 @@ static void mmc_omap_send_stop_work(struct work_struct *work)
struct mmc_data *data = host->stop_data;
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);
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;
/* 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;
while (restarts < maxloops) {
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)
n = host->buffer_bytes_left;
nwords = n / 2;
nwords += n & 1; /* handle odd number of bytes to transfer */
/* Round up to handle odd number of bytes to transfer */
nwords = DIV_ROUND_UP(n, 2);
host->buffer_bytes_left -= n;
host->total_bytes_left -= n;

View File

@ -31,7 +31,7 @@
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_device.h>
#include <linux/omap-dma.h>
#include <linux/omap-dmaengine.h>
#include <linux/mmc/host.h>
#include <linux/mmc/core.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
*/
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)) {
regval = OMAP_HSMMC_READ(host->base, HCTL);
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;
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 */
else
con &= ~DDR;
@ -920,16 +920,17 @@ omap_hsmmc_xfer_done(struct omap_hsmmc_host *host, struct mmc_data *data)
static void
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) &&
!host->mrq->sbc->error && !(host->flags & AUTO_CMD23)) {
host->cmd = NULL;
omap_hsmmc_start_dma_transfer(host);
omap_hsmmc_start_command(host, host->mrq->cmd,
host->mrq->data);
return;
}
host->cmd = NULL;
if (cmd->flags & MMC_RSP_PRESENT) {
if (cmd->flags & MMC_RSP_136) {
/* response type 2 */
@ -1851,6 +1852,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
unsigned tx_req, rx_req;
struct pinctrl *pinctrl;
const struct omap_mmc_of_data *data;
void __iomem *base;
match = of_match_device(of_match_ptr(omap_mmc_of_match), &pdev->dev);
if (match) {
@ -1881,9 +1883,9 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
if (res == NULL || irq < 0)
return -ENXIO;
res = request_mem_region(res->start, resource_size(res), pdev->name);
if (res == NULL)
return -EBUSY;
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base))
return PTR_ERR(base);
ret = omap_hsmmc_gpio_init(pdata);
if (ret)
@ -1904,7 +1906,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
host->irq = irq;
host->slot_id = 0;
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->next_data.cookie = 1;
host->pbias_enabled = 0;
@ -1922,7 +1924,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
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)) {
ret = PTR_ERR(host->fclk);
host->fclk = NULL;
@ -1941,7 +1943,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
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.
*/
@ -1949,7 +1951,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
host->dbclk = NULL;
} else if (clk_prepare_enable(host->dbclk) != 0) {
dev_warn(mmc_dev(host->mmc), "Failed to enable debounce clk\n");
clk_put(host->dbclk);
host->dbclk = NULL;
}
@ -2018,7 +2019,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
}
/* 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);
if (ret) {
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) {
dev_err(mmc_dev(host->mmc),
"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 */
if ((mmc_slot(host).card_detect_irq)) {
ret = request_threaded_irq(mmc_slot(host).card_detect_irq,
NULL,
omap_hsmmc_detect,
ret = devm_request_threaded_irq(&pdev->dev,
mmc_slot(host).card_detect_irq,
NULL, omap_hsmmc_detect,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
mmc_hostname(mmc), host);
if (ret) {
@ -2089,15 +2090,12 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
err_slot_name:
mmc_remove_host(mmc);
free_irq(mmc_slot(host).card_detect_irq, host);
err_irq_cd:
if (host->use_reg)
omap_hsmmc_reg_put(host);
err_reg:
if (host->pdata->cleanup)
host->pdata->cleanup(&pdev->dev);
err_irq_cd_init:
free_irq(host->irq, host);
err_irq:
if (host->tx_chan)
dma_release_channel(host->tx_chan);
@ -2105,27 +2103,19 @@ err_irq:
dma_release_channel(host->rx_chan);
pm_runtime_put_sync(host->dev);
pm_runtime_disable(host->dev);
clk_put(host->fclk);
if (host->dbclk) {
if (host->dbclk)
clk_disable_unprepare(host->dbclk);
clk_put(host->dbclk);
}
err1:
iounmap(host->base);
mmc_free_host(mmc);
err_alloc:
omap_hsmmc_gpio_free(pdata);
err:
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res)
release_mem_region(res->start, resource_size(res));
return ret;
}
static int omap_hsmmc_remove(struct platform_device *pdev)
{
struct omap_hsmmc_host *host = platform_get_drvdata(pdev);
struct resource *res;
pm_runtime_get_sync(host->dev);
mmc_remove_host(host->mmc);
@ -2133,9 +2123,6 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
omap_hsmmc_reg_put(host);
if (host->pdata->cleanup)
host->pdata->cleanup(&pdev->dev);
free_irq(host->irq, host);
if (mmc_slot(host).card_detect_irq)
free_irq(mmc_slot(host).card_detect_irq, host);
if (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_disable(host->dev);
clk_put(host->fclk);
if (host->dbclk) {
if (host->dbclk)
clk_disable_unprepare(host->dbclk);
clk_put(host->dbclk);
}
omap_hsmmc_gpio_free(host->pdata);
iounmap(host->base);
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;
}

View File

@ -236,6 +236,9 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,
case MMC_RSP_R1:
rsp_type = SD_RSP_TYPE_R1;
break;
case MMC_RSP_R1 & ~MMC_RSP_CRC:
rsp_type = SD_RSP_TYPE_R1 | SD_NO_CHECK_CRC7;
break;
case MMC_RSP_R1B:
rsp_type = SD_RSP_TYPE_R1b;
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);
break;
case MMC_TIMING_MMC_DDR52:
case MMC_TIMING_UHS_DDR50:
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG1,
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->double_clk = false;
break;
case MMC_TIMING_MMC_DDR52:
case MMC_TIMING_UHS_DDR50:
case MMC_TIMING_UHS_SDR25:
host->ssc_depth = RTSX_SSC_DEPTH_1M;

View File

@ -34,7 +34,8 @@
#include <linux/mfd/rtsx_usb.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/workqueue.h>
#define RTSX_USB_USE_LEDS_CLASS
@ -59,7 +60,7 @@ struct rtsx_usb_sdmmc {
unsigned char power_mode;
#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
#ifdef RTSX_USB_USE_LEDS_CLASS
struct led_classdev led;
char led_name[32];
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 = {
.set_clock = sdhci_set_clock,
.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 = {
.set_clock = sdhci_set_clock,
.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,
};

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 = {
.set_clock = sdhci_set_clock,
.get_max_clock = sdhci_bcm_kona_get_max_clk,
.get_timeout_clock = sdhci_bcm_kona_get_timeout_clock,
.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,
};

View File

@ -131,8 +131,12 @@ static const struct sdhci_ops bcm2835_sdhci_ops = {
.read_l = bcm2835_sdhci_readl,
.read_w = bcm2835_sdhci_readw,
.read_b = bcm2835_sdhci_readb,
.set_clock = sdhci_set_clock,
.get_max_clock = sdhci_pltfm_clk_get_max_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 = {

View File

@ -30,13 +30,12 @@ static void sdhci_cns3xxx_set_clock(struct sdhci_host *host, unsigned int clock)
u16 clk;
unsigned long timeout;
if (clock == host->clock)
return;
host->mmc->actual_clock = 0;
sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
if (clock == 0)
goto out;
return;
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;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
out:
host->clock = clock;
}
static const struct sdhci_ops sdhci_cns3xxx_ops = {
.get_max_clock = sdhci_cns3xxx_get_max_clk,
.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 = {
@ -90,8 +90,7 @@ static const struct sdhci_pltfm_data sdhci_cns3xxx_pdata = {
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
SDHCI_QUIRK_INVERTED_WRITE_PROTECT |
SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN |
SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
SDHCI_QUIRK_NONSTANDARD_CLOCK,
SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
};
static int sdhci_cns3xxx_probe(struct platform_device *pdev)

View File

@ -21,28 +21,17 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/mmc/host.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include "sdhci-pltfm.h"
struct sdhci_dove_priv {
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)
{
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)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_dove_priv *priv = pltfm_host->priv;
u32 ret;
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 */
ret &= ~SDHCI_CAN_VDD_300;
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;
}
@ -86,6 +65,10 @@ static u32 sdhci_dove_readl(struct sdhci_host *host, int reg)
static const struct sdhci_ops sdhci_dove_ops = {
.read_w = sdhci_dove_readw,
.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 = {
@ -113,28 +96,9 @@ static int sdhci_dove_probe(struct platform_device *pdev)
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);
if (IS_ERR(host)) {
ret = PTR_ERR(host);
goto err_sdhci_pltfm_init;
}
if (IS_ERR(host))
return PTR_ERR(host);
pltfm_host = sdhci_priv(host);
pltfm_host->priv = priv;
@ -142,39 +106,20 @@ static int sdhci_dove_probe(struct platform_device *pdev)
if (!IS_ERR(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);
if (ret)
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;
err_request_irq:
sdhci_remove_host(host, 0);
err_sdhci_add:
if (!IS_ERR(priv->clk))
clk_disable_unprepare(priv->clk);
sdhci_pltfm_free(pdev);
err_sdhci_pltfm_init:
if (gpio_is_valid(priv->gpio_cd))
gpio_free(priv->gpio_cd);
return ret;
}
@ -186,11 +131,6 @@ static int sdhci_dove_remove(struct platform_device *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))
clk_disable_unprepare(priv->clk);

View File

@ -160,7 +160,6 @@ struct pltfm_imx_data {
MULTIBLK_IN_PROCESS, /* exact multiblock cmd in process */
WAIT_FOR_INT, /* sent CMD12, waiting for response INT */
} multiblock_status;
u32 uhs_mode;
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)
ret |= SDHCI_CTRL_TUNED_CLK;
ret |= (imx_data->uhs_mode & SDHCI_CTRL_UHS_MASK);
ret &= ~SDHCI_CTRL_PRESET_VAL_ENABLE;
return ret;
@ -429,7 +427,6 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg)
else
new_val &= ~ESDHC_VENDOR_SPEC_VSELECT;
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) {
new_val = readl(host->ioaddr + ESDHC_MIX_CTRL);
if (val & SDHCI_CTRL_TUNED_CLK)
@ -600,12 +597,14 @@ static inline void esdhc_pltfm_set_clock(struct sdhci_host *host,
u32 temp, val;
if (clock == 0) {
host->mmc->actual_clock = 0;
if (esdhc_is_usdhc(imx_data)) {
val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
host->ioaddr + ESDHC_VENDOR_SPEC);
}
goto out;
return;
}
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);
out:
host->clock = clock;
}
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;
}
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;
@ -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,
SDHCI_HOST_CONTROL);
return 0;
}
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 */
mdelay(1);
/* This is balanced by the runtime put in sdhci_tasklet_finish */
pm_runtime_get_sync(host->mmc->parent);
reg = readl(host->ioaddr + ESDHC_MIX_CTRL);
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);
}
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_request mrq = {NULL};
struct mmc_data data = {0};
struct scatterlist sg;
char tuning_pattern[ESDHC_TUNING_BLOCK_PATTERN_LEN];
cmd.opcode = opcode;
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.blocks = 1;
data.flags = MMC_DATA_READ;
data.sg = &sg;
data.sg = sg;
data.sg_len = 1;
sg_init_one(&sg, tuning_pattern, sizeof(tuning_pattern));
mrq.cmd = &cmd;
mrq.cmd->mrq = &mrq;
mrq.data = &data;
@ -742,14 +735,12 @@ static int esdhc_send_tuning_cmd(struct sdhci_host *host, u32 opcode)
mrq.done = esdhc_request_done;
init_completion(&(mrq.completion));
disable_irq(host->irq);
spin_lock(&host->lock);
spin_lock_irq(&host->lock);
host->mrq = &mrq;
sdhci_send_command(host, mrq.cmd);
spin_unlock(&host->lock);
enable_irq(host->irq);
spin_unlock_irq(&host->lock);
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)
{
struct scatterlist sg;
char *tuning_pattern;
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 */
min = ESDHC_TUNE_CTRL_MIN;
while (min < ESDHC_TUNE_CTRL_MAX) {
esdhc_prepare_tuning(host, min);
if (!esdhc_send_tuning_cmd(host, opcode))
if (!esdhc_send_tuning_cmd(host, opcode, &sg))
break;
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;
while (max < ESDHC_TUNE_CTRL_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;
break;
}
@ -797,9 +796,11 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
/* use average delay to get the best timing */
avg = (min + max) / 2;
esdhc_prepare_tuning(host, avg);
ret = esdhc_send_tuning_cmd(host, opcode);
ret = esdhc_send_tuning_cmd(host, opcode, &sg);
esdhc_post_tuning(host);
kfree(tuning_pattern);
dev_dbg(mmc_dev(host->mmc), "tunning %s at 0x%x ret %d\n",
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);
}
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 pltfm_imx_data *imx_data = pltfm_host->priv;
struct esdhc_platform_data *boarddata = &imx_data->boarddata;
switch (uhs) {
switch (timing) {
case MMC_TIMING_UHS_SDR12:
imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR12;
break;
case MMC_TIMING_UHS_SDR25:
imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR25;
break;
case MMC_TIMING_UHS_SDR50:
imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR50;
break;
case MMC_TIMING_UHS_SDR104:
case MMC_TIMING_MMC_HS200:
imx_data->uhs_mode = SDHCI_CTRL_UHS_SDR104;
break;
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) |
ESDHC_MIX_CTRL_DDREN,
host->ioaddr + ESDHC_MIX_CTRL);
@ -875,7 +869,15 @@ static int esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
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 = {
@ -888,8 +890,9 @@ static struct sdhci_ops sdhci_esdhc_ops = {
.get_max_clock = esdhc_pltfm_get_max_clock,
.get_min_clock = esdhc_pltfm_get_min_clock,
.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,
.reset = esdhc_reset,
};
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);
clk_disable_unprepare(imx_data->clk_per);
clk_disable_unprepare(imx_data->clk_ipg);
if (!sdhci_sdio_irq_enabled(host)) {
clk_disable_unprepare(imx_data->clk_per);
clk_disable_unprepare(imx_data->clk_ipg);
}
clk_disable_unprepare(imx_data->clk_ahb);
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 pltfm_imx_data *imx_data = pltfm_host->priv;
clk_prepare_enable(imx_data->clk_per);
clk_prepare_enable(imx_data->clk_ipg);
if (!sdhci_sdio_irq_enabled(host)) {
clk_prepare_enable(imx_data->clk_per);
clk_prepare_enable(imx_data->clk_ipg);
}
clk_prepare_enable(imx_data->clk_ahb);
return sdhci_runtime_resume_host(host);

View File

@ -20,10 +20,8 @@
#define ESDHC_DEFAULT_QUIRKS (SDHCI_QUIRK_FORCE_BLK_SZ_2048 | \
SDHCI_QUIRK_NO_BUSY_IRQ | \
SDHCI_QUIRK_NONSTANDARD_CLOCK | \
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | \
SDHCI_QUIRK_PIO_NEEDS_DELAY | \
SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
SDHCI_QUIRK_PIO_NEEDS_DELAY)
#define ESDHC_SYSTEM_CONTROL 0x2c
#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 = {
.set_clock = sdhci_set_clock,
.get_max_clock = sdhci_pltfm_clk_get_max_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 = {

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)
{
int pre_div = 2;
int div = 1;
u32 temp;
host->mmc->actual_clock = 0;
if (clock == 0)
goto out;
return;
/* Workaround to reduce the clock frequency for 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));
sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
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)
{
u32 vvn;
@ -269,7 +254,7 @@ static void esdhc_of_platform_init(struct sdhci_host *host)
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;
@ -289,8 +274,6 @@ static int esdhc_pltfm_bus_width(struct sdhci_host *host, int width)
clrsetbits_be32(host->ioaddr + SDHCI_HOST_CONTROL,
ESDHC_CTRL_BUSWIDTH_MASK, ctrl);
return 0;
}
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_min_clock = esdhc_of_get_min_clock,
.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,
.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 = {
/*
* card detection could be handled via GPIO
@ -374,7 +390,7 @@ static struct platform_driver sdhci_esdhc_driver = {
.name = "sdhci-esdhc",
.owner = THIS_MODULE,
.of_match_table = sdhci_esdhc_of_match,
.pm = SDHCI_PLTFM_PMOPS,
.pm = ESDHC_PMOPS,
},
.probe = sdhci_esdhc_probe,
.remove = sdhci_esdhc_remove,

View File

@ -58,6 +58,10 @@ static const struct sdhci_ops sdhci_hlwd_ops = {
.write_l = sdhci_hlwd_writel,
.write_w = sdhci_hlwd_writew,
.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 = {

View File

@ -21,6 +21,45 @@
#include "sdhci-pci.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)
{
u32 scratch_32;
@ -216,6 +255,40 @@ int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip)
scratch &= 0x7f;
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 */
ret = pci_read_config_dword(chip->pdev,
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);
ret = pci_read_config_dword(chip->pdev,
O2_SD_FUNC_REG0, &scratch_32);
O2_SD_PLL_SETTING, &scratch_32);
if ((scratch_32 & 0xff000000) == 0x01000000) {
scratch_32 &= 0x0000FFFF;
@ -299,6 +372,9 @@ int sdhci_pci_o2_probe(struct sdhci_pci_chip *chip)
O2_SD_FUNC_REG4, scratch_32);
}
/* Set Tuning Windows to 5 */
pci_write_config_byte(chip->pdev,
O2_SD_TUNING_CTRL, 0x55);
/* Lock WP */
ret = pci_read_config_byte(chip->pdev,
O2_SD_LOCK_WP, &scratch);

View File

@ -57,6 +57,9 @@
#define O2_SD_UHS2_L1_CTRL 0x35C
#define O2_SD_FUNC_REG3 0x3E0
#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_SETTING2 0x1C8

View File

@ -1031,7 +1031,7 @@ static int sdhci_pci_enable_dma(struct sdhci_host *host)
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;
@ -1052,8 +1052,6 @@ static int sdhci_pci_bus_width(struct sdhci_host *host, int width)
}
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
return 0;
}
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 = {
.set_clock = sdhci_set_clock,
.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,
};

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);
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

View File

@ -51,11 +51,13 @@
#define MMC_CARD 0x1000
#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 sdhci_pxa_platdata *pdata = pdev->dev.platform_data;
sdhci_reset(host, mask);
if (mask == SDHCI_RESET_ALL) {
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;
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);
writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
return 0;
}
static const struct sdhci_ops pxav2_sdhci_ops = {
.set_clock = sdhci_set_clock,
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
.platform_reset_exit = pxav2_set_private_registers,
.platform_bus_width = pxav2_mmc_set_width,
.set_bus_width = pxav2_mmc_set_bus_width,
.reset = pxav2_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
};
#ifdef CONFIG_OF

View File

@ -112,11 +112,13 @@ static int mv_conf_mbus_windows(struct platform_device *pdev,
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 sdhci_pxa_platdata *pdata = pdev->dev.platform_data;
sdhci_reset(host, mask);
if (mask == SDHCI_RESET_ALL) {
/*
* 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;
}
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;
@ -218,15 +220,16 @@ static int pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
dev_dbg(mmc_dev(host->mmc),
"%s uhs = %d, ctrl_2 = %04X\n",
__func__, uhs, ctrl_2);
return 0;
}
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,
.platform_send_init_74_clocks = pxav3_gen_init_74_clocks,
.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 = {

View File

@ -33,9 +33,6 @@
#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
* @host: The SDHCI host created
@ -58,6 +55,8 @@ struct sdhci_s3c {
struct clk *clk_io;
struct clk *clk_bus[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 {
unsigned int sdhci_quirks;
bool no_divider;
};
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
* 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);
return wanted - rate;
}
@ -161,9 +161,13 @@ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock)
int src;
u32 ctrl;
host->mmc->actual_clock = 0;
/* don't bother if the clock is going off. */
if (clock == 0)
if (clock == 0) {
sdhci_set_clock(host, clock);
return;
}
for (src = 0; src < MAX_BUS_CLK; src++) {
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)
ctrl |= (S3C_SDHCI_CTRL3_FCSEL3 | S3C_SDHCI_CTRL3_FCSEL2);
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;
u16 clk = 0;
host->mmc->actual_clock = 0;
/* If the clock is going off, set to 0 at clock control register */
if (clock == 0) {
sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
host->clock = clock;
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);
host->clock = clock;
clk = SDHCI_CLOCK_INT_EN;
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
* @width: MMC_BUS_WIDTH_ macro for the bus width being requested
*
* We have 8-bit width support but is not a v3 controller.
* 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;
@ -358,93 +363,23 @@ static int sdhci_s3c_platform_bus_width(struct sdhci_host *host, int width)
}
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
return 0;
}
static struct sdhci_ops sdhci_s3c_ops = {
.get_max_clock = sdhci_s3c_get_max_clk,
.set_clock = sdhci_s3c_set_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
static int sdhci_s3c_parse_dt(struct device *dev,
struct sdhci_host *host, struct s3c_sdhci_platdata *pdata)
{
struct device_node *node = dev->of_node;
struct sdhci_s3c *ourhost = to_s3c(host);
u32 max_width;
int gpio;
/* if the bus-width property is not specified, assume width as 1 */
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;
}
gpio = 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;
if (of_get_named_gpio(node, "cd-gpios", 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 */
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 */
host->quirks |= SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC;
host->quirks |= SDHCI_QUIRK_NO_HISPD_BIT;
if (drv_data)
if (drv_data) {
host->quirks |= drv_data->sdhci_quirks;
sc->no_divider = drv_data->no_divider;
}
#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,
* 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.get_min_clock = sdhci_cmu_get_min_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_suspend_ignore_children(&pdev->dev, 1);
mmc_of_parse(host->mmc);
ret = sdhci_add_host(host);
if (ret) {
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;
}
/* 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
if (pdata->cd_type != S3C_SDHCI_CD_INTERNAL)
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_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)
free_irq(sc->ext_cd_irq, sc);
#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);
#endif
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)
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)
#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 = {
.set_clock = sdhci_set_clock,
.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 = {

View File

@ -38,7 +38,10 @@ struct spear_sdhci {
/* sdhci 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

View File

@ -32,11 +32,17 @@
/* Tegra SDHOST controller vendor register definitions */
#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_DDR50 0x200
#define NVQUIRK_FORCE_SDHCI_SPEC_200 BIT(0)
#define NVQUIRK_ENABLE_BLOCK_GAP_DET BIT(1)
#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 {
const struct sdhci_pltfm_data *pdata;
@ -48,19 +54,6 @@ struct sdhci_tegra {
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)
{
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);
}
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_tegra *tegra_host = pltfm_host->priv;
const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;
u32 misc_ctrl;
sdhci_reset(host, mask);
if (!(mask & SDHCI_RESET_ALL))
return;
misc_ctrl = sdhci_readw(host, SDHCI_TEGRA_VENDOR_MISC_CTRL);
/* Erratum: Enable SDHCI spec v3.00 support */
if (soc_data->nvquirks & NVQUIRK_ENABLE_SDHCI_SPEC_300) {
u32 misc_ctrl;
misc_ctrl = sdhci_readb(host, SDHCI_TEGRA_VENDOR_MISC_CTRL);
if (soc_data->nvquirks & NVQUIRK_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;
@ -144,23 +144,25 @@ static int tegra_sdhci_buswidth(struct sdhci_host *host, int bus_width)
ctrl &= ~SDHCI_CTRL_4BITBUS;
}
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
return 0;
}
static const struct sdhci_ops tegra_sdhci_ops = {
.get_ro = tegra_sdhci_get_ro,
.read_l = tegra_sdhci_readl,
.read_w = tegra_sdhci_readw,
.write_l = tegra_sdhci_writel,
.platform_bus_width = tegra_sdhci_buswidth,
.platform_reset_exit = tegra_sdhci_reset_exit,
.set_clock = sdhci_set_clock,
.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 = {
.quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL |
SDHCI_QUIRK_SINGLE_POWER_WRITE |
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,
};
@ -175,13 +177,16 @@ static const struct sdhci_pltfm_data sdhci_tegra30_pdata = {
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
SDHCI_QUIRK_SINGLE_POWER_WRITE |
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,
};
static struct sdhci_tegra_soc_data soc_data_tegra30 = {
.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 = {
@ -189,12 +194,16 @@ static const struct sdhci_pltfm_data sdhci_tegra114_pdata = {
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK |
SDHCI_QUIRK_SINGLE_POWER_WRITE |
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,
};
static struct sdhci_tegra_soc_data soc_data_tegra114 = {
.pdata = &sdhci_tegra114_pdata,
.nvquirks = NVQUIRK_DISABLE_SDR50 |
NVQUIRK_DISABLE_DDR50 |
NVQUIRK_DISABLE_SDR104,
};
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_min_clock)(struct sdhci_host *host);
unsigned int (*get_timeout_clock)(struct sdhci_host *host);
int (*platform_bus_width)(struct sdhci_host *host,
int width);
void (*set_bus_width)(struct sdhci_host *host, int width);
void (*platform_send_init_74_clocks)(struct sdhci_host *host,
u8 power_mode);
unsigned int (*get_ro)(struct sdhci_host *host);
void (*platform_reset_enter)(struct sdhci_host *host, u8 mask);
void (*platform_reset_exit)(struct sdhci_host *host, u8 mask);
void (*reset)(struct sdhci_host *host, u8 mask);
int (*platform_execute_tuning)(struct sdhci_host *host, u32 opcode);
int (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
void (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
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 (*platform_init)(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,
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
extern int sdhci_suspend_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;
}
switch (host->timing) {
case MMC_TIMING_UHS_DDR50:
case MMC_TIMING_MMC_DDR52:
/*
* MMC core will only set this timing, if the host
* advertises the MMC_CAP_UHS_DDR50 capability. MMCIF
* implementations with this capability, e.g. sh73a0,
* will have to set it in their platform data.
* advertises the MMC_CAP_1_8V_DDR/MMC_CAP_1_2V_DDR
* capability. MMCIF implementations with this
* capability, e.g. sh73a0, will have to set it
* in their platform data.
*/
tmp |= CMD_SET_DARS;
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,
mmc->max_blk_count * 16,
&priv->dma_desc_device_addr,
208);
GFP_KERNEL);
if (!priv->dma_desc_buffer) {
dev_err(&pdev->dev, "DMA alloc fail\n");
ret = -EPERM;

View File

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

View File

@ -63,12 +63,12 @@ struct mmc_ext_csd {
unsigned int power_off_longtime; /* Units: ms */
u8 power_off_notification; /* state */
unsigned int hs_max_dtr;
unsigned int hs200_max_dtr;
#define MMC_HIGH_26_MAX_DTR 26000000
#define MMC_HIGH_52_MAX_DTR 52000000
#define MMC_HIGH_DDR_MAX_DTR 52000000
#define MMC_HS200_MAX_DTR 200000000
unsigned int sectors;
unsigned int card_type;
unsigned int hc_erase_size; /* In sectors */
unsigned int hc_erase_timeout; /* In milliseconds */
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_ddr_52_195; /* 238 */
u8 raw_pwr_cl_ddr_52_360; /* 239 */
u8 raw_pwr_cl_ddr_200_360; /* 253 */
u8 raw_bkops_status; /* 246 */
u8 raw_sectors[4]; /* 212 - 4 bytes */
@ -194,6 +195,7 @@ struct sdio_cis {
};
struct mmc_host;
struct mmc_ios;
struct sdio_func;
struct sdio_func_tuple;
@ -250,15 +252,11 @@ struct mmc_card {
unsigned int state; /* (our) card state */
#define MMC_STATE_PRESENT (1<<0) /* present in sysfs */
#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<<3) /* card uses block-addressing */
#define MMC_STATE_HIGHSPEED_DDR (1<<4) /* card is in high speed mode */
#define MMC_STATE_ULTRAHIGHSPEED (1<<5) /* card is in ultra high speed mode */
#define MMC_CARD_SDXC (1<<6) /* card is SDXC */
#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 */
#define MMC_STATE_BLOCKADDR (1<<2) /* card uses block-addressing */
#define MMC_CARD_SDXC (1<<3) /* card is SDXC */
#define MMC_CARD_REMOVED (1<<4) /* card has been removed */
#define MMC_STATE_DOING_BKOPS (1<<5) /* card is doing BKOPS */
#define MMC_STATE_SUSPENDED (1<<6) /* card is suspended */
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_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 */
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 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_NAME_ANY (NULL)
#define END_FIXUP { 0 }
#define END_FIXUP { NULL }
#define _FIXUP_EXT(_name, _manfid, _oemid, _rev_start, _rev_end, \
_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_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_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_removed(c) ((c) && ((c)->state & MMC_CARD_REMOVED))
#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_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_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_removed(c) ((c)->state |= MMC_CARD_REMOVED)
#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 */
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 dma_pdata *data;
struct block_settings *blk_settings;

View File

@ -17,6 +17,7 @@
#include <linux/fault-inject.h>
#include <linux/mmc/core.h>
#include <linux/mmc/card.h>
#include <linux/mmc/pm.h>
struct mmc_ios {
@ -58,13 +59,9 @@ struct mmc_ios {
#define MMC_TIMING_UHS_SDR50 5
#define MMC_TIMING_UHS_SDR104 6
#define MMC_TIMING_UHS_DDR50 7
#define MMC_TIMING_MMC_HS200 8
#define MMC_SDR_MODE 0
#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
#define MMC_TIMING_MMC_DDR52 8
#define MMC_TIMING_MMC_HS200 9
#define MMC_TIMING_MMC_HS400 10
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 */
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);
void (*hw_reset)(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 | \
MMC_CAP2_PACKED_WR)
#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 */
@ -318,6 +323,8 @@ struct mmc_host {
int rescan_disable; /* disable card detection */
int rescan_entered; /* used with nonremovable devices */
bool trigger_card_event; /* card_event necessary */
struct mmc_card *card; /* device attached to this host */
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);
}
void sdio_run_irqs(struct mmc_host *host);
#ifdef CONFIG_REGULATOR
int mmc_regulator_get_ocrmask(struct regulator *supply);
int mmc_regulator_set_ocr(struct mmc_host *mmc,
struct regulator *supply,
unsigned short vdd_bit);
int mmc_regulator_get_supply(struct mmc_host *mmc);
#else
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;
}
static inline int mmc_regulator_get_supply(struct mmc_host *mmc)
{
return 0;
}
#endif
int mmc_regulator_get_supply(struct mmc_host *mmc);
int mmc_pm_notify(struct notifier_block *notify_block, unsigned long, void *);
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;
}
#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 */

View File

@ -325,6 +325,7 @@ struct _mmc_csd {
#define EXT_CSD_POWER_OFF_LONG_TIME 247 /* RO */
#define EXT_CSD_GENERIC_CMD6_TIME 248 /* RO */
#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_DATA_TAG_SUPPORT 499 /* 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_CPSECURE (1<<2)
#define EXT_CSD_CARD_TYPE_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_MASK 0x3F /* Mask out reserved bits */
#define EXT_CSD_CARD_TYPE_HS_26 (1<<0) /* Card can run at 26MHz */
#define EXT_CSD_CARD_TYPE_HS_52 (1<<1) /* Card can run at 52MHz */
#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 */
/* DDR mode @1.8V or 3V I/O */
#define EXT_CSD_CARD_TYPE_DDR_1_2V (1<<3) /* Card can run at 52MHz */
/* DDR mode @1.2V I/O */
#define EXT_CSD_CARD_TYPE_DDR_52 (EXT_CSD_CARD_TYPE_DDR_1_8V \
| 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_SDR_1_2V (1<<5) /* 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_HS200_1_2V (1<<5) /* Card can run at 200MHz */
/* 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_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_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_BD_BLK_EN BIT(2)
#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)
/* Controller reports inverted write-protect state */
#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 */
#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 */
#define SDHCI_QUIRK_FORCE_BLK_SZ_2048 (1<<20)
/* Controller cannot do multi-block transfers */
@ -147,6 +143,7 @@ struct sdhci_host {
bool runtime_suspended; /* Host is runtime suspended */
bool bus_on; /* Bus power prevents runtime suspend */
bool preset_enabled; /* Preset is enabled */
struct mmc_request *mrq; /* Current request */
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 align_addr; /* Mapped bounce buffer */
struct tasklet_struct card_tasklet; /* Tasklet structures */
struct tasklet_struct finish_tasklet;
struct tasklet_struct finish_tasklet; /* Tasklet structures */
struct timer_list timer; /* Timer for timeouts */
@ -177,6 +173,13 @@ struct sdhci_host {
unsigned int ocr_avail_mmc;
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 */
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
#define __LINUX_OMAP_DMA_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
#include <linux/omap-dmaengine.h>
/*
* 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 */