]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
Merge remote-tracking branch 'mmc/mmc-next'
authorStephen Rothwell <sfr@canb.auug.org.au>
Tue, 10 Jun 2014 03:06:06 +0000 (13:06 +1000)
committerStephen Rothwell <sfr@canb.auug.org.au>
Tue, 10 Jun 2014 03:06:10 +0000 (13:06 +1000)
Conflicts:
drivers/mmc/host/Makefile
drivers/mmc/host/rtsx_usb_sdmmc.c
include/linux/omap-dma.h

67 files changed:
Documentation/devicetree/bindings/mmc/mmc.txt
Documentation/devicetree/bindings/mmc/moxa,moxart-mmc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/sunxi-mmc.txt [deleted file]
Documentation/devicetree/bindings/mmc/synopsys-dw-mshc.txt
Documentation/devicetree/bindings/mmc/usdhi6rol0.txt [new file with mode: 0644]
MAINTAINERS
drivers/mmc/core/bus.c
drivers/mmc/core/core.c
drivers/mmc/core/debugfs.c
drivers/mmc/core/host.c
drivers/mmc/core/mmc.c
drivers/mmc/core/sd.c
drivers/mmc/core/sd.h
drivers/mmc/core/sdio.c
drivers/mmc/core/sdio_bus.c
drivers/mmc/core/sdio_irq.c
drivers/mmc/core/slot-gpio.c
drivers/mmc/host/Kconfig
drivers/mmc/host/Makefile
drivers/mmc/host/atmel-mci.c
drivers/mmc/host/dw_mmc-exynos.c
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/dw_mmc.h
drivers/mmc/host/jz4740_mmc.c
drivers/mmc/host/mmci.c
drivers/mmc/host/moxart-mmc.c [new file with mode: 0644]
drivers/mmc/host/mvsdio.c
drivers/mmc/host/mxcmmc.c
drivers/mmc/host/mxs-mmc.c
drivers/mmc/host/omap.c
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/rtsx_pci_sdmmc.c
drivers/mmc/host/rtsx_usb_sdmmc.c
drivers/mmc/host/sdhci-acpi.c
drivers/mmc/host/sdhci-bcm-kona.c
drivers/mmc/host/sdhci-bcm2835.c
drivers/mmc/host/sdhci-cns3xxx.c
drivers/mmc/host/sdhci-dove.c
drivers/mmc/host/sdhci-esdhc-imx.c
drivers/mmc/host/sdhci-esdhc.h
drivers/mmc/host/sdhci-of-arasan.c
drivers/mmc/host/sdhci-of-esdhc.c
drivers/mmc/host/sdhci-of-hlwd.c
drivers/mmc/host/sdhci-pci-o2micro.c
drivers/mmc/host/sdhci-pci-o2micro.h
drivers/mmc/host/sdhci-pci.c
drivers/mmc/host/sdhci-pltfm.c
drivers/mmc/host/sdhci-pxav2.c
drivers/mmc/host/sdhci-pxav3.c
drivers/mmc/host/sdhci-s3c.c
drivers/mmc/host/sdhci-sirf.c
drivers/mmc/host/sdhci-spear.c
drivers/mmc/host/sdhci-tegra.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
drivers/mmc/host/sh_mmcif.c
drivers/mmc/host/sunxi-mmc.c [deleted file]
drivers/mmc/host/usdhi6rol0.c [new file with mode: 0644]
drivers/mmc/host/wmt-sdmmc.c
drivers/net/wireless/rsi/rsi_91x_sdio.c
include/linux/mmc/card.h
include/linux/mmc/dw_mmc.h
include/linux/mmc/host.h
include/linux/mmc/mmc.h
include/linux/mmc/sdhci.h
include/linux/omap-dma.h
include/linux/omap-dmaengine.h [new file with mode: 0644]

index 9dce540771fb115f9b1eb8e0d73dca574589595e..3c18001dfd5d75fe91038926fd6da8f98637fe88 100644 (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"
diff --git a/Documentation/devicetree/bindings/mmc/moxa,moxart-mmc.txt b/Documentation/devicetree/bindings/mmc/moxa,moxart-mmc.txt
new file mode 100644 (file)
index 0000000..b638191
--- /dev/null
@@ -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";
+       };
diff --git a/Documentation/devicetree/bindings/mmc/sunxi-mmc.txt b/Documentation/devicetree/bindings/mmc/sunxi-mmc.txt
deleted file mode 100644 (file)
index 91b3a34..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-* Allwinner sunxi MMC controller
-
-The highspeed MMC host controller on Allwinner SoCs provides an interface
-for MMC, SD and SDIO types of memory cards.
-
-Supported maximum speeds are the ones of the eMMC standard 4.5 as well
-as the speed of SD standard 3.0.
-Absolute maximum transfer rate is 200MB/s
-
-Required properties:
- - compatible : "allwinner,sun4i-a10-mmc" or "allwinner,sun5i-a13-mmc"
- - reg : mmc controller base registers
- - clocks : a list with 2 phandle + clock specifier pairs
- - clock-names : must contain "ahb" and "mmc"
- - interrupts : mmc controller interrupt
-
-Optional properties:
- - resets : phandle + reset specifier pair
- - reset-names : must contain "ahb"
- - for cd, bus-width and additional generic mmc parameters
-   please refer to mmc.txt within this directory
-
-Examples:
-       - Within .dtsi:
-       mmc0: mmc@01c0f000 {
-               compatible = "allwinner,sun5i-a13-mmc";
-               reg = <0x01c0f000 0x1000>;
-               clocks = <&ahb_gates 8>, <&mmc0_clk>;
-               clock-names = "ahb", "mod";
-               interrupts = <0 32 4>;
-               status = "disabled";
-       };
-
-       - Within dts:
-       mmc0: mmc@01c0f000 {
-               pinctrl-names = "default", "default";
-               pinctrl-0 = <&mmc0_pins_a>;
-               pinctrl-1 = <&mmc0_cd_pin_reference_design>;
-               bus-width = <4>;
-               cd-gpios = <&pio 7 1 0>; /* PH1 */
-               cd-inverted;
-               status = "okay";
-       };
index 8f3f13315358028f20a5a79720e6a27266caf2be..2d4a7258a10db9d2c30dc808bb7b5ad5e74fa994 100644 (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>;
diff --git a/Documentation/devicetree/bindings/mmc/usdhi6rol0.txt b/Documentation/devicetree/bindings/mmc/usdhi6rol0.txt
new file mode 100644 (file)
index 0000000..8babdaa
--- /dev/null
@@ -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>;
+};
index 350072bc65eb95120db8544f4273901436d49402..b76f2929f1493da0b18d4bb58f6d30481d0e5232 100644 (file)
@@ -5981,6 +5981,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/
@@ -9088,7 +9089,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*
index 824644875d41691fe6dc099c53e4770f1cbea23e..d2dbf02022bd05803cda6ad5b0e9b4d201721b32 100644 (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);
        }
 
index acbc3f2aaaf9e3adff743de7081e1e6508b6b03c..7dc0c85fdb6067b980b7cfd636e4c23a98d1803c 100644 (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;
 
index 54829c0ed0002fcc08f193b6af6112eabd00699d..91eb162232462d6f5f142904d9c4fea5b9e65451 100644 (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";
index fdea825dbb240238b66531214b7761bda4b698eb..95cceae96944c17c19dbb4e9916119a72fb2bce6 100644 (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;
 
index 1ab5f3a0af5b734a1829e732fe91b5bef8f24d2b..793c6f7ddb049a735916eae87585b5cfb0f3b452 100644 (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;
+       unsigned int hs_max_dtr = 0, hs200_max_dtr = 0;
+       unsigned int avail_type = 0;
 
-       if (card_type & EXT_CSD_CARD_TYPE_26)
+       if (caps & MMC_CAP_MMC_HIGHSPEED &&
+           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_52)
+           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) {
+               hs_max_dtr = MMC_HIGH_DDR_MAX_DTR;
+               avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
+       }
 
-       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_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_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 (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;
 }
 
+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;
+}
+
 /*
- * Selects the desired buswidth and switch to the HS200 mode
- * if bus width set without error
+ * Set the bus speed for the selected speed mode.
  */
-static int mmc_select_hs200(struct mmc_card *card)
+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);
-
-       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;
+       if ((card->csd.mmca_vsn < CSD_SPEC_VER_4) &&
+           !(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)))
+               return 0;
 
-       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)
-        */
-       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);
-
-               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).
+        * Select timing interface
         */
-       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;
-       }
+       err = mmc_select_timing(card);
+       if (err)
+               goto free_card;
 
-       /*
-        * 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));
+               err = mmc_hs200_tuning(card);
+               if (err)
                        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_select_hs400(card);
                if (err)
-                       pr_warning("%s: power class selection to bus width %d"
-                                  " failed\n", mmc_hostname(card->host),
-                                  1 << bus_width);
+                       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);
index 2dd359d2242fa811efae1a03d02ca9d9dfba77ca..0c44510bf717874808a0e1d20de68aa3cf2afda5 100644 (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);
index 4b34b24f3f762f62ea026b491661f9e496d99b8d..aab824a9a7f369b858b663797807c07088b29142 100644 (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
index 4d721c6e2af01026ea967dbd54bdaf17c8648aee..e636d9e99e4ae7faa698bb77a33285b301a33523 100644 (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;
 }
index 92d1ba8e8153ab9849ab51037804747cd37df7f1..4fa8fef9147f75ec4e9ff974957093bb28f0ec6a 100644 (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,
index aaa90460ed234c1d6744f5cef073f053c18c1afb..5cc13c8d35bbf3b2c60c8bc68054e05bec0e62fc 100644 (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;
index f7650b899e3d426fbce08e8b636784adf0d0cdf0..5f89cb83d5f00008aa3c98f550f9ff962c0306c0 100644 (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;
index 779368b683d02283f242b4edf529029b4b099b03..a75ab5dda3c8152a6d5a5c15716aaead551f8339 100644 (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
@@ -701,10 +716,3 @@ config MMC_REALTEK_USB
        help
          Say Y here to include driver code to support SD/MMC card interface
          of Realtek RTS5129/39 series card reader
-
-config MMC_SUNXI
-       tristate "Allwinner sunxi SD/MMC Host Controller support"
-       depends on ARCH_SUNXI
-       help
-         This selects support for the SD/MMC Host Controller on
-         Allwinner sunxi SoCs.
index 61cbc241935b2bf3fc9d7749c89070b5b7bf839f..203d57c2bfa61c7546df77ce47647a370b49673d 100644 (file)
@@ -50,7 +50,8 @@ 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_SUNXI)                += sunxi-mmc.o
+obj-$(CONFIG_MMC_MOXART)       += moxart-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
index 42706ea0ba85407cdead6259756fd4ed1b898016..aece7cafbb9701c6dee629a622d156c74499dbc2 100644 (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)
index 3423c5ed50c7a0ec918af7c7adcba7b2e5d2baed..0fbc53ac7eae8fb27f60b12575be4cabbe759c15 100644 (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,
index cced599d5aebe22aef357fd427a6aa03d7edaa79..1ac227c603b7e13a687b631eff298ce16222707d 100644 (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);
 
index 68349779c39614cd397723c86f810651b8e93754..738fa241d05882258958107348a75b511c76fc08 100644 (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;
 
index de2139cf344477bbe8922448a963c9e1094dd882..537d6c7a5ae48a9458dd3674cf56a975a8331996 100644 (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;
index a084edd37af53f379a429d40ea0f9ab6851b80f5..7ad463e9741c0e4359b0c2c10a43f83ea3683995 100644 (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;
 
        /*
diff --git a/drivers/mmc/host/moxart-mmc.c b/drivers/mmc/host/moxart-mmc.c
new file mode 100644 (file)
index 0000000..74924a0
--- /dev/null
@@ -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>");
index 45aa2206741db8da3bebac2f6b94385add678ced..9377284f8544be955d01e3839250c848928380c6 100644 (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:
index f7199c83f5cf8e85c49ed54b575502d0187fc8c3..ed1cb93c3784b54a62916e9aeb0540db2bf303e6 100644 (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)
-{
-       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)
+static void mxcmci_set_power(struct mxcmci_host *host, 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;
+
+       host = mmc_priv(mmc);
 
-       mmc = mmc_alloc_host(sizeof(struct mxcmci_host), &pdev->dev);
-       if (!mmc) {
-               ret = -ENOMEM;
-               goto out_release_mem;
+       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,
        }
 };
index 073e871a0fc8fe8ef00e6aca2da8a46b172488e6..babfea03ba8a0ce50b64fae4e0bcbcc96ef0e60e 100644 (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;
 
index 5c2e58b29305ce4cab01e34c2d3e17b842979334..81974ecdfcbcb7a1649eee6eeab7a14dd8f49600 100644 (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;
index e91ee21549d03ad22c2bcf2287f61074cc3d889b..6b7b75585926c44d2fc39fdda4f0d58e73ec392a 100644 (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;
 }
 
index 0b9ded13a3ae89d72a94e7e8e075f62496483f0e..0d519649b5758a943512f16b853bbfff095ee442 100644 (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;
index e11fafa6fc6be82b9c65a43e35ca1027dd3e575a..5d3766e792f0855cd117b42fab7068e3c90a7726 100644 (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;
index ebb3f392b5894f6af8705604a38476b4e0048aa3..8ce3c28cb76ed503e9ea16605e059fa93780ea1a 100644 (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,
 };
 
index 6f166e63b8172fd5484796584cb36c8291410aeb..dd780c315a638edbfb90dbdae818472f927a0c5e 100644 (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,
 };
 
index f6d8d67c545f882678ea40bca4f2525a77bf28bf..46af9a439d7b48c772f68352253ba23641d756ea 100644 (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 = {
index f2cc26633cb2442bc67e1d46bb52ab044be02598..14b74075589afd5b24ce594bb0b42adf7f5ae1cc 100644 (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)
index 736d7a2eb7ec454a0bde08de0ae9bc3ba0b006e0..e6278ec007d775c576346102e358426e08c3edbe 100644 (file)
 
 #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);
 
index b841bb7cd3714c11982a7f2b652a946dfb5e811c..ccec0e32590f6b5f9336f0fc77df279e429756a2 100644 (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);
index a7d9f95a7b03dd81af540212ef8016157a595c5e..3497cfaf683c539edbd062199e03f5692e43bb26 100644 (file)
 
 #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
index f7c7cf62437d5d359c4b216d5c0bd6e8af91a5b1..5bd1092310f2e6c1b742ce11e3b590119be66435 100644 (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 = {
index 0b249970b1197fcc92af6e63184c72cf7c406286..8be4dcfb49a05f12c2f2711323e321af8f529625 100644 (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,13 +288,46 @@ 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 = {
        /*
@@ -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,
index 57c514a81ca558777474c699a2cac27fcc265ec9..b341661369a20a645ea3356e2d8a71cfb42a9ee0 100644 (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 = {
index f49666bcc52a7244cdde83ced6117c022343bb07..5670e381b0cf7888c07614b15b7a3fda53ce2d45 100644 (file)
 #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);
index dbec4c933488f317a851ab7761e7d7cf10cd2187..f7ffc908d9a0d2f83b13a7a00e09c635aceb5079 100644 (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
index fdc612120362000be42b145240acd96a306695de..52c42fcc284c4b3dca6cd889b562954d9bfc6352 100644 (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,
 };
 
index bef250e954188c3feb5d6d0889c1c32ef620de39..7e834fb78f427d2c085dce62956337d126e7e4f3 100644 (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
index d51e061ec576a666cb2fa19edf77725ef0905cdf..3c0f3c0a1cc86969f5f72dfaa27d6fdc2f083b58 100644 (file)
 #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
index 2fd73b38c303da0d57a592c82e227e800e6c2b60..f4f128947561266e63b47f74c3af458c22aca27b 100644 (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 = {
index d61eb5a708331d54ad9c4ea948bf7cbb4533d8da..fa5954a05449f9ae0116c1db1d486458674e8d0b 100644 (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
index 696122c1b468b315968128fb5a414fee21c740bd..17004531d089e6c2bce4fc33d319f6fdf3cb377f 100644 (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 = {
index 0316dec3f0060e5ad7a8d83a35421018e210811c..9d535c7336ef8425ab40bc6d6abea91553f17294 100644 (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
index a835898a68dd3be47fcbb720a9e83c5da3701458..d93a063a36f37bc5d25c6f6c1b3beba5c8d544a9 100644 (file)
 
 /* 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[] = {
index 9a79fc4b60ca82bb7319fa34a3ae2d79d093833e..47055f3f01b8580e01ff147232d106bc14db3667 100644 (file)
@@ -44,6 +44,8 @@
 
 #define MAX_TUNING_LOOP 40
 
+#define ADMA_SIZE      ((128 * 2 + 1) * 4)
+
 static unsigned int debug_quirks = 0;
 static unsigned int debug_quirks2;
 
@@ -131,43 +133,26 @@ static void sdhci_dumpregs(struct sdhci_host *host)
  *                                                                           *
 \*****************************************************************************/
 
-static void sdhci_clear_set_irqs(struct sdhci_host *host, u32 clear, u32 set)
-{
-       u32 ier;
-
-       ier = sdhci_readl(host, SDHCI_INT_ENABLE);
-       ier &= ~clear;
-       ier |= set;
-       sdhci_writel(host, ier, SDHCI_INT_ENABLE);
-       sdhci_writel(host, ier, SDHCI_SIGNAL_ENABLE);
-}
-
-static void sdhci_unmask_irqs(struct sdhci_host *host, u32 irqs)
-{
-       sdhci_clear_set_irqs(host, 0, irqs);
-}
-
-static void sdhci_mask_irqs(struct sdhci_host *host, u32 irqs)
-{
-       sdhci_clear_set_irqs(host, irqs, 0);
-}
-
 static void sdhci_set_card_detection(struct sdhci_host *host, bool enable)
 {
-       u32 present, irqs;
+       u32 present;
 
        if ((host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION) ||
            (host->mmc->caps & MMC_CAP_NONREMOVABLE))
                return;
 
-       present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
-                             SDHCI_CARD_PRESENT;
-       irqs = present ? SDHCI_INT_CARD_REMOVE : SDHCI_INT_CARD_INSERT;
+       if (enable) {
+               present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
+                                     SDHCI_CARD_PRESENT;
 
-       if (enable)
-               sdhci_unmask_irqs(host, irqs);
-       else
-               sdhci_mask_irqs(host, irqs);
+               host->ier |= present ? SDHCI_INT_CARD_REMOVE :
+                                      SDHCI_INT_CARD_INSERT;
+       } else {
+               host->ier &= ~(SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT);
+       }
+
+       sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+       sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 }
 
 static void sdhci_enable_card_detection(struct sdhci_host *host)
@@ -180,22 +165,9 @@ static void sdhci_disable_card_detection(struct sdhci_host *host)
        sdhci_set_card_detection(host, false);
 }
 
-static void sdhci_reset(struct sdhci_host *host, u8 mask)
+void sdhci_reset(struct sdhci_host *host, u8 mask)
 {
        unsigned long timeout;
-       u32 uninitialized_var(ier);
-
-       if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
-               if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) &
-                       SDHCI_CARD_PRESENT))
-                       return;
-       }
-
-       if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
-               ier = sdhci_readl(host, SDHCI_INT_ENABLE);
-
-       if (host->ops->platform_reset_enter)
-               host->ops->platform_reset_enter(host, mask);
 
        sdhci_writeb(host, mask, SDHCI_SOFTWARE_RESET);
 
@@ -220,16 +192,27 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
                timeout--;
                mdelay(1);
        }
+}
+EXPORT_SYMBOL_GPL(sdhci_reset);
+
+static void sdhci_do_reset(struct sdhci_host *host, u8 mask)
+{
+       if (host->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
+               if (!(sdhci_readl(host, SDHCI_PRESENT_STATE) &
+                       SDHCI_CARD_PRESENT))
+                       return;
+       }
 
-       if (host->ops->platform_reset_exit)
-               host->ops->platform_reset_exit(host, mask);
+       host->ops->reset(host, mask);
 
-       if (host->quirks & SDHCI_QUIRK_RESTORE_IRQS_AFTER_RESET)
-               sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK, ier);
+       if (mask & SDHCI_RESET_ALL) {
+               if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
+                       if (host->ops->enable_dma)
+                               host->ops->enable_dma(host);
+               }
 
-       if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
-               if ((host->ops->enable_dma) && (mask & SDHCI_RESET_ALL))
-                       host->ops->enable_dma(host);
+               /* Resetting the controller clears many */
+               host->preset_enabled = false;
        }
 }
 
@@ -238,15 +221,18 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
 static void sdhci_init(struct sdhci_host *host, int soft)
 {
        if (soft)
-               sdhci_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA);
+               sdhci_do_reset(host, SDHCI_RESET_CMD|SDHCI_RESET_DATA);
        else
-               sdhci_reset(host, SDHCI_RESET_ALL);
+               sdhci_do_reset(host, SDHCI_RESET_ALL);
 
-       sdhci_clear_set_irqs(host, SDHCI_INT_ALL_MASK,
-               SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
-               SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX |
-               SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |
-               SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE);
+       host->ier = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
+                   SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT |
+                   SDHCI_INT_INDEX | SDHCI_INT_END_BIT | SDHCI_INT_CRC |
+                   SDHCI_INT_TIMEOUT | SDHCI_INT_DATA_END |
+                   SDHCI_INT_RESPONSE;
+
+       sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+       sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 
        if (soft) {
                /* force clock reconfiguration */
@@ -502,11 +488,6 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
        else
                direction = DMA_TO_DEVICE;
 
-       /*
-        * The ADMA descriptor table is mapped further down as we
-        * need to fill it with data first.
-        */
-
        host->align_addr = dma_map_single(mmc_dev(host->mmc),
                host->align_buffer, 128 * 4, direction);
        if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr))
@@ -567,7 +548,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
                 * If this triggers then we have a calculation bug
                 * somewhere. :/
                 */
-               WARN_ON((desc - host->adma_desc) > (128 * 2 + 1) * 4);
+               WARN_ON((desc - host->adma_desc) > ADMA_SIZE);
        }
 
        if (host->quirks & SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC) {
@@ -595,17 +576,8 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
                        host->align_addr, 128 * 4, direction);
        }
 
-       host->adma_addr = dma_map_single(mmc_dev(host->mmc),
-               host->adma_desc, (128 * 2 + 1) * 4, DMA_TO_DEVICE);
-       if (dma_mapping_error(mmc_dev(host->mmc), host->adma_addr))
-               goto unmap_entries;
-       BUG_ON(host->adma_addr & 0x3);
-
        return 0;
 
-unmap_entries:
-       dma_unmap_sg(mmc_dev(host->mmc), data->sg,
-               data->sg_len, direction);
 unmap_align:
        dma_unmap_single(mmc_dev(host->mmc), host->align_addr,
                128 * 4, direction);
@@ -623,19 +595,25 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
        u8 *align;
        char *buffer;
        unsigned long flags;
+       bool has_unaligned;
 
        if (data->flags & MMC_DATA_READ)
                direction = DMA_FROM_DEVICE;
        else
                direction = DMA_TO_DEVICE;
 
-       dma_unmap_single(mmc_dev(host->mmc), host->adma_addr,
-               (128 * 2 + 1) * 4, DMA_TO_DEVICE);
-
        dma_unmap_single(mmc_dev(host->mmc), host->align_addr,
                128 * 4, direction);
 
-       if (data->flags & MMC_DATA_READ) {
+       /* Do a quick scan of the SG list for any unaligned mappings */
+       has_unaligned = false;
+       for_each_sg(data->sg, sg, host->sg_count, i)
+               if (sg_dma_address(sg) & 3) {
+                       has_unaligned = true;
+                       break;
+               }
+
+       if (has_unaligned && data->flags & MMC_DATA_READ) {
                dma_sync_sg_for_cpu(mmc_dev(host->mmc), data->sg,
                        data->sg_len, direction);
 
@@ -721,9 +699,12 @@ static void sdhci_set_transfer_irqs(struct sdhci_host *host)
        u32 dma_irqs = SDHCI_INT_DMA_END | SDHCI_INT_ADMA_ERROR;
 
        if (host->flags & SDHCI_REQ_USE_DMA)
-               sdhci_clear_set_irqs(host, pio_irqs, dma_irqs);
+               host->ier = (host->ier & ~pio_irqs) | dma_irqs;
        else
-               sdhci_clear_set_irqs(host, dma_irqs, pio_irqs);
+               host->ier = (host->ier & ~dma_irqs) | pio_irqs;
+
+       sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+       sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 }
 
 static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
@@ -976,8 +957,8 @@ static void sdhci_finish_data(struct sdhci_host *host)
                 * upon error conditions.
                 */
                if (data->error) {
-                       sdhci_reset(host, SDHCI_RESET_CMD);
-                       sdhci_reset(host, SDHCI_RESET_DATA);
+                       sdhci_do_reset(host, SDHCI_RESET_CMD);
+                       sdhci_do_reset(host, SDHCI_RESET_DATA);
                }
 
                sdhci_send_command(host, data->stop);
@@ -1107,24 +1088,23 @@ static void sdhci_finish_command(struct sdhci_host *host)
 
 static u16 sdhci_get_preset_value(struct sdhci_host *host)
 {
-       u16 ctrl, preset = 0;
-
-       ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+       u16 preset = 0;
 
-       switch (ctrl & SDHCI_CTRL_UHS_MASK) {
-       case SDHCI_CTRL_UHS_SDR12:
+       switch (host->timing) {
+       case MMC_TIMING_UHS_SDR12:
                preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR12);
                break;
-       case SDHCI_CTRL_UHS_SDR25:
+       case MMC_TIMING_UHS_SDR25:
                preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR25);
                break;
-       case SDHCI_CTRL_UHS_SDR50:
+       case MMC_TIMING_UHS_SDR50:
                preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR50);
                break;
-       case SDHCI_CTRL_UHS_SDR104:
+       case MMC_TIMING_UHS_SDR104:
+       case MMC_TIMING_MMC_HS200:
                preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR104);
                break;
-       case SDHCI_CTRL_UHS_DDR50:
+       case MMC_TIMING_UHS_DDR50:
                preset = sdhci_readw(host, SDHCI_PRESET_FOR_DDR50);
                break;
        default:
@@ -1136,32 +1116,22 @@ static u16 sdhci_get_preset_value(struct sdhci_host *host)
        return preset;
 }
 
-static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
+void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 {
        int div = 0; /* Initialized for compiler warning */
        int real_div = div, clk_mul = 1;
        u16 clk = 0;
        unsigned long timeout;
 
-       if (clock && clock == host->clock)
-               return;
-
        host->mmc->actual_clock = 0;
 
-       if (host->ops->set_clock) {
-               host->ops->set_clock(host, clock);
-               if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK)
-                       return;
-       }
-
        sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
 
        if (clock == 0)
-               goto out;
+               return;
 
        if (host->version >= SDHCI_SPEC_300) {
-               if (sdhci_readw(host, SDHCI_HOST_CONTROL2) &
-                       SDHCI_CTRL_PRESET_VAL_ENABLE) {
+               if (host->preset_enabled) {
                        u16 pre_val;
 
                        clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
@@ -1247,26 +1217,16 @@ clock_set:
 
        clk |= SDHCI_CLOCK_CARD_EN;
        sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
-
-out:
-       host->clock = clock;
 }
+EXPORT_SYMBOL_GPL(sdhci_set_clock);
 
-static inline void sdhci_update_clock(struct sdhci_host *host)
-{
-       unsigned int clock;
-
-       clock = host->clock;
-       host->clock = 0;
-       sdhci_set_clock(host, clock);
-}
-
-static int sdhci_set_power(struct sdhci_host *host, unsigned short power)
+static void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
+                           unsigned short vdd)
 {
        u8 pwr = 0;
 
-       if (power != (unsigned short)-1) {
-               switch (1 << power) {
+       if (mode != MMC_POWER_OFF) {
+               switch (1 << vdd) {
                case MMC_VDD_165_195:
                        pwr = SDHCI_POWER_180;
                        break;
@@ -1284,7 +1244,7 @@ static int sdhci_set_power(struct sdhci_host *host, unsigned short power)
        }
 
        if (host->pwr == pwr)
-               return -1;
+               return;
 
        host->pwr = pwr;
 
@@ -1292,38 +1252,43 @@ static int sdhci_set_power(struct sdhci_host *host, unsigned short power)
                sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
                if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
                        sdhci_runtime_pm_bus_off(host);
-               return 0;
-       }
-
-       /*
-        * Spec says that we should clear the power reg before setting
-        * a new value. Some controllers don't seem to like this though.
-        */
-       if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
-               sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
+               vdd = 0;
+       } else {
+               /*
+                * Spec says that we should clear the power reg before setting
+                * a new value. Some controllers don't seem to like this though.
+                */
+               if (!(host->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
+                       sdhci_writeb(host, 0, SDHCI_POWER_CONTROL);
 
-       /*
-        * At least the Marvell CaFe chip gets confused if we set the voltage
-        * and set turn on power at the same time, so set the voltage first.
-        */
-       if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER)
-               sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
+               /*
+                * At least the Marvell CaFe chip gets confused if we set the
+                * voltage and set turn on power at the same time, so set the
+                * voltage first.
+                */
+               if (host->quirks & SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER)
+                       sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
 
-       pwr |= SDHCI_POWER_ON;
+               pwr |= SDHCI_POWER_ON;
 
-       sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
+               sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
 
-       if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
-               sdhci_runtime_pm_bus_on(host);
+               if (host->quirks2 & SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON)
+                       sdhci_runtime_pm_bus_on(host);
 
-       /*
-        * Some controllers need an extra 10ms delay of 10ms before they
-        * can apply clock after applying power
-        */
-       if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER)
-               mdelay(10);
+               /*
+                * Some controllers need an extra 10ms delay of 10ms before
+                * they can apply clock after applying power
+                */
+               if (host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER)
+                       mdelay(10);
+       }
 
-       return power;
+       if (host->vmmc) {
+               spin_unlock_irq(&host->lock);
+               mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd);
+               spin_lock_irq(&host->lock);
+       }
 }
 
 /*****************************************************************************\
@@ -1427,10 +1392,53 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
        spin_unlock_irqrestore(&host->lock, flags);
 }
 
+void sdhci_set_bus_width(struct sdhci_host *host, int width)
+{
+       u8 ctrl;
+
+       ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
+       if (width == MMC_BUS_WIDTH_8) {
+               ctrl &= ~SDHCI_CTRL_4BITBUS;
+               if (host->version >= SDHCI_SPEC_300)
+                       ctrl |= SDHCI_CTRL_8BITBUS;
+       } else {
+               if (host->version >= SDHCI_SPEC_300)
+                       ctrl &= ~SDHCI_CTRL_8BITBUS;
+               if (width == MMC_BUS_WIDTH_4)
+                       ctrl |= SDHCI_CTRL_4BITBUS;
+               else
+                       ctrl &= ~SDHCI_CTRL_4BITBUS;
+       }
+       sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
+}
+EXPORT_SYMBOL_GPL(sdhci_set_bus_width);
+
+void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
+{
+       u16 ctrl_2;
+
+       ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+       /* Select Bus Speed Mode for host */
+       ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
+       if ((timing == MMC_TIMING_MMC_HS200) ||
+           (timing == MMC_TIMING_UHS_SDR104))
+               ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
+       else if (timing == MMC_TIMING_UHS_SDR12)
+               ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
+       else if (timing == MMC_TIMING_UHS_SDR25)
+               ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
+       else if (timing == MMC_TIMING_UHS_SDR50)
+               ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
+       else if ((timing == MMC_TIMING_UHS_DDR50) ||
+                (timing == MMC_TIMING_MMC_DDR52))
+               ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
+       sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+}
+EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling);
+
 static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 {
        unsigned long flags;
-       int vdd_bit = -1;
        u8 ctrl;
 
        spin_lock_irqsave(&host->lock, flags);
@@ -1456,45 +1464,17 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
                !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN))
                sdhci_enable_preset_value(host, false);
 
-       sdhci_set_clock(host, ios->clock);
-
-       if (ios->power_mode == MMC_POWER_OFF)
-               vdd_bit = sdhci_set_power(host, -1);
-       else
-               vdd_bit = sdhci_set_power(host, ios->vdd);
-
-       if (host->vmmc && vdd_bit != -1) {
-               spin_unlock_irqrestore(&host->lock, flags);
-               mmc_regulator_set_ocr(host->mmc, host->vmmc, vdd_bit);
-               spin_lock_irqsave(&host->lock, flags);
+       if (!ios->clock || ios->clock != host->clock) {
+               host->ops->set_clock(host, ios->clock);
+               host->clock = ios->clock;
        }
 
+       sdhci_set_power(host, ios->power_mode, ios->vdd);
+
        if (host->ops->platform_send_init_74_clocks)
                host->ops->platform_send_init_74_clocks(host, ios->power_mode);
 
-       /*
-        * If your platform has 8-bit width support but is not a v3 controller,
-        * or if it requires special setup code, you should implement that in
-        * platform_bus_width().
-        */
-       if (host->ops->platform_bus_width) {
-               host->ops->platform_bus_width(host, ios->bus_width);
-       } else {
-               ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
-               if (ios->bus_width == MMC_BUS_WIDTH_8) {
-                       ctrl &= ~SDHCI_CTRL_4BITBUS;
-                       if (host->version >= SDHCI_SPEC_300)
-                               ctrl |= SDHCI_CTRL_8BITBUS;
-               } else {
-                       if (host->version >= SDHCI_SPEC_300)
-                               ctrl &= ~SDHCI_CTRL_8BITBUS;
-                       if (ios->bus_width == MMC_BUS_WIDTH_4)
-                               ctrl |= SDHCI_CTRL_4BITBUS;
-                       else
-                               ctrl &= ~SDHCI_CTRL_4BITBUS;
-               }
-               sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
-       }
+       host->ops->set_bus_width(host, ios->bus_width);
 
        ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
 
@@ -1510,19 +1490,20 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
 
                /* In case of UHS-I modes, set High Speed Enable */
                if ((ios->timing == MMC_TIMING_MMC_HS200) ||
+                   (ios->timing == MMC_TIMING_MMC_DDR52) ||
                    (ios->timing == MMC_TIMING_UHS_SDR50) ||
                    (ios->timing == MMC_TIMING_UHS_SDR104) ||
                    (ios->timing == MMC_TIMING_UHS_DDR50) ||
                    (ios->timing == MMC_TIMING_UHS_SDR25))
                        ctrl |= SDHCI_CTRL_HISPD;
 
-               ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
-               if (!(ctrl_2 & SDHCI_CTRL_PRESET_VAL_ENABLE)) {
+               if (!host->preset_enabled) {
                        sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
                        /*
                         * We only need to set Driver Strength if the
                         * preset value enable is not set.
                         */
+                       ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
                        ctrl_2 &= ~SDHCI_CTRL_DRV_TYPE_MASK;
                        if (ios->drv_type == MMC_SET_DRIVER_TYPE_A)
                                ctrl_2 |= SDHCI_CTRL_DRV_TYPE_A;
@@ -1546,7 +1527,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
                        sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
 
                        /* Re-enable SD Clock */
-                       sdhci_update_clock(host);
+                       host->ops->set_clock(host, host->clock);
                }
 
 
@@ -1555,25 +1536,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
                clk &= ~SDHCI_CLOCK_CARD_EN;
                sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
 
-               if (host->ops->set_uhs_signaling)
-                       host->ops->set_uhs_signaling(host, ios->timing);
-               else {
-                       ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
-                       /* Select Bus Speed Mode for host */
-                       ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
-                       if ((ios->timing == MMC_TIMING_MMC_HS200) ||
-                           (ios->timing == MMC_TIMING_UHS_SDR104))
-                               ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
-                       else if (ios->timing == MMC_TIMING_UHS_SDR12)
-                               ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
-                       else if (ios->timing == MMC_TIMING_UHS_SDR25)
-                               ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
-                       else if (ios->timing == MMC_TIMING_UHS_SDR50)
-                               ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
-                       else if (ios->timing == MMC_TIMING_UHS_DDR50)
-                               ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
-                       sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
-               }
+               host->ops->set_uhs_signaling(host, ios->timing);
+               host->timing = ios->timing;
 
                if (!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN) &&
                                ((ios->timing == MMC_TIMING_UHS_SDR12) ||
@@ -1590,7 +1554,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
                }
 
                /* Re-enable SD Clock */
-               sdhci_update_clock(host);
+               host->ops->set_clock(host, host->clock);
        } else
                sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
 
@@ -1600,7 +1564,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
         * it on each ios seems to solve the problem.
         */
        if(host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS)
-               sdhci_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
+               sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
 
        mmiowb();
        spin_unlock_irqrestore(&host->lock, flags);
@@ -1709,24 +1673,16 @@ static int sdhci_get_ro(struct mmc_host *mmc)
 
 static void sdhci_enable_sdio_irq_nolock(struct sdhci_host *host, int enable)
 {
-       if (host->flags & SDHCI_DEVICE_DEAD)
-               goto out;
-
-       if (enable)
-               host->flags |= SDHCI_SDIO_IRQ_ENABLED;
-       else
-               host->flags &= ~SDHCI_SDIO_IRQ_ENABLED;
-
-       /* SDIO IRQ will be enabled as appropriate in runtime resume */
-       if (host->runtime_suspended)
-               goto out;
+       if (!(host->flags & SDHCI_DEVICE_DEAD)) {
+               if (enable)
+                       host->ier |= SDHCI_INT_CARD_INT;
+               else
+                       host->ier &= ~SDHCI_INT_CARD_INT;
 
-       if (enable)
-               sdhci_unmask_irqs(host, SDHCI_INT_CARD_INT);
-       else
-               sdhci_mask_irqs(host, SDHCI_INT_CARD_INT);
-out:
-       mmiowb();
+               sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+               sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+               mmiowb();
+       }
 }
 
 static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
@@ -1734,9 +1690,18 @@ static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
        struct sdhci_host *host = mmc_priv(mmc);
        unsigned long flags;
 
+       sdhci_runtime_pm_get(host);
+
        spin_lock_irqsave(&host->lock, flags);
+       if (enable)
+               host->flags |= SDHCI_SDIO_IRQ_ENABLED;
+       else
+               host->flags &= ~SDHCI_SDIO_IRQ_ENABLED;
+
        sdhci_enable_sdio_irq_nolock(host, enable);
        spin_unlock_irqrestore(&host->lock, flags);
+
+       sdhci_runtime_pm_put(host);
 }
 
 static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
@@ -1855,22 +1820,15 @@ static int sdhci_card_busy(struct mmc_host *mmc)
 
 static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
 {
-       struct sdhci_host *host;
+       struct sdhci_host *host = mmc_priv(mmc);
        u16 ctrl;
-       u32 ier;
        int tuning_loop_counter = MAX_TUNING_LOOP;
-       unsigned long timeout;
        int err = 0;
-       bool requires_tuning_nonuhs = false;
        unsigned long flags;
 
-       host = mmc_priv(mmc);
-
        sdhci_runtime_pm_get(host);
        spin_lock_irqsave(&host->lock, flags);
 
-       ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
-
        /*
         * The Host Controller needs tuning only in case of SDR104 mode
         * and for SDR50 mode when Use Tuning for SDR50 is set in the
@@ -1878,15 +1836,18 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
         * If the Host Controller supports the HS200 mode then the
         * tuning function has to be executed.
         */
-       if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR50) &&
-           (host->flags & SDHCI_SDR50_NEEDS_TUNING ||
-            host->flags & SDHCI_SDR104_NEEDS_TUNING))
-               requires_tuning_nonuhs = true;
-
-       if (((ctrl & SDHCI_CTRL_UHS_MASK) == SDHCI_CTRL_UHS_SDR104) ||
-           requires_tuning_nonuhs)
-               ctrl |= SDHCI_CTRL_EXEC_TUNING;
-       else {
+       switch (host->timing) {
+       case MMC_TIMING_MMC_HS200:
+       case MMC_TIMING_UHS_SDR104:
+               break;
+
+       case MMC_TIMING_UHS_SDR50:
+               if (host->flags & SDHCI_SDR50_NEEDS_TUNING ||
+                   host->flags & SDHCI_SDR104_NEEDS_TUNING)
+                       break;
+               /* FALLTHROUGH */
+
+       default:
                spin_unlock_irqrestore(&host->lock, flags);
                sdhci_runtime_pm_put(host);
                return 0;
@@ -1899,6 +1860,8 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
                return err;
        }
 
+       ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+       ctrl |= SDHCI_CTRL_EXEC_TUNING;
        sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
 
        /*
@@ -1911,21 +1874,17 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
         * to make sure we don't hit a controller bug, we _only_
         * enable Buffer Read Ready interrupt here.
         */
-       ier = sdhci_readl(host, SDHCI_INT_ENABLE);
-       sdhci_clear_set_irqs(host, ier, SDHCI_INT_DATA_AVAIL);
+       sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_INT_ENABLE);
+       sdhci_writel(host, SDHCI_INT_DATA_AVAIL, SDHCI_SIGNAL_ENABLE);
 
        /*
         * Issue CMD19 repeatedly till Execute Tuning is set to 0 or the number
         * of loops reaches 40 times or a timeout of 150ms occurs.
         */
-       timeout = 150;
        do {
                struct mmc_command cmd = {0};
                struct mmc_request mrq = {NULL};
 
-               if (!tuning_loop_counter && !timeout)
-                       break;
-
                cmd.opcode = opcode;
                cmd.arg = 0;
                cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
@@ -1933,6 +1892,9 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
                cmd.data = NULL;
                cmd.error = 0;
 
+               if (tuning_loop_counter-- == 0)
+                       break;
+
                mrq.cmd = &cmd;
                host->mrq = &mrq;
 
@@ -1990,26 +1952,25 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
                host->tuning_done = 0;
 
                ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
-               tuning_loop_counter--;
-               timeout--;
-               mdelay(1);
+
+               /* eMMC spec does not require a delay between tuning cycles */
+               if (opcode == MMC_SEND_TUNING_BLOCK)
+                       mdelay(1);
        } while (ctrl & SDHCI_CTRL_EXEC_TUNING);
 
        /*
         * The Host Driver has exhausted the maximum number of loops allowed,
         * so use fixed sampling frequency.
         */
-       if (!tuning_loop_counter || !timeout) {
+       if (tuning_loop_counter < 0) {
                ctrl &= ~SDHCI_CTRL_TUNED_CLK;
                sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+       }
+       if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) {
+               pr_info(DRIVER_NAME ": Tuning procedure"
+                       " failed, falling back to fixed sampling"
+                       " clock\n");
                err = -EIO;
-       } else {
-               if (!(ctrl & SDHCI_CTRL_TUNED_CLK)) {
-                       pr_info(DRIVER_NAME ": Tuning procedure"
-                               " failed, falling back to fixed sampling"
-                               " clock\n");
-                       err = -EIO;
-               }
        }
 
 out:
@@ -2044,7 +2005,8 @@ out:
        if (err && (host->flags & SDHCI_USING_RETUNING_TIMER))
                err = 0;
 
-       sdhci_clear_set_irqs(host, SDHCI_INT_DATA_AVAIL, ier);
+       sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+       sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
        spin_unlock_irqrestore(&host->lock, flags);
        sdhci_runtime_pm_put(host);
 
@@ -2054,26 +2016,30 @@ out:
 
 static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable)
 {
-       u16 ctrl;
-
        /* Host Controller v3.00 defines preset value registers */
        if (host->version < SDHCI_SPEC_300)
                return;
 
-       ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
-
        /*
         * We only enable or disable Preset Value if they are not already
         * enabled or disabled respectively. Otherwise, we bail out.
         */
-       if (enable && !(ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) {
-               ctrl |= SDHCI_CTRL_PRESET_VAL_ENABLE;
-               sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
-               host->flags |= SDHCI_PV_ENABLED;
-       } else if (!enable && (ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) {
-               ctrl &= ~SDHCI_CTRL_PRESET_VAL_ENABLE;
+       if (host->preset_enabled != enable) {
+               u16 ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+
+               if (enable)
+                       ctrl |= SDHCI_CTRL_PRESET_VAL_ENABLE;
+               else
+                       ctrl &= ~SDHCI_CTRL_PRESET_VAL_ENABLE;
+
                sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
-               host->flags &= ~SDHCI_PV_ENABLED;
+
+               if (enable)
+                       host->flags |= SDHCI_PV_ENABLED;
+               else
+                       host->flags &= ~SDHCI_PV_ENABLED;
+
+               host->preset_enabled = enable;
        }
 }
 
@@ -2095,8 +2061,8 @@ static void sdhci_card_event(struct mmc_host *mmc)
                pr_err("%s: Resetting controller.\n",
                        mmc_hostname(host->mmc));
 
-               sdhci_reset(host, SDHCI_RESET_CMD);
-               sdhci_reset(host, SDHCI_RESET_DATA);
+               sdhci_do_reset(host, SDHCI_RESET_CMD);
+               sdhci_do_reset(host, SDHCI_RESET_DATA);
 
                host->mrq->cmd->error = -ENOMEDIUM;
                tasklet_schedule(&host->finish_tasklet);
@@ -2124,15 +2090,6 @@ static const struct mmc_host_ops sdhci_ops = {
  *                                                                           *
 \*****************************************************************************/
 
-static void sdhci_tasklet_card(unsigned long param)
-{
-       struct sdhci_host *host = (struct sdhci_host*)param;
-
-       sdhci_card_event(host->mmc);
-
-       mmc_detect_change(host->mmc, msecs_to_jiffies(200));
-}
-
 static void sdhci_tasklet_finish(unsigned long param)
 {
        struct sdhci_host *host;
@@ -2169,12 +2126,12 @@ static void sdhci_tasklet_finish(unsigned long param)
                /* Some controllers need this kick or reset won't work here */
                if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET)
                        /* This is to force an update */
-                       sdhci_update_clock(host);
+                       host->ops->set_clock(host, host->clock);
 
                /* Spec says we should do both at the same time, but Ricoh
                   controllers do not like that. */
-               sdhci_reset(host, SDHCI_RESET_CMD);
-               sdhci_reset(host, SDHCI_RESET_DATA);
+               sdhci_do_reset(host, SDHCI_RESET_CMD);
+               sdhci_do_reset(host, SDHCI_RESET_DATA);
        }
 
        host->mrq = NULL;
@@ -2424,101 +2381,94 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
 
 static irqreturn_t sdhci_irq(int irq, void *dev_id)
 {
-       irqreturn_t result;
+       irqreturn_t result = IRQ_NONE;
        struct sdhci_host *host = dev_id;
-       u32 intmask, unexpected = 0;
-       int cardint = 0, max_loops = 16;
+       u32 intmask, mask, unexpected = 0;
+       int max_loops = 16;
 
        spin_lock(&host->lock);
 
-       if (host->runtime_suspended) {
+       if (host->runtime_suspended && !sdhci_sdio_irq_enabled(host)) {
                spin_unlock(&host->lock);
                return IRQ_NONE;
        }
 
        intmask = sdhci_readl(host, SDHCI_INT_STATUS);
-
        if (!intmask || intmask == 0xffffffff) {
                result = IRQ_NONE;
                goto out;
        }
 
-again:
-       DBG("*** %s got interrupt: 0x%08x\n",
-               mmc_hostname(host->mmc), intmask);
-
-       if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
-               u32 present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
-                             SDHCI_CARD_PRESENT;
-
-               /*
-                * There is a observation on i.mx esdhc.  INSERT bit will be
-                * immediately set again when it gets cleared, if a card is
-                * inserted.  We have to mask the irq to prevent interrupt
-                * storm which will freeze the system.  And the REMOVE gets
-                * the same situation.
-                *
-                * More testing are needed here to ensure it works for other
-                * platforms though.
-                */
-               sdhci_mask_irqs(host, present ? SDHCI_INT_CARD_INSERT :
-                                               SDHCI_INT_CARD_REMOVE);
-               sdhci_unmask_irqs(host, present ? SDHCI_INT_CARD_REMOVE :
-                                                 SDHCI_INT_CARD_INSERT);
-
-               sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT |
-                            SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS);
-               intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE);
-               tasklet_schedule(&host->card_tasklet);
-       }
-
-       if (intmask & SDHCI_INT_CMD_MASK) {
-               sdhci_writel(host, intmask & SDHCI_INT_CMD_MASK,
-                       SDHCI_INT_STATUS);
-               sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
-       }
+       do {
+               /* Clear selected interrupts. */
+               mask = intmask & (SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK |
+                                 SDHCI_INT_BUS_POWER);
+               sdhci_writel(host, mask, SDHCI_INT_STATUS);
 
-       if (intmask & SDHCI_INT_DATA_MASK) {
-               sdhci_writel(host, intmask & SDHCI_INT_DATA_MASK,
-                       SDHCI_INT_STATUS);
-               sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
-       }
+               DBG("*** %s got interrupt: 0x%08x\n",
+                       mmc_hostname(host->mmc), intmask);
 
-       intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK);
+               if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
+                       u32 present = sdhci_readl(host, SDHCI_PRESENT_STATE) &
+                                     SDHCI_CARD_PRESENT;
 
-       intmask &= ~SDHCI_INT_ERROR;
+                       /*
+                        * There is a observation on i.mx esdhc.  INSERT
+                        * bit will be immediately set again when it gets
+                        * cleared, if a card is inserted.  We have to mask
+                        * the irq to prevent interrupt storm which will
+                        * freeze the system.  And the REMOVE gets the
+                        * same situation.
+                        *
+                        * More testing are needed here to ensure it works
+                        * for other platforms though.
+                        */
+                       host->ier &= ~(SDHCI_INT_CARD_INSERT |
+                                      SDHCI_INT_CARD_REMOVE);
+                       host->ier |= present ? SDHCI_INT_CARD_REMOVE :
+                                              SDHCI_INT_CARD_INSERT;
+                       sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+                       sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+
+                       sdhci_writel(host, intmask & (SDHCI_INT_CARD_INSERT |
+                                    SDHCI_INT_CARD_REMOVE), SDHCI_INT_STATUS);
+
+                       host->thread_isr |= intmask & (SDHCI_INT_CARD_INSERT |
+                                                      SDHCI_INT_CARD_REMOVE);
+                       result = IRQ_WAKE_THREAD;
+               }
 
-       if (intmask & SDHCI_INT_BUS_POWER) {
-               pr_err("%s: Card is consuming too much power!\n",
-                       mmc_hostname(host->mmc));
-               sdhci_writel(host, SDHCI_INT_BUS_POWER, SDHCI_INT_STATUS);
-       }
+               if (intmask & SDHCI_INT_CMD_MASK)
+                       sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK);
 
-       intmask &= ~SDHCI_INT_BUS_POWER;
+               if (intmask & SDHCI_INT_DATA_MASK)
+                       sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK);
 
-       if (intmask & SDHCI_INT_CARD_INT)
-               cardint = 1;
+               if (intmask & SDHCI_INT_BUS_POWER)
+                       pr_err("%s: Card is consuming too much power!\n",
+                               mmc_hostname(host->mmc));
 
-       intmask &= ~SDHCI_INT_CARD_INT;
+               if (intmask & SDHCI_INT_CARD_INT) {
+                       sdhci_enable_sdio_irq_nolock(host, false);
+                       host->thread_isr |= SDHCI_INT_CARD_INT;
+                       result = IRQ_WAKE_THREAD;
+               }
 
-       if (intmask) {
-               unexpected |= intmask;
-               sdhci_writel(host, intmask, SDHCI_INT_STATUS);
-       }
+               intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE |
+                            SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK |
+                            SDHCI_INT_ERROR | SDHCI_INT_BUS_POWER |
+                            SDHCI_INT_CARD_INT);
 
-       result = IRQ_HANDLED;
+               if (intmask) {
+                       unexpected |= intmask;
+                       sdhci_writel(host, intmask, SDHCI_INT_STATUS);
+               }
 
-       intmask = sdhci_readl(host, SDHCI_INT_STATUS);
+               if (result == IRQ_NONE)
+                       result = IRQ_HANDLED;
 
-       /*
-        * If we know we'll call the driver to signal SDIO IRQ, disregard
-        * further indications of Card Interrupt in the status to avoid a
-        * needless loop.
-        */
-       if (cardint)
-               intmask &= ~SDHCI_INT_CARD_INT;
-       if (intmask && --max_loops)
-               goto again;
+               intmask = sdhci_readl(host, SDHCI_INT_STATUS);
+       } while (intmask && --max_loops);
 out:
        spin_unlock(&host->lock);
 
@@ -2527,15 +2477,38 @@ out:
                           mmc_hostname(host->mmc), unexpected);
                sdhci_dumpregs(host);
        }
-       /*
-        * We have to delay this as it calls back into the driver.
-        */
-       if (cardint)
-               mmc_signal_sdio_irq(host->mmc);
 
        return result;
 }
 
+static irqreturn_t sdhci_thread_irq(int irq, void *dev_id)
+{
+       struct sdhci_host *host = dev_id;
+       unsigned long flags;
+       u32 isr;
+
+       spin_lock_irqsave(&host->lock, flags);
+       isr = host->thread_isr;
+       host->thread_isr = 0;
+       spin_unlock_irqrestore(&host->lock, flags);
+
+       if (isr & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
+               sdhci_card_event(host->mmc);
+               mmc_detect_change(host->mmc, msecs_to_jiffies(200));
+       }
+
+       if (isr & SDHCI_INT_CARD_INT) {
+               sdio_run_irqs(host->mmc);
+
+               spin_lock_irqsave(&host->lock, flags);
+               if (host->flags & SDHCI_SDIO_IRQ_ENABLED)
+                       sdhci_enable_sdio_irq_nolock(host, true);
+               spin_unlock_irqrestore(&host->lock, flags);
+       }
+
+       return isr ? IRQ_HANDLED : IRQ_NONE;
+}
+
 /*****************************************************************************\
  *                                                                           *
  * Suspend/resume                                                            *
@@ -2572,9 +2545,6 @@ EXPORT_SYMBOL_GPL(sdhci_disable_irq_wakeups);
 
 int sdhci_suspend_host(struct sdhci_host *host)
 {
-       if (host->ops->platform_suspend)
-               host->ops->platform_suspend(host);
-
        sdhci_disable_card_detection(host);
 
        /* Disable tuning since we are suspending */
@@ -2584,7 +2554,9 @@ int sdhci_suspend_host(struct sdhci_host *host)
        }
 
        if (!device_may_wakeup(mmc_dev(host->mmc))) {
-               sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
+               host->ier = 0;
+               sdhci_writel(host, 0, SDHCI_INT_ENABLE);
+               sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
                free_irq(host->irq, host);
        } else {
                sdhci_enable_irq_wakeups(host);
@@ -2605,8 +2577,9 @@ int sdhci_resume_host(struct sdhci_host *host)
        }
 
        if (!device_may_wakeup(mmc_dev(host->mmc))) {
-               ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
-                                 mmc_hostname(host->mmc), host);
+               ret = request_threaded_irq(host->irq, sdhci_irq,
+                                          sdhci_thread_irq, IRQF_SHARED,
+                                          mmc_hostname(host->mmc), host);
                if (ret)
                        return ret;
        } else {
@@ -2628,9 +2601,6 @@ int sdhci_resume_host(struct sdhci_host *host)
 
        sdhci_enable_card_detection(host);
 
-       if (host->ops->platform_resume)
-               host->ops->platform_resume(host);
-
        /* Set the re-tuning expiration flag */
        if (host->flags & SDHCI_USING_RETUNING_TIMER)
                host->flags |= SDHCI_NEEDS_RETUNING;
@@ -2682,10 +2652,12 @@ int sdhci_runtime_suspend_host(struct sdhci_host *host)
        }
 
        spin_lock_irqsave(&host->lock, flags);
-       sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
+       host->ier &= SDHCI_INT_CARD_INT;
+       sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+       sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
        spin_unlock_irqrestore(&host->lock, flags);
 
-       synchronize_irq(host->irq);
+       synchronize_hardirq(host->irq);
 
        spin_lock_irqsave(&host->lock, flags);
        host->runtime_suspended = true;
@@ -2729,7 +2701,7 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
        host->runtime_suspended = false;
 
        /* Enable SDIO IRQ */
-       if ((host->flags & SDHCI_SDIO_IRQ_ENABLED))
+       if (host->flags & SDHCI_SDIO_IRQ_ENABLED)
                sdhci_enable_sdio_irq_nolock(host, true);
 
        /* Enable Card Detection */
@@ -2788,7 +2760,7 @@ int sdhci_add_host(struct sdhci_host *host)
        if (debug_quirks2)
                host->quirks2 = debug_quirks2;
 
-       sdhci_reset(host, SDHCI_RESET_ALL);
+       sdhci_do_reset(host, SDHCI_RESET_ALL);
 
        host->version = sdhci_readw(host, SDHCI_HOST_VERSION);
        host->version = (host->version & SDHCI_SPEC_VER_MASK)
@@ -2848,15 +2820,29 @@ int sdhci_add_host(struct sdhci_host *host)
                 * (128) and potentially one alignment transfer for
                 * each of those entries.
                 */
-               host->adma_desc = kmalloc((128 * 2 + 1) * 4, GFP_KERNEL);
+               host->adma_desc = dma_alloc_coherent(mmc_dev(host->mmc),
+                                                    ADMA_SIZE, &host->adma_addr,
+                                                    GFP_KERNEL);
                host->align_buffer = kmalloc(128 * 4, GFP_KERNEL);
                if (!host->adma_desc || !host->align_buffer) {
-                       kfree(host->adma_desc);
+                       dma_free_coherent(mmc_dev(host->mmc), ADMA_SIZE,
+                                         host->adma_desc, host->adma_addr);
                        kfree(host->align_buffer);
                        pr_warning("%s: Unable to allocate ADMA "
                                "buffers. Falling back to standard DMA.\n",
                                mmc_hostname(mmc));
                        host->flags &= ~SDHCI_USE_ADMA;
+                       host->adma_desc = NULL;
+                       host->align_buffer = NULL;
+               } else if (host->adma_addr & 3) {
+                       pr_warning("%s: unable to allocate aligned ADMA descriptor\n",
+                                  mmc_hostname(mmc));
+                       host->flags &= ~SDHCI_USE_ADMA;
+                       dma_free_coherent(mmc_dev(host->mmc), ADMA_SIZE,
+                                         host->adma_desc, host->adma_addr);
+                       kfree(host->align_buffer);
+                       host->adma_desc = NULL;
+                       host->align_buffer = NULL;
                }
        }
 
@@ -2941,6 +2927,7 @@ int sdhci_add_host(struct sdhci_host *host)
        mmc->max_busy_timeout = (1 << 27) / host->timeout_clk;
 
        mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
+       mmc->caps2 |= MMC_CAP2_SDIO_IRQ_NOTHREAD;
 
        if (host->quirks & SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12)
                host->flags |= SDHCI_AUTO_CMD12;
@@ -3212,8 +3199,6 @@ int sdhci_add_host(struct sdhci_host *host)
        /*
         * Init tasklets.
         */
-       tasklet_init(&host->card_tasklet,
-               sdhci_tasklet_card, (unsigned long)host);
        tasklet_init(&host->finish_tasklet,
                sdhci_tasklet_finish, (unsigned long)host);
 
@@ -3230,8 +3215,8 @@ int sdhci_add_host(struct sdhci_host *host)
 
        sdhci_init(host, 0);
 
-       ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
-               mmc_hostname(mmc), host);
+       ret = request_threaded_irq(host->irq, sdhci_irq, sdhci_thread_irq,
+                                  IRQF_SHARED, mmc_hostname(mmc), host);
        if (ret) {
                pr_err("%s: Failed to request IRQ %d: %d\n",
                       mmc_hostname(mmc), host->irq, ret);
@@ -3273,12 +3258,12 @@ int sdhci_add_host(struct sdhci_host *host)
 
 #ifdef SDHCI_USE_LEDS_CLASS
 reset:
-       sdhci_reset(host, SDHCI_RESET_ALL);
-       sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
+       sdhci_do_reset(host, SDHCI_RESET_ALL);
+       sdhci_writel(host, 0, SDHCI_INT_ENABLE);
+       sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
        free_irq(host->irq, host);
 #endif
 untasklet:
-       tasklet_kill(&host->card_tasklet);
        tasklet_kill(&host->finish_tasklet);
 
        return ret;
@@ -3315,14 +3300,14 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
 #endif
 
        if (!dead)
-               sdhci_reset(host, SDHCI_RESET_ALL);
+               sdhci_do_reset(host, SDHCI_RESET_ALL);
 
-       sdhci_mask_irqs(host, SDHCI_INT_ALL_MASK);
+       sdhci_writel(host, 0, SDHCI_INT_ENABLE);
+       sdhci_writel(host, 0, SDHCI_SIGNAL_ENABLE);
        free_irq(host->irq, host);
 
        del_timer_sync(&host->timer);
 
-       tasklet_kill(&host->card_tasklet);
        tasklet_kill(&host->finish_tasklet);
 
        if (host->vmmc) {
@@ -3335,7 +3320,9 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
                regulator_put(host->vqmmc);
        }
 
-       kfree(host->adma_desc);
+       if (host->adma_desc)
+               dma_free_coherent(mmc_dev(host->mmc), ADMA_SIZE,
+                                 host->adma_desc, host->adma_addr);
        kfree(host->align_buffer);
 
        host->adma_desc = NULL;
index 0a3ed01887db824da03a66f103ef4b4948fc074f..4a5cd5e3fa3eeb7a0992976c902b99bb29316584 100644 (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);
index 54730f4aac87f0143ca08a5ca740634376fc4871..656fbba4c4223f275dffba85ebbc29ffb4574174 100644 (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;
diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c
deleted file mode 100644 (file)
index 024f67c..0000000
+++ /dev/null
@@ -1,1049 +0,0 @@
-/*
- * Driver for sunxi SD/MMC host controllers
- * (C) Copyright 2007-2011 Reuuimlla Technology Co., Ltd.
- * (C) Copyright 2007-2011 Aaron Maoye <leafy.myeh@reuuimllatech.com>
- * (C) Copyright 2013-2014 O2S GmbH <www.o2s.ch>
- * (C) Copyright 2013-2014 David Lanzend�rfer <david.lanzendoerfer@o2s.ch>
- * (C) Copyright 2013-2014 Hans de Goede <hdegoede@redhat.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-
-#include <linux/clk.h>
-#include <linux/clk-private.h>
-#include <linux/clk/sunxi.h>
-
-#include <linux/gpio.h>
-#include <linux/platform_device.h>
-#include <linux/spinlock.h>
-#include <linux/scatterlist.h>
-#include <linux/dma-mapping.h>
-#include <linux/slab.h>
-#include <linux/reset.h>
-
-#include <linux/of_address.h>
-#include <linux/of_gpio.h>
-#include <linux/of_platform.h>
-
-#include <linux/mmc/host.h>
-#include <linux/mmc/sd.h>
-#include <linux/mmc/sdio.h>
-#include <linux/mmc/mmc.h>
-#include <linux/mmc/core.h>
-#include <linux/mmc/card.h>
-#include <linux/mmc/slot-gpio.h>
-
-/* register offset definitions */
-#define SDXC_REG_GCTRL (0x00) /* SMC Global Control Register */
-#define SDXC_REG_CLKCR (0x04) /* SMC Clock Control Register */
-#define SDXC_REG_TMOUT (0x08) /* SMC Time Out Register */
-#define SDXC_REG_WIDTH (0x0C) /* SMC Bus Width Register */
-#define SDXC_REG_BLKSZ (0x10) /* SMC Block Size Register */
-#define SDXC_REG_BCNTR (0x14) /* SMC Byte Count Register */
-#define SDXC_REG_CMDR  (0x18) /* SMC Command Register */
-#define SDXC_REG_CARG  (0x1C) /* SMC Argument Register */
-#define SDXC_REG_RESP0 (0x20) /* SMC Response Register 0 */
-#define SDXC_REG_RESP1 (0x24) /* SMC Response Register 1 */
-#define SDXC_REG_RESP2 (0x28) /* SMC Response Register 2 */
-#define SDXC_REG_RESP3 (0x2C) /* SMC Response Register 3 */
-#define SDXC_REG_IMASK (0x30) /* SMC Interrupt Mask Register */
-#define SDXC_REG_MISTA (0x34) /* SMC Masked Interrupt Status Register */
-#define SDXC_REG_RINTR (0x38) /* SMC Raw Interrupt Status Register */
-#define SDXC_REG_STAS  (0x3C) /* SMC Status Register */
-#define SDXC_REG_FTRGL (0x40) /* SMC FIFO Threshold Watermark Registe */
-#define SDXC_REG_FUNS  (0x44) /* SMC Function Select Register */
-#define SDXC_REG_CBCR  (0x48) /* SMC CIU Byte Count Register */
-#define SDXC_REG_BBCR  (0x4C) /* SMC BIU Byte Count Register */
-#define SDXC_REG_DBGC  (0x50) /* SMC Debug Enable Register */
-#define SDXC_REG_HWRST (0x78) /* SMC Card Hardware Reset for Register */
-#define SDXC_REG_DMAC  (0x80) /* SMC IDMAC Control Register */
-#define SDXC_REG_DLBA  (0x84) /* SMC IDMAC Descriptor List Base Addre */
-#define SDXC_REG_IDST  (0x88) /* SMC IDMAC Status Register */
-#define SDXC_REG_IDIE  (0x8C) /* SMC IDMAC Interrupt Enable Register */
-#define SDXC_REG_CHDA  (0x90)
-#define SDXC_REG_CBDA  (0x94)
-
-#define mmc_readl(host, reg) \
-       readl((host)->reg_base + SDXC_##reg)
-#define mmc_writel(host, reg, value) \
-       writel((value), (host)->reg_base + SDXC_##reg)
-
-/* global control register bits */
-#define SDXC_SOFT_RESET                        BIT(0)
-#define SDXC_FIFO_RESET                        BIT(1)
-#define SDXC_DMA_RESET                 BIT(2)
-#define SDXC_INTERRUPT_ENABLE_BIT      BIT(4)
-#define SDXC_DMA_ENABLE_BIT            BIT(5)
-#define SDXC_DEBOUNCE_ENABLE_BIT       BIT(8)
-#define SDXC_POSEDGE_LATCH_DATA                BIT(9)
-#define SDXC_DDR_MODE                  BIT(10)
-#define SDXC_MEMORY_ACCESS_DONE                BIT(29)
-#define SDXC_ACCESS_DONE_DIRECT                BIT(30)
-#define SDXC_ACCESS_BY_AHB             BIT(31)
-#define SDXC_ACCESS_BY_DMA             (0 << 31)
-#define SDXC_HARDWARE_RESET \
-       (SDXC_SOFT_RESET | SDXC_FIFO_RESET | SDXC_DMA_RESET)
-
-/* clock control bits */
-#define SDXC_CARD_CLOCK_ON             BIT(16)
-#define SDXC_LOW_POWER_ON              BIT(17)
-
-/* bus width */
-#define SDXC_WIDTH1                    0
-#define SDXC_WIDTH4                    1
-#define SDXC_WIDTH8                    2
-
-/* smc command bits */
-#define SDXC_RESP_EXPIRE               BIT(6)
-#define SDXC_LONG_RESPONSE             BIT(7)
-#define SDXC_CHECK_RESPONSE_CRC                BIT(8)
-#define SDXC_DATA_EXPIRE               BIT(9)
-#define SDXC_WRITE                     BIT(10)
-#define SDXC_SEQUENCE_MODE             BIT(11)
-#define SDXC_SEND_AUTO_STOP            BIT(12)
-#define SDXC_WAIT_PRE_OVER             BIT(13)
-#define SDXC_STOP_ABORT_CMD            BIT(14)
-#define SDXC_SEND_INIT_SEQUENCE                BIT(15)
-#define SDXC_UPCLK_ONLY                        BIT(21)
-#define SDXC_READ_CEATA_DEV            BIT(22)
-#define SDXC_CCS_EXPIRE                        BIT(23)
-#define SDXC_ENABLE_BIT_BOOT           BIT(24)
-#define SDXC_ALT_BOOT_OPTIONS          BIT(25)
-#define SDXC_BOOT_ACK_EXPIRE           BIT(26)
-#define SDXC_BOOT_ABORT                        BIT(27)
-#define SDXC_VOLTAGE_SWITCH            BIT(28)
-#define SDXC_USE_HOLD_REGISTER         BIT(29)
-#define SDXC_START                     BIT(31)
-
-/* interrupt bits */
-#define SDXC_RESP_ERROR                        BIT(1)
-#define SDXC_COMMAND_DONE              BIT(2)
-#define SDXC_DATA_OVER                 BIT(3)
-#define SDXC_TX_DATA_REQUEST           BIT(4)
-#define SDXC_RX_DATA_REQUEST           BIT(5)
-#define SDXC_RESP_CRC_ERROR            BIT(6)
-#define SDXC_DATA_CRC_ERROR            BIT(7)
-#define SDXC_RESP_TIMEOUT              BIT(8)
-#define SDXC_DATA_TIMEOUT              BIT(9)
-#define SDXC_VOLTAGE_CHANGE_DONE       BIT(10)
-#define SDXC_FIFO_RUN_ERROR            BIT(11)
-#define SDXC_HARD_WARE_LOCKED          BIT(12)
-#define SDXC_START_BIT_ERROR           BIT(13)
-#define SDXC_AUTO_COMMAND_DONE         BIT(14)
-#define SDXC_END_BIT_ERROR             BIT(15)
-#define SDXC_SDIO_INTERRUPT            BIT(16)
-#define SDXC_CARD_INSERT               BIT(30)
-#define SDXC_CARD_REMOVE               BIT(31)
-#define SDXC_INTERRUPT_ERROR_BIT \
-       (SDXC_RESP_ERROR | SDXC_RESP_CRC_ERROR | SDXC_DATA_CRC_ERROR | \
-        SDXC_RESP_TIMEOUT | SDXC_DATA_TIMEOUT | SDXC_FIFO_RUN_ERROR | \
-        SDXC_HARD_WARE_LOCKED | SDXC_START_BIT_ERROR | SDXC_END_BIT_ERROR)
-#define SDXC_INTERRUPT_DONE_BIT \
-       (SDXC_AUTO_COMMAND_DONE | SDXC_DATA_OVER | \
-        SDXC_COMMAND_DONE | SDXC_VOLTAGE_CHANGE_DONE)
-
-/* status */
-#define SDXC_RXWL_FLAG                 BIT(0)
-#define SDXC_TXWL_FLAG                 BIT(1)
-#define SDXC_FIFO_EMPTY                        BIT(2)
-#define SDXC_FIFO_FULL                 BIT(3)
-#define SDXC_CARD_PRESENT              BIT(8)
-#define SDXC_CARD_DATA_BUSY            BIT(9)
-#define SDXC_DATA_FSM_BUSY             BIT(10)
-#define SDXC_DMA_REQUEST               BIT(31)
-#define SDXC_FIFO_SIZE                 16
-
-/* Function select */
-#define SDXC_CEATA_ON                  (0xceaa << 16)
-#define SDXC_SEND_IRQ_RESPONSE         BIT(0)
-#define SDXC_SDIO_READ_WAIT            BIT(1)
-#define SDXC_ABORT_READ_DATA           BIT(2)
-#define SDXC_SEND_CCSD                 BIT(8)
-#define SDXC_SEND_AUTO_STOPCCSD                BIT(9)
-#define SDXC_CEATA_DEV_IRQ_ENABLE      BIT(10)
-
-/* IDMA controller bus mod bit field */
-#define SDXC_IDMAC_SOFT_RESET          BIT(0)
-#define SDXC_IDMAC_FIX_BURST           BIT(1)
-#define SDXC_IDMAC_IDMA_ON             BIT(7)
-#define SDXC_IDMAC_REFETCH_DES         BIT(31)
-
-/* IDMA status bit field */
-#define SDXC_IDMAC_TRANSMIT_INTERRUPT          BIT(0)
-#define SDXC_IDMAC_RECEIVE_INTERRUPT           BIT(1)
-#define SDXC_IDMAC_FATAL_BUS_ERROR             BIT(2)
-#define SDXC_IDMAC_DESTINATION_INVALID         BIT(4)
-#define SDXC_IDMAC_CARD_ERROR_SUM              BIT(5)
-#define SDXC_IDMAC_NORMAL_INTERRUPT_SUM                BIT(8)
-#define SDXC_IDMAC_ABNORMAL_INTERRUPT_SUM      BIT(9)
-#define SDXC_IDMAC_HOST_ABORT_INTERRUPT                BIT(10)
-#define SDXC_IDMAC_IDLE                                (0 << 13)
-#define SDXC_IDMAC_SUSPEND                     (1 << 13)
-#define SDXC_IDMAC_DESC_READ                   (2 << 13)
-#define SDXC_IDMAC_DESC_CHECK                  (3 << 13)
-#define SDXC_IDMAC_READ_REQUEST_WAIT           (4 << 13)
-#define SDXC_IDMAC_WRITE_REQUEST_WAIT          (5 << 13)
-#define SDXC_IDMAC_READ                                (6 << 13)
-#define SDXC_IDMAC_WRITE                       (7 << 13)
-#define SDXC_IDMAC_DESC_CLOSE                  (8 << 13)
-
-/*
-* If the idma-des-size-bits of property is ie 13, bufsize bits are:
-*  Bits  0-12: buf1 size
-*  Bits 13-25: buf2 size
-*  Bits 26-31: not used
-* Since we only ever set buf1 size, we can simply store it directly.
-*/
-#define SDXC_IDMAC_DES0_DIC    BIT(1)  /* disable interrupt on completion */
-#define SDXC_IDMAC_DES0_LD     BIT(2)  /* last descriptor */
-#define SDXC_IDMAC_DES0_FD     BIT(3)  /* first descriptor */
-#define SDXC_IDMAC_DES0_CH     BIT(4)  /* chain mode */
-#define SDXC_IDMAC_DES0_ER     BIT(5)  /* end of ring */
-#define SDXC_IDMAC_DES0_CES    BIT(30) /* card error summary */
-#define SDXC_IDMAC_DES0_OWN    BIT(31) /* 1-idma owns it, 0-host owns it */
-
-struct sunxi_idma_des {
-       u32     config;
-       u32     buf_size;
-       u32     buf_addr_ptr1;
-       u32     buf_addr_ptr2;
-};
-
-struct sunxi_mmc_host {
-       struct mmc_host *mmc;
-       struct reset_control *reset;
-
-       /* IO mapping base */
-       void __iomem    *reg_base;
-
-       /* clock management */
-       struct clk      *clk_ahb;
-       struct clk      *clk_mmc;
-
-       /* irq */
-       spinlock_t      lock;
-       int             irq;
-       u32             int_sum;
-       u32             sdio_imask;
-
-       /* dma */
-       u32             idma_des_size_bits;
-       dma_addr_t      sg_dma;
-       void            *sg_cpu;
-       bool            wait_dma;
-
-       struct mmc_request *mrq;
-       struct mmc_request *manual_stop_mrq;
-       int             ferror;
-};
-
-static int sunxi_mmc_reset_host(struct sunxi_mmc_host *host)
-{
-       unsigned long expire = jiffies + msecs_to_jiffies(250);
-       u32 rval;
-
-       mmc_writel(host, REG_CMDR, SDXC_HARDWARE_RESET);
-       do {
-               rval = mmc_readl(host, REG_GCTRL);
-       } while (time_before(jiffies, expire) && (rval & SDXC_HARDWARE_RESET));
-
-       if (rval & SDXC_HARDWARE_RESET) {
-               dev_err(mmc_dev(host->mmc), "fatal err reset timeout\n");
-               return -EIO;
-       }
-
-       return 0;
-}
-
-static int sunxi_mmc_init_host(struct mmc_host *mmc)
-{
-       u32 rval;
-       struct sunxi_mmc_host *host = mmc_priv(mmc);
-
-       if (sunxi_mmc_reset_host(host))
-               return -EIO;
-
-       mmc_writel(host, REG_FTRGL, 0x20070008);
-       mmc_writel(host, REG_TMOUT, 0xffffffff);
-       mmc_writel(host, REG_IMASK, host->sdio_imask);
-       mmc_writel(host, REG_RINTR, 0xffffffff);
-       mmc_writel(host, REG_DBGC, 0xdeb);
-       mmc_writel(host, REG_FUNS, SDXC_CEATA_ON);
-       mmc_writel(host, REG_DLBA, host->sg_dma);
-
-       rval = mmc_readl(host, REG_GCTRL);
-       rval |= SDXC_INTERRUPT_ENABLE_BIT;
-       rval &= ~SDXC_ACCESS_DONE_DIRECT;
-       mmc_writel(host, REG_GCTRL, rval);
-
-       return 0;
-}
-
-static void sunxi_mmc_init_idma_des(struct sunxi_mmc_host *host,
-                                   struct mmc_data *data)
-{
-       struct sunxi_idma_des *pdes = (struct sunxi_idma_des *)host->sg_cpu;
-       struct sunxi_idma_des *pdes_pa = (struct sunxi_idma_des *)host->sg_dma;
-       int i, max_len = (1 << host->idma_des_size_bits);
-
-       for (i = 0; i < data->sg_len; i++) {
-               pdes[i].config = SDXC_IDMAC_DES0_CH | SDXC_IDMAC_DES0_OWN |
-                                SDXC_IDMAC_DES0_DIC;
-
-               if (data->sg[i].length == max_len)
-                       pdes[i].buf_size = 0; /* 0 == max_len */
-               else
-                       pdes[i].buf_size = data->sg[i].length;
-
-               pdes[i].buf_addr_ptr1 = sg_dma_address(&data->sg[i]);
-               pdes[i].buf_addr_ptr2 = (u32)&pdes_pa[i + 1];
-       }
-
-       pdes[0].config |= SDXC_IDMAC_DES0_FD;
-       pdes[i - 1].config = SDXC_IDMAC_DES0_OWN | SDXC_IDMAC_DES0_LD;
-
-       /*
-        * Avoid the io-store starting the idmac hitting io-mem before the
-        * descriptors hit the main-mem.
-        */
-       wmb();
-}
-
-static enum dma_data_direction sunxi_mmc_get_dma_dir(struct mmc_data *data)
-{
-       if (data->flags & MMC_DATA_WRITE)
-               return DMA_TO_DEVICE;
-       else
-               return DMA_FROM_DEVICE;
-}
-
-static int sunxi_mmc_map_dma(struct sunxi_mmc_host *host,
-                            struct mmc_data *data)
-{
-       u32 i, dma_len;
-       struct scatterlist *sg;
-
-       dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
-                            sunxi_mmc_get_dma_dir(data));
-       if (dma_len == 0) {
-               dev_err(mmc_dev(host->mmc), "dma_map_sg failed\n");
-               return -ENOMEM;
-       }
-
-       for_each_sg(data->sg, sg, data->sg_len, i) {
-               if (sg->offset & 3 || sg->length & 3) {
-                       dev_err(mmc_dev(host->mmc),
-                               "unaligned scatterlist: os %x length %d\n",
-                               sg->offset, sg->length);
-                       return -EINVAL;
-               }
-       }
-
-       return 0;
-}
-
-static void sunxi_mmc_start_dma(struct sunxi_mmc_host *host,
-                               struct mmc_data *data)
-{
-       u32 rval;
-
-       sunxi_mmc_init_idma_des(host, data);
-
-       rval = mmc_readl(host, REG_GCTRL);
-       rval |= SDXC_DMA_ENABLE_BIT;
-       mmc_writel(host, REG_GCTRL, rval);
-       rval |= SDXC_DMA_RESET;
-       mmc_writel(host, REG_GCTRL, rval);
-
-       mmc_writel(host, REG_DMAC, SDXC_IDMAC_SOFT_RESET);
-
-       if (!(data->flags & MMC_DATA_WRITE))
-               mmc_writel(host, REG_IDIE, SDXC_IDMAC_RECEIVE_INTERRUPT);
-
-       mmc_writel(host, REG_DMAC,
-                  SDXC_IDMAC_FIX_BURST | SDXC_IDMAC_IDMA_ON);
-}
-
-static void sunxi_mmc_send_manual_stop(struct sunxi_mmc_host *host,
-                                      struct mmc_request *req)
-{
-       u32 arg, cmd_val, ri;
-       unsigned long expire = jiffies + msecs_to_jiffies(1000);
-
-       cmd_val = SDXC_START | SDXC_RESP_EXPIRE |
-                 SDXC_STOP_ABORT_CMD | SDXC_CHECK_RESPONSE_CRC;
-
-       if (req->cmd->opcode == SD_IO_RW_EXTENDED) {
-               cmd_val |= SD_IO_RW_DIRECT;
-               arg = (1 << 31) | (0 << 28) | (SDIO_CCCR_ABORT << 9) |
-                     ((req->cmd->arg >> 28) & 0x7);
-       } else {
-               cmd_val |= MMC_STOP_TRANSMISSION;
-               arg = 0;
-       }
-
-       mmc_writel(host, REG_CARG, arg);
-       mmc_writel(host, REG_CMDR, cmd_val);
-
-       do {
-               ri = mmc_readl(host, REG_RINTR);
-       } while (!(ri & (SDXC_COMMAND_DONE | SDXC_INTERRUPT_ERROR_BIT)) &&
-                time_before(jiffies, expire));
-
-       if (!(ri & SDXC_COMMAND_DONE) || (ri & SDXC_INTERRUPT_ERROR_BIT)) {
-               dev_err(mmc_dev(host->mmc), "send stop command failed\n");
-               if (req->stop)
-                       req->stop->resp[0] = -ETIMEDOUT;
-       } else {
-               if (req->stop)
-                       req->stop->resp[0] = mmc_readl(host, REG_RESP0);
-       }
-
-       mmc_writel(host, REG_RINTR, 0xffff);
-}
-
-static void sunxi_mmc_dump_errinfo(struct sunxi_mmc_host *host)
-{
-       struct mmc_command *cmd = host->mrq->cmd;
-       struct mmc_data *data = host->mrq->data;
-
-       /* For some cmds timeout is normal with sd/mmc cards */
-       if ((host->int_sum & SDXC_INTERRUPT_ERROR_BIT) ==
-               SDXC_RESP_TIMEOUT && (cmd->opcode == SD_IO_SEND_OP_COND ||
-                                     cmd->opcode == SD_IO_RW_DIRECT))
-               return;
-
-       dev_err(mmc_dev(host->mmc),
-               "smc %d err, cmd %d,%s%s%s%s%s%s%s%s%s%s !!\n",
-               host->mmc->index, cmd->opcode,
-               data ? (data->flags & MMC_DATA_WRITE ? " WR" : " RD") : "",
-               host->int_sum & SDXC_RESP_ERROR     ? " RE"     : "",
-               host->int_sum & SDXC_RESP_CRC_ERROR  ? " RCE"    : "",
-               host->int_sum & SDXC_DATA_CRC_ERROR  ? " DCE"    : "",
-               host->int_sum & SDXC_RESP_TIMEOUT ? " RTO"    : "",
-               host->int_sum & SDXC_DATA_TIMEOUT ? " DTO"    : "",
-               host->int_sum & SDXC_FIFO_RUN_ERROR  ? " FE"     : "",
-               host->int_sum & SDXC_HARD_WARE_LOCKED ? " HL"     : "",
-               host->int_sum & SDXC_START_BIT_ERROR ? " SBE"    : "",
-               host->int_sum & SDXC_END_BIT_ERROR   ? " EBE"    : ""
-               );
-}
-
-/* Called in interrupt context! */
-static irqreturn_t sunxi_mmc_finalize_request(struct sunxi_mmc_host *host)
-{
-       struct mmc_request *mrq = host->mrq;
-       struct mmc_data *data = mrq->data;
-       u32 rval;
-
-       mmc_writel(host, REG_IMASK, host->sdio_imask);
-       mmc_writel(host, REG_IDIE, 0);
-
-       if (host->int_sum & SDXC_INTERRUPT_ERROR_BIT) {
-               sunxi_mmc_dump_errinfo(host);
-               mrq->cmd->error = -ETIMEDOUT;
-
-               if (data) {
-                       data->error = -ETIMEDOUT;
-                       host->manual_stop_mrq = mrq;
-               }
-
-               if (mrq->stop)
-                       mrq->stop->error = -ETIMEDOUT;
-       } else {
-               if (mrq->cmd->flags & MMC_RSP_136) {
-                       mrq->cmd->resp[0] = mmc_readl(host, REG_RESP3);
-                       mrq->cmd->resp[1] = mmc_readl(host, REG_RESP2);
-                       mrq->cmd->resp[2] = mmc_readl(host, REG_RESP1);
-                       mrq->cmd->resp[3] = mmc_readl(host, REG_RESP0);
-               } else {
-                       mrq->cmd->resp[0] = mmc_readl(host, REG_RESP0);
-               }
-
-               if (data)
-                       data->bytes_xfered = data->blocks * data->blksz;
-       }
-
-       if (data) {
-               mmc_writel(host, REG_IDST, 0x337);
-               mmc_writel(host, REG_DMAC, 0);
-               rval = mmc_readl(host, REG_GCTRL);
-               rval |= SDXC_DMA_RESET;
-               mmc_writel(host, REG_GCTRL, rval);
-               rval &= ~SDXC_DMA_ENABLE_BIT;
-               mmc_writel(host, REG_GCTRL, rval);
-               rval |= SDXC_FIFO_RESET;
-               mmc_writel(host, REG_GCTRL, rval);
-               dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
-                                    sunxi_mmc_get_dma_dir(data));
-       }
-
-       mmc_writel(host, REG_RINTR, 0xffff);
-
-       host->mrq = NULL;
-       host->int_sum = 0;
-       host->wait_dma = false;
-
-       return host->manual_stop_mrq ? IRQ_WAKE_THREAD : IRQ_HANDLED;
-}
-
-static irqreturn_t sunxi_mmc_irq(int irq, void *dev_id)
-{
-       struct sunxi_mmc_host *host = dev_id;
-       struct mmc_request *mrq;
-       u32 msk_int, idma_int;
-       bool finalize = false;
-       bool sdio_int = false;
-       irqreturn_t ret = IRQ_HANDLED;
-
-       spin_lock(&host->lock);
-
-       idma_int  = mmc_readl(host, REG_IDST);
-       msk_int   = mmc_readl(host, REG_MISTA);
-
-       dev_dbg(mmc_dev(host->mmc), "irq: rq %p mi %08x idi %08x\n",
-               host->mrq, msk_int, idma_int);
-
-       mrq = host->mrq;
-       if (mrq) {
-               if (idma_int & SDXC_IDMAC_RECEIVE_INTERRUPT)
-                       host->wait_dma = false;
-
-               host->int_sum |= msk_int;
-
-               /* Wait for COMMAND_DONE on RESPONSE_TIMEOUT before finalize */
-               if ((host->int_sum & SDXC_RESP_TIMEOUT) &&
-                               !(host->int_sum & SDXC_COMMAND_DONE))
-                       mmc_writel(host, REG_IMASK,
-                                  host->sdio_imask | SDXC_COMMAND_DONE);
-               /* Don't wait for dma on error */
-               else if (host->int_sum & SDXC_INTERRUPT_ERROR_BIT)
-                       finalize = true;
-               else if ((host->int_sum & SDXC_INTERRUPT_DONE_BIT) &&
-                               !host->wait_dma)
-                       finalize = true;
-       }
-
-       if (msk_int & SDXC_SDIO_INTERRUPT)
-               sdio_int = true;
-
-       mmc_writel(host, REG_RINTR, msk_int);
-       mmc_writel(host, REG_IDST, idma_int);
-
-       if (finalize)
-               ret = sunxi_mmc_finalize_request(host);
-
-       spin_unlock(&host->lock);
-
-       if (finalize && ret == IRQ_HANDLED)
-               mmc_request_done(host->mmc, mrq);
-
-       if (sdio_int)
-               mmc_signal_sdio_irq(host->mmc);
-
-       return ret;
-}
-
-static irqreturn_t sunxi_mmc_handle_manual_stop(int irq, void *dev_id)
-{
-       struct sunxi_mmc_host *host = dev_id;
-       struct mmc_request *mrq;
-       unsigned long iflags;
-
-       spin_lock_irqsave(&host->lock, iflags);
-       mrq = host->manual_stop_mrq;
-       spin_unlock_irqrestore(&host->lock, iflags);
-
-       if (!mrq) {
-               dev_err(mmc_dev(host->mmc), "no request for manual stop\n");
-               return IRQ_HANDLED;
-       }
-
-       dev_err(mmc_dev(host->mmc), "data error, sending stop command\n");
-       sunxi_mmc_send_manual_stop(host, mrq);
-
-       spin_lock_irqsave(&host->lock, iflags);
-       host->manual_stop_mrq = NULL;
-       spin_unlock_irqrestore(&host->lock, iflags);
-
-       mmc_request_done(host->mmc, mrq);
-
-       return IRQ_HANDLED;
-}
-
-static int sunxi_mmc_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en)
-{
-       unsigned long expire = jiffies + msecs_to_jiffies(250);
-       u32 rval;
-
-       rval = mmc_readl(host, REG_CLKCR);
-       rval &= ~(SDXC_CARD_CLOCK_ON | SDXC_LOW_POWER_ON);
-
-       if (oclk_en)
-               rval |= SDXC_CARD_CLOCK_ON;
-
-       mmc_writel(host, REG_CLKCR, rval);
-
-       rval = SDXC_START | SDXC_UPCLK_ONLY | SDXC_WAIT_PRE_OVER;
-       mmc_writel(host, REG_CMDR, rval);
-
-       do {
-               rval = mmc_readl(host, REG_CMDR);
-       } while (time_before(jiffies, expire) && (rval & SDXC_START));
-
-       /* clear irq status bits set by the command */
-       mmc_writel(host, REG_RINTR,
-                  mmc_readl(host, REG_RINTR) & ~SDXC_SDIO_INTERRUPT);
-
-       if (rval & SDXC_START) {
-               dev_err(mmc_dev(host->mmc), "fatal err update clk timeout\n");
-               return -EIO;
-       }
-
-       return 0;
-}
-
-static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
-                                 struct mmc_ios *ios)
-{
-       u32 rate, oclk_dly, rval, sclk_dly, src_clk;
-       int ret;
-
-       rate = clk_round_rate(host->clk_mmc, ios->clock);
-       dev_dbg(mmc_dev(host->mmc), "setting clk to %d, rounded %d\n",
-               ios->clock, rate);
-
-       /* setting clock rate */
-       ret = clk_set_rate(host->clk_mmc, rate);
-       if (ret) {
-               dev_err(mmc_dev(host->mmc), "error setting clk to %d: %d\n",
-                       rate, ret);
-               return ret;
-       }
-
-       ret = sunxi_mmc_oclk_onoff(host, 0);
-       if (ret)
-               return ret;
-
-       /* clear internal divider */
-       rval = mmc_readl(host, REG_CLKCR);
-       rval &= ~0xff;
-       mmc_writel(host, REG_CLKCR, rval);
-
-       /* determine delays */
-       if (rate <= 400000) {
-               oclk_dly = 0;
-               sclk_dly = 7;
-       } else if (rate <= 25000000) {
-               oclk_dly = 0;
-               sclk_dly = 5;
-       } else if (rate <= 50000000) {
-               if (ios->timing == MMC_TIMING_UHS_DDR50) {
-                       oclk_dly = 2;
-                       sclk_dly = 4;
-               } else {
-                       oclk_dly = 3;
-                       sclk_dly = 5;
-               }
-       } else {
-               /* rate > 50000000 */
-               oclk_dly = 2;
-               sclk_dly = 4;
-       }
-
-       src_clk = clk_get_rate(clk_get_parent(host->clk_mmc));
-       if (src_clk >= 300000000 && src_clk <= 400000000) {
-               if (oclk_dly)
-                       oclk_dly--;
-               if (sclk_dly)
-                       sclk_dly--;
-       }
-
-       clk_sunxi_mmc_phase_control(host->clk_mmc, sclk_dly, oclk_dly);
-
-       return sunxi_mmc_oclk_onoff(host, 1);
-}
-
-static void sunxi_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
-{
-       struct sunxi_mmc_host *host = mmc_priv(mmc);
-       u32 rval;
-
-       /* Set the power state */
-       switch (ios->power_mode) {
-       case MMC_POWER_ON:
-               break;
-
-       case MMC_POWER_UP:
-               mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd);
-
-               host->ferror = sunxi_mmc_init_host(mmc);
-               if (host->ferror)
-                       return;
-
-               dev_dbg(mmc_dev(mmc), "power on!\n");
-               break;
-
-       case MMC_POWER_OFF:
-               dev_dbg(mmc_dev(mmc), "power off!\n");
-               sunxi_mmc_reset_host(host);
-               mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0);
-               break;
-       }
-
-       /* set bus width */
-       switch (ios->bus_width) {
-       case MMC_BUS_WIDTH_1:
-               mmc_writel(host, REG_WIDTH, SDXC_WIDTH1);
-               break;
-       case MMC_BUS_WIDTH_4:
-               mmc_writel(host, REG_WIDTH, SDXC_WIDTH4);
-               break;
-       case MMC_BUS_WIDTH_8:
-               mmc_writel(host, REG_WIDTH, SDXC_WIDTH8);
-               break;
-       }
-
-       /* set ddr mode */
-       rval = mmc_readl(host, REG_GCTRL);
-       if (ios->timing == MMC_TIMING_UHS_DDR50)
-               rval |= SDXC_DDR_MODE;
-       else
-               rval &= ~SDXC_DDR_MODE;
-       mmc_writel(host, REG_GCTRL, rval);
-
-       /* set up clock */
-       if (ios->clock && ios->power_mode) {
-               host->ferror = sunxi_mmc_clk_set_rate(host, ios);
-               /* Android code had a usleep_range(50000, 55000); here */
-       }
-}
-
-static void sunxi_mmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
-{
-       struct sunxi_mmc_host *host = mmc_priv(mmc);
-       unsigned long flags;
-       u32 imask;
-
-       spin_lock_irqsave(&host->lock, flags);
-
-       imask = mmc_readl(host, REG_IMASK);
-       if (enable) {
-               host->sdio_imask = SDXC_SDIO_INTERRUPT;
-               imask |= SDXC_SDIO_INTERRUPT;
-       } else {
-               host->sdio_imask = 0;
-               imask &= ~SDXC_SDIO_INTERRUPT;
-       }
-       mmc_writel(host, REG_IMASK, imask);
-       spin_unlock_irqrestore(&host->lock, flags);
-}
-
-static void sunxi_mmc_hw_reset(struct mmc_host *mmc)
-{
-       struct sunxi_mmc_host *host = mmc_priv(mmc);
-       mmc_writel(host, REG_HWRST, 0);
-       udelay(10);
-       mmc_writel(host, REG_HWRST, 1);
-       udelay(300);
-}
-
-static void sunxi_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
-{
-       struct sunxi_mmc_host *host = mmc_priv(mmc);
-       struct mmc_command *cmd = mrq->cmd;
-       struct mmc_data *data = mrq->data;
-       unsigned long iflags;
-       u32 imask = SDXC_INTERRUPT_ERROR_BIT;
-       u32 cmd_val = SDXC_START | (cmd->opcode & 0x3f);
-       int ret;
-
-       /* Check for set_ios errors (should never happen) */
-       if (host->ferror) {
-               mrq->cmd->error = host->ferror;
-               mmc_request_done(mmc, mrq);
-               return;
-       }
-
-       if (data) {
-               ret = sunxi_mmc_map_dma(host, data);
-               if (ret < 0) {
-                       dev_err(mmc_dev(mmc), "map DMA failed\n");
-                       cmd->error = ret;
-                       data->error = ret;
-                       mmc_request_done(mmc, mrq);
-                       return;
-               }
-       }
-
-       if (cmd->opcode == MMC_GO_IDLE_STATE) {
-               cmd_val |= SDXC_SEND_INIT_SEQUENCE;
-               imask |= SDXC_COMMAND_DONE;
-       }
-
-       if (cmd->flags & MMC_RSP_PRESENT) {
-               cmd_val |= SDXC_RESP_EXPIRE;
-               if (cmd->flags & MMC_RSP_136)
-                       cmd_val |= SDXC_LONG_RESPONSE;
-               if (cmd->flags & MMC_RSP_CRC)
-                       cmd_val |= SDXC_CHECK_RESPONSE_CRC;
-
-               if ((cmd->flags & MMC_CMD_MASK) == MMC_CMD_ADTC) {
-                       cmd_val |= SDXC_DATA_EXPIRE | SDXC_WAIT_PRE_OVER;
-                       if (cmd->data->flags & MMC_DATA_STREAM) {
-                               imask |= SDXC_AUTO_COMMAND_DONE;
-                               cmd_val |= SDXC_SEQUENCE_MODE |
-                                          SDXC_SEND_AUTO_STOP;
-                       }
-
-                       if (cmd->data->stop) {
-                               imask |= SDXC_AUTO_COMMAND_DONE;
-                               cmd_val |= SDXC_SEND_AUTO_STOP;
-                       } else {
-                               imask |= SDXC_DATA_OVER;
-                       }
-
-                       if (cmd->data->flags & MMC_DATA_WRITE)
-                               cmd_val |= SDXC_WRITE;
-                       else
-                               host->wait_dma = true;
-               } else {
-                       imask |= SDXC_COMMAND_DONE;
-               }
-       } else {
-               imask |= SDXC_COMMAND_DONE;
-       }
-
-       dev_dbg(mmc_dev(mmc), "cmd %d(%08x) arg %x ie 0x%08x len %d\n",
-               cmd_val & 0x3f, cmd_val, cmd->arg, imask,
-               mrq->data ? mrq->data->blksz * mrq->data->blocks : 0);
-
-       spin_lock_irqsave(&host->lock, iflags);
-
-       if (host->mrq || host->manual_stop_mrq) {
-               spin_unlock_irqrestore(&host->lock, iflags);
-
-               if (data)
-                       dma_unmap_sg(mmc_dev(mmc), data->sg, data->sg_len,
-                                    sunxi_mmc_get_dma_dir(data));
-
-               dev_err(mmc_dev(mmc), "request already pending\n");
-               mrq->cmd->error = -EBUSY;
-               mmc_request_done(mmc, mrq);
-               return;
-       }
-
-       if (data) {
-               mmc_writel(host, REG_BLKSZ, data->blksz);
-               mmc_writel(host, REG_BCNTR, data->blksz * data->blocks);
-               sunxi_mmc_start_dma(host, data);
-       }
-
-       host->mrq = mrq;
-       mmc_writel(host, REG_IMASK, host->sdio_imask | imask);
-       mmc_writel(host, REG_CARG, cmd->arg);
-       mmc_writel(host, REG_CMDR, cmd_val);
-
-       spin_unlock_irqrestore(&host->lock, iflags);
-}
-
-static const struct of_device_id sunxi_mmc_of_match[] = {
-       { .compatible = "allwinner,sun4i-a10-mmc", },
-       { .compatible = "allwinner,sun5i-a13-mmc", },
-       { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, sunxi_mmc_of_match);
-
-static struct mmc_host_ops sunxi_mmc_ops = {
-       .request         = sunxi_mmc_request,
-       .set_ios         = sunxi_mmc_set_ios,
-       .get_ro          = mmc_gpio_get_ro,
-       .get_cd          = mmc_gpio_get_cd,
-       .enable_sdio_irq = sunxi_mmc_enable_sdio_irq,
-       .hw_reset        = sunxi_mmc_hw_reset,
-};
-
-static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
-                                     struct platform_device *pdev)
-{
-       struct device_node *np = pdev->dev.of_node;
-       int ret;
-
-       if (of_device_is_compatible(np, "allwinner,sun4i-a10-mmc"))
-               host->idma_des_size_bits = 13;
-       else
-               host->idma_des_size_bits = 16;
-
-       ret = mmc_regulator_get_supply(host->mmc);
-       if (ret) {
-               if (ret != -EPROBE_DEFER)
-                       dev_err(&pdev->dev, "Could not get vmmc supply\n");
-               return ret;
-       }
-
-       host->reg_base = devm_ioremap_resource(&pdev->dev,
-                             platform_get_resource(pdev, IORESOURCE_MEM, 0));
-       if (IS_ERR(host->reg_base))
-               return PTR_ERR(host->reg_base);
-
-       host->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
-       if (IS_ERR(host->clk_ahb)) {
-               dev_err(&pdev->dev, "Could not get ahb clock\n");
-               return PTR_ERR(host->clk_ahb);
-       }
-
-       host->clk_mmc = devm_clk_get(&pdev->dev, "mmc");
-       if (IS_ERR(host->clk_mmc)) {
-               dev_err(&pdev->dev, "Could not get mmc clock\n");
-               return PTR_ERR(host->clk_mmc);
-       }
-
-       host->reset = devm_reset_control_get(&pdev->dev, "ahb");
-
-       ret = clk_prepare_enable(host->clk_ahb);
-       if (ret) {
-               dev_err(&pdev->dev, "Enable ahb clk err %d\n", ret);
-               return ret;
-       }
-
-       ret = clk_prepare_enable(host->clk_mmc);
-       if (ret) {
-               dev_err(&pdev->dev, "Enable mmc clk err %d\n", ret);
-               goto error_disable_clk_ahb;
-       }
-
-       if (!IS_ERR(host->reset)) {
-               ret = reset_control_deassert(host->reset);
-               if (ret) {
-                       dev_err(&pdev->dev, "reset err %d\n", ret);
-                       goto error_disable_clk_mmc;
-               }
-       }
-
-       /*
-        * Sometimes the controller asserts the irq on boot for some reason,
-        * make sure the controller is in a sane state before enabling irqs.
-        */
-       ret = sunxi_mmc_reset_host(host);
-       if (ret)
-               goto error_assert_reset;
-
-       host->irq = platform_get_irq(pdev, 0);
-       return devm_request_threaded_irq(&pdev->dev, host->irq, sunxi_mmc_irq,
-                       sunxi_mmc_handle_manual_stop, 0, "sunxi-mmc", host);
-
-error_assert_reset:
-       if (!IS_ERR(host->reset))
-               reset_control_assert(host->reset);
-error_disable_clk_mmc:
-       clk_disable_unprepare(host->clk_mmc);
-error_disable_clk_ahb:
-       clk_disable_unprepare(host->clk_ahb);
-       return ret;
-}
-
-static int sunxi_mmc_probe(struct platform_device *pdev)
-{
-       struct sunxi_mmc_host *host;
-       struct mmc_host *mmc;
-       int ret;
-
-       mmc = mmc_alloc_host(sizeof(struct sunxi_mmc_host), &pdev->dev);
-       if (!mmc) {
-               dev_err(&pdev->dev, "mmc alloc host failed\n");
-               return -ENOMEM;
-       }
-
-       host = mmc_priv(mmc);
-       host->mmc = mmc;
-       spin_lock_init(&host->lock);
-
-       ret = sunxi_mmc_resource_request(host, pdev);
-       if (ret)
-               goto error_free_host;
-
-       host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE,
-                                         &host->sg_dma, GFP_KERNEL);
-       if (!host->sg_cpu) {
-               dev_err(&pdev->dev, "Failed to allocate DMA descriptor mem\n");
-               ret = -ENOMEM;
-               goto error_free_host;
-       }
-
-       mmc->ops                = &sunxi_mmc_ops;
-       mmc->max_blk_count      = 8192;
-       mmc->max_blk_size       = 4096;
-       mmc->max_segs           = PAGE_SIZE / sizeof(struct sunxi_idma_des);
-       mmc->max_seg_size       = (1 << host->idma_des_size_bits);
-       mmc->max_req_size       = mmc->max_seg_size * mmc->max_segs;
-       /* 400kHz ~ 50MHz */
-       mmc->f_min              =   400000;
-       mmc->f_max              = 50000000;
-       mmc->caps              |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
-
-       ret = mmc_of_parse(mmc);
-       if (ret)
-               goto error_free_dma;
-
-       ret = mmc_add_host(mmc);
-       if (ret)
-               goto error_free_dma;
-
-       dev_info(&pdev->dev, "base:0x%p irq:%u\n", host->reg_base, host->irq);
-       platform_set_drvdata(pdev, mmc);
-       return 0;
-
-error_free_dma:
-       dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
-error_free_host:
-       mmc_free_host(mmc);
-       return ret;
-}
-
-static int sunxi_mmc_remove(struct platform_device *pdev)
-{
-       struct mmc_host *mmc = platform_get_drvdata(pdev);
-       struct sunxi_mmc_host *host = mmc_priv(mmc);
-
-       mmc_remove_host(mmc);
-       disable_irq(host->irq);
-       sunxi_mmc_reset_host(host);
-
-       if (!IS_ERR(host->reset))
-               reset_control_assert(host->reset);
-
-       clk_disable_unprepare(host->clk_mmc);
-       clk_disable_unprepare(host->clk_ahb);
-
-       dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
-       mmc_free_host(mmc);
-
-       return 0;
-}
-
-static struct platform_driver sunxi_mmc_driver = {
-       .driver = {
-               .name   = "sunxi-mmc",
-               .owner  = THIS_MODULE,
-               .of_match_table = of_match_ptr(sunxi_mmc_of_match),
-       },
-       .probe          = sunxi_mmc_probe,
-       .remove         = sunxi_mmc_remove,
-};
-module_platform_driver(sunxi_mmc_driver);
-
-MODULE_DESCRIPTION("Allwinner's SD/MMC Card Controller Driver");
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("David Lanzend�rfer <david.lanzendoerfer@o2s.ch>");
-MODULE_ALIAS("platform:sunxi-mmc");
diff --git a/drivers/mmc/host/usdhi6rol0.c b/drivers/mmc/host/usdhi6rol0.c
new file mode 100644 (file)
index 0000000..eb2bbbe
--- /dev/null
@@ -0,0 +1,1847 @@
+/*
+ * Copyright (C) 2013-2014 Renesas Electronics Europe Ltd.
+ * Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/highmem.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/log2.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+#include <linux/mmc/sd.h>
+#include <linux/mmc/sdio.h>
+#include <linux/module.h>
+#include <linux/pagemap.h>
+#include <linux/platform_device.h>
+#include <linux/scatterlist.h>
+#include <linux/string.h>
+#include <linux/time.h>
+#include <linux/virtio.h>
+#include <linux/workqueue.h>
+
+#define USDHI6_SD_CMD          0x0000
+#define USDHI6_SD_PORT_SEL     0x0004
+#define USDHI6_SD_ARG          0x0008
+#define USDHI6_SD_STOP         0x0010
+#define USDHI6_SD_SECCNT       0x0014
+#define USDHI6_SD_RSP10                0x0018
+#define USDHI6_SD_RSP32                0x0020
+#define USDHI6_SD_RSP54                0x0028
+#define USDHI6_SD_RSP76                0x0030
+#define USDHI6_SD_INFO1                0x0038
+#define USDHI6_SD_INFO2                0x003c
+#define USDHI6_SD_INFO1_MASK   0x0040
+#define USDHI6_SD_INFO2_MASK   0x0044
+#define USDHI6_SD_CLK_CTRL     0x0048
+#define USDHI6_SD_SIZE         0x004c
+#define USDHI6_SD_OPTION       0x0050
+#define USDHI6_SD_ERR_STS1     0x0058
+#define USDHI6_SD_ERR_STS2     0x005c
+#define USDHI6_SD_BUF0         0x0060
+#define USDHI6_SDIO_MODE       0x0068
+#define USDHI6_SDIO_INFO1      0x006c
+#define USDHI6_SDIO_INFO1_MASK 0x0070
+#define USDHI6_CC_EXT_MODE     0x01b0
+#define USDHI6_SOFT_RST                0x01c0
+#define USDHI6_VERSION         0x01c4
+#define USDHI6_HOST_MODE       0x01c8
+#define USDHI6_SDIF_MODE       0x01cc
+
+#define USDHI6_SD_CMD_APP              0x0040
+#define USDHI6_SD_CMD_MODE_RSP_AUTO    0x0000
+#define USDHI6_SD_CMD_MODE_RSP_NONE    0x0300
+#define USDHI6_SD_CMD_MODE_RSP_R1      0x0400  /* Also R5, R6, R7 */
+#define USDHI6_SD_CMD_MODE_RSP_R1B     0x0500  /* R1b */
+#define USDHI6_SD_CMD_MODE_RSP_R2      0x0600
+#define USDHI6_SD_CMD_MODE_RSP_R3      0x0700  /* Also R4 */
+#define USDHI6_SD_CMD_DATA             0x0800
+#define USDHI6_SD_CMD_READ             0x1000
+#define USDHI6_SD_CMD_MULTI            0x2000
+#define USDHI6_SD_CMD_CMD12_AUTO_OFF   0x4000
+
+#define USDHI6_CC_EXT_MODE_SDRW                BIT(1)
+
+#define USDHI6_SD_INFO1_RSP_END                BIT(0)
+#define USDHI6_SD_INFO1_ACCESS_END     BIT(2)
+#define USDHI6_SD_INFO1_CARD_OUT       BIT(3)
+#define USDHI6_SD_INFO1_CARD_IN                BIT(4)
+#define USDHI6_SD_INFO1_CD             BIT(5)
+#define USDHI6_SD_INFO1_WP             BIT(7)
+#define USDHI6_SD_INFO1_D3_CARD_OUT    BIT(8)
+#define USDHI6_SD_INFO1_D3_CARD_IN     BIT(9)
+
+#define USDHI6_SD_INFO2_CMD_ERR                BIT(0)
+#define USDHI6_SD_INFO2_CRC_ERR                BIT(1)
+#define USDHI6_SD_INFO2_END_ERR                BIT(2)
+#define USDHI6_SD_INFO2_TOUT           BIT(3)
+#define USDHI6_SD_INFO2_IWA_ERR                BIT(4)
+#define USDHI6_SD_INFO2_IRA_ERR                BIT(5)
+#define USDHI6_SD_INFO2_RSP_TOUT       BIT(6)
+#define USDHI6_SD_INFO2_SDDAT0         BIT(7)
+#define USDHI6_SD_INFO2_BRE            BIT(8)
+#define USDHI6_SD_INFO2_BWE            BIT(9)
+#define USDHI6_SD_INFO2_SCLKDIVEN      BIT(13)
+#define USDHI6_SD_INFO2_CBSY           BIT(14)
+#define USDHI6_SD_INFO2_ILA            BIT(15)
+
+#define USDHI6_SD_INFO1_CARD_INSERT (USDHI6_SD_INFO1_CARD_IN | USDHI6_SD_INFO1_D3_CARD_IN)
+#define USDHI6_SD_INFO1_CARD_EJECT (USDHI6_SD_INFO1_CARD_OUT | USDHI6_SD_INFO1_D3_CARD_OUT)
+#define USDHI6_SD_INFO1_CARD (USDHI6_SD_INFO1_CARD_INSERT | USDHI6_SD_INFO1_CARD_EJECT)
+#define USDHI6_SD_INFO1_CARD_CD (USDHI6_SD_INFO1_CARD_IN | USDHI6_SD_INFO1_CARD_OUT)
+
+#define USDHI6_SD_INFO2_ERR    (USDHI6_SD_INFO2_CMD_ERR |      \
+       USDHI6_SD_INFO2_CRC_ERR | USDHI6_SD_INFO2_END_ERR |     \
+       USDHI6_SD_INFO2_TOUT | USDHI6_SD_INFO2_IWA_ERR |        \
+       USDHI6_SD_INFO2_IRA_ERR | USDHI6_SD_INFO2_RSP_TOUT |    \
+       USDHI6_SD_INFO2_ILA)
+
+#define USDHI6_SD_INFO1_IRQ    (USDHI6_SD_INFO1_RSP_END | USDHI6_SD_INFO1_ACCESS_END | \
+                                USDHI6_SD_INFO1_CARD)
+
+#define USDHI6_SD_INFO2_IRQ    (USDHI6_SD_INFO2_ERR | USDHI6_SD_INFO2_BRE | \
+                                USDHI6_SD_INFO2_BWE | 0x0800 | USDHI6_SD_INFO2_ILA)
+
+#define USDHI6_SD_CLK_CTRL_SCLKEN      BIT(8)
+
+#define USDHI6_SD_STOP_STP             BIT(0)
+#define USDHI6_SD_STOP_SEC             BIT(8)
+
+#define USDHI6_SDIO_INFO1_IOIRQ                BIT(0)
+#define USDHI6_SDIO_INFO1_EXPUB52      BIT(14)
+#define USDHI6_SDIO_INFO1_EXWT         BIT(15)
+
+#define USDHI6_SD_ERR_STS1_CRC_NO_ERROR        BIT(13)
+
+#define USDHI6_SOFT_RST_RESERVED       (BIT(1) | BIT(2))
+#define USDHI6_SOFT_RST_RESET          BIT(0)
+
+#define USDHI6_SD_OPTION_TIMEOUT_SHIFT 4
+#define USDHI6_SD_OPTION_TIMEOUT_MASK  (0xf << USDHI6_SD_OPTION_TIMEOUT_SHIFT)
+#define USDHI6_SD_OPTION_WIDTH_1       BIT(15)
+
+#define USDHI6_SD_PORT_SEL_PORTS_SHIFT 8
+
+#define USDHI6_SD_CLK_CTRL_DIV_MASK    0xff
+
+#define USDHI6_SDIO_INFO1_IRQ  (USDHI6_SDIO_INFO1_IOIRQ | 3 | \
+                                USDHI6_SDIO_INFO1_EXPUB52 | USDHI6_SDIO_INFO1_EXWT)
+
+#define USDHI6_MIN_DMA 64
+
+enum usdhi6_wait_for {
+       USDHI6_WAIT_FOR_REQUEST,
+       USDHI6_WAIT_FOR_CMD,
+       USDHI6_WAIT_FOR_MREAD,
+       USDHI6_WAIT_FOR_MWRITE,
+       USDHI6_WAIT_FOR_READ,
+       USDHI6_WAIT_FOR_WRITE,
+       USDHI6_WAIT_FOR_DATA_END,
+       USDHI6_WAIT_FOR_STOP,
+       USDHI6_WAIT_FOR_DMA,
+};
+
+struct usdhi6_page {
+       struct page *page;
+       void *mapped;           /* mapped page */
+};
+
+struct usdhi6_host {
+       struct mmc_host *mmc;
+       struct mmc_request *mrq;
+       void __iomem *base;
+       struct clk *clk;
+
+       /* SG memory handling */
+
+       /* Common for multiple and single block requests */
+       struct usdhi6_page pg;  /* current page from an SG */
+       void *blk_page;         /* either a mapped page, or the bounce buffer */
+       size_t offset;          /* offset within a page, including sg->offset */
+
+       /* Blocks, crossing a page boundary */
+       size_t head_len;
+       struct usdhi6_page head_pg;
+
+       /* A bounce buffer for unaligned blocks or blocks, crossing a page boundary */
+       struct scatterlist bounce_sg;
+       u8 bounce_buf[512];
+
+       /* Multiple block requests only */
+       struct scatterlist *sg; /* current SG segment */
+       int page_idx;           /* page index within an SG segment */
+
+       enum usdhi6_wait_for wait;
+       u32 status_mask;
+       u32 status2_mask;
+       u32 sdio_mask;
+       u32 io_error;
+       u32 irq_status;
+       unsigned long imclk;
+       unsigned long rate;
+       bool app_cmd;
+
+       /* Timeout handling */
+       struct delayed_work timeout_work;
+       unsigned long timeout;
+
+       /* DMA support */
+       struct dma_chan *chan_rx;
+       struct dma_chan *chan_tx;
+       bool dma_active;
+};
+
+/*                     I/O primitives                                  */
+
+static void usdhi6_write(struct usdhi6_host *host, u32 reg, u32 data)
+{
+       iowrite32(data, host->base + reg);
+       dev_vdbg(mmc_dev(host->mmc), "%s(0x%p + 0x%x) = 0x%x\n", __func__,
+               host->base, reg, data);
+}
+
+static void usdhi6_write16(struct usdhi6_host *host, u32 reg, u16 data)
+{
+       iowrite16(data, host->base + reg);
+       dev_vdbg(mmc_dev(host->mmc), "%s(0x%p + 0x%x) = 0x%x\n", __func__,
+               host->base, reg, data);
+}
+
+static u32 usdhi6_read(struct usdhi6_host *host, u32 reg)
+{
+       u32 data = ioread32(host->base + reg);
+       dev_vdbg(mmc_dev(host->mmc), "%s(0x%p + 0x%x) = 0x%x\n", __func__,
+               host->base, reg, data);
+       return data;
+}
+
+static u16 usdhi6_read16(struct usdhi6_host *host, u32 reg)
+{
+       u16 data = ioread16(host->base + reg);
+       dev_vdbg(mmc_dev(host->mmc), "%s(0x%p + 0x%x) = 0x%x\n", __func__,
+               host->base, reg, data);
+       return data;
+}
+
+static void usdhi6_irq_enable(struct usdhi6_host *host, u32 info1, u32 info2)
+{
+       host->status_mask = USDHI6_SD_INFO1_IRQ & ~info1;
+       host->status2_mask = USDHI6_SD_INFO2_IRQ & ~info2;
+       usdhi6_write(host, USDHI6_SD_INFO1_MASK, host->status_mask);
+       usdhi6_write(host, USDHI6_SD_INFO2_MASK, host->status2_mask);
+}
+
+static void usdhi6_wait_for_resp(struct usdhi6_host *host)
+{
+       usdhi6_irq_enable(host, USDHI6_SD_INFO1_RSP_END |
+                         USDHI6_SD_INFO1_ACCESS_END | USDHI6_SD_INFO1_CARD_CD,
+                         USDHI6_SD_INFO2_ERR);
+}
+
+static void usdhi6_wait_for_brwe(struct usdhi6_host *host, bool read)
+{
+       usdhi6_irq_enable(host, USDHI6_SD_INFO1_ACCESS_END |
+                         USDHI6_SD_INFO1_CARD_CD, USDHI6_SD_INFO2_ERR |
+                         (read ? USDHI6_SD_INFO2_BRE : USDHI6_SD_INFO2_BWE));
+}
+
+static void usdhi6_only_cd(struct usdhi6_host *host)
+{
+       /* Mask all except card hotplug */
+       usdhi6_irq_enable(host, USDHI6_SD_INFO1_CARD_CD, 0);
+}
+
+static void usdhi6_mask_all(struct usdhi6_host *host)
+{
+       usdhi6_irq_enable(host, 0, 0);
+}
+
+static int usdhi6_error_code(struct usdhi6_host *host)
+{
+       u32 err;
+
+       usdhi6_write(host, USDHI6_SD_STOP, USDHI6_SD_STOP_STP);
+
+       if (host->io_error &
+           (USDHI6_SD_INFO2_RSP_TOUT | USDHI6_SD_INFO2_TOUT)) {
+               u32 rsp54 = usdhi6_read(host, USDHI6_SD_RSP54);
+               int opc = host->mrq ? host->mrq->cmd->opcode : -1;
+
+               err = usdhi6_read(host, USDHI6_SD_ERR_STS2);
+               /* Response timeout is often normal, don't spam the log */
+               if (host->wait == USDHI6_WAIT_FOR_CMD)
+                       dev_dbg(mmc_dev(host->mmc),
+                               "T-out sts 0x%x, resp 0x%x, state %u, CMD%d\n",
+                               err, rsp54, host->wait, opc);
+               else
+                       dev_warn(mmc_dev(host->mmc),
+                                "T-out sts 0x%x, resp 0x%x, state %u, CMD%d\n",
+                                err, rsp54, host->wait, opc);
+               return -ETIMEDOUT;
+       }
+
+       err = usdhi6_read(host, USDHI6_SD_ERR_STS1);
+       if (err != USDHI6_SD_ERR_STS1_CRC_NO_ERROR)
+               dev_warn(mmc_dev(host->mmc), "Err sts 0x%x, state %u, CMD%d\n",
+                        err, host->wait, host->mrq ? host->mrq->cmd->opcode : -1);
+       if (host->io_error & USDHI6_SD_INFO2_ILA)
+               return -EILSEQ;
+
+       return -EIO;
+}
+
+/*                     Scatter-Gather management                       */
+
+/*
+ * In PIO mode we have to map each page separately, using kmap(). That way
+ * adjacent pages are mapped to non-adjacent virtual addresses. That's why we
+ * have to use a bounce buffer for blocks, crossing page boundaries. Such blocks
+ * have been observed with an SDIO WiFi card (b43 driver).
+ */
+static void usdhi6_blk_bounce(struct usdhi6_host *host,
+                             struct scatterlist *sg)
+{
+       struct mmc_data *data = host->mrq->data;
+       size_t blk_head = host->head_len;
+
+       dev_dbg(mmc_dev(host->mmc), "%s(): CMD%u of %u SG: %ux%u @ 0x%x\n",
+               __func__, host->mrq->cmd->opcode, data->sg_len,
+               data->blksz, data->blocks, sg->offset);
+
+       host->head_pg.page      = host->pg.page;
+       host->head_pg.mapped    = host->pg.mapped;
+       host->pg.page           = nth_page(host->pg.page, 1);
+       host->pg.mapped         = kmap(host->pg.page);
+
+       host->blk_page = host->bounce_buf;
+       host->offset = 0;
+
+       if (data->flags & MMC_DATA_READ)
+               return;
+
+       memcpy(host->bounce_buf, host->head_pg.mapped + PAGE_SIZE - blk_head,
+              blk_head);
+       memcpy(host->bounce_buf + blk_head, host->pg.mapped,
+              data->blksz - blk_head);
+}
+
+/* Only called for multiple block IO */
+static void usdhi6_sg_prep(struct usdhi6_host *host)
+{
+       struct mmc_request *mrq = host->mrq;
+       struct mmc_data *data = mrq->data;
+
+       usdhi6_write(host, USDHI6_SD_SECCNT, data->blocks);
+
+       host->sg = data->sg;
+       /* TODO: if we always map, this is redundant */
+       host->offset = host->sg->offset;
+}
+
+/* Map the first page in an SG segment: common for multiple and single block IO */
+static void *usdhi6_sg_map(struct usdhi6_host *host)
+{
+       struct mmc_data *data = host->mrq->data;
+       struct scatterlist *sg = data->sg_len > 1 ? host->sg : data->sg;
+       size_t head = PAGE_SIZE - sg->offset;
+       size_t blk_head = head % data->blksz;
+
+       WARN(host->pg.page, "%p not properly unmapped!\n", host->pg.page);
+       if (WARN(sg_dma_len(sg) % data->blksz,
+                "SG size %zd isn't a multiple of block size %zd\n",
+                sg_dma_len(sg), data->blksz))
+               return NULL;
+
+       host->pg.page = sg_page(sg);
+       host->pg.mapped = kmap(host->pg.page);
+       host->offset = sg->offset;
+
+       /*
+        * Block size must be a power of 2 for multi-block transfers,
+        * therefore blk_head is equal for all pages in this SG
+        */
+       host->head_len = blk_head;
+
+       if (head < data->blksz)
+               /*
+                * The first block in the SG crosses a page boundary.
+                * Max blksz = 512, so blocks can only span 2 pages
+                */
+               usdhi6_blk_bounce(host, sg);
+       else
+               host->blk_page = host->pg.mapped;
+
+       dev_dbg(mmc_dev(host->mmc), "Mapped %p (%lx) at %p + %u for CMD%u @ 0x%p\n",
+               host->pg.page, page_to_pfn(host->pg.page), host->pg.mapped,
+               sg->offset, host->mrq->cmd->opcode, host->mrq);
+
+       return host->blk_page + host->offset;
+}
+
+/* Unmap the current page: common for multiple and single block IO */
+static void usdhi6_sg_unmap(struct usdhi6_host *host, bool force)
+{
+       struct mmc_data *data = host->mrq->data;
+       struct page *page = host->head_pg.page;
+
+       if (page) {
+               /* Previous block was cross-page boundary */
+               struct scatterlist *sg = data->sg_len > 1 ?
+                       host->sg : data->sg;
+               size_t blk_head = host->head_len;
+
+               if (!data->error && data->flags & MMC_DATA_READ) {
+                       memcpy(host->head_pg.mapped + PAGE_SIZE - blk_head,
+                              host->bounce_buf, blk_head);
+                       memcpy(host->pg.mapped, host->bounce_buf + blk_head,
+                              data->blksz - blk_head);
+               }
+
+               flush_dcache_page(page);
+               kunmap(page);
+
+               host->head_pg.page = NULL;
+
+               if (!force && sg_dma_len(sg) + sg->offset >
+                   (host->page_idx << PAGE_SHIFT) + data->blksz - blk_head)
+                       /* More blocks in this SG, don't unmap the next page */
+                       return;
+       }
+
+       page = host->pg.page;
+       if (!page)
+               return;
+
+       flush_dcache_page(page);
+       kunmap(page);
+
+       host->pg.page = NULL;
+}
+
+/* Called from MMC_WRITE_MULTIPLE_BLOCK or MMC_READ_MULTIPLE_BLOCK */
+static void usdhi6_sg_advance(struct usdhi6_host *host)
+{
+       struct mmc_data *data = host->mrq->data;
+       size_t done, total;
+
+       /* New offset: set at the end of the previous block */
+       if (host->head_pg.page) {
+               /* Finished a cross-page block, jump to the new page */
+               host->page_idx++;
+               host->offset = data->blksz - host->head_len;
+               host->blk_page = host->pg.mapped;
+               usdhi6_sg_unmap(host, false);
+       } else {
+               host->offset += data->blksz;
+               /* The completed block didn't cross a page boundary */
+               if (host->offset == PAGE_SIZE) {
+                       /* If required, we'll map the page below */
+                       host->offset = 0;
+                       host->page_idx++;
+               }
+       }
+
+       /*
+        * Now host->blk_page + host->offset point at the end of our last block
+        * and host->page_idx is the index of the page, in which our new block
+        * is located, if any
+        */
+
+       done = (host->page_idx << PAGE_SHIFT) + host->offset;
+       total = host->sg->offset + sg_dma_len(host->sg);
+
+       dev_dbg(mmc_dev(host->mmc), "%s(): %zu of %zu @ %u\n", __func__,
+               done, total, host->offset);
+
+       if (done < total && host->offset) {
+               /* More blocks in this page */
+               if (host->offset + data->blksz > PAGE_SIZE)
+                       /* We approached at a block, that spans 2 pages */
+                       usdhi6_blk_bounce(host, host->sg);
+
+               return;
+       }
+
+       /* Finished current page or an SG segment */
+       usdhi6_sg_unmap(host, false);
+
+       if (done == total) {
+               /*
+                * End of an SG segment or the complete SG: jump to the next
+                * segment, we'll map it later in usdhi6_blk_read() or
+                * usdhi6_blk_write()
+                */
+               struct scatterlist *next = sg_next(host->sg);
+
+               host->page_idx = 0;
+
+               if (!next)
+                       host->wait = USDHI6_WAIT_FOR_DATA_END;
+               host->sg = next;
+
+               if (WARN(next && sg_dma_len(next) % data->blksz,
+                        "SG size %zd isn't a multiple of block size %zd\n",
+                        sg_dma_len(next), data->blksz))
+                       data->error = -EINVAL;
+
+               return;
+       }
+
+       /* We cannot get here after crossing a page border */
+
+       /* Next page in the same SG */
+       host->pg.page = nth_page(sg_page(host->sg), host->page_idx);
+       host->pg.mapped = kmap(host->pg.page);
+       host->blk_page = host->pg.mapped;
+
+       dev_dbg(mmc_dev(host->mmc), "Mapped %p (%lx) at %p for CMD%u @ 0x%p\n",
+               host->pg.page, page_to_pfn(host->pg.page), host->pg.mapped,
+               host->mrq->cmd->opcode, host->mrq);
+}
+
+/*                     DMA handling                                    */
+
+static void usdhi6_dma_release(struct usdhi6_host *host)
+{
+       host->dma_active = false;
+       if (host->chan_tx) {
+               struct dma_chan *chan = host->chan_tx;
+               host->chan_tx = NULL;
+               dma_release_channel(chan);
+       }
+       if (host->chan_rx) {
+               struct dma_chan *chan = host->chan_rx;
+               host->chan_rx = NULL;
+               dma_release_channel(chan);
+       }
+}
+
+static void usdhi6_dma_stop_unmap(struct usdhi6_host *host)
+{
+       struct mmc_data *data = host->mrq->data;
+
+       if (!host->dma_active)
+               return;
+
+       usdhi6_write(host, USDHI6_CC_EXT_MODE, 0);
+       host->dma_active = false;
+
+       if (data->flags & MMC_DATA_READ)
+               dma_unmap_sg(host->chan_rx->device->dev, data->sg,
+                            data->sg_len, DMA_FROM_DEVICE);
+       else
+               dma_unmap_sg(host->chan_tx->device->dev, data->sg,
+                            data->sg_len, DMA_TO_DEVICE);
+}
+
+static void usdhi6_dma_complete(void *arg)
+{
+       struct usdhi6_host *host = arg;
+       struct mmc_request *mrq = host->mrq;
+
+       if (WARN(!mrq || !mrq->data, "%s: NULL data in DMA completion for %p!\n",
+                dev_name(mmc_dev(host->mmc)), mrq))
+               return;
+
+       dev_dbg(mmc_dev(host->mmc), "%s(): CMD%u DMA completed\n", __func__,
+               mrq->cmd->opcode);
+
+       usdhi6_dma_stop_unmap(host);
+       usdhi6_wait_for_brwe(host, mrq->data->flags & MMC_DATA_READ);
+}
+
+static int usdhi6_dma_setup(struct usdhi6_host *host, struct dma_chan *chan,
+                           enum dma_transfer_direction dir)
+{
+       struct mmc_data *data = host->mrq->data;
+       struct scatterlist *sg = data->sg;
+       struct dma_async_tx_descriptor *desc = NULL;
+       dma_cookie_t cookie = -EINVAL;
+       enum dma_data_direction data_dir;
+       int ret;
+
+       switch (dir) {
+       case DMA_MEM_TO_DEV:
+               data_dir = DMA_TO_DEVICE;
+               break;
+       case DMA_DEV_TO_MEM:
+               data_dir = DMA_FROM_DEVICE;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = dma_map_sg(chan->device->dev, sg, data->sg_len, data_dir);
+       if (ret > 0) {
+               host->dma_active = true;
+               desc = dmaengine_prep_slave_sg(chan, sg, ret, dir,
+                                       DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+       }
+
+       if (desc) {
+               desc->callback = usdhi6_dma_complete;
+               desc->callback_param = host;
+               cookie = dmaengine_submit(desc);
+       }
+
+       dev_dbg(mmc_dev(host->mmc), "%s(): mapped %d -> %d, cookie %d @ %p\n",
+               __func__, data->sg_len, ret, cookie, desc);
+
+       if (cookie < 0) {
+               /* DMA failed, fall back to PIO */
+               if (ret >= 0)
+                       ret = cookie;
+               usdhi6_dma_release(host);
+               dev_warn(mmc_dev(host->mmc),
+                        "DMA failed: %d, falling back to PIO\n", ret);
+       }
+
+       return cookie;
+}
+
+static int usdhi6_dma_start(struct usdhi6_host *host)
+{
+       if (!host->chan_rx || !host->chan_tx)
+               return -ENODEV;
+
+       if (host->mrq->data->flags & MMC_DATA_READ)
+               return usdhi6_dma_setup(host, host->chan_rx, DMA_DEV_TO_MEM);
+
+       return usdhi6_dma_setup(host, host->chan_tx, DMA_MEM_TO_DEV);
+}
+
+static void usdhi6_dma_kill(struct usdhi6_host *host)
+{
+       struct mmc_data *data = host->mrq->data;
+
+       dev_dbg(mmc_dev(host->mmc), "%s(): SG of %u: %ux%u\n",
+               __func__, data->sg_len, data->blocks, data->blksz);
+       /* Abort DMA */
+       if (data->flags & MMC_DATA_READ)
+               dmaengine_terminate_all(host->chan_rx);
+       else
+               dmaengine_terminate_all(host->chan_tx);
+}
+
+static void usdhi6_dma_check_error(struct usdhi6_host *host)
+{
+       struct mmc_data *data = host->mrq->data;
+
+       dev_dbg(mmc_dev(host->mmc), "%s(): IO error %d, status 0x%x\n",
+               __func__, host->io_error, usdhi6_read(host, USDHI6_SD_INFO1));
+
+       if (host->io_error) {
+               data->error = usdhi6_error_code(host);
+               data->bytes_xfered = 0;
+               usdhi6_dma_kill(host);
+               usdhi6_dma_release(host);
+               dev_warn(mmc_dev(host->mmc),
+                        "DMA failed: %d, falling back to PIO\n", data->error);
+               return;
+       }
+
+       /*
+        * The datasheet tells us to check a response from the card, whereas
+        * responses only come after the command phase, not after the data
+        * phase. Let's check anyway.
+        */
+       if (host->irq_status & USDHI6_SD_INFO1_RSP_END)
+               dev_warn(mmc_dev(host->mmc), "Unexpected response received!\n");
+}
+
+static void usdhi6_dma_kick(struct usdhi6_host *host)
+{
+       if (host->mrq->data->flags & MMC_DATA_READ)
+               dma_async_issue_pending(host->chan_rx);
+       else
+               dma_async_issue_pending(host->chan_tx);
+}
+
+static void usdhi6_dma_request(struct usdhi6_host *host, phys_addr_t start)
+{
+       struct dma_slave_config cfg = {
+               .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
+               .dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
+       };
+       int ret;
+
+       host->chan_tx = dma_request_slave_channel(mmc_dev(host->mmc), "tx");
+       dev_dbg(mmc_dev(host->mmc), "%s: TX: got channel %p\n", __func__,
+               host->chan_tx);
+
+       if (!host->chan_tx)
+               return;
+
+       cfg.direction = DMA_MEM_TO_DEV;
+       cfg.dst_addr = start + USDHI6_SD_BUF0;
+       cfg.dst_maxburst = 128; /* 128 words * 4 bytes = 512 bytes */
+       cfg.src_addr = 0;
+       ret = dmaengine_slave_config(host->chan_tx, &cfg);
+       if (ret < 0)
+               goto e_release_tx;
+
+       host->chan_rx = dma_request_slave_channel(mmc_dev(host->mmc), "rx");
+       dev_dbg(mmc_dev(host->mmc), "%s: RX: got channel %p\n", __func__,
+               host->chan_rx);
+
+       if (!host->chan_rx)
+               goto e_release_tx;
+
+       cfg.direction = DMA_DEV_TO_MEM;
+       cfg.src_addr = cfg.dst_addr;
+       cfg.src_maxburst = 128; /* 128 words * 4 bytes = 512 bytes */
+       cfg.dst_addr = 0;
+       ret = dmaengine_slave_config(host->chan_rx, &cfg);
+       if (ret < 0)
+               goto e_release_rx;
+
+       return;
+
+e_release_rx:
+       dma_release_channel(host->chan_rx);
+       host->chan_rx = NULL;
+e_release_tx:
+       dma_release_channel(host->chan_tx);
+       host->chan_tx = NULL;
+}
+
+/*                     API helpers                                     */
+
+static void usdhi6_clk_set(struct usdhi6_host *host, struct mmc_ios *ios)
+{
+       unsigned long rate = ios->clock;
+       u32 val;
+       unsigned int i;
+
+       for (i = 1000; i; i--) {
+               if (usdhi6_read(host, USDHI6_SD_INFO2) & USDHI6_SD_INFO2_SCLKDIVEN)
+                       break;
+               usleep_range(10, 100);
+       }
+
+       if (!i) {
+               dev_err(mmc_dev(host->mmc), "SD bus busy, clock set aborted\n");
+               return;
+       }
+
+       val = usdhi6_read(host, USDHI6_SD_CLK_CTRL) & ~USDHI6_SD_CLK_CTRL_DIV_MASK;
+
+       if (rate) {
+               unsigned long new_rate;
+
+               if (host->imclk <= rate) {
+                       if (ios->timing != MMC_TIMING_UHS_DDR50) {
+                               /* Cannot have 1-to-1 clock in DDR mode */
+                               new_rate = host->imclk;
+                               val |= 0xff;
+                       } else {
+                               new_rate = host->imclk / 2;
+                       }
+               } else {
+                       unsigned long div =
+                               roundup_pow_of_two(DIV_ROUND_UP(host->imclk, rate));
+                       val |= div >> 2;
+                       new_rate = host->imclk / div;
+               }
+
+               if (host->rate == new_rate)
+                       return;
+
+               host->rate = new_rate;
+
+               dev_dbg(mmc_dev(host->mmc), "target %lu, div %u, set %lu\n",
+                       rate, (val & 0xff) << 2, new_rate);
+       }
+
+       /*
+        * if old or new rate is equal to input rate, have to switch the clock
+        * off before changing and on after
+        */
+       if (host->imclk == rate || host->imclk == host->rate || !rate)
+               usdhi6_write(host, USDHI6_SD_CLK_CTRL,
+                            val & ~USDHI6_SD_CLK_CTRL_SCLKEN);
+
+       if (!rate) {
+               host->rate = 0;
+               return;
+       }
+
+       usdhi6_write(host, USDHI6_SD_CLK_CTRL, val);
+
+       if (host->imclk == rate || host->imclk == host->rate ||
+           !(val & USDHI6_SD_CLK_CTRL_SCLKEN))
+               usdhi6_write(host, USDHI6_SD_CLK_CTRL,
+                            val | USDHI6_SD_CLK_CTRL_SCLKEN);
+}
+
+static void usdhi6_set_power(struct usdhi6_host *host, struct mmc_ios *ios)
+{
+       struct mmc_host *mmc = host->mmc;
+
+       if (!IS_ERR(mmc->supply.vmmc))
+               /* Errors ignored... */
+               mmc_regulator_set_ocr(mmc, mmc->supply.vmmc,
+                                     ios->power_mode ? ios->vdd : 0);
+}
+
+static int usdhi6_reset(struct usdhi6_host *host)
+{
+       int i;
+
+       usdhi6_write(host, USDHI6_SOFT_RST, USDHI6_SOFT_RST_RESERVED);
+       cpu_relax();
+       usdhi6_write(host, USDHI6_SOFT_RST, USDHI6_SOFT_RST_RESERVED | USDHI6_SOFT_RST_RESET);
+       for (i = 1000; i; i--)
+               if (usdhi6_read(host, USDHI6_SOFT_RST) & USDHI6_SOFT_RST_RESET)
+                       break;
+
+       return i ? 0 : -ETIMEDOUT;
+}
+
+static void usdhi6_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+       struct usdhi6_host *host = mmc_priv(mmc);
+       u32 option, mode;
+       int ret;
+
+       dev_dbg(mmc_dev(mmc), "%uHz, OCR: %u, power %u, bus-width %u, timing %u\n",
+               ios->clock, ios->vdd, ios->power_mode, ios->bus_width, ios->timing);
+
+       switch (ios->power_mode) {
+       case MMC_POWER_OFF:
+               usdhi6_set_power(host, ios);
+               usdhi6_only_cd(host);
+               break;
+       case MMC_POWER_UP:
+               /*
+                * We only also touch USDHI6_SD_OPTION from .request(), which
+                * cannot race with MMC_POWER_UP
+                */
+               ret = usdhi6_reset(host);
+               if (ret < 0) {
+                       dev_err(mmc_dev(mmc), "Cannot reset the interface!\n");
+               } else {
+                       usdhi6_set_power(host, ios);
+                       usdhi6_only_cd(host);
+               }
+               break;
+       case MMC_POWER_ON:
+               option = usdhi6_read(host, USDHI6_SD_OPTION);
+               /*
+                * The eMMC standard only allows 4 or 8 bits in the DDR mode,
+                * the same probably holds for SD cards. We check here anyway,
+                * since the datasheet explicitly requires 4 bits for DDR.
+                */
+               if (ios->bus_width == MMC_BUS_WIDTH_1) {
+                       if (ios->timing == MMC_TIMING_UHS_DDR50)
+                               dev_err(mmc_dev(mmc),
+                                       "4 bits are required for DDR\n");
+                       option |= USDHI6_SD_OPTION_WIDTH_1;
+                       mode = 0;
+               } else {
+                       option &= ~USDHI6_SD_OPTION_WIDTH_1;
+                       mode = ios->timing == MMC_TIMING_UHS_DDR50;
+               }
+               usdhi6_write(host, USDHI6_SD_OPTION, option);
+               usdhi6_write(host, USDHI6_SDIF_MODE, mode);
+               break;
+       }
+
+       if (host->rate != ios->clock)
+               usdhi6_clk_set(host, ios);
+}
+
+/* This is data timeout. Response timeout is fixed to 640 clock cycles */
+static void usdhi6_timeout_set(struct usdhi6_host *host)
+{
+       struct mmc_request *mrq = host->mrq;
+       u32 val;
+       unsigned long ticks;
+
+       if (!mrq->data)
+               ticks = host->rate / 1000 * mrq->cmd->busy_timeout;
+       else
+               ticks = host->rate / 1000000 * (mrq->data->timeout_ns / 1000) +
+                       mrq->data->timeout_clks;
+
+       if (!ticks || ticks > 1 << 27)
+               /* Max timeout */
+               val = 14;
+       else if (ticks < 1 << 13)
+               /* Min timeout */
+               val = 0;
+       else
+               val = order_base_2(ticks) - 13;
+
+       dev_dbg(mmc_dev(host->mmc), "Set %s timeout %lu ticks @ %lu Hz\n",
+               mrq->data ? "data" : "cmd", ticks, host->rate);
+
+       /* Timeout Counter mask: 0xf0 */
+       usdhi6_write(host, USDHI6_SD_OPTION, (val << USDHI6_SD_OPTION_TIMEOUT_SHIFT) |
+                    (usdhi6_read(host, USDHI6_SD_OPTION) & ~USDHI6_SD_OPTION_TIMEOUT_MASK));
+}
+
+static void usdhi6_request_done(struct usdhi6_host *host)
+{
+       struct mmc_request *mrq = host->mrq;
+       struct mmc_data *data = mrq->data;
+
+       if (WARN(host->pg.page || host->head_pg.page,
+                "Page %p or %p not unmapped: wait %u, CMD%d(%c) @ +0x%x %ux%u in SG%u!\n",
+                host->pg.page, host->head_pg.page, host->wait, mrq->cmd->opcode,
+                data ? (data->flags & MMC_DATA_READ ? 'R' : 'W') : '-',
+                data ? host->offset : 0, data ? data->blocks : 0,
+                data ? data->blksz : 0, data ? data->sg_len : 0))
+               usdhi6_sg_unmap(host, true);
+
+       if (mrq->cmd->error ||
+           (data && data->error) ||
+           (mrq->stop && mrq->stop->error))
+               dev_dbg(mmc_dev(host->mmc), "%s(CMD%d: %ux%u): err %d %d %d\n",
+                       __func__, mrq->cmd->opcode, data ? data->blocks : 0,
+                       data ? data->blksz : 0,
+                       mrq->cmd->error,
+                       data ? data->error : 1,
+                       mrq->stop ? mrq->stop->error : 1);
+
+       /* Disable DMA */
+       usdhi6_write(host, USDHI6_CC_EXT_MODE, 0);
+       host->wait = USDHI6_WAIT_FOR_REQUEST;
+       host->mrq = NULL;
+
+       mmc_request_done(host->mmc, mrq);
+}
+
+static int usdhi6_cmd_flags(struct usdhi6_host *host)
+{
+       struct mmc_request *mrq = host->mrq;
+       struct mmc_command *cmd = mrq->cmd;
+       u16 opc = cmd->opcode;
+
+       if (host->app_cmd) {
+               host->app_cmd = false;
+               opc |= USDHI6_SD_CMD_APP;
+       }
+
+       if (mrq->data) {
+               opc |= USDHI6_SD_CMD_DATA;
+
+               if (mrq->data->flags & MMC_DATA_READ)
+                       opc |= USDHI6_SD_CMD_READ;
+
+               if (cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
+                   cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK ||
+                   (cmd->opcode == SD_IO_RW_EXTENDED &&
+                    mrq->data->blocks > 1)) {
+                       opc |= USDHI6_SD_CMD_MULTI;
+                       if (!mrq->stop)
+                               opc |= USDHI6_SD_CMD_CMD12_AUTO_OFF;
+               }
+
+               switch (mmc_resp_type(cmd)) {
+               case MMC_RSP_NONE:
+                       opc |= USDHI6_SD_CMD_MODE_RSP_NONE;
+                       break;
+               case MMC_RSP_R1:
+                       opc |= USDHI6_SD_CMD_MODE_RSP_R1;
+                       break;
+               case MMC_RSP_R1B:
+                       opc |= USDHI6_SD_CMD_MODE_RSP_R1B;
+                       break;
+               case MMC_RSP_R2:
+                       opc |= USDHI6_SD_CMD_MODE_RSP_R2;
+                       break;
+               case MMC_RSP_R3:
+                       opc |= USDHI6_SD_CMD_MODE_RSP_R3;
+                       break;
+               default:
+                       dev_warn(mmc_dev(host->mmc),
+                                "Unknown response type %d\n",
+                                mmc_resp_type(cmd));
+                       return -EINVAL;
+               }
+       }
+
+       return opc;
+}
+
+static int usdhi6_rq_start(struct usdhi6_host *host)
+{
+       struct mmc_request *mrq = host->mrq;
+       struct mmc_command *cmd = mrq->cmd;
+       struct mmc_data *data = mrq->data;
+       int opc = usdhi6_cmd_flags(host);
+       int i;
+
+       if (opc < 0)
+               return opc;
+
+       for (i = 1000; i; i--) {
+               if (!(usdhi6_read(host, USDHI6_SD_INFO2) & USDHI6_SD_INFO2_CBSY))
+                       break;
+               usleep_range(10, 100);
+       }
+
+       if (!i) {
+               dev_dbg(mmc_dev(host->mmc), "Command active, request aborted\n");
+               return -EAGAIN;
+       }
+
+       if (data) {
+               bool use_dma;
+               int ret = 0;
+
+               host->page_idx = 0;
+
+               if (cmd->opcode == SD_IO_RW_EXTENDED && data->blocks > 1) {
+                       switch (data->blksz) {
+                       case 512:
+                               break;
+                       case 32:
+                       case 64:
+                       case 128:
+                       case 256:
+                               if (mrq->stop)
+                                       ret = -EINVAL;
+                               break;
+                       default:
+                               ret = -EINVAL;
+                       }
+               } else if ((cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
+                           cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK) &&
+                          data->blksz != 512) {
+                       ret = -EINVAL;
+               }
+
+               if (ret < 0) {
+                       dev_warn(mmc_dev(host->mmc), "%s(): %u blocks of %u bytes\n",
+                                __func__, data->blocks, data->blksz);
+                       return -EINVAL;
+               }
+
+               if (cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
+                   cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK ||
+                   (cmd->opcode == SD_IO_RW_EXTENDED &&
+                    data->blocks > 1))
+                       usdhi6_sg_prep(host);
+
+               usdhi6_write(host, USDHI6_SD_SIZE, data->blksz);
+
+               if ((data->blksz >= USDHI6_MIN_DMA ||
+                    data->blocks > 1) &&
+                   (data->blksz % 4 ||
+                    data->sg->offset % 4))
+                       dev_dbg(mmc_dev(host->mmc),
+                               "Bad SG of %u: %ux%u @ %u\n", data->sg_len,
+                               data->blksz, data->blocks, data->sg->offset);
+
+               /* Enable DMA for USDHI6_MIN_DMA bytes or more */
+               use_dma = data->blksz >= USDHI6_MIN_DMA &&
+                       !(data->blksz % 4) &&
+                       usdhi6_dma_start(host) >= DMA_MIN_COOKIE;
+
+               if (use_dma)
+                       usdhi6_write(host, USDHI6_CC_EXT_MODE, USDHI6_CC_EXT_MODE_SDRW);
+
+               dev_dbg(mmc_dev(host->mmc),
+                       "%s(): request opcode %u, %u blocks of %u bytes in %u segments, %s %s @+0x%x%s\n",
+                       __func__, cmd->opcode, data->blocks, data->blksz,
+                       data->sg_len, use_dma ? "DMA" : "PIO",
+                       data->flags & MMC_DATA_READ ? "read" : "write",
+                       data->sg->offset, mrq->stop ? " + stop" : "");
+       } else {
+               dev_dbg(mmc_dev(host->mmc), "%s(): request opcode %u\n",
+                       __func__, cmd->opcode);
+       }
+
+       /* We have to get a command completion interrupt with DMA too */
+       usdhi6_wait_for_resp(host);
+
+       host->wait = USDHI6_WAIT_FOR_CMD;
+       schedule_delayed_work(&host->timeout_work, host->timeout);
+
+       /* SEC bit is required to enable block counting by the core */
+       usdhi6_write(host, USDHI6_SD_STOP,
+                    data && data->blocks > 1 ? USDHI6_SD_STOP_SEC : 0);
+       usdhi6_write(host, USDHI6_SD_ARG, cmd->arg);
+
+       /* Kick command execution */
+       usdhi6_write(host, USDHI6_SD_CMD, opc);
+
+       return 0;
+}
+
+static void usdhi6_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+       struct usdhi6_host *host = mmc_priv(mmc);
+       int ret;
+
+       cancel_delayed_work_sync(&host->timeout_work);
+
+       host->mrq = mrq;
+       host->sg = NULL;
+
+       usdhi6_timeout_set(host);
+       ret = usdhi6_rq_start(host);
+       if (ret < 0) {
+               mrq->cmd->error = ret;
+               usdhi6_request_done(host);
+       }
+}
+
+static int usdhi6_get_cd(struct mmc_host *mmc)
+{
+       struct usdhi6_host *host = mmc_priv(mmc);
+       /* Read is atomic, no need to lock */
+       u32 status = usdhi6_read(host, USDHI6_SD_INFO1) & USDHI6_SD_INFO1_CD;
+
+/*
+ *     level   status.CD       CD_ACTIVE_HIGH  card present
+ *     1       0               0               0
+ *     1       0               1               1
+ *     0       1               0               1
+ *     0       1               1               0
+ */
+       return !status ^ !(mmc->caps2 & MMC_CAP2_CD_ACTIVE_HIGH);
+}
+
+static int usdhi6_get_ro(struct mmc_host *mmc)
+{
+       struct usdhi6_host *host = mmc_priv(mmc);
+       /* No locking as above */
+       u32 status = usdhi6_read(host, USDHI6_SD_INFO1) & USDHI6_SD_INFO1_WP;
+
+/*
+ *     level   status.WP       RO_ACTIVE_HIGH  card read-only
+ *     1       0               0               0
+ *     1       0               1               1
+ *     0       1               0               1
+ *     0       1               1               0
+ */
+       return !status ^ !(mmc->caps2 & MMC_CAP2_RO_ACTIVE_HIGH);
+}
+
+static void usdhi6_enable_sdio_irq(struct mmc_host *mmc, int enable)
+{
+       struct usdhi6_host *host = mmc_priv(mmc);
+
+       dev_dbg(mmc_dev(mmc), "%s(): %sable\n", __func__, enable ? "en" : "dis");
+
+       if (enable) {
+               host->sdio_mask = USDHI6_SDIO_INFO1_IRQ & ~USDHI6_SDIO_INFO1_IOIRQ;
+               usdhi6_write(host, USDHI6_SDIO_INFO1_MASK, host->sdio_mask);
+               usdhi6_write(host, USDHI6_SDIO_MODE, 1);
+       } else {
+               usdhi6_write(host, USDHI6_SDIO_MODE, 0);
+               usdhi6_write(host, USDHI6_SDIO_INFO1_MASK, USDHI6_SDIO_INFO1_IRQ);
+               host->sdio_mask = USDHI6_SDIO_INFO1_IRQ;
+       }
+}
+
+static struct mmc_host_ops usdhi6_ops = {
+       .request        = usdhi6_request,
+       .set_ios        = usdhi6_set_ios,
+       .get_cd         = usdhi6_get_cd,
+       .get_ro         = usdhi6_get_ro,
+       .enable_sdio_irq = usdhi6_enable_sdio_irq,
+};
+
+/*                     State machine handlers                          */
+
+static void usdhi6_resp_cmd12(struct usdhi6_host *host)
+{
+       struct mmc_command *cmd = host->mrq->stop;
+       cmd->resp[0] = usdhi6_read(host, USDHI6_SD_RSP10);
+}
+
+static void usdhi6_resp_read(struct usdhi6_host *host)
+{
+       struct mmc_command *cmd = host->mrq->cmd;
+       u32 *rsp = cmd->resp, tmp = 0;
+       int i;
+
+/*
+ * RSP10       39-8
+ * RSP32       71-40
+ * RSP54       103-72
+ * RSP76       127-104
+ * R2-type response:
+ * resp[0]     = r[127..96]
+ * resp[1]     = r[95..64]
+ * resp[2]     = r[63..32]
+ * resp[3]     = r[31..0]
+ * Other responses:
+ * resp[0]     = r[39..8]
+ */
+
+       if (mmc_resp_type(cmd) == MMC_RSP_NONE)
+               return;
+
+       if (!(host->irq_status & USDHI6_SD_INFO1_RSP_END)) {
+               dev_err(mmc_dev(host->mmc),
+                       "CMD%d: response expected but is missing!\n", cmd->opcode);
+               return;
+       }
+
+       if (mmc_resp_type(cmd) & MMC_RSP_136)
+               for (i = 0; i < 4; i++) {
+                       if (i)
+                               rsp[3 - i] = tmp >> 24;
+                       tmp = usdhi6_read(host, USDHI6_SD_RSP10 + i * 8);
+                       rsp[3 - i] |= tmp << 8;
+               }
+       else if (cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
+                cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK)
+               /* Read RSP54 to avoid conflict with auto CMD12 */
+               rsp[0] = usdhi6_read(host, USDHI6_SD_RSP54);
+       else
+               rsp[0] = usdhi6_read(host, USDHI6_SD_RSP10);
+
+       dev_dbg(mmc_dev(host->mmc), "Response 0x%x\n", rsp[0]);
+}
+
+static int usdhi6_blk_read(struct usdhi6_host *host)
+{
+       struct mmc_data *data = host->mrq->data;
+       u32 *p;
+       int i, rest;
+
+       if (host->io_error) {
+               data->error = usdhi6_error_code(host);
+               goto error;
+       }
+
+       if (host->pg.page) {
+               p = host->blk_page + host->offset;
+       } else {
+               p = usdhi6_sg_map(host);
+               if (!p) {
+                       data->error = -ENOMEM;
+                       goto error;
+               }
+       }
+
+       for (i = 0; i < data->blksz / 4; i++, p++)
+               *p = usdhi6_read(host, USDHI6_SD_BUF0);
+
+       rest = data->blksz % 4;
+       for (i = 0; i < (rest + 1) / 2; i++) {
+               u16 d = usdhi6_read16(host, USDHI6_SD_BUF0);
+               ((u8 *)p)[2 * i] = ((u8 *)&d)[0];
+               if (rest > 1 && !i)
+                       ((u8 *)p)[2 * i + 1] = ((u8 *)&d)[1];
+       }
+
+       return 0;
+
+error:
+       dev_dbg(mmc_dev(host->mmc), "%s(): %d\n", __func__, data->error);
+       host->wait = USDHI6_WAIT_FOR_REQUEST;
+       return data->error;
+}
+
+static int usdhi6_blk_write(struct usdhi6_host *host)
+{
+       struct mmc_data *data = host->mrq->data;
+       u32 *p;
+       int i, rest;
+
+       if (host->io_error) {
+               data->error = usdhi6_error_code(host);
+               goto error;
+       }
+
+       if (host->pg.page) {
+               p = host->blk_page + host->offset;
+       } else {
+               p = usdhi6_sg_map(host);
+               if (!p) {
+                       data->error = -ENOMEM;
+                       goto error;
+               }
+       }
+
+       for (i = 0; i < data->blksz / 4; i++, p++)
+               usdhi6_write(host, USDHI6_SD_BUF0, *p);
+
+       rest = data->blksz % 4;
+       for (i = 0; i < (rest + 1) / 2; i++) {
+               u16 d;
+               ((u8 *)&d)[0] = ((u8 *)p)[2 * i];
+               if (rest > 1 && !i)
+                       ((u8 *)&d)[1] = ((u8 *)p)[2 * i + 1];
+               else
+                       ((u8 *)&d)[1] = 0;
+               usdhi6_write16(host, USDHI6_SD_BUF0, d);
+       }
+
+       return 0;
+
+error:
+       dev_dbg(mmc_dev(host->mmc), "%s(): %d\n", __func__, data->error);
+       host->wait = USDHI6_WAIT_FOR_REQUEST;
+       return data->error;
+}
+
+static int usdhi6_stop_cmd(struct usdhi6_host *host)
+{
+       struct mmc_request *mrq = host->mrq;
+
+       switch (mrq->cmd->opcode) {
+       case MMC_READ_MULTIPLE_BLOCK:
+       case MMC_WRITE_MULTIPLE_BLOCK:
+               if (mrq->stop->opcode == MMC_STOP_TRANSMISSION) {
+                       host->wait = USDHI6_WAIT_FOR_STOP;
+                       return 0;
+               }
+               /* Unsupported STOP command */
+       default:
+               dev_err(mmc_dev(host->mmc),
+                       "unsupported stop CMD%d for CMD%d\n",
+                       mrq->stop->opcode, mrq->cmd->opcode);
+               mrq->stop->error = -EOPNOTSUPP;
+       }
+
+       return -EOPNOTSUPP;
+}
+
+static bool usdhi6_end_cmd(struct usdhi6_host *host)
+{
+       struct mmc_request *mrq = host->mrq;
+       struct mmc_command *cmd = mrq->cmd;
+
+       if (host->io_error) {
+               cmd->error = usdhi6_error_code(host);
+               return false;
+       }
+
+       usdhi6_resp_read(host);
+
+       if (!mrq->data)
+               return false;
+
+       if (host->dma_active) {
+               usdhi6_dma_kick(host);
+               if (!mrq->stop)
+                       host->wait = USDHI6_WAIT_FOR_DMA;
+               else if (usdhi6_stop_cmd(host) < 0)
+                       return false;
+       } else if (mrq->data->flags & MMC_DATA_READ) {
+               if (cmd->opcode == MMC_READ_MULTIPLE_BLOCK ||
+                   (cmd->opcode == SD_IO_RW_EXTENDED &&
+                    mrq->data->blocks > 1))
+                       host->wait = USDHI6_WAIT_FOR_MREAD;
+               else
+                       host->wait = USDHI6_WAIT_FOR_READ;
+       } else {
+               if (cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK ||
+                   (cmd->opcode == SD_IO_RW_EXTENDED &&
+                    mrq->data->blocks > 1))
+                       host->wait = USDHI6_WAIT_FOR_MWRITE;
+               else
+                       host->wait = USDHI6_WAIT_FOR_WRITE;
+       }
+
+       return true;
+}
+
+static bool usdhi6_read_block(struct usdhi6_host *host)
+{
+       /* ACCESS_END IRQ is already unmasked */
+       int ret = usdhi6_blk_read(host);
+
+       /*
+        * Have to force unmapping both pages: the single block could have been
+        * cross-page, in which case for single-block IO host->page_idx == 0.
+        * So, if we don't force, the second page won't be unmapped.
+        */
+       usdhi6_sg_unmap(host, true);
+
+       if (ret < 0)
+               return false;
+
+       host->wait = USDHI6_WAIT_FOR_DATA_END;
+       return true;
+}
+
+static bool usdhi6_mread_block(struct usdhi6_host *host)
+{
+       int ret = usdhi6_blk_read(host);
+
+       if (ret < 0)
+               return false;
+
+       usdhi6_sg_advance(host);
+
+       return !host->mrq->data->error &&
+               (host->wait != USDHI6_WAIT_FOR_DATA_END || !host->mrq->stop);
+}
+
+static bool usdhi6_write_block(struct usdhi6_host *host)
+{
+       int ret = usdhi6_blk_write(host);
+
+       /* See comment in usdhi6_read_block() */
+       usdhi6_sg_unmap(host, true);
+
+       if (ret < 0)
+               return false;
+
+       host->wait = USDHI6_WAIT_FOR_DATA_END;
+       return true;
+}
+
+static bool usdhi6_mwrite_block(struct usdhi6_host *host)
+{
+       int ret = usdhi6_blk_write(host);
+
+       if (ret < 0)
+               return false;
+
+       usdhi6_sg_advance(host);
+
+       return !host->mrq->data->error &&
+               (host->wait != USDHI6_WAIT_FOR_DATA_END || !host->mrq->stop);
+}
+
+/*                     Interrupt & timeout handlers                    */
+
+static irqreturn_t usdhi6_sd_bh(int irq, void *dev_id)
+{
+       struct usdhi6_host *host = dev_id;
+       struct mmc_request *mrq;
+       struct mmc_command *cmd;
+       struct mmc_data *data;
+       bool io_wait = false;
+
+       cancel_delayed_work_sync(&host->timeout_work);
+
+       mrq = host->mrq;
+       if (!mrq)
+               return IRQ_HANDLED;
+
+       cmd = mrq->cmd;
+       data = mrq->data;
+
+       switch (host->wait) {
+       case USDHI6_WAIT_FOR_REQUEST:
+               /* We're too late, the timeout has already kicked in */
+               return IRQ_HANDLED;
+       case USDHI6_WAIT_FOR_CMD:
+               /* Wait for data? */
+               io_wait = usdhi6_end_cmd(host);
+               break;
+       case USDHI6_WAIT_FOR_MREAD:
+               /* Wait for more data? */
+               io_wait = usdhi6_mread_block(host);
+               break;
+       case USDHI6_WAIT_FOR_READ:
+               /* Wait for data end? */
+               io_wait = usdhi6_read_block(host);
+               break;
+       case USDHI6_WAIT_FOR_MWRITE:
+               /* Wait data to write? */
+               io_wait = usdhi6_mwrite_block(host);
+               break;
+       case USDHI6_WAIT_FOR_WRITE:
+               /* Wait for data end? */
+               io_wait = usdhi6_write_block(host);
+               break;
+       case USDHI6_WAIT_FOR_DMA:
+               usdhi6_dma_check_error(host);
+               break;
+       case USDHI6_WAIT_FOR_STOP:
+               usdhi6_write(host, USDHI6_SD_STOP, 0);
+               if (host->io_error) {
+                       int ret = usdhi6_error_code(host);
+                       if (mrq->stop)
+                               mrq->stop->error = ret;
+                       else
+                               mrq->data->error = ret;
+                       dev_warn(mmc_dev(host->mmc), "%s(): %d\n", __func__, ret);
+                       break;
+               }
+               usdhi6_resp_cmd12(host);
+               mrq->stop->error = 0;
+               break;
+       case USDHI6_WAIT_FOR_DATA_END:
+               if (host->io_error) {
+                       mrq->data->error = usdhi6_error_code(host);
+                       dev_warn(mmc_dev(host->mmc), "%s(): %d\n", __func__,
+                                mrq->data->error);
+               }
+               break;
+       default:
+               cmd->error = -EFAULT;
+               dev_err(mmc_dev(host->mmc), "Invalid state %u\n", host->wait);
+               usdhi6_request_done(host);
+               return IRQ_HANDLED;
+       }
+
+       if (io_wait) {
+               schedule_delayed_work(&host->timeout_work, host->timeout);
+               /* Wait for more data or ACCESS_END */
+               if (!host->dma_active)
+                       usdhi6_wait_for_brwe(host, mrq->data->flags & MMC_DATA_READ);
+               return IRQ_HANDLED;
+       }
+
+       if (!cmd->error) {
+               if (data) {
+                       if (!data->error) {
+                               if (host->wait != USDHI6_WAIT_FOR_STOP &&
+                                   host->mrq->stop &&
+                                   !host->mrq->stop->error &&
+                                   !usdhi6_stop_cmd(host)) {
+                                       /* Sending STOP */
+                                       usdhi6_wait_for_resp(host);
+
+                                       schedule_delayed_work(&host->timeout_work,
+                                                             host->timeout);
+
+                                       return IRQ_HANDLED;
+                               }
+
+                               data->bytes_xfered = data->blocks * data->blksz;
+                       } else {
+                               /* Data error: might need to unmap the last page */
+                               dev_warn(mmc_dev(host->mmc), "%s(): data error %d\n",
+                                        __func__, data->error);
+                               usdhi6_sg_unmap(host, true);
+                       }
+               } else if (cmd->opcode == MMC_APP_CMD) {
+                       host->app_cmd = true;
+               }
+       }
+
+       usdhi6_request_done(host);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t usdhi6_sd(int irq, void *dev_id)
+{
+       struct usdhi6_host *host = dev_id;
+       u16 status, status2, error;
+
+       status = usdhi6_read(host, USDHI6_SD_INFO1) & ~host->status_mask &
+               ~USDHI6_SD_INFO1_CARD;
+       status2 = usdhi6_read(host, USDHI6_SD_INFO2) & ~host->status2_mask;
+
+       usdhi6_only_cd(host);
+
+       dev_dbg(mmc_dev(host->mmc),
+               "IRQ status = 0x%08x, status2 = 0x%08x\n", status, status2);
+
+       if (!status && !status2)
+               return IRQ_NONE;
+
+       error = status2 & USDHI6_SD_INFO2_ERR;
+
+       /* Ack / clear interrupts */
+       if (USDHI6_SD_INFO1_IRQ & status)
+               usdhi6_write(host, USDHI6_SD_INFO1,
+                            0xffff & ~(USDHI6_SD_INFO1_IRQ & status));
+
+       if (USDHI6_SD_INFO2_IRQ & status2) {
+               if (error)
+                       /* In error cases BWE and BRE aren't cleared automatically */
+                       status2 |= USDHI6_SD_INFO2_BWE | USDHI6_SD_INFO2_BRE;
+
+               usdhi6_write(host, USDHI6_SD_INFO2,
+                            0xffff & ~(USDHI6_SD_INFO2_IRQ & status2));
+       }
+
+       host->io_error = error;
+       host->irq_status = status;
+
+       if (error) {
+               /* Don't pollute the log with unsupported command timeouts */
+               if (host->wait != USDHI6_WAIT_FOR_CMD ||
+                   error != USDHI6_SD_INFO2_RSP_TOUT)
+                       dev_warn(mmc_dev(host->mmc),
+                                "%s(): INFO2 error bits 0x%08x\n",
+                                __func__, error);
+               else
+                       dev_dbg(mmc_dev(host->mmc),
+                               "%s(): INFO2 error bits 0x%08x\n",
+                               __func__, error);
+       }
+
+       return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t usdhi6_sdio(int irq, void *dev_id)
+{
+       struct usdhi6_host *host = dev_id;
+       u32 status = usdhi6_read(host, USDHI6_SDIO_INFO1) & ~host->sdio_mask;
+
+       dev_dbg(mmc_dev(host->mmc), "%s(): status 0x%x\n", __func__, status);
+
+       if (!status)
+               return IRQ_NONE;
+
+       usdhi6_write(host, USDHI6_SDIO_INFO1, ~status);
+
+       mmc_signal_sdio_irq(host->mmc);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t usdhi6_cd(int irq, void *dev_id)
+{
+       struct usdhi6_host *host = dev_id;
+       struct mmc_host *mmc = host->mmc;
+       u16 status;
+
+       /* We're only interested in hotplug events here */
+       status = usdhi6_read(host, USDHI6_SD_INFO1) & ~host->status_mask &
+               USDHI6_SD_INFO1_CARD;
+
+       if (!status)
+               return IRQ_NONE;
+
+       /* Ack */
+       usdhi6_write(host, USDHI6_SD_INFO1, !status);
+
+       if (!work_pending(&mmc->detect.work) &&
+           (((status & USDHI6_SD_INFO1_CARD_INSERT) &&
+             !mmc->card) ||
+            ((status & USDHI6_SD_INFO1_CARD_EJECT) &&
+             mmc->card)))
+               mmc_detect_change(mmc, msecs_to_jiffies(100));
+
+       return IRQ_HANDLED;
+}
+
+/*
+ * Actually this should not be needed, if the built-in timeout works reliably in
+ * the both PIO cases and DMA never fails. But if DMA does fail, a timeout
+ * handler might be the only way to catch the error.
+ */
+static void usdhi6_timeout_work(struct work_struct *work)
+{
+       struct delayed_work *d = container_of(work, struct delayed_work, work);
+       struct usdhi6_host *host = container_of(d, struct usdhi6_host, timeout_work);
+       struct mmc_request *mrq = host->mrq;
+       struct mmc_data *data = mrq ? mrq->data : NULL;
+
+       dev_warn(mmc_dev(host->mmc),
+                "%s timeout wait %u CMD%d: IRQ 0x%08x:0x%08x, last IRQ 0x%08x\n",
+                host->dma_active ? "DMA" : "PIO",
+                host->wait, mrq ? mrq->cmd->opcode : -1,
+                usdhi6_read(host, USDHI6_SD_INFO1),
+                usdhi6_read(host, USDHI6_SD_INFO2), host->irq_status);
+
+       if (host->dma_active) {
+               usdhi6_dma_kill(host);
+               usdhi6_dma_stop_unmap(host);
+       }
+
+       switch (host->wait) {
+       default:
+               dev_err(mmc_dev(host->mmc), "Invalid state %u\n", host->wait);
+               /* mrq can be NULL in this actually impossible case */
+       case USDHI6_WAIT_FOR_CMD:
+               usdhi6_error_code(host);
+               if (mrq)
+                       mrq->cmd->error = -ETIMEDOUT;
+               break;
+       case USDHI6_WAIT_FOR_STOP:
+               usdhi6_error_code(host);
+               mrq->stop->error = -ETIMEDOUT;
+               break;
+       case USDHI6_WAIT_FOR_DMA:
+       case USDHI6_WAIT_FOR_MREAD:
+       case USDHI6_WAIT_FOR_MWRITE:
+       case USDHI6_WAIT_FOR_READ:
+       case USDHI6_WAIT_FOR_WRITE:
+               dev_dbg(mmc_dev(host->mmc),
+                       "%c: page #%u @ +0x%x %ux%u in SG%u. Current SG %u bytes @ %u\n",
+                       data->flags & MMC_DATA_READ ? 'R' : 'W', host->page_idx,
+                       host->offset, data->blocks, data->blksz, data->sg_len,
+                       sg_dma_len(host->sg), host->sg->offset);
+               usdhi6_sg_unmap(host, true);
+               /*
+                * If USDHI6_WAIT_FOR_DATA_END times out, we have already unmapped
+                * the page
+                */
+       case USDHI6_WAIT_FOR_DATA_END:
+               usdhi6_error_code(host);
+               data->error = -ETIMEDOUT;
+       }
+
+       if (mrq)
+               usdhi6_request_done(host);
+}
+
+/*                      Probe / release                                */
+
+static const struct of_device_id usdhi6_of_match[] = {
+       {.compatible = "renesas,usdhi6rol0"},
+       {}
+};
+MODULE_DEVICE_TABLE(of, usdhi6_of_match);
+
+static int usdhi6_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct mmc_host *mmc;
+       struct usdhi6_host *host;
+       struct resource *res;
+       int irq_cd, irq_sd, irq_sdio;
+       u32 version;
+       int ret;
+
+       if (!dev->of_node)
+               return -ENODEV;
+
+       irq_cd = platform_get_irq_byname(pdev, "card detect");
+       irq_sd = platform_get_irq_byname(pdev, "data");
+       irq_sdio = platform_get_irq_byname(pdev, "SDIO");
+       if (irq_sd < 0 || irq_sdio < 0)
+               return -ENODEV;
+
+       mmc = mmc_alloc_host(sizeof(struct usdhi6_host), dev);
+       if (!mmc)
+               return -ENOMEM;
+
+       ret = mmc_of_parse(mmc);
+       if (ret < 0)
+               goto e_free_mmc;
+
+       mmc_regulator_get_supply(mmc);
+
+       host            = mmc_priv(mmc);
+       host->mmc       = mmc;
+       host->wait      = USDHI6_WAIT_FOR_REQUEST;
+       host->timeout   = msecs_to_jiffies(4000);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       host->base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(host->base)) {
+               ret = PTR_ERR(host->base);
+               goto e_free_mmc;
+       }
+
+       host->clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(host->clk))
+               goto e_free_mmc;
+
+       host->imclk = clk_get_rate(host->clk);
+
+       ret = clk_prepare_enable(host->clk);
+       if (ret < 0)
+               goto e_free_mmc;
+
+       version = usdhi6_read(host, USDHI6_VERSION);
+       if ((version & 0xfff) != 0xa0d) {
+               dev_err(dev, "Version not recognized %x\n", version);
+               goto e_clk_off;
+       }
+
+       dev_info(dev, "A USDHI6ROL0 SD host detected with %d ports\n",
+                usdhi6_read(host, USDHI6_SD_PORT_SEL) >> USDHI6_SD_PORT_SEL_PORTS_SHIFT);
+
+       usdhi6_mask_all(host);
+
+       if (irq_cd >= 0) {
+               ret = devm_request_irq(dev, irq_cd, usdhi6_cd, 0,
+                                      dev_name(dev), host);
+               if (ret < 0)
+                       goto e_clk_off;
+       } else {
+               mmc->caps |= MMC_CAP_NEEDS_POLL;
+       }
+
+       ret = devm_request_threaded_irq(dev, irq_sd, usdhi6_sd, usdhi6_sd_bh, 0,
+                              dev_name(dev), host);
+       if (ret < 0)
+               goto e_clk_off;
+
+       ret = devm_request_irq(dev, irq_sdio, usdhi6_sdio, 0,
+                              dev_name(dev), host);
+       if (ret < 0)
+               goto e_clk_off;
+
+       INIT_DELAYED_WORK(&host->timeout_work, usdhi6_timeout_work);
+
+       usdhi6_dma_request(host, res->start);
+
+       mmc->ops = &usdhi6_ops;
+       mmc->caps |= MMC_CAP_SD_HIGHSPEED | MMC_CAP_MMC_HIGHSPEED |
+               MMC_CAP_UHS_SDR50 | MMC_CAP_UHS_DDR50 | MMC_CAP_SDIO_IRQ;
+       /* Set .max_segs to some random number. Feel free to adjust. */
+       mmc->max_segs = 32;
+       mmc->max_blk_size = 512;
+       mmc->max_req_size = PAGE_CACHE_SIZE * mmc->max_segs;
+       mmc->max_blk_count = mmc->max_req_size / mmc->max_blk_size;
+       /*
+        * Setting .max_seg_size to 1 page would simplify our page-mapping code,
+        * But OTOH, having large segments makes DMA more efficient. We could
+        * check, whether we managed to get DMA and fall back to 1 page
+        * segments, but if we do manage to obtain DMA and then it fails at
+        * run-time and we fall back to PIO, we will continue getting large
+        * segments. So, we wouldn't be able to get rid of the code anyway.
+        */
+       mmc->max_seg_size = mmc->max_req_size;
+       if (!mmc->f_max)
+               mmc->f_max = host->imclk;
+       mmc->f_min = host->imclk / 512;
+
+       platform_set_drvdata(pdev, host);
+
+       ret = mmc_add_host(mmc);
+       if (ret < 0)
+               goto e_clk_off;
+
+       return 0;
+
+e_clk_off:
+       clk_disable_unprepare(host->clk);
+e_free_mmc:
+       mmc_free_host(mmc);
+
+       return ret;
+}
+
+static int usdhi6_remove(struct platform_device *pdev)
+{
+       struct usdhi6_host *host = platform_get_drvdata(pdev);
+
+       mmc_remove_host(host->mmc);
+
+       usdhi6_mask_all(host);
+       cancel_delayed_work_sync(&host->timeout_work);
+       usdhi6_dma_release(host);
+       clk_disable_unprepare(host->clk);
+       mmc_free_host(host->mmc);
+
+       return 0;
+}
+
+static struct platform_driver usdhi6_driver = {
+       .probe          = usdhi6_probe,
+       .remove         = usdhi6_remove,
+       .driver         = {
+               .name   = "usdhi6rol0",
+               .owner  = THIS_MODULE,
+               .of_match_table = usdhi6_of_match,
+       },
+};
+
+module_platform_driver(usdhi6_driver);
+
+MODULE_DESCRIPTION("Renesas usdhi6rol0 SD/SDIO host driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:usdhi6rol0");
+MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
index 498d1f79908574144408536fa9488ad5f0d0c39f..282891a8e451e77040faaf26e5267e70595cc4ba 100644 (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;
index 2e39d38d6a9ee80d28c56283541ca625992aeacc..46e7af446f01028ad15eec09e461037bc9f9211c 100644 (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;
index b73027298b3a68e71f92b2716ac6952cfc8a1091..d424b9de3affbbee5476b9973070fc03b1b38422 100644 (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)
index 6ce7d2cd3c7ad7dd5eea530192de207b3d1aef22..babaea93bca646d302ae19435e468e9ba68b0042 100644 (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;
index cb61ea4d69455366768fa04bc2263c65795bc92f..7960424d0bc0cf4f1ad65e93f9df79fa83bf9403 100644 (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 */
index 50bcde3677ca19d19baf5da199fbcb73ab29df25..64ec963ed3478b88babe7c4292c2b2e310ca51c2 100644 (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)
index 7be12b883485965beea0eecf10bf0abd69119b89..08abe9941884ebc40667ee246881b2b2bfd66f70 100644 (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 */
 
index c29a6dee6bec5906a2b72503463761197fce17a0..88e6ea4a5d3683543cf6c4cc57be13483ef36476 100644 (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
diff --git a/include/linux/omap-dmaengine.h b/include/linux/omap-dmaengine.h
new file mode 100644 (file)
index 0000000..8e6906c
--- /dev/null
@@ -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 */